Tags: cryptography
Rating:
# N0PS CTF 2025 - Key Exchange Writeup
**Category**: CrypTopia
**Challenge Name**: Key Exchange
**Flag**: ✅ `N0PS{d1fFi3_h31lm4n_k3y_XcH4ng3}`
**Author**: algorab
---
## Challenge Description
We’re given a connection endpoint to a secret service belonging to CrypTopia:
```
nc 0.cloud.chals.io 26625
```
The challenge implies that if we manage to speak the right language to this service, it will reward us with the flag. The format is `N0PS{...}`. No additional hints — just the address and an attached Python script.
---
Naturally, I started by connecting to the server using netcat to see what kind of response it gives:
```
nc 0.cloud.chals.io 26625
```
As expected, I was greeted with a screen full of binary garbage. This was a clear sign that the server is expecting a binary-level protocol, not plain text.

. The file was named `main.py` given , and it contained the core logic running on the server.
---
## Code Breakdown
The script performs a Diffie-Hellman key exchange followed by AES encryption of a flag file. Here's a brief summary:
- The server generates a safe prime `p` and a generator `g`.
- It calculates `k_a = g^a mod p` where `a` is a random private key.
- It sends `p`, `g`, and `k_a` to the client.
- The client is expected to respond with `k_b = g^b mod p`.
- Both parties compute the shared secret key `k = g^(ab) mod p`.
- The server uses `SHA-256(k)` as an AES key to encrypt the flag and send it back.
---
## Realization
What we had here was a textbook example of a **Diffie-Hellman key exchange** implemented in a CTF setting. The goal is to mirror the server’s steps, perform the math on our side, and decrypt the flag ourselves.
To solve it, I needed to:
1. Parse the 1024-byte `p`, `g`, and `k_a` values sent by the server.
2. Generate a private `b`, compute `k_b`, and send it back.
3. Receive the AES-encrypted flag.
4. Derive the same shared key and decrypt the ciphertext.
---
## Building the Exploit Script
To automate this, I wrote a Python script using `socket`, `Crypto`, and `hashlib` libraries. One important note: the server sends 1024 **bytes**, not bits — I initially messed this up and got all zeroes for `p`, `g`, and `k_a`.
Once that was corrected, everything lined up.

---
## Decryption & Discovery
After decryption, the data didn't look like text, so I ran:
```
file decrypted_flag.bin
```
And saw this:
```
PNG image data, 4267 x 4267, 8-bit/color RGBA
```
---
converted it to the png file
```
mv decrypted_flag.bin flag.png
```
Bingo. The flag was embedded inside an image.
`decrypted_flag.bin: PNG image data, 4267 x 4267, 8-bit/color RGBA`
I opened the file and found the flag painted on top of a shiny treasure chest.

---
## ? Final Flag
```
N0PS{d1fFi3_h31lm4n_k3y_XcH4ng3}
```
---
Team N0C71S