本文最后更新于:星期四, 五月 28日 2020, 1:36 下午

本文其实没有什么干货,“偶尔发发牢骚,吐吐槽”。

背景

上周四,2020-05-21,“杭州四小龙”临时组队,参加了网鼎杯。四个 Web 狗,还可以勉强做一下 misc 和密码,本来也不抱什么很大的希望,毕竟不管怎么说 ctf 肯定有逆向/神仙 pwn,也可能会有安卓,加上我们平时也没怎么打过 ctf,经验不足,所以我们想着把 Web A 了就溜了,神仙打架让他们打去吧。

过程

签到

签到题本质上是个 Ajax,只需要向一个地址 post token 即可拿到 flag。神奇的事情发生了!队友用 burpsuite 试了 n 次,均无法拿到 flag,http header 也没有问题。眼看着过的队伍越来越多,我猜是不是 bs 发包有什么奇怪的地方,随口说了一句要不要试试用 curl 提交,然后就过了。。。吐了

open_box

这题最后也没能做出来。不过我想吐槽的是 pow,连位数也不说,就返回类似的:

...
x[:20] = b192d0ae24852828ad6e
<build-in md5>

总之就是告诉你,某个字符串的 hash 前面 20 位是多少,然后问你这个字符串是哪个。hash 方法以及 hash 值都是动态的,每连一次就会变一次。然后呢,我就从只能长度为 1 开始爆,爆到长度为四位,成功了,提交队伍 token,才算拿到了题目。接下来就是各种分析,代码有点长,就想着先放着后面再和队友一起看。结果就再也没机会看了。。

easy_wa

这道题是密码学,神仙题目。同样需要过 pow,与 open_box 一致,不过这个有提示是 4 位的字符串(这才算正常吧?)。过了之后,提交 token 拿到密文:

3723147309
8034322053911434180
49745872180417846725334070082004720258
52533909732625715277851750493149794582946123291447879643150522322430787956274

附件代码如下:

from secret import flag
from os import urandom as ua
import binascii
from libnum import s2n


# 原来是 lambda,改了一下,不影响
def hlen(x): return len(hex(x)[2:].strip('L'))

magic = 32805

def calc(m, p):
    res = 0
    lens = hlen(p)
    for i in bin(m)[2:]:
        res *= 2
        res ^= m if i == '1' else 0
        res ^= p if hlen(res) == lens else 0
    return res

# pow_check()
# token_check()

assert len(flag) <= 64
if len(flag) != 64:
    for i in range(64-len(flag)):
        flag += ua(1)

r = 4
for i in range(4):
    print(calc(s2n(flag[:r]), magic + (1 << r*8)))
    flag = flag[r:]
    r *= 2

这个代码很简单,主要是怎么破解 calc,其实如果耐心分析,就能发现 calc 其实就是根据 m 的二进制位来选择不同的运算,每个位有 4 种情况。反推的话,可以先把这四种情况的对应的反解函数写出来,再一个一个爆破试试。说起来很简单对吧?其实 debug 需要花很多时间。。。然后我就打算试试硬爆,能不能爆破出来,结果跑着跑着电脑提示硬盘不足了,吐血的是这个时候也没法删东西,删除的时候会提醒 no space,意思就是空间不足没法删东西,我想着重启后可能会清掉一些缓存文件,结果也不行,无解了,好在队友有 2 台 macbook,应急顶了一下。写反解函数,写着写着就 5 点了,头秃啊,挺可惜的,思路都是有的。然后当天晚上我洗澡的时候,突然想到,爆破能不能用遗传算法这类随机化搜索方法呢?calc 函数,在输入字符串越大的时候,结果并不是越大的,所以没法用贪心来解,但是可能可以用动归,但是我写动归不熟练,动归实在不行还可以换随机化搜索啊?越想感觉越有戏,遗传算法代码之前也写过。于是第二天我就以二进制相同(相同位置,相同数值)的位数作为 feature,试着跑了一下密文,上午就轻松跑出了前三个密文:

flag: 3723147309
{6372edc: 8034322053911434180
74529ccec2ed74d7: 49745872180417846725334070082004720258

需要注意的是,生成种族的时候,在 0-9a-zA-Z{} 之间随机选对应长度的字符串,再转为 num。原本的方法是随机 01 直接生成数字,这样其实会慢很多。

然后最后一个密文是比较坑的,看代码我习惯性以为最后一个密文对应的明文长度是 34,实际上是 32。但是跑了很久依旧跑不出来,不过也算正常,空间越大的目标跑的时间越久,也越容易陷入局部最优解。接下来我打算从 flag 的格式入手优化一下,看了一下已有的明文:没有大写字符、没有特殊字符(-之类的),不像 uuid,更像 hash 对吧?那就是说长度可能是 32 位的,也就是说最后一个明文的格式为:(0-9a-z){9} + } + 全字符随机{22},一共 32 个字符。话不多说,开跑:

712af599a}|\xb6\x0f\x8f\xf4v\xbaC\xad\xb7\xb0^\xdf\xe13\x87\xf5\xe4\x8c\xb7\x0cf: 52533909732625715277851750493149794582946123291447879643150522322430787956274

不到 10 分钟!各位观众,全体起立!

最后 flag 为:

flag{6372edc74529ccec2ed74d7712af599a}

妥妥的非预期解法(截至目前网上还没有 writeup,说不定还是预期解呢哈哈)。不过就算用遗传算法,写完调试+跑+优化+踩坑,也需要几个小时。虽迟但到哎。

突然想起了大三的时候,面试数模参赛资格,过程中聊到了过遗传算法,老师说他自己很讨厌随机化搜索,诸如遗传算法啊,蚁群算法啊,因为优化玄学,而且往往也不能得出精确的结果。但是我感觉 ctf 很多题说不定都可以这样去爆破,虽然是非预期解法,也算解出来了嘛。

js_on

我是没有时间看 Web 了,有 2 位队友在负责。js_on 好奇看了一下,队友说应该是注入,但是没法闭合。最后看网上的 writeup,说是 select<> 绕过,空格用注释绕过。但是我们的确是试过 admin'#,也试过 admin'/**/--/**/#,依旧是 500。也不知道到底是卡哪了。

ssrfme

网上说考点主要是 redis 主从复制,主从复制也算常规的攻击方式,问题是队友做的时候说 gopher 协议提交不了,会提示 url invalid。本地尝试是可以的,同样也不知道踩了那个地方的坑。

一些想法

py

网鼎杯第一场就被各种喷
有喷公开卖 flag 啊:

有消费某主播的啊:

主办方的确做得不算完美,不知道有没有流量分析之类的手段,可以揪出部分交换思路的 py,不过成本比较高,估计没有?不过我认为这个并不能过于苛责主办方,搅屎棍本来就一直都有,而且很难杜绝

卡点

网鼎杯卡点设置有点迷,做题的时候出现各种玄学问题。并且 Web 容器只能下发一个。你以为是一个题目只能下发一个容器,实际上是所有的 Web 题目都只能一次下发一个 —— 也就是说一个队同时只能做一道 Web 题。还有信息不足的 pow,都是泪啊。

难度

平心而论,网鼎杯玄武组是真的难。个人认为 ctf 难度可分为 2 种,一种是思路难,一种是麻烦。思路难、新颖的题目质量要远高于解题步骤繁琐的题目,一味地增加繁琐的解题步骤却没有一个比较好的引导,体验自然极差(我又想说那个 pow),况且做题时间就一天。我甚至在想是不是大家都经常打,所以知道套路?比如 hash pow 约定俗成就是 4 位?话又说回来,open_box 与 easy_wa 当天能做出来的是真的强,打不过就是打不过,题目不能成为菜的借口

看待 CTF

我大概是 16 年开始接触 CTF 的,当时我是转专业了,所以新的班级认识的人不多,熟悉的人里有的是打 ACM 有的是打数模,没有队友一起打 CTF,当时还是有点内向的,不太喜欢进社团接触很多陌生人,后来渐渐也就不打了。那个时候大家都喜欢打,纯粹是喜欢那种寻宝的感觉,还能学到很多利用♂姿势♀,没有 py 也没有什么利益关系。后来也不知道怎么了,有 py,利益关系复杂了,也有搅屎棍了,于是有很多前辈在呼吁净化 CTF,大家也都比较抵触那种 py 行为。但是再后来我感觉有点矫枉过正了,甚至找队友都被视为有点功利的行为。我在临近毕业找队友的时候,有人和我说打 CTF 自己一个人去打就好了,目的是为了学习,又不是为了拿那些奖金。我倒是认为既然要参加比赛了就要找队友好好打,这既是尊重主办方,也是尊重出题人,更是尊重自己的努力。稍微功利一点嘛也没什么不好,只要是通过自己的真实实力赢得比赛,就值得自豪。并且说自己喜欢打 CTF 也没必要有什么心理负担,不是说能够参加国际比赛的才有资格自称 ctfer,自己喜欢就好了么,世界上那么多事情,也没说做不到顶级大家就都不去做了吧。最后,给自己或者别人贴标签,或者说试图利用拉低别人来显得自己没那么菜,真的没什么实质性的好处。

那天晚上心态其实挺崩的,其实只要做出 3 题就能进下一场了(没错,只需要 3 题)。有时候差一点,就是没得有机会咯。

现在队友有现成的,时机成熟或许我们四小龙能够正式组成一个队,再去参(zhao)加(nue)其他的比赛,想想还是挺开心的。

这里有个自闭的二维码,
用你的大手机扫一扫,给它加加油!