ahe17 (android hacker event 2017) writeup
一开始是flanker在微博上转发的,说是面向android hacker的ctf,那我肯定得参加一下,结果下来ak了,题目都不是很难,这国际版的ctf也是比较水,不知道主办方是什么心态。。。
转载请联系本人,否则作侵权处理。 相关文件链接:https://github.com/LeadroyaL/attachment_repo/tree/master/ahe17
比赛前放出三道题,说是做出来的local hacker可以领取T恤,都是送分题,没写writeup,就记住三个flag。
1 | ahe17 cat easy/flag |
1、AES-Decrypt
It's right in front of you, just decrypt it!
没有任何输入,点击后在JNI里对某个数据进行解密,返回的string为“Key=Af03BC291F82”,用来迷惑的,哪有这种key啊,屏幕上又说“AES-256-CBC”,请我们解密另一段data。 JNI里符号表都在,使用手写的方式调用libssl和libcrypto。 直接找到Java_MainActivity_decryptAES,上面进行了一大堆操作,后面对操作结果进行了memcpy以及使用Log进行打印。
1 | int __fastcall Java_challenge_teamsik_aesdecryption_MainActivity_decryptAES(JNIEnv *env, int a2, int a3) |
在sub_39e4和sub_3a58中,分别进行了b64解码和AES解密,通过API的名称可以猜到。 再猜一下长度,根据API名字是aes_256_cbc,找到unk_FD56位置的IV,从Log里找到key,解密后把string返回到JNI里,所以2个参数找全,开始解密。
1 | iv = [0x99,0x3F,0x76,6,0xA7,0x88,0x1C,0x67,0x49,0x27,0x66,6,0x8D,0xE9,0xD8,0xAA] |
2、Token-Generator(doNetChallenge) 这题还是比较难搞的,用的是doNet,使用mono技术,Java层是一个外壳,没太大的用处。上两款软件,ILSpy和dnSpy一起搞一下,打开时候巨卡无比。相比JEB这两款软件简直low爆了。。。 一般核心的dll放在assets里,找名字最特殊的那个。 硬着头皮从onCreate开始看,每次onCreate时候创建一个AES-256,但马上又clear掉,删掉所有的临时文件,随机挑选一个X开头的方法去调用,每个X开头的方法在结束后再去随机调用另一个X开头的方法,这样一共递归调用10次。 X开头的方法有很多个,主要功能有几类:
- 解密、创建文件,文件名为foo+uuid(唯一而且随机)和bar+uuid(唯一且随机)
- check,拿到目录下所有foo文件,并且依次进行SHA1,将结果作为AES的key,拿到目录下所有的bar文件,并且依次进行SHA1,将结果作为AES的IV,对给定的String进行解密
- (不太记得了)
总之,就是瞎jb调用、瞎jb解密,总有一次会解密一大堆文件,总有一次可能解密出了flag。思路大概就是遍历所有的可能,碰运气可能将结果解密出来。 我们拖出所有的foo+uuid和bar+uuid文件,对其进行sha1的操作,共有6个sha1。
1 | sha-foo |
观察API,搜索C#的一系列知识,发现不是AES,而是Rijdael的算法,使用Visual Studio的C#去调用一下API,最多9次就好了,给定20byte的key,给定20byte的IV,给定密文
1 | enc = [17, 185, 186,161,188,43,253,224,76,24,133,9,201,173,255,152,113,171,225,163,121,177,211,18,50,50,219,190,168,138,97,197] |
这里我就不写C#的代码了,反正是抄来的,不会写的话抄这个题的源码,最后某次解密成功,得到flag为
1 | AHE17-d0tn€t-c0de |
然而那个符号中国键盘打印不出来,复制粘贴应该可以。 这题真是神坑,不认识C#,带有大量随机性。。。还好没出啥大事
3、Flag_Validator
4个小check,分别在校验4部分;1个大check,校验整个字符串的hash值。
第一个check: 输入的字符串逆序后base64编码为"cHVtcjRX"
1 | from base64 import b64decode |
第二个check: 将给定的int[]
进行一系列运算,再将int转化为char再转化为string,与输入做比较,写一段Java模拟一遍即可。
1 | ch4ll3ng3 |
第三个check: 使用反射去调用第二个check时候的那个方法,给定的int[]
不一样,结果也不一样,同样用Java模拟一遍。
1 | 5UcC33D3d |
第四个check: 将输入string的md5值与某个值进行比较,再cmd5上花钱买掉即可。
1 | continue1 |
最后的check是连带-,组成W4rmup-ch4ll3ng3-5UcC33D3d-continue1,进行SHA1,与预期做对比。 结果是
1 | W4rmup-ch4ll3ng3-5UcC33D3d-continue1 |
4、You Can Hide - But You Cannot Run
一个比较骚的题,几十个线程同时启动,对某文件进行写入操作,每个线程只写1byte,而且写完就退出。如果我们观察这个文件的话,每一秒这个文件的里存放的char是不一样的。
这时我们猜测,将输出的字符按照时间顺序连起来,应该就是flag。
观察一下这一堆线程,只有int sleepTillTime
和char c
是不一样的,所有思路就是对smali文件进行正则,拿到time和char的对应关系。 这里使用这段python来提取
1 | patter = re.compile( |
之后进行简单的排序即可,输出是
1 | Aol jsvjrdvyr ohz ybzalk Puav h zapmm tvklyu hya zahabl, Whpualk if uhabyl, svhaolk if aol Thzzlz, huk svclk if aol mld. Aol nlhyz zjylht pu h mhpslk ylcpchs: HOL17{IlaalyJyfwaZ4m3vyKpl} |
显然是单表替换之类的,扔到quipquip里解一下,得到flag
1 | The clockwork has rusted Into a stiff modern art statue, Painted by nature, loathed by the Masses, and loved by the few. The ?ears scream in a failed revival: AHE17{BetterCryptS4f3orDie} |
AHE17{BetterCryptS4f3orDie}
5、Why Should I Pay? 简单的注册机,有一个在线购买,但是URL坏掉了,购买成功后会在 SharedPreferences里写一些数据。 在Java里采集了MAC地址。 在MainActivity里有一处JNI,传入了MAC地址和Key,于是打开so文件。 mdzz,在so里直接看到flag。。。
AHE17{pr3mium4ctiv4ted}
剩下两道没做的,一个是web题,服务器贼卡,写脚本跑完了也不知道要干嘛;还有个brainfuck,没有target,不知道在干嘛。
总体来说,ahe17的出题真是水。。。我还以为会有我做不出来的,失望了