Загрузка данных


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()