2023 CryptoCTF wp by lingfeng (easy分类)

想说的一些话,第一次打CryptoCTF,比赛的时候时间不够,就做了六七个题,没通宵干,最近没啥事,终于复现完了,不愧是CryptoCTF,收获很多,关于椭圆曲线和丢番图的知识学到了不少,希望下次Crypto争取做出来一半。
下面是本次比赛easy分类的个人题解,其他几个分类的会后续更新,在肝了在肝了(╰(°▽°)╯).

Easy

DId it(220 sloves)

附件代码

# !/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

Suction(151 solves)

附件代码

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师傅),学到了学到了,贴一个学习地址。

Blue Office(181 solves)

附件代码

!/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}) GF224上进行,结果和加密过程也是不变的,既然如此,我们可以对加密过程加上个 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_!!}'
结束语

努力和收获,都是自己的,与他人无关。最大的成就感,就是一直在朝着自己想要的方向前进。
共勉!
未完待续~~~~

你可能感兴趣的:(CryptoCTF,python,密码学)