看雪CTF在业内享有盛誉 每年两届 都是精英云集
笔者参加看雪赛事不久 有了一点体会 想与大家分享
不妥之处 万望指正
笔者认为 看雪CTF的防守作品(以下简称CM)应该追求的设计目标是:设计者知道一条捷径可以容易得到正确序列号 而其他人难以找出这条捷径
这条捷径不可以是“设计者拥有一个私钥” 但可以是“设计者隐藏的某个(破解者可以发现或者猜到的)秘密”
这个秘密可以有很多形式:某种逆向的技巧 某种减少穷举空间的技巧等等
历届比赛的防守方 不论是萌新还是dalao 都在上演各种‘秘密’
可谓百家争鸣百花齐放 一片繁荣
同时 我们也看到了几个现象
1)难存活:这些秘密虽然形式很多 但真正能有效阻挡破解者的 不多
2)见光死:虽然有的作品成功阻挡了破解者48小时 但其方法是不可重用的 如果再次使用是挡不住破解者的
3)不划算:即使有些方法可以再现 但再现成本很高 远高于破解者所要付出的代价
于是 笔者曾提出过一个问题:是否存在一种终极方法 能够低成本地产出CM且能阻挡破解者?
为了看清本质 我们从起点开始分析
CM的运行方式是:用户输入序列号 CM判断是否正确并给出提示
不论CM里面是怎么干的 宏观上可以认为是:利用输入的序列号 进行了某种运算 判断计算结果并提示
运算的输入 是破解者可以任意指定的
运算的正确理想结果 是存在CM中的(即便可以各种伪装 但高手是一定能找到的)
运算的过程 是破解者可以看到的(即便可以各种anti-debug 但高手总是能看清滴)
由于我们关注的是存活问题 所以我们只关注破解者是高手的情况
因此 我们就不讨论那些伪装和anti技巧了
具体实现时 还可以有多种变化 例如:可以把序列号拆成多个部分或者视角 分别验证
验证结果 可与 可或 可串联
所谓串联 是指用前一个运算的结果 当做下一个运算的条件
如果前一个验算不正确 则无法展开下一个计算(例如 SMC)
但这些变化只是‘量’上的区别 并无‘质’上区别 我们在此也不讨论了
于是 我们回归到问题的本质(假设CM中只有1个运算过程)
1)攻击模式:破解者已知运算过程 已知运算结果 寻找正确的运算输入
2)防守模式:防守方力图在假设正向运算公开的前提下 加大从‘结果’逆推‘输入’的难度 且需要保留一条逆推捷径
防守方要设计出‘难以逆推’的运算过程 是容易的(例如 单向函数)
要设计出‘只有设计者才能快速逆推而其他人难以逆推’的运算过程 也是容易的(例如 单向陷门函数)
难点在于:这条‘快速逆推捷径’必须是攻击者基于人类公开共享知识能够推导或猜测出来的,或者在有限时间内能穷举出来的(否则就违反了看雪CTF比赛规则和比赛精神)
那么问题来了
捷径不可以是不公开的密钥 那还能是什么呢?
这个问题看似令人困惑 但只要我们参考一下“信息对称条件下的零和博弈”模型 答案马上就清晰了 捷径只能是破题方法
也就是说 CM的安全要基于:让攻击者不知道该如何逆推正确输入
而不是 攻击者知道正确逆推方法 只是逆推时间较长而已
但是 紧接着问题又来了
攻击者是知道正向算法的 凭什么攻击者就找不出逆推算法呢?
有这么几种情况
1)这种正向算法根本就不可逆(例如 SHA-512)。这种情况显然是违规的 不予考虑
2)逆推方法是基于某种生僻的专业知识(例如 要求破解者根据一个阿尔巴尼亚语提问者的情绪给出适当的回答 CM使用一个经过深度学习训练好的网络来判断回答是否正确)原则上 这类出题思路是符合看雪比赛规则的 而且有可能在比赛中胜出 但这种方法会使得参赛者参与度很低 有悖于比赛精神 不予推荐
3)不超出广大参与者都应该具备的知识背景 要想阻止攻击者找出逆推算法 唯一能挡住攻击者的 笔者认为 就只剩下:想象力!
想象力 是不以‘秘密’的形式存在的
它只受限于破解者的思维能力 和富裕程度(开个玩笑啊)
The only limitation is imagination.
---big hero
如何考验破解者的想象力呢?
这个问题本身就很考验设计者的想象力!
让我们来看一个例子吧
老师出了一道几何证明题 全班同学都做不出来 只有小明走到黑板前 画了一条辅助线 于是全班同学都豁然开朗
这就叫 想象力!
作为破解者 小明显然比其他同学聪明
这个 我们就认了
但是 出题的老师真的要和做题的小明一样聪明吗?
其实 出题老师并不需要那么聪明
之所以老师能够出得出来这样的题 是因为老师在出题的时候 是通过这条辅助线把题目设计出来的
只不过 在发布题目的时候 老师故意抹掉了辅助线
只要做题人能够想得出来 在合适的地方添加一条辅助线 此题即可解开 否则难解
笔者认为 这才是看雪CTF的最佳出题方式!
换句话说 一个好的CM是这样设计出来的
1)选择一个领域 能够用数字化的方式进行表达
2)在已知辅助线的情况下 设计出正向运算过程 在给定的正确输入下 得到正确结果
3)抹掉辅助线 只保留正向运算和正确结果 要求破解者找正确输入
假如破解者能够找到正确的画辅助线的方式 那么此题易解 否则难解
上面提到的‘辅助线’ 只是一个形象的比喻
在真实环境中 并不一定真是一条线
那么 在真实环境中 该怎么设计这根辅助线呢?
辅助线的本质 是一种联系 它将2个或多个概念联系了起来
在CM中 辅助线可能是(但不仅限于):
1)看起来两个独立的处理流程之间的内在关系(例如 暗风吹雨中的spectre隐通道)
2)输入输出数据之间的数学关系(例如 cm2017-ccfer中的频域滤波)
3)看起来是一种语义 但实际是另一种语义的对应关系(例如 九重妖塔中的2层VM指令流)
破解的关键点 恰恰就是 找出或者猜出这种联系
一旦破解者开始怀疑 这两者存在某种特定联系 那么这就是破解之门即将开启的前奏
破解者会用各种方法来验证其猜想
通常 验证猜想的时间不会太长
我们一层一层抽丝剥茧 终于要走到问题的核心上了
要想挡住破解者关键就在于:不能让破解者轻易地知道
1)到底哪两个者是存在关联的
2)到底存在什么样的关联
(注意:一旦猜到了 验证起来是很容易的)
到这里 大家应该都明白了我想说什么吧
如果想在看雪CTF比赛中存活下来 讲人话 有2个方案:
1)坦克方案
为了让破解者找不到哪两个对象有关联 只要让对象数量多起来就好了
但是 比赛规则规定了CM的filesize 所以直接对象的数量不可能太多
于是 我们可以把注意力转向‘直接对象’组合出的‘间接对象’
只要程序里值得怀疑的‘可能有关联’的间接对象很多 而且相互之间的关系都很相似
破解者就难以从茫茫对象中找出真正有关联的对象(组合)
设计方法:CM中对象地位对等 且组合数量众多 难以找出对象满足组合关系
坦克座右铭:直白而血厚
2)法师方案
如果不想把数据量搞得很大 程序中值得怀疑的对象自然就会少 甚至只有两个对象
那就要想办法阻止破解者找出这两个对象之间的具体关联关系(例如 魔法森林拟群运算的输入输出)
在对象之间设计足够复杂的函数关系 只保留函数结果 却要求破解者去猜测函数的显式表达式
设计方法:对象数量不多 但其间的数学关系隐晦难猜 妨碍逆推求解公式
法师座右铭:女人只有一颗心 可你就是看不懂
实操中不排除混合使用坦克方案和法师方案
好,方案已经有了
那是不是只要遵循这2种方案就一定能设计出能存活的CM呢?
答案是否定的!因为还有这些方面不能忽略:
1)坦克方案中的对象数量众多 要特别当心存在设计者没想到的多解和非预期解(感谢んеХег在这个问题上的垂手指点)
要解决这个问题有2个办法:
1.1)将对象分散在多个正交基上 从数学上能证明 不同正交基上的对象之间不可能产生指定关联(例如 叹息之墙中的9个子群)
1.2)扩大输入空间 降低关联空间 使得碰撞概率极低 可能性忽略不计(Riatre对七十二疑冢是如何避免多解 已有透彻论述)
2)法师方案中的函数关系要足够复杂且不可预测 (感谢po叔指点 让笔者对‘猜’的套路有了一定的了解)
要解决这个问题需要把握好一个度!函数关系不能容易被猜到,但也不能过于偏激!
笔者在摸索这个度的过程中 从易到难 逐步加大难度 逐步加深埋藏线索的深度(魔法森林证明 目前的埋藏深度可以阻挡大多数破解者 但还不足以挡住个别高手)
除了以上2种方案以外 还存在着一种非理性因素 也能够帮助存活:皮肤压制
虽然我们都知道 皮肤并无太大实际功用 但是当你面前真的出现一个冰封战神时 很多人还是会胆怯的 其战斗力和判断力都会受到影响 甚至会放弃对抗(例如:2006年cnbragon那道RSA768题)
不过 皮肤压制只能用于吓唬一般玩家 对顶级高手基本上没用 所以需要与其它困难问题混合使用
设计方法:用一个知名难题来伪装CM 吓退破解者
皮肤座右铭:我爸是李刚(有时候 我爸真的是李刚)
如果正确使用了上述方法 那么就有机会设计出能撑过48小时的CM
而且笔者认为 可以设计出很多个
不论是坦克 还是法师 要想高效安全地设计出CM 都是有规律可循的
所以 在每次实现的时候 即使设计者都有一定的发挥空间 但要想不放弃上述基本设计原则 其实设计出来的作品 多少会让人觉得似曾相识
(例如 叹息之墙与七十二疑冢很相似 密室逃脱与魔法森林很相似。尽管它们的破解难度有很大区别)
他们就像培育水稻和玉米一样 只要掌握了正确的基因修饰技术 就能不断改善品种 产量会越来越高 抗病虫害能力越来越强
笔者相信 沿着这些系列不断推进作品 终有一天它们能够支撑48小时以上
可能有人会问 难道只有这些坦克和法师能存活吗?
当然不是!
在前面的推导过程中 曾经在很多个环节 都舍弃了许多变化和分支
但在实际操作中 这些变化和分支 都是有一定‘阻止破解’的作用的
而且 将多种防护方法进行组合 效果会强于 单单指望着一种貌似最强的防护
这样一来 就算不是坦克或者法师 也一样有机会撑过48小时
而且实际上 在这些过程中 即使是那些没有存活下来的作品 对于攻防双方来说 也都是学习和长进的机会 是好的
“攻防双方都有长进!”
这才是值得我们追求的目标!
笔者之所以不愿意用组合防护 每次出题都是‘单吊一个点’
有时还会冒着被人误解为‘故意放水’的风险 给破解者一点鼓励和提示 引导破解者直扑核心
甚至不惜在看雪CTF中屡战屡败(但从未就核心问题给出过任何提示)
其原因
1)笔者希望看清每一种防护手段到底能抵御到什么程度(而组合防护虽然可以提高胜率 但是会让研究工作变得困难 看不清各个手段的独立作用)
2)笔者能力有限 见识有限 在当时那个历史时期 也就那个水平 已经尽力了(即便使用了组合防护 不给任何提示 也苟延不了几个小时)
笔者这么选择 不是为了赢得比赛 而是为了研究比赛 促进比赛
希望笔者的研究成果能够对大家有所帮助 这些付出就都值了
感谢んеХег亲手指导,让笔者在2天的时间内以超越常人一年多的速度提升。
感谢海风月影促膝夜谈,让笔者眼界大开思路升华。
感谢po叔时常分享破解经验,让笔者少走了不少弯路。
感谢Riatre的破解与分享。破解成功 就是笔者的进步之源。
感谢netwind公正裁判,也给了笔者修改bug的机会。
感谢kanxue搭建了如此优秀的平台,聚拢一帮精英。
感谢所有帮助过、击败过看场雪的朋友们!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2018-12-16 20:17
被看场雪编辑
,原因: