[CISCN 2018]sm
chall.py
from Crypto.Util.number import getPrime,long_to_bytes,bytes_to_long
from Crypto.Cipher import AES
import hashlib
from random import randint
def gen512num():
order=[]
while len(order)!=512:
tmp=randint(1,512)
if tmp not in order:
order.append(tmp)
# order[]:1~512的一个随机排列
ps=[]
for i in range(512):
p=getPrime(512-order[i]+10)
pre=bin(p)[2:][0:(512-order[i])]+"1"
ps.append(int(pre+"0"*(512-len(pre)),2))
return ps
def run():
choose=getPrime(512)
ps=gen512num()
print ("gen over")
bchoose=bin(choose)[2:]
r=0
bchoose = "0"*(512-len(bchoose))+bchoose
for i in range(512):
if bchoose[i]=='1':
r=r^ps[i]
flag=open("flag","r").read()
key=long_to_bytes(int(hashlib.md5(long_to_bytes(choose)).hexdigest(),16))
aes_obj = AES.new(key, AES.MODE_ECB)
ef=aes_obj.encrypt(flag).encode("base64")
open("r", "w").write(str(r))
open("ef","w").write(ef)
gg=""
for p in ps:
gg+=str(p)+"\n"
open("ps","w").write(gg)
run()
分析:
重点是要注意到
这个0是补在右边的!
也就是每个ps中的p 它右边的0个数是不同的
那么 r 作为这些数中间某些数的xor 就可以通过r某位的值是0/1来推断对应的p的位置 从而得到flag每位的bit
实现思路:
- 先计算并保存每个p右边0的个数 num0[]
- r从低位开始判断 1:找num0[]中值为当前r位数的下标
solution.py
from Crypto.Util.number import *
from Crypto.Cipher import AES
import hashlib
from base64 import *
r = 6753785483255906709117615805253027649453460653974415214642466102672301763943358839905575042938258141827000621474498066533397472809407687579125519939754658
ef = '5eFo3ANg2fu9LRrFktWCJmVvx6RgBFzd0R8GXQ8JD78='
ps = open('.\[CISCN 2018]sm\ps','r+').readlines()
def Get0snum(x):
x = int(x)
tot = 0
while((x&1)==0):
tot += 1
x>>=1
return tot
flag = [0]*512
num0 = []
for p in ps:
num0.append(Get0snum(p))
for i in range(511,-1,-1):
if((r>>(511-i))&1 == 1):
r ^= int(ps[num0.index(511-i)])
flag[num0.index(511-i)] = '1'
else:
flag[num0.index(511-i)] = '0'
flag = ''.join(flag)
flag = int(flag,2)
choose = flag
key = long_to_bytes(int(hashlib.md5(long_to_bytes(choose)).hexdigest(),16))
aes_obj = AES.new(key, AES.MODE_ECB)
flag = b64decode(ef.encode())
flag = aes_obj.decrypt(flag)
print(flag)