# !/usr/bin/env python3
from random import randint
import sys
from flag import flag
def die(*args):
pr(*args)
quit()
def pr(*args):
s = " ".join(map(str, args))
sys.stdout.write(s + "\n")
sys.stdout.flush()
def sc():
return sys.stdin.buffer.readline()
def did(n, l, K, A):
A, K = set(A), set(K)
R = [pow(_, 2, n) + randint(0, 1) for _ in A - K]
return R
def main():
border = "+"
pr(border * 72)
pr(border, ".:: Hi all, she DID it, you should do it too! Are you ready? ::. ", border)
pr(border * 72)
_flag = False
n, l = 127, 20
N = set(list(range(0, n)))
K = [randint(0, n - 1) for _ in range(l)]
cnt, STEP = 0, 2 * n // l - 1
while True:
ans = sc().decode().strip()
try:
_A = [int(_) for _ in ans.split(',')]
if len(_A) <= l and set(_A).issubset(N):
DID = did(n, l, K, _A)
pr(border, f'DID = {DID}')
if set(_A) == set(K):
_flag = True
else:
die(border, 'Exception! Bye!!')
except:
die(border, 'Your input is not valid! Bye!!')
if _flag:
die(border, f'Congrats! the flag: {flag}')
if cnt > STEP:
die(border, f'Too many tries, bye!')
cnt += 1
if __name__ == '__main__':
main()
这个题是解出最多的题,但是如果轮难度的话,我认为他比另外两个easy的题更难一点,只是因为它是由服务器交互的,每次生成随机数据,导致有很大的拼人品的成分(我也是人品手)
服务器会每次生成一组范围在(0~126)的20个随机数,然后我们向服务器发送我们猜测的一组数据进行比对,服务器会将我们我们猜测得数据中错误的数据进行加密后进行发送过来,我们一共有13次机会,只需要在第十三次之前将这组数据猜测出来即可。
def did(n, l, K, A):
A, K = set(A), set(K)
R = [pow(_, 2, n) + randint(0, 1) for _ in A - K]
return R
代码很短,很好理解。
既然有十三次机会,那就尽可能的用完所有机会。
首先将随机数范围内的所有数都作为错误数据加密,包括错误数据加密中混淆产生的0或1,
全部保存下来
前十二次机会作为试错机会,将着127个数分为12组,(下面在我的代码中,我分为了10组,组数越大,成功概率越大)
依次向服务器发送一组数据,然后将返回的错误数据进行与我们保存下来的加密数据进行对比,如果对比成功,那很大概率,这个数据就是猜测错误的数据,可以进行排除掉
十二次机会用完后,大部分的错误数据已经排除了,剩下的大概率就是正确的数据,但是不能打包票,(概率问题)
此时就可以要求这个排除下来的数据需要是20个,刚好与服务器生成的20个数对应,如果排出后不是20个,那就很明显,中间我们的排除出错了,重新来过就好了,这是就需要一个While循环。不断重复,知道猜测的答案正确为止,我用10组的机会,大概需要循环来连接几十次就好
(就算排除后的数据是20个,也有可能不是正确的)
from pwn import *
from tqdm import *
while True:
r=remote("00.cr.yp.toc.tf" ,11337)
r.recvline()
r.recvline()
r.recvline()
n, l = 127, 20
N = set(list(range(0, n)))
x=[]
for k in trange(9):
a=list(range(13*k,13*(k+1)))
A1=[pow(i, 2, n)for i in a]
A2=[pow(i,2,n)+1for i in a]
r.sendline(str(a)[1:-1].encode())
r.recvuntil(b'=')
b=eval(r.recvline(keepends=False).decode())
for i in range(len(b)):
if b[i] in A1 :
t1=A1.index(b[i])
A1[t1]=-1
A2[t1]=-1
x.append(13*k+t1)
elif b[i] in A2 :
t1=A2.index(b[i])
A1[t1] = -1
A2[t1] = -1
x.append(13*k+t1)
a=list(range(13*9,127))
A1=[pow(i, 2, n)for i in a]
A2=[pow(i,2,n)+1for i in a]
r.sendline(str(a)[1:-1].encode())
r.recvuntil(b'=')
b=eval(r.recvline(keepends=False).decode())
for i in range(len(b)):
if b[i] in A1 :
t1 = A1.index(b[i])
A1[t1] = -1
A2[t1] = -1
x.append(13 * 9 + t1 )
elif b[i] in A2 :
t1 = A2.index(b[i])
A1[t1] = -1
A2[t1] = -1
x.append(13 * 9 + t1 )
T=list(N-set(x))
# print(N-set(x))
print(len(T))
if len(T)!=20:
r.close()
continue
r.sendline(str(T[len(T)-20:])[1:-1].encode())
# r.interactive()
m= r.recvline()
print(m)
if b'[]' not in m:
r.close()
continue
flag=r.recvline()
print(flag)#CCTF{W4rM_Up_CrYpt0_Ch4Ll3n9e!!}
break
from Crypto.Util.number import *
from flag import flag
def keygen(nbit, r):
while True:
p, q = [getPrime(nbit) for _ in '__']
e, n = getPrime(16), p * q
phi = (p - 1) * (q - 1)
if GCD(e, phi) == 1:
N = bin(n)[2:-r]
E = bin(e)[2:-r]
PKEY = N + E
pkey = (n, e)
return PKEY, pkey
def encrypt(msg, pkey, r):
m = bytes_to_long(msg)
n, e = pkey
c = pow(m, e, n)
C = bin(c)[2:-r]
return C
r, nbit = 8, 128
PKEY, pkey = keygen(nbit, r)
print(f'PKEY = {int(PKEY, 2)}')
FLAG = flag.lstrip(b'CCTF{').rstrip(b'}')
enc = encrypt(FLAG, pkey, r)
print(f'enc = {int(enc, 2)}')
这个题是一个RSA加密问题,所用的公钥比特数都很小,只有128BIT,是可以通过sage进行分解素因子的
不正常的RSA,题目生成128bit为两个素数作为p,q,16bit的素数作为e,将公钥(n,e)的高位输出,只有低8位没有,然后经过rsa加密后,再次将C的高位输出,也是低八位没有。
对于这种只有8位未知的数据,是在计算机的可爆破之内的,
对于e,我们知道的条件是,e是一个16bit的素数。
对于n,我们知道的是n不是一个素数,并且n可以分解为两个大素因子,大素因子
由着两个条件进行限制,我们划小n,e可能的范围,然后通过这个范围进行对c的解密(c也是爆破)
from Crypto.Util.number import *
from tqdm import *
from Crypto.Util.number import *
PKEY = 55208723145458976481271800608918815438075571763947979755496510859604544396672
ENC = 127194641882350916936065994389482700479720132804140137082316257506737630761
C=ENC<<8
N_=int(bin(PKEY)[2:-8],2)<<8
E_=int(bin(PKEY)[-8:],2)<<8
x=sieve_base#调用前一万个素数
n=[]
for i in trange(0,255):
N=N_+i
if N%2==0 or isPrime(N):
continue
t=[N%a for a in x]
if 0 in t:
continue
n.append(N)
print(n)
for i in trange(len(n)):
print(factor(n[i]))
#188473222069998143349386719941755726311 * 292926085409388790329114797826820624883
p =292926085409388790329114797826820624883
q = 188473222069998143349386719941755726311
phi=(p-1)*(q-1)
e=[E_+i if isPrime(E_+i) else None for i in range(255)]
# for i in trange(0,255):
# E=E_+i
# if isPrime(E)==0 or gcd(E,phi)!=1:
# continue
# e.append(E)
c=[C+i i for i in range(255)]
n=p*q
for e0 in tqdm(e):
try:
d=inverse(e0,phi)
for c0 in c:
m= pow(c0,d,n)
flag=long_to_bytes(int(m))
if len(str(flag))<=65:
print(flag)
#6oRYGy&Dc$G2ZS
except:continue
对于这种方法,大概需要十几分钟,能够完成对于公钥n的分解,找到正确的p,q。
在和@3tefanie丶zhou的学习中学到一种更好的方法,调用factor网站api进行n的排除查找,只需要一分半就可以找到,好方法(3tefanie丶zhou师傅),学到了学到了,贴一个学习地址。
!/usr/bin/enc python3
import binascii
from secret import seed, flag
def gen_seed(s):
i, j, k = 0, len(s), 0
while i < j:
k = k + ord(s[i])
i += 1
i = 0
while i < j:
if (i % 2) != 0:
k = k - (ord(s[i]) * (j - i + 1))
else:
k = k + (ord(s[i]) * (j - i + 1))
k = k % 2147483647
i += 1
k = (k * j) % 2147483647
return k
def reseed(s):
return s * 214013 + 2531011
def encrypt(s, msg):
assert s <= 2**32
c, d = 0, s
enc, l = b'', len(msg)
while c < l:
d = reseed(d)
enc += (msg[c] ^ ((d >> 16) & 0xff)).to_bytes(1, 'big')
c += 1
return enc
enc = encrypt(seed, flag)
print(f'enc = {binascii.hexlify(enc)}')
题目是一个流密码,
生成一个32bit的数作为种子seed,每轮对seed进行线性加密生成新的seed
每次加密将seed的低24bit-低16bit的数据与flag的每一个字节进行异或,返回作为加密数据。
既然每次加密只有seed的低24bit的数据有关,则可以在理解为整个加密系统在 G F ( 2 24 ) GF(2^{24}) GF(224)上进行,结果和加密过程也是不变的,既然如此,我们可以对加密过程加上个 m o d 2 24 mod2^{24} mod224 ,
一个24bit的数据,
并且我们还知道flag格式为CCTF{,
通过这个格式,我们可以获得前5个seed的低24-16bit,也就是说只有低16bit的数据是不知道的
16bit(完全可以通过计算机爆破(成爆破小子了))
为防止爆破出多个结果满足,我们可以再限制经过seed加密生成后的下一个seed低24-16bit满足我们已知的第二个seed的低24-16bit。依次约束两次就行
# !/usr/bin/env python3.10
# -*- coding: utf-8 -*-
import binascii
from tqdm import *
enc = b'b0cb631639f8a5ab20ff7385926383f89a71bbc4ed2d57142e05f39d434fce'
enc=binascii.unhexlify(enc)
flag=b'CCTF{'
d=[flag[i]^enc[i] for i in range(5)]
def reseed(s):
return (s * 214013 + 2531011)&(2**24-1)
def decrypt(d, enc):
c,dec, l = 1,b'C', len(enc)
while c < l:
d = reseed(d)
dec += (enc[c] ^ ((d >> 16) & 0xff)).to_bytes(1, 'big')
c += 1
return dec
d0_,D=d[0]<<16,0
for i in trange(2**16):
d0=d0_+i
d1=reseed(d0)
if d1>>16==d[1]:
d2=reseed(d1)
if d2>>16==d[2]:
d3=reseed(d2)
if d3>>16==d[3]:
D=d0
FLAG=decrypt(D,enc)
print(FLAG)
#b'CCTF{__B4ck_0r!F1c3__C1pHeR_!!}'
努力和收获,都是自己的,与他人无关。最大的成就感,就是一直在朝着自己想要的方向前进。
共勉!
未完待续~~~~