首页 > WriteUp > 2016 SWPU CTF的WriteUp

2016 SWPU CTF的WriteUp

2016年10月28日 发表评论 阅读评论

前言&乱七八糟的话

之前在公司群看到军爷说是想看看这个比赛,想一起搞搞,这是背景一。
刚好周四去北京出差了,出差的主要目的是给华北电力的各位童鞋做培训,同学们纷纷表示想打一下真正的CTF,这是背景二。
于是综上两个背景,从周六开始我也参与到这次CTF中了,吐槽一下,题目名字真心乱,这让我写WriteUp都没办法好好写- -!
当然比赛过程中,和出题人也交(P)流(y)了不少,很感谢出题人的慷概解答和循循善诱
对了,还有个槽点
比赛地址:http://ctf.08067.me/
08067,远程溢出,太imba了
平心而论,比赛的题目还是很有意思的,很感谢主办方给了一个这样的环境,里面也学到了一些新的姿势,从题目方面看得出来各位童鞋Web狗居多啊2333

签到题

题目信息

地址: QQ群:184517991
分值: 50
Flag: flag{welcome_swpu_ctf}

解题过程

进入他们官方的QQ群,找了一圈没找到Flag,然后问了下管理员,管理员表示Flag在历史公告,But我的Mac QQ并不能看历史公告,于是。。。


嗯,这是一道送分题

Misc150(Misc2)

题目信息

地址: http://misc.08067.me/misc2/misc.pcapng
分值: 150
Flag: flag{Rgb_dhskjadyhjksndjsagh}

解题过程

得到是个pcapng包,直接丢WireShark
发现有一大堆的HTTP通信包,于是直接看下HTTP的导出对象里有什么,果然功夫不负有心人


有一个名为flag.zip的文件,解压开,得到一个名为ce.txt的文件,打开之后发现其记载的似乎是一些RGB值

然后估计应该是依据这些RGB值来画图,看了一下这些信息,有98457行
然后首先要得到图片的长和宽,把98457因式分解下可得到

感觉887作为长是比较OK的,37*3作为宽,于是得到图片大小为887 * 111
接下来写个小程序就可以画出来了

Misc100(Misc4)

题目信息

地址: http://misc.08067.me/misc4/fuck.html
分值: 100
Flag: flag{wjTdUoAgqzxxnjfa9kan}

解题过程

老实说,这也是一道送分题,给的说明是fuck!!fuck!!,进去一看,乐了,JSFuck,于是估计下一个是BrainFuck


直接丢Chrome的Console跑一下

还真是BrainFuck

找到一个在线运行这玩意的网站,拿到了Flag
https://www.nayuki.io/page/brainfuck-interpreter-javascript

Web200-1(Web1)

题目信息

地址: http://web1.08067.me/
分值: 200
Flag: flag{sql_iNJEct_comMond_eXEC!}

解题过程

只给了一个登录框,然后没了,那么尝试了一下admin, admin提示密码错误,再尝试了下其他的用户名密码,提示用户名错误,确定用户名就是admin
然后尝试了下万能密码,发现是有WAF检测的


另外HTTP头这里给出了提示

base64_decode之后内容为

得到了他的查询语句。
如果被ban了则提示illegal character!!@_@
那么首先先看下都有哪些被ban了,经过Fuzz发现

等等,都是被ban掉了,所以我们可用的就剩下

以及不含关键词的mysql自带函数
于是这是肉眼可见的一个盲注,接下来怎么注入就是问题了
显然没了空格,那么得先找到一个办法不需要空格也能注入的,因为*被Ban了所以注释代替空格也废了
在网上查找了一番,发现可以利用括号来代替空格

这两条语句是没有任何区别的


于是,在这里我们可以用()来绕过空格被过滤的情况,第一步,大功告成,
然后接下来,得想一个办法把末尾的’消灭掉,因为用空格代替之后的语句最后一个肯定是),But人家原先的语句最后一个肯定是’,所以接下来就需要构造我们的布尔条件了
在mysql的where里,允许如下这种的比较


其比较过程从左至右,依次比较,需要注意的是,在mysql里字符串表示为真,数字1(字符串格式的数字同样)同样表示为真,数字0(字符串格式的数字同样)可以表示为假,没取到数据也可以表示为假

于是最后的结果为真,所以我们可以控制的是他的逻辑
让原先的查询条件(user=xxx)为假,让最后的比较(xxx=’0′)为假,这样我们在中间的1就可以自己任意控制了,再加上mysql的子查询,就可以构造出完整的payload

提交之后发现提示password error,说明uname取出来了,即我们给出的条件为真


但是如果没取出来,则提示username error,说明uname没取出来,即我们给出的条件为假

于是接下来我们只要跑这个布尔盲注即可
然后猜passwd有多少位,二分法,最多100位,他不会真丧心病狂的把passwd搞成100位以上吧


passwd有32位,猜测是个md5,
然后发现有个坑···逗号被ban了,尴尬,mid substr都废了,But这俩要废了,布尔盲注就相当于废了,本着不信邪的原则上网各种找资料
http://www.2cto.com/Article/201609/545408.html找到这么一段话

逗号绕过
在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from to的方式来解决。

但是for里又包含关键词or,所以for也不能用,最后尝试把for 1直接删掉,发现是可以执行的
不断变换最后from的1(N),则mid或是substr将会从右往左开始取第N位到末尾
上个图就很容易看明白了


OK,最后一个问题也解决了,愉快的注入吧
这里写了个python的小脚本来慢慢跑

很快结果就出来了

扔到cmd5查一下


OK,得到密码为1234567mn,直接用admin登陆进去吧
登陆进去懵逼了,一脸懵逼,对角懵逼,排比懵逼,二叉树懵逼,霍夫曼懵逼,薛定谔懵逼,空中转体两周半懵逼,阿姆斯特朗回旋加速式阿姆斯特朗懵逼,反正就是各种懵逼就对了

What The Fuck!!!!,这踏马是个什么鬼!!!说好的Flag呢!!!
看来还有最后的考验,看起来像是命令执行,执行成功会有提示,失败了也会有提示,就是没有回显,然而一旦命令里有空格就GG了,好吧,找个在linux能代替空格的东西
在本机尝试之后,发现这玩意,也就是制表符能代替Linux命令行下的空格
最后就是解决回显的问题了,在问了出题人之后,确认了自己的思路,需要利用Cloud Eye或是Web Server Log把数据透传出来
那简单了,利用这个把命令裹起来,然后curl到自己服务器,直接查看自己服务器的Web Server Log就可以知道数据了
最终的payload

执行完成之后用head和tail取其中第N条数据,然后带着这个数据去访问我的服务器,我只要查看我的webserver的log就可以了


看来flag不在当前目录,跳到上层目录看看


上层目录也没有,再往上看


嗯,看到flag了,cat下看看


搞定,flag似乎少了{},在flag之后和末尾加上就好了

WEB200-2(Web3)

题目信息

地址: http://web3.08067.me/wakeup/index.php
分值: 200
Flag: flag{WakEup!_v1ry_f4N}

解题过程

提示,出题人喜欢在编辑器下修改代码,于是猜测是不是有.bak .swp文件,查看了一下robots.txt和bak swp文件
得到两个bak
/wakeup/index.php.bak

/wakeup/index.php.bak

从代码逻辑可以看到从Cookie里取user的值,然后base64_decode,然后反序列化到login这个类,反序列化之后先执行__wakeup(),然后执行__destruct()
在__wakeup()里可以看到几乎过滤了全部注入/XSS的关键词


所以首先要把__wakeup()给Bypass掉
在网上寻找之后,发现在php5.6以下的版本是有一漏洞的,CVE-2016-7124
http://www.tuicool.com/articles/aMfeEfJ
https://bugs.php.net/bug.php?id=72663
当序列化之后的字符串定义的的元素个数与实际个数不符合的时候(定义个数大于实际个数),__wakeup()将不会执行
那么接下来构造序列化字符串就行

当使用第二条序列化的字符串时,将会绕过__wakeup()的执行
OK,第一步已经完成了,接下来想办法绕过help::CheckSql()的检查即可
这里卡了半天,最后不得已问了下出题人,出题人表示这里是个时间盲注,然后看了下代码,sleep被ban了。然后再问出题人,出题人表示和80sec-ids有关,然后就不说话了- -!
在DeDeCMS里用的也是这一个WAF,在网络上查找一番之后,发现如果数据被两个引号包裹的话,就不会进行检测,也就意味着sleep可以逃逸出来了,然后想办法把引号包含进去,在查(xun)阅(web)过相关(chu)资(ti)料(ren)之后,了解到在mysql中,以
包裹的字符串会当做表名/列名处理,如果是包裹的单引号的话,也就相当于什么都没有包裹,于是只要改变原有的where条件就可以了。
那么最终的payload就是

写个小程序去处理这一切吧

差不多5分钟左右flag就出来了(时间盲注真够蛋疼的)
这里是成功的图

REVERSE50(CM50)

题目信息

地址: http://misc.08067.me/CM50/CM50.exe
分值: 50
Flag: Flag{sWpU_the_1_R3}

解题过程

讲道理,这题也是一个送分题,基本可以看做是Reverse类型的签到题
下载下来是个exe,打开之后提示缺少两个dll,mfc120ud.dll和msvcr120d.dll,补齐dll后界面如图所示


丢到IDA里没发现啥东西,然后突发奇想是不是把什么元素/控件隐藏起来了,于是用ResHacker打开看看,果不其然Flag就在其中

REVERSE100(CM100)

题目信息

地址: http://misc.08067.me/CM100/CM100.exe
分值: 100
Flag: Flag{lr{-l0F-)uFe?}

解题过程

CM100不是我做的,找了Incken帮我搞定的,所以这里也就直接让他帮我写了这题的WP。
先查下壳,没有。直接扔进OD,运行。提示“wrong”,在堆栈向下找



这里似乎是flag,但其实不是。还是静态分析吧。
在ida里直接搜索字串flag。

找到位置直接F5看C代码。

获取输入值后先与12345678异或,然后与26544631比较,真则设dword_DE4028为1,否则设0并报”wrong”。
之后异或值再与12345678异或参与真flag的计算。Text为假flag字串。
上图中标出的位置应该是由于不小心,导致了V10的访问过界。应该是i % 8。
剩下就简单了,所以最后的密码也就是输入值与12345678异或之后和26544631
反过来就是

通过12345678与26544631异或算出正确输入值.
然后让程序告诉我们真的flag吧。

WEB50(Web签到)

题目信息

地址: http://139.196.35.85/
分值: 50
Flag: flag{This_a_web!}

解题过程

Web系列的签到题,右键查看源代码就行

REVERSE150

题目信息

地址: http://misc.08067.me/CM150/cm150.apk
分值: 150
Flag: Flag{I’m_s0_Tir3D|T-T}

解题过程

题目是个apk,安装上去之后只有一个输入框和一个按钮


不说话,直接拖到jadx里看源代码,在com.example.test1这个包的MainActiveity里就可以直接看到代码

根据代码流程,输入的字符串要为16位,然后进行Encode1
Encode1的过程如下
把字符串的每个字符的ASCII HEX转成数组(toCharArray),
每一位与0x29异或,然后把
第14位的值设为第2位
第13位的值设为第3位
第12位的值设为第4位
第11位的值设为第5位
第10位的值设为第6位
第9位的值设为第7位
然后结果return回去,Encode1就完了,进入Encode2阶段
在Encode2阶段,把每个双数位的值换成相应位置输入的值
例如输入abcdefghijklmnop,encode之后的结果为|rspqvwttwvqpsrm
然后进入encode2,双位替换

经过Encode2的结果与{73, 48, 109, 97, 115, 46, 95, 116, 105, 111, 51, 89, 124, 73, 45, 73}的每一位比较
所以第一步就可以先把Encode2的结果推回去,先转换为ASCII字符 I0mas._tio3Y|I-I

然后在Encode1里有交换,所以可以得出交换赋值之前的内容

妈的想不来,写不下去了,
反正我是把算法拿出来,比较的时候打印人工爆破出来的


经过无数次尝试(大约50来次吧),得出的答案是I*m*s*_*ir3D|T-T * 代表任意字符,也就是说此题有多解

问了下出题人,截图给出题人证明之后,出题人给了flag

REVERSE200

题目信息

地址: http://misc.08067.me/CM200/CM200.exe
分值: 200
Flag: Flag{y3s_Is_tH3_LaSt}

解题过程

这题也是Inkcen表哥做的,办法很暴力,按位爆破,按照他的话说,为什么要按位做检测呢- -!
直接附上爆破代码和截图吧


每一位输入之后可以检测,那么接下来就类似于盲注一样,一位一位检测就可以拿到所有的了

WEB100

题目信息

地址: http://web2.08067.me/
分值: 100
Flag: flag{this_is_fl@g_1}

解题过程

讲道理,这题界面很炫


嗯,很Imba,我很喜欢
看到提示有include.php,于是访问一下,发现没有什么,看了下源代码,发现新的tips

目前就凭这两个文件名,可以看出这题应该是上传一个东西,然后给包含进来
访问了下upload.php,发现只能上传jpg/png/gif,其他的都上传不上去
然后看了下include,用file参数包含下自己,发现失败,然后问了下军爷,他说你把.php删掉试试,结果….

竟然终止了,看来他会自己把.php后缀加上,所以成了无限递归包含了,于是想想怎么把php传上去
在网上查了相关文章之后,发现phar伪协议可以满足这个要求
http://www.hackdig.com/09/hack-26779.htm
把php文件打包成zip,后缀改为jpg,上传上去,然后利用phar伪协议包含进来
我这里打包了两个文件,一个为phpinfo.php,一个为yijuhua.php

成功,于是直接访问webshell

在shell目录下有个swpu_wbe2_tips.txt,打开之后得到该题Flag,还有下题的提示

WEB200-3

题目信息

地址: http://web2.08067.me/
分值: 200
Flag: flag{You_get_the_root_–!}

解题过程

从上题得到的提示,看样子是要提权,有一个tomcat.08067.me的域名,问了一下出题人,tomcat和web2这台服务器是同一台服务器
翻了一下服务器上的文件,发现在icematcha这个用户的家目录下有个tomcat_restart.sh文件


访问了下是tomcat的默认页面,管理页面被改过无法访问,于是在这里想了一下是不是要利用tomcat去提权呢,搜了一下果然是这个思路
http://blog.csdn.net/jlvsjp/article/details/52776377
跟着这篇文章从头看了下,所有提权特征就差tomcat权限的用户了,这篇文章对整个提权漏洞的分析还是很透彻的
php的shell的权限为www-data,所以得把权限换成tomcat
啥都不说了,先找一下tomcat路径,扔一个jsp的马上去
tomcat的默认路径在/var/lib/tomcat6/,往/var/lib/tomcat6/webapps/ROOT/写一个jsp的马,然后反弹shell

然后把tomcat的提权exp丢上去,直接提权
提权过程需要path_to_catalina.out这个文件的绝对路径,该文件在/var/lib/tomcat6/logs/catalina.out

MISC100-2

题目信息

地址: http://misc.08067.me/misc3/misc.jpg
分值: 100
Flag: flag{kaSaI_fbnkjdksSFGHFkfjksabfdJNKLDWOIafsadf}

解题过程

拿到一个图片,然后直接丢010editor,发现尾部有数据


拿出来,然后base64_decode失败,base32_decode解开了

可以拿到解开的数据vbkq{ukCkS_vrduztucCVQXVuvzuckrvtZDUBTGYSkvcktv}
然后看起来像是移位,前四位肯定是flag,然后去研究规律···
-16相当于v向前推16位,也就相当于向后推10位,所以可以看做+10
老实说这里规律我我一开始的以为两位+10,两位-10

解出来之后发现不对···然后懵逼了
不得已去问了下出题人,确认此题是不是有问题,,出题人表示题目没问题,并让我尝试奇偶变换,
然后不管怎么奇偶变化都解不出来flag,然后再问了一下(原谅我这么不要脸),让我把字母奇偶变换
瞬间明白

于是写了个程序让他自己完成变换的过程

解出来之后是flagqkaSaIUfbnkjdksSFGHFkfjksabfdJNKLDWOIafsadfs,然后把三个符号再换回去就得到flag了

WEB400

题目信息

地址: http://web4.08067.me/
分值: 400
Flag: flag{I_L0vE_xx1a0m4i}

解题过程

这题是个代码审计的题目,扫描发现有web.zip
下载下来之后即为整站的源代码
首先在common.php里。可以看到把提交过来的各类参数foreach成k,v
common.php

在foreach最后的赋值阶段,对value进行了addslashes,所以这里是没办法代入一些奇怪的东西的
但是这里会存在一个可能导致变量覆盖的问题
如果接下来哪个页面没有定义某个变量,但是调用到了,就会发生变量覆盖的问题
然后去找找哪里有未定义的变量,找了一圈,就发现只有riji.php里有这么一段可疑的代码
riji.php

假如$result[‘userid’]没有东西,则$id就不会被定义,然后接下来选取文章的时候就可以进行注入了
要使$result[‘userid’]取不到东西,就要$_SESSION[‘user’]不存在,于是看了一下,$_SESSION[‘user’]是在登录的时候定义的,但是整体代码没有什么地方进行unset,所以只要让$_SESSION[‘user’]不存在就可以了。
然后跟着这个思路,再看看如何让$_SESSION[‘user’]不存在,又看了一下,发现在api.php里有删除账号的操作,如果可以删除掉一个账户,而保持该账户的登录状态,
那么在riji.php里取$result[‘userid’]的时候,就会取不到东西,这时候就可以自己传入一个id值,实现变量覆盖
api.php

从代码中可以看出,传入一个序列化的数据,然后进行反序列化之后进入check,于是要调用api.php,必须要知道admin用户的salt,data和username是自己传入的,所以是可以控制的
salt这个在登录的时候会设置在cookie里

一开始我以为是要重置掉admin的密码,结果发现重置密码是要拿到admin的mibao的,但是mibao是无论如何都拿不到的。各种尝试都没办法
于是无奈,又求助于出题人(出题人是真心的大好人呐)
出题人给出了一点提示,hash扩展攻击
Bingo!
查阅了一下原理
http://blog.csdn.net/syh_486_007/article/details/51228628
然后,再找回密码的地方可以拿到salt在MD5之后的值


base64_decode之后为917cc87f88b8833632b012418a7211ad
在github上找到了相应的工具,自己生成出了需要的hash
https://github.com/iagox86/hash_extender

拿到了hash扩展攻击之后的数据,生成base64,同时记录下利用该数据的md5 8f4d7a58b13a34d34f8384595a3de5f7

然后登陆,登陆过程抓包,拿到自己账户的id

我自己的账户id为100,然后新开一个隐身窗口(为了防止cookie冲突)访问api,删除账户

然后拿着这个生成好的base64字符串调用接口删除用户


删除完成之后,访问riji.php,抓包,拿到PHPSESSID,直接丢sqlmap跑就行

WEB300

题目信息

地址: http://web5.08067.me/
分值: 300
Flag: Flag{It_iS_s0_ea3y_!!!!!!!!!_FUCK_!!!!!}

解题过程

输入自己网站么,先输入了一下自己的,发现是把请求的内容返回来了,于是猜测这里有SSRF


于是查了一下操作系统类型,CentOS 6.5

查一下IP 172.16.181.165

利用SSRF扫了一下内网,发现存在166这台主机

然后顺手一个admin,居然存在,然后又顺手一个login.php 居然又存在,hhhhh

form表单提交到wllmctf_login.php了,看样子是要登陆进去了
登录需要POST,查阅资料了解到可以用gopher协议提交POST的表单
payload

于是开始尝试,发现在username这里存在盲注

接下来跑注入就行了
一样,交给脚本去处理

基础的pyaload也就是inje了,接下来猜库猜表猜内容
首先是获取数据库名长度,二分法,数据库名长度为7

长度为7,然后查库名叫啥

数据库名字为wllmctf
然后查这个库有几个表

只有一个表,有意思,查这个表名字长度

表名长度为4,查表名叫啥

表名ssrf,果然有意思
表里有几个字段

2个字段,查询第一个字段名长度

第一个字段名长度为8,估计为username,下个估计是password,
查询第二个字段名长度

也是8
查第一个字段名

第一个字段名是username,然后查第二个

第二个字段名为passowrd,现在需要的信息齐了
数据库名wllmctf
表名ssrf
字段1名username
字段2名password
数据开跑
账号长度跑出来为5,跑账号

账号admin,密码长度跑出来为12,开始跑密码

密码xiaozhang123
登录吧~

WEB200-4

题目信息

地址: http://web7.08067.me/web7
分值: 200
Flag: flag{this_FUN_XXoo_ABC_UDAFBFnsasfg}

解题过程

看起来又像是一个SSRF,妈蛋!
老样子,想写上自己的服务器,发现请求的UA头是urllib2.6


然后找了一下相关漏洞,发现存在HTTP头注入,然后在admin页面随便提交一个发现提示fast fast fast….
更快?想想,什么能更快,然后灵光一闪,缓存啊,然后想想什么能做缓存,redis和memcached,猜测是redis,于是访问了下本地6379端口,果然开放
payload

如果可以访问到的话则是Header is empty,访问不到的话则是什么都不显示
于是开始构造HTTP头注入,一开始是以为要写公钥,但是又想到写进去也访问不了啊,于是思(xun)索(wen)了(ti)下(shi)
是要更新redis里的admin的值,服务端那边会以一定线程去更新,如果我更新的速度比他快,那就可以更新成功,然后就可以login进去
好一个线程竞争
写程序提交更新吧

登录这里也需要有一个高速访问的状态,我这里直接用Burp去访问了
所以就是先启动更新脚本,然后启动Burp,观察Burp的length,不同的那个即为登陆成功状态
我这里怕更新不上,把更新脚本运行的多份,每个都是多线程的,不怕更新不上去


讲道理,这么给自己服务器找DDoS真的好么- -!

REVERSE300

题目信息

地址: http://misc.08067.me/CM300/
分值: 300
Flag: flag{sA7_Tr03_I’m_Sb!|SwP0}

解题过程

因为本人水平有限,所以此题最终并没有解出来,此处摘抄了官方的解题过程
官方链接:http://bobao.360.cn/ctf/detail/173.html
CM300分为两个部分第一个为 key 和第二个部分 flag
Key输入进行md5加密。找到常量186, 23, 99, 168, 254, 185, 21, 172, 61, 195, 239, 219, 52, 229, 129, 55转为16进制。再去解md5就OK。

总觉得最后应该多点废话的总结

老实说,这次CTF算起来并不能是一份满意的答卷,因为在很多关键的思路点,各位出题人一步一步的引导,才让我能够做出来绝大部分题目,其中Web400的哥们陪我撸到5点,真心感动
也是第一次知道反序列化wakeup可以绕过,第一次知道还有hash扩展攻击,第一次知道gopher可以发POST包,第一次知道redis无差别接收数据,第一次做代码审计发现变量覆盖
Misc的哥们第一次出的NTFS流我发现有问题,反馈之后很快的处理,完事还专门通知我题目更新了~
有朋友告诉我WriteUp写这么详细没什么卵用啊,浪费时间,随便写写赚个流量就OK了嘛,
But我不这么认为,当初开博客的初衷就是写给自己看的东西,以防自己以后踩坑
写的过程我尽量照顾到水平有限的看官,用我觉得最能通俗易懂的语言,描述整个解题的过程及思路
相关的资料我这里尽量都给出链接,工具给出步骤截图
写到这里,这份WP已经4W字了,自己看到也是吓了一跳
能在CTF中认识到各种新鲜的玩法,有趣的漏洞,牛逼的思路,本身就已经赚了
最后,总是要感谢一下嘛~
感谢主办方西南石油大学,题目十分精彩
感谢各位熬夜值守出题人,我也参与过整个CTF的从出题到上线,到部署,值守,统计,到线下接待,环境部署,疑难解答,深知这份工作之艰辛
通宵几天很正常,几乎是用生命在战斗
十分感谢!!!
嗯,可以结束了
LinE Writing with the 2016-10-30 01:30

其他说明

如需转载烦请注明出处
来自于LinE's Blog
From: http://blog.l1n3.net
谢谢~~

分类: WriteUp 标签:
  1. 2016年12月12日08:04 | #1

    今天真冷,哈哈!

  2. Mochazz
    2017年11月4日17:14 | #2

    写的真的很详细,学到不少