better mutator
This commit is contained in:
parent
b4b97fe34f
commit
ebc9571410
@ -120,7 +120,7 @@ pub fn buffer_copy(dst: &mut [u8], src: &[u8], from: usize, to: usize, len: usiz
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn buffer_set(data: &mut [u8], from: usize, len: usize, val: u8) {
|
fn buffer_set(data: &mut [u8], from: usize, len: usize, val: u8) {
|
||||||
debug_assert!(from + len <= data.len());
|
debug_assert!(from + len <= data.len());
|
||||||
for p in &mut data[from..from + len] {
|
for p in &mut data[from..(from + len)] {
|
||||||
*p = val
|
*p = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -491,11 +491,19 @@ where
|
|||||||
if size == 0 {
|
if size == 0 {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
let off = rand.below(size as u64 - 1) as usize;
|
let off = rand.below(size as u64) as usize;
|
||||||
let len = rand.below(min(16, mutator.max_size() as u64 - 1) + 1) as usize;
|
let mut len = 1 + rand.below(16) as usize;
|
||||||
|
|
||||||
|
if size + len > mutator.max_size() {
|
||||||
|
if mutator.max_size() > size {
|
||||||
|
len = mutator.max_size() - size;
|
||||||
|
} else {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
input.bytes_mut().resize(size + len, 0);
|
input.bytes_mut().resize(size + len, 0);
|
||||||
buffer_self_copy(input.bytes_mut(), 0, 0 + off, len);
|
buffer_self_copy(input.bytes_mut(), off, off + len, size - off);
|
||||||
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
@ -511,21 +519,25 @@ where
|
|||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
let mut size = input.bytes().len();
|
let size = input.bytes().len();
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
// Generate random bytes if we're empty.
|
return Ok(MutationResult::Skipped);
|
||||||
input
|
}
|
||||||
.bytes_mut()
|
let off = rand.below(size as u64) as usize;
|
||||||
.append(&mut rand.next().to_be_bytes().to_vec());
|
let mut len = 1 + rand.below(16) as usize;
|
||||||
size = input.bytes().len();
|
|
||||||
|
if size + len > mutator.max_size() {
|
||||||
|
if mutator.max_size() > size {
|
||||||
|
len = mutator.max_size() - size;
|
||||||
|
} else {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let off = rand.below(size as u64 - 1) as usize;
|
|
||||||
let len = rand.below(max(16, mutator.max_size() as u64)) as usize;
|
|
||||||
|
|
||||||
let val = input.bytes()[rand.below(size as u64) as usize];
|
let val = input.bytes()[rand.below(size as u64) as usize];
|
||||||
|
|
||||||
input.bytes_mut().resize(max(size, off + (2 * len) + 1), 0);
|
input.bytes_mut().resize(size + len, 0);
|
||||||
buffer_self_copy(input.bytes_mut(), off, off + len, len);
|
buffer_self_copy(input.bytes_mut(), off, off + len, size - off);
|
||||||
buffer_set(input.bytes_mut(), off, len, val);
|
buffer_set(input.bytes_mut(), off, len, val);
|
||||||
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
@ -542,20 +554,25 @@ where
|
|||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
let mut size = input.bytes().len();
|
let size = input.bytes().len();
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
input
|
return Ok(MutationResult::Skipped);
|
||||||
.bytes_mut()
|
}
|
||||||
.append(&mut rand.next().to_le_bytes().to_vec());
|
let off = rand.below(size as u64) as usize;
|
||||||
size = input.bytes().len();
|
let mut len = 1 + rand.below(16) as usize;
|
||||||
|
|
||||||
|
if size + len > mutator.max_size() {
|
||||||
|
if mutator.max_size() > size {
|
||||||
|
len = mutator.max_size() - size;
|
||||||
|
} else {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let off = rand.below(size as u64 - 1) as usize;
|
|
||||||
let len = rand.below(core::cmp::min(16, mutator.max_size() as u64)) as usize;
|
|
||||||
|
|
||||||
let val = rand.below(256) as u8;
|
let val = rand.below(256) as u8;
|
||||||
|
|
||||||
input.bytes_mut().resize(max(size, off + (2 * len) + 1), 0);
|
input.bytes_mut().resize(size + len, 0);
|
||||||
buffer_self_copy(input.bytes_mut(), off, off + len, len);
|
buffer_self_copy(input.bytes_mut(), off, off + len, size - off);
|
||||||
buffer_set(input.bytes_mut(), off, len, val);
|
buffer_set(input.bytes_mut(), off, len, val);
|
||||||
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
@ -575,16 +592,12 @@ where
|
|||||||
if size == 0 {
|
if size == 0 {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
|
let off = rand.below(size as u64) as usize;
|
||||||
|
let len = 1 + rand.below(min(16, size - off) as u64) as usize;
|
||||||
|
|
||||||
let val = input.bytes()[rand.below(size as u64) as usize];
|
let val = input.bytes()[rand.below(size as u64) as usize];
|
||||||
let start = if size == 1 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
rand.below(size as u64 - 1) as usize
|
|
||||||
};
|
|
||||||
|
|
||||||
let end = rand.between(start as u64, size as u64) as usize;
|
buffer_set(input.bytes_mut(), off, len, val);
|
||||||
buffer_set(input.bytes_mut(), start, end - start, val);
|
|
||||||
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
@ -603,16 +616,12 @@ where
|
|||||||
if size == 0 {
|
if size == 0 {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
|
let off = rand.below(size as u64) as usize;
|
||||||
|
let len = 1 + rand.below(min(16, size - off) as u64) as usize;
|
||||||
|
|
||||||
let val = rand.below(256) as u8;
|
let val = rand.below(256) as u8;
|
||||||
let start = if size == 1 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
rand.below(size as u64 - 1) as usize
|
|
||||||
};
|
|
||||||
|
|
||||||
let len = rand.below((size - start) as u64) as usize;
|
buffer_set(input.bytes_mut(), off, len, val);
|
||||||
buffer_set(input.bytes_mut(), start, len, val);
|
|
||||||
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
@ -632,9 +641,9 @@ where
|
|||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
let from = rand.below(input.bytes().len() as u64 - 1) as usize;
|
let from = rand.below(input.bytes().len() as u64) as usize;
|
||||||
let to = rand.below(input.bytes().len() as u64 - 1) as usize;
|
let to = rand.below(input.bytes().len() as u64) as usize;
|
||||||
let len = rand.below((size - core::cmp::max(from, to)) as u64) as usize;
|
let len = 1 + rand.below((size - max(from, to)) as u64) as usize;
|
||||||
|
|
||||||
buffer_self_copy(input.bytes_mut(), from, to, len);
|
buffer_self_copy(input.bytes_mut(), from, to, len);
|
||||||
|
|
||||||
@ -656,11 +665,11 @@ where
|
|||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
let first = rand.below(input.bytes().len() as u64 - 1) as usize;
|
let first = rand.below(input.bytes().len() as u64) as usize;
|
||||||
let second = rand.below(input.bytes().len() as u64 - 1) as usize;
|
let second = rand.below(input.bytes().len() as u64) as usize;
|
||||||
let len = max(rand.below((size - max(first, second)) as u64) as usize, 1);
|
let len = 1 + rand.below((size - max(first, second)) as u64) as usize;
|
||||||
|
|
||||||
let tmp = input.bytes()[first..=first + len].to_vec();
|
let tmp = input.bytes()[first..(first + len)].to_vec();
|
||||||
buffer_self_copy(input.bytes_mut(), second, first, len);
|
buffer_self_copy(input.bytes_mut(), second, first, len);
|
||||||
buffer_copy(input.bytes_mut(), &tmp, 0, second, len);
|
buffer_copy(input.bytes_mut(), &tmp, 0, second, len);
|
||||||
|
|
||||||
|
BIN
fuzzers/libfuzzer_libpng/corpus/not_kitty.png
Normal file
BIN
fuzzers/libfuzzer_libpng/corpus/not_kitty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 B |
BIN
fuzzers/libfuzzer_libpng/corpus/not_kitty_alpha.png
Normal file
BIN
fuzzers/libfuzzer_libpng/corpus/not_kitty_alpha.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 376 B |
BIN
fuzzers/libfuzzer_libpng/corpus/not_kitty_gamma.png
Normal file
BIN
fuzzers/libfuzzer_libpng/corpus/not_kitty_gamma.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 228 B |
BIN
fuzzers/libfuzzer_libpng/corpus/not_kitty_icc.png
Normal file
BIN
fuzzers/libfuzzer_libpng/corpus/not_kitty_icc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 427 B |
@ -1,12 +1,8 @@
|
|||||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||||
//! The example harness is built for libpng.
|
//! The example harness is built for libpng.
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate clap;
|
|
||||||
|
|
||||||
// extern crate libc;
|
// extern crate libc;
|
||||||
|
|
||||||
use clap::{App, Arg};
|
|
||||||
use std::{env, path::PathBuf};
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
use afl::{
|
use afl::{
|
||||||
@ -55,69 +51,12 @@ where
|
|||||||
|
|
||||||
/// The main fn, parsing parameters, and starting the fuzzer
|
/// The main fn, parsing parameters, and starting the fuzzer
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let matches = App::new("libAFLrs fuzzer harness")
|
println!("Workdir: {:?}", env::current_dir().unwrap().to_string_lossy().to_string());
|
||||||
.about("libAFLrs fuzzer harness help options.")
|
fuzz(vec![PathBuf::from("./corpus")], 1337).expect("An error occurred while fuzzing");
|
||||||
.arg(
|
|
||||||
Arg::with_name("port")
|
|
||||||
.short("p")
|
|
||||||
.value_name("PORT")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("Broker TCP port to use."),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("dictionary")
|
|
||||||
.short("x")
|
|
||||||
.value_name("DICTIONARY")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.help("Dictionary file to use, can be specified multiple times."),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("statstime")
|
|
||||||
.short("T")
|
|
||||||
.value_name("STATSTIME")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("How often to print statistics in seconds [default: 5, disable: 0]"),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("workdir")
|
|
||||||
.help("Where to write the corpus, also reads the data on start. If more than one is supplied the first will be the work directory, all others will just be initially read from.")
|
|
||||||
.multiple(true)
|
|
||||||
.value_name("WORKDIR")
|
|
||||||
)
|
|
||||||
.get_matches();
|
|
||||||
|
|
||||||
let _ = value_t!(matches, "statstime", u32).unwrap_or(5);
|
|
||||||
let broker_port = value_t!(matches, "port", u16).unwrap_or(1337);
|
|
||||||
|
|
||||||
let workdir = if matches.is_present("workdir") {
|
|
||||||
matches.value_of("workdir").unwrap().to_string()
|
|
||||||
} else {
|
|
||||||
env::current_dir().unwrap().to_string_lossy().to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut dictionary: Option<Vec<PathBuf>> = None;
|
|
||||||
|
|
||||||
if matches.is_present("dictionary") {
|
|
||||||
dictionary = Some(values_t!(matches, "dictionary", PathBuf).unwrap_or_else(|e| e.exit()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut input: Option<Vec<PathBuf>> = None;
|
|
||||||
if matches.is_present("workdir") {
|
|
||||||
input = Some(values_t!(matches, "workdir", PathBuf).unwrap_or_else(|e| e.exit()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if dictionary != None || input != None {
|
|
||||||
println!("Information: the first process started is the broker and only processes the \'-p PORT\' option if present.");
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Workdir: {:?}", workdir);
|
|
||||||
|
|
||||||
fuzz(Some(vec![PathBuf::from("./in1")]), broker_port).expect("An error occurred while fuzzing");
|
|
||||||
//fuzz(input, broker_port).expect("An error occurred while fuzzing");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The actual fuzzer
|
/// The actual fuzzer
|
||||||
fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
|
fn fuzz(corpus_dirs: Vec<PathBuf>, broker_port: u16) -> Result<(), AflError> {
|
||||||
let mut rand = StdRand::new(0);
|
let mut rand = StdRand::new(0);
|
||||||
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
|
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
|
||||||
let stats = SimpleStats::new(|s| println!("{}", s));
|
let stats = SimpleStats::new(|s| println!("{}", s));
|
||||||
@ -165,36 +104,13 @@ fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// TODO close fds in a rusty way
|
|
||||||
unsafe {
|
|
||||||
let null_fname = std::ffi::CString::new("/dev/null").unwrap();
|
|
||||||
let null_file = libc::open(null_fname.as_ptr(), libc::O_RDWR);
|
|
||||||
libc::dup2(null_file, 1);
|
|
||||||
libc::dup2(null_file, 2);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// in case the corpus is empty (on first run), reset
|
// in case the corpus is empty (on first run), reset
|
||||||
if state.corpus().count() < 1 {
|
if state.corpus().count() < 1 {
|
||||||
match input {
|
state
|
||||||
Some(x) => state
|
.load_initial_inputs(&mut executor, &mut restarting_mgr, &corpus_dirs)
|
||||||
.load_initial_inputs(&mut executor, &mut restarting_mgr, &x)
|
.expect(&format!("Failed to load initial corpus at {:?}", &corpus_dirs));
|
||||||
.expect(&format!("Failed to load initial corpus at {:?}", &x)),
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if state.corpus().count() < 1 {
|
|
||||||
println!("Generating random inputs");
|
|
||||||
let mut generator = RandPrintablesGenerator::new(32);
|
|
||||||
state
|
|
||||||
.generate_initial_inputs(&mut rand, &mut executor, &mut generator, &mut restarting_mgr, 4)
|
|
||||||
.expect("Failed to generate initial inputs");
|
|
||||||
println!("We generated {} inputs.", state.corpus().count());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
fuzzer.fuzz_loop(&mut rand, &mut executor, &mut state, &mut restarting_mgr)
|
fuzzer.fuzz_loop(&mut rand, &mut executor, &mut state, &mut restarting_mgr)
|
||||||
}
|
}
|
||||||
|
14
fuzzers/libfuzzer_libpng/test.sh
Normal file → Executable file
14
fuzzers/libfuzzer_libpng/test.sh
Normal file → Executable file
@ -1,18 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
cargo build --release || exit 1
|
cargo build --release || exit 1
|
||||||
cp ./target/release/libfuzzer ./.libfuzzer_test.elf
|
cp ../../target/release/libfuzzer ./.libfuzzer_test.elf
|
||||||
|
|
||||||
RUST_BACKTRACE=full taskset -c 0 ./.libfuzzer_test.elf &
|
RUST_BACKTRACE=full ./.libfuzzer_test.elf
|
||||||
|
|
||||||
test "$!" -gt 0 && {
|
|
||||||
|
|
||||||
usleep 250
|
|
||||||
RUST_BACKTRACE=full taskset -c 1 ./.libfuzzer_test.elf &
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep 20
|
|
||||||
echo "[+] Done"
|
|
||||||
killall .libfuzzer_test.elf
|
|
||||||
rm -rf ./.libfuzzer_test.elf
|
rm -rf ./.libfuzzer_test.elf
|
||||||
|
Loading…
x
Reference in New Issue
Block a user