前言
继续ctf的旅程
攻防世界Crypto高手进阶区的7分题
本篇是Decrypt-It-easy的writeup
发现攻防世界的题目分数是动态的
就仅以做题时的分数为准了
解题过程
题目描述
得到三个文件
readme里写着$ ./rnd crypt1.png ecrypt1.bin
把rnd扔进ida
内容很简单
输入一个文件,每个字节异或一个随机数,再输出来
由于输入文件是png
其文件头固定
可以爆破
先取得时间戳
然后爆破
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE *cipher = fopen(argv[1], "rb");
FILE *plain = fopen(argv[2], "wb");
unsigned int seed = atoi(argv[3]);
int c;
srand(seed);
c = (fgetc(cipher) & 0xff) ^ (rand() & 0xff);
while (!feof(cipher)) {
fputc(c, plain);
c = (fgetc(cipher) & 0xff) ^ (rand() & 0xff);
}
fclose(plain);
fclose(cipher);
}
得到图片
解一个类似RSA的加密
陷入困境
去查了查wp
SECCON 2014 quals # Crypto – Decrypt it (Easy)
在已知flag格式:SECCON{...}
的情况下做个试验
N, B, FLAG = 0xB8AE199365, 0xFFEEE, 'SECCON{'
for i in range(1, len(FLAG)+1):
M = int(FLAG[0:i].encode('hex'), 16)
print FLAG[0:i]+'\t'+hex(M * (M + B) % N)
发现最多5位字符
那就有
N, B = 0xB86E78C811, 0xFFFEE
for i in range(32, 127):
for j in range(32, 127):
for k in range(32, 127):
M = int(('N{' + chr(i) + chr(j) + chr(k)).encode('hex'), 16)
if ((M * (M + B) % N) == 0x5FFA0AC1A2):
print 'N{' + chr(i) + chr(j) + chr(k)
N, B = 0x7BD4071E55, 0xFEFEF
for i in range(32, 127):
for j in range(32, 127):
for k in range(32, 127):
for l in range(32, 127):
M = int((chr(i) + chr(j) + chr(k) + chr(l) + '}').encode('hex'), 16)
if ((M * (M + B) % N) == 0x6008DDF867):
print chr(i) + chr(j) + chr(k) + chr(l) + '}'
得到flag:SECCON{Ra_b1_N}
大神还给了个优美脚本
def mul_inv(a, b):
b0 = b
x0, x1 = 0, 1
if b == 1: return 1
while a > 1:
q = a / b
a, b = b, a%b
x0, x1 = x1 - q * x0, x0
if x1 < 0: x1 += b0
return x1
def chinese_remainder(n, a, lena):
p = i = prod = 1; sm = 0
for i in range(lena): prod *= n[i]
for i in range(lena):
p = prod / n[i]
sm += a[i] * mul_inv(p, n[i]) * p
return sm % prod
def bruteforce(p, q, C, B):
for Mp in [m for m in xrange(p) if (C % p) == (m * (m + B) % p)]:
for Mq in [m for m in xrange(q) if (C % q) == (m * (m + B) % q)]:
print ('%x' % chinese_remainder([p, q], [Mp, Mq], 2)).decode('hex')
结语
学到了