[GXYCTF2019]CommonModulusAttack
题目
old.txt
-1029728314
1487023297
1423989849
1599108224
-1105891682
-155445570
1810855967
-86576152
-699473878
148445908
2098722170
1844125436
1326761031
552466959
-2003932646
-743304688
1450367769
1947341463
-1847355229
111050485
解题
class文件是需要反翻译的,在线反翻译网址:http://javare.cn/
反翻译完之后得到:
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CommonModulusAttack {
private Random random = new Random();
private ArrayList states = new ArrayList(24);
private String seed;
private int statespoint = 0;
private int stateselse = 24;
public void oldtest() {
try {
PrintWriter var1 = new PrintWriter("old.txt", "UTF-8");
for(int var2 = 0; var2 < 20; ++var2) {
int var3 = this.random.nextInt();
var1.println(var3);
}
var1.close();
} catch (IOException var4) {
var4.printStackTrace();
}
}
public BigInteger generate_init_state() {
BigInteger var1 = BigInteger.valueOf(0L);
char[] var2 = this.seed.toCharArray();
char[] var3 = var2;
int var4 = var2.length;
for(int var5 = 0; var5 < var4; ++var5) {
char var6 = var3[var5];
var1 = var1.shiftLeft(1);
if(var6 == 49) {
var1 = var1.xor(new BigInteger(this.seed, 2));
}
if(var1.shiftRight(256) != BigInteger.ZERO) {
var1 = var1.xor(new BigInteger("10000000000000000000000000000000000000000000000000000000000000223", 16));
}
}
return var1;
}
public void gen_states() {
BigInteger var1 = this.generate_init_state();
BigInteger var2 = BigInteger.valueOf(17L);
ArrayList var3 = new ArrayList(24);
ArrayList var4 = new ArrayList(24);
for(int var5 = 0; var5 < 24; ++var5) {
BigInteger var6 = BigInteger.probablePrime(512, this.random);
BigInteger var7 = BigInteger.probablePrime(512, this.random);
BigInteger var8 = var6.multiply(var7);
BigInteger var9 = var1.modPow(var2, var8);
var3.add(var8);
var4.add(var9);
}
try {
PrintWriter var11 = new PrintWriter("product", "UTF-8");
for(int var12 = 0; var12 < 24; ++var12) {
var11.println(((BigInteger)var3.get(var12)).toString());
this.states.add(var4.get(var12));
}
var11.close();
} catch (IOException var10) {
var10.printStackTrace();
}
}
public byte[] encrypt(BigInteger var1) {
try {
IvParameterSpec var2 = new IvParameterSpec(new byte[16]);
byte[] var3 = new byte[16];
this.random.nextBytes(var3);
SecretKeySpec var4 = new SecretKeySpec(var3, "AES");
Cipher var5 = Cipher.getInstance("AES/CBC/NoPadding");
var5.init(1, var4, var2);
byte[] var6 = new byte[128];
byte[] var7 = var1.toByteArray();
int var8;
if(var7.length == 129) {
for(var8 = 0; var8 < 128; ++var8) {
var6[var8] = var7[var8 + 1];
}
} else {
for(var8 = 0; var8 < 128; ++var8) {
var6[var8] = var7[var8];
}
}
byte[] var10 = var5.doFinal(var6);
return var10;
} catch (Exception var9) {
var9.printStackTrace();
return null;
}
}
public void gen_new_states() {
for(int var1 = 0; var1 < 24; ++var1) {
BigInteger var2 = (BigInteger)this.states.get(this.statespoint - 24 + var1);
byte[] var3 = this.encrypt(var2);
this.states.add(new BigInteger(var3));
}
this.stateselse += 24;
}
public byte[] stateconvert(BigInteger var1) {
byte[] var2 = this.encrypt(var1);
return var2;
}
public byte[] lrandout() {
if(this.stateselse > 0) {
--this.stateselse;
BigInteger var1 = (BigInteger)this.states.get(this.statespoint);
++this.statespoint;
return this.stateconvert(var1);
} else {
this.gen_new_states();
return this.lrandout();
}
}
public static String byte2hex(byte[] var0) {
StringBuffer var1 = new StringBuffer(var0.length * 2);
for(int var2 = 0; var2 < var0.length; ++var2) {
if((var0[var2] & 255) < 16) {
var1.append("0");
}
var1.append(Long.toString((long)(var0[var2] & 255), 16));
}
return var1.toString();
}
public static String convert_2_binary(String var0) {
byte[] var1 = var0.getBytes();
StringBuilder var2 = new StringBuilder();
byte[] var3 = var1;
int var4 = var1.length;
for(int var5 = 0; var5 < var4; ++var5) {
byte var6 = var3[var5];
int var7 = var6;
for(int var8 = 0; var8 < 8; ++var8) {
var2.append((var7 & 128) == 0?0:1);
var7 <<= 1;
}
}
return var2.toString();
}
public void initseed() {
try {
Scanner var1 = new Scanner(Paths.get("flag", new String[0]), "UTF-8");
String var2 = var1.next();
String var3 = convert_2_binary(var2);
this.seed = var3;
} catch (IOException var4) {
var4.printStackTrace();
}
}
public static void main(String[] var0) {
CommonModulusAttack var1 = new CommonModulusAttack();
var1.oldtest();
var1.initseed();
var1.gen_states();
for(int var2 = 0; var2 < 24; ++var2) {
var1.lrandout();
}
try {
PrintWriter var5 = new PrintWriter("new.txt", "UTF-8");
for(int var3 = 0; var3 < 24; ++var3) {
var5.println(byte2hex(var1.lrandout()));
}
var5.close();
} catch (IOException var4) {
var4.printStackTrace();
}
System.out.println("Bye!");
}
}
感觉自己Java还是太菜了,代码一长就发怵
先是进行了20次的.random.nextInt(),得到old.txt
然后initseed把flag进行一系列运算,进一步分析得知是在GF(2256)中将flag平方了一下;
state通过RSA part生成的24组(p,q),e=17,加密得到this.states (len(states == 24))
lrandout先AES/CBC完整加密了一次this.states的24个值,但该次并未更新this.states
由于this.stateselse此时为0,因此执行lrandout会先新生成24个state(即调用gen_new_states)
在旧states后新增一长度为24的states后,用新增的states加密得到的结果即为new.txt中内容
啊,智商不够啊😭
来看某大佬的代码
SeedAttack.java
public class SeedAttack {
private long a = 0x5deece66dL;
private long b = 11L;
private long m = 0xffffffffffffL;
public long crack_seed(long d1, long d2) throws Exception {
for (int i = 0; i <= 0xffff; i++) {
long seed = (d1 << 16) + i;
long guess_d2 = (a * seed + b & m) >>> 16;
if (guess_d2 == d2) {
System.out.println("[+] PRNG's seed: " + String.valueOf(seed));
return seed;
}
}
throw new Exception("[!] PRNG crack failed!");
}
// public static void main(String[] args) {
// SeedAttack localSeedAttack = new SeedAttack();
// long d1 = -1029728314L;
// long d2 = 1487023297L;
// try {
// long seed = localSeedAttack.crack_seed(d1, d2);
// System.out.println(seed);
// } catch (Exception e) {
// System.out.println(e.getMessage());
// }
// }
}
CMA.java
import java.util.Random;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.math.BigInteger;
public class CMA {
private Random random = new Random();
public CMA() {
long PRNG_seed = 0L;
SeedAttack localSeedAttack = new SeedAttack();
long d1 = -1029728314L;
long d2 = 1487023297L;
try {
PRNG_seed = localSeedAttack.crack_seed(d1, d2);
// System.out.println(PRNG_seed);
} catch (Exception e) {
System.out.println(e.getMessage());
}
this.random.setSeed(PRNG_seed ^ 0x5DEECE66DL);
}
// discard trash which generate old.txt
public void discardTrash() {
for (int i = 0; i < 19; i++) {
int j = this.random.nextInt();
}
}
public void genRSA() {
BigInteger e = BigInteger.valueOf(17L);
ArrayList<ArrayList> RSA_params = new ArrayList<ArrayList>(24);
for (int i = 0; i < 24; i++) {
ArrayList curRSAparams = new ArrayList(2);
BigInteger p = BigInteger.probablePrime(512, this.random);
BigInteger q = BigInteger.probablePrime(512, this.random);
curRSAparams.add(p);
curRSAparams.add(q);
RSA_params.add(curRSAparams);
}
try {
PrintWriter localPrintWriter = new PrintWriter("prikey", "UTF-8");
for (int i = 0; i < 24; i++) {
ArrayList curRSAparams = RSA_params.get(i);
String p = curRSAparams.get(0).toString();
String q = curRSAparams.get(1).toString();
localPrintWriter.println("(" + p + ", " + q + ")");
}
System.out.println("[+] RSA's priKey found");
localPrintWriter.close();
} catch (IOException error) {
error.printStackTrace();
}
}
public static String byte2hex(byte[] paramArrayOfByte)
{
StringBuffer localStringBuffer = new StringBuffer(paramArrayOfByte.length * 2);
for (int i = 0; i < paramArrayOfByte.length; i++)
{
if ((paramArrayOfByte[i] & 0xFF) < 16) localStringBuffer.append("0");
localStringBuffer.append(Long.toString(paramArrayOfByte[i] & 0xFF, 16));
}
return localStringBuffer.toString();
}
public void genKey() {
try {
PrintWriter localPrintWriter = new PrintWriter("AESkey", "UTF-8");
for (int i = 0; i < 72; i++) {
byte[] key = new byte[16];
this.random.nextBytes(key);
localPrintWriter.println(byte2hex(key));
}
System.out.println("[+] AES's key found");
localPrintWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
CMA exp = new CMA();
exp.discardTrash();
exp.genRSA();
exp.genKey();
}
}
exp.py
import re
from Crypto.Cipher import AES
from binascii import unhexlify
from Crypto.Util.number import *
def getData():
pqs = []
with open('prikey', 'r') as fRSA:
for line in fRSA:
pq = re.findall(r"\((.*), (.*)\)", line)[0]
pqs.append((int(pq[0]), int(pq[1])))
with open('AESkey', 'r') as fAES:
key = [unhexlify(line.strip()) for line in fAES]
key = [key[:24], key[24:48], key[48:]]
with open('new.txt', 'r') as fCIPHER:
cipher = [unhexlify(line.strip()) for line in fCIPHER]
return pqs, key, cipher
def dec1(p, q, c, key1, key2):
aes2 = AES.new(key2, AES.MODE_CBC, iv=b"\x00"*16)
c = aes2.decrypt(c)
aes1 = AES.new(key1, AES.MODE_CBC, iv=b"\x00"*16)
c = bytes_to_long(aes1.decrypt(c))
e = 17
n = p * q
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
return m
def mul(x):
a = 0
for i in bin(x)[2:]:
a = a << 1
if (int(i)):
a = a ^ x
if a >> 256:
a = a ^ 0x10000000000000000000000000000000000000000000000000000000000000223
return a
def dec2(m):
while True:
m = mul(m)
if b"flag" in long_to_bytes(m):
print(long_to_bytes(m))
break
def main():
pqs, key, cipher = getData()
m = dec1(pqs[0][0], pqs[0][1], cipher[0], key[1][0], key[2][0])
dec2(m)
if __name__ == '__main__':
main()
# b'flag{86824087489918371343860652}'