当前位置:网站首页 > 黑客培训 > 正文

第二届强网杯中应用的一种反作弊新思路

freebuffreebuf 2018-03-28 262 0

本文来源:i_春秋

作者:FlappyPig

前言

这次比赛的题目总体上我们自己的收获还是很多的,但也出现了很多的非预期,这里代表战队向大家抱歉。

我们一些很多有趣的思路因为非预期没有体现出来。比如流密码级数给的是我测试时用的级数,少了一倍,导致有3个流密码考点都没有考到;星星的qemu monitor的console没关,正解:https://bbs.pediy.com/thread-225488.htm ;lowkey的pwn中出现的各类2b解法;同样我的题目中,windows pwn中的flag忘了padding,不用heartbleed都可以算出flag;bendawang在汪神的oj部署时直接装了docker,忘了关和改很多东西,正解看orange师傅的wp:http://blog.orange.tw/2018/03/pwn-ctf-platform-with-java-jrmp-gadget.html

中途还发生了两起dos,一起还是1个t的ddos。不得不说阿里云的清洗功能还是厉害的,是不是得给我广告费=……=。

言归正传,在本次比赛中,秉承公平公正的原则,我们开发了一些新的技术用于反作弊,改善目前较为恶劣的CTF环境,一定程度上保证了竞赛的公平性。运用这种方法,我们实锤了若干队伍,也希望被实锤的队伍不要有怨言,认真打比赛,提升自己的水平才是正解。

这个方法叫做基于信息不对等的竞赛作弊检测技术(是不是可以发论文了=)。这个方法的适用条件需要满足:

交互类题目

通常来说,在PWN类型、PPC类型、Crypto类型应用面较广。在不同类型的题目上应用需要有很多调整,这里我们以nextrsa为例进行介绍。

Nextrsa

Nextrsa这个题目原本思路源自某次比赛的Twin Primes,只有nextprime一个关卡,解题思路也很简单,首先进行假设:

nextprime(p)*nexprime(q)=(p+x)*(q+y)

然后和n=p*q列方程组,最后爆破x和y解一元二次方程,即可分解n:

import gmpy2 n = 0x78e2e04bdc50ea0b297fe9228f825543f2ee0ed4c0ad94b6198b672c3b005408fd8330c36f55d36fb129d308c23e5cb8f4d61aa7b058c23607cef83d63c4ed0f066fc0b3c0062a2ac68c75ca8035b3bd7a320bdf29cfcf6cc30377743d2a8cc29f7c588b8043412366ab69ec824309cb1ef3851d4fb14a1f0a58e4a1193f5518fa1d0c159621e1f832b474182593db2352ef05101bf367865ad26efe14fce977e9e48d3310a18b67991958d1a01bd0f3276a669866f4deaef2a68bfaefd35fe2ba5023a22c32ae8b2979c26923ee3f855363f18d8d58bb1bc3b7f585c9d9f6618c727f0f7b9e6f32af2864a77402803011874ed2c65545ced72b183f5c55d4d1L m = 0x78e2e04bdc50ea0b297fe9228f825543f2ee0ed4c0ad94b6198b672c3b005408fd8330c36f55d36fb129d308c23e5cb8f4d61aa7b058c23607cef83d63c4ed0f066fc0b3c0062a2ac68c75ca8035b3bd7a320bdf29cfcf6cc30377743d2a8cc29f7c588b8043412366ab69ec824309cb1ef3851d4fb14a1f0a58e4a1193f5a58ee70a59ac06b64dbe04b876ff69436b78cf03371f2062707897bf4e580870e42b5e62709b69f6d4939ac5641ea0f29de44aaee8f2fcd0f66aaa720b584f7c801e52ce7cd41db45ceb99ebd7b51bef8d0cd2deb5c50b59f168276c9c98d46a1c37bd3d6ef81f2c6e89028680a172e00d92dd8b392135112dd16efab57d00b26b9L def quadratic(a,b,c):     ga=gmpy2.mpz(a)     gb=gmpy2.mpz(b)     gc=gmpy2.mpz(c)     delta=gb**2-4*ga*gc     if delta=0 or a==0:         return 0     tmp=gmpy2.iroot(delta,2)     if tmp[1]==True:         x1 = (-gb + tmp[0]) / (2*ga)         x2 = (-gb - tmp[0]) / (2 * ga)         if x1>0 and n%x1==0:             print x1             return x1         if x2>0 and n%x2==0:             print x2             return x2     return 0 def main():     for x in range(1500):         print x         for y in range(1500):             a=y             b=x*y-m+n             c=x*n             if quadratic(a,b,c)!=0:                 return 0 main()

这个题出完之后,感觉就是水了个题,好弱;于是我把这个做成了交互式的,又好弱;考虑到强网杯普及面很广,萌新很多,于是我准备把RSA所有考点搬过来让大家学习学习。于是就有了:

problem_brute_256bit(conn) problem_wiener_attack(conn) problem_LLL_attack(conn) problem_np_nq(conn) cheat=problem_yafu_cheat_check(conn, address,teamtoken) problem_e_3_brute(conn) problem_gcd_attack(conn) problem_same_n(conn) problem_broadcast(conn)

9个关卡。本来我构想是大概到15个左右,但是实在是有点忙,9个也够喂饱萌新了,于是题目最终出成了这样。所有给予的信息,都是完整的信息,通过这些判断条件是可以知道用什么方法去解的,如果不知道,可以参考我以前的一篇文章:https://www.anquanke.com/post/id/84632

题目的源码也已经公开,详情参见:https://github.com/fpbibi/nextrsa

基于信息不对等的竞赛作弊检测技术-Crypto版本

这个方法最关键的地方在于信息不对等,也就是选手知道的信息和出题者知道的信息是不对等的。这就造成了一个后果:

题目对选手黑盒 或 运行的题目和选手拿到的题目不一样

前者常用于PPC和Crypto类型的题目,后者常用于PWN类型题目。

我们在题目中设置一些类似于“陷门”的东西,可以100%地实锤某些作弊,主要可以实锤一种行为:

两个队伍交换了解题脚本,并修改teamtoken直接运行

以nextrsa举例,我做了如下设置(因为从平台方拿到teamtoken的时间有点晚,所以我是以IP区分来源的):

首先我选择了9关中的1个关卡,我选择的是第5关使用yafu分解n的关卡,选择这一关的原因有两点:

1 上一关是整个游戏最难的一关,所以到这一关的人很少,可以减少日志数量 2 这一关的yafu是需要把字符串复制出来跑的,难以动态获取立即跑完

选手在遇到这个关卡的时候,会获得以下信息:

1 这个用yafu可以跑出来 2 这个字符串每次跑都是一样的,是固定的

通过上述两个信息,选手会把n直接复制出来扔到yafu里,并分解成功后,将pq,或者将算好的私钥,也就是d放到脚本中过此关卡。
但是,在服务器上的代码并不是固定的n,n是使用这种方式生成的:

q=0xab724df05ca87067ce1573550a6a05f41f93e910b0380c71cdc5de940ef790a475f5c3d512354bc57b3410e7f5158fb287f79397353acb169ef583260eec76f4c46d21e4cb43426e3c66ba9b75d3c1b009ff1f9a0fea9c7d9815eadc5f7ac776d6dcae3c1fa3de865253623b4121e6b4f51deea0b7ae9ca84aad5fe83ba56451L seed=int(hashlib.sha256(ip).hexdigest()[0:8],16) p=primefac.nextprime(seed) n=p*q

这里可惜的是,使用的是ip,所以又有了很多复杂的工作;这里最好是以teamtoken作为种子生成p。这种方式生成的p和d,每个ip或者每个token不一样。当一个队伍成功解题的时候,服务器端会记录其ip/token对应的d和n。

if rec_m == hex(m).replace("L",""):     d=primefac.modinv(e,(p-1)*(q-1))     if d0:         d+=(p-1)*(q-1)     successdn.append((d,n))     f=open("success/"+ip,"a")     f.write("teamtoken:"+teamtoken+"\n"+"time:"+time.strftime('%Y%m%d%H%M%S')+"\nm:"+hex(m).replace("L","")+"\nd:"+hex(d).replace("L","")+"\nn:"+hex(n).replace("L","")+"\n\n")     f.close()     ok(conn)     return 0

正常解题会发生如下情况,那么不正常解题呢?也就是说,如果这个脚本到了其他人的手里,ip和token都会发生改变,那么服务器给他的n肯定就变了,但是他脚本里的d没变。如下:

某个队伍使用自己的ip/token和服务器交互的时候,提交了和自己的ip/token不对应的d,并且这个d是其他队伍使用的。那么可以认为这个队伍有作弊嫌疑。

最骚的操作是,当服务发现该队伍作弊,使用了其他队伍的私钥后,还继续正常进行,让该队伍获得flag。######不要打我
因为我使用的是ip,不是token,所以还需要进一步分析,就是会存在这样两种情况:

1 同一个队伍的大佬做完题目后,把脚本给了另外一个ip的小弟跑 2 两个ip的p相撞

因此我又编制了一个脚本,用来筛选:

只有在两个不同的teamtoken中出现了相同私钥 and 作弊队伍的teamtoken没有成功的交互记录

for i in cheatlist:     (cheat_token,cheat_time,cheat_d,cheat_n)=i     find_father=0     for j in successlist:         (token,time,d,n)=j         if token==cheat_token and cheat_d==d and cheat_n==n and cheat_time>time:             find_father=1             break     if find_father==0:         print cheat_token         for j in successlist:             (token, time, d, n) = j             if cheat_d==d and cheat_n==n and cheat_time>time:                 print "from",token

只要满足上述所有条件,那么该队伍在概率学上是100%实锤作弊,而且还能一下锤两个。==!

图片.png

项目目录中,ppc_rsa.py是题目服务,自带socket;hide.py是flag文件,flag文件夹内记录成果获取flag的ip和token,success文件夹内记录成功以正确的私钥过那一关的ip和token,cheat文件夹内表示作弊嫌疑人,运行check_cheat.py可以进行数据分析,并给出100%实锤的作弊token。

图片.png

最后

Pwn类型的题目有着类似的思路,有兴趣的可以自己思考一下。也希望CTF的氛围越来越好,大佬越来越多。




转载请注明来自网盾网络安全培训,本文标题:《第二届强网杯中应用的一种反作弊新思路》

标签:安全比赛

关于我

欢迎关注微信公众号

关于我们

网络安全培训,黑客培训,渗透培训,ctf,攻防

标签列表