7.31,今天打两场,一场巅峰极客,一场CryptoCTF,人麻了。巅峰极客一共三题密码,SM4那题听说差分,直接摸了,所以我就写了剩下两题,以下是wp。
MedicalImage
拿到题目源码,分析一下,题目缺少,根据提示可以知道,是logistics混沌模型,百度找一下,让参数取最大的4就可以了,直接return 4*x*(1-x)。
后面encrypt的部分,先循环了200次,把它们混沌了,然后是一个交换点的过程,这个过程是需要倒序逆向的 (正序没出,有师傅知道原因,告诉我为什么)。p0 c0做为config没有给我们,一共16组可以爆破,然后就是真正的加密部分的循环。
加密部分关键是 c0 = k ^ ((k + p0) % 256) ^ c0 。k这里可以直接得到然后异或回去,c0的话,取上一个点的值异或,然后再减k就可以了。这一部分的逆向需要顺序进行,否则p0是未知的。
from PIL import Image from decimal import * import numpy as np import random getcontext().prec = 20 def f1(x): assert (x >= 0) assert (x <= 1) return 4 * x * (1 - x) def f2(x): assert (x >= 0) assert (x <= 1) return 4 * x * (1 - x) def f3(x): assert (x >= 0) assert (x <= 1) return 4 * x * (1 - x) im = Image.open('flag_enc.bmp') size = im.size pic = np.array(im) im.close() r1 = Decimal('0.478706063089473894123') r2 = Decimal('0.613494245341234672318') r3 = Decimal('0.946365754637812381837') w, h = size for i in range(200): r1 = f1(r1) r2 = f2(r2) r3 = f3(r3) const = 10 ** 14 p = [100, 101, 102, 103] c = [200, 201, 202, 203] R1, R2, R3 = r1, r2, r3 l1 = [] l2 = [] for i in range(w * h): l1.append(r1) l2.append(r2) r1 = f1(r1) r2 = f2(r2) def decrypt(p0, c0, r1=R1, r2=R2, r3=R3): for x in range(w): for y in range(h): k = int(round(const * r3)) % 256 k = bin(k)[2:].ljust(8, '0') k = int(k[p0 % 8:] + k[:p0 % 8], 2) r3 = f3(r3) pic[y, x] = ((pic[y, x] ^ c0 ^ k) - k) % 256 p0 = pic[y, x] c0 = k ^ ((k + p0) % 256) ^ c0 t = w * h - 1 for x in range(w - 1, -1, -1): for y in range(h - 1, -1, -1): x1 = int(round(const * l1[t])) % w y1 = int(round(const * l2[t])) % h tmp = pic[y, x] pic[y, x] = pic[y1, x1] pic[y1, x1] = tmp t -= 1 return pic, size enc_img = 'flag.bmp' count = 0 for p0 in p: for c0 in c: pic, size = decrypt(p0, c0) im = Image.new('P', size, 'white') pixels = im.load() for i in range(im.size[0]): for j in range(im.size[1]): pixels[i, j] = (int(pic[j][i])) count += 1 im.save(str(count) + enc_img)
crtrsa
这题一开始拿到,以为和MRCTF那题差不多,翻了那题的paper,怎么搞都搞不出来。再回到式子本身,才知道怎么做。
先对CRT化简
对(p-1)和(q-1)取模可以知道,dp、dq就是正常的dp、dq。
注意到dp被限制在1<<20之内,所以可以爆破。于是我们有
所以由费马小定理我们可以知道
于是只需要把等式左边的值,和n GCD就可以得到p,进而得到flag,不过爆破还是要跑一小会的。
import gmpy2 as gp from Crypto.Util.number import * e = 2953544268002866703872076551930953722572317122777861299293407053391808199220655289235983088986372630141821049118015752017412642148934113723174855236142887 n = 6006128121276172470274143101473619963750725942458450119252491144009018469845917986523007748831362674341219814935241703026024431390531323127620970750816983 c = 4082777468662493175049853412968913980472986215497247773911290709560282223053863513029985115855416847643274608394467813391117463817805000754191093158289399 for i in range(1,1<<20): dp=i t=pow(2,e*dp-1,n)-1 if gp.gcd(t,n)!=1: print(gp.gcd(t,n)) p=88483113499234291234797595363172914275282163218450540253170700235627922981203 q=n//p phi=(p-1)*(q-1) d=gp.invert(e,phi) print(long_to_bytes(pow(c,d,n)))
SM4
这题过几天复现(咕咕咕咕咕
Comments NOTHING