强网杯线下Router-路由器漏洞挖掘

栏目: 编程工具 · 发布时间: 5年前

内容简介:组委会说这个漏洞是刚报官方还没有披露,所以这里就不说具体的设备厂商和型号了,仅针对题目进行一个分析。之前有过解压bin文件的经验所以选择了直接用binwak解压

组委会说这个漏洞是刚报官方还没有披露,所以这里就不说具体的设备厂商和型号了,仅针对题目进行一个分析。

binwalk&firmware-mod-kit解压

之前有过解压bin文件的经验所以选择了直接用binwak解压

binwalk -Me ./xxx

但是发现解压出来的文件中比较有用的squashfs-root文件夹竟然是空的。于是赶紧去搜一下资料,发现同目录下一个以 .squashfs 的文件可以被解压为文件系统。就下载来试试,利用的是其中的一个 .sh 脚本。

unsquashfs_all.sh ./xxx.squashfs

这样一个完整的文件系统就被解压出来了。其中包含的文件 htdocs 是主要的挖掘对象。

漏洞搜寻

这里对文件夹中的 cgbin 的二进制文件进行分析,用的是之前NASA开源的工具。

强网杯线下Router-路由器漏洞挖掘

看起来像是一个服务解析然后针对服务进行一个函数的调用。

这里我当时所用的技巧是直接定位 system 函数的位置,因为自己太菜了只知道可能有命令注入。。。

强网杯线下Router-路由器漏洞挖掘

命令注入分析

captchacgi_main

undefined4 captchacgi_main(void)

{
  char *__s1;
  int iVar1;
  code *pcVar2;
  undefined4 uVar3;
  char acStack648 [256];
  undefined auStack392 [216];
  undefined auStack176 [164];

  __s1 = getenv("REQUEST_METHOD");
  if (__s1 == (char *)0x0) {
    __s1 = "no REQUEST";
LAB_0040b694:
    cgibin_print_http_status(400,0x420554,__s1);
    uVar3 = 0xffffffff;
  }
  else {
    iVar1 = strcasecmp(__s1,"GET");
    if (iVar1 == 0) {
      pcVar2 = FUN_0040b7e8;
      uVar3 = 0x40;
    }
    else {
      iVar1 = strcasecmp(__s1,"POST");
      if (iVar1 != 0) {
        __s1 = "unsupported HTTP request";
        goto LAB_0040b694;
      }
      pcVar2 = FUN_0040b734;
      uVar3 = 0x400;
    }
    cgibin_parse_request(pcVar2,0,uVar3);
    iVar1 = sess_generate_captcha(auStack392);
    if (iVar1 == 0) {
      printf(
            "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<?xml version=\"1.0\" encoding=\"utf-8\"?><captcha>\n\t<result>FAIL</result><message>NO SESSION</message>\n</captcha>"
            );
      uVar3 = 0;
    }
    else {
      sprintf(acStack648,
              "rndimage -f /htdocs/web/docs/captcha_%d.jpeg -p /usr/sbin/fonts -w 180 -t 40 %s",
              iVar1,auStack176);
      uVar3 = 0;
      system(acStack648);
      printf(
             "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<?xml version=\"1.0\" encoding=\"utf-8\"?><captcha><result>OK</result><message>/docs/captcha_%d.jpeg</message></captcha>"
             ,iVar1);
    }
  }
  FUN_0040b4e0();
  return uVar3;
}

这里反编译有一点奇怪,就是在 sprintf 函数这个位置的austack176并没有赋值,但是通过汇编的分析这个值是固定没有办法进行命令注入。。

lxmldbc_system

void lxmldbc_system(char *pcParm1,undefined4 uParm2,undefined4 uParm3,undefined4 uParm4)

{
  undefined4 local_res4;
  undefined4 local_res8;
  undefined4 local_resc;
  char acStack1036 [1028];

  local_res4 = uParm2;
  local_res8 = uParm3;
  local_resc = uParm4;
  vsnprintf(acStack1036,0x400,pcParm1,&local_res4);
  system(acStack1036);
  return;
}

这里的system参数的开放性很大可以仔细看一下,接着对这个函数进行一个交叉引用的查看。可以找到一个 ssdpcgi_main

undefined4 ssdpcgi_main(int iParm1)

{
  undefined4 uVar1;
  char *__s1;
  char *pcVar2;
  char *pcVar3;
  char *pcVar4;
  int iVar5;
  char *pcVar6;

  uVar1 = 0xffffffff;
  if (iParm1 == 2) {
    __s1 = getenv("HTTP_ST");
    pcVar2 = getenv("REMOTE_ADDR");
    pcVar3 = getenv("REMOTE_PORT");
    pcVar4 = getenv("SERVER_ID");
    if ((((__s1 == (char *)0x0) || (pcVar2 == (char *)0x0)) || (pcVar3 == (char *)0x0)) ||
       (pcVar4 == (char *)0x0)) {
      uVar1 = 0xffffffff;
    }
    else {
      iVar5 = strncmp(__s1,"ssdp:all",8);
      if (iVar5 == 0) {
        __s1 = "%s ssdpall %s:%s %s &";
      }
      else {
        iVar5 = strncmp(__s1,"upnp:rootdevice",0xf);
        if (iVar5 == 0) {
          __s1 = "%s rootdevice %s:%s %s &";
        }
        else {
          iVar5 = strncmp(__s1,"uuid:",5);
          if (iVar5 == 0) {
            __s1 = "%s uuid %s:%s %s %s &";
          }
          else {
            iVar5 = strncmp(__s1,"urn:",4);
            if (iVar5 != 0) {
              return 0;
            }
            pcVar6 = strstr(__s1,":device:");
            if (pcVar6 == (char *)0x0) {
              __s1 = strstr(__s1,":service:");
              if (__s1 == (char *)0x0) {
                return 0;
              }
              __s1 = "%s services %s:%s %s %s &";
            }
            else {
              __s1 = "%s devices %s:%s %s %s &";
            }
          }
        }
      }
      lxmldbc_system(__s1,"/etc/scripts/upnp/M-SEARCH.sh",pcVar2,pcVar3,pcVar4);
      uVar1 = 0;
    }
  }
  return uVar1;
}

这里就有一个命令注入的风险,因为输入的参数是我们可以控制的,这样就发现了第一个漏洞,接下来继续逆一波。

offby\n

当时发现的时候感觉可以更改用户组的权限来达到执行更高指令的目的。

int phpcgi_main(int iParm1,int iParm2,int *piParm3)

{
  char *__s1;
  FILE *__stream;
  undefined4 uVar1;
  code *pcVar2;
  int iVar3;
  int iVar4;
  char acStack40 [24];

  if (iParm1 < 2) {
    iVar3 = -1;
    iVar4 = 0;
    goto LAB_004060e8;
  }
  iVar4 = sobj_new();
  if (iVar4 != 0) {
    sobj_add_string(iVar4,*(undefined4 *)(iParm2 + 4));
    sobj_add_char(iVar4,10);
    while (*piParm3 != 0) {
      sobj_add_string(iVar4,"_SERVER_");
      iVar3 = *piParm3;
      piParm3 = piParm3 + 1;
      sobj_add_string(iVar4,iVar3);
      sobj_add_char(iVar4,10);
    }
    __s1 = getenv("REQUEST_METHOD");
    if (__s1 != (char *)0x0) {
      iVar3 = strcasecmp(__s1,"HEAD");
      if ((iVar3 == 0) || (iVar3 = strcasecmp(__s1,"GET"), iVar3 == 0)) {
        pcVar2 = FUN_00405cdc;
      }
      else {
        iVar3 = strcasecmp(__s1,"POST");
        if (iVar3 != 0) goto LAB_004060e4;
        pcVar2 = FUN_00405aa0;
      }
      iVar3 = cgibin_parse_request(pcVar2,iVar4,0x80000);
      if (iVar3 < 0) {
        if (iVar3 == -100) {
          __stream = fopen("/htdocs/web/info.php","r");
          if (__stream != (FILE *)0x0) {
            fclose(__stream);
            cgibin_print_http_resp(1,"/info.php",&DAT_00420ca4,"ERR_REQ_TOO_LONG",0,0x420554);
          }
        }
        else {
          cgibin_print_http_status(400,"unsupported HTTP request","unsupported HTTP request");
        }
      }
      else {
        uVar1 = sess_validate();
        sprintf(acStack40,"AUTHORIZED_GROUP=%d",uVar1);
        sobj_add_string(iVar4,acStack40);
        sobj_add_char(iVar4,10);
        sobj_add_string(iVar4,"SESSION_UID=");
        sess_get_uid(iVar4);
        sobj_add_char(iVar4,10);
        uVar1 = sobj_get_string(iVar4);
        iVar3 = xmldbc_ephp(0,0,uVar1,stdout);
      }
      goto LAB_004060e8;
    }
  }
LAB_004060e4:
  iVar3 = -1;
LAB_004060e8:
  cgibin_clean_tempfiles();
  if (iVar4 != 0) {
    sobj_del(iVar4);
  }
  return iVar3;
}

信息泄漏漏洞

这个漏洞是一个老洞,但是厂商的修复方法很暴力,只是吧信息泄漏的信息改了,但其实可以leak别的地方的信息。

htdocs/web/getcfg.php

在这个 php 文件中,读者可以自己进行一个分析,网上也有对应的文章,这里选择leak的文件 RUNTIME.WPS.WLAN-1.xml.php 其中就可以读到需要的账户和密码,然后利用一些方法就可以get。因为这个方法是偏web个人的能力实在有限贴出链接:

https://blog.csdn.net/qq_33850304/article/details/92395201

关于路由调试

环境上这里是用qemu搭建的,调试 工具 利用的是ida。

qemu语句

- E  var=value 设置环境变量
- g  port      开启调试模式等待attach
chroot ./qemu-mips 指定根目录运行qemu-mips

完整的语句

echo $INPUT | chroot . ./qemu-mips -g $PORT -E HTTP_ST=$ST -E REMOTE_ADDR=1.1.1.1 -E REMOTE_PORT=1111 -E SERVER_ID=1 -E HOST="239.255.255.250:1900" /ssdpcgi ssdpcgi

ida调试

环境上这里是用qemu搭建的,调试工具利用的是ida。

qemu语句

- E  var=value 设置环境变量
- g  port      开启调试模式等待attach
chroot ./qemu-mips 指定根目录运行qemu-mips

完整的语句

echo $INPUT | chroot . ./qemu-mips -g $PORT -E HTTP_ST=$ST -E REMOTE_ADDR=1.1.1.1 -E REMOTE_PORT=1111 -E SERVER_ID=1 -E HOST="239.255.255.250:1900" /ssdpcgi ssdpcgi

ida调试

先设置remote debug选项

强网杯线下Router-路由器漏洞挖掘

在设置debug选项

强网杯线下Router-路由器漏洞挖掘

接着设置两个debug-options即可

强网杯线下Router-路由器漏洞挖掘

强网杯线下Router-路由器漏洞挖掘

这里主要是选择一下调试的类型,如果你打开了文件就基本不用设置,如果只是attach需要进行一下设置。

总结

因为一些原因这里就不贴出利用的poc了,已知漏洞下这些利用还是比较简单的。这次比赛发现了iot这个大世界的丰富精彩啊。。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

实战Java高并发程序设计

实战Java高并发程序设计

葛一鸣、郭超 / 电子工业出版社 / 2015-10-1 / CNY 69.00

在过去单核CPU时代,单任务在一个时间点只能执行单一程序,随着多核CPU的发展,并行程序开发就显得尤为重要。 《实战Java高并发程序设计》主要介绍基于Java的并行程序设计基础、思路、方法和实战。第一,立足于并发程序基础,详细介绍Java中进行并行程序设计的基本方法。第二,进一步详细介绍JDK中对并行程序的强大支持,帮助读者快速、稳健地进行并行程序开发。第三,详细讨论有关“锁”的优化和提高......一起来看看 《实战Java高并发程序设计》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具