02 Angr Find Condition¶
Analyzing the Binary¶
This function looks pretty straightforward. Similar to the ones we have already done.
The input is expecting eight characters again.
The complex function is called on each character.
Here we can see what happens if we enter the correct password and the incorrect password.
In the instructions it is asking us to do something a bit different. Instead of putting in the addresses for the find and avoid states, we will check the output and determine the solution based on that. Now on to writing the script.
Building the Script¶
The start is the same we have seen before.
path_to_binary = "./02_angr_find_condition"
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state(
add_options={
angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
},
)
simulation = project.factory.simgr(initial_state)
But now we want to check the output to determine a success. The function must return a boolean.
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return b"Good Job." in stdout_output
The same goes for a fail.
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return b"Try again." in stdout_output
Now we give the simulation manager the functions as callbacks to determine the success/failure of each path and let'er rip.
simulation.explore(find=is_successful, avoid=should_abort)
Final Script¶
import angr
import sys
import pwn
def run_binary(solution, path_to_binary):
if type(solution) == str:
solution = bytes(solution, "utf-8")
print(f"[+] Solution found: {solution.decode()}")
print(" [|] Running binary")
elf = pwn.ELF(path_to_binary, checksec=False)
pty = pwn.process.PTY
io = elf.process(stdin=pty, stdout=pty, level="warn")
io.recvuntil(b":")
io.sendline(solution)
output = io.recvline().decode().splitlines()[0].strip()
print(f" [+] Output: {output}")
def main():
path_to_binary = "./02_angr_find_condition"
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state(
add_options={
angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
},
)
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return b"Good Job." in stdout_output # :boolean
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return b"Try again." in stdout_output # :boolean
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution = solution_state.posix.dumps(sys.stdin.fileno()).decode()
run_binary(solution, path_to_binary)
else:
raise Exception("Could not find the solution")
if __name__ == "__main__":
main()