-
-
Notifications
You must be signed in to change notification settings - Fork 323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multipart Input support #1617
Merged
Merged
Multipart Input support #1617
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
5119a71
initial commit: multipart
addisoncrump b1b376a
document + wrap up baby fuzzer
addisoncrump f0d263e
oops
addisoncrump c3a025f
core
addisoncrump 1db7d0a
add from method, option to iter
addisoncrump 032f5bd
improve example; use minmap; fix initial_mut
addisoncrump 81a5b6e
bindings
addisoncrump e9e48f9
clippy, again
addisoncrump 67284e2
moar clippy
addisoncrump f3b1da6
fmt
addisoncrump b26fd71
drop rand dep because we don't need it, actually
addisoncrump 273ff7e
docfix
addisoncrump 6513297
ok actually fix docs pls
addisoncrump File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
libpng-* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
[package] | ||
name = "baby_fuzzer_multi" | ||
version = "0.10.0" | ||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>", "Addison Crump <me@addisoncrump.info>"] | ||
edition = "2021" | ||
|
||
[features] | ||
default = ["std"] | ||
tui = [] | ||
std = [] | ||
|
||
[profile.dev] | ||
panic = "abort" | ||
|
||
[profile.release] | ||
panic = "abort" | ||
lto = true | ||
codegen-units = 1 | ||
opt-level = 3 | ||
debug = true | ||
|
||
[dependencies] | ||
libafl = { path = "../../libafl/", features = ["multipart_inputs"] } | ||
libafl_bolts = { path = "../../libafl_bolts/" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Baby fuzzer multi | ||
|
||
This is a minimalistic example about how to create a libafl based fuzzer for targets with multipart inputs. | ||
|
||
It runs on a single core until a crash occurs and then exits. | ||
|
||
The tested program is a simple Rust function without any instrumentation. | ||
For real fuzzing, you will want to add some sort to add coverage or other feedback. | ||
|
||
You can run this example using `cargo run`, and you can enable the TUI feature by running `cargo run --features tui`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
#[cfg(windows)] | ||
use std::ptr::write_volatile; | ||
use std::{path::PathBuf, ptr::write}; | ||
|
||
#[cfg(feature = "tui")] | ||
use libafl::monitors::tui::{ui::TuiUI, TuiMonitor}; | ||
#[cfg(not(feature = "tui"))] | ||
use libafl::monitors::SimpleMonitor; | ||
use libafl::{ | ||
corpus::{InMemoryCorpus, OnDiskCorpus}, | ||
events::SimpleEventManager, | ||
executors::{inprocess::InProcessExecutor, ExitKind}, | ||
feedback_or_fast, | ||
feedbacks::{CrashFeedback, MaxMapFeedback, MinMapFeedback}, | ||
fuzzer::{Fuzzer, StdFuzzer}, | ||
inputs::{BytesInput, HasTargetBytes, MultipartInput}, | ||
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, | ||
observers::StdMapObserver, | ||
schedulers::QueueScheduler, | ||
stages::mutational::StdMutationalStage, | ||
state::StdState, | ||
Evaluator, | ||
}; | ||
use libafl_bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice}; | ||
|
||
/// Coverage map with explicit assignments due to the lack of instrumentation | ||
static mut SIGNALS: [u8; 128] = [0; 128]; | ||
static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() }; | ||
|
||
/// "Coverage" map for count, just to help things along | ||
static mut LAST_COUNT: [usize; 1] = [usize::MAX]; | ||
static mut LAST_COUNT_PTR: *mut usize = unsafe { LAST_COUNT.as_mut_ptr() }; | ||
|
||
/// Assign a signal to the signals map | ||
fn signals_set(idx: usize) { | ||
unsafe { write(SIGNALS_PTR.add(idx), 1) }; | ||
} | ||
|
||
/// Assign a count to the count "map" | ||
fn count_set(count: usize) { | ||
unsafe { LAST_COUNT[0] = count }; | ||
} | ||
|
||
#[allow(clippy::similar_names, clippy::manual_assert)] | ||
pub fn main() { | ||
// The closure that we want to fuzz | ||
let mut harness = |input: &MultipartInput<BytesInput>| { | ||
let mut count = input.parts().len(); | ||
for (i, input) in input.parts().iter().enumerate() { | ||
let target = input.target_bytes(); | ||
let buf = target.as_slice(); | ||
signals_set(i * 8); | ||
if !buf.is_empty() && buf[0] == b'a' { | ||
signals_set(1 + i * 8); | ||
if buf.len() > 1 && buf[1] == b'b' { | ||
signals_set(2 + i * 8); | ||
if buf.len() > 2 && buf[2] == b'c' { | ||
count -= 1; | ||
} | ||
} | ||
} | ||
} | ||
if count == 0 { | ||
#[cfg(unix)] | ||
panic!("Artificial bug triggered =)"); | ||
|
||
// panic!() raises a STATUS_STACK_BUFFER_OVERRUN exception which cannot be caught by the exception handler. | ||
// Here we make it raise STATUS_ACCESS_VIOLATION instead. | ||
// Extending the windows exception handler is a TODO. Maybe we can refer to what winafl code does. | ||
// https://github.com/googleprojectzero/winafl/blob/ea5f6b85572980bb2cf636910f622f36906940aa/winafl.c#L728 | ||
#[cfg(windows)] | ||
unsafe { | ||
write_volatile(0 as *mut u32, 0); | ||
} | ||
} | ||
|
||
// without this, artificial bug is not found | ||
// maybe interesting to try to auto-derive this, researchers! :) | ||
count_set(count); | ||
|
||
ExitKind::Ok | ||
}; | ||
|
||
// Create an observation channel using the signals map | ||
let signals_observer = | ||
unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; | ||
let mut count_observer = | ||
unsafe { StdMapObserver::from_mut_ptr("count", LAST_COUNT_PTR, LAST_COUNT.len()) }; | ||
*count_observer.initial_mut() = usize::MAX; // we are minimising! | ||
|
||
// Feedback to rate the interestingness of an input | ||
let signals_feedback = MaxMapFeedback::new(&signals_observer); | ||
let count_feedback = MinMapFeedback::new(&count_observer); | ||
|
||
let mut feedback = feedback_or_fast!(count_feedback, signals_feedback); | ||
|
||
// A feedback to choose if an input is a solution or not | ||
let mut objective = CrashFeedback::new(); | ||
|
||
// create a State from scratch | ||
let mut state = StdState::new( | ||
// RNG | ||
StdRand::with_seed(current_nanos()), | ||
// Corpus that will be evolved, we keep it in memory for performance | ||
InMemoryCorpus::new(), | ||
// Corpus in which we store solutions (crashes in this example), | ||
// on disk so the user can get them after stopping the fuzzer | ||
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), | ||
// States of the feedbacks. | ||
// The feedbacks can report the data that should persist in the State. | ||
&mut feedback, | ||
// Same for objective feedbacks | ||
&mut objective, | ||
) | ||
.unwrap(); | ||
|
||
// The Monitor trait define how the fuzzer stats are displayed to the user | ||
#[cfg(not(feature = "tui"))] | ||
let mon = SimpleMonitor::new(|s| println!("{s}")); | ||
#[cfg(feature = "tui")] | ||
let ui = TuiUI::with_version(String::from("Baby Fuzzer"), String::from("0.0.1"), false); | ||
#[cfg(feature = "tui")] | ||
let mon = TuiMonitor::new(ui); | ||
|
||
// The event manager handle the various events generated during the fuzzing loop | ||
// such as the notification of the addition of a new item to the corpus | ||
let mut mgr = SimpleEventManager::new(mon); | ||
|
||
// A queue policy to get testcasess from the corpus | ||
let scheduler = QueueScheduler::new(); | ||
|
||
// A fuzzer with feedbacks and a corpus scheduler | ||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); | ||
|
||
// Create the executor for an in-process function with just one observer | ||
let mut executor = InProcessExecutor::new( | ||
&mut harness, | ||
tuple_list!(signals_observer, count_observer), | ||
&mut fuzzer, | ||
&mut state, | ||
&mut mgr, | ||
) | ||
.expect("Failed to create the Executor"); | ||
|
||
// a generator here is not generalisable | ||
let initial = MultipartInput::from([ | ||
("part", BytesInput::new(vec![b'h', b'e', b'l', b'l', b'o'])), | ||
("part", BytesInput::new(vec![b'h', b'e', b'l', b'l', b'o'])), | ||
("part", BytesInput::new(vec![b'h', b'e', b'l', b'l', b'o'])), | ||
("part", BytesInput::new(vec![b'h', b'e', b'l', b'l', b'o'])), | ||
]); | ||
|
||
fuzzer | ||
.evaluate_input(&mut state, &mut executor, &mut mgr, initial) | ||
.unwrap(); | ||
|
||
// Setup a mutational stage with a basic bytes mutator | ||
let mutator = StdScheduledMutator::new(havoc_mutations()); | ||
let mut stages = tuple_list!(StdMutationalStage::new(mutator)); | ||
|
||
fuzzer | ||
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr) | ||
.expect("Error in the fuzzing loop"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
had to "cheat" here a little bit 😉