def main(): # length of desired input is 75 as found from reversing the binary in ghidra # 1 extra byte for first input input_len = 1 + 75 # seting up the angr project p = angr.Project('./engine') # looking at the code/binary, we can tell the input string is expected to fill 22 bytes, # thus the 8 byte symbolic size. Hopefully we can find the constraints the binary # expects during symbolic execution flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(input_len)] #extra \n for first input, then find the flag! flag = claripy.Concat(*flag_chars + [claripy.BVV(b'\n')]) # enable unicorn engine for fast efficient solving st = p.factory.entry_state(stdin=angr.SimFile('/dev/stdin', content=flag)) # constrain to non-newline bytes # constrain to ascii-only characters for k in flag_chars: st.solver.add(k < 0x7f) st.solver.add(k > 0x20) # Construct a SimulationManager to perform symbolic execution. # Step until there is nothing left to be stepped. sm = p.factory.simulation_manager(st) # now we defind the callback to check is the right or woring path def isOk(x): return b'Chugga' in x.posix.dumps(1) def isBad(x): return b'TRAINing' in x.posix.dumps(1) # now we find it ! sm.explore(find=isOk, avoid=isBad) # try to get the right path! if sm.found: valid = sm.found[0].posix.dumps(0) flag = valid[1:76] return flag.decode('utf-8') # otherwise ,must be something woring! raise Exception('something wrong!')
def conc_trace(file_name, p, prog_input="", input_stdin=True): ret_dict = {} if input_stdin: my_stdin = angr.SimFile(name='my_stdin', content=prog_input, has_end=True) state = p.factory.entry_state(args=[file_name], mode='tracing', stdin=my_stdin) else: state = p.factory.full_init_state(args=[file_name, prog_input], mode='tracing') simgr = p.factory.simgr(state) simgr.run() ret_dict['count'] = 0 if len(simgr.deadended) > 0: ret_dict['count'] = simgr.deadended[0].history.block_count ret_dict['stdout'] = simgr.deadended[0].state.posix.dumps(1) elif len(simgr.errored) > 0: ret_dict['count'] = simgr.errored[0].state.history.block_count ret_dict['stdout'] = simgr.errored[0].state.posix.dumps(1) return ret_dict
def main(): p = angr.Project('./filegr.elf') simFile = angr.SimFile("mySim", size=0x24 * 8) state = p.factory.entry_state(args=["./filegr.elf", "mySim"]) simFile.set_state(state) state.fs.insert('/root/filgerAns', simFile) sm = p.factory.simulation_manager(state) sm.explore(find=(0x1C01 + 0x400000)) found = sm.found[0] return found.posix.dumps(3)
def main(argv): project = angr.Project('07_angr_symbolic_file') start_address = 0x00401462 filename = 'FYMDJLWG.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 ) initial_state.fs.insert(filename, password_file) initial_state.regs.ebx = 0x404000 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')
def _load_file(self, guest_path): ''' For some reason the procfs files cannot be fetched with the docker API, so here we just `cat` instead :param guest_path: :return: ''' # attempt normal loading first file = super()._load_file(os.path.join('/proc', guest_path)) if file is not None: return file target_path = self.target.realpath( os.path.join('/proc', guest_path.lstrip(os.path.sep))) content, error = self.target.run_command(["cat", target_path]).communicate() if not error: return angr.SimFile(name='file://' + target_path, content=content, size=len(content)) else: assert ': No such file or directory' in error return None
def _load_file(self, guest_path): content = self.target.retrieve_contents(guest_path) return angr.SimFile(name='file://' + guest_path, content=content, size=len(content))
# state.solver.add(char <= '~') # '\x7e' # Create a symbolic string and constrain specific byte values char = state.solver.BVS("char", 4 * 8) state.solver.add(char.get_byte(2) == state.solver.BVV(0x30, 8)) state.solver.add(char.get_byte(1) == state.solver.BVV(0x2d, 8)) state.solver.add(char.get_byte(0) == state.solver.BVV(0x00, 8)) # Since we started from inside a function, we need to setup # the arguments that should have been passed to it. We pass # the symbolic string as an argument to the function in memory. state.memory.store(state.regs.ebp + 0x8, char) state.memory.store(state.regs.ebp + 0xc, 0x20) # Create a concrete file simfile = angr.SimFile('key', content='A'*32) state.fs.insert('./key', simfile) # Create simgr from the state # Veritesting helps reduce useless loops simgr = proj.factory.simgr(state, veritesting=True) # Use history of active states to identify bottleneck locations # list(map(hex, simgr.active[0].history.bbl_addrs)) # # Example: Hook the strcspn function and remove it to speed up exploration # def nop(state): # state.regs.rax = 36 # proj.hook(addr=0x400fef, hook=nop, length=5) print_flag = proj.loader.find_symbol("read_and_print_flag").rebased_addr
def makeSimfile(oldpoc, newpoc): symsize = claripy.BVS('mysize', 64) #filesize = os.path.getsize(oldpoc) #filedata = claripy.BVS('filedata', (filesize)*8) simfile = angr.SimFile(newpoc, size=symsize) return simfile
def addDevURandom(state): # we don't need the data in /dev/urandom to be symbolic, any concrete data should do devurandom = angr.SimFile("devurandom", writable=False, concrete=True, has_end=True, # if /dev/urandom actually gets to the end of this string and returns EOF, we want to be notified and have things fail rather than have it just invisibly generate symbolic data content="fdjkslaiuoewouriejaklhewf,masdnm,fuiorewewrhewjlfawjjkl!$RU(!KshjkLAFjfsdu*(SD(*(*(Asafdlksfjfsisefiklsdanm,fsdhjksfesijlfjesfes,se,esf,jkflesejiolflajiewmn,.waehjkowaejhfofyoivnm,cxhvgudyviuovnxcvncvixocjvsidooiI*DVJSKLFE*#L@N#@$$*Dsjklfjksd8fds9#WU*#(R@$JMksldfjfsd89J*F(F#KLJRJ*(RW") state.fs.insert('/dev/urandom', devurandom) state.options.discard(angr.options.SHORT_READS)
# bp걸면 ipdb가 실행된다. # ipdb는 파이썬 코드 디버거다. angr 내부 코드를 보여준다. # 바이너리 런타임 정보를 보려면 bp 추가할 때, action 인자를 사용해서 디버깅 함수를 이용해야할 것 같다. import angr, claripy def debug_func(state): print('='*10) print(state.callstack) proj = angr.Project("./sample", load_options={"auto_load_libs": False}) input1 = claripy.BVS("input1", 8*0x100) st = proj.factory.call_state(0x4011bb, stdin=angr.SimFile('/dev/stdin', input1)) for b in input1.chop(8): st.solver.add(b!=0) st.inspect.b('mem_write', when=angr.BP_AFTER, action=debug_func) simgr = proj.factory.simulation_manager(st, save_unconstrained=True) while len(simgr.unconstrained) == 0: simgr.step() print('[*] data: ', simgr.unconstrained[0].solver.eval(input1))
def main(argv): path_to_binary = argv[1] project = angr.Project(path_to_binary) start_address = 0x080488D9 initial_state = project.factory.blank_state(addr=start_address) # Specify some information needed to construct a simulated file. For this # challenge, the filename is hardcoded, but in theory, it could be symbolic. # Note: to read from the file, the binary calls # 'fread(buffer, sizeof(char), 64, file)'. # (!) filename = "OJKSQYDP.txt" # :string symbolic_file_size_bytes = 64 # A file, in Linux, represents a stream of sequential data. This stream may # come from a physical file on your hard drive, the network, the output of # another program (ex: /dev/urandom), or anything else. In our case, we want # to construct a block of memory where we store our symbolic variables for the # program to read. The following constructs the symbolic memory that will # supply the stream of data to the Linux file. Also, to communicate with # Angr's constraint solving system, we need to associate the memory with the # initial_state. # Commented out, for Angr versions earlier than 9.0 # symbolic_file_backing_memory = angr.state_plugins.SimSymbolicMemory() # symbolic_file_backing_memory.set_state(initial_state) # Construct a bitvector for the password and then store it in the file's # backing memory. The store method works exactly the same as the store method # you have already used. In fact, it's the exact same method! That means that # memory.store(address, bitvector) will write bitvector to the address we # specify. In this memory, unlike our program's memory, we want to write to # the beginning, as the Linux file will stream data from the beginning of the # file. For example, imagine a simple file, 'hello.txt': # # Hello world, my name is John. # ^ ^ # ^ address 0 ^ address 24 (count the number of characters) # In order to represent this in memory, we would want to write the string to # the beginning of the file: # # hello_txt_contents = claripy.BVV('Hello world, my name is John.', 30*8) # hello_txt_backing_memory.store(0, hello_txt_contents) # # Perhaps, then, we would want to replace John with a # symbolic variable. We would call: # # name_bitvector = claripy.BVS('symbolic_name', 4*8) # hello_txt_backing_memory.store(24, name_bitvector) # # Then, after the program calls fopen('hello.txt', 'r') and then # fread(buffer, sizeof(char), 30, hello_txt_file), the buffer would contain # the string from the file, except four symbolic bytes where the name would be # stored. # (!) password = claripy.BVS('password', symbolic_file_size_bytes * 8) # Commented out, for Angr versions earlier than 9.0 # symbolic_file_backing_memory.store(filename, password) # Construct the symbolic file. The file_options parameter specifies the Linux # file permissions (read, read/write, execute etc.) The content parameter # specifies from where the stream of data should be supplied. If content is # an instance of SimSymbolicMemory (we constructed one above), the stream will # contain the contents (including any symbolic contents) of the memory, # beginning from address zero. # Set the content parameter to our SimSymbolicMemory instance that holds the # symbolic data. # (!) # Commented out, for Angr versions earlier than 9.0 # file_options = 'r' # password_file = angr.storage.SimFile(filename, file_options, content=password, size=symbolic_file_size_bytes) # https://docs.angr.io/advanced-topics/file_system#example-2-create-a-file-with-symbolic-content-and-a-defined-size password_file = angr.SimFile("password_file", content=password, size=symbolic_file_size_bytes) # We have already created the file and the memory that stores the data that # the file will stream to the program, but we now need to tell Angr where the # file should appear to exist on the filesystem. This is a mapping between # strings representing the filenames and the angr.storage.SimFiles themselves. For # example, if hello_txt_file was a SimFile, # symbolic_filesystem = { # 'hello.txt' : hello_txt_file # } # would specify that any fopen('hello.txt', 'r') calls should stream data from # hello_txt_file. # Commented out, for Angr versions earlier than 9.0 # symbolic_filesystem = { # filename : password_file # } # initial_state.posix.fs = symbolic_filesystem initial_state.fs.insert(filename, password_file) simulation = project.factory.simgr(initial_state) def is_successful(state): stdout_output = state.posix.dumps(sys.stdout.fileno()) return bytes.decode(stdout_output).find("Good Job") != -1 def should_abort(state): stdout_output = state.posix.dumps(sys.stdout.fileno()) return bytes.decode(stdout_output).find("Try again") != -1 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')
def decode1(dedata): filename = 'that_girl' thatgirl = '' filethat = open(filename, 'r') thatgirl = filethat.read() filethat.close() filesize = len(thatgirl) @p.hook(0x00000000000400F67, length=0) def readfile1(_state): global t t = time.time() print(_state, 'start readfile;') @p.hook(0x00000000000400F6C, length=0) def readfile2(_state): global t print(_state, 'end readfile;') print(time.time() - t) @p.hook(0x00000400E8C, length=0) def count(_state): print(_state.regs.eax) # In[6]: claripy.BVV(0x12, 16).reversed # Out[6]: < BV16 0x1200 > # In[7]: claripy.BVV(0x12, 16) # Out[7]: < BV16 0x12 > need = [] @p.hook(0x00000000000400EC5, length=0) def solvaddrs(_state): index = _state.solver.eval(_state.regs.rax) * 8 _state.solver.add(dedata.reversed[index + 7:index] == _state.regs.dl) if index in need: _state.solver.add(False) _state.downsize() if _state.satisfiable(): print(True) print(_state.solver.eval(flag, cast_to=bytes)) need.append(index) else: _state.solver.add(False) _state.downsize() thatgirl_symbols = [ claripy.BVV(ord(thatgirl[i]), 8) for i in range(filesize) ] thatgirlContent = claripy.Concat(*thatgirl_symbols) simfile = angr.SimFile('./that_girl', content=thatgirlContent, size=filesize, has_end=angr.options.FILES_HAVE_EOF) flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(38 + 5)] flag = claripy.Concat(*flag_chars + [claripy.BVV(b'}')] + [claripy.BVV(b'\n')]) state = p.factory.entry_state(add_options=angr.options.unicorn | { angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY, angr.options.REPLACEMENT_SOLVER }, stdin=flag, remove_options={angr.options.LAZY_SOLVES}) #state.options.add(angr.options.LAZY_SOLVES) state.fs.insert('that_girl', simfile) for k in flag_chars: state.solver.add(k != 10) so1 = state.solver.And(k > 8, k < 14) so2 = state.solver.And(k > 31, k < 127) state.solver.add(state.solver.Or(so1, so2) == True) simulation = p.factory.simulation_manager(state) res = simulation.explore(find=0x00000000400EEC, avoid=[0x000400C36], enable_veritesting=True) #Threading print(len(res.found)) for pp in res.found: print(pp.posix.dumps(0))
import angr import claripy p = angr.Project("change_my_mind") symsize = claripy.BVS('inputLength', 64) simfile = angr.SimFile('/tmp/stdin', size=symsize) state = p.factory.entry_state(stdin=simfile) simgr = p.factory.simulation_manager(state) simgr.explore(find=lambda s: b"Good" in s.posix.dumps(1)) f = simgr.found[0] print(f) print((b"STDOUT: " + f.posix.dumps(1)).decode()) print((b"FLAG: " + f.posix.dumps(0)).decode()) """ STDOUT: Hello! Please provide your credentials! >>Lets'check... Good password. Congratulations! FLAG: justCTF{1_ch4ng3d_my_m1nd_by_cl34r1n6_7h3_r00m} """
#!/usr/bin/env python3 import angr import socket import claripy import pickle with open("./code.bin", "rb") as f: code = f.read() code = angr.SimFile('code.bin', content=code) stdin = claripy.BVV(b"1234567789012345678901234567" + b"\n") p = angr.Project("./eVMoji") s = p.factory.main_state(args=["eVMoji", "code.bin"], stdin=stdin) s.fs.insert("code.bin", code) s.options.add(angr.options.UNICORN) # base = tracer.QEMURunner(argv=["eVMoji", "code.bin"], binary="./eVMoji", input=b'A'*32 + b'\n', record_stdout=True, project=p) # print(base.stdout.decode()) # from IPython import embed # embed() sm = p.factory.simulation_manager(s) sm.explore(find=lambda s: b"tRy" in s.posix.dumps(1)) print(sm)