小花吐槽:
这是特意为成都沙龙设立的现场CTF。
拿到题目之后我问麦香,难么?
他邪魅一笑,不难啊,就是脑洞有点大
天真的我以为真的不难,为此设立了闯关成功的10名大奖,希望大家开开心心满载而归。
没想到,整整五小时,没人能够拿到唯一的FLAG。
千元大奖又被我邮寄回了北京。。。
厉害了我的麦香同学。
恭喜你在跨次元CTF夺得第一。
下次出题我们脑洞可以再小点哦:)
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
题目地址如下
http://btctf.secbox.cn/
这套简单的CTF主要由三部分组成。Web、Misc、Apk,每个部分都有一个小坑~
0x01Web
思路很简单,就是一个PHP弱类型 php在不加strict的情况下,不会对类型进行严格比较,比较坑的点就是加了Salt,需要写脚本去爆破下。
脚本如下
import hashlib
import string
import itertools
import sys
defmd5(string):
m1 = hashlib.md5()
m1.update(string)
return m1.hexdigest()
prefix= "0e"
fori in itertools.product(string.ascii_letters,repeat = int(sys.argv[1])):
pw = "".join(i)
password1 = md5(pw) + "SALT"
password = md5(password1)
if password[:2] == prefix:
if password[2:].isdigit():
print pw
print password1
print password
或者
import string
import hashlib
import itertools
def md5(strs):
m1 = hashlib.md5()
m1.update(strs)
return m1.hexdigest()
def ver(passwd):
pwd = md5(passwd) + "SALT"
pwd_1 = md5(pwd)
if pwd_1[:2] == '0e':
if pwd_1[2:].isdigit():
return True
def go(num):
for i initertools.product(string.ascii_letters, repeat=int(num)):
if ver(''.join(i)):
print ''.join(i)
exit()
go(9)
最后过关,拿到下一关的地址。
0x02 Misc
Misc首先查看源代码,可以看到两个提示,tieba&机器人。
仔细推测可能是贴吧&robots
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
我们使用贴吧的高级搜索
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
http://tieba.baidu.com/p/4827665506?pid=99279354524&cid=0#99279354524
找到了一个有关系的帖子,帖子上提示了一个二维码,扫描发现是一串无意义的字符串,但是同时帖子里还给出了一张鸟叔的照片,这时候就可以尝试搜索psy(鸟叔的英文名)+QRCODE(二维码英文)。搜索到了一个二维码隐写软件,Psytec QR Code,尝试解密二维码发现需要密码。于是继续从之前的提示下手。
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
在robots.txt中发现passwd文件夹,访问后发现了一串64位的字符串:7c43bc96790717a772d50754f9f1f7e6a8db1d82db78ed452ba0882fb9554fc9
明显是两个Md5,解出来拼凑成butianctf.
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
顺利拿到第三关的apk地址。
0x03 Apk
下面主要说下Apk的解题思路。
运行apk,点击屏幕中央的按钮,提示“Youneed to press tha button harder”。使用jeb打开apk,找到MainActivity类的onCreate函数中,按钮设立的监听器类为b,并且传入了textview对象和MainActivity类本身。
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
跟踪b类的onClick函数,如下,如果步骤中的任何一部出现异常,就会输出“You need to press tha button harder”
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
我们一步一步看,首先调用了“private byte[] a(String arg4)”函数,如下图,可以看出这个函数主要是用于读取assets目录下的文件,并返回文件内容。
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
随后调用了函数“private byte[] a(byte[] arg7)”,如下图,这个函数看起来就比较复杂了,它其中调用了d类的“byte[] a(byte[] arg15, int arg16, int[]arg17, int arg18)“函数,我们先看一下d类的这个函数
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
d类中的“byte[] a(byte[] arg15, int arg16, int[] arg17, int arg18)”函数如下图,看起来像某个加密算法,对其中的魔数0x9E3779B9进行搜索,搜索结果均指向tea加密,如下图
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
通过比对加密算法,这部分算法是tea算法的解密算法。因此上面的整体流程就清晰了:首先读取assets目录下的nothere文件的内容,然后读取assets目录下flag文件的内容,随后对flag文件的内容进行tea算法解密,密钥在类初始化的时候写明,如下图,之后将nothere文件内容与flag文件解密后内容进行对比,如果相同则会进入下一步流程,不相同或文件不存在则显示“You need to press tha button harder”。
密钥:![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
我们看一下下一步的流程,其将nothere的内容和apk中classes.dex的crc校验值传入类a的a函数,并且输出,推测该做法是为了防止修改dex文件,该函数并没有做多余的检查,推测该函数运行完成后会得到flag。
下面有两条道路,首先解密出nothere文件的内容,然后将nothere拷贝到apk的assets目录下,重打包运行即可;另一个思路是解密出nothere文件的内容,取出classes.dex文件的crc校验,复制出类a的a函数编译运行即可。
考虑到本题目名字为rererepack,因此采取第一种重打包的方法。
tea解密代码如下,参考http://www.blogjava.net/orangehf/archive/2007/10/12/152328.html
Tea.java
/** * Tea算法 * 每次操作可以处理8个字节数据 * KEY为16字节,应为包含4个int型数的int[],一个int为4个字节 * 加密解密轮数应为8的倍数,推荐加密轮数为64轮 */ class Tea { //加密 byte[] encrypt(byte[] content, int offset, int[] key, int times) {//times为加密轮数 int[] tempInt = byteToInt(content, offset); int y = tempInt[0], z = tempInt[1], sum = 0, i; int delta = 0x9e3779b9; //这是算法标准给的值 int a = key[0], b = key[1], c = key[2], d = key[3]; for (i = 0; i < times; i++) { sum += delta; y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); } tempInt[0] = y; tempInt[1] = z; return intToByte(tempInt, 0); } //解密 byte[] decrypt(byte[] encryptContent, int offset, int[] key, int times) { int[] tempInt = byteToInt(encryptContent, offset); int y = tempInt[0], z = tempInt[1], sum = 0, i; int delta = 0x9e3779b9; //这是算法标准给的值 int a = key[0], b = key[1], c = key[2], d = key[3]; if (times == 32) sum = 0xC6EF3720; /* delta << 5*/ else if (times == 16) sum = 0xE3779B90; /* delta << 4*/ else sum = delta * times; for (i = 0; i < times; i++) { z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); sum -= delta; } tempInt[0] = y; tempInt[1] = z; return intToByte(tempInt, 0); } //byte[]型数据转成int[]型数据 private int[] byteToInt(byte[] content, int offset) { int[] result = new int[content.length >> 2];//除以2的n次方 == 右移n位 即 content.length / 4 == content.length >> 2 for (int i = 0, j = offset; j < content.length; i++, j += 4) { result[i] = transform(content[j + 3]) | transform(content[j + 2]) << 8 | transform(content[j + 1]) << 16 | (int) content[j] << 24; } return result; } //int[]型数据转成byte[]型数据 private byte[] intToByte(int[] content, int offset) { byte[] result = new byte[content.length << 2];//乘以2的n次方 == 左移n位 即 content.length * 4 == content.length << 2 for (int i = 0, j = offset; j < result.length; i++, j += 4) { result[j + 3] = (byte) (content[i] & 0xff); result[j + 2] = (byte) ((content[i] >> 8) & 0xff); result[j + 1] = (byte) ((content[i] >> 16) & 0xff); result[j] = (byte) ((content[i] >> 24) & 0xff); } return result; } //若某字节为负数则需将其转成无符号正数 private static int transform(byte temp) { int tempInt = (int) temp; if (tempInt < 0) { tempInt += 256; } return tempInt; } }
|
TeaMain.java
import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class TeaMain { private Tea tea; private int[] KEY = new int[]{//加密解密所用的KEY 0xdfabcbfa, 0xfdbaecba, 0xedbafced, 0xbfaecfda }; public TeaMain() { this.tea = new Tea(); } //通过TEA算法加密信息 public byte[] encryptByTea(byte[] temp) { int n = 8 - temp.length % 8;//若temp的位数不足8的倍数,需要填充的位数 byte[] encryptStr = new byte[temp.length + n]; encryptStr[0] = (byte) n; System.arraycopy(temp, 0, encryptStr, n, temp.length); byte[] result = new byte[encryptStr.length]; for (int offset = 0; offset < result.length; offset += 8) { byte[] tempEncrpt = tea.encrypt(encryptStr, offset, KEY, 32); System.arraycopy(tempEncrpt, 0, result, offset, 8); } return result; } //通过TEA算法解密信息 public byte[] decryptByTea(byte[] secretInfo) { byte[] decryptStr = null; byte[] tempDecrypt = new byte[secretInfo.length]; for (int offset = 0; offset < secretInfo.length; offset += 8) { decryptStr = tea.decrypt(secretInfo, offset, KEY, 32); System.arraycopy(decryptStr, 0, tempDecrypt, offset, 8); } int n = tempDecrypt[0]; byte[] result = new byte[decryptStr.length - n]; System.arraycopy(tempDecrypt, n, result, 0, decryptStr.length - n); // return new String(tempDecrypt, n, decryptStr.length - n); return result; } public byte[] readFile(String path) throws IOException { File file = new File(path); FileInputStream in = new FileInputStream(file); FileChannel channel = in.getChannel(); ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size()); while ((channel.read(byteBuffer)) > 0) { } channel.close(); in.close(); return byteBuffer.array(); } public void writeFile(String path, byte[] data) throws IOException { File file = new File(path); FileOutputStream out = new FileOutputStream(file); out.write(data); out.close(); } public static void main(String[] args) throws IOException { System.out.println("Hello World!"); TeaMain main = new TeaMain(); byte[] encryptInfo = main.readFile("/Users/alset/Desktop/flag"); byte[] decryptInfo = main.decryptByTea(encryptInfo); System.out.print("解密后的数据:"); System.out.println(decryptInfo); for (byte i : decryptInfo) System.out.print(i + " "); System.out.println(); main.writeFile("/Users/a/Desktop/nothere", decryptInfo); } }
|
用unzip将apk解压,拷贝assets目录下的flag文件至桌面,运行上面的TeaMain,即可得到解密后的nothere文件。
将生成的nothere文件拷贝到assets目录下,在apk解压目录下使用“zip -r app.apk .”命令重打包,再使用signapk.jar签名,即可安装到手机上,点击按钮将显示flag。
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
提示:使用jeb1的快捷键b可以快速修改整数的显示方式。
![5h没人做出来的脑洞大开折磨人CTF,思路原来是这样... 5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...]()
原文始发于微信公众号(补天漏洞响应平台):5h没人做出来的脑洞大开折磨人CTF,思路原来是这样...
评论