巅峰极客wp

发布于 2021-07-31  1109 次阅读





巅峰极客wp

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

这题过几天复现(咕咕咕咕咕