From 0a5e8039cc088a9f142f4ea8447ad56c0bc4a231 Mon Sep 17 00:00:00 2001 From: rileyseefeldt Date: Mon, 12 Jan 2026 17:28:13 -0700 Subject: [PATCH 1/6] fuzzing xmllint example --- examples/xmllint/linux_xmllint_fuzz.py | 73 ++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 examples/xmllint/linux_xmllint_fuzz.py diff --git a/examples/xmllint/linux_xmllint_fuzz.py b/examples/xmllint/linux_xmllint_fuzz.py new file mode 100644 index 0000000..957f0d7 --- /dev/null +++ b/examples/xmllint/linux_xmllint_fuzz.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 + +import os +import shutil + +import angr +import claripy +from angr.rustylib.fuzzer import Fuzzer, InMemoryCorpus, ClientStats +from angr import sim_options as so + + +def create_corpus() -> list[bytes]: + return [ + b"", + b"b", + b"", + b"]>&x;", + ] + + +def apply_fn(state: angr.SimState, data: bytes) -> angr.SimState: + # Arrange a recognizable return address + state.project.factory.cc().return_addr.set_value(state, 0xDEADBEEF) + s = state.posix.stdin + s.content = [(claripy.BVV(data), claripy.BVV(len(data), state.arch.bits))] + if hasattr(s, "pos"): + s.pos = 0 + return state + + +def main() -> None: + target = shutil.which("xmllint") + if not target or not os.path.exists(target): + raise SystemExit("xmllint not found") + + # xmllint CLI: read from stdin with '-' and keep output quiet/nonet + xmllint_args = [target, "--noout", "--nonet", "--recover", "--noent", "-"] + + project = angr.Project(target, auto_load_libs=True, use_sim_procedures=False) + base_state = project.factory.entry_state( + args=xmllint_args, + add_options={ + so.ZERO_FILL_UNCONSTRAINED_MEMORY, + so.ZERO_FILL_UNCONSTRAINED_REGISTERS, + }, + ) + + corpus = InMemoryCorpus.from_list(create_corpus()) + solutions = InMemoryCorpus() + + fuzzer = Fuzzer( + base_state=base_state, + apply_fn=apply_fn, + corpus=corpus, + solutions=solutions, + timeout=100, + seed=0, + ) + + def progress_callback(stats: ClientStats, type_: str, _client_id: int) -> None: + print( + f"[{type_}] C: {stats.corpus_size}, O: {stats.objective_size}, E: {stats.executions}, E/s: {stats.execs_per_sec_pretty}, Cov: {stats.edges_hit}/{stats.edges_total}" + ) + + fuzzer.run_once(progress_callback=progress_callback) + print(f"Corpus now has {len(fuzzer.corpus())} inputs.") + print(f"Corpus inputs: \n{fuzzer.corpus().to_bytes_list()}") + print(f"Found {len(fuzzer.solutions())} solutions.") + print(f"Found the following solutions: \n{fuzzer.solutions().to_bytes_list()}") + + +if __name__ == "__main__": + main() From 0e34c15d81c455264a8b2932eeb0df92a2b02aa9 Mon Sep 17 00:00:00 2001 From: rileyseefeldt Date: Tue, 13 Jan 2026 19:56:58 -0700 Subject: [PATCH 2/6] added test function and xmllint binary --- examples/xmllint/linux_xmllint_fuzz.py | 73 ------------------- examples/xmllint/solve.py | 95 +++++++++++++++++++++++++ examples/xmllint/xmllint_bin | Bin 0 -> 80840 bytes 3 files changed, 95 insertions(+), 73 deletions(-) delete mode 100644 examples/xmllint/linux_xmllint_fuzz.py create mode 100644 examples/xmllint/solve.py create mode 100755 examples/xmllint/xmllint_bin diff --git a/examples/xmllint/linux_xmllint_fuzz.py b/examples/xmllint/linux_xmllint_fuzz.py deleted file mode 100644 index 957f0d7..0000000 --- a/examples/xmllint/linux_xmllint_fuzz.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python3 - -import os -import shutil - -import angr -import claripy -from angr.rustylib.fuzzer import Fuzzer, InMemoryCorpus, ClientStats -from angr import sim_options as so - - -def create_corpus() -> list[bytes]: - return [ - b"", - b"b", - b"", - b"]>&x;", - ] - - -def apply_fn(state: angr.SimState, data: bytes) -> angr.SimState: - # Arrange a recognizable return address - state.project.factory.cc().return_addr.set_value(state, 0xDEADBEEF) - s = state.posix.stdin - s.content = [(claripy.BVV(data), claripy.BVV(len(data), state.arch.bits))] - if hasattr(s, "pos"): - s.pos = 0 - return state - - -def main() -> None: - target = shutil.which("xmllint") - if not target or not os.path.exists(target): - raise SystemExit("xmllint not found") - - # xmllint CLI: read from stdin with '-' and keep output quiet/nonet - xmllint_args = [target, "--noout", "--nonet", "--recover", "--noent", "-"] - - project = angr.Project(target, auto_load_libs=True, use_sim_procedures=False) - base_state = project.factory.entry_state( - args=xmllint_args, - add_options={ - so.ZERO_FILL_UNCONSTRAINED_MEMORY, - so.ZERO_FILL_UNCONSTRAINED_REGISTERS, - }, - ) - - corpus = InMemoryCorpus.from_list(create_corpus()) - solutions = InMemoryCorpus() - - fuzzer = Fuzzer( - base_state=base_state, - apply_fn=apply_fn, - corpus=corpus, - solutions=solutions, - timeout=100, - seed=0, - ) - - def progress_callback(stats: ClientStats, type_: str, _client_id: int) -> None: - print( - f"[{type_}] C: {stats.corpus_size}, O: {stats.objective_size}, E: {stats.executions}, E/s: {stats.execs_per_sec_pretty}, Cov: {stats.edges_hit}/{stats.edges_total}" - ) - - fuzzer.run_once(progress_callback=progress_callback) - print(f"Corpus now has {len(fuzzer.corpus())} inputs.") - print(f"Corpus inputs: \n{fuzzer.corpus().to_bytes_list()}") - print(f"Found {len(fuzzer.solutions())} solutions.") - print(f"Found the following solutions: \n{fuzzer.solutions().to_bytes_list()}") - - -if __name__ == "__main__": - main() diff --git a/examples/xmllint/solve.py b/examples/xmllint/solve.py new file mode 100644 index 0000000..199645e --- /dev/null +++ b/examples/xmllint/solve.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 + +import os + +import angr +import claripy +from angr.rustylib.fuzzer import Fuzzer, InMemoryCorpus, ClientStats +from angr import sim_options as so + + +def create_corpus(): + return [ + b"]>&y;", # one byte flip ('y'->'x') enables entity resolution path + ] + + +def apply_fn(state: angr.SimState, data: bytes): + # Arrange a recognizable return address + state.project.factory.cc().return_addr.set_value(state, 0xDEADBEEF) + s = state.posix.stdin + s.content = [(claripy.BVV(data), claripy.BVV(len(data), state.arch.bits))] + if hasattr(s, "pos"): + s.pos = 0 + return state + + +def main(verbose=True, seed=0): + target = os.path.join(os.path.dirname(__file__), "xmllint_bin") + + # xmllint CLI: read from stdin with '-' and keep output quiet/nonet + xmllint_args = [target, "--noout", "--nonet", "--recover", "--noent", "-"] + + project = angr.Project(target, auto_load_libs=True, use_sim_procedures=False) + base_state = project.factory.entry_state( + args=xmllint_args, + add_options={ + so.ZERO_FILL_UNCONSTRAINED_MEMORY, + so.ZERO_FILL_UNCONSTRAINED_REGISTERS, + }, + ) + + corpus = InMemoryCorpus.from_list(create_corpus()) + solutions = InMemoryCorpus() + + fuzzer = Fuzzer( + base_state=base_state, + apply_fn=apply_fn, + corpus=corpus, + solutions=solutions, + timeout=0, + seed=seed, + ) + + def progress_callback(stats: ClientStats, type_: str, _client_id: int): + print( + f"[{type_}] C: {stats.corpus_size}, O: {stats.objective_size}, E: {stats.executions}, E/s: {stats.execs_per_sec_pretty}, Cov: {stats.edges_hit}/{stats.edges_total}" + ) + + before = len(fuzzer.corpus()) + idx = fuzzer.run_once(progress_callback=progress_callback if verbose else None) + new_input = fuzzer.corpus()[idx] + if verbose: + print(f"Corpus now has {len(fuzzer.corpus())} inputs.") + print(f"Corpus inputs: \n{fuzzer.corpus().to_bytes_list()}") + print(f"Found {len(fuzzer.solutions())} solutions.") + print(f"Found the following solutions: \n{fuzzer.solutions().to_bytes_list()}") + after = len(fuzzer.corpus()) + return idx, before, after, new_input + + +def test(): + idx, before, after, new_input = main(verbose=False) + # Basic corpus growth sanity checks + assert after == before + 1 + assert 0 <= idx < after + + # Desired mutation check: change entity reference '&y;' -> '&x;' + expected = b"]>&x;" + assert new_input == expected + return True + +#looks for right seed to get deterministic answer +def search_for_seed(): + seed = 1 + expected = b"]>&x;" + while True: + print(f"Attempting Seed: {seed}") + _, _, _, new_input = main(verbose=False, seed=seed) + if expected == new_input: + print(f"Found Seed: {seed}") + break + seed += 1 + +if __name__ == "__main__": + search_for_seed() diff --git a/examples/xmllint/xmllint_bin b/examples/xmllint/xmllint_bin new file mode 100755 index 0000000000000000000000000000000000000000..760c2d1281f7707b7534f831843f6963f4a9f3e9 GIT binary patch literal 80840 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 uD~ Date: Tue, 13 Jan 2026 20:42:40 -0700 Subject: [PATCH 3/6] found seed --- examples/xmllint/solve.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/xmllint/solve.py b/examples/xmllint/solve.py index 199645e..cb4259a 100644 --- a/examples/xmllint/solve.py +++ b/examples/xmllint/solve.py @@ -23,8 +23,8 @@ def apply_fn(state: angr.SimState, data: bytes): s.pos = 0 return state - -def main(verbose=True, seed=0): +#SEED VALUE NEEDED FOR TEST +def main(verbose=True, seed=12751): target = os.path.join(os.path.dirname(__file__), "xmllint_bin") # xmllint CLI: read from stdin with '-' and keep output quiet/nonet @@ -58,13 +58,14 @@ def progress_callback(stats: ClientStats, type_: str, _client_id: int): before = len(fuzzer.corpus()) idx = fuzzer.run_once(progress_callback=progress_callback if verbose else None) - new_input = fuzzer.corpus()[idx] + after = len(fuzzer.corpus()) + #take last mutation (should be the new one) + new_input = fuzzer.corpus()[after - 1] if verbose: print(f"Corpus now has {len(fuzzer.corpus())} inputs.") print(f"Corpus inputs: \n{fuzzer.corpus().to_bytes_list()}") print(f"Found {len(fuzzer.solutions())} solutions.") print(f"Found the following solutions: \n{fuzzer.solutions().to_bytes_list()}") - after = len(fuzzer.corpus()) return idx, before, after, new_input @@ -92,4 +93,4 @@ def search_for_seed(): seed += 1 if __name__ == "__main__": - search_for_seed() + main() From 9f320c1ef2626aaeddadf8da34ca3ade8edb8a60 Mon Sep 17 00:00:00 2001 From: rileyseefeldt Date: Tue, 13 Jan 2026 21:03:23 -0700 Subject: [PATCH 4/6] added to tester script --- tests/test_examples.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_examples.py b/tests/test_examples.py index 23a6569..b9aec50 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -262,6 +262,10 @@ def test_defcon2019quals_veryandroidoso(): exampletest_single("defcon2019quals_veryandroidoso") +def test_xmllint(): + exampletest_single("xmllint") + + ## END EXAMPLE TESTS From 3fa2ae4352b69940167908ea9f8f35be534d5e17 Mon Sep 17 00:00:00 2001 From: rileyseefeldt Date: Wed, 14 Jan 2026 14:23:47 -0700 Subject: [PATCH 5/6] fix lint errors --- examples/xmllint/solve.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/examples/xmllint/solve.py b/examples/xmllint/solve.py index cb4259a..a8cfa05 100644 --- a/examples/xmllint/solve.py +++ b/examples/xmllint/solve.py @@ -23,7 +23,8 @@ def apply_fn(state: angr.SimState, data: bytes): s.pos = 0 return state -#SEED VALUE NEEDED FOR TEST + +# SEED VALUE NEEDED FOR TEST def main(verbose=True, seed=12751): target = os.path.join(os.path.dirname(__file__), "xmllint_bin") @@ -52,14 +53,18 @@ def main(verbose=True, seed=12751): ) def progress_callback(stats: ClientStats, type_: str, _client_id: int): - print( - f"[{type_}] C: {stats.corpus_size}, O: {stats.objective_size}, E: {stats.executions}, E/s: {stats.execs_per_sec_pretty}, Cov: {stats.edges_hit}/{stats.edges_total}" + msg = ( + f"[{type_}] " + f"C: {stats.corpus_size}, O: {stats.objective_size}, " + f"E: {stats.executions}, E/s: {stats.execs_per_sec_pretty}, " + f"Cov: {stats.edges_hit}/{stats.edges_total}" ) + print(msg) before = len(fuzzer.corpus()) idx = fuzzer.run_once(progress_callback=progress_callback if verbose else None) after = len(fuzzer.corpus()) - #take last mutation (should be the new one) + # take last mutation (should be the new one) new_input = fuzzer.corpus()[after - 1] if verbose: print(f"Corpus now has {len(fuzzer.corpus())} inputs.") @@ -74,13 +79,14 @@ def test(): # Basic corpus growth sanity checks assert after == before + 1 assert 0 <= idx < after - + # Desired mutation check: change entity reference '&y;' -> '&x;' expected = b"]>&x;" assert new_input == expected return True -#looks for right seed to get deterministic answer + +# looks for right seed to get deterministic answer def search_for_seed(): seed = 1 expected = b"]>&x;" @@ -92,5 +98,6 @@ def search_for_seed(): break seed += 1 + if __name__ == "__main__": main() From e42874fc542d1449e99f25a67198f40c2d979acf Mon Sep 17 00:00:00 2001 From: rileyseefeldt Date: Wed, 14 Jan 2026 15:42:28 -0700 Subject: [PATCH 6/6] fixed type errors --- examples/xmllint/solve.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/xmllint/solve.py b/examples/xmllint/solve.py index a8cfa05..97869f9 100644 --- a/examples/xmllint/solve.py +++ b/examples/xmllint/solve.py @@ -14,14 +14,17 @@ def create_corpus(): ] -def apply_fn(state: angr.SimState, data: bytes): +def apply_fn(state: angr.SimState, data: bytes) -> None: # Arrange a recognizable return address - state.project.factory.cc().return_addr.set_value(state, 0xDEADBEEF) + p = state.project + if p is not None: + ra = p.factory.cc().return_addr + if ra is not None: + ra.set_value(state, 0xDEADBEEF) s = state.posix.stdin s.content = [(claripy.BVV(data), claripy.BVV(len(data), state.arch.bits))] if hasattr(s, "pos"): s.pos = 0 - return state # SEED VALUE NEEDED FOR TEST