# Cyber Apocalypse 2024: Hacker Royale
{%hackmd @themes/orangeheart %}
## Dynastic

source.py
```python=
from secret import FLAG
from random import randint
def to_identity_map(a):
return ord(a) - 0x41
def from_identity_map(a):
return chr(a % 26 + 0x41)
def encrypt(m):
c = ''
for i in range(len(m)):
ch = m[i]
if not ch.isalpha():
ech = ch
else:
chi = to_identity_map(ch)
ech = from_identity_map(chi + i)
c += ech
return c
with open('output.txt', 'w') as f:
f.write('Make sure you wrap the decrypted text with the HTB flag format :-]\n')
f.write(encrypt(FLAG))
```
**output.txt**
```
Make sure you wrap the decrypted text with the HTB flag format :-]
DJF_CTA_SWYH_NPDKK_MBZ_QPHTIGPMZY_KRZSQE?!_ZL_CN_PGLIMCU_YU_KJODME_RYGZXL
```
Đọc source code ta có:
`ech = chr((ord(m[i]) - 0x41)+i) % 26 + 0x41)`
--> `ord(ech) - 0x41 = ord(m[i]) - 0x41 + i - k*26`
--> `ord(m[i]) = ord(ech) - i + k*26`
**script:**
```python=
from random import randint
c = 'DJF_CTA_SWYH_NPDKK_MBZ_QPHTIGPMZY_KRZSQE?!_ZL_CN_PGLIMCU_YU_KJODME_RYGZXL'
p = ''
for i in range(len(c)):
if not c[i].isalpha():
p=p+c[i]
else:
for k in range(5):
tmp = chr(ord(c[i]) + k*26 - i)
if tmp.isalpha():
p = p + tmp
break
print(p)
```
Flag: `HTB{DID_YOU_KNOW_ABOUT_THE_TRITHEMIUS_CIPHER?!_IT_IS_SIMILAR_TO_CAESAR_CIPHER}`
Một số challange tiếp theo khá đơn giản nên mình sẽ lướt qua luôn nhé !!!
**Blunt:** Tìm share_secret trong Diffie-Hellman Elliptic Curves. Mình chỉ cần sử dụng logarit rời rạc để tính được khóa bí mật của Bob hoặc Alice đều được.
**Makeshift:** Mã hóa bằng cách hoán vị từng 3 kí tự một. Để giải mã ta chỉ cần làm ngược lại khá là đơn giản :))))).
## Arranged
Đây là sourcecode
**main.sage**
```python3=
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import long_to_bytes
from hashlib import sha256
from secret import FLAG, p, b, priv_a, priv_b
F = GF(p)
E = EllipticCurve(F, [726, b])
G = E(926644437000604217447316655857202297402572559368538978912888106419470011487878351667380679323664062362524967242819810112524880301882054682462685841995367, 4856802955780604241403155772782614224057462426619061437325274365157616489963087648882578621484232159439344263863246191729458550632500259702851115715803253)
A = G * priv_a
B = G * priv_b
print(A)
print(B)
C = priv_a * B
assert C == priv_b * A
# now use it as shared secret
secret = C[0]
hash = sha256()
hash.update(long_to_bytes(secret))
key = hash.digest()[16:32]
iv = b'u\x8fo\x9aK\xc5\x17\xa7>[\x18\xa3\xc5\x11\x9en'
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(pad(FLAG, 16))
print(encrypted)
```
**output.txt**
```python3=
(6174416269259286934151093673164493189253884617479643341333149124572806980379124586263533252636111274525178176274923169261099721987218035121599399265706997 : 2456156841357590320251214761807569562271603953403894230401577941817844043774935363309919542532110972731996540328492565967313383895865130190496346350907696 : 1)
(4226762176873291628054959228555764767094892520498623417484902164747532571129516149589498324130156426781285021938363575037142149243496535991590582169062734 : 425803237362195796450773819823046131597391930883675502922975433050925120921590881749610863732987162129269250945941632435026800264517318677407220354869865 : 1)
b'V\x1b\xc6&\x04Z\xb0c\xec\x1a\tn\xd9\xa6(\xc1\xe1\xc5I\xf5\x1c\xd3\xa7\xdd\xa0\x84j\x9bob\x9d"\xd8\xf7\x98?^\x9dA{\xde\x08\x8f\x84i\xbf\x1f\xab'
```
Target ở bài này là mình cần phải đi tìm được các giá trị còn lại của đường cong. Mình đã có 3 điểm trên đường cong và `a`.
Để tìm được `b` thì chỉ cần thay một điểm vào và giải phương trình thì ta tìm được ngay.
Ta có:
$y^2 = x^3 + a*x + b \pmod p$, tức là đường cong này được xác định trên trường $F_p$
suy ra: $y^2 - x^3 - a*x - b = k*p$, với 3 điểm có sẵn mình lần lượt thay thế vào thì mình có 3 cái bội của `p`. Tiếp đến sử dụng GCD để tìm ước chung của 3 cái bội đó thì ta tìm được p.
Sau khi đã có các dữ kiện cần thiết mình chỉ cần đi tìm share_secret và nhận flag thôi.
**script:**
```python3=
from sage.all import *
x1 = 926644437000604217447316655857202297402572559368538978912888106419470011487878351667380679323664062362524967242819810112524880301882054682462685841995367
y1 = 4856802955780604241403155772782614224057462426619061437325274365157616489963087648882578621484232159439344263863246191729458550632500259702851115715803253
x2 = 6174416269259286934151093673164493189253884617479643341333149124572806980379124586263533252636111274525178176274923169261099721987218035121599399265706997
y2 = 2456156841357590320251214761807569562271603953403894230401577941817844043774935363309919542532110972731996540328492565967313383895865130190496346350907696
x3 = 4226762176873291628054959228555764767094892520498623417484902164747532571129516149589498324130156426781285021938363575037142149243496535991590582169062734
y3 = 425803237362195796450773819823046131597391930883675502922975433050925120921590881749610863732987162129269250945941632435026800264517318677407220354869865
a = 726
#b = var('b')
#solve(y2**2 - x2**3 - a*x2 - b, b)
b = -235389841633113518256718847719878733250125469551464659906955192105157068458892240496251208387305226684383977028692545364635616542911806071089784509634298138989466830088876060296948154657939206289908022191050803100386883123914692738193940269023567868365152264359631600117242932969716150281155438233466191095095609214364837462241270538753838231525244229345683421423856137208707912136351137768367596194932966862290676506665434291342481388359433898092926158324340379
K1 = (y1**2 - x1**3 - a*x1 - b)
K2 = (y2**2 - x2**3 - a*x2 - b)
K3 = (y3**2 - x3**3 - a*x3 - b)
p = gcd(gcd(K1, K2), K3)
F = GF(p)
E = EllipticCurve(F, [726, b])
G = E([x1, y1])
A = E([x2, y2])
B = E([x3, y3])
a = G.discrete_log(A)
S = a*B
S
```
```python3=
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import long_to_bytes
from hashlib import sha256
secret = 926644437000604217447316655857202297402572559368538978912888106419470011487878351667380679323664062362524967242819810112524880301882054682462685841995367
ciphertext = b'''V\x1b\xc6&\x04Z\xb0c\xec\x1a\tn\xd9\xa6(\xc1\xe1\xc5I\xf5\x1c\xd3\xa7\xdd\xa0\x84j\x9bob\x9d"\xd8\xf7\x98?^\x9dA{\xde\x08\x8f\x84i\xbf\x1f\xab'''
hash = sha256()
hash.update(long_to_bytes(secret))
key = hash.digest()[16:32]
iv = b'u\x8fo\x9aK\xc5\x17\xa7>[\x18\xa3\xc5\x11\x9en'
cipher = AES.new(key, AES.MODE_CBC, iv)
flag = cipher.decrypt(ciphertext)
print(flag)
# b'HTB{0rD3r_mUsT_b3_prEs3RveD_!!@!}\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f'
```
## Iced Tea
**source.py**
```python3=
import os
from Crypto.Util.Padding import pad
from Crypto.Util.number import bytes_to_long as b2l, long_to_bytes as l2b
from enum import Enum
from pwn import xor
class Mode(Enum):
ECB = 0x01
CBC = 0x02
class Cipher:
def __init__(self, key, iv=None):
self.BLOCK_SIZE = 64
self.KEY = [b2l(key[i:i+self.BLOCK_SIZE//16]) for i in range(0, len(key), self.BLOCK_SIZE//16)]
self.DELTA = 0x9e3779b9
self.IV = iv
if self.IV:
self.mode = Mode.CBC
else:
self.mode = Mode.ECB
def _xor(self, a, b):
return b''.join(bytes([_a ^ _b]) for _a, _b in zip(a, b))
def encrypt(self, msg):
msg = pad(msg, self.BLOCK_SIZE//8)
blocks = [msg[i:i+self.BLOCK_SIZE//8] for i in range(0, len(msg), self.BLOCK_SIZE//8)]
ct = b''
if self.mode == Mode.ECB:
for pt in blocks:
ct += self.encrypt_block(pt)
elif self.mode == Mode.CBC:
X = self.IV
for pt in blocks:
enc_block = self.encrypt_block(self._xor(X, pt))
ct += enc_block
X = enc_block
return ct
def encrypt_block(self, msg):
m0 = b2l(msg[:4])
m1 = b2l(msg[4:])
K = self.KEY
msk = (1 << (self.BLOCK_SIZE//2)) - 1
s = 0
for i in range(32):
s += self.DELTA
m0 += ((m1 << 4) + K[0]) ^ (m1 + s) ^ ((m1 >> 5) + K[1])
m0 &= msk
m1 += ((m0 << 4) + K[2]) ^ (m0 + s) ^ ((m0 >> 5) + K[3])
m1 &= msk
m = ((m0 << (self.BLOCK_SIZE//2)) + m1) & ((1 << self.BLOCK_SIZE) - 1) # m = m0 || m1
return l2b(m)
def decrypt_block(self, msg):
m = b2l(msg)
m0 = (m >> (self.BLOCK_SIZE//2)) & ((1 << (self.BLOCK_SIZE//2)) - 1)
m1 = m & ((1 << (self.BLOCK_SIZE//2)) - 1)
K = self.KEY
msk = (1 << (self.BLOCK_SIZE//2)) - 1
s = 0xC6EF3720
for i in range(32):
m1 -= ((m0 << 4) + K[2]) ^ (m0 + s) ^ ((m0 >> 5) + K[3])
m1 &= msk
m0 -= ((m1 << 4) + K[0]) ^ (m1 + s) ^ ((m1 >> 5) + K[1])
m0 &= msk
s -= self.DELTA
return l2b(m0) + l2b(m1)
def decrypt(self, msg):
msg = pad(msg, self.BLOCK_SIZE//8)
blocks = [msg[i:i+self.BLOCK_SIZE//8] for i in range(0, len(msg), self.BLOCK_SIZE//8)]
ct = b''
if self.mode == Mode.ECB:
for pt in blocks:
ct += self.decrypt_block(pt)
elif self.mode == Mode.CBC:
X = self.IV
for pt in blocks:
enc_block = self.decrypt_block(self._xor(pt, X))
ct += enc_block
X = pt
return ct
if __name__ == '__main__':
key = bytes.fromhex("850c1413787c389e0b34437a6828a1b2")
cipher = Cipher(key)
Ciphertext = "b36c62d96d9daaa90634242e1e6c76556d020de35f7a3b248ed71351cc3f3da97d4d8fd0ebc5c06a655eb57f2b250dcb2b39c8b2000297f635ce4a44110ec66596c50624d6ab582b2fd92228a21ad9eece4729e589aba644393f57736a0b870308ff00d778214f238056b8cf5721a843"
c = bytes.fromhex(Ciphertext)
ct = cipher.decrypt(c)
print(c)
```
**output.txt**
```
Key : 850c1413787c389e0b34437a6828a1b2
Ciphertext : b36c62d96d9daaa90634242e1e6c76556d020de35f7a3b248ed71351cc3f3da97d4d8fd0ebc5c06a655eb57f2b250dcb2b39c8b2000297f635ce4a44110ec66596c50624d6ab582b2fd92228a21ad9eece4729e589aba644393f57736a0b870308ff00d778214f238056b8cf5721a843
```
Mình mò trên mạng thì biết được đây là [Tiny Encryption Algorithm](https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm). Một loại block cipher đơn giản các bước mã hóa cũng đơn giản không kém.
Mình có luôn hàm decrypt.
```python=
import os
from Crypto.Util.Padding import pad, unpad
from Crypto.Util.number import bytes_to_long as b2l, long_to_bytes as l2b
from enum import Enum
class Mode(Enum):
ECB = 0x01
CBC = 0x02
class Cipher:
def __init__(self, key, iv=None):
self.BLOCK_SIZE = 64
self.KEY = [b2l(key[i:i+self.BLOCK_SIZE//16]) for i in range(0, len(key), self.BLOCK_SIZE//16)]
self.DELTA = 0x9e3779b9
self.IV = iv
if self.IV:
self.mode = Mode.CBC
else:
self.mode = Mode.ECB
def _xor(self, a, b):
return b''.join(bytes([_a ^ _b]) for _a, _b in zip(a, b))
def encrypt(self, msg):
msg = pad(msg, self.BLOCK_SIZE//8)
blocks = [msg[i:i+self.BLOCK_SIZE//8] for i in range(0, len(msg), self.BLOCK_SIZE//8)]
ct = b''
if self.mode == Mode.ECB:
for pt in blocks:
ct += self.encrypt_block(pt)
elif self.mode == Mode.CBC:
X = self.IV
for pt in blocks:
enc_block = self.encrypt_block(self._xor(X, pt))
ct += enc_block
X = enc_block
return ct
def encrypt_block(self, msg):
m0 = b2l(msg[:4])
m1 = b2l(msg[4:])
K = self.KEY
msk = (1 << (self.BLOCK_SIZE//2)) - 1
s = 0
for i in range(32):
s += self.DELTA
m0 += ((m1 << 4) + K[0]) ^ (m1 + s) ^ ((m1 >> 5) + K[1])
m0 &= msk
m1 += ((m0 << 4) + K[2]) ^ (m0 + s) ^ ((m0 >> 5) + K[3])
m1 &= msk
m = ((m0 << (self.BLOCK_SIZE//2)) + m1) & ((1 << self.BLOCK_SIZE) - 1) # m = m0 || m1
return l2b(m)
def decrypt_block(self, ct):
c0 = b2l(ct[:4])
c1 = b2l(ct[4:])
K = self.KEY
msk = (1 << (self.BLOCK_SIZE//2)) - 1
s = 0xC6EF3720
for i in range(32):
c1 -= ((c0 << 4) + K[2]) ^ (c0 + s) ^ ((c0 >> 5) + K[3])
c1 &= msk
c0 -= ((c1 << 4) + K[0]) ^ (c1 + s) ^ ((c1 >> 5) + K[1])
c0 &= msk
s -= self.DELTA
c = ((c0 << (self.BLOCK_SIZE//2)) + c1) & ((1 << self.BLOCK_SIZE) - 1)
return l2b(c)
def decrypt(self, ct):
blocks = [ct[i:i+self.BLOCK_SIZE//8] for i in range(0, len(ct), self.BLOCK_SIZE//8)]
msg = b''
if self.mode == Mode.ECB:
for ct in blocks:
msg += self.decrypt_block(ct)
elif self.mode == Mode.CBC:
X = self.IV
for ct in blocks:
msg += self._xor(self.decrypt_block(ct), X)
X = ct
return msg
```
chỉ cần chạy đoạn code trên và lấy flag thôi!!!
## Tsayaki
source.py
```python=
from tea import Cipher as TEA
from secret import IV, FLAG
import os
ROUNDS = 10
def show_menu():
print("""
============================================================================================
|| I made this decryption oracle in which I let users choose their own decryption keys. ||
|| I think that it's secure as the tea cipher doesn't produce collisions (?) ... Right? ||
|| If you manage to prove me wrong 10 times, you get a special gift. ||
============================================================================================
""")
def run():
show_menu()
server_message = os.urandom(20)
print(f'Here is my special message: {server_message.hex()}')
used_keys = []
ciphertexts = []
for i in range(ROUNDS):
print(f'Round {i+1}/10')
try:
ct = bytes.fromhex(input('Enter your target ciphertext (in hex) : '))
assert ct not in ciphertexts
for j in range(4):
key = bytes.fromhex(input(f'[{i+1}/{j+1}] Enter your encryption key (in hex) : '))
assert len(key) == 16 and key not in used_keys
used_keys.append(key)
cipher = TEA(key, IV)
enc = cipher.encrypt(server_message)
if enc != ct:
print(f'Hmm ... close enough, but {enc.hex()} does not look like {ct.hex()} at all! Bye...')
exit()
except:
print('Nope.')
exit()
ciphertexts.append(ct)
print(f'Wait, really? {FLAG}')
if __name__ == '__main__':
run()
```
Challenge này sử dụng TEA đã được nói đến ở chall trước.
Việc chúng ta cần làm là gửi đến `target ciphertext`. Sau đó gửi 4 key liên tiếp sao cho chúng mã hóa `server_mesage` thành `target ciphertext`. Vượt qua được 10 rounds thì lụm flag.
Đọc [link](https://www.tayloredge.com/reference/Mathematics/VRAndem.pdf) này mình đã tìm ra cách xử lí. Ở phần 3.5 **Equivalent Key**
Đây là trường hợp các khóa tương đương của mã hóa TEA. Từ một khóa ban đầu ta có thể tạo thêm được 3 khóa tương đương. Nghĩa là nếu cùng sử dụng 4 khóa này thì sẽ cho ra cũng một ciphertext.

Đầu tiên mình cần tìm được IV để lấy `target ciphertext`.
Giả sử ta gửi đến server một `key` và `target ciphertext` lại sai (lúc này đã biết được ciphertext đâu). Thì server sẽ trả về cho ta ciphertext sau khi mã hóa `plaintext` của server.
Cùng nhìn lại hàm decrypt:
```python
def decrypt(self, ct):
blocks = [ct[i:i+self.BLOCK_SIZE//8] for i in range(0, len(ct), self.BLOCK_SIZE//8)]
msg = b''
if self.mode == Mode.ECB:
for ct in blocks:
msg += self.decrypt_block(ct)
elif self.mode == Mode.CBC:
X = self.IV
for ct in blocks:
msg += self._xor(self.decrypt_block(ct), X)
X = ct
return msg
```
Ta chỉ cần lấy `msg` xor lại với `ct` thì có IV.
```python=
c = bytes.fromhex("8c0acbde4a1af63579313db874ab79a991fbaad4a459e4a5")
key = bytes.fromhex("9d6e095e19614e4f0bade6546f99d105")
msg = bytes.fromhex("0bc8f872e85a549c9815e69e1be5774631837362")
cipher = Cipher(key)
from pwn import xor
block1 = cipher.decrypt(c[:8])
iv = xor(block1, msg[:8])
print(iv)
# iv = b'\r\xdd\xd2w<\xf4\xb9\x08'
```
Tiếp đến mình viết hàm để tạo thành các key tương đương:
```python=
CONST = bytes.fromhex("80000000")
def gen_key():
keys = []
key = os.urandom(16)
key1, key2, key3, key4 = [key[i:i+4] for i in range(0, 16, 4)]
keys = [
b''.join([key1, key2, key3, key4]),
b''.join([key1, key2, xor(key3, CONST), xor(key4, CONST)]),
b''.join([xor(key1, CONST), xor(key2, CONST), key3 , key4 ]),
b''.join([xor(key1, CONST), xor(key2, CONST), xor(key3, CONST), xor(key4, CONST)])
]
return keys
```
**script**
```python=
import os
from Crypto.Util.Padding import pad, unpad
from Crypto.Util.number import bytes_to_long as b2l, long_to_bytes as l2b
from enum import Enum
class Mode(Enum):
ECB = 0x01
CBC = 0x02
class Cipher:
def __init__(self, key, iv=None):
self.BLOCK_SIZE = 64
self.KEY = [b2l(key[i:i+self.BLOCK_SIZE//16]) for i in range(0, len(key), self.BLOCK_SIZE//16)]
self.DELTA = 0x9e3779b9
self.IV = iv
if self.IV:
self.mode = Mode.CBC
else:
self.mode = Mode.ECB
def _xor(self, a, b):
return b''.join(bytes([_a ^ _b]) for _a, _b in zip(a, b))
def encrypt(self, msg):
msg = pad(msg, self.BLOCK_SIZE//8)
blocks = [msg[i:i+self.BLOCK_SIZE//8] for i in range(0, len(msg), self.BLOCK_SIZE//8)]
ct = b''
if self.mode == Mode.ECB:
for pt in blocks:
ct += self.encrypt_block(pt)
elif self.mode == Mode.CBC:
X = self.IV
for pt in blocks:
enc_block = self.encrypt_block(self._xor(X, pt))
ct += enc_block
X = enc_block
return ct
def encrypt_block(self, msg):
m0 = b2l(msg[:4])
m1 = b2l(msg[4:])
K = self.KEY
msk = (1 << (self.BLOCK_SIZE//2)) - 1
s = 0
for i in range(32):
s += self.DELTA
m0 += ((m1 << 4) + K[0]) ^ (m1 + s) ^ ((m1 >> 5) + K[1])
m0 &= msk
m1 += ((m0 << 4) + K[2]) ^ (m0 + s) ^ ((m0 >> 5) + K[3])
m1 &= msk
m = ((m0 << (self.BLOCK_SIZE//2)) + m1) & ((1 << self.BLOCK_SIZE) - 1) # m = m0 || m1
return l2b(m)
def decrypt_block(self, ct):
c0 = b2l(ct[:4])
c1 = b2l(ct[4:])
K = self.KEY
msk = (1 << (self.BLOCK_SIZE//2)) - 1
s = 0xC6EF3720
for i in range(32):
c1 -= ((c0 << 4) + K[2]) ^ (c0 + s) ^ ((c0 >> 5) + K[3])
c1 &= msk
c0 -= ((c1 << 4) + K[0]) ^ (c1 + s) ^ ((c1 >> 5) + K[1])
c0 &= msk
s -= self.DELTA
c = ((c0 << (self.BLOCK_SIZE//2)) + c1) & ((1 << self.BLOCK_SIZE) - 1)
return l2b(c)
def decrypt(self, ct):
blocks = [ct[i:i+self.BLOCK_SIZE//8] for i in range(0, len(ct), self.BLOCK_SIZE//8)]
msg = b''
if self.mode == Mode.ECB:
for ct in blocks:
msg += self.decrypt_block(ct)
elif self.mode == Mode.CBC:
X = self.IV
for ct in blocks:
msg += self._xor(self.decrypt_block(ct), X)
X = ct
return msg
from pwn import remote, xor
import os
CONST = bytes.fromhex("80000000")
IV = b'\r\xdd\xd2w<\xf4\xb9\x08'
def gen_key():
keys = []
key = os.urandom(16)
key1, key2, key3, key4 = [key[i:i+4] for i in range(0, 16, 4)]
keys = [
b''.join([key1, key2, key3, key4]),
b''.join([key1, key2, xor(key3, CONST), xor(key4, CONST)]),
b''.join([xor(key1, CONST), xor(key2, CONST), key3 , key4 ]),
b''.join([xor(key1, CONST), xor(key2, CONST), xor(key3, CONST), xor(key4, CONST)])
]
return keys
io = remote('83.136.254.223', 32915)
io.recvuntil(b'Here is my special message:')
server_message = io.recvuntil(b'\n', drop = True).decode()
def payload(key):
cipher = Cipher(key, IV)
enc = cipher.encrypt(bytes.fromhex(server_message))
return enc.hex()
for i in range(10):
keys = gen_key()
io.recvuntil(b'Enter your target ciphertext (in hex) : ')
io.sendline(payload(keys[0]).encode())
for key in keys:
io.recvuntil(b'Enter your encryption key (in hex) : ')
io.sendline(key.hex().encode())
io.recvlines()
```
## Partial Tenacity
source.py
```python=
from secret import FLAG
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
class RSACipher:
def __init__(self, bits):
self.key = RSA.generate(bits)
self.cipher = PKCS1_OAEP.new(self.key)
def encrypt(self, m):
return self.cipher.encrypt(m)
def decrypt(self, c):
return self.cipher.decrypt(c)
cipher = RSACipher(1024)
enc_flag = cipher.encrypt(FLAG)
with open('output.txt', 'w') as f:
f.write(f'n = {cipher.key.n}\n')
f.write(f'ct = {enc_flag.hex()}\n')
f.write(f'p = {str(cipher.key.p)[::2]}\n')
f.write(f'q = {str(cipher.key.q)[1::2]}')
```
output.txt
```
n = 118641897764566817417551054135914458085151243893181692085585606712347004549784923154978949512746946759125187896834583143236980760760749398862405478042140850200893707709475167551056980474794729592748211827841494511437980466936302569013868048998752111754493558258605042130232239629213049847684412075111663446003
ct = 7f33a035c6390508cee1d0277f4712bf01a01a46677233f16387fae072d07bdee4f535b0bd66efa4f2475dc8515696cbc4bc2280c20c93726212695d770b0a8295e2bacbd6b59487b329cc36a5516567b948fed368bf02c50a39e6549312dc6badfef84d4e30494e9ef0a47bd97305639c875b16306fcd91146d3d126c1ea476
p = 151441473357136152985216980397525591305875094288738820699069271674022167902643
q = 15624342005774166525024608067426557093567392652723175301615422384508274269305
```
Đọc đoạn code trên mình nhận thấy p và q đã bị khuyết các số. Nó kiểu như này:
```python=
leak_p = "1?5?1?4?4?1?4?7?3?3?5?7?1?3?6?1?5?2?9?8?5?2?1?6?9?8?0?3?9?7?5?2?5?5?9?1?3?0?5?8?7?5?0?9?4?2?8?8?7?3?8?8?2?0?6?9?9?0?6?9?2?7?1?6?7?4?0?2?2?1?6?7?9?0?2?6?4?3"
leak_q = "?1?5?6?2?4?3?4?2?0?0?5?7?7?4?1?6?6?5?2?5?0?2?4?6?0?8?0?6?7?4?2?6?5?5?7?0?9?3?5?6?7?3?9?2?6?5?2?7?2?3?1?7?5?3?0?1?6?1?5?4?2?2?3?8?4?5?0?8?2?7?4?2?6?9?3?0?5?"
```
Cách mà mình hay sử dụng để giải quyết các bài kiểu như thế này đó chính là dựa vào:
- Cho 2 số a, b với a*b = n, ta có:
Số chữ số cuối của a * số chữ số cuối của b = số chữ số cuối của n.
**script:**
```python=
from Crypto.Util.number import long_to_bytes
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
# p = "151441473357136152985216980397525591305875094288738820699069271674022167902643"
# leak_p = ''
# for i in p:
# leak_p += i + '?'
# q = "15624342005774166525024608067426557093567392652723175301615422384508274269305"
# leak_q = ''
# for i in q:
# leak_q += '?' + i
# print(leak_p)
# print(leak_q)
leak_p = "1?5?1?4?4?1?4?7?3?3?5?7?1?3?6?1?5?2?9?8?5?2?1?6?9?8?0?3?9?7?5?2?5?5?9?1?3?0?5?8?7?5?0?9?4?2?8?8?7?3?8?8?2?0?6?9?9?0?6?9?2?7?1?6?7?4?0?2?2?1?6?7?9?0?2?6?4?3"
leak_q = "?1?5?6?2?4?3?4?2?0?0?5?7?7?4?1?6?6?5?2?5?0?2?4?6?0?8?0?6?7?4?2?6?5?5?7?0?9?3?5?6?7?3?9?2?6?5?2?7?2?3?1?7?5?3?0?1?6?1?5?4?2?2?3?8?4?5?0?8?2?7?4?2?6?9?3?0?5?"
n = 118641897764566817417551054135914458085151243893181692085585606712347004549784923154978949512746946759125187896834583143236980760760749398862405478042140850200893707709475167551056980474794729592748211827841494511437980466936302569013868048998752111754493558258605042130232239629213049847684412075111663446003
ct = "7f33a035c6390508cee1d0277f4712bf01a01a46677233f16387fae072d07bdee4f535b0bd66efa4f2475dc8515696cbc4bc2280c20c93726212695d770b0a8295e2bacbd6b59487b329cc36a5516567b948fed368bf02c50a39e6549312dc6badfef84d4e30494e9ef0a47bd97305639c875b16306fcd91146d3d126c1ea476"
e = 65537
def guess(a, b, i, p, q):
conditon = 1
if b == '?':
a, b = b, a
p, q = q, p
conditon = 0
for _ in range(10):
if str(int(str(_) + str(p)) * int(str(b) + str(q)))[-i:] == str(n)[-i:]:
a = str(_)
break
if conditon:
return a + p, b + q
else:
return b + q, a + p
p = ''
q = ''
index = 1
for i, j in zip(leak_p[::-1], leak_q[::-1]):
p, q = guess(i, j, index, p, q)
index += 1
p = int(p)
q = int(q)
assert p * q == n
phi = (p-1)*(q-1)
d = pow(e, -1, phi)
private_key = RSA.construct([n, e, d])
cipher = PKCS1_OAEP.new(private_key)
m = cipher.decrypt(bytes.fromhex(ct))
print(m)
```