参考博客:CTFSHOW 菜狗杯--WEB_LZ_KaiHuang的博客-CSDN博客
ctfshow-菜狗杯-抽老婆_Don't know的博客-CSDN博客
打开环境后发现是一个图片下载,看了页面源代码,发现有一处标注,看到下载的路径就敏感起来
尝试读取flag,发现被过滤
再输入随意的图片名称呢?666.jpg,发现没有过滤了,而且在报错中爆出一些路径
有一些路径,看到app.py,猜测有app.py的泄露,这是网站源文件, download?file=../../app/app.py下载下来先看看
发现是python 的flask,在源码里面发现最后有一个/secret_path_U_never_know路径,用get传参条件判断session['isadmin']为真,即可返回flag字段。直接访问看看
发现和源码说的一样需要身份验证
查询后发现flask中的session伪造,代码只需要让session中的isadmin为真就可,这个用的是JWT方式认证,里面签名要用到SECRET_KEY;将isadmin的值更改后,使用密钥SECRET_KEY重新加密生成一个session。
下面是引用大佬的一个解释
这里cookie中的session使用了jwt加密,这里对jwt的知识点做一个补充:
JWT全称是JSON Web Token是一个开放标准(RFC 7519),目前最流行的跨域身份验证解决方案。它定义了一种经过加密的格式,放在json对象在请求中传递,用于验证请求是否被允许访问。
JSON Web Token由三部分组成,它们之间用.连接。 * Header 头部* Payload 负载* Signature 签名
Header 部分用Base64URL解密后是一个JSON对象,主要描述了签名的算法和令牌类型。
{ "alg": "HS256", "typ": "JWT" }Payload 部分同样也是一个JSON对象,它包含Claim。
Claim中存的就是这些字段,有三种类型:
Registered claims 预定义的声明
Public claims 公开声明
Private claims 私有声明JWT 规定了7个Registered claims
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号Signature
Signature 部分是对前两部分的签名,用来防止数据篡改。
服务端指定密钥(secret),使用Header指定的签名算法,用转码后的JWT串产生签名。
jwt加密后,会生成三段以.分割的字符串,解码可以还原到加密前的三部分,我们可以由此入手,伪造能符合验证通过的session值。
我们对抓包到的session值进行jwt解码后得到 "isadmin":=false 如果让它为ture,就可以获得cookie了
通过源码,我们知道app.config['SECRET_KEY'] = 'tanji_is_A_boy_Yooooooooooooooooooooo!'其中tanji_is_A_boy_Yooooooooooooooooooooo!就是key
利用一个开源脚本自动生成,使用脚本进行重新加密:开始构造头,使isadmin为ture
{
"current_wifi": "1c47df4e32edfd634effcc43c1bf3ab7.jpg",
"isadmin": Ture
}运行脚本
python flask_session_cookie_manager3.py encode -s "tanji_is_A_boy_Yooooooooooooooooooooo!" -t "{'current_wifi': '1c47df4e32edfd634effcc43c1bf3ab7.jpg', 'isadmin': True}"
生成了伪造的jwt加密后的session
eyJjdXJyZW50X3dpZmkiOiIxYzQ3ZGY0ZTMyZWRmZDYzNGVmZmNjNDNjMWJmM2FiNy5qcGciLCJpc2FkbWluIjp0cnVlfQ.ZC6syw.Josp6V3pjiP3t3oE_bTWsyYb1Yg
把这个session替换bp中原来的值,即可获得flag了