Загрузка данных
import socket
import json
import re
HOST = 'tasks.duckerz.ru'
PORT = 30009
def solve_math(expr):
"""Решает математическое выражение вида '123 + 456' или '123*456'."""
expr = expr.replace(' ', '')
# Ищем числа и оператор
match = re.match(r'^(\d+)([\+\-\*\/])(\d+)$', expr)
if not match:
return None
a, op, b = match.groups()
a, b = int(a), int(b)
if op == '+': return a + b
if op == '-': return a - b
if op == '*': return a * b
if op == '/': return a // b
return None
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
# Получаем первое сообщение (от Алисы)
data = s.recv(4096).decode('utf-8').strip()
print(f"[*] Получено от Алисы: {data}")
# Парсим JSON из строки
json_match = re.search(r'\{.*\}', data)
if not json_match:
print("[-] Не удалось найти JSON в сообщении")
return
alice_data = json.loads(json_match.group())
p = int(alice_data['p'], 16)
g = int(alice_data['g'], 16)
A = int(alice_data['A'], 16)
print(f"[*] p = {p}")
print(f"[*] g = {g}")
print(f"[*] A (Alice) = {A}")
# Наш приватный ключ (может быть любым числом)
c = 1337
# Наш публичный ключ для отправки
C = pow(g, c, p)
# Отправляем Бобу наш ключ (подменяем Алису)
# Предполагаем, что сервер ждет JSON в таком же формате, либо просто hex-строку.
# Обычно в таких задачах формат ответа: {"C": "0x..."} или просто число.
# Попробуем отправить JSON, если не сработает - отправим просто hex.
payload = json.dumps({"C": hex(C)})
print(f"[*] Отправляем Бобу наш ключ: {payload}")
s.sendall((payload + "\n").encode())
# Получаем ответ от Боба
data2 = s.recv(4096).decode('utf-8').strip()
print(f"[*] Получено от Боба: {data2}")
# Ищем hex-число в ответе (публичный ключ Боба)
hex_match = re.search(r'0x[0-9a-fA-F]+', data2)
if not hex_match:
print("[-] Не удалось найти публичный ключ Боба")
return
B = int(hex_match.group(), 16)
print(f"[*] B (Bob) = {B}")
# Вычисляем общий секрет с Бобом
S_bob = pow(B, c, p)
print(f"[*] Общий секрет S_bob = {S_bob}")
# Отправляем Алисе наш ключ (подменяем Боба)
# Если сервер ждет просто число, а не JSON, поменяй формат ниже.
payload_alice = json.dumps({"C": hex(C)})
print(f"[*] Отправляем Алисе наш ключ: {payload_alice}")
s.sendall((payload_alice + "\n").encode())
# Дальше начинается цикл обмена зашифрованными сообщениями
s.settimeout(3.0)
while True:
try:
data3 = s.recv(4096).decode('utf-8').strip()
if not data3:
break
print(f"[*] Получено: {data3}")
# Пытаемся найти зашифрованное выражение (обычно это hex)
# Предполагаем, что шифрование - это XOR с секретом или просто сложение.
# Часто в таких CTF используется XOR.
# Ищем hex-строку
hex_match = re.search(r'0x[0-9a-fA-F]+', data3)
if hex_match:
encrypted_hex = hex_match.group()
encrypted_int = int(encrypted_hex, 16)
# Пробуем расшифровать XOR с секретом S_bob
# (Секрет может быть огромным, но XOR работает побитово)
decrypted_int = encrypted_int ^ S_bob
# Преобразуем обратно в строку
try:
decrypted_str = decrypted_int.to_bytes((decrypted_int.bit_length() + 7) // 8, 'big').decode('utf-8')
print(f"[*] Расшифровано: {decrypted_str}")
# Если это математическое выражение
if re.search(r'\d+[\+\-\*\/]\d+', decrypted_str):
result = solve_math(decrypted_str)
if result is not None:
print(f"[*] Решаем: {decrypted_str} = {result}")
# Шифруем ответ обратно
enc_result = result ^ S_bob
# Отправляем (формат может быть hex или просто число)
s.sendall((hex(enc_result) + "\n").encode())
print(f"[*] Отправлен ответ: {hex(enc_result)}")
# Если в ответе был флаг, выводим его
if "DUCKERZ{" in decrypted_str:
print(f"\n[!!!] ФЛАГ НАЙДЕН: {decrypted_str}\n")
break
except Exception as e:
# Если не XOR, возможно это простое сложение/вычитание
pass
# Если флаг уже в открытом виде
if "DUCKERZ{" in data3:
print(f"\n[!!!] ФЛАГ НАЙДЕН: {data3}\n")
break
except socket.timeout:
print("[-] Таймаут. Сервер не отвечает.")
break
except Exception as e:
print(f"[-] Ошибка: {e}")
break
if __name__ == '__main__':
main()