x86_64: Phase 1

In [1]:
# Imports

import angr
import claripy

Approach 1: Blind Walk

Here we'll let Angr do what it does best: walk all over the binary without any care in the world. We treat the function as a black box and do not look into it's working. We just let Angr do it's work.

Since it's a blind approach, it takes a while to complete, about an hour estimated.

Load the binary.

In [2]:
project_approach_1 = angr.Project('bomb64')

Define the address for the execution path to be followed.

In [3]:
# The address where the symbolic execution shall begin. It is the beginning of the binary.
addr_start = 0x400F0A

# The address of the input for the next phase, right after defused greetings are printed.
addr_target = 0x400F3C

# The address of the first instruction of the explode_bomb function, which is to be avoided.
addr_bomb = 0x40143A

Define the user input to be provided.

In [4]:
# A BitVectorSymbol is declared of max allowed lenght of 78 characters * 8 bits.
user_input = claripy.BVS('user_input', 8 * 78)

Define a blank state for the simulation, a state with most of it's data uninitialized. Pass the address where the state is initialized, along with the user input to be given via standard input.

In [5]:
state = project_approach_1.factory.blank_state(addr=addr_start, stdin=user_input)

Create a simulation manager with this blank state that would help us manage the symbolic execution.

In [6]:
simgr = project_approach_1.factory.simulation_manager(state)

We call the explore method of the simulation manager, tasked with finding an execution path that reaches the target address and avoids the address which explodes the bomb.

In [7]:
simgr.explore(find=addr_target, avoid=addr_bomb)
WARNING | 2020-06-04 06:11:40,755 | angr.state_plugins.symbolic_memory | The program is accessing memory or registers with an unspecified value. This could indicate unwanted behavior.
WARNING | 2020-06-04 06:11:40,756 | angr.state_plugins.symbolic_memory | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by:
WARNING | 2020-06-04 06:11:40,757 | angr.state_plugins.symbolic_memory | 1) setting a value to the initial state
WARNING | 2020-06-04 06:11:40,757 | angr.state_plugins.symbolic_memory | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null
WARNING | 2020-06-04 06:11:40,758 | angr.state_plugins.symbolic_memory | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY_REGISTERS}, to suppress these messages.
WARNING | 2020-06-04 06:11:40,759 | angr.state_plugins.symbolic_memory | Filling register rbx with 8 unconstrained bytes referenced from 0x400da0 (main+0x0 in bomb64 (0x400da0))
WARNING | 2020-06-04 06:11:40,763 | angr.state_plugins.symbolic_memory | Filling register rdi with 8 unconstrained bytes referenced from 0x400da0 (main+0x0 in bomb64 (0x400da0))
WARNING | 2020-06-04 06:11:40,856 | angr.state_plugins.symbolic_memory | Filling register rsi with 8 unconstrained bytes referenced from 0x400db6 (main+0x16 in bomb64 (0x400db6))
.
.
.
WARNING | 2020-06-04 06:24:17,981 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
WARNING | 2020-06-04 06:24:22,941 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
WARNING | 2020-06-04 06:24:34,727 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
WARNING | 2020-06-04 06:24:39,720 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
WARNING | 2020-06-04 06:24:58,416 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
WARNING | 2020-06-04 06:25:16,309 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
WARNING | 2020-06-04 06:25:35,082 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
WARNING | 2020-06-04 06:25:58,761 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
WARNING | 2020-06-04 06:26:18,887 | angr.state_plugins.symbolic_memory | Filling register r12 with 8 unconstrained bytes referenced from 0x401338 (strings_not_equal+0x0 in bomb64 (0x401338))
Out[7]:
<SimulationManager with 6 active, 1 deadended, 1 found, 520 avoid (1 errored)>

We dereference the execution path "found" by the simulation manager and dump the output.

In [8]:
found_path = simgr.found[0]
In [9]:
found_path.solver.eval(user_input, cast_to=bytes)
Out[9]:
b'Border relations with Canada have never been better.\xff\x00\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\x00'

VoilĂ ! There's the input we need to give to pass the first phase. The trailing bytes seem to be padding to fulfill the criteria of 78 string length, should be ignored.

Approach 2: Targeted Walk

This approach is targeted, based on our knowledge of the inside workings of the function. We add a hook to the function and dump the values in the memory to find out the string against which the user input is compared.

The last approach took too long, which led me to believe I could definitely work something out if I wrote a script tailored for this function. Since this approach is a targeted one, it only takes seconds to yield results.

Load the binary.

In [10]:
project_approach_2 = angr.Project('bomb64')

Define the address for the start of the execution path.

In [11]:
# The address where the symbolic execution shall begin. It is the beginning of the binary.
addr_start = 0x400DA0

# The address where the hook will be established.
# It is right before the string comparison function.
# Dumps it's arguments and finds out the reference string.
addr_hook = 0x400EE9

Define a blank state for the simulation, a state with most of it's data uninitialized. Pass the address where the state is initialized, along with the user input to be given via standard input.

In [12]:
state = project_approach_2.factory.blank_state(addr=addr_start)

We define and add the hook to the function.

In [13]:
# Takes the state as initialiser.
class HookClass(angr.SimProcedure):
    def run(self):
        # Dumps the address of the argument to "strings_not_equal" function from the register.
        addr = self.state.regs.esi
        # Dereferences the address of the string and prints it.
        print(self.state.mem[addr].string.concrete)
        return 0

# Adds the hook to the execution flow.
project_approach_2.hook(addr_hook, HookClass())

Create a simulation manager with this blank state that would help us manage the symbolic execution.

In [14]:
simgr = project_approach_2.factory.simulation_manager(state)

Run the simulation manager so as to walk over various states.

In [15]:
simgr.run()
WARNING | 2020-06-04 07:30:18,672 | angr.state_plugins.symbolic_memory | Filling register rbx with 8 unconstrained bytes referenced from 0x400da0 (main+0x0 in bomb64 (0x400da0))
WARNING | 2020-06-04 07:30:18,675 | angr.state_plugins.symbolic_memory | Filling register rdi with 8 unconstrained bytes referenced from 0x400da0 (main+0x0 in bomb64 (0x400da0))
WARNING | 2020-06-04 07:30:18,746 | angr.state_plugins.symbolic_memory | Filling register rsi with 8 unconstrained bytes referenced from 0x400db6 (main+0x16 in bomb64 (0x400db6))
WARNING | 2020-06-04 07:30:18,973 | angr.state_plugins.symbolic_memory | Filling memory at 0xffffffc000000008 with 8 unconstrained bytes referenced from 0x400dbe (main+0x1e in bomb64 (0x400dbe))
WARNING | 2020-06-04 07:30:19,129 | angr.state_plugins.symbolic_memory | Filling memory at 0xffffffc000000000 with 8 unconstrained bytes referenced from 0x400df8 (main+0x58 in bomb64 (0x400df8))
WARNING | 2020-06-04 07:30:19,292 | angr.state_plugins.symbolic_memory | Filling memory at 0xffff000000000000 with 256 unconstrained bytes referenced from 0x775b40 (_IO_fopen@@GLIBC_2.2.5+0x0 in libc.so.6 (0x75b40))
WARNING | 2020-06-04 07:30:19,431 | angr.state_plugins.posix | Trying to open unknown file b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - created a symbolic file since ALL_FILES_EXIST is set
WARNING | 2020-06-04 07:30:19,844 | angr.state_plugins.symbolic_memory | Filling memory at 0xffffffffffffff00 with 256 unconstrained bytes referenced from 0x80dd70 (__printf_chk+0x0 in libc.so.6 (0x10dd70))
WARNING | 2020-06-04 07:30:20,594 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefde0 with 8 unconstrained bytes referenced from 0x73c4d6 (__libc_sigaction+0xe6 in libc.so.6 (0x3c4d6))
WARNING | 2020-06-04 07:30:20,595 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefdf8 with 16 unconstrained bytes referenced from 0x73c4de (__libc_sigaction+0xee in libc.so.6 (0x3c4de))
WARNING | 2020-06-04 07:30:20,597 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe08 with 16 unconstrained bytes referenced from 0x73c4e7 (__libc_sigaction+0xf7 in libc.so.6 (0x3c4e7))
WARNING | 2020-06-04 07:30:20,599 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe18 with 16 unconstrained bytes referenced from 0x73c4f0 (__libc_sigaction+0x100 in libc.so.6 (0x3c4f0))
WARNING | 2020-06-04 07:30:20,602 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe28 with 16 unconstrained bytes referenced from 0x73c4f9 (__libc_sigaction+0x109 in libc.so.6 (0x3c4f9))
WARNING | 2020-06-04 07:30:20,604 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefde8 with 8 unconstrained bytes referenced from 0x73c505 (__libc_sigaction+0x115 in libc.so.6 (0x3c505))
WARNING | 2020-06-04 07:30:20,607 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe38 with 16 unconstrained bytes referenced from 0x73c512 (__libc_sigaction+0x122 in libc.so.6 (0x3c512))
WARNING | 2020-06-04 07:30:20,608 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe48 with 16 unconstrained bytes referenced from 0x73c51b (__libc_sigaction+0x12b in libc.so.6 (0x3c51b))
WARNING | 2020-06-04 07:30:20,611 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe58 with 16 unconstrained bytes referenced from 0x73c529 (__libc_sigaction+0x139 in libc.so.6 (0x3c529))
WARNING | 2020-06-04 07:30:20,614 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe68 with 16 unconstrained bytes referenced from 0x73c532 (__libc_sigaction+0x142 in libc.so.6 (0x3c532))
WARNING | 2020-06-04 07:30:20,620 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefdf0 with 8 unconstrained bytes referenced from 0x73c542 (__libc_sigaction+0x152 in libc.so.6 (0x3c542))
WARNING | 2020-06-04 07:30:20,685 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefde0 with 8 unconstrained bytes referenced from 0x73c4d6 (__libc_sigaction+0xe6 in libc.so.6 (0x3c4d6))
WARNING | 2020-06-04 07:30:20,686 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefdf8 with 16 unconstrained bytes referenced from 0x73c4de (__libc_sigaction+0xee in libc.so.6 (0x3c4de))
WARNING | 2020-06-04 07:30:20,688 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe08 with 16 unconstrained bytes referenced from 0x73c4e7 (__libc_sigaction+0xf7 in libc.so.6 (0x3c4e7))
WARNING | 2020-06-04 07:30:20,691 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe18 with 16 unconstrained bytes referenced from 0x73c4f0 (__libc_sigaction+0x100 in libc.so.6 (0x3c4f0))
WARNING | 2020-06-04 07:30:20,693 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe28 with 16 unconstrained bytes referenced from 0x73c4f9 (__libc_sigaction+0x109 in libc.so.6 (0x3c4f9))
WARNING | 2020-06-04 07:30:20,695 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefde8 with 8 unconstrained bytes referenced from 0x73c505 (__libc_sigaction+0x115 in libc.so.6 (0x3c505))
WARNING | 2020-06-04 07:30:20,698 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe38 with 16 unconstrained bytes referenced from 0x73c512 (__libc_sigaction+0x122 in libc.so.6 (0x3c512))
WARNING | 2020-06-04 07:30:20,700 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe48 with 16 unconstrained bytes referenced from 0x73c51b (__libc_sigaction+0x12b in libc.so.6 (0x3c51b))
WARNING | 2020-06-04 07:30:20,703 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe58 with 16 unconstrained bytes referenced from 0x73c529 (__libc_sigaction+0x139 in libc.so.6 (0x3c529))
WARNING | 2020-06-04 07:30:20,706 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefe68 with 16 unconstrained bytes referenced from 0x73c532 (__libc_sigaction+0x142 in libc.so.6 (0x3c532))
WARNING | 2020-06-04 07:30:20,711 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffefdf0 with 8 unconstrained bytes referenced from 0x73c542 (__libc_sigaction+0x152 in libc.so.6 (0x3c542))
WARNING | 2020-06-04 07:30:20,941 | angr.state_plugins.symbolic_memory | Filling register rbp with 8 unconstrained bytes referenced from 0x4013bc (blank_line+0x0 in bomb64 (0x4013bc))
WARNING | 2020-06-04 07:30:20,948 | angr.state_plugins.symbolic_memory | Filling memory at 0x4f with 1 unconstrained bytes referenced from 0x4013de (blank_line+0x22 in bomb64 (0x4013de))
WARNING | 2020-06-04 07:30:21,882 | angr.state_plugins.symbolic_memory | Filling register rbp with 8 unconstrained bytes referenced from 0x4013bc (blank_line+0x0 in bomb64 (0x4013bc))
WARNING | 2020-06-04 07:30:21,899 | angr.state_plugins.symbolic_memory | Filling memory at 0x50 with 7 unconstrained bytes referenced from 0x4013d4 (blank_line+0x18 in bomb64 (0x4013d4))
WARNING | 2020-06-04 07:30:22,215 | angr.state_plugins.symbolic_memory | Filling memory at 0xffffffffffffffe0 with 1 unconstrained bytes referenced from 0x4013d7 (blank_line+0x1b in bomb64 (0x4013d7))
WARNING | 2020-06-04 07:30:22,562 | angr.state_plugins.symbolic_memory | Filling memory at 0x4f with 1 unconstrained bytes referenced from 0x4013de (blank_line+0x22 in bomb64 (0x4013de))
WARNING | 2020-06-04 07:30:23,232 | angr.state_plugins.symbolic_memory | Filling memory at 0x50 with 7 unconstrained bytes referenced from 0x4013d4 (blank_line+0x18 in bomb64 (0x4013d4))
WARNING | 2020-06-04 07:30:23,465 | angr.state_plugins.symbolic_memory | Filling memory at 0xffffff0000000081 with 1 unconstrained bytes referenced from 0x4013d7 (blank_line+0x1b in bomb64 (0x4013d7))
WARNING | 2020-06-04 07:30:23,850 | angr.state_plugins.symbolic_memory | Filling memory at 0xfffffffffffffff5 with 8 unconstrained bytes referenced from 0x4013d4 (blank_line+0x18 in bomb64 (0x4013d4))
WARNING | 2020-06-04 07:30:23,997 | angr.state_plugins.symbolic_memory | Filling memory at 0x0 with 1 unconstrained bytes referenced from 0x4013d7 (blank_line+0x1b in bomb64 (0x4013d7))
WARNING | 2020-06-04 07:30:26,045 | angr.state_plugins.symbolic_memory | Filling memory at 0xffffff0000000180 with 8 unconstrained bytes referenced from 0x4013d4 (blank_line+0x18 in bomb64 (0x4013d4))
WARNING | 2020-06-04 07:30:26,194 | angr.state_plugins.symbolic_memory | Filling memory at 0xffffffffffffffff with 1 unconstrained bytes referenced from 0x4013d7 (blank_line+0x1b in bomb64 (0x4013d7))
WARNING | 2020-06-04 07:30:26,474 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffeffe0 with 8 unconstrained bytes referenced from 0x400ee9 (phase_1+0x9 in bomb64 (0x400ee9))
b'Border relations with Canada have never been better.'
WARNING | 2020-06-04 07:30:26,875 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 mem_7fffffffffeffe0_713_64{UNINITIALIZED}>
WARNING | 2020-06-04 07:30:27,018 | angr.state_plugins.symbolic_memory | Filling memory at 0x1 with 8 unconstrained bytes referenced from 0x4013d4 (blank_line+0x18 in bomb64 (0x4013d4))
WARNING | 2020-06-04 07:30:28,042 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffeffe0 with 8 unconstrained bytes referenced from 0x400ee9 (phase_1+0x9 in bomb64 (0x400ee9))
b'Border relations with Canada have never been better.'
WARNING | 2020-06-04 07:30:28,504 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 mem_7fffffffffeffe0_715_64{UNINITIALIZED}>
WARNING | 2020-06-04 07:30:28,992 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffeffe0 with 8 unconstrained bytes referenced from 0x400ee9 (phase_1+0x9 in bomb64 (0x400ee9))
b'Border relations with Canada have never been better.'
WARNING | 2020-06-04 07:30:29,357 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 mem_7fffffffffeffe0_717_64{UNINITIALIZED}>
WARNING | 2020-06-04 07:30:29,805 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffeffe0 with 8 unconstrained bytes referenced from 0x400ee9 (phase_1+0x9 in bomb64 (0x400ee9))
b'Border relations with Canada have never been better.'
WARNING | 2020-06-04 07:30:30,155 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 mem_7fffffffffeffe0_718_64{UNINITIALIZED}>
WARNING | 2020-06-04 07:30:30,633 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffeffe0 with 8 unconstrained bytes referenced from 0x400ee9 (phase_1+0x9 in bomb64 (0x400ee9))
b'Border relations with Canada have never been better.'
WARNING | 2020-06-04 07:30:31,013 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 mem_7fffffffffeffe0_719_64{UNINITIALIZED}>
WARNING | 2020-06-04 07:30:31,413 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffeffe0 with 8 unconstrained bytes referenced from 0x400ee9 (phase_1+0x9 in bomb64 (0x400ee9))
b'Border relations with Canada have never been better.'
WARNING | 2020-06-04 07:30:31,771 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 mem_7fffffffffeffe0_720_64{UNINITIALIZED}>
WARNING | 2020-06-04 07:30:32,107 | angr.state_plugins.symbolic_memory | Filling memory at 0x0 with 8 unconstrained bytes referenced from 0x4013d4 (blank_line+0x18 in bomb64 (0x4013d4))
WARNING | 2020-06-04 07:30:32,419 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffeffe0 with 8 unconstrained bytes referenced from 0x400ee9 (phase_1+0x9 in bomb64 (0x400ee9))
b'Border relations with Canada have never been better.'
WARNING | 2020-06-04 07:30:32,795 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 mem_7fffffffffeffe0_722_64{UNINITIALIZED}>
WARNING | 2020-06-04 07:30:32,911 | angr.state_plugins.symbolic_memory | Filling memory at 0x7fffffffffeffe0 with 8 unconstrained bytes referenced from 0x400ee9 (phase_1+0x9 in bomb64 (0x400ee9))
b'Border relations with Canada have never been better.'
WARNING | 2020-06-04 07:30:33,990 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 mem_7fffffffffeffe0_724_64{UNINITIALIZED}>
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
~/.local/lib/python3.8/site-packages/claripy/ast/base.py in replace_dict(self, replacements, variable_set, leaf_operation)
    710             try:
--> 711                 ast = next(arg_queue[-1])
    712                 repl = ast

StopIteration: 

During handling of the above exception, another exception occurred:

KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-35-d7a0b3e79488> in <module>
----> 1 simgr.run()

~/.local/lib/python3.8/site-packages/angr/sim_manager.py in run(self, stash, n, until, **kwargs)
    259         for _ in (itertools.count() if n is None else range(0, n)):
.
.
.
~/.local/lib/python3.8/site-packages/claripy/ast/base.py in __hash__(self)
     25         self.ast = a
     26 
---> 27     def __hash__(self):
     28         return hash(self.ast)
     29 

KeyboardInterrupt: 

VoilĂ ! Yet again, there's the input we need to give to pass the first phase. It will be printed repeatedly as different branches being explored by Angr reach a conclusive stage, so I stopped the execution.