From ebc95714104215d1cd666de0972785cc5ec787f2 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 12 Feb 2021 23:05:00 +0100 Subject: [PATCH] better mutator --- afl/src/mutators/mutations.rs | 101 ++++++++++-------- fuzzers/libfuzzer_libpng/corpus/not_kitty.png | Bin 0 -> 218 bytes .../corpus/not_kitty_alpha.png | Bin 0 -> 376 bytes .../corpus/not_kitty_gamma.png | Bin 0 -> 228 bytes .../libfuzzer_libpng/corpus/not_kitty_icc.png | Bin 0 -> 427 bytes fuzzers/libfuzzer_libpng/src/mod.rs | 96 ++--------------- fuzzers/libfuzzer_libpng/test.sh | 14 +-- 7 files changed, 63 insertions(+), 148 deletions(-) create mode 100644 fuzzers/libfuzzer_libpng/corpus/not_kitty.png create mode 100644 fuzzers/libfuzzer_libpng/corpus/not_kitty_alpha.png create mode 100644 fuzzers/libfuzzer_libpng/corpus/not_kitty_gamma.png create mode 100644 fuzzers/libfuzzer_libpng/corpus/not_kitty_icc.png mode change 100644 => 100755 fuzzers/libfuzzer_libpng/test.sh diff --git a/afl/src/mutators/mutations.rs b/afl/src/mutators/mutations.rs index 40fc47785e..09009bd561 100644 --- a/afl/src/mutators/mutations.rs +++ b/afl/src/mutators/mutations.rs @@ -120,7 +120,7 @@ pub fn buffer_copy(dst: &mut [u8], src: &[u8], from: usize, to: usize, len: usiz #[inline] fn buffer_set(data: &mut [u8], from: usize, len: usize, val: u8) { debug_assert!(from + len <= data.len()); - for p in &mut data[from..from + len] { + for p in &mut data[from..(from + len)] { *p = val } } @@ -491,12 +491,20 @@ where if size == 0 { return Ok(MutationResult::Skipped); } - let off = rand.below(size as u64 - 1) as usize; - let len = rand.below(min(16, mutator.max_size() as u64 - 1) + 1) as usize; + let off = rand.below(size as u64) 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); - buffer_self_copy(input.bytes_mut(), 0, 0 + off, len); - + buffer_self_copy(input.bytes_mut(), off, off + len, size - off); + Ok(MutationResult::Mutated) } @@ -511,21 +519,25 @@ where I: Input + HasBytesVec, R: Rand, { - let mut size = input.bytes().len(); + let size = input.bytes().len(); if size == 0 { - // Generate random bytes if we're empty. - input - .bytes_mut() - .append(&mut rand.next().to_be_bytes().to_vec()); - size = input.bytes().len(); + 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 off = rand.below(size as u64) 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); + } + } + let val = input.bytes()[rand.below(size as u64) as usize]; - input.bytes_mut().resize(max(size, off + (2 * len) + 1), 0); - buffer_self_copy(input.bytes_mut(), off, off + len, len); + input.bytes_mut().resize(size + len, 0); + buffer_self_copy(input.bytes_mut(), off, off + len, size - off); buffer_set(input.bytes_mut(), off, len, val); Ok(MutationResult::Mutated) @@ -542,20 +554,25 @@ where I: Input + HasBytesVec, R: Rand, { - let mut size = input.bytes().len(); + let size = input.bytes().len(); if size == 0 { - input - .bytes_mut() - .append(&mut rand.next().to_le_bytes().to_vec()); - size = input.bytes().len(); + 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 off = rand.below(size as u64) 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); + } + } + let val = rand.below(256) as u8; - input.bytes_mut().resize(max(size, off + (2 * len) + 1), 0); - buffer_self_copy(input.bytes_mut(), off, off + len, len); + input.bytes_mut().resize(size + len, 0); + buffer_self_copy(input.bytes_mut(), off, off + len, size - off); buffer_set(input.bytes_mut(), off, len, val); Ok(MutationResult::Mutated) @@ -575,16 +592,12 @@ where if size == 0 { 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 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(), start, end - start, val); + buffer_set(input.bytes_mut(), off, len, val); Ok(MutationResult::Mutated) } @@ -603,16 +616,12 @@ where if size == 0 { 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 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(), start, len, val); + buffer_set(input.bytes_mut(), off, len, val); Ok(MutationResult::Mutated) } @@ -632,9 +641,9 @@ where return Ok(MutationResult::Skipped); } - let from = rand.below(input.bytes().len() as u64 - 1) as usize; - let to = rand.below(input.bytes().len() as u64 - 1) as usize; - let len = rand.below((size - core::cmp::max(from, to)) as u64) as usize; + let from = rand.below(input.bytes().len() as u64) as usize; + let to = rand.below(input.bytes().len() 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); @@ -656,11 +665,11 @@ where return Ok(MutationResult::Skipped); } - let first = rand.below(input.bytes().len() as u64 - 1) as usize; - let second = rand.below(input.bytes().len() as u64 - 1) as usize; - let len = max(rand.below((size - max(first, second)) as u64) as usize, 1); + let first = rand.below(input.bytes().len() as u64) as usize; + let second = rand.below(input.bytes().len() as u64) as usize; + 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_copy(input.bytes_mut(), &tmp, 0, second, len); diff --git a/fuzzers/libfuzzer_libpng/corpus/not_kitty.png b/fuzzers/libfuzzer_libpng/corpus/not_kitty.png new file mode 100644 index 0000000000000000000000000000000000000000..eff7c1707b936a8f8df725814f604d454b78b5c3 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X_yc@GT+_~+`TzevkY_wIZRYx+5&y#hyq+?%!C8<`)MX5lF!N|bSRM)^r*U&J;z}U*bz{;0L z1Vuw`eoAIqC5i?kD`P_|6GMoGiCWXn12ss3YzWRzD=AMbN@Z|N$xljE@XSq2PYp^< WOsOn9nQ8-6#Ng@b=d#Wzp$PyV*n0l} literal 0 HcmV?d00001 diff --git a/fuzzers/libfuzzer_libpng/corpus/not_kitty_gamma.png b/fuzzers/libfuzzer_libpng/corpus/not_kitty_gamma.png new file mode 100644 index 0000000000000000000000000000000000000000..939d9d29a9b9f95bac5e9a72854361ee85469921 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmTQ929t;oCfmw1AIbU z)6Sgv|NlRbXFM})=KnKxKI=t+9LW;bh?3y^w370~qErUQl>DSr1<%~X^wgl##FWay zlc_d9MbVxvjv*GO?@o5)YH;9THa`3B|5>?^8?LvjJ}xLe>!7e@k)r^sLedir0mCVe z=5sMjEm$*~tHD+}{NS_$nMdb|ABqg-@UGMMsZ=uY-X%Cq@&3vmZ%&@H{P?6&+U!yq VvuXWlo?M_c44$rjF6*2UngF4cP+$N6 literal 0 HcmV?d00001 diff --git a/fuzzers/libfuzzer_libpng/corpus/not_kitty_icc.png b/fuzzers/libfuzzer_libpng/corpus/not_kitty_icc.png new file mode 100644 index 0000000000000000000000000000000000000000..f0c7804d99829cc6307c1c6ae9915cf42d555414 GIT binary patch literal 427 zcmV;c0aX5pP)9xSWu9|B*4Isn^#g47m^r~thH)GiR<@yX0fO)OF<2Kt#qCldyUF#H?{4jV?XGw9)psxE&K1B1m^ z1_tH{2(hG@3=G>_85ksPA;eS`Ffj19FfeR8pIlm01~rBeWCZ{dbvfq;rA3DT000kA zOjJc?%*_A){{R30GnreSaefwW^{L9a%BKPWN%_+AW3auXJt}l zVPtu6$z?nM003J_L_t(I%iWVf3V=Wi12fJ3|IHp$*hSlV@t||fKp?cDK@bHXV&o_g zF_hw;3ILUGteXmeJsVfSmcVJno)^MdQwU3bFHCtNG)uY>mLcD%`0UBaIq~Fq8#dBr V12uok3~c}a002ovPDHLkV1nKBo!S5Z literal 0 HcmV?d00001 diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index d18702a311..c8f120c1a9 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -1,12 +1,8 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -#[macro_use] -extern crate clap; - // extern crate libc; -use clap::{App, Arg}; use std::{env, path::PathBuf}; use afl::{ @@ -55,69 +51,12 @@ where /// The main fn, parsing parameters, and starting the fuzzer pub fn main() { - let matches = App::new("libAFLrs fuzzer harness") - .about("libAFLrs fuzzer harness help options.") - .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> = None; - - if matches.is_present("dictionary") { - dictionary = Some(values_t!(matches, "dictionary", PathBuf).unwrap_or_else(|e| e.exit())); - } - - let mut input: Option> = 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"); + println!("Workdir: {:?}", env::current_dir().unwrap().to_string_lossy().to_string()); + fuzz(vec![PathBuf::from("./corpus")], 1337).expect("An error occurred while fuzzing"); } /// The actual fuzzer -fn fuzz(input: Option>, broker_port: u16) -> Result<(), AflError> { +fn fuzz(corpus_dirs: Vec, broker_port: u16) -> Result<(), AflError> { let mut rand = StdRand::new(0); // 'While the stats are state, they are usually used in the broker - which is likely never restarted let stats = SimpleStats::new(|s| println!("{}", s)); @@ -165,36 +104,13 @@ fn fuzz(input: Option>, 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 if state.corpus().count() < 1 { - match input { - Some(x) => state - .load_initial_inputs(&mut executor, &mut restarting_mgr, &x) - .expect(&format!("Failed to load initial corpus at {:?}", &x)), - None => (), - } + state + .load_initial_inputs(&mut executor, &mut restarting_mgr, &corpus_dirs) + .expect(&format!("Failed to load initial corpus at {:?}", &corpus_dirs)); 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) } diff --git a/fuzzers/libfuzzer_libpng/test.sh b/fuzzers/libfuzzer_libpng/test.sh old mode 100644 new mode 100755 index c115d14436..5f5b2b7176 --- a/fuzzers/libfuzzer_libpng/test.sh +++ b/fuzzers/libfuzzer_libpng/test.sh @@ -1,18 +1,8 @@ #!/bin/sh 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