def test(): from manticore.native import Manticore from manticore.core.smtlib import operators if __name__ == "__main__": m = Manticore("./angrme") else: m = Manticore("./test_hxp2018_angrme/angrme") m.context["solved"] = False max_length = 40 # maximum flag length (rough guess-timate) m.verbosity(1) @m.hook(0x555555555187) def inject_symbolic_input(state): # skip expensive call to fgets state.cpu.RIP = 0x5555555551A0 # manually inject symbolic variable in place of input with m.locked_context() as context: solution = state.new_symbolic_buffer(max_length) # constrain flag format state.constrain(solution[0] == ord("h")) state.constrain(solution[1] == ord("x")) state.constrain(solution[2] == ord("p")) state.constrain(solution[3] == ord("{")) # constrain characters to be printable ASCII or null byte for i in range(max_length): state.constrain( operators.OR( solution[i] == 0, operators.AND(ord(" ") <= solution[i], solution[i] <= ord("}")), ) ) address = state.cpu.RSP + 0x30 context["input_address"] = address print("[+] input address: " + hex(state.cpu.RSP + 0x30)) state.cpu.write_bytes(address, solution) @m.hook(0x555555556390) def abandon(state): print("[-] abandoning path") state.abandon() @m.hook(0x555555556370) def success(state): with m.locked_context() as context: print("[+] found success path") address = context["input_address"] flag = "".join(map(chr, state.solve_buffer(address, max_length))) print("[+] flag: " + flag) with m.locked_context() as context: if "hxp{4nd_n0w_f0r_s0m3_r3al_ch4ll3ng3}" in flag: context["solved"] = True m.kill() m.run() assert m.context["solved"]
def setUp(self): dirname = os.path.dirname(__file__) self.m = Manticore(os.path.join(dirname, 'binaries', 'arguments_linux_amd64'), argv=['argv', 'mc', 'argface']) self.concrete_instance = Manticore(os.path.join( dirname, 'binaries', 'arguments_linux_amd64'), argv=['argv', 'mc', 'argface']) self.concrete_instance.register_plugin(ConcretePlugin()) '''
def setUp(self): dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, "binaries", "arguments_linux_amd64"), argv=["argv", "mc", "argface"], ) self.concrete_instance = Manticore( os.path.join(dirname, "binaries", "arguments_linux_amd64"), argv=["argv", "mc", "argface"], ) self.concrete_instance.register_plugin(ConcretePlugin()) """
def test_introspect_daemon(self): self.history = [] m = Manticore(ms_file, stdin_size=17) m.register_daemon(self.introspect_loop) m.run() sleep(1) # Leave time for the callback to fire after we've finished self.assertGreater(len(self.history), 0) progression = [] for hist in self.history: hist = hist.values() progression.append(( sum(1 if (st.state_list == StateLists.ready) else 0 for st in hist), sum(1 if (st.state_list == StateLists.busy) else 0 for st in hist), sum(1 if (st.state_list == StateLists.terminated) else 0 for st in hist), )) self.assertEqual(progression[-1][0], 0) # Once finished, we have no ready states self.assertEqual(progression[-1][1], 0) # Once finished, we have no busy states # Once finished, we have only terminated states. self.assertGreater(progression[-1][2], 0) f = io.StringIO() with contextlib.redirect_stdout(f): m.pretty_print_states() self.assertIn("Terminated States: {}".format(progression[-1][2]), f.getvalue())
def setUp(self): core = config.get_group("core") core.seed = 61 core.mprocessing = core.mprocessing.single dirname = os.path.dirname(__file__) self.m = Manticore(os.path.join(dirname, "binaries", "basic_linux_amd64"), policy="random")
def test_daemon(self): self.fired = False m = Manticore(ms_file, stdin_size=17) m.register_daemon(self.daemon) m.run() self.assertTrue(self.fired)
def test_resume(self): m = Manticore(ms_file, stdin_size=17) # First instruction of `main` @m.hook(0x4009AE) def serialize(state): with m.locked_context() as context: if context.get("kill", False): raise TerminateState("Abandoning...") context["kill"] = True raise SerializeState("/tmp/ms_checkpoint.pkl") m.run() self.assertEqual(m.count_terminated_states(), 1) for state in m.terminated_states: self.assertEqual(state.cpu.PC, 0x4009AE) m = Manticore.from_saved_state("/tmp/ms_checkpoint.pkl") self.assertEqual(m.count_ready_states(), 1) for st in m.ready_states: self.assertEqual(state.cpu.PC, 0x4009AE) m.run() self.assertEqual(m.count_terminated_states(), 18) self.assertTrue( any("exit status: 0" in str(st._terminated_by) for st in m.terminated_states) ) m.finalize() for st in m.terminated_states: if "exit status: 0" in str(st._terminated_by): self.assertEqual(st.solve_one(st.input_symbols[0]), b"coldlikeminisodas")
def setUp(self): dirname = os.path.dirname(__file__) self.concrete_instance = Manticore(os.path.join(dirname, "binaries", "rusticorn")) self.concrete_instance.register_plugin(ResumeUnicornPlugin()) self.concrete_instance.add_hook(self.MAIN, callback=self.hook_main) self.concrete_instance.add_hook(self.PRE_LOOP, callback=self.hook_pre_loop) self.concrete_instance.add_hook(self.DONE, callback=self.hook_ret_good) self.concrete_instance.add_hook(self.FAIL, callback=self.hook_ret_fail)
def verify(argv): logger.debug(f'Verifying program "{argv}"') # Address and stack_size are from linux.py # TODO(yan): Refactor these constants into a reachable value in platform qemu.start("arm", argv, va_size=stack_top, stack_size=stack_size) gdb.start("arm", argv) m = Manticore(argv[0], argv[1:]) m.verbosity = 2 init_logging() logger.setLevel(logging.DEBUG) @m.hook(None) def on_instruction(state): """ Handle all the hooks for each instruction executed. Ordered as: pre_qemu * qemu exec * post_qemu // svc synchronization happens here (mmap specifically) pre_mcore * mcore exec * post_mcore // all memory written in a mcore syscall gets moved to qemu here """ global initialized, last_instruction # Initialize our state to QEMU's if not initialized: initialize(state) initialized = True if last_instruction: post_mcore(state, last_instruction) # Kernel helpers are inline in QEMU; do nothing if (state.cpu.PC >> 16) == 0xFFFF: return pre_qemu(state) last_mnemonic = [x.strip() for x in gdb.getInstruction().split(":") ][1].split("\t")[0] gdb.stepi() post_qemu(state, last_mnemonic) last_instruction = state.cpu.instruction pre_mcore(state) m.run()
def test(): from manticore.native import Manticore m = Manticore("test_ais3_crackme/ais3_crackme", ["a" * 30]) buffer_addr = 0 num_bytes = 24 with m.locked_context() as w: w[1] = False @m.hook(0x4005CD) def hook(state): print("fake 2 args EDI=2") state.cpu.EDI = 0x2 @m.hook(0x4005F3) def hook(state): print("retreive buffer from rax") global buffer_addr # print state.cpu.read_int(state.cpu.RAX), 'yoo' # assert 0 solution = state.new_symbolic_buffer(num_bytes) state.constrain(solution[0] == ord("a")) state.constrain(solution[1] == ord("i")) state.constrain(solution[2] == ord("s")) state.constrain(solution[3] == ord("3")) state.constrain(solution[4] == ord("{")) buffer_addr = state.cpu.read_int(state.cpu.RAX) with m.locked_context() as w: w[1] = buffer_addr print("buffer addr : %08x " % (buffer_addr)) state.cpu.write_bytes(buffer_addr, solution) @m.hook(0x40060E) def hook(state): state.abandon() print("failure path") @m.hook(0x400602) def hook(state): print("win path: attemping to solve") with m.locked_context() as w: buffer_addr = w[1] res = "".join(map(chr, state.solve_buffer(buffer_addr, num_bytes))) print("flag: %s" % res) if res == "ais3{I_tak3_g00d_n0t3s}": with m.locked_context() as w: w[1] = True m.kill() m.verbosity = 1 m.run() with m.locked_context() as w: assert w[1]
def test_custom_introspector(self): self.history = [] m = Manticore(ms_file, introspection_plugin_type=MyIntrospector, stdin_size=17) m.register_daemon(self.introspect_loop) m.run() self.assertGreater(len(self.history), 0) self.assertTrue( any( getattr(st, "i_am_custom", False) for st in self.history[-1].values()))
def setUp(self): core = config.get_group("core") core.seed = 61 core.mprocessing = core.mprocessing.single dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, "binaries", "basic_state_merging"), policy="random" ) self.plugin = self.StateCounter() self.m.register_plugin(Merger()) self.m.register_plugin(self.plugin)
def benchmark(program): print(f"[*] Benchmarking program \"{program}\"") m = Manticore(program) m.run(should_profile=True) results = m._executor.dump_stats() if results is None: print(f"[*] Failed to collect stats for program {program}") return display(results) return results
def test_symbolic(self): # Create src and dst strings # This binary is compiled using gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 # with flags: -g -static -fno-builtin BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries/str_model_tests", "sym_strncpy_test") tmp_dir = tempfile.TemporaryDirectory(prefix="mcore_test_sym_") m = Manticore(BIN_PATH, stdin_size=10, workspace_url=str(tmp_dir.name)) addr_of_strncpy = 0x0400490 @m.hook(addr_of_strncpy) def strncpy_model(state): state.invoke_model(strncpy) m.run() m.finalize() # Approximate regexes for expected testcase output # Example Match above each regex # Manticore varies the hex output slightly per run expected = [ # STDIN: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' r"STDIN: b\'\\x00(\\x([0-9a-f]{2})){9}\'", # STDIN: b'\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff' r"STDIN: b\'(\\x((?!(00))([0-9a-f]{2}))){1}\\x00(\\x([0-9a-f]{2})){8}\'", # STDIN: b'\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff' r"STDIN: b\'(\\x((?!(00))([0-9a-f]{2}))){2}\\x00(\\x([0-9a-f]{2})){7}\'", # STDIN: b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' r"STDIN: b\'(\\x((?!(00))([0-9a-f]{2}))){10}\'", ] inputs = f"{str(m.workspace)}/test_*.input" # Make a list of the generated input states stdins = [] for inpt in glob(inputs): with open(inpt) as f: stdins.append(f.read()) # Check the number of input states matches the number of regexes self.assertEqual(len(stdins), len(expected)) # Assert that every regex has a matching input for e in expected: match = False for s in stdins: if re.fullmatch(e, s) == None: match = True break self.assertTrue(match)
def profile(program, sort="cumulative"): print(f'[*] Profiling program "{program}"') m = Manticore(program) m.run(should_profile=True) stats = m.get_profiling_stats() print(f"[*] Loaded profiling data.") if stats is None: print(f"[*] Failed to collect stats for program {program}") return stats.sort_stats(sort) stats.print_stats()
def test_integration_basic_stdin(self): import struct dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, 'binaries', 'basic_linux_amd64')) self.m.run() workspace = self.m._output.store.uri with open(os.path.join(workspace, 'test_00000000.stdin'), 'rb') as f: a = struct.unpack('<I', f.read())[0] with open(os.path.join(workspace, 'test_00000001.stdin'), 'rb') as f: b = struct.unpack('<I', f.read())[0] if a > 0x41: self.assertTrue(a > 0x41) self.assertTrue(b <= 0x41) else: self.assertTrue(a <= 0x41) self.assertTrue(b > 0x41)
def profile(program, sort="cumulative"): print(f'[*] Profiling program "{program}"') m = Manticore(program) profiler = Profiler() m.register_plugin(profiler) m.run() m.finalize() stats = profiler.get_profiling_data() print(f"[*] Loaded profiling data.") if stats is None: print(f"[*] Failed to collect stats for program {program}") return stats.sort_stats(sort) stats.print_stats()
def test_integration_basic_stdin(self): import struct dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, "binaries", "basic_linux_amd64")) self.m.run() self.m.finalize() workspace = self.m._output.store.uri with open(os.path.join(workspace, "test_00000000.stdin"), "rb") as f: a = struct.unpack("<I", f.read())[0] with open(os.path.join(workspace, "test_00000001.stdin"), "rb") as f: b = struct.unpack("<I", f.read())[0] if a > 0x41: self.assertTrue(a > 0x41) self.assertTrue(b <= 0x41) else: self.assertTrue(a <= 0x41) self.assertTrue(b > 0x41)
def test_symbolic_length_recv() -> None: BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries", "symbolic_length_recv") tmp_dir = tempfile.TemporaryDirectory(prefix="mcore_test_") m = Manticore(BIN_PATH, workspace_url=str(tmp_dir.name)) m.run() m.finalize() found_msg = False less_len_msg = "Received less than BUFFER_SIZE" outs_glob = f"{str(m.workspace)}/test_*.stdout" # Search all output messages for output_p in glob(outs_glob): with open(output_p) as f: if less_len_msg in f.read(): found_msg = True break assert found_msg, f'Did not find our message in {outs_glob}: "{less_len_msg}"'
def test_symbolic_syscall_arg() -> None: BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries", "symbolic_read_count") tmp_dir = tempfile.TemporaryDirectory(prefix="mcore_test_") m = Manticore(BIN_PATH, argv=["+"], workspace_url=str(tmp_dir.name)) m.run() m.finalize() found_win_msg = False win_msg = "WIN: Read more than zero data" outs_glob = f"{str(m.workspace)}/test_*.stdout" # Search all output messages for output_p in glob(outs_glob): with open(output_p) as f: if win_msg in f.read(): found_win_msg = True break assert found_win_msg, f'Did not find win message in {outs_glob}: "{win_msg}"'
def symbolic_execution(self, targets): log.info("Starting symbolic execution...") linux = make_linux(self.path, auto_load=False) m = Manticore(linux) m.verbosity(0) # change to 2 for debugging buf_addr = targets["buf_addr"] # reached the goal (memcpy call) def reached_goal(state): con_buf = state.solve_buffer(buf_addr, 48) with m.locked_context() as context: context["magic_values"] = con_buf m.terminate() m.add_hook(targets["goal"], reached_goal) #skip intro shit def skip_intro(state): buf = state.new_symbolic_buffer(48) # buffer we will solve state.cpu.write_bytes(buf_addr, buf) state.cpu.RIP = targets["check_start"] m.add_hook(self.binary.symbols[b"__libc_start_main"], skip_intro) # never take jumps for failed solutions def constrain_jump(state): state.constrain(state.cpu.ZF == 1) for jne_addr in targets["jnes"]: m.add_hook(jne_addr, constrain_jump) m.run(procs=1) magic_values = m.context["magic_values"] return magic_values
def executeDirected(program, pathsObject, args=[]): workplace_url = "/tmp/mcore_tmp" m = Manticore(program, argv=args, workspace_url=workplace_url, pure_symbolic=False) consts = config.get_group("core") consts.__setattr__("procs", 1) #Store variables in global context to ensure that we can communicate them to the callback function with m.locked_context() as context: context['paths'] = pathsObject context['targets'] = dict() #Register hook to have each executed instruction's RIP logged m.add_hook(None, log_rip) m.register_plugin(DirectedExtractorPlugin()) #Output the set of paths for i in pathsObject.paths: l = [hex(j) for j in i.path] logger.debug(",".join(l)) #Execute the directed symbolic execution m.run() #Obtain the dictionary of control flow edges from Manticore with m.locked_context() as context: targets = context['targets'] #Output results logger.debug("--Results Sorted by Pathlen--") sortedPaths = sorted(pathsObject.paths, key=lambda x: x.pathLen, reverse=False) for i in range(pathsObject.pathsLen): pathID = sortedPaths[i].pathID if pathID in targets.keys(): logger.debug("Path " + str(pathID) + "[len=" + str(sortedPaths[i].pathLen) + "] ending with " + hex( pathsObject.lastAddresses[pathID]) + " has the following successors " + ",".join([str(i) for i in targets[pathID]])) else: logger.debug("Path " + str(pathID) + "[len=" + str(sortedPaths[i].pathLen) + "]" + " is infeasible") return targets
def test(): from manticore.native import Manticore if __name__ == "__main__": import sys prog = sys.argv[1] params = sys.argv[2:] else: prog = "test_exploit_generation_example/bof" params = ["AAAAAAAAAAAAAAAAAAAAAAA"] m = Manticore(prog, params) m.verbosity(2) # 'trace' will contain the executed instructions m.context["trace"] = [] # None: The hook will be applied to all the instructions @m.hook(None) def record_trace(state): pc = state.cpu.PC ins = state.cpu.instruction # Store the instruction with m.locked_context() as c: c["trace"] += [pc] # We manipulate directly capstone instruction c["last_ins"] = "%s %s" % (ins.mnemonic, ins.op_str) # print(state.cpu) # print(state.mem) m.run() # Print number of instructions recorded and the last executed print("%d instructions are recorded" % len(m.context["trace"])) print("Last instruction executed:") print("0x%x: %s" % (m.context["trace"][-1], m.context["last_ins"])) assert m.context["last_ins"] == "call eax"
def symbolic_run(prog, params, trace, pc_crash): print "Starting symbolic execution" trace_set = set(trace) m = Manticore(prog, params) # The hook will be applied only to the instruction @pc_crash @m.hook(pc_crash) def crash_analysis(state): # Add the constraint on eax state.constrain(state.cpu.EAX == 0x0804887c) # 0x0804887c = @call_me # Retrieve the arguments corresponding to argv[1] argv_1 = next((i for i in state.input_symbols if i.name == 'ARGV1_1'), None) if argv_1: # Ask the value of argv_1 to the solver val_argv_1 = state.solve_one(argv_1) # Pretty print of the solution print "The solution is:" print "\\x" + "\\x".join("{:02x}".format(ord(c)) for c in val_argv_1) state.abandon() trace_set = set(trace) # convert the list to a set # None: The hook will be applied to all the instructions @m.hook(None) def follow_trace(state): if 'visited' not in state.context: state.context['visited'] = set() state.context['visited'].add(state.cpu.PC) # We stop to explore the current path if it doesn't follow the targeted path if not state.context['visited'] <= trace_set: print "State diverge at 0x%x" % state.cpu.PC state.abandon() m.run()
def concrete_run(prog, params): print "Starting concrete execution" m = Manticore(prog, params) # 'trace' will contain the executed instructions m.context['trace'] = [] # None: The hook will be applied to all the instructions @m.hook(None) def record_trace(state): pc = state.cpu.PC # Store the instruction with m.locked_context() as c: c['trace'] += [pc] m.run() # Print number of instructions recorded with m.locked_context() as c: print "%d instructions are recorded" % len(c['trace']) return c
def test_symbolic_fork(self): # This binary is compiled using gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 # with flags: -g -static -fno-builtin BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries/str_model_tests", "sym_strlen_test") tmp_dir = tempfile.TemporaryDirectory(prefix="mcore_test_sym_") m = Manticore(BIN_PATH, stdin_size=10, workspace_url=str(tmp_dir.name)) addr_of_strlen = 0x04404D0 @m.hook(addr_of_strlen) def strlen_model(state): state.invoke_model(strlen_exact) m.run() m.finalize() # Expected stdout outputs expected = { "Length of string is: 0", "Length of string is: 1", "Length of string is: 2", "Length of string is: 3", "Length of string is: 4", "Length of string is: 5", } # Make a list of the generated output states outputs = f"{str(m.workspace)}/test_*.stdout" stdouts = set() for out in glob(outputs): with open(out) as f: stdouts.add(f.read()) # Assert that every expected stdout has a matching output self.assertEqual(expected, stdouts)
def test_symbol_resolution(self): dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, "binaries", "basic_linux_amd64")) self.assertTrue(self.m.resolve("sbrk"), 0x449EE0)
def setUp(self): dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, "binaries", "arguments_linux_amd64"))
#!/usr/bin/env python3 # -*- coding: utf-8 -- from manticore.native import Manticore m = Manticore('./lab1B') m.verbosity(1) """ This lab has 21 unique cases equivalent to switch(0x1337d00d - input): case(1): ... case(2): ... ... case(21): ... by setting our input to 0x1337d00d - 1, we ensure we will hit the first case """ m.context['password'] = 0x1337d00d - 1 @m.hook(0x8048A55) def bad_password(state): """ If this address is reached, the password check has failed. Luckily, there are a limited number of possible cases. We can decrement our input to reach the next case, then manually jump back to the switch """
#!/usr/bin/env python3 # -*- coding: utf-8 -- from manticore.native import Manticore from manticore.core.smtlib import operators m = Manticore('./angrme') max_length = 40 # maximum flag length (rough guess-timate) m.verbosity(1) @m.hook(0x555555555187) def inject_symbolic_input(state): # skip expensive call to fgets state.cpu.RIP = 0x5555555551a0 # manually inject symbolic variable in place of input with m.locked_context() as context: solution = state.new_symbolic_buffer(max_length) # constrain flag format state.constrain(solution[0] == ord('h')) state.constrain(solution[1] == ord('x')) state.constrain(solution[2] == ord('p')) state.constrain(solution[3] == ord('{')) # constrain characters to be printable ASCII or null byte for i in range(max_length): state.constrain( operators.OR(