[CryptoCTF 2023] 部分简单题

这个网站居然家里的宽带上不去。群里下了附件,作了几个小题。这比赛全部是密码题,相当高级的比赛。

Blue_office

一个LNG的题,通过一个种子生成d然后用d的第2字节异或加密

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)}')

由于flag的头部是已知的,可以用这个头部算出种子

enc = bytes.fromhex('b0cb631639f8a5ab20ff7385926383f89a71bbc4ed2d57142e05f39d434fce')

plan = b'CCTF{'

from z3 import *

s = Solver()
d = BitVec('d', 32)

for i in range(5):
    d = d*214013+2531011
    s.add((d>>16) &0xff == enc[i]^plan[i])

s.check()
s.model()

#10364460

然后用这个种子去解密

m = []
d = 10364460
for i in range(len(enc)):
    d = d*214013+2531011
    m.append(enc[i]^((d>>16) &0xff))

bytes(m)
#CCTF{__B4ck_0r!F1c3__C1pHeR_!!}

开头几题很简单,还是可以应夫的。

DID

这是个有远端的题,在128个数字里去掉20个,每次输入最多20个数字可以返回i^2+randint(0,1)

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

由于最后对结果取模并加了误差,导致不同的数字会出现相同的结果,所以要想办法把这些数字合理分组,在同一组中不存在有误解的项。这里用个小程序处理一下:

n=127

a = [[] for i in range(127)]
for i in range(127):
    a[i*i%n].append(i)
    a[i*i%n+1].append(i)

#[len(a[i]) for i in range(127)]
#从最大长度里取值
K = []
for _ in range(7):
    tmp = []
    used = []
    while len(tmp)<20:
        l = max([len(a[i]) for i in range(127) if i not in used])
        if l == 0:
            break
        for i in range(127):
            if len(a[i]) == l and i not in used:
                v = a[i].pop()
                tmp.append(v)
                used.append(v*v%n)
                used.append(v*v%n+1)
                for j in range(127):
                    if v in a[j]:
                        a[j] = [ii for ii in a[j] if ii != v]
                break 
    
    #K.append(','.join([str(i) for i in tmp]))
    K.append([i for i in tmp])

print(K)

for v in K:
    t = eval('['+v+']')
    s = []
    for i in t:
        s.append(i*i%n)
        s.append(i*i%n+1)
    print(len(s),s)

把这个结果提交上去,并逐个判断是否在集合里即可。

from pwn import *


p = remote('00.cr.yp.toc.tf', 11337)
context.log_level = 'debug'

p.recvline()
p.recvline()
p.recvline()

n = 127
KP = [[126,124,123,115,107,104,122,86,83,110,121,75,114,120,106,76,113,109,96,94], 
[118,77,112,117,105,116,111,95,74,79,99,91,64,65,66,101,80,69,103,84], 
[70,92,71,90,72,82,73,1,125,32,97,93,53,12,48,28,36,44,62,17], 
[52,26,67,89,47,68,51,119,24,18,43,33,87,98,35,81,56,100,37,55], 
[108,85,78,102,45,54,88,0,16,2,3,30,34,4,20,23,5,41,63,6], 
[61,13,60,38,7,59,21,58,8,14,31,57,40,29,9,46,50,27,15,10], 
[22,19,42,49,25,11,39]]

K = []
for kk in KP:
    p.sendline(','.join(map(str, kk)).encode())
    p.recvuntil(b'DID = ')
    v = eval(p.recvline().strip().decode())
    for tk in kk:
        r = tk*tk%n
        if (r not in v) and (r+1 not in v):
            K.append(str(tk))
    
    print('K = ', K)    
    if len(K) == 20:
        break

p.sendline((','.join(K)).encode())
print(p.recvline())
#CCTF{W4rM_Up_CrYpt0_Ch4Ll3n9e!!}

虽然网站上不了,但是这些题目还能用,真良心

suction

一个rsa的题目,但n,e,c都少了8位,由于n非常小,可以分解,大功率爆破

#!/usr/bin/env python3

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)}')

先过滤一下,一共得到9个n

from Crypto.Util.number import *

PKEY = 55208723145458976481271800608918815438075571763947979755496510859604544396672
ENC = 127194641882350916936065994389482700479720132804140137082316257506737630761

#部分nec 
hn = int(bin(PKEY)[2:-8],2)<<8
he = int(bin(PKEY)[-8:],2)<<8
hc = ENC<<8


#可能的n
plist = [3]
for i in range(100000):
    plist.append(next_prime(plist[-1]))

for i in range(1,256,2):
    tn = hn+i
    for v in plist:
        if tn%v == 0:
            break 
    else:
        if not isPrime(tn):
            print(tn)

'''
分解,得到p,q都约128位
55208723145458976481271800608918815438075571763947979755496510859604544396571
55208723145458976481271800608918815438075571763947979755496510859604544396577
55208723145458976481271800608918815438075571763947979755496510859604544396583
55208723145458976481271800608918815438075571763947979755496510859604544396589
55208723145458976481271800608918815438075571763947979755496510859604544396603
55208723145458976481271800608918815438075571763947979755496510859604544396613
55208723145458976481271800608918815438075571763947979755496510859604544396633
55208723145458976481271800608918815438075571763947979755496510859604544396643
55208723145458976481271800608918815438075571763947979755496510859604544396667
'''

然后用yafu分解,得到正确的 n

n = 55208723145458976481271800608918815438075571763947979755496510859604544396613
p = 292926085409388790329114797826820624883
q = 188473222069998143349386719941755726311
phi = (p-1)*(q-1)

#可能的e
for j in range(1,256,2):
    e = he+j
    if isPrime(e):
        d = invert(e, phi)
        for i in range(256): #可能的c
            c = hc+i 
            m = pow(c,d,n)
            m = long_to_bytes(m)
            if all([1 if v<0x7f else 0 for v in m]):
                print(m)

#CCTF{6oRYGy&Dc$G2ZS}

ASIv1

题目用3进制生成矩阵和flag的积,3进制这东西还真不常见。不过与难度无关。

#!/usr/bin/env python3

from Crypto.Util.number import *
from flag import flag

def base(n, l):
    D = []
    while n > 0:
        n, r = divmod(n, l)
        D.append(r)
    return ''.join(str(d) for d in reversed(D)) or '0'

def asiv_prng(seed):
	l = len(seed)
	_seed = base(bytes_to_long(seed), 3)
	_seed = [int(_) for _ in _seed]
	_l = len(_seed)
	R = [[getRandomRange(0, 3) for _ in range(_l)] for _ in range(_l**2)]
	S = []
	for r in R:
		s = 0
		for _ in range(_l):
			s += (r[_] * _seed[_]) % 3
		# s += getRandomRange(0, 3)
		s %= 3
		S.append(s)
	return R, S

seed = flag.lstrip(b'CCTF{').rstrip(b'}')
R, S = asiv_prng(seed)

f = open('output.txt', 'w')
f.write(f'R = {R}\nS = {S}')
f.close()

直接解右即可。

from output import *

MR = matrix(GF(3), R)
MS = matrix(GF(3),12100,1, S)

a = MR.solve_right(MS)
flag = ''.join([str(a[i,0]) for i in range(110)])
#'12200101122112210002110212001112001011210012200110200221111110001002012120200110211202001221221020201121010111'
bytes.fromhex(hex(int(flag,3))[2:])
b'3Xpl0i7eD_bY_AtT4ck3r!'

#CCTF{3Xpl0i7eD_bY_AtT4ck3r!}

Barak 

看上去是个椭圆方程,但y是3次的,这就不会了,结束两天就找到WP

#!/usr/bin/env sage

from Crypto.Util.number import *
from flag import flag

def on_barak(P, E):
	c, d, p = E
	x, y = P
	return (x**3 + y**3 + c - d*x*y) % p == 0

def add_barak(P, Q, E):
	if P == (0, 0):
		return Q
	if Q == (0, 0):
		return P
	assert on_barak(P, E) and on_barak(Q, E)
	x1, y1 = P
	x2, y2 = Q
	if P == Q:
		x3 = y1 * (c - x1**3) * inverse(x1**3 - y1**3, p) % p
		y3 = x1 * (y1**3 - c) * inverse(x1**3 - y1**3, p) % p
	else:

		x3 = (y1**2*x2 - y2**2*x1) * inverse(x2*y2 - x1*y1, p) % p
		y3 = (x1**2*y2 - x2**2*y1) * inverse(x2*y2 - x1*y1, p) % p
	return (x3, y3)

def mul_barak(m, P, E):
	if P == (0, 0):
		return P
	R = (0, 0)
	while m != 0:
		if m & 1:
			R = add_barak(R, P, E)
		m = m >> 1
		if m != 0:
			P = add_barak(P, P, E)
	return R

def rand_barak(E):
	c, d, p = E
	while True:
		y = randint(1, p - 1)
		K = Zmod(p)
		P.<x> = PolynomialRing(K) 
		f = x**3 - d*x*y + c + y^3
		R = f.roots()
		try:
			r = R[0][0]
			return (r, y)
		except:
			continue

p = 73997272456239171124655017039956026551127725934222347
d = 68212800478915688445169020404812347140341674954375635
c = 1
E = (c, d, p)

P = rand_barak(E)

FLAG = flag.lstrip(b'CCTF{').rstrip(b'}')
m = bytes_to_long(FLAG) 
assert m < p
Q = mul_barak(m, P, E)
print(f'P = {P}')
print(f'Q = {Q}')

又一个新东西 Hessian Curve,与椭圆曲线类似

x^3 + y^3 +c - Dxy =0 mod p

这里边的秩比较麻烦,要转成椭圆方程求。求的方法是之样。

p = 73997272456239171124655017039956026551127725934222347
G = GF(p)
d = G(68212800478915688445169020404812347140341674954375635)
D = d/3
c = 1
# Hessian Curve:
# x³ + y³ + 1 = 3Dxy

# Weierstrass equivalent
a = -27*D*(D^3 + 8)
b = 54*(D^6 - 20*D^3 - 8)
E2 = EllipticCurve(G, [a, b])
print(E2)
# Elliptic Curve defined by y^2 = x^3 + 44905983883632632311912975168565494049729462391119290*x + 4053170785171018449128623853386306889464200866918538 over Finite Field of size 73997272456239171124655017039956026551127725934222347

order = E2.order()
# 73997272456239171124655016995459084401465136460086688

然后生成这条曲线,并且根据秩的分解求出使P*n == O(0,0)的n

class HessianPoint:
    def __init__(self, x, y):
        self.x = G(x)
        self.y = G(y)

        assert (x, y) == (0, 0) or x^3 + y^3 + c - d*x*y == 0

    def __eq__(P, Q):
        return (P.x, P.y) == (Q.x, Q.y)

    def __add__(P, Q):
        if (P.x, P.y) == (0, 0):
            return Q
        if (Q.x, Q.y) == (0, 0):
            return P
        if (P.x, P.y) == (Q.y, Q.x):
            return HessianPoint(0, 0)

        x1, y1 = P.x, P.y
        x2, y2 = Q.x, Q.y
        if P == Q:
            x3 = y1 * (c - x1^3) / (x1^3 - y1^3)
            y3 = x1 * (y1^3 - c) / (x1^3 - y1^3)
        else:
            x3 = (y1^2*x2 - y2^2*x1) / (x2*y2 - x1*y1)
            y3 = (x1^2*y2 - x2^2*y1) / (x2*y2 - x1*y1)
        return HessianPoint(x3, y3)

    def __mul__(P, m):
        if (P.x, P.y) == (0, 0):
            return P
        R = HessianPoint(0, 0)
        while m != 0:
            if m & 1:
                R = P + R
            m = m >> 1
            if m != 0:
                P = P + P
        return R

    def __neg__(self):
        return HessianPoint(self.y, self.x)

    def __rmul__(P, m):
        return P*m

    def __repr__(self):
        return f"({self.x}, {self.y})"

    def __hash__(self):
        return hash((self.x, self.y))
        
P = HessianPoint(71451574057642615329217496196104648829170714086074852, 69505051165402823276701818777271117086632959198597714)
Q = HessianPoint(40867727924496334272422180051448163594354522440089644, 56052452825146620306694006054673427761687498088402245)
O = HessianPoint(0, 0)

for k in order.divisors():
    if P * k == O:
        break
n = k
# 3083219685676632130193959041477461850061047352503612

 然后用Pohlig-Hellman方法求私钥

def baby_step_giant_step(P, Q, order):
    """
    Résoud P·x = Q pour x entre 0 et order-1
    """

    m = isqrt(order)
    #   x = am + b
    # ⇒ Q = P*(am + b)
    # ⇒ P*(am) = Q+P*(-b)

    memory = {}
    # On y stocke toutes les valeurs possibles de P*(am),
    # associées à leur valeur de `a` respective.
    M = O
    S = P*m # giant step

    for a in range(m):
        # M = P*(am)
        memory[M] = a
        M += S

    b = 0
    M = Q
    S = -P # baby step

    while M not in memory:
        # M = Q+P*(-b)
        b += 1
        M += S

    a = memory[M]
    x = a*m + b
    assert P * x == Q
    return x

factors = n.factor()
p = [factor[0] for factor in factors]
e = [factor[1] for factor in factors]

crt_a = []
crt_b = []
for i in range(len(p)):
    pi = p[i]
    ei = e[i]
    P0 = (n // (pi^ei)) * P
    Q0 = (n // (pi^ei)) * Q
    k = baby_step_giant_step(P0, Q0, pi^ei)
    crt_a.append(k)
    crt_b.append(pi^ei)
    print(f"m = {k} mod {pi^ei}")
# m = 1 mod 4
# m = 1 mod 9
# m = 13 mod 17
# m = 1489 mod 2341
# m = 18879 mod 23497
# m = 339241 mod 500369
# m = 4831116 mod 5867327
# m = 31953114 mod 33510311
# m = 10804270204 mod 13824276503
# m = 57315765050 mod 67342255597

m = CRT(crt_a, crt_b)
# 1780694557271320552511299360138314441283923223949197
assert P * m == Q

 这个值比真正的m小,要加模爆破一下,原文就是这样,存在这里,以便不时之需。

p = 73997272456239171124655017039956026551127725934222347
while m < p:
    flag = long_to_bytes(m)
    try:
        print('CCTF{' + flag.decode() + '}')
    except ValueError:
        pass
    m += n

# CCTF{_hE5S!4n_f0rM_0F_3CC!!}

Derik

这题多少有点猜的成分

#!/usr/bin/env python3

from Crypto.Util.number import *
from secret import C, e, d, p, q, r, flag

O = [1391526622949983, 2848691279889518, 89200900157319, 31337]

assert isPrime(e) and isPrime(d) and isPrime(p) and isPrime(q) and isPrime(r)
assert C[0] * p - C[1] * q >= 0
assert C[2] * q - C[3] * r >= 0
assert C[4] * r - C[5] * p >= 0
assert (C[0] * p - C[1] * q) ** e + (C[2] * q - C[3] * r) ** e + (C[4] * r - C[5] * p) ** e == d * (C[0] * p - C[1] * q) * (C[2] * q - C[3] * r) * (C[4] * r - C[5] * p)
assert C[6] * e - C[7] * d == O[3]

n = e * d * p * q * r
m = bytes_to_long(flag)
c = pow(m, 65537, n)
print(f'C = {C}')
print(f'c = {c}')

给了参数集,结果集,但从题面上并没有说O[:3]是干什么用的。所以猜是与前3个assert对应的。通过4个O得到全部参数,难点就在猜这一下。

C = [5960650533801939766973431801711817334521794480800845853788489396583576739362531091881299990317357532712965991685855356736023156123272639095501827949743772, 6521307334196962312588683933194431457121496634106944587943458360009084052009954473233805656430247044180398241991916007097053259167347016989949709567530079, 1974144590530162761749719653512492399674271448426179161347522113979158665904709425021321314572814344781742306475435350045259668002944094011342611452228289, 2613994669316609213059728351496129310385706729636898358367479603483933513667486946164472738443484347294444234222189837370548518512002145671578950835894451, 8127380985210701021743355783483366664759506587061015828343032669060653534242331741280215982865084745259496501567264419306697788067646135512747952351628613, 5610271406291656026350079703507496574797593266125358942992954619413518379131260031910808827754539354830563482514244310277292686031300804846114623378588204, 10543, 4]
c = 80607532565510116966388633842290576008441185412513199071132245517888982730482694498575603226192340250444218146275844981580541820190393565327655055810841864715587561905777565790204415381897361016717820490400344469662479972681922265843907711283466105388820804099348169127917445858990935539611525002789966360469324052731259957798534960845391898385316664884009395500706952606508518095360995300436595374193777531503846662413864377535617876584843281151030183895735511854
O = [1391526622949983, 2848691279889518, 89200900157319, 31337]

from Crypto.Util.number import *
#C[6] * e - C[7] * d == O[3]
for e in range(2, 0x1000000):
    if isPrime(e):
        d7 = 10543*e - 31337
        if d7%4 == 0 and isPrime(d7//4):
            print(e, d7//4)

e,dd = 3,73

from z3 import *
p,q,r = Ints('p q r')

s = Solver()
s.add(p>0)
s.add(q>0)
s.add(r>0)

s.add(C[0] * p - C[1] * q  == O[0])
s.add(C[2] * q - C[3] * r  == O[1])
s.add(C[4] * r - C[5] * p  == O[2])
s.add((C[0] * p - C[1] * q) ** e + (C[2] * q - C[3] * r) ** e + (C[4] * r - C[5] * p) ** e == dd * (C[0] * p - C[1] * q) * (C[2] * q - C[3] * r) * (C[4] * r - C[5] * p))

s.check()
s.model()
r = 6736304432663651651650099104581016800112378771266600017972326085742513966258250417227421932482058281545032658577816441378170466639375931780967727070265551
p = 9758621034843917661145412977193922808892309951663464821517963113005483457886774294910761723767526582514514505278091600074371768233672585649562672245905811
q = 8919642442779618620315315582249815126044061421894622037450496385178083791083142991676417756698881509754110765444929271564991855378540939292428839562446571

d = inverse(65537, p-1)
long_to_bytes(pow(c, d, p))
#CCTF{____Sylvester____tHE0r3m_Of_D3r!va7i0n!}

Insights

题目给了n,e,c和p,q的一小点,这一点是求出不啥来的。不过给出了d = next_prime(pow(n, 0.2919))

#!/usr/bin/env sage

from Crypto.Util.number import *
from flag import flag

def getRandomNBits(n):
	nb = '1' + ''.join([str(randint(0, 1)) for _ in range(n - 1)])
	return nb

def getLeader(L, n):
	nb = L + getRandomNBits(n)
	return int(nb, 2)

def genPrime(L, nbit):
	l = len(L)
	assert nbit >= l
	while True:
		p = getLeader(L, nbit - l)
		if is_prime(p):
			return p

def genKey(L, nbit):
	p, q = [genPrime(L, nbit) for _ in '__']
	n = p * q
	d = next_prime(pow(n, 0.2919))
	phi = (p - 1) * (q - 1)
	e = inverse(d, phi)
	pubkey, privkey = (n, e), (p, q)
	return pubkey, privkey

def encrypt(msg, pubkey):
	n, e = pubkey
	m = bytes_to_long(msg)
	c = pow(m, e, n)
	return c

nbit = 1024
L = bin(bytes_to_long(b'Practical'))[2:]
pubkey, privkey = genKey(L, nbit)
p, q = privkey
c = encrypt(flag, pubkey)

print('Information:')
print('-' * 85)
print(f'n = {p * q}')
print(f'e = {pubkey[1]}')
print(f'c = {c}')
print(f'p = {bin(p)[2:len(L)]}...[REDACTED]')
print(f'q = {bin(q)[2:len(L)]}...[REDACTED]')
print('-' * 85)

有d就可以直接解密了

#sage
d = next_prime(pow(n, 0.2919))
m = pow(c,d,n)
long_to_bytes(int(m))
#CCTF{RSA_N3w_rEc0rd5_4Nd_nEw_!nSi9h75!}

Keymoted

椭圆方程,模是p*q,并且q是p异或两位得到的。

#!/usr/bin/env sage

from Crypto.Util.number import *
from flag import flag

def gen_koymoted(nbit):
	p = getPrime(nbit)
	a, b = [randint(1, p - 1) for _ in '__']
	Ep = EllipticCurve(GF(p), [a, b])
	tp = p + 1 - Ep.order()
	_s = p ^^ ((2 ** (nbit - 1)) + 2 ** (nbit // 2))
	q = next_prime(2 * _s + 1)
	Eq = EllipticCurve(GF(q), [a, b])
	n = p * q
	tq = q + 1 - Eq.order()
	e = 65537
	while True:
		if gcd(e, (p**2 - tp**2) * (q**2 - tq**2)) == 1:
			break
		else:
			e = next_prime(e)
	pkey, skey = (n, e, a, b), (p, q)
	return pkey, skey

def encrypt(msg, pkey, skey):
	n, e, a, b = pkey
	p, q = skey
	m = bytes_to_long(msg)
	assert m < n
	while True:
		xp = (m**3 + a*m + b) % p
		xq = (m**3 + a*m + b) % q
		if pow(xp, (p-1)//2, p) == pow(xq, (q-1)//2, q) == 1:
			break
		else:
			m += 1
	eq1, eq2 = Mod(xp, p), Mod(xq, q)
	rp, rq = sqrt(eq1), sqrt(eq2)
	_, x, y = xgcd(p, q)
	Z = Zmod(n)
	x = (Z(rp) * Z(q) * Z(y) + Z(rq) * Z(p) * Z(x)) % n
	E = EllipticCurve(Z, [a, b])
	P = E(m, x)
	enc = e * P
	return enc

nbit = 256
pkey, skey = gen_koymoted(nbit)
enc = encrypt(flag, pkey, skey)

print(f'pkey = {pkey}')
print(f'enc = {enc}')

两位异或只有4种情况,直接用z3求解

pkey = (6660938713055850877314255610895820875305739186102790477966786501810416821294442374977193379731704125177528590285016474818841859956990486067573436301232301, 65537, 5539256645640498184116966196249666621079506508209770360679460869295427007578, 20151017657582479433586370393795140515103572865771721775868586710594524816458)
enc = (6641320679869421443758875467781930795132746694454926965779628505713445486895274490835545942727970688359873955019634877304270220728625521646208912044469433,2856872654927815636828860866843721158889474116106462420201092148493803550131351543372740950198853438539317164093538508795630146854596724019329887894933972,1)
nbit = 256
n,e,a,b = pkey 


from z3 import *


k1 = 2 ** (nbit - 1)
k2 = 2 ** (nbit // 2)
for i in range(0,2000,2):
    print(i)
    s= Solver()
    p = BitVec('p', 256)
    q = 2*(p+k1+k2)+1+i     #4种情况 第1种情况i=2有解
    s.add(p*q == n)
    if s.check() == sat:
        tp = s.model()[p].as_long()
        if n%tp == 0:
            print(tp)
        

p = 93511613846272978051774379195449772332692693333173612296021789501865098047641    
q = 71231138455229760679977773382211636812795966734548537479512744210680602878261

解出p,q来以后,椭圆这块就好办了。这里由于m作了几次加1,导致最后一个字符有点误差.

这里的椭圆方程是已知m*G 和 m 求G ,师傅提示类似于RSA,用mG*invert(m,E.order())乘就能得到G。

p = 93511613846272978051774379195449772332692693333173612296021789501865098047641    
q = 71231138455229760679977773382211636812795966734548537479512744210680602878261

Ep =  EllipticCurve(GF(p), [a, b])
po = Ep.order()

Eq =  EllipticCurve(GF(q), [a, b])
qo = Eq.order()

Qp = Ep((enc[0], enc[1]))
Qq = Eq((enc[0], enc[1]))
dp = inverse_mod(65537, po)
dq = inverse_mod(65537, qo)

Pp = Qp*dp 
Pq = Qq*dq 

mp = Pp[0]
mq = Pq[0]

m = crt([int(mp),int(mq)],[p,q])
long_to_bytes(m)
#'CCTF{a_n3W_4t7aCk_0n_RSA_a9ain!?\x82

Trex

这题没找着远端,不过应该没啥问题

#!/usr/bin/env python3

import random
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 check_inputs(a, b, c):
	if not all(isinstance(x, int) for x in [a, b, c]):
		return False
	if a == 0 or b == 0 or c == 0:
		return False
	if a == b or b == c or a == c:
		return False
	return True

def check_solution(a, x, y, z):
	return (x*x + y*y - x*y - a*(z**3)) == 0

def main():
	border = "|"
	pr(border*72)
	pr(border, ".::   Hi all, she DID it, you should do it too! Are you ready? ::.  ", border)
	pr(border, "Welcome to the Ternary World! You need to pass each level until 20  ", border)
	pr(border, "to get the flag. Pay attention that your solutions should be nonzero", border)
	pr(border, "distinct integers. Let's start!                                     ", border)
	pr(border*72)

	level, step = 0, 19
	while level <= step:
		a = random.randint(2**(level * 12), 2**(level*12 + 12))
		equation = f'x^2 + y^2 - xy = {a}*z^3'
		pr(f"Level {level + 1}: {equation}")
		inputs = input().strip().split(",")
		try:
			x, y, z = map(int, inputs)
		except:
			die(border, "Invalid input, Bye!!")
		if check_inputs(x, y, z):
			if check_solution(a, x, y, z):
				pr(border, "Correct! Try the next level :)")
				level += 1
			else:
				pr(border, "You didn't provide the correct solution.")
				die(border, "Better luck next time!")			
		else:
			pr(border, "Your solutions should be non-zero distinct integers")
			die(border, "Quiting...")
		if level == step:
			pr(border, "Congratulations! You've successfully solved all the equations!")
			die(border, f"flag: {flag}")

if __name__ == '__main__':
	main()

核心问题就是一个公式,每次生成a,然后要求输入x,y,z满足公式。

x^2 + y^2 - x*y = a*z^3

这里如果z=k*a的话,x,y都是k*a^2这样就可以把a^4约掉,所以这个式子就与a无关了,也就与关卡设置的难度无关了。只需要求出

k1^2 +k2^2 - k1*k2 = k3^3

先假设k1==1爆破一下,得到1,19,7

for i in range(2, 0x10000000):
    if iroot(1+i*i-i,3)[1]:
        print(i)
x = a**2 
y = 19*a**2 
z = 7*a

还有好多没仔细看,估计后边的都不会了,等WP

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值