前些日子打了CyBRICS CTF国际赛,被虐哭。写篇笔记,记录下一些题目,这道Matreshka考察了java,go,python的基本逆向知识,涉及简单的加密算法,难度不是很大,首先是题目给了一个Code2.class文件和一个data.bin文件,可以直接将class反编译成java源码,看下代码逻辑:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
class Code2
{
Code2() {}
public static byte[] decode(byte[] paramArrayOfByte, String paramString) throws Exception
{
SecretKeyFactory localSecretKeyFactory = SecretKeyFactory.getInstance("DES");
byte[] arrayOfByte1 = paramString.getBytes();
javax.crypto.spec.DESKeySpec localDESKeySpec = new javax.crypto.spec.DESKeySpec(arrayOfByte1);
javax.crypto.SecretKey localSecretKey = localSecretKeyFactory.generateSecret(localDESKeySpec);
Cipher localCipher = Cipher.getInstance("DES");
localCipher.init(2, localSecretKey);
byte[] arrayOfByte2 = localCipher.doFinal(paramArrayOfByte);
return arrayOfByte2;
}
public static byte[] encode(byte[] paramArrayOfByte, String paramString) throws Exception { SecretKeyFactory localSecretKeyFactory = SecretKeyFactory.getInstance("DES");
byte[] arrayOfByte1 = paramString.getBytes();
javax.crypto.spec.DESKeySpec localDESKeySpec = new javax.crypto.spec.DESKeySpec(arrayOfByte1);
javax.crypto.SecretKey localSecretKey = localSecretKeyFactory.generateSecret(localDESKeySpec);
Cipher localCipher = Cipher.getInstance("DES");
localCipher.init(1, localSecretKey);
byte[] arrayOfByte2 = localCipher.doFinal(paramArrayOfByte);
return arrayOfByte2;
}
public static void main(String[] paramArrayOfString) throws Exception {
String str = "matreha!";
byte[] arrayOfByte1 = encode(System.getProperty("user.name").getBytes(), str);
byte[] arrayOfByte2 = { 76, -99, 37, 75, -68, 10, -52, 10, -5, 9, 92, 1, 99, -94, 105, -18 };
for (int i = 0; i < arrayOfByte2.length; i++) {
if (arrayOfByte2[i] != arrayOfByte1[i]) {
System.out.println("No");
return;
}
}
java.io.File localFile = new java.io.File("data.bin");
FileInputStream localFileInputStream = new FileInputStream(localFile);
byte[] arrayOfByte3 = new byte[(int)localFile.length()];
localFileInputStream.read(arrayOfByte3);
localFileInputStream.close();
byte[] arrayOfByte4 = decode(arrayOfByte3, System.getProperty("user.name"));
FileOutputStream localFileOutputStream = new FileOutputStream("stage2.bin");
localFileOutputStream.write(arrayOfByte4, 0, arrayOfByte4.length);
localFileOutputStream.flush();
localFileOutputStream.close();
}
}
可以看出这段用了DES算法对字符串进行encode,密钥key为matreha!,如果和结果和byte[] arrayOfByte2 = { 76, -99, 37, 75, -68, 10, -52, 10, -5, 9, 92, 1, 99, -94, 105, -18 };相同则继续将bin文件使用这段字符串进行decode操作,保存成stage2.bin文件,所以我们需要知道这段字符串的真正内容,只需要使用密钥matreha!直接decode这段byte[] arrayOfByte2 = { 76, -99, 37, 75, -68, 10, -52, 10, -5, 9, 92, 1, 99, -94, 105, -18 };即可。
完整代码如下所示:
package test;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.Base64.Encoder;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
public class Code2
{
Code2() {}
public static byte[] decode(byte[] paramArrayOfByte, String paramString) throws Exception
{
SecretKeyFactory localSecretKeyFactory = SecretKeyFactory.getInstance("DES");
byte[] arrayOfByte1 = paramString.getBytes();
javax.crypto.spec.DESKeySpec localDESKeySpec = new javax.crypto.spec.DESKeySpec(arrayOfByte1);
javax.crypto.SecretKey localSecretKey = localSecretKeyFactory.generateSecret(localDESKeySpec);
Cipher localCipher = Cipher.getInstance("DES");
localCipher.init(2, localSecretKey);
byte[] arrayOfByte2 = localCipher.doFinal(paramArrayOfByte);
return arrayOfByte2;
}
public static byte[] encode(byte[] paramArrayOfByte, String paramString) throws Exception { SecretKeyFactory localSecretKeyFactory = SecretKeyFactory.getInstance("DES");
byte[] arrayOfByte1 = paramString.getBytes();
javax.crypto.spec.DESKeySpec localDESKeySpec = new javax.crypto.spec.DESKeySpec(arrayOfByte1);
javax.crypto.SecretKey localSecretKey = localSecretKeyFactory.generateSecret(localDESKeySpec);
Cipher localCipher = Cipher.getInstance("DES");
localCipher.init(1, localSecretKey);
byte[] arrayOfByte2 = localCipher.doFinal(paramArrayOfByte);
return arrayOfByte2;
}
public static void main(String[] paramArrayOfString) throws Exception {
String str = "matreha!";
byte[] arrayOfByte1 = encode("lettreha".getBytes(), str);
byte[] arrayOfByte2 = { 76, -99, 37, 75, -68, 10, -52, 10, -5, 9, 92, 1, 99, -94, 105, -18 };
byte[] arrayOfByte7 = decode(arrayOfByte2, str);
String s = new String(arrayOfByte7);
for (int i = 0; i < arrayOfByte2.length; i++) {
if (arrayOfByte2[i] == arrayOfByte1[i]) {
System.out.println(s);
return;
}
}
java.io.File localFile = new java.io.File("data.bin");
FileInputStream localFileInputStream = new FileInputStream(localFile);
byte[] arrayOfByte3 = new byte[(int)localFile.length()];
localFileInputStream.read(arrayOfByte3);
localFileInputStream.close();
byte[] arrayOfByte4 = decode(arrayOfByte3, "lettreha");
FileOutputStream localFileOutputStream = new FileOutputStream("stage2.bin");
localFileOutputStream.write(arrayOfByte4, 0, arrayOfByte4.length);
localFileOutputStream.flush();
localFileOutputStream.close();
}
}
可以得出真正的密钥为lettreha,替换掉System.getProperty("user.name"),可以得到stage2.bin,根据文件头可以看出是一个elf可执行文件,直接扔入IDA,分析一下就可以找到关键跳转:
将这第一个跳转改为jnz,第二个跳转改为jmp就可以直接进入写入文件,可以得到第三个文件,是一个pyc文件,需要反编译出py源码,我用的是uncompyle6.exe:
# uncompyle6 version 3.2.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:14:34) [MSC v.1900 32 bit (Intel)]
# Embedded file name: ./1.py
# Size of source mod 2**32: 439 bytes
def decode(data, key):
idx = 0
res = []
for c in data:
res.append(chr(c ^ ord(key[idx])))
idx = (idx + 1) % len(key)
return res
flag = [
40, 11, 82, 58, 93, 82, 64, 76, 6, 70, 100, 26, 7, 4, 123, 124, 127, 45, 1, 125, 107, 115, 0, 2, 31, 15]
print('Enter key to get flag:')
key = input()
if len(key) != 8:
print('Invalid len')
quit()
res = decode(flag, key)
print(''.join(res))
# okay decompiling result.pyc
可以看出是一个简单的按位异或加密,可以根据flag的开头是cybrics{来轻易得到密钥,从而得到最终flag,解题脚本如下:
def decode(data, key):
idx = 0
res = []
for c in data:
res.append(chr(c ^ ord(key[idx])))
idx = (idx + 1) % len(key)
return res
flag = [40, 11, 82, 58, 93, 82, 64, 76, 6, 70, 100, 26, 7, 4, 123, 124, 127, 45, 1, 125, 107, 115, 0, 2, 31, 15]
key=''
a="cybrics{"
for i in range(8):
key+=chr(flag[i]^ord(a[i]))
print key
res = decode(flag, key)
print(''.join(res))
最后得到flag为: