TGCTF2025

AAAAAAAA·真·签到:

1
2
3
4
5
6
7
8
9
10
11
给你flag签个到好了

UGBRC{RI0G!O04_5C3_OVUI_DV_MNTB}

诶,我的flag怎么了????

好像字母对不上了

我的签到怎么办呀,急急急

听说福来阁好像是TGCTF开头的喔

变异的凯撒编码,用前几位对一对就知道变异量是-1,0,1…,并且不对数字生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
list = "UGBRC{RI0G!O04_5C3_OVUI_DV_MNTB}"
def decryptd(encrypted):
decrypted = []
move = -1
for char in encrypted:
if 'A' <= char <= 'Z':
new_char = chr(((ord(char) - 65 + move) % 26) + 65)
decrypted.append(new_char)
else:
decrypted.append(char)
move += 1
return ''.join(decrypted)
print(decryptd(list))
#TGCTF{WO0O!Y04_5R3_GOOD_AT_MOVE}

mm不躲猫猫

多组nc,每两组判断一下是否存在公约数即可找到正确的一组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from Crypto.Util.number import *
def extract_rsa_data(file_path):
n_list = []
c_list = []
current_n = None
current_c = None

with open(file_path, 'rb') as f:
for line in f:
line = line.decode('utf-8').strip()

if line.startswith('[') and line.endswith(']'):
if current_n is not None and current_c is not None:
n_list.append(current_n)
c_list.append(current_c)
current_n = None
current_c = None

elif line.startswith('n ='):
current_n = int(line.split('=')[1].strip())

elif line.startswith('c ='):
current_c = int(line.split('=')[1].strip())

if current_n is not None and current_c is not None:
n_list.append(current_n)
c_list.append(current_c)

return n_list, c_list
n, c = extract_rsa_data('challenge (1).txt')
e = 65537
for i in range(len(n)):
for j in range(len(n)):
if i != j:
t = GCD(n[i], n[j])
if t != 1:
p = t
q = n[i] // p
d = inverse(e, (p-1)*(q-1))
m = pow(c[i], d, n[i])
print(long_to_bytes(m))
#b'TGCTF{ExcePt10n4lY0u_Fl4gF0rY0u_555b0nus}'

tRwSiAns

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from flag import FLAG
from Crypto.Util.number import getPrime, bytes_to_long
import hashlib

def generate_key(bits=512):
p = getPrime(bits)
q = getPrime(bits)
return p * q, 3


def hash(x):
return int(hashlib.md5(str(x).encode()).hexdigest(), 16)


def encrypt(m, n, e):
x1, x2 = 307, 7
c1 = pow(m + hash(x1), e, n)
c2 = pow(m + hash(x2), e, n)
return c1, c2


m = bytes_to_long(FLAG)
n, e = generate_key()
c1, c2 = encrypt(m, n, e)
print(f"n = {n}")
print(f"e = {e}")
print(f"c1 = {c1}")
print(f"c2 = {c2}")

n = 100885785256342169056765112203447042910886647238787490462506364977429519290706204521984596783537199842140535823208433284571495132415960381175163434675775328905396713032321690195499705998621049971024487732085874710868565606249892231863632731481840542506411757024315315311788336796336407286355303887021285839839
e = 3
c1 = 41973910895747673899187679417443865074160589754180118442365040608786257167532976519645413349472355652086604920132172274308809002827286937134629295632868623764934042989648498006706284984313078230848738989331579140105876643369041029438708179499450424414752031366276378743595588425043730563346092854896545408366
c2 = 41973912583926901518444642835111314526720967879172223986535984124576403651553273447618087600591347032422378272332279802860926604693828116337548053006928860031338938935746179912330961194768693506712533420818446672613053888256943921222915644107389736912059397747390472331492265060448066180414639931364582445814

线性关联攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#sage
import hashlib
from Crypto.Util.number import *
def franklinReiter(n,e,c1,c2,a,b):
R.<X> = Zmod(n)[]
f1 = (X+a)^e - c1
f2 = (X+b)^e - c2
# coefficient 0 = -m, which is what we wanted!
return Integer(n-(compositeModulusGCD(f1,f2)).coefficients()[0]) # 系数

# GCD is not implemented for rings over composite modulus in Sage
# so we do our own implementation. Its the exact same as standard GCD, but with
# the polynomials monic representation
def compositeModulusGCD(a, b):
if(b == 0):
return a.monic()
else:
return compositeModulusGCD(b, a % b)

n = 100885785256342169056765112203447042910886647238787490462506364977429519290706204521984596783537199842140535823208433284571495132415960381175163434675775328905396713032321690195499705998621049971024487732085874710868565606249892231863632731481840542506411757024315315311788336796336407286355303887021285839839
e = 3
c1 = 41973910895747673899187679417443865074160589754180118442365040608786257167532976519645413349472355652086604920132172274308809002827286937134629295632868623764934042989648498006706284984313078230848738989331579140105876643369041029438708179499450424414752031366276378743595588425043730563346092854896545408366
c2 = 41973912583926901518444642835111314526720967879172223986535984124576403651553273447618087600591347032422378272332279802860926604693828116337548053006928860031338938935746179912330961194768693506712533420818446672613053888256943921222915644107389736912059397747390472331492265060448066180414639931364582445814

def hash(x):
return int(hashlib.md5(str(x).encode()).hexdigest(), 16)

x1 = hash(307)
x2 = hash(7)

m= franklinReiter(n, e, c1, c2, x1, x2)
print(long_to_bytes(m))
#b'TGCTF{RS4_Tw1nZ_d0You_th1nk_ItS_fun_2win?!!!1111111111}'

宝宝rsa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from math import gcd
from Crypto.Util.number import *
from secret import flag

# PART1
p1 = getPrime(512)
q1 = getPrime(512)
n1 = p1 * q1
phi = (p1 - 1) * (q1 - 1)
m1 = bytes_to_long(flag[:len(flag) // 2])
e1 = getPrime(18)
while gcd(e1, phi) != 1:
e1 = getPrime(17)
c1 = pow(m1, e1, n1)

print("p1 =", p1)
print("q1 =", q1)
print("c1 =", c1)

# PART2
n2 = getPrime(512) * getPrime(512)
e2 = 3
m2 = bytes_to_long(flag[len(flag) // 2:])
c2 = pow(m2, e2, n2)

print("n2 =", n2)
print("c2 =", c2)
print("e2 =", e2)

# p1 = 8362851990079664018649774360159786938757293294328116561219351503022492961843907118845919317399785168488103775809531198339213009936918460080250107807031483
# q1 = 8312546034426788223492083178829355192676175323324230533451989649056072814335528263136523605276378801682321623998646291206494179416941978672637426346496531
# c1 = 39711973075443303473292859404026809299317446021917391206568511014894789946819103680496756934914058521250438186214943037578346772475409633145435232816799913236259074769958139045997486622505579239448395807857034154142067866860431132262060279168752474990452298895511880964765819538256786616223902867436130100322
# n2 = 103873139604388138367962901582343595570773101048733694603978570485894317088745160532049473181477976966240986994452119002966492405873949673076731730953232584747066494028393377311943117296014622567610739232596396108513639030323602579269952539931712136467116373246367352649143304819856986264023237676167338361059
# c2 = 51380982170049779703682835988073709896409264083198805522051459033730166821511419536113492522308604225188048202917930917221
# e2 = 3

第一段爆破e,第二段低指数攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import gmpy2
from Crypto.Util.number import *
from sympy import nextprime

p1 = 8362851990079664018649774360159786938757293294328116561219351503022492961843907118845919317399785168488103775809531198339213009936918460080250107807031483
q1 = 8312546034426788223492083178829355192676175323324230533451989649056072814335528263136523605276378801682321623998646291206494179416941978672637426346496531
c1 = 39711973075443303473292859404026809299317446021917391206568511014894789946819103680496756934914058521250438186214943037578346772475409633145435232816799913236259074769958139045997486622505579239448395807857034154142067866860431132262060279168752474990452298895511880964765819538256786616223902867436130100322
n1 = p1 * q1
phi = (p1 - 1) * (q1 - 1)
e = 65537
while e <= 2 ** 19:
try:
d = inverse(e, phi)
m = pow(c1, d, n1)
flag = long_to_bytes(m)
if b'TGCTF' in flag:
break
except:
pass
e = nextprime(e)

print(flag.decode(),end="")

c2=51380982170049779703682835988073709896409264083198805522051459033730166821511419536113492522308604225188048202917930917221
print(long_to_bytes(gmpy2.iroot(c2,3)[0]))

费克特尔

1
2
3
c=670610235999012099846283721569059674725712804950807955010725968103642359765806
n=810544624661213367964996895060815354972889892659483948276203088055391907479553
e=65537

factordb网站查询分解,得到五个因子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
p1=113
p2=18251
p3=2001511
p4=214168842768662180574654641
p5=916848439436544911290378588839845528581

from Crypto.Util.number import *

N=p1 * p2 * p3 * p4 * p5
e=65537
phi=(p1-1)*(p2-1)*(p3-1)*(p4-1)*(p5-1)
d=inverse(e, phi)
c=670610235999012099846283721569059674725712804950807955010725968103642359765806
print(long_to_bytes(pow(c, d, N)))
#b'TGCTF{f4888_6abdc_9c2bd_9036bb}'

emojiRSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from secrets import flag, get_random_emojiiiiii
from Crypto.Util.number import *


def genarate_emojiiiiii_prime(nbits, base=0):
while True:
p = getPrime(base // 32 * 32) if base >= 3 else 0
for i in range(nbits // 8 // 4 - base // 32):
p = (p << 32) + get_random_emojiiiiii() # 猜一猜
if isPrime(p):
return p


m = bytes_to_long(flag.encode()+ "".join([long_to_bytes(get_random_emojiiiiii()).decode() for _ in range(5)]).encode())
p = genarate_emojiiiiii_prime(512, 224)
q = genarate_emojiiiiii_prime(512)

n = p * q
e = "💯"
c = pow(m, bytes_to_long(e.encode()), n)

print("p0 =", long_to_bytes(p % 2 ** 256).decode())
print("n =", n)
print("c =", c)
# p0 = 😘😾😂😋😶😾😳😷
# n = 156583691355552921614631145152732482393176197132995684056861057354110068341462353935267384379058316405283253737394317838367413343764593681931500132616527754658531492837010737718142600521325345568856010357221012237243808583944390972551218281979735678709596942275013178851539514928075449007568871314257800372579
# c = 47047259652272336203165844654641527951135794808396961300275905227499051240355966018762052339199047708940870407974724853429554168419302817757183570945811400049095628907115694231183403596602759249583523605700220530849961163557032168735648835975899744556626132330921576826526953069435718888223260480397802737401



分析数据,先将p0全部转为正常字符

1
2
3
4
5
6
7
8
from Crypto.Util.number import *
p= "😘😾😂😋😶😾😳😷"
print(bytes_to_long(p.encode('utf-8')))
e = "💯"
e=bytes_to_long(e.encode("utf-8"))
print(e)
#108837065531980906150333850570890620719343963272506332719822248235755953428663
#4036989615

可以得到p是泄露了低256位,需要爆破256位,同时由生成函数

1
2
3
4
5
6
7
8
def genarate_emojiiiiii_prime(nbits, base=0):
while True:
p = getPrime(base // 32 * 32) if base >= 3 else 0
for i in range(nbits // 8 // 4 - base // 32):
p = (p << 32) + get_random_emojiiiiii() # 猜一猜
if isPrime(p):
return p

我们还可以爆破32位拿到288位,剩下就是打一个一元copper攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
for i in trange(4036991100,4036991200):#这里拿表情包自己测测就知道大概的长度和范围
PR.<x> = PolynomialRing(Zmod(n))
p1=p0+i*2**256
f = x*2**288 + p1
f=f.monic()
x0 = f.small_roots(X=2^224, beta=0.4,epsilon=0.05)
if x0:
p = int(x0[0]*2**288) + p1
print(p)
q= n // p
print(q)
#12424840247075830662687097292458444573014198016321428995092662043898159667123240573630892907827505266982898641483333170032514244713840745287869771915696311
#12602471198163266643743702664647336358595911975665358584258749238146841559843060594842063473155049870396568542257767865369797827796765830093256146584311989

然后直接解发现e和phi不互素,常规的e和phi不互素解不了,上amm板子(网上找的板子)

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from Crypto.Util.number import *
from tqdm import trange
import gmpy2
import random
p= "😘😾😂😋😶😾😳😷"
p0=bytes_to_long(p.encode('utf-8'))
e = "💯"
e=bytes_to_long(e.encode("utf-8"))
n = 156583691355552921614631145152732482393176197132995684056861057354110068341462353935267384379058316405283253737394317838367413343764593681931500132616527754658531492837010737718142600521325345568856010357221012237243808583944390972551218281979735678709596942275013178851539514928075449007568871314257800372579
c = 47047259652272336203165844654641527951135794808396961300275905227499051240355966018762052339199047708940870407974724853429554168419302817757183570945811400049095628907115694231183403596602759249583523605700220530849961163557032168735648835975899744556626132330921576826526953069435718888223260480397802737401

def AMM_3(c,p):
phi_p=p*p-1
s_p=phi_p//3
d_p=inverse(3,s_p)
l_3=[]

l_3.append(pow(c,d_p,p))

for i in range(1000):
if(len(l_3)>=5):
break
a=random.randint(1,p-1)
a=pow(a,(p**2-1)//3,p)
a=a*l_3[0]
a=pow(a,1,p)
if(a not in l_3):
l_3.append(a)
return l_3

def AMM_5(c,p):
phi_p=p*p-1
s_p=phi_p//5
d_p=inverse(5,s_p)
l_3=[]

l_3.append(pow(c,d_p,p))

for i in range(3000):
if(len(l_3)>=7):
break
a=random.randint(1,p-1)
a=pow(a,(p**2-1)//5,p)
a=a*l_3[0]
a=pow(a,1,p)
if(a not in l_3):
l_3.append(a)
return l_3

for i in trange(4036991100,4036991200):
PR.<x> = PolynomialRing(Zmod(n))
p1=p0+i*2**256
f = x*2**288 + p1
f=f.monic()
x0 = f.small_roots(X=2^224, beta=0.4,epsilon=0.05)
if x0:
p = int(x0[0]*2**288) + p1
print(p)
q= n // p
print(q)
phi = (p-1)*(q-1)
#print(GCD(e, phi))

c_q=c%q
c_p=c%p

d_q=inverse(e//3, q-1)
d_p=inverse(e//5, p-1)
c1=pow(c_q,d_q,q)
c2=pow(c_p,d_p,p)

m_q=AMM_3(c1,q)
m_p=AMM_5(c2,p)

for i in m_q:
for j in m_p:
m=crt([i,j],[q,p])
if b"TG" in long_to_bytes(m):
print(long_to_bytes(m).decode("UTF-8"))
break
#TGCTF{🙇🏮🤟_🫡🫡🫡_🚩🚩🚩}😃😖😘😨😢

LLLCG

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

class TripleLCG:
def __init__(self, seed1, seed2, seed3, a, b, c, d, n):
self.state = [seed1, seed2, seed3]
self.a = a
self.b = b
self.c = c
self.d = d
self.n = n

def next(self):
new = (self.a * self.state[-3] + self.b * self.state[-2] + self.c * self.state[-1] + self.d) % self.n
self.state.append(new)
return new


class DSA:
def __init__(self):
# while True:
# self.q = getPrime(160)
# t = 2 * getPrime(1024 - 160) * self.q
# if isPrime(t + 1):
# self.p = t + 1
# break
self.p = dsa_p
self.q = dsa_q
self.g = pow(2, (self.p - 1) // self.q, self.p)
self.x = randint(1, self.q - 1)
self.y = pow(self.g, self.x, self.p)

def sign(self, msg, k):
h = bytes_to_long(sha256(msg).digest())
r = pow(self.g, k, self.p) % self.q
s = (inverse(k, self.q) * (h + self.x * r)) % self.q
return (r, s)

def verify(self, msg, r, s):
if not (0 < r < self.q and 0 < s < self.q):
return False
h = bytes_to_long(sha256(msg).digest())
w = inverse(s, self.q)
u1 = (h * w) % self.q
u2 = (r * w) % self.q
v = ((pow(self.g, u1, self.p) * pow(self.y, u2, self.p)) % self.p) % self.q
return v == r


class Task(socketserver.BaseRequestHandler):
def _recvall(self):
BUFF_SIZE = 2048
data = b''
while True:
part = self.request.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
break
return data.strip()

def send(self, msg, newline=True):
if newline:
msg += b'\n'
self.request.sendall(msg)

def recv(self, prompt=b'[-] '):
self.send(prompt, newline=False)
return self._recvall()

def handle(self):
n = getPrime(128)
a, b, c, d = [randint(1, n - 1) for _ in range(4)]
seed1, seed2, seed3 = [randint(1, n - 1) for _ in range(3)]

lcg = TripleLCG(seed1, seed2, seed3, a, b, c, d, n)
dsa = DSA()

self.send(b"Welcome to TGCTF Challenge!\n")
self.send(f"p = {dsa.p}, q = {dsa.q}, g = {dsa.g}, y = {dsa.y}".encode())

small_primes = [59093, 65371, 37337, 43759, 52859, 39541, 60457, 61469, 43711]
used_messages = set()
for o_v in range(3):
self.send(b"Select challenge parts: 1, 2, 3\n")
parts = self.recv().decode().split()

if '1' in parts:
self.send(b"Part 1\n")
for i in range(12):
self.send(f"Message {i + 1}: ".encode())
msg = self.recv()
used_messages.add(msg)
k = lcg.next()
r, s = dsa.sign(msg, k)
self.send(f"r = {r}, ks = {[k % p for p in small_primes]}\n".encode())

if '2' in parts:
self.send(b"Part 2\n")
for _ in range(307):
k = lcg.next()
for i in range(10):
self.send(f"Message {i + 1}: ".encode())
msg = self.recv()
k = lcg.next() % dsa.q
r, s = dsa.sign(msg, k)
self.send(f"Signature: r = {r}, s = {s}\n".encode())
used_messages.add(msg)

if '3' in parts:
self.send(b"Part 3\n")
self.send(b"Forged message: ")
final_msg = self.recv()
self.send(b"Forged r: ")
r = int(self.recv())
self.send(b"Forged s: ")
s = int(self.recv())

if final_msg in used_messages:
self.send(b"Message already signed!\n")
elif dsa.verify(final_msg, r, s):
self.send(f"Good! Your flag: {flag}\n".encode())
else:
self.send(b"Invalid signature.\n")