2021祥云杯-secrets_of_admin
知识点概要:审计、XSS+SSRF组合拳
首页

有源码,源码结构:
在database.ts
文件里有admin账户密码,可以直接登录。另外可以看出有users和files两个表,还有一个superuser用户
登录之后进入/admin
目录,在文本框随便输入,会提示,大致意思是保存成了pdf文件,但是需要知道怎么下载

源码分析
审计index.ts
,几个关键路由
根目录,做登录验证,登录成功设置cookie,并重定向到/admin
目录
/admin
目录
1.POST提交content参数值,会有几个类似XSS的黑名单过滤;
2.将content直接拼接到一段HTML代码标签里;
3.将HTML代码写入pdf文件,pdf以uuid()的值命名,存在./files/
路径下;
4.用文件名计算checksum值,将superuser、文件名、checksum值一块存入数据库。
/api/files
目录
1.正则匹配请求地址的socket(IP:PORT),要求冒号前(即IP地址)只能是127.0.0.1;
2.GET参数:username、filename、checksum只能是字符串类型,会被存储到数据库
/api/files/:id
目录
1.token的username不能是superuser;
2.token的username和请求参数id会被用来查找数据库文件名;
3.全场唯一读文件函数readFile读取../files/
路径下的对应文件。
数据库getFile()操作代码如下,可以看到传入的参数id对应checksum,从files表中查找对应的文件名
捋一下思路
1.读文件需要token的username是admin,并且知道文件对应的checksum值;
2.要保证token的username是admin,只需正常登录admin账户就可以;
3.文件对应的checksum值则有两条路线,一条是/admin
路由的uuid()
生成的文件名计算所得,这不可控,另一条是通过/api/files
路由的GET参数传入。并且从最初的database.ts可以看到,flag文件属于superuser用户,所以这里也需要通过/api/files
路由传入一条username=admin&filename=flag
的数据,那么checksum就可以随意设置;
4.又因为/api/files
路由只能通过127.0.0.1访问,所以必须通过/admin
路由的XSS来构造SSRF请求;
5./admin
路由的XSS过滤只是对content参数过滤,所以只需以content数组的形式传入即可绕过。
综上,目标:以admin登录,/admin
路由POST传入payload,/api/files/:id
访问
Payload如下
content[]=<img+src%3D"http%3A//127.0.0.1:8888/api/files?username%3Dadmin%26filename%3D./flag%26checksum%3D999">
或
content[]=%3Cscript%3E%0Avar%20xhr%20%3D%20new%20XMLHttpRequest()%3Bxhr.open(%22GET%22%2C%20%22http%3A%2F%2F127.0.0.1%3A8888%2Fapi%2Ffiles%3Fusername%3Dadmin%26filename%3D.%2Fflag%26checksum%3D999%22%2C%20true)%3Bxhr.send()%3B%0A%3C%2Fscript%3E
再访问/api/files/999
,就会把文件下载下来,打开即可看到flag
注:这里端口用8888是因为app.ts
文件中设置路由监听端口是8888