赘述

这里先用几句话简单的介绍下漏洞成因:

  1. 前端使用js来校验 ping相关的参数
  2. 后端直接使用snprintf来构造执行指令
  3. 后端构造的具体指令为ipping -c 1 -s %d -w %d %s -I %s

    1. -c:ping的次数
    2. -s:ping的数据包大小
    3. -w:ping的timeout
    4. %s(第二个):用户输入的host
    5. -I:ping使用的网卡
  4. 注入host就可以命令执行:ipping -c 1 -s 64 -w 1 $(host) -I 192.168.0.12

0x1 漏洞成因-前端

  • 1 首先后台页面的 ping入口只是在前端校验

06.png

  • 2 核心实现文件为pingNTraceRoute.htm,其中startDiag函数实现了ipping的相关逻辑,关键代码如下所示
      function startDiag() {
      ...
          if ($.id("ipping").checked) {
              if (isNaN(icmpPkts) || icmpPkts < 1 || icmpPkts > 50) {
                  $.alert(ERR_DIAG_PING_COUNT);
                  $.id("l_ping_pkt").focus();
                  return
              }
              //执行 ipping 的关键注入
              ipping = $.act(ACT_GET, IPPING_DIAG, null, null, ["dataBlockSize", "timeout", "numberOfRepetitions", "host", "X_TP_ConnName", "diagnosticsState"]);
              if (!$.exe()) {
                  ipping.diagnosticsState = "Requested";
                  ipping.dataBlockSize = parseInt($.id("l_ping_pkt_size").value, 10);
                  ipping.timeout = parseInt($.id("l_ping_pkt_time").value, 10);
                  ipping.numberOfRepetitions = parseInt($.id("l_ping_pkt").value, 10);
                  ipping.host = $.id("l_addr").value;
                  ipping.X_TP_ConnName = test_conn;
                  pktSize = parseInt($.id("l_ping_pkt_size").value, 10) + 8;
                  pingtimeout = parseInt($.id("l_ping_pkt_time").value, 10);
                  $.act(ACT_SET, IPPING_DIAG, null, null, ipping);
                  if (!$.exe()) {
                      $.id("testButton").disabled = true;
                      $.addLoading($.id("testButton"));
                      var gotResult = 1;
                      var i = 1;
                      $.auto(function() {
                          ipping = $.act(ACT_GET, IPPING_DIAG, null, null, null);
                          if (!$.exe()) {
                              if (i > icmpPkts) {
                                  result = "";
                                  disNewLine(result, "");
                                  result = "---" + ipping.X_TP_IPAddress + " ping statistics ---";
                                  disNewLine(result, "");
                                  result = ipping.numberOfRepetitions + " packets transmitted, " + ipping.successCount + " packets received," + Math.round(ipping.failureCount * 100 / ipping.numberOfRepetitions) + "% packet loss";
                                  disNewLine(result, "");
                                  if (ipping.minimumResponseTime != 65535) {
                                      result = "round-trip min/avg/max = " + ipping.minimumResponseTime / 1000 + "/" + ipping.averageResponseTime / 1000 + "/" + ipping.maximumResponseTime / 1000 + " ms";
                                      disNewLine(result, "")
                                  }
                                  $.id("testButton").disabled = false;
                                  $.removeLoading($.id("testButton"));
                                  return false
                              }
                              if (gotResult) {
                                  $.act(ACT_OP, ACT_OP_IPPING);
                                  if (!$.exe()) {
                                      gotResult = 0;
                                      return true
                                  }
                                  return false
                              }
                              if (printHeader) {
                                  result = "PING " + ipping.host;
                                  if ($.ifip(ipping.host, true) == 0) {
                                      result = result + " (" + ipping.host + "): " + ipping.dataBlockSize + " data bytes";
                                      disNewLine(result, "");
                                      result = "";
                                      disNewLine(result, "");
                                      printHeader = 0
                                  } else {
                                      if ($.ifip(ipping.X_TP_IPAddress, true) == 0) {
                                          result = result + " (" + ipping.X_TP_IPAddress + "): " + ipping.dataBlockSize + " data bytes";
                                          disNewLine(result, "");
                                          result = "";
                                          disNewLine(result, "");
                                          printHeader = 0
                                      }
                                  }
                              }
                              if ("Error_CannotResolveHostName" == ipping.diagnosticsState) {
                                  result = "PING: unknown host: " + ipping.host;
                                  disNewLine(result, "");
                                  $.id("testButton").disabled = false;
                                  $.removeLoading($.id("testButton"));
                                  return false
                              } else {
                                  if ("Requested" == ipping.diagnosticsState) {
                                      gotResult = 0;
                                      return true
                                  } else {
                                      if ("None" == ipping.diagnosticsState) {
                                          gotResult = 1;
                                          var res = pktSize + " bytes from " + ipping.X_TP_IPAddress + ": icmp_seq=" + i + " ttl=128 time=" + ipping.X_TP_ResponseTime / 1000 + " ms";
                                          disNewLine(res, "");
                                          res = "";
                                          i++
                                      } else {
                                          if ("Complete" == ipping.diagnosticsState) {
                                              if (strstr(ipping.X_TP_Result, "Request timed out.") != -1) {
                                                  result = "Request timed out.";
                                                  disNewLine(result, "")
                                              } else {
                                                  result = pktSize + " bytes from " + ipping.X_TP_IPAddress + ": icmp_seq=" + i + " ttl=128 time=" + ipping.X_TP_ResponseTime / 1000 + " ms";
                                                  disNewLine(result, "")
                                              }
                                              result = "";
                                              disNewLine(result, "");
                                              result = "---" + ipping.X_TP_IPAddress + " ping statistics ---";
                                              disNewLine(result, "");
                                              result = ipping.numberOfRepetitions + " packets transmitted, " + ipping.successCount + " packets received," + Math.round(ipping.failureCount * 100 / ipping.numberOfRepetitions) + "% packet loss";
                                              disNewLine(result, "");
                                              if (ipping.minimumResponseTime != 65535) {
                                                  result = "round-trip min/avg/max = " + ipping.minimumResponseTime / 1000 + "/" + ipping.averageResponseTime / 1000 + "/" + ipping.maximumResponseTime / 1000 + " ms";
                                                  disNewLine(result, "")
                                              }
                                              $.id("testButton").disabled = false;
                                              $.removeLoading($.id("testButton"));
                                              return false
                                          } else {
                                              if ("Error_Internal" == ipping.diagnosticsState) {
                                                  gotResult = 1;
                                                  disNewLine(ipping.X_TP_Result, "")
                                              } else {
                                                  gotResult = 1;
                                                  disNewLine(ipping.X_TP_Result, "");
                                                  i++
                                              }
                                          }
                                      }
                                  }
                              }
                              ipping.diagnosticsState = "Requested";
                              ipping.X_TP_Result = "";
                              $.act(ACT_SET, IPPING_DIAG, null, null, ["X_TP_Result=", "diagnosticsState=Requested"]);
                              if (!$.exe()) {}
                          }
                      },
                      500)
                  }
              }
          } else {
              if ($.id("traceroute").checked) {
                  var maxHop;
                  var lqtmp;
                  maxHop = parseInt($.id("l_tr_hop").value, 10);
                  if (isNaN(maxHop) || maxHop < 1 || maxHop > 30) {
                      $.alert(ERR_DIAG_TTL);
                      $.id("l_tr_hop").focus();
                      return
                  }
                  tracert = $.act(ACT_GET, TRACEROUTE_DIAG, null, null, ["maxHopCount", "timeout", "numberOfTries", "host", "dataBlockSize", "X_TP_ConnName", "diagnosticsState", "X_TP_HopSeq"]);
                  var HopCount = 0;
                  var tmp;
                  var loopTime = 500;
                  var traceHost;
                  var tpktsize;
                  if (!$.exe()) {
                      tracert.diagnosticsState = "Requested";
                      tracert.host = $.id("l_addr").value;
                      tracert.dataBlockSize = 64;
                      tracert.timeout = 5;
                      tracert.numberOfTries = 1;
                      tracert.maxHopCount = parseInt($.id("l_tr_hop").value, 10);
                      tracert.X_TP_ConnName = test_conn;
                      tracert.X_TP_HopSeq = 0;
                      HopCount = parseInt($.id("l_tr_hop").value, 10);
                      traceHost = $.id("l_addr").value;
                      tpktsize = 64;
                      maxHop = parseInt($.id("l_tr_hop").value, 10);
                      $.act(ACT_SET, TRACEROUTE_DIAG, null, null, tracert);
                      if (!$.exe()) {
                          $.id("testButton").disabled = true;
                          $.addLoading($.id("testButton"));
                          var i = 0;
                          $.act(ACT_OP, ACT_OP_TRACERT);
                          if ($.exe()) {
                              $.id("testButton").disabled = false;
                              $.removeLoading($.id("testButton"));
                              return
                          }
                          $.auto(function() {
                              tracert = $.act(ACT_GET, TRACEROUTE_DIAG, null, null, ["diagnosticsState", "X_TP_HopSeq", "X_TP_Result"]);
                              if (!$.exe()) {
                                  if ((tracert.X_TP_HopSeq == 0) && (tracert.X_TP_Result != "") && printHeader) {
                                      printHeader = 0;
                                      if (strstr(tracert.X_TP_Result, "traceroute") >= 0) {
                                          disNewLine(tracert.X_TP_Result, ""); ++tracert.X_TP_HopSeq;
                                          loopTime = 500;
                                          tracert.X_TP_Result = "";
                                          $.act(ACT_SET, TRACEROUTE_DIAG, null, null, tracert);
                                          if (!$.exe()) {
                                              return true
                                          }
                                      } else {
                                          if (tracert.diagnosticsState == "Complete" || tracert.diagnosticsState == "None" || tracert.diagnosticsState == "Requested") {
                                              lqtmp = tracert.X_TP_Result
                                          }
                                          var ip = $.act(ACT_GET, TRACEROUTE_DIAG, null, null, ["X_TP_IPAddress"]);
                                          if (!$.exe()) {
                                              result = "traceroute to " + traceHost + " (" + ip.X_TP_IPAddress + "), " + maxHop + " hops max, " + tpktsize + " byte packets";
                                              disNewLine(result, "");
                                              disNewLine(lqtmp, ""); ++tracert.X_TP_HopSeq;
                                              loopTime = 500;
                                              tracert.X_TP_Result = "";
                                              $.act(ACT_SET, TRACEROUTE_DIAG, null, null, tracert);
                                              if (!$.exe()) {
                                                  return true
                                              }
                                          }
                                      }
                                  }
                                  if ((tracert.diagnosticsState != "Requested") && (tracert.diagnosticsState != "None") && (tracert.diagnosticsState != "Complete")) {
                                      disNewLine(tracert.X_TP_Result, "");
                                      tracert.X_TP_Result = "";
                                      $.act(ACT_SET, TRACEROUTE_DIAG, null, null, tracert);
                                      if (!$.exe()) {}
                                      $.id("testButton").disabled = false;
                                      $.removeLoading($.id("testButton"));
                                      return false
                                  } else {
                                      if (tracert.diagnosticsState == "Complete") {
                                          disNewLine(tracert.X_TP_Result, "");
                                          tracert.X_TP_Result = "";
                                          $.act(ACT_SET, TRACEROUTE_DIAG, null, null, tracert);
                                          if (!$.exe()) {}
                                          $.id("testButton").disabled = false;
                                          $.removeLoading($.id("testButton"));
                                          return false
                                      }
                                  }
                                  if (tracert.X_TP_Result != "") {
                                      disNewLine(tracert.X_TP_Result, "");
                                      loopTime = 500; ++tracert.X_TP_HopSeq;
                                      tracert.X_TP_Result = "";
                                      $.act(ACT_SET, TRACEROUTE_DIAG, null, null, tracert);
                                      if (!$.exe()) {
                                          return true
                                      }
                                  }
                                  loopTime += 500;
                                  if (tracert.X_TP_HopSeq == HopCount) {
                                      disNewLine(tracert.X_TP_Result, "");
                                      $.id("testButton").disabled = false;
                                      $.removeLoading($.id("testButton"));
                                      return false
                                  }
                                  if (loopTime >= 150000) {
                                      result = "traceroute to (" + traceHost + ") failed!";
                                      disNewLine(result, "");
                                      $.id("testButton").disabled = false;
                                      $.removeLoading($.id("testButton"));
                                      return false
                                  }
                              }
                          },
                          500)
                      }
                  }
              }
          }
      }
      
  • 3 主要是利用host参数进行注入

0x2 漏洞成因-后端

  • 实现ACT_OP_IPPING的函数位于libcmm.so中的.text:0009A210 oal_startPing:
  • 核心代码以及漏洞点如下
int __fastcall oal_startPing(int a1)
{
  int v3; // $v0
  int v4; // $v0
  int v5; // $v0
  int v6; // $v0
  int v7; // [sp+28h] [-418h] BYREF
  int v8[4]; // [sp+2Ch] [-414h] BYREF
  char str_cmd[1028]; // [sp+3Ch] [-404h] BYREF

  memset(str_cmd, 0, 1024);
  memset(v8, 0, sizeof(v8));
  v7 = 0;
  util_findSystemProc("ipping", 0, (int)str_cmd, (int)"ipping", &v7);
  if ( v7 )
  {
    cdbg_printf(
      8,
      "oal_startPing",
      87,
      "The previous ping to (%s) haven't complete, please wait a few minutes",
      a1 + 268);
    return 1;
  }
  memset(str_cmd, 0, 1024);
  if ( *(_BYTE *)(a1 + 236) && !oal_intf_getIfAddr(a1 + 236, v8) )
  {
    cdbg_printf(8, "oal_startPing", 98, "Get interface(%s)'s IP failed!", a1 + 236);
    return 1;
  }
  v3 = strlen(str_cmd);
  if ( *(_BYTE *)(a1 + 204) )
    snprintf(
      &str_cmd[v3],
      1024 - v3,
      "ipping -c 1 -s %d -w %d %s",
      *(_DWORD *)(a1 + 256),
      *(_DWORD *)(a1 + 260),
      (const char *)(a1 + 268));
  else
    snprintf(
      &str_cmd[v3],
      1024 - v3,
      "ipping -c %d -s %d -w %d %s ",
      *(_DWORD *)(a1 + 264),                    // ping的次数
      *(_DWORD *)(a1 + 256),                    // ping的数据包大小
      *(_DWORD *)(a1 + 260),                    // ping的timeout
      (const char *)(a1 + 268));                // 域名->host
  if ( util_netChkLegalIpAddr((int)v8) )
  {
    v4 = strlen(str_cmd);
    snprintf(&str_cmd[v4], 1024 - v4, " -I %s", v8);
  }
  else if ( *(_BYTE *)(a1 + 236) )
  {
    v5 = strlen(str_cmd);
    snprintf(&str_cmd[v5], 1024 - v5, " -I %s", a1 + 236);
  }
  v6 = strlen(str_cmd);
  snprintf(&str_cmd[v6], 1024 - v6, (const char *)&off_B4C58);
  util_execSystem("oal_startPing", (int)str_cmd);// 直接执行指令
  return 0;
}
  • 首先注入hosta1 + 268
  • 接着程序使用snprintfhost构造出str_cmd
  • 然后util_execSystem直接执行str_cmd
  • ps:str_cmd长度为1024,利用强度还是很高的

0x2 漏洞利用

  • 利用bp构造简单的数据包即可达成利用
  • 1 首先构造host数据包

10.png

  • 2 接着触发指令

11.png

  • 3 查看文件/var/tmp/k44可以发现执行成功

12.png

0x3 exp

  • 完整的利用代码如下
...

0x4 搜集

  • web/js/lib.js
  • https://www.shodan.io
Last modification:June 8, 2022
如果觉得我的文章对你有用,请随意赞赏