Skip to content

Instantly share code, notes, and snippets.

@acheong08
Created January 12, 2026 16:38
Show Gist options
  • Select an option

  • Save acheong08/59dd6d97eb9c2914407014118f53c2b8 to your computer and use it in GitHub Desktop.

Select an option

Save acheong08/59dd6d97eb9c2914407014118f53c2b8 to your computer and use it in GitHub Desktop.
HackEurope CTF Challenge writeup. Here for proof

HackEurope CTF Challenge Writeup

Challenge Overview

This challenge involves finding a hidden SSH server, logging in, and solving a cryptography puzzle to obtain the flag.

Step 1: Finding the Hidden Challenge

Clues in HTML Files

registration.html contains two hints:

  1. The placeholder for the code is hack2026 in the registration form.
  2. Lines 91-93: A comment revealing the username:
    <!--
    User: applicant
    Maybe I should try and look for an IP address?
    -->

hackeurope.com.html reveals the SSH server IP address 13.61.140.249 in its ASCII art banner.

SSH Credentials

  • Host: 13.61.140.249
  • Username: applicant
  • Password: hack2026

Step 2: The Cryptography Challenge

After SSH login, you find report.txt containing:

transmitted first - 5
alice = 105809507955850449608538293817470449109
bob = 55938997548049651744678882539014889077
m = 315971781879435631453266619927156525572
something seems off....

ciphertext = b'\xc4\xdd\xb8\\...' (42 bytes)

This is a Diffie-Hellman key exchange problem:

  • g = 5 (generator, "transmitted first")
  • alice = g^a mod m (Alice's public key)
  • bob = g^b mod m (Bob's public key)
  • m = modulus

Step 3: The Vulnerability

The hint "something seems off" refers to the modulus m being composite, not prime:

m = 2² × 3 × 7 × 83 × 20023 × 69828291110269 × 32413830721955773

In secure Diffie-Hellman, the modulus should be a large prime. A composite modulus makes the discrete logarithm problem solvable using the Pohlig-Hellman algorithm.

Step 4: Solving the Discrete Log

Using Python's sympy library:

from sympy.ntheory import discrete_log

g = 5
alice = 105809507955850449608538293817470449109
m = 315971781879435631453266619927156525572

# Find Alice's private key
a = discrete_log(m, alice, g)
# Result: a = 17396215127836868879

Step 5: Computing the Shared Secret

bob = 55938997548049651744678882539014889077

shared_secret = pow(bob, a, m)
# Result: 187072517503334265819838342125691547249

Step 6: Decrypting the Flag

The encryption is XOR using the raw 16-byte big-endian representation of the shared secret:

ciphertext = b'\xc4\xdd\xb8\\\xbb\xe0u\xe7\xd2\xeb\x1a\xf6\xb6\xd7K\x03\xd3\xd1\xbeh\x97\xfbs\xe7\xfd\xef\x11\xe3\x87\xc0A\x15\xe9\xe3\xe9\x04\xc7\xfb6\xe6\xc3\xf3'

key = shared_secret.to_bytes(16, 'big')
plaintext = bytes([c ^ key[i % len(key)] for i, c in enumerate(ciphertext)])

Flag

HackEurope{enter_me_into_app_code_239n1na}

Solution Script

#!/usr/bin/env python3
from sympy.ntheory import discrete_log

# Given values
g = 5
alice = 105809507955850449608538293817470449109
bob = 55938997548049651744678882539014889077
m = 315971781879435631453266619927156525572
ciphertext = b'\xc4\xdd\xb8\\\xbb\xe0u\xe7\xd2\xeb\x1a\xf6\xb6\xd7K\x03\xd3\xd1\xbeh\x97\xfbs\xe7\xfd\xef\x11\xe3\x87\xc0A\x15\xe9\xe3\xe9\x04\xc7\xfb6\xe6\xc3\xf3'

# Solve discrete log (possible due to composite modulus)
a = discrete_log(m, alice, g)
print(f"Private key a = {a}")

# Compute shared secret
shared_secret = pow(bob, a, m)
print(f"Shared secret = {shared_secret}")

# Decrypt with XOR
key = shared_secret.to_bytes(16, 'big')
flag = bytes([c ^ key[i % len(key)] for i, c in enumerate(ciphertext)])
print(f"Flag: {flag.decode()}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment