Barter
两个文件:
homework
from Crypto.Util.number import *
from params import N, E, D
from leak_data import P, Q, r_1
import re
def challenge():
meum = '''option:
1: get pubkey
2: get sign
3: verify
4: exit'''
print("Hi, I am John. If you help me with my homework, I'll give you the data that I know ( ̄o ̄) . z Z")
print(meum)
sign = None
while True:
print('[+]input your option: ', end='')
your_input = input()
if your_input == '1':
print(f'[+]N = {N}')
print(f'[+]e = {E}')
continue
elif your_input == '2':
sign = pow(bytes_to_long(MSG.encode()), D, N)
print(f'[+]sign = {sign}')
continue
elif your_input == '3':
if sign is None:
print('[+]Please input option 2 to generate sign first.')
continue
msg_user = input("[+]Please input your message: ")
n = int(input("[+]Please input n: "))
e = int(input("[+]Please input e: "))
if e <= 3:
print('[+]e is invalid')
break
else:
if re.match(r'I can not agree more!!!$', msg_user):
if pow(bytes_to_long(msg_user.encode()), e, n) == sign:
print("Goooooooood! You are my hero! I can give you the data that I know ╰(*°▽°*)╯")
print(f'Leak_data: \n P={P}\n Q={Q}\n first num in r_list={r_1}')
break
else:
print('[+]Error signature!')
break
else:
print('[+]Error message!')
break
elif your_input == '4':
break
if __name__ == '__main__':
MSG = 'This is an easy challenge'
challenge()
chal
from Crypto.Util.number import *
from random import *
from secrets import flag
def gen_random(seed, P, Q, r_list, times):
s = seed
for i in range(times):
s = int((s * P)[0])
r = int((s * Q)[0])
r_list.append(r)
return r_list
def gen_seed():
seed = getRandomNBitInteger(32)
return seed
def getP_Q():
Q = Curve.random_point()
P = 114514*Q
return P, Q
def enc(flag, rlist):
seq = list(randint(0, 1) for _ in range(4))
add = rlist[55]*(seq[0]*rlist[66] + seq[1]*rlist[77] + seq[2]*rlist[88] + seq[3]*rlist[99])
xor = pow(rlist[114], rlist[514], rlist[233]*rlist[223])
enc = (bytes_to_long(flag)^^xor)+add
return enc
nums = 600
seed = gen_seed()
p = 58836547289031152641641668761108233140346455328711205590162376160181002854061
F = GF(p)
a = F(114)
b = F(514)
Curve = EllipticCurve(F, [a, b])
P, Q = getP_Q()
r_list = []
r_list = gen_random(seed, P, Q, r_list, nums)
ENCFLAG = enc(flag, r_list)
print(ENCFLAG)
print(P, Q)
print(r_list[0])
'''
4911741083112145038719536311222612998219730565328651097326896414315857050336523018712625917027324116103593300559128797807261543857571883314990480072241188
#####################################
#####################################
Oh no, P, Q and r_list[0] are accidentally lost, but John seems to know, you can ask him about these missing values ::>_<::
'''
需要先通过homework求出P、Q、r_list[0]来。
第一步就是输入合适的n和e,且e>3,保证pow(bytes_to_long(msg_user.encode()), e, n) == sign,有两种方法:
法一:因为e>3,取个较小的e(4、5),这样可以直接求出n:
$n = m^e-sign$
法二:生成光滑n后离散对数求出e(光滑数较于普通的大整数更容易求出离散对数)
def gen_primes(nbit, imbalance):
"""
:param nbit: 最终光滑数比特数
:param imbalance: 最小单位比特数
:return: 比特数
"""
p = int(2)
FACTORS = [p]
while p.bit_length() < nbit - 2 * imbalance:
factor = getPrime(imbalance)
FACTORS.append(factor)
p *= factor
rbit = (nbit - p.bit_length()) // 2
while True:
r, s = [getPrime(rbit) for _ in '01']
_p = p * r * s
if _p.bit_length() < nbit: rbit += 1
if _p.bit_length() > nbit: rbit -= 1
if isPrime(_p + 1):
FACTORS.extend((r, s))
p = _p + 1
break
FACTORS.sort()
return (p, FACTORS)
MSG = 'This is an easy challenge'
msg = 'I can not agree more!!!'
sign = 2007693265003793531961671894515047380652880039368379717802504726955615563153911755018745338145752718217463688949530928466521446062822626671546131855463622
M = bytes_to_long(MSG.encode())
m = bytes_to_long(msg.encode())
n, n_fac = gen_primes(512, 20)
# 离散对数sage求解(模数小 / 阶光滑)
# h = g^x mod p
# c1 = m^e mod n1
p = n
g = m
h = sign
x = discrete_log(Mod(h,p),Mod(g,p))
print(pow(m,x,p)==sign)
print('n =', p)
print('e =', x)
$P = 114514 \times Q $
$s_0 = seed \cdot P = 114514 \cdot seed \cdot Q $
$r_0 = s_0 \cdot Q = (114514 \cdot seed \cdot Q) \cdot Q $
$\Rightarrow$
$s_1 = s_0 \cdot P = (114514 \cdot seed \cdot Q) \cdot 114514 \cdot Q = r_0 \cdot 114514$
$r_1 = s_1 \cdot Q$
通过求出的$r_0$和$Q$求出$s_0$,进而能得到每次迭代的s和r,完整的$r_{list}$便能求出:
rlist = [r0]
for i in range(600):
s = (E.lift_x(rlist[-1])*114514)[0]
rlist.append((s*Q)[0])
有了rlist就开始求flag:
seq = list(randint(0, 1) for _ in range(4))
seq总共4个元素,每个元素要么是0要么是1,总共16中情况,可爆破。
from Crypto.Util.number import *
p = ...
F = GF(p)
a = F(114)
b = F(514)
E = EllipticCurve(F, [a, b])
P = E(..., ...)
Q = E(..., ...)
r0 = ...
enc = ...
rlist = [r0]
for _ in range(600):
s = (E.lift_x(rlist[-1])*114514)[0]
rlist.append((s*Q)[0])
for i in range(0,2):
for j in range(0,2):
for m in range(0,2):
for n in range(0,2):
add = rlist[55] * (i * rlist[66] + j * rlist[77] + m * rlist[88] + n * rlist[99])
xor = pow(rlist[114], rlist[514], rlist[233] * rlist[223])
flag = long_to_bytes(int((enc - add)^^xor))
if b'SCTF' in flag:
print(flag)
Math forbidden
from Crypto.Util.number import *
from Crypto.Cipher import AES
import os
from flag import flag
secret = os.urandom(16)*2
sysKEY = os.urandom(8)
aeskey = os.urandom(16)
iv = os.urandom(16)
p = getPrime(256)
q = getPrime(256)
e = 0x10001
d = inverse(e,(p-1)*(q-1))
n = p*q
def aes_enc(m,key,iv):
aes = AES.new(key,AES.MODE_CBC,iv)
c = aes.encrypt(m)
return c
def aes_dec(c,key,iv):
aes = AES.new(key,AES.MODE_CBC,iv)
m = aes.decrypt(c)
return m
def add_to_16(key):
padding = 16 - (len(key) % 16)
key += bytes([padding])*padding
return(key)
def unpadding(key):
padding = key[-1]
if(padding==0):
return key,False
for i in range(padding):
if key[-i-1]!=padding:
return key,False
key = key[:-padding]
return key,True
def check_token():
print("input your token")
print("key")
print(">",end='')
enc_key = input()
print("IV")
print(">",end='')
iv = input()
enc_key = bytes.fromhex(enc_key)
iv = bytes.fromhex(iv)
key_padding = aes_dec(enc_key,aeskey,iv)
dec_key,flag= unpadding(key_padding)
if(flag==False):
print("fake token")
else:
if(dec_key == sysKEY):
print("0.0")
print('N',hex(n))
print('E',hex(e))
print('c',pow(bytes_to_long(secret),e,n))
else:
print("0.0??")
def adminadmin():
print("input n:")
print(">",end='')
n = input()
print("input c:")
print(">",end='')
c = input()
n = bytes.fromhex(n)
c = bytes.fromhex(c)
n = bytes_to_long(n)
c = bytes_to_long(c)
secret = pow(c,d,n)
print("only admin can touch the answer[yes/no]")
op1 = input()
if(op1=='yes'):
print("input admin password:")
print(">",end='')
password = input()
adminKEY = bytes.fromhex(password)
if adminKEY==sysKEY:
m = long_to_bytes(secret,64)
print(m[:2].hex())
key_padding = add_to_16(sysKEY)
enc_key = aes_enc(key_padding,aeskey,iv)
print('your token',enc_key.hex(),iv.hex())
menu = """
1.check
2.admin
3.getflag
"""
while 1:
print(menu)
print(">",end='')
op = input()
if(op=='1'):
check_token()
continue
if(op=='2'):
adminadmin()
continue
if(op=='3'):
print("oops! I forget to hide the backdoor!\n>",end='')
tmp = bytes.fromhex(input())
if(tmp==secret):
print(flag)
continue
print("try again")
考点:CBC Padding Oracle && MSB Oracle Attack
SCTF 2023 Writeup - 星盟安全团队 (xmcve.com)
[SCTF 2023] 小部分_石氏是时试的博客-CSDN博客
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1666739907@qq.com