这比赛,对我这菜鸡来说又是一次降维打击,希望自己能够砥砺前行!
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。
下面的解参考这篇博客,先贴这了,有空回过头来再分析。
参考: