好久没玩ctf了,除了签到题一个小时才看到有人拿了一血还是有点意外,打了个酱油就解了道safe_box的题。
题目代码:
#!/usr/bin/python
# encoding: utf-8
import random
import sys
import os
from hashlib import sha256,sha512
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
from secret import flag
def my_print(message):
sys.stdout.write('{0}\n'.format(message))
sys.stdout.flush()
sys.stderr.flush()
def read_str():
return sys.stdin.readline().strip()
def read_int():
return int(sys.stdin.readline().strip())
def proof_of_work():
s = os.urandom(10)
digest = sha256(s).hexdigest()
print("sha256(XXX + {0}) == {1}".format(s[3:].encode('hex'),digest))
my_print("Give me XXX in hex: ")
x = read_str()
if len(x) != 6 or x != s[:3].encode('hex'):
print("Wrong!")
return False
return True
def PoW():
if not proof_of_work():
exit(-1)
class Cipher:
def __init__(self, q, p, d):
self.p = p
self.q = q
self.e = [bytes_to_long(os.urandom(10)) for _ in range(self.p-1)]
self.d = d
def pad(self, msg, l):
return msg+(l-(len(msg)%l))*chr(l-(len(msg)%l))
def unpad(self,msg):
return msg.replace(msg[-1]*ord(msg[-1]),'')
def enc(self, p):
c = []
for i in range(self.q):
b = bytes_to_long(p)
a = i+1
for j in self.e:
b += j*a
a *= i+1
c.append({'a':i+1, 'b':b})
return c
def encrypt(self,p):
c = {}
p = self.pad(p, self.d)
for i in range(len(p)/self.d):
c[i] = self.enc(p[i*self.d:(i+1)*self.d])
return c
def dec(self, x, key):
s = 0
for a, b in enumerate(key):
r1 = 1
r2 = 1
for c, d in enumerate(key):
if a == c:
continue
r1 *= (x - d['a'])
r2 *= (b['a'] - d['a'])
s = (s + b['b'] * int(r1/r2))
return s
def decrypt(self, c):
p = ''
for i in c.keys():
p += long_to_bytes(self.dec(0,c[i]))
return self.unpad(p)
def print_key(x):
for i in range(len(c)):
my_print('part:{}'.format(i))
for j in range(x):
my_print(c[i][j])
def open_box():
key = {}
my_print('hash:{}'.format(sha512(pri).hexdigest()))
my_print('Input your key:')
try:
for i in range(len(c)):
my_print('How many?')
n = read_int()
k = []
for j in range(n):
my_print('a:')
a = read_int()
my_print('b:')
b = read_int()
k.append({'a':a, 'b':b})
key[i] = k
my_print(C.decrypt(key))
except:
my_print('Wrong!')
exit(-1)
def print_flag():
my_print('flag:{}'.format(flag_enc))
if __name__ == '__main__':
PoW()
rsa_key = RSA.generate(1024)
pri = rsa_key.exportKey().decode('ascii')
e = rsa_key.e
n = rsa_key.n
flag_enc = pow(bytes_to_long(flag),e,n)
C = Cipher(40,30,40)
c = {}
c = C.encrypt(pri)
my_print('====================================',)
my_print(' Safe Box ',)
my_print('====================================',)
my_print('1. Print key ',)
my_print('2. Open the box ',)
my_print('3. Print flag ',)
my_print('4. Exit ',)
my_print('====================================',)
try:
while True:
my_print('Your choice:')
choice = read_int()
if choice == 1:
print_key(20)
elif choice == 2:
open_box()
continue
elif choice == 3:
print_flag()
continue
elif choice == 4:
my_print('Bye~')
exit(0)
else:
my_print('Invalid!')
exit(-1)
except:
exit(-1)
代码看上去并不多,感觉没啥难度,不过还是浪费了不少时间。
解题步骤:
1.先爆破Pow()函数,直接利用返回的信息里的sha256值就可以了
tables='0123456789abcdef'
def crack(hash,phash):
for a in tables:
for b in tables:
for c in tables:
for d in tables:
for e in tables:
for f in tables:
key=a+b+c+d+e+f
aa=(key+phash).decode('hex')
en=sha256(aa).hexdigest()
if(en==hash):
print key
crack('d622fa1b255187ef62a3a7b3f4d8302e8af5e4c9ad4b8022cc35fc460b88aaed','846e0c60f208bd')
2. 输入爆破得到的值后,就可以进行 Safe Box 的流程了,这里有3个选项让你选
输入1:返回加密后的private key
输入2:可以手动输入得到的加密Key ,然后得到解密后的key(这里是个坑)
输入3: 返回加密后的flag
一开始一直在选项2里折腾,发现怎么都无法解密出还原出原始的private key,仔细一看原来print_key(20)处被写死,然后又在想会不会有什么点可以绕过这个限制,事实证明我想多了,只能认真的分析下程序算法了,加解密算法并不复杂,大概原理就是将数据按每40字节分组,然后与一组随机生成的数组进行40轮简单加解密。经过分析发现每组数据在第一轮加密后与原始明文long数值的差值是固定的,即随机数组里所有元素的和,然后又发现每次明文最后一组的数据是固定的即 :Y-----"""""""""""""""""""""""""""""""""" (转换成long型就是 744061660490831401720358135957044040624762956183858929566796822738090422707035217211627153793570 )
那么问题就很简单了,只要获取到每个加密数数组的第一轮加密数据,然后减去随机数组的元素和即可到每组数据到明文了。
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
Y=744061660490831401720358135957044040624762956183858929566796822738090422707035217211627153793570 # Y-----""""""""""""""""""""""""""""""""""
b=744061660490831401720358135957044040624762956183858929566796822738090443044343341555030147467997 # 22:{a:1,b)
key=b-Y
enArray=(376938888692085382665423970042166795432413643305381575515959305455321957741014775556099620418045,544468557384865678127345888521495313711382128314859750251204026686164722602749584634601451696932,936101863006478342720038665189970172996754294438095819543794318309687441954041410312356961205021,945355955896365723878024971494183079099098972541901990987319507419339577081199196130743996725552,1009927065105467358154476981763299990726808995553632657647913745864178492326783116709365594331925,836241384832791658137916346910573727829004236580891323144317685292381904999801468162685758611444,595280407097020068888759905382405777941512944367468979590546217648279108805708209523967337050866,811862911578721893752222144128069161704293431371813548289344133980059786179414937927256660646891,446003104010318947186274361077732608843996581840608966768396761016666881193309951106081400511499,429193079854919286788434876264198143566911851436927601048419350638341406138476562661649103532338,937014067747737592606609025374139759103571073396876043808772291642335260548903025831635445888559,729208755537554932956043583675437131853651711344675678385026621665056085849104934561648366407166,402107753811158736815110639265848158215095048209693387269254227563798934696564548250919178751495,927727845373399402412610559053654216346976069623456352980299764410620755363258805047478014064640,746115275774873409205189797393521344082179101140418072961666897265918298006377841353214785958414,838257545574874382295194121765901957577655245852630668226460565037927114012623060794922636227621,629433974006044324659221111265384100736178750737700485339308412867233355147145455948368163058927,984891273313147336895952391272313093974330446431216458686712895436107646744733102205255571361025,645150230225498024293187757526128357832649727978165711927749423366581907868767100605472749862954,629728321731935633564795173187536429717504149188177011275213046248401785264348076908848682322412,853445946967267849671129453112618997400335475512430361491441643662072543222492330760705669159718,920655243119519668135791583707354953573453025435735289018915049432726028584966406841033994941440,744061660490831401720358135957044040624762956183858929566796822738090443044343341555030147467997)
pri_key=''
for e in enArray:
pri_key+=long_to_bytes(e-key)
print pri_key.replace('"','')
enFlag=63691588785660450317214825708635325578264899588028990196984494438817954811895751497618774951869925317964025052448125889561348001616704468223377247262611909655901924855878419507099314895648511160807472080632874648633768843995755598898623455640343918449933193867222158283075059339069188753156113156738195632730
rsa_key=RSA.importKey(pri_key)
n = rsa_key.n
d = rsa_key.d
print long_to_bytes(pow(enFlag,d,n))