7.31,今天打两场,一场巅峰极客,一场CryptoCTF,人麻了。巅峰极客一共三题密码,SM4那题听说差分,直接摸了,所以我就写了剩下两题,以下是wp。
MedicalImage
拿到题目源码,分析一下,题目缺少
后面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 1 条评论
博主 Lyutoon
需要逆序回去是因为有的点会被多次交换,所以必须逆回去(