unctf Arbi ( ssrf & express特性利用 )

0x01 题目描述

我们打开题目,是一个简单的登录注册页面
在这里插入图片描述

0x02 解题过程

首先我们随便注册一个账户试试
在这里插入图片描述我们直接F12查看源码,我们可以看见图片的src
在这里插入图片描述


1、我们这儿便联想到ssrf,我们试试看可不可以读取源码,通过测试,我们发现用户名必须和图片的名称相对应,否则会报错,于是我们便可以通过?绕过这个限制,根据题目提示,此网站由js的express搭建,我们知道一般js框架都有package.json文件,于是我们注册用户名为../package.json?,这样便可以读取package.json文件了,由于这个文件在img标签里,所以图片无法显示,我们可以先把图片下载下来,然后用记事本打开就可以,根据提示,flag在根目录/flag中。



2、package.json 显示主入口为mainapp.js,所以继续注册读取mainapp.js文件, 发现路由在 /routers/index.js文件 继续读取 ,读取 /routers/index.js 可以看到有个 VerYs3cretWwWb4ck4p33441122.zip 路由 直接在web上访问即可下载源代码。接下来的便是审计代码了。



3、然后就是白盒审计,可以发现注册登录功能采用了jwt认证,每个人拥有自己独立的jwt secret 并且存在于服务端一个列表中,并且不同用户secret列表对应的id存储在了jwt中,登陆的时候会直接从jwt token中读取id 然后通过列表获取secret 进行解密,这里有个tricknodejsonwebtoken 有个bug,当jwt secret为空时 jsonwebtoken会采用algorithm none进行解密 又因为服务端 通过

 var secret = global.secretlist[id];
 jwt.verify(req.cookies.token,secret);

解密,我可以通过传入不存在的id,让secretundefined,导致algorithmnone,然后就可以通过伪造jwt来成为admin

import jwt
token = jwt.encode({"id":-1,"username":"admin","password":"123456"},algorithm="none",key="").decode(encoding='utf-8')
print(token)


4、成为admin后,就可以访问admin23333_interface接口 审计可以发现,这是一个读取文件的接口 这里用到了express的特性,当传入?a[b]=1的时候,变量a会自动变成一个对象 a = {"b":1} 所以可以通过传入name为一个对象,避开进入if判断 从而绕过第一层
if(!/^key$/im.test(req.query.name.filename))return res.sendStatus(500);
的白名单过滤 第二个过滤是 判断filename 不能大于3,否者会过滤./,而读取flag需要先目录穿越到根目录 而../就已经占了3个字符,再加上flag肯定超过限制 这时候可以换个思路,length不仅可以取字符串长度还可以取数组长度,把filename设数组,再配合下面的循环 即可完美绕过过滤 而express 中当碰到两个同名变量时,会把这个变量设置为数组,例如a=123&a=456 解析后 a = [123,456],所以最终组合成

/admin23333_interface?name[filename]=../&name[filename]=f&name[filename]=l&name[filename]=a&name[filename]=g

此时 name={"filename":["../", "f", "l", "a", "g"]}
完美绕过 if(c !== "/" && c!==".")



0x03 参考链接

链接

发布了47 篇原创文章 · 获赞 2 · 访问量 3131

猜你喜欢

转载自blog.csdn.net/a3320315/article/details/103092073