Angr 9 SimFile without SimSymbolicMemory
Whilst working on angr_ctf in order to properly dive into Angr, there was one exercise which required the use of a symbolic filesystem with SimFile
backed by symbolic memory.
This particular challenge requires a particular input to be present in the input file and as such act as the password. The filename can be quickly looked up in the binary; the
contents however will be made symbolic so we can solve for that.
The provided scaffold was along the lines of:
#!/usr/bin/env python3
import angr
import claripy
project = angr.Project('07_angr_symbolic_file')
initial_state = project.factory.blank_state(addr=0x80488db)
filename = 'INYXFAJA.txt'
symbolic_file_size_bytes = 0x40
symbolic_file_backing_memory = angr.state_plugins.SimSymbolicMemory()
symbolic_file_backing_memory.set_state(initial_state)
password = claripy.BVS('password', symbolic_file_size_bytes * 8)
symbolic_file_backing_memory.store(0 , password)
file_options = 'r'
password_file = angr.storage.SimFile(filename, file_options,
content=symbolic_file_backing_memory, size=symbolic_file_size_bytes)
symbolic_filesystem = { filename : password_file }
initial_state.posix.fs = symbolic_filesystem
simulation = project.factory.simgr(initial_state)
While I know this CTF is not too new and is using Python2 still, so far I the tweaks required to get it working with Python 3 were minimal. However the error when running the code above with a fresly installed version of Angr (9.0.5171 at the time of writing) signalled this was a less trivial issue:
AttributeError: module 'angr.state_plugins' has no attribute 'SimSymbolicMemory'
As it turns out, the entire SimSymbolicMemory
class was removed without so much as a migration path that’s easily found like what was done for angr 8 and angr 7 before that1.
Now, Angr is a rapidly evolving project (that’s a good thing!) so lacking a migration guide, I was hoping to at least find a clue in the changelog. Alas, the changelog at the time of writing doesn’t cover anything beyond angr 8.19.7.25 and repository doesn’t contain anything resembling a changelog.
Obviously I wasn’t the first to run into this particular issue with SimSymbolicMemory
and someone filed an issue upstream, but I wanted to provide a working example. If nothing else, it’s a reference for future-me.
The referenced issue states that SimSymbolicMemory
was removed and instead we can provide the contents, a Claripy bitvector in this case, directly. Also the second argument when instantiating a SimFile
class no longer represents a file mode2.
Furthermore we can skip the entire symbolic_filesystem
construction and instead pass it when setting up the initial state.
Putting everything together the complete solution3 for 07_angr_symbolic_file that works with Angr 9 becomes:
import angr
import claripy
def main(argv):
project = angr.Project('07_angr_symbolic_file')
start_address = 0x080488f4
filename = 'INYXFAJA.txt'
# This is passed to fread() at 0x08048925 as nmemb
# 0x080488f4 6a40 push 0x40
symbolic_file_size_bytes = 0x40
password = claripy.BVS('password', symbolic_file_size_bytes * 8)
password_file = angr.SimFile(filename,
content = password,
size = symbolic_file_size_bytes)
initial_state = project.factory.blank_state(
addr = start_address,
fs = {filename: password_file}
)
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
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return b'Try again.' in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution = solution_state.solver.eval(password,cast_to=bytes).decode()
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main()