loading...
第四届强网拟态防御国际精英挑战赛Crypto方向复现
Published in:2021-10-27 | category: 密码学

这比赛,对我这菜鸡来说又是一次降维打击,希望自己能够砥砺前行!

onlyrsa

题目如下:

#!/usr/bin/env python
from Crypto.Util.number import *
from secret import flag

n = 264048827496427248021277383801027180195275776366915828865010362454006394906519399441496561006668252031429735502465174250525698696973129422193405161920872162928097673289330345041221985548078586423910246601720647996170161319016119241836415788315729493164331517547663558380515400720081995290120793014108439083514403659082115510258023834737471488528527557960636984676435543300074504679264476413252780514962473070445293528877641502742438571110744667739728450283295649865745629276142949963507003094791773183928894536793857609738113546410753895719242547720815692998871947957214118354127328586542848234994500987288641595105
e = 65537
m = bytes_to_long(flag)
c = pow(m,e,n)
print(c)
# 76196483810925191371357319946893762223027002702624516192769497540954799651198719100683206759706879828894501526423422596543748404479640715319801018211652987852179907519286760601944889601355220646374788026632971331786307898234821477134265724962397355614076896148563340833323366935479885600112872998594315513803419069126624158092821269145991266528158747750965226483644012365861166608598063649804899693010576080857540523307078138634628539419178875838147396170651777949577793359622498517581948006585916952705460782942977789615065947303447566918741750017127110484065354974088489869377128636357092420660532261674969708694
------------------------------------------------------------------------------------------------------------
hint:
    RSA say : My birthday is in November instead of October

思路其实很简单,中规中矩的分解大素数。就是当你把十进制的n放到factordb上进行分解时,发现无法完全分解。所以要想得到n的素因子必须得看懂hint,不过它确实脑洞(愣是没看明白),看了大佬的WP也是惊呼“绝了”。hint的意思是“October”对应“10进制”,“November”对应“11进制”。这样直接在sage上进行进制转换,再进行11进制的多项式在环上分解。sage脚本如下:

n = 264048827496427248021277383801027180195275776366915828865010362454006394906519399441496561006668252031429735502465174250525698696973129422193405161920872162928097673289330345041221985548078586423910246601720647996170161319016119241836415788315729493164331517547663558380515400720081995290120793014108439083514403659082115510258023834737471488528527557960636984676435543300074504679264476413252780514962473070445293528877641502742438571110744667739728450283295649865745629276142949963507003094791773183928894536793857609738113546410753895719242547720815692998871947957214118354127328586542848234994500987288641595105
p = 11
a = n.digits(p)
PR.<x> = PolynomialRing(ZZ)

f = PR(a)
fac = f.factor()

for coefficient, exponent in fac:  //获取多项式
    print (coefficient(p)^exponent) //11代回多项式得到对应的十进制数

得到两个素因子:

q = 16249579302136589695295481114504339262045249125801939374419304404565893699789462299636475519992076209810443523832755415818528536943125532985768629325734679453205207122927745917471850395124342956866284689792620888965652429711989205344392333681297321070276796015579775171010928476523589349812683875326849195595
p = 16249579302136675275737472669394168521026727339712083110552530420348131906271518040549529167354613121510156841352658645018277766962773342379074137176993546193979134201416444089373463960664685121485689105129185197998903479181913613273443541075619342246119648308939006396145123630152777688592984718084919469059

最后就是模p下的RSA基操:

from Crypto.Util.number import *
from gmpy2 import *

n = 26404882749642724802127738380102718019527577636691582886501036245400639490651939944149656100666825203142973550246517425052569869697312942219340516192087216292809767328933034504122198554807858642391024660172064799617016131901611924183641578831572949316433151754766355838051540072008199529012079301410843908351440365908211551025802383473747148852852755796063698467643554330007450467926447641325278051496247307044529352887764150274243857111074466773972845028329564986574562927614294996350700309479177318392889453679385760973811354641075389571924254772081569299887194795721411835412732858654284823499450098728864159510511
e = 65537
c = 76196483810925191371357319946893762223027002702624516192769497540954799651198719100683206759706879828894501526423422596543748404479640715319801018211652987852179907519286760601944889601355220646374788026632971331786307898234821477134265724962397355614076896148563340833323366935479885600112872998594315513803419069126624158092821269145991266528158747750965226483644012365861166608598063649804899693010576080857540523307078138634628539419178875838147396170651777949577793359622498517581948006585916952705460782942977789615065947303447566918741750017127110484065354974088489869377128636357092420660532261674969708694
p = 16249579302136675275737472669394168521026727339712083110552530420348131906271518040549529167354613121510156841352658645018277766962773342379074137176993546193979134201416444089373463960664685121485689105129185197998903479181913613273443541075619342246119648308939006396145123630152777688592984718084919469059

phin = (p - 1)
d = inverse(e, phin)
m = pow(c, d, p)
print(long_to_bytes(m))

Ezhash

题目如下:

import os, random, hashlib, string
from signal import alarm
from Crypto.Cipher import AES
from binascii import unhexlify
from secret import flag

class MyHash:
    def __init__(self):
        self.cipher = AES.new(b"a"*32,AES.MODE_ECB)
        self.state = b"\x00"*16
    
    def enc(self,m):
        return self.cipher.encrypt(m)
    
    def upadteState(self,m):
        m += b"\x00" * 5
        state = bytes([(a+b+2)%256 for a,b in zip(self.state,m)])
        self.state = self.enc(state)
    
    def finalUpdateState(self,m):
        padding_len = 11 - len(m) % 11
        m += bytes([0x80] + [padding_len - 1] * (padding_len - 1))
        self.upadteState(m)

    def genResult(self):
        result = hashlib.sha256(self.state[:11]).digest() + self.state[11:]
        return result

    def hash(self,msg):
        self.state = b"\x00" * 16
        length = len(msg) // 11
        for i in range(length):
            subMsg = msg[11*i:11*(i+1)]
            self.upadteState(subMsg)
        finalMsg = msg[length*11:]
        self.finalUpdateState(finalMsg)
        return self.genResult()


def proof_of_work():
    random.seed(os.urandom(8))
    proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
    digest = hashlib.sha256(proof.encode()).hexdigest()
    print("sha256(XXXX+%s) == %s" % (proof[4:],digest))
    print("Give me XXXX:")
    x = input()
    if len(x) != 4 or hashlib.sha256((x + proof[4:]).encode()).hexdigest() != digest: 
        return False
    return True
   
def main():
    alarm(60)
    if not proof_of_work():
        return
    alarm(10)
    TARGET = b"I think the hash function has no weakness!"
    try:
        h = MyHash()
        h1 = h.hash(TARGET)
        anotherHash = unhexlify(input("Please your hash (hex) : "))
        if anotherHash != TARGET:
            h2 = h.hash(anotherHash)
            if h1 == h2:
                print(f"Success! Here is your flag : {flag}")
            else:
                print("Try again!")
        else:
            print("Can't input TARGET!")
    except:
        print("Error!")

if __name__ == "__main__":
    main()

我们把里面的函数一个一个地分析:

def __init__(self):
        self.cipher = AES.new(b"a"*32,AES.MODE_ECB)
        self.state = b"\x00"*16

初始化函数,生成一个AES对象模式为ECB(可以把它看作是一个加密工具,以下简称它为“AES加密工具”),key为32个字节‘a’,‘a’的ASCII码值为97,一个字节的‘a’表示成‘01100001’。并初始化state为16字节长度的0。

def enc(self,m):
        return self.cipher.encrypt(m)

enc()为AES的加密函数。

def upadteState(self,m):
        m += b"\x00" * 5
        state = bytes([(a+b+2)%256 for a,b in zip(self.state,m)])
        self.state = self.enc(state)

先贴一下zip函数的用例:

zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
zip 语法:
zip([iterable, ...])
iterabl -- 一个或多个迭代器;返回元组列表。
>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)]
>>> zip(a,c)              # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
>>> zip(*zipped)          # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
[(1, 2, 3), (4, 5, 6)]

该函数传入两个参数分别是AES工具和m,先在m后面补上5个字节‘0’,然后让m的每个字节数与state的字节数相加再加2模256,将其加密后把值赋给AES工具的state。

def finalUpdateState(self,m):
        padding_len = 11 - len(m) % 11
        m += bytes([0x80] + [padding_len - 1] * (padding_len - 1))
        self.upadteState(m)

计算附加字节长度(这里假设为n),如果不是11的倍数,就在m的后面补上b’0x80’+(n - 1)个b’n - 1’,最后再调用upadteState()函数。

def genResult(self):
        result = hashlib.sha256(self.state[:11]).digest() + self.state[11:]
        return result

对state的前11个字节进行sha256加密,剩余的部分照抄。

def hash(self,msg):
        self.state = b"\x00" * 16
        length = len(msg) // 11
        for i in range(length):
            subMsg = msg[11*i:11*(i+1)]
            self.upadteState(subMsg)
        finalMsg = msg[length*11:]
        self.finalUpdateState(finalMsg)
        return self.genResult()

这个函数是对前面几个函数的整合,初始化state,subMsg为msg的每11个字节的分段,通过调用upadteState()函数一直加密state,加密的次数是满11字节分段的数量(假设为n)。最后一个不足11字节的部分通过finalUpdateState()函数进行填补,然后再调用upadteState()函数加密state,也就是这里对state加密了n+1次。最后通过调用genResult()函数对state的前11字节进行sha256加密,剩余部分不变。

def proof_of_work():
    random.seed(os.urandom(8))
    proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
    digest = hashlib.sha256(proof.encode()).hexdigest()
    print("sha256(XXXX+%s) == %s" % (proof[4:],digest))
    print("Give me XXXX:")
    x = input()
    if len(x) != 4 or hashlib.sha256((x + proof[4:]).encode()).hexdigest() != digest: 
        return False
    return True

随机生成种子,proof是随机的20个字母和数字,接着对proof加密赋值给digest。在nc的时候题目要求我们输入四个字符,让其附上proof的第四位到末尾的字符串通过sha256加密,看看加密的结果是否等于digest。

下面的解参考这篇博客,先贴这了,有空回过头来再分析。


参考:

https://zhuanlan.zhihu.com/p/425964043

Prev:
LFSR
Next:
BUUCTF-Crypto系列-[113-128]WP
catalog
catalog