Added noaslr (#1333)

This commit is contained in:
WorksButNotTested 2023-06-30 19:37:48 +01:00 committed by GitHub
parent 97b3d3c7c7
commit 07047cb3bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 486 additions and 0 deletions

7
utils/noaslr/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[workspace]
resolver = "2"
members = [
"noaslr",
"demo",
"libnoaslr"
]

View File

@ -0,0 +1,89 @@
[config]
default_to_workspace = false
[env]
PROFILE="dev"
BUILD_DIR="${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/debug"
[env.release]
PROFILE="release"
BUILD_DIR="${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/release"
[tasks.clean]
command = "cargo"
args = ["clean"]
[tasks.format]
install_crate = "rustfmt"
command = "cargo"
args = ["fmt", "--", "--emit=files"]
[tasks.demo]
dependencies = ["format", "clippy"]
command = "cargo"
args = [
"build",
"-p", "demo",
"--profile", "${PROFILE}",
]
[tasks.run_demo]
dependencies = ["demo"]
command = "cargo"
args = [
"run",
"-p", "demo",
]
[tasks.build]
dependencies = ["format", "clippy"]
command = "cargo"
args = [
"build",
"-p", "noaslr",
"--profile", "${PROFILE}",
]
[tasks.buildlib]
dependencies = ["format", "clippy"]
command = "cargo"
args = [
"build",
"-p", "libnoaslr",
"--profile", "${PROFILE}",
]
[tasks.run]
command = "cargo"
dependencies = [ "demo" ]
env = { "ZZZ_TEST_ZZZ" = "ZZZ TEST ZZZ"}
args = [
"run",
"-p", "noaslr",
"--profile", "${PROFILE}",
"--",
"${BUILD_DIR}/demo",
"--",
"-f",
"/proc/self/maps",
"--",
"test"
]
[tasks.runlib]
command = "cargo"
dependencies = [ "demo", "buildlib" ]
env = { "LD_PRELOAD" = "${BUILD_DIR}/libnoaslr.so", "ZZZ_TEST_ZZZ" = "ZZZ TEST ZZZ"}
args = [
"run",
"-p", "demo",
"--profile", "${PROFILE}",
"--",
"-f",
"/proc/self/maps",
"--",
"test"
]
[tasks.all]
dependencies = ["demo", "build", "buildlib"]

118
utils/noaslr/README.md Normal file
View File

@ -0,0 +1,118 @@
# NOASLR
`noaslr` is a launcher for running applications with ASLR disabled without having
to disable the feature system-wide.
`libnoaslr` is a dynamic shared object which can be injected into an application
at startup using `LD_PRELOAD` which will cause it to disable ASLR.
Also included is `demo` an application which reads and prints the contents of the
file passed as its single argument. By passing `/proc/self/maps` as its argument
it can be observed that the application loads at the same default address each
time it is run.
# Test
## App
```
$ cargo make run
```
## Library
```
$ cargo make runlib
```
# Example
## App
```
$ ./target/debug/noaslr ./target/debug/demo -- /proc/self/maps
```
## Library
```
$ LD_PRELOAD=target/debug/libnoaslr.so ./target/debug/demo /proc/self/maps
```
## Output
...
555555554000-55555556d000 r--p 00000000 fd:03 78381550 /home/jon/git/LibAFL/utils/noaslr/target/debug/demo
55555556d000-5555556a1000 r-xp 00019000 fd:03 78381550 /home/jon/git/LibAFL/utils/noaslr/target/debug/demo
5555556a1000-5555556ee000 r--p 0014d000 fd:03 78381550 /home/jon/git/LibAFL/utils/noaslr/target/debug/demo
5555556ee000-5555556fb000 r--p 00199000 fd:03 78381550 /home/jon/git/LibAFL/utils/noaslr/target/debug/demo
5555556fb000-5555556fc000 rw-p 001a6000 fd:03 78381550 /home/jon/git/LibAFL/utils/noaslr/target/debug/demo
5555556fc000-55555571d000 rw-p 00000000 00:00 0 [heap]
7ffff7d74000-7ffff7d76000 rw-p 00000000 00:00 0
7ffff7d76000-7ffff7d98000 r--p 00000000 fd:03 9972607 /usr/lib/x86_64-linux-gnu/libc-2.31.so
7ffff7d98000-7ffff7f10000 r-xp 00022000 fd:03 9972607 /usr/lib/x86_64-linux-gnu/libc-2.31.so
7ffff7f10000-7ffff7f5e000 r--p 0019a000 fd:03 9972607 /usr/lib/x86_64-linux-gnu/libc-2.31.so
7ffff7f5e000-7ffff7f62000 r--p 001e7000 fd:03 9972607 /usr/lib/x86_64-linux-gnu/libc-2.31.so
7ffff7f62000-7ffff7f64000 rw-p 001eb000 fd:03 9972607 /usr/lib/x86_64-linux-gnu/libc-2.31.so
7ffff7f64000-7ffff7f68000 rw-p 00000000 00:00 0
7ffff7f68000-7ffff7f69000 r--p 00000000 fd:03 9972611 /usr/lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7f69000-7ffff7f6b000 r-xp 00001000 fd:03 9972611 /usr/lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7f6b000-7ffff7f6c000 r--p 00003000 fd:03 9972611 /usr/lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7f6c000-7ffff7f6d000 r--p 00003000 fd:03 9972611 /usr/lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7f6d000-7ffff7f6e000 rw-p 00004000 fd:03 9972611 /usr/lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7f6e000-7ffff7f74000 r--p 00000000 fd:03 9972655 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
7ffff7f74000-7ffff7f85000 r-xp 00006000 fd:03 9972655 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
7ffff7f85000-7ffff7f8b000 r--p 00017000 fd:03 9972655 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
7ffff7f8b000-7ffff7f8c000 r--p 0001c000 fd:03 9972655 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
7ffff7f8c000-7ffff7f8d000 rw-p 0001d000 fd:03 9972655 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
7ffff7f8d000-7ffff7f91000 rw-p 00000000 00:00 0
7ffff7f91000-7ffff7f94000 r--p 00000000 fd:03 9961835 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7f94000-7ffff7fa6000 r-xp 00003000 fd:03 9961835 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7fa6000-7ffff7faa000 r--p 00015000 fd:03 9961835 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7faa000-7ffff7fab000 r--p 00018000 fd:03 9961835 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7fab000-7ffff7fac000 rw-p 00019000 fd:03 9961835 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7fac000-7ffff7fae000 rw-p 00000000 00:00 0
7ffff7fc8000-7ffff7fc9000 ---p 00000000 00:00 0
7ffff7fc9000-7ffff7fcb000 rw-p 00000000 00:00 0
7ffff7fcb000-7ffff7fce000 r--p 00000000 00:00 0 [vvar]
7ffff7fce000-7ffff7fcf000 r-xp 00000000 00:00 0 [vdso]
7ffff7fcf000-7ffff7fd0000 r--p 00000000 fd:03 9972533 /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7fd0000-7ffff7ff3000 r-xp 00001000 fd:03 9972533 /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ff3000-7ffff7ffb000 r--p 00024000 fd:03 9972533 /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffc000-7ffff7ffd000 r--p 0002c000 fd:03 9972533 /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffd000-7ffff7ffe000 rw-p 0002d000 fd:03 9972533 /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
```
# About
## APP
`noaslr` does the following:
* Uses the `personality` API to set the flag `ADDR_NO_RANDOMIZE`.
* Uses the `execve` API to launch the child application.
## Lib
`libnoasl` does the following:
* Uses rusts `ctor` crate to define a function as `__attribute__((constructor))`
* Uses the `personality` API to determine if the flag `ADDR_NO_RANDOMIZE` is set
* If the flag is set, the constructor returns, otherwise...
* Uses the `personality` API again to set the flag
* Reads the program arguments from `/proc/self/cmdline`
* Reads the program environment variables from `/proc/self/environ`
* Uses the `execvpe` API to re-launch the application
# Usage
```
Tool launching applications with ASLR disabled
Usage: noaslr <PROGRAM> [-- <ARGS>...]
Arguments:
<PROGRAM>
Name of the application to launch
[ARGS]...
Arguments passed to the target
Options:
-h, --help
Print help (see a summary with '-h')
-V, --version
Print version
```

View File

@ -0,0 +1,12 @@
[package]
name = "demo"
version = "0.1.0"
edition = "2021"
[build-dependencies]
vergen = { version = "8.1.1", features = ["build", "cargo", "git", "gitcl", "rustc", "si"] }
[dependencies]
anyhow = { version = "1.0.71", default-features = false }
clap = { version = "4.2.0", default-features = false, features = ["derive", "string", "std", "help"] }
readonly = { version = "0.2.8", default-features = false }

View File

@ -0,0 +1,13 @@
use {std::error::Error, vergen::EmitBuilder};
fn main() -> Result<(), Box<dyn Error>> {
EmitBuilder::builder()
.all_build()
.all_cargo()
.all_git()
.all_rustc()
.all_sysinfo()
.emit()?;
Ok(())
}

View File

@ -0,0 +1,45 @@
use clap::{builder::Str, Parser};
#[derive(Default)]
pub struct Version;
impl From<Version> for Str {
fn from(_: Version) -> Str {
let version = [
("Build Timestamp:", env!("VERGEN_BUILD_TIMESTAMP")),
("Describe:", env!("VERGEN_GIT_DESCRIBE")),
("Commit SHA:", env!("VERGEN_GIT_SHA")),
("Commit Date:", env!("VERGEN_RUSTC_COMMIT_DATE")),
("Commit Branch:", env!("VERGEN_GIT_BRANCH")),
("Rustc Version:", env!("VERGEN_RUSTC_SEMVER")),
("Rustc Channel:", env!("VERGEN_RUSTC_CHANNEL")),
("Rustc Host Triple:", env!("VERGEN_RUSTC_HOST_TRIPLE")),
("Rustc Commit SHA:", env!("VERGEN_RUSTC_COMMIT_HASH")),
("Cargo Target Triple", env!("VERGEN_CARGO_TARGET_TRIPLE")),
]
.iter()
.map(|(k, v)| format!("{k:25}: {v}\n"))
.collect::<String>();
format!("\n{version:}").into()
}
}
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
#[command(
version = Version::default(),
about = "demo",
long_about = "Application to demonstrate noaslr utility"
)]
#[readonly::make]
pub struct Args {
#[arg(short, long, help = "Unused flag")]
pub flag: bool,
#[arg(help = "Name of the file to read")]
pub file: String,
#[arg(last = true, value_parser, value_delimiter = ' ', num_args = 1.., help = "Arguments passed to the target")]
args: Vec<String>,
}

View File

@ -0,0 +1,34 @@
mod args;
use {
crate::args::Args,
anyhow::{anyhow, Result},
clap::Parser,
std::{
env,
fs::File,
io::{BufRead, BufReader},
},
};
fn main() -> Result<()> {
let args = Args::parse();
for (i, a) in env::args().enumerate() {
println!("ARG - {i:3}: {a}");
}
for (i, (k, v)) in env::vars().enumerate() {
println!("ENV {i:3}: {k} = {v}");
}
let file = File::open(&args.file).map_err(|e| anyhow!("Failed to open maps: {e:}"))?;
let lines = BufReader::new(file).lines();
for line in lines {
println!(
"{}",
line.map_err(|e| anyhow!("Failed to read line: {e:}"))?
);
}
Ok(())
}

View File

@ -0,0 +1,16 @@
[package]
name = "libnoaslr"
version = "0.1.0"
edition = "2021"
[lib]
name = "noaslr"
path = "src/lib.rs"
crate-type = ["dylib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = { version = "1.0.71", default-features = false }
ctor = { version = "0.2.2", default-features = false }
nix = { version = "0.26.2", default-features = false, features = ["process", "personality"] }

View File

@ -0,0 +1,42 @@
use {
anyhow::{anyhow, Result},
ctor::ctor,
nix::{
sys::{personality, personality::Persona},
unistd::execvpe,
},
std::{ffi::CString, fs::File, io::Read},
};
fn read_null_lines(path: &str) -> Result<Vec<CString>> {
let mut file = File::open(path).map_err(|e| anyhow!("Failed to open maps: {e:}"))?;
let mut data = String::new();
file.read_to_string(&mut data)
.map_err(|e| anyhow!("Failed to read command line: {e:}"))?;
data.split('\0')
.map(|s| s.to_string())
.filter(|s| !s.is_empty())
.map(|x| CString::new(x).map_err(|e| anyhow!("Failed to read argument: {e:}")))
.collect::<Result<Vec<CString>>>()
}
fn libnoaslr() -> Result<()> {
let mut persona = personality::get().map_err(|e| anyhow!("Failed to get personality: {e:}"))?;
if (persona & Persona::ADDR_NO_RANDOMIZE) == Persona::ADDR_NO_RANDOMIZE {
return Ok(());
}
persona |= Persona::ADDR_NO_RANDOMIZE;
personality::set(persona).map_err(|e| anyhow!("Failed to set personality: {e:}"))?;
let args = read_null_lines("/proc/self/cmdline")?;
let env = read_null_lines("/proc/self/environ")?;
execvpe(&args[0], &args, &env).map_err(|e| anyhow!("Failed to exceve: {e:}"))?;
Ok(())
}
#[ctor]
fn init() {
libnoaslr().unwrap();
}

View File

@ -0,0 +1,15 @@
[package]
name = "noaslr"
version = "0.1.0"
edition = "2021"
[build-dependencies]
vergen = { version = "8.1.1", features = ["build", "cargo", "git", "gitcl", "rustc", "si"] }
[dependencies]
anyhow = { version = "1.0.71", default-features = false }
clap = { version = "4.2.0", default-features = false, features = ["derive", "string", "std", "help", "derive", "error-context", "usage"] }
log = { version = "0.4.19", default-features = false }
nix = { version = "0.26.2", default-features = false, features = ["process", "personality"] }
readonly = { version = "0.2.8", default-features = false }
simplelog = { version = "0.12.1", default-features = false }

View File

@ -0,0 +1,13 @@
use {std::error::Error, vergen::EmitBuilder};
fn main() -> Result<(), Box<dyn Error>> {
EmitBuilder::builder()
.all_build()
.all_cargo()
.all_git()
.all_rustc()
.all_sysinfo()
.emit()?;
Ok(())
}

View File

@ -0,0 +1,54 @@
use {
clap::{builder::Str, Parser},
std::iter,
};
#[derive(Default)]
pub struct Version;
impl From<Version> for Str {
fn from(_: Version) -> Str {
let version = [
("Build Timestamp:", env!("VERGEN_BUILD_TIMESTAMP")),
("Describe:", env!("VERGEN_GIT_DESCRIBE")),
("Commit SHA:", env!("VERGEN_GIT_SHA")),
("Commit Date:", env!("VERGEN_RUSTC_COMMIT_DATE")),
("Commit Branch:", env!("VERGEN_GIT_BRANCH")),
("Rustc Version:", env!("VERGEN_RUSTC_SEMVER")),
("Rustc Channel:", env!("VERGEN_RUSTC_CHANNEL")),
("Rustc Host Triple:", env!("VERGEN_RUSTC_HOST_TRIPLE")),
("Rustc Commit SHA:", env!("VERGEN_RUSTC_COMMIT_HASH")),
("Cargo Target Triple", env!("VERGEN_CARGO_TARGET_TRIPLE")),
]
.iter()
.map(|(k, v)| format!("{k:25}: {v}\n"))
.collect::<String>();
format!("\n{version:}").into()
}
}
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
#[command(
version = Version::default(),
about = "nosalr",
long_about = "Tool launching applications with ASLR disabled"
)]
#[readonly::make]
pub struct Args {
#[arg(help = "Name of the application to launch")]
program: String,
#[arg(last = true, value_parser, value_delimiter = ' ', num_args = 1.., help = "Arguments passed to the target")]
args: Vec<String>,
}
impl Args {
pub fn argv(&self) -> Vec<String> {
iter::once(&self.program)
.chain(self.args.iter())
.cloned()
.collect::<Vec<String>>()
}
}

View File

@ -0,0 +1,28 @@
mod args;
use {
crate::args::Args,
anyhow::{anyhow, Result},
clap::Parser,
nix::{
sys::{personality, personality::Persona},
unistd::execvp,
},
std::ffi::CString,
};
fn main() -> Result<()> {
let args = Args::parse();
let mut persona = personality::get().map_err(|e| anyhow!("Failed to get personality: {e:}"))?;
persona |= Persona::ADDR_NO_RANDOMIZE;
personality::set(persona).map_err(|e| anyhow!("Failed to set personality: {e:}"))?;
let cargs = args
.argv()
.iter()
.map(|x| CString::new(x.clone()).map_err(|e| anyhow!("Failed to read argument: {e:}")))
.collect::<Result<Vec<CString>>>()?;
execvp(&cargs[0], &cargs).map_err(|e| anyhow!("Failed to exceve: {e:}"))?;
Ok(())
}