U-Boot NFS RCE漏洞(CVE-2019-14192)
U-Boot NFS RCE漏洞(CVE-2019-14192)
原文:https://blog.semmle.com/uboot-rce-nfs-vulnerability/
翻译:看雪翻译小组 - lipss
校对:看雪翻译小组 - Nxe
这篇文章是关于U-Boot引导加载程序中的13个远程执行代码漏洞的,我和我的同事Pavel Avgustinov和Kevin Backhouse发现了这些漏洞。当U-Boot配置为使用网络来获取下一阶段的启动资源时,可以触发这些漏洞。
请注意,该漏洞尚未通过https://gitlab.denx.de/u-boot/u-boot进行修补,并且我应U-Boot的主要托管人Tom Rini的要求将这些漏洞公开。有关更多信息,请查看下面的时间表。
MITER已针对这13个漏洞发布了以下CVE:CVE-2019-14192,CVE-2019-14193,CVE-2019-14194,CVE-2019-14195,CVE-2019-14196,CVE-2019-14197,CVE-2019 -14198,CVE-2019-14199,CVE-2019-14200,CVE-2019-14201,CVE-2019-14202,CVE-2019-14203和CVE-2019-14204
什么是U-Boot?
Das U-Boot(通常称为“通用引导加载程序”)是一种流行的主引导加载程序,广泛用于嵌入式设备中,以从不同来源获取数据并运行下一阶段的代码,通常(但不限于)Linux内核。IoT,Kindle和ARM ChromeOS设备通常使用它。
U-Boot支持从不同的文件分区格式(例如ext4),以及网络(TFTP和NFS)获取下一阶段的代码。请注意,U-boot支持验证启动,在其中检查获取的映像是否被篡改。这样可以减轻使用不安全的明文协议(例如TFTP和NFS)的风险。因此签名检查之前的任何漏洞都可能意味着设备越狱。
我正在使用U-boot,会受到影响吗?
这些漏洞影响非常特定的U-Boot配置,其中指示U-Boot使用网络。这些漏洞中的一些存在于NFS解析代码中,而其他一些则存在于通用TCP / IP堆栈中。
此配置通常用于无盘IoT部署和快速开发过程中。
有什么影响?
通过这些漏洞,同一网络(或控制恶意NFS服务器)中的攻击者可以在U-Boot驱动的设备上执行代码。由于此漏洞的性质,利用似乎并不十分复杂,尽管可以通过使用堆栈cookie,ASLR或其他运行时和编译时的内存保护机制来提高其挑战性。
明白了,这些漏洞是什么?
通过源代码审查在2个非常相似的事件中发现了第一个漏洞,我们使用了Semmle的LGTM.com和QL来查找其他漏洞。它是普通的memcpy
溢出,攻击者控制的大小来自网络数据包,没有任何验证。
该问题存在于nfs_readlink_reply
解析来自网络的nfs答复的函数中。它解析4个字节,并且无需进一步验证,就在两个不同位置中将它们用作memcpy
的长度。
static int nfs_readlink_reply(uchar *pkt, unsigned len)
{
[...]
/* new path length */
rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]);
if (*((char *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset])) != '/') {
int pathlen;
strcat(nfs_path, "/");
pathlen = strlen(nfs_path);
memcpy(nfs_path + pathlen,
(uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]),
rlen);
nfs_path[pathlen + rlen] = 0;
} else {
memcpy(nfs_path,
(uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]),
rlen);
nfs_path[rlen] = 0;
}
return 0;
}
目标缓冲区nfs_path
是一个全局缓冲区,最多可容纳2048个字节。
使用QL的变异分析
以下查询为我们提供了9个列表,以便手动进行跟踪。查询背后的想法是从任何辅助函数(例如ntohl()
/ ntohs()
...)到memcpy
的size参数来执行数据流分析。
import cpp
import semmle.code.cpp.dataflow.TaintTracking
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
class NetworkByteOrderTranslation extends Expr {
NetworkByteOrderTranslation() {
// On Windows, there are ntoh* functions.
this.(Call).getTarget().getName().regexpMatch("ntoh(l|ll|s)")
or
// On Linux, and in some code bases, these are defined as macros.
this = any(MacroInvocation mi |
mi.getOutermostMacroAccess().getMacroName().regexpMatch("(?i)(^|.*_)ntoh(l|ll|s)")
).getExpr()
}
}
class NetworkToMemFuncLength extends TaintTracking::Configuration {
NetworkToMemFuncLength() { this = "NetworkToMemFuncLength" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof NetworkByteOrderTranslation
}
override predicate isSink(DataFlow::Node sink) {
exists (FunctionCall fc |
fc.getTarget().getName().regexpMatch("memcpy|memmove") and
fc.getArgument(2) = sink.asExpr() )
}
}
from Expr ntoh, Expr sizeArg, NetworkToMemFuncLength config
where config.hasFlow(DataFlow::exprNode(ntoh), DataFlow::exprNode(sizeArg))
select ntoh.getLocation(), sizeArg
我们找到任何变体了吗?
我们检查了结果,虽然有些数据在从源到接收器的数据流之间进行了大小检查,但发现有些数据是可利用的。此外,我们通过源代码审查发现了其他一些变体。
nfs_lookup_reply
中失败的长度检查导致未限界memcpy
nfs_lookup_reply
函数再次解析来自网络的nfs答复时存在此问题。它解析4个字节,并在两个不同位置中将它们用作memcpy
的长度。
进行长度检查以确保它不大于分配的缓冲区。不幸的是,可以用负值绕过此检查,这将在以后导致较大的缓冲区溢出。
filefh3_length = ntohl(rpc_pkt.u.reply.data\[1]);
if (filefh3_length > NFS3_FHSIZE)
filefh3_length = NFS3_FHSIZE;
memcpy(filefh, rpc_pkt.u.reply.data + 2, filefh3_length);
目标缓冲区filefh
是一个全局缓冲区,最多可容纳64个字节。
nfs_read_reply
/store_block
中失败的长度检查导致未限界memcpy
nfs_read_reply
读取文件并将其存储到另一种介质(闪存或物理存储器)中以供以后处理时,该函数中存在此问题。同样,数据和长度由攻击者完全控制,并且从未验证。
static int nfs_read_reply(uchar *pkt, unsigned len)
{ [...]
if (supported_nfs_versions & NFSV2_FLAG) {
rlen = ntohl(rpc_pkt.u.reply.data[18]); // <-- rlen is attacker-controlled could be 0xFFFFFFFF
data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]);
} else { /* NFSV3_FLAG */
int nfsv3_data_offset =
nfs3_get_attributes_offset(rpc_pkt.u.reply.data);
/* count value */
rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]); // <-- rlen is attacker-controlled
/* Skip unused values :
EOF: 32 bits value,
data_size: 32 bits value,
*/
data_ptr = (uchar *)
&(rpc_pkt.u.reply.data[4 + nfsv3_data_offset]);
}
if (store_block(data_ptr, nfs_offset, rlen)) // <-- We pass to store_block source and length controlled by the attacker
return -9999;
[...]
}
关注store_block
函数的物理内存部分,它尝试使用特定于arch的函数map_physmem
保留一些内存,最终调用phys_to_virt
。正如您在x86实现中所看到的那样,在保留物理内存时,它显然忽略了长度,并为您提供了原始指针,而没有检查周围区域是否为其他目的保留。
static inline void *phys_to_virt(phys_addr_t paddr)
{
return (void *)(unsigned long)paddr;
}
其后在store_block
中有一个攻击者控制的源和长度的memcpy
缓冲区溢出。
static inline int store_block(uchar *src, unsigned offset, unsigned len)
{
[...]
void *ptr = map_sysmem(load_addr + offset, len); // <-- essentially this is ptr = load_addr + offset
memcpy(ptr, src, len); // <-- unrestricted overflow happens here
unmap_sysmem(ptr);
[...]
}
flash_write
代码路径中也可能存在类似的问题。
由于整数下溢,在解析UDP数据包时出现未限界memcpy
函数net_process_received_packet
在未经验证的情况下使用ip->udp_len
会导致整数下溢。其后,此字段将用于通过net_set_udp_handler
(DNS,dhcp,...)设置的memcpy
atnc_input_packet
和所有udp数据包处理函数中。
#if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_SPL_BUILD)
nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE,
src_ip,
ntohs(ip->udp_dst),
ntohs(ip->udp_src),
ntohs(ip->udp_len) - UDP_HDR_SIZE); // <- integer underflow
#endif
/*
* IP header OK. Pass the packet to the current handler.
*/
(*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE,
ntohs(ip->udp_dst),
src_ip,
ntohs(ip->udp_src),
ntohs(ip->udp_len) - UDP_HDR_SIZE); // <- integer underflow
请注意,我们并未审计为不同目的(DNS,DHCP等)设置的所有潜在udp处理程序。但是,我们确实对nfs_handler
进行了审计,如下所述。
响应辅助函数nfs_handler
中多个基于堆栈的缓冲区溢出
这是上述漏洞的代码审查变体。在此,当解析很大的ip->udp_len
参数的udp数据包时会发生整数下溢,随后又调用nfs_handler
。在此函数中,同样没有对长度的验证,我们将调用辅助函数,例如nfs_readlink_reply
。该函数盲目使用长度而不进行验证,从而导致基于堆栈的缓冲区溢出。
static int nfs_readlink_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
[...]
memcpy((unsigned char *)&rpc_pkt, pkt, len);
我们确定了5个不同的易受攻击的函数,它们遵循相同的代码模式,从而导致基于堆栈的缓冲区溢出。除了nfs_readlink_reply
之外,还有:
rpc_lookup_reply
nfs_mount_reply
nfs_umountall_reply
nfs_lookup_reply
nfs_read_reply
中读取越界数据
这与以前的漏洞非常相似。开发人员试图在复制来自套接字的数据时执行大小检查,以保持谨慎。当他们检查以防止缓冲区溢出时,他们没有检查源缓冲区中是否有足够的数据,从而导致潜在的读取越界访问冲突。
static int nfs_read_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
[...]
memcpy(&rpc_pkt.u.data[0], pkt, sizeof(rpc_pkt.u.reply));
攻击者可以向NFS数据包提供读取请求和发送给套接字的较小数据包请求。
有什么建议吗?
为了缓解这些漏洞,只有两种选择:
- 补丁发布后立即应用,或者
- 处于可攻击时,请勿通过NFS或任何U-Boot网络功能挂载文件系统
披露时间表
此漏洞报告受披露政策的约束,在此处可见https://lgtm.com/security/#disclosure_policy。
- 2019年5月15日-Fermín Serna最初发现了两个漏洞,并编写了一个QL查询,以发现另外三个有问题的调用处。
- 2019年5月16日-Pavel Avgustinov带来了一些QL魔术,概括了查询并找到了更多解析ip和udp标头的函数。
- 2019年5月23日-Kevin Backhouse通过nfs_handler向Pavel和Fermín警告有关基于堆栈的缓冲区溢出的疏忽。
- 2019年5月23日-Semmle安全团队结束调查并通过电子邮件联系维护者。
- 2019年5月24日-Tom Rini(U-Boot的主要托管人)确认收到安全报告。
- 2019年7月19日-Tom Rini请求在其公共邮件列表u-boot@lists.denx.de上公开此报告。
- 2019年7月22日-为了避免周末披露,Fermin将该报告通过u-boot@lists.denx.de公开。
U-Boot NFS RCE漏洞(CVE-2019-14192)的更多相关文章
- Zimbra无需登录RCE漏洞利用
2019年3月13号,一名国外的安全研究员在他的博客上公布了zimbra RCE漏洞相关信息,但其中并未提到一些漏洞利用细节. 经过一段时间努力,根据网上各位大牛的分析和我自己的理解,在此我将整个漏洞 ...
- WordPress插件Social Warfare<=3.5.2 无需登录RCE漏洞
该漏洞只存在于Social Warfare插进的3.5.0.3.5.1和3.5.2版本中,其他版本不存在. 2019年3月21日插件作者紧急发布了3.5.3版本以修复高危的RCE漏洞,在<=3. ...
- 威胁快报|首爆,新披露Jenkins RCE漏洞成ImposterMiner挖矿木马新“跳板”
简介 阿里云安全于近日捕获到一起使用Jenkins RCE漏洞进行攻击的挖矿事件.除挖矿外,攻击者还曾植入具有C&C功能的tsunami木马,也预留了反弹shell的功能,给用户带来极大安全隐 ...
- ThinkPHP-5.0.23新的RCE漏洞测试和POC
TP5新RCE漏洞 昨天又是周五,讨厌周五曝漏洞,还得又得加班,算了,还是先验证一波.新的TP5RCE,据说发现者因为上次的RCE,于是又审计了代码,结果发现的.TP5也成了万人轮啊. 测试 环境搭建 ...
- GitStack系统RCE漏洞学习
漏洞简介 漏洞简情 漏洞程序 GitStack 影响版本 <=2.3.10 漏洞类型 RCE 漏洞评价 高危 漏洞编号 CVE-2018-5955 漏洞程序介绍 GitStack是一款基于Pyt ...
- Joomla 3.0.0 -3.4.6远程代码执行(RCE)漏洞复现
Joomla 3.0.0 -3.4.6远程代码执行(RCE)漏洞复现 一.漏洞描述 Joomla是一套内容管理系统,是使用PHP语言加上MYSQL数据库所开发的软件系统,最新版本为3.9.12,官网: ...
- Apache Solr Velocity模板注入RCE漏洞复现
Apache Solr Velocity模板注入RCE漏洞复现 一.Apache Solr介绍 Solr是一个独立的企业级搜索应用服务器,它对外提供类似于web-service的API接口,用户可以通 ...
- Apache Shiro<=1.2.4反序列化RCE漏洞
介绍:Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理. 漏洞原因:因为shiro对cookie里的rememberme字段进行了反序列化,所以如果知道了 ...
- Joomla 3.0.0 - 3.4.6 RCE漏洞分析记录
0x00 前言 今天早上看到了国内几家安全媒体发了Joomla RCE漏洞的预警,漏洞利用的EXP也在Github公开了.我大致看了一眼描述,觉得是个挺有意思的漏洞,因此有了这篇分析的文章,其实这个 ...
随机推荐
- CSS滑动门
如下图所示,每个导航栏目的文字个数不一样多,有的长,有的短,如何用一张背景图片,适应不同字数”的导航条,“滑动门”设计的非常巧妙,采用两个相同的背景图像,一左一右,一个负责提供左边框,一个负责提供右边 ...
- Linux中三种SCSI target的介绍之各个target的优劣
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/scaleqiao/article/deta ...
- 【模板】最小割树(Gomory-Hu Tree)
传送门 Description 给定一个\(n\)个点\(m\)条边的无向连通图,多次询问两点之间的最小割 两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不 ...
- Linux下的find命令详解
0x01 简介 find命令用来在指定目录下查找文件.任何位于参数之前的字符串都将被视为欲查找的目录名.如果使用该命令时,不设置任何参数,则find命令将在当前目录下查找子目录与文件.并且将查找到的子 ...
- docker-machine 远程安装docker
base=https://github.com/docker/machine/releases/download/v0.14.0 && curl -L $base/docker-mac ...
- Kafka(三) —— 集群监控
任何应用功能再强大.性能再优越,如果没有与之匹配的监控,那么一切都是虚无缥缈的.监控不仅可以为应用提供运行时的数据作为依据参考,还可以迅速定位问题,提供预防及告警等功能,很大程度上增强了整体服务的鲁棒 ...
- 一段js MD5。加密 转换C#语法过程
A 帮忙把这段js脚本转换 c#语言. JS: function md5 (bit,sMessage) {debugger //var sMessage = this; function Rotate ...
- google chrome 浏览器插件
如果感觉浏览器(chrome)的背景是白色太亮太刺眼,可以先在 设置->外观->主题背景 里选择 oceanic,将浏览器头部颜色设置为海蓝色.然后再安装插件 “眼睛护航”,改变所有网页的 ...
- Python有堆栈/堆,如何管理内存?
Python有堆栈/堆,如何管理内存? - 代码日志 https://codeday.me/bug/20171016/86264.html
- Android从5.0到9.0版本的主要变更
https://www.jianshu.com/p/10bdbf883c46?utm_source=desktop&utm_medium=timeline Android5.0 1.虚拟机 在 ...