# Write up KCSC Recruitment 2026
## MiniRSA
Đề bài cho source code như sau:
```python=
from Crypto.Util.number import getPrime, bytes_to_long
from hashlib import sha256
# fake flag, complete 4 phases below to get the real one
FLAG = b"KCSC{676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767}"
FLAG = FLAG[5:-1]
assert all(c in b"0123456789abcdef" for c in FLAG) # hex-only
assert len(FLAG) == 162
part1 = FLAG[0 : 37]
part2 = FLAG[37 : 91]
part3 = FLAG[91 : 155]
part4 = FLAG[155: 162]
assert part1 + part2 + part3 + part4 == FLAG
# Phase 1:
assert len(part1) == 37
n1 = getPrime(1024) * getPrime(1024)
flag1 = bytes_to_long(part1)
assert flag1 < n1
e1 = 7
c1 = pow(flag1, e1, n1)
print("Phase 1:")
print(f"n = {n1}")
print(f"e = {e1}")
print(f"c = {c1}\n")
# n = 24768551472661189646803798025735994729675923012939876254832364742560290611235358539402960915109731271068761785643095443054780548009656705453830110379444700418833089171817064649224391362714139414078789526050887157582406524961283991222714583389641534201051586959980157906704312629985265485739450352043789888921235279589151315468070396525574513463528110969355058846977730601522857753194783784154604698121483122903344163960138046879651018970211352779930792196553883676319989732719640639947477887444507816814644473808320811170489238150100695729301133978725734344966342539008392521368848055667562401810828901055904263751087
# e = 7
# c = 18095221808696767364482784106578665305597072892957003660200677125082480938590759416561596931362184836970227059449018023231775268023936196618166559695219893530882687916034256857200503922379924700258829452303164421775991854747192890323693977001251087329555558918620707751930767202265420598175188863386691087599780498257684594011697328525563218286665773793900960107693859824245088548197358663304146296383128902903029994359803481927306296829608298387122321098870479487155445811455194372706211665184810020606934406988332111485009183488421535000282713153719587883866210474448900196771807191538210239194200766493898209050827
# Phase 2:
assert len(part2) == 54
moduli = [getPrime(500) * getPrime(500) for _ in range(3)]
flag2 = bytes_to_long(part2)
assert flag2 < min(moduli)
e2 = 7
ciphertexts = [pow(flag2, e2, moduli[i]) for i in range(3)]
print("Phase 2:")
print(f"ns = {moduli}")
print(f"e = {e2}")
print(f"cs = {ciphertexts}\n")
# ns = [5776746251180954410501143373555071446651309076079023801239927839678110284298053445067843385733923949632510804583576555583870535387441316658685840687689240200699587579390668561563937127040444465254726625310777306158594065224927251973217783491441064524351035802071558210418452732784328906404928346757561, 6676568530944751773705274371029619538616953853214731842955709009914939432096974301535527889053677971564433108995378797418249594276219798862529871540959246847221996855818534102541008885671426716581485932426758973143450314953430892380665585863829711961246704347425347121483579347058369739426135845646693, 4192125436309381894285355753973720387617056931265026941800223776464084287332759678003685944684491135983930538940594703444960195450172411842880979937537165579234724095471901440019430531228826628339513666609406387657919179589286169600368614047778141005381080248940651068046222358006840623976659320922801]
# e = 7
# cs = [4162314281829070969983785868478817487122811901286983843325224202348302016796815815333452464672872912888701572281242789929104022254953168740731678111433971515437492093542686431714890537676381271531800973763109092820046704937574547000215411647046072684054960320518397352086234888330336947666810104929210, 50764199787126347289275452914702574991784396905310732416007230764340015964909418575803553215557208257135086801048181610281948813886172483845338416063595514468150336763299168160503561124717579857540938345665633478359717032027020484374804577083335729646127615429489801214833042281198632815600258496021, 2226866454269961169554477487076928558283277297558185848127271094461892302315098156482036398655353603737228883411877291393627455878900738358485648657420475192577890517627929950639476113316539806453385202418270139866437710517550467476876937820556775982947361645302515541452549533744585394098458949714224]
# Phase 3:
assert len(part3) == 64
p3 = getPrime(512)
q3 = getPrime(512)
n3 = p3 * q3
flag3 = bytes_to_long(part3)
assert flag3 < n3
phi3 = (p3 - 1) * (q3 - 1)
e3 = 0x10001
E = getPrime(16)
assert e3 != E
d3 = pow(E, -1, phi3) # I'm so generous that I will give you d directly :)
c3 = pow(flag3, e3, n3)
print("Phase 3:")
print(f"n = {n3}")
print(f"e = {e3}")
print(f"E = {E}")
print(f"d = {d3}")
print(f"c = {c3}\n")
# n = 58918298105520625812936595965949791679948485672063422501379350174567652137330835174097919449869935351283983373480427262310194532256798429690185381024326970315021350533262412067581291819891395690548362953546838296879197806387922608866341956665531154816197564814442845602714598090456294723302800178858587739713
# e = 65537
# E = 39119
# d = 47540992349005816963249153906419008010878957801546101159437592685401670280805946273432368604390309296333723642831097076480004356212731471488808547049589210685661344692631483342927181931551362472531714993510869363985573142465639097423475598977423653768735951445358570563443850030507199283981083278104055782079
# c = 37398307787309593195399039608335293998782975977344821375594074480912755773091240878727726167860952796427287138264423555320002390940336425049899775688041256572345243342480573394310574660551049821001839500881785836377907724697125451771009902048018563262095797500165548399273323153654585302502917216971632506342
# Phase 4:
assert len(part4) == 7
# hash of the flag
Flag_hash = sha256(FLAG).hexdigest()
print("Phase 4:")
print(f"{Flag_hash = }")
# Flag_hash = 6c65e2cc4142210eac7503a24a2d48205aeaf8686407c70fde01478336853281
```
Đọc source thì thấy flag cần tìm là dãy byte độ dài 162 được ghép từ 4 phase đề bài
**Phase 1**
part1 là 1 chuỗi byte có độ dài là 37. Do đề cho e khá nhỏ, nên ta có thể lấy căn để tìm m(part1).
Có $c = m^e \bmod n$, hay $m^e - c$ chia hết cho $n$. Vậy, ta có $m^e = c +k.n$ với $k \in \mathbb{Z}$. Vậy chỉ cần tìm k sao cho $\sqrt[7]{c +k.n}$ là một số nguyên. Code như sau:
```python=
from Crypto.Util.number import long_to_bytes
from gmpy2 import *
n1 = 24768551472661189646803798025735994729675923012939876254832364742560290611235358539402960915109731271068761785643095443054780548009656705453830110379444700418833089171817064649224391362714139414078789526050887157582406524961283991222714583389641534201051586959980157906704312629985265485739450352043789888921235279589151315468070396525574513463528110969355058846977730601522857753194783784154604698121483122903344163960138046879651018970211352779930792196553883676319989732719640639947477887444507816814644473808320811170489238150100695729301133978725734344966342539008392521368848055667562401810828901055904263751087
e1 = 7
c1 = 18095221808696767364482784106578665305597072892957003660200677125082480938590759416561596931362184836970227059449018023231775268023936196618166559695219893530882687916034256857200503922379924700258829452303164421775991854747192890323693977001251087329555558918620707751930767202265420598175188863386691087599780498257684594011697328525563218286665773793900960107693859824245088548197358663304146296383128902903029994359803481927306296829608298387122321098870479487155445811455194372706211665184810020606934406988332111485009183488421535000282713153719587883866210474448900196771807191538210239194200766493898209050827
for k in range(10000000):
thu = k*n1 + c1
can, so = iroot(thu, e1)
if so:
print(long_to_bytes(can).decode())
break
```
được part1 là `f8fc7143e81ab9e2a4b8cd7b5893504c68619`
**Phase 2**
part2 là chuỗi byte có độ dài 54. Đề cho list ns và cs gồm 3n và 3c, thêm số mũ e nhỏ là 7, nên mình nghĩ đến dùng crt để giải. Sau khi đã giải và tìm được nghiệm của crt, mình tiếp tục dùng phương pháp như phase 1 để tìm ra m chính xác, sau đó long_to_bytes và tìm được part2 đúng bằng độ dài ban đầu. Code như sau:
```python=
from Crypto.Util.number import long_to_bytes
from gmpy2 import *
import libnum
N = [5776746251180954410501143373555071446651309076079023801239927839678110284298053445067843385733923949632510804583576555583870535387441316658685840687689240200699587579390668561563937127040444465254726625310777306158594065224927251973217783491441064524351035802071558210418452732784328906404928346757561, 6676568530944751773705274371029619538616953853214731842955709009914939432096974301535527889053677971564433108995378797418249594276219798862529871540959246847221996855818534102541008885671426716581485932426758973143450314953430892380665585863829711961246704347425347121483579347058369739426135845646693, 4192125436309381894285355753973720387617056931265026941800223776464084287332759678003685944684491135983930538940594703444960195450172411842880979937537165579234724095471901440019430531228826628339513666609406387657919179589286169600368614047778141005381080248940651068046222358006840623976659320922801]
e = 7
C = [4162314281829070969983785868478817487122811901286983843325224202348302016796815815333452464672872912888701572281242789929104022254953168740731678111433971515437492093542686431714890537676381271531800973763109092820046704937574547000215411647046072684054960320518397352086234888330336947666810104929210, 50764199787126347289275452914702574991784396905310732416007230764340015964909418575803553215557208257135086801048181610281948813886172483845338416063595514468150336763299168160503561124717579857540938345665633478359717032027020484374804577083335729646127615429489801214833042281198632815600258496021, 2226866454269961169554477487076928558283277297558185848127271094461892302315098156482036398655353603737228883411877291393627455878900738358485648657420475192577890517627929950639476113316539806453385202418270139866437710517550467476876937820556775982947361645302515541452549533744585394098458949714224]
n=1
for i in N: n*=i
m = libnum.solve_crt(C,N)
for k in range(10000000):
thu = k*n + m
can, so = iroot(thu, 7)
if so:
print(long_to_bytes(can).decode())
break
```
part2: `9fea0ba22e7e9ffafae5aaba63a1a64b732debe30e2aaa9e957040`
**Phase 3**
part3 là chuỗi byte có độ dài 64. Ngoài các giá trị n, e, c thì phần này đề cung cấp thêm E, và d sao cho $E.d \equiv 1 \bmod \phi(n)$. Có $k = E \cdot d - 1 = m \cdot \phi(n)$ => $k = 2^s \cdot r$. Ta cần tìm $g$ thõa mãn $g^r \not\equiv \pm 1 \pmod{N}$ và tồn tại $x = g^{2^i r} \pmod{N}$ sao cho $x \not\equiv \pm 1 \pmod{N}$ nhưng $x^2 \equiv 1 \pmod{N}$. Sau đó tính $p = \gcd(x - 1, N)$, có được p, ta giải như bình thường và tìm được part3. Code như sau:
```python=
from Crypto.Util.number import long_to_bytes, inverse
from gmpy2 import *
N = 58918298105520625812936595965949791679948485672063422501379350174567652137330835174097919449869935351283983373480427262310194532256798429690185381024326970315021350533262412067581291819891395690548362953546838296879197806387922608866341956665531154816197564814442845602714598090456294723302800178858587739713
e = 65537
E = 39119
d = 47540992349005816963249153906419008010878957801546101159437592685401670280805946273432368604390309296333723642831097076480004356212731471488808547049589210685661344692631483342927181931551362472531714993510869363985573142465639097423475598977423653768735951445358570563443850030507199283981083278104055782079
c = 37398307787309593195399039608335293998782975977344821375594074480912755773091240878727726167860952796427287138264423555320002390940336425049899775688041256572345243342480573394310574660551049821001839500881785836377907724697125451771009902048018563262095797500165548399273323153654585302502917216971632506342
k = E*d-1
s = 0
r = k
while r % 2 == 0:
r //= 2
s += 1
p=q=0
for g in range(2, 10):
x=pow(g, r, N)
for i in range(s):
y = pow(x, 2, N)
if y == 1:
p = gcd(x - 1, N)
if p>1 and p<N:
q = N // p
break
else:
break
x = y
if p!=0 and p!=1: break
q=N//p
phi = (p-1)*(q-1)
D=inverse(e, phi)
part3=long_to_bytes(pow(c,D,N)).decode()
print(part3)
```
part 3: `3504c6861f68832310c7d569ae3ec1ecbfbba80d65a282127376ef656f9ce50e`
**Phase 4**
part4 là chuỗi byte có độ dài là 7. Sau khi ghép với part1, part2, part3 và được băm bằng hàm sha256, sẽ có được Flag_hash đề cho. Để tìm lại part 4, cần duyệt qua tất cả các chuỗi byte có độ dài là 7 và chỉ chứa các ký tự hex, sau đó băm bằng hàm sha256, nếu ra được Flag_hash đề cho, thì đó chính là part4 cần tìm. Code như sau:
```python=
import hashlib
import itertools
TARGET_HASH = "6c65e2cc4142210eac7503a24a2d48205aeaf8686407c70fde01478336853281"
FLAG_LEN = 7
CHARSET_DIGITS = "fedcba9876543210"
CHARSET_BYTES = CHARSET_DIGITS.encode('ascii')
FLAG_PREFIX = b"f8fc7143e81ab9e2a4b8cd7b5893504c686199fea0ba22e7e9ffafae5aaba63a1a64b732debe30e2aaa9e9570403504c6861f68832310c7d569ae3ec1ecbfbba80d65a282127376ef656f9ce50e"
found = False
for suffix_tuple in itertools.product(CHARSET_BYTES, repeat=FLAG_LEN):
suffix_bytes = bytes(suffix_tuple)
flag_candidate = FLAG_PREFIX + suffix_bytes
hash_hex = hashlib.sha256(flag_candidate).hexdigest()
if hash_hex == TARGET_HASH:
print(flag_candidate)
found = True
break
```
flag: `KCSC{f8fc7143e81ab9e2a4b8cd7b5893504c686199fea0ba22e7e9ffafae5aaba63a1a64b732debe30e2aaa9e9570403504c6861f68832310c7d569ae3ec1ecbfbba80d65a282127376ef656f9ce50ed2aa3fe}`
## Rsabcde (giải sau khi hết thời gian làm bài)
Đề bài cung cấp file source:
```python=
from Crypto.Util.number import bytes_to_long, long_to_bytes, getPrime
from secret import flag, f4k3_fl4g
import sys , random
sys.set_int_max_str_digits(678)
assert bytes_to_long(flag) < 2**456
try:
a, b, c, d, e = [ int(input(f"{x} = ")) for x in "abcde" ]
assert a > 0
assert 1111111111111111111 * a == c + 8888888888888888881 * e
assert 9999999999999999961 * b == 1258462969247482836585791373370000000000000000000000000000000000000000011896691036181988787986574538026426876 * a
assert d ** 2 == a + b
if a.bit_length() < 234:
prime = getPrime(512)
rand = random.choice([a, b, c, d, e])
n = prime * rand
ct = pow(bytes_to_long(flag), e, n)
print(f"n = {n}")
print(f"ct = {ct}")
else:
print("(👉゚ヮ゚)👉", f4k3_fl4g.decode())
except: print("Nope!")
```
và server `nc 67.223.119.69 5010`
Đề cho các biến $a, b, c, d, e$ là số nguyên dương ($a > 0$). Các ràng buộc là:
* $1111111111111111111 \cdot a = c + 8888888888888888881 \cdot e$
* $9999999999999999961 \cdot b = 1258462969247482836585791373370000000000000000000000000000000000000000011896691036181988787986574538026426876 \cdot a$
* $d^2 = a + b$
* $\text{a.bit_length()} < 234$
Ký hiệu:
* $K_1 = 1111111111111111111$
* $K_2 = 8888888888888888881$
* $K_3 = 9999999999999999961$
* $K_4 = 1258462969247482836585791373370000000000000000000000000000000000000000011896691036181988787986574538026426876$
Chọn e là 1, cần tìm a, b sao cho a+b là một số chính phương và $$\frac{b}{a} = \frac{K_4}{K_3}$$
Vậy, $a$ và $b$ phải có dạng:$$a = k \cdot K_3$$$$b = k \cdot K_4$$ với $k \in \mathbb{N^*}$
Thay $a$ và $b$ vào điều kiện (3):$$d^2 = k \cdot K_3 + k \cdot K_4 = k \cdot (K_3 + K_4)$$Đặt $s = K_3 + K_4$, cần tìm $k$ sao cho:$$d^2 = k \cdot s$$
Do $k.s$ phải là số chính phương, nên k phải chứa tất cả các thừa số nguyên tố của y với số mũ lẻ, ta nhân thêm các thừa số nguyên tố có số mũ lẻ vào k. Sau đó
```python=
from math import gcd, isqrt
from sympy.ntheory import factorint
k1 = 1111111111111111111
k2 = 8888888888888888881
k3 = 9999999999999999961
k4 = 1258462969247482836585791373370000000000000000000000000000000000000000011896691036181988787986574538026426876
s = (k3+k4)
k = 1
for p, cnt in factorint(s).items():
if cnt%2!=0: k *= p
a = k * k3
while k1 * a <= k2:
a <<= 2
b = a*k4//k3
c = k1*a-k2
d = isqrt(a + b)
print(a)
print(b)
print(c)
print(d)
```
Nộp a,b,c,d,e lên server được n và ct, long to byte ct ta được flag `KCSC{f4c70rDB_15_4m4z1ng!}`