CDDC 2025
Reassemble The Pieces
Network | Qualifier
Extract H.264 video payloads from RTP packets in a .pcap
file using rtp_h264_extractor.lua.

└─$CDDC2025{5tr3@m1ng_53rv1ce35_u53_th3_RT5P_pr0t0c01}
Break the ECDSA
Cryptography | Qualifier
The overall solution is:
Using given signatures to compute the private key using ECDSA Nonce Reuse Attack
Brute-force candidate 12-word BIP-39 mnemonics from the given dictionary, derive their corresponding private keys using
bip32utils
and compare them against the recovered key
from ecdsa.numbertheory import inverse_mod
from itertools import product
import mnemonic
import bip32utils
# Provided constants
r = 81210355722750344493541519494641458710145722871994877785183554697310523407018
h1 = 45643200378651069483892104393394606812504455659831083323743202489147422538955
h2 = 74831345439009646272332597737070016777412939113737083148228963710487431876647
s1 = 110764343964105699917226529930289538481215574456544978805357332521308340464732
s2 = 90138993253633063487274662700800979929978777245182171200537527514756442604713
# SECP256k1 curve order
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
# Step 1: Recover the private key
numerator = (s2 * h1 - s1 * h2) % N
denominator = inverse_mod(r * ((s1 - s2) % N), N)
private_key = hex((numerator * denominator) % N)
print(f"[+] Recovered Private Key:\n{private_key}")
# 0x9f9068a0cc25f39b9c5fba5bb88d75bc5e4503a8406101a3195dc395194ea690
# Step 2: Brute-force message
words = [
"v1ew", "5tr0ng", "app1e", "fr13nd", "7hank5", "sch00l", "c0d3", "kn0w1edg3", "g00d",
"b4d", "dr34m", "r1v3r", "mou7a1n", "f0r3st", "5kyb1u3", "p14n3t", "c4r", "b1k3", "b00k",
"5tor3", "l4ugh", "sm1l3", "v1ct0ry", "p0w3r", "3n3rgy", "7r4v3l", "p3ac3", "f1gh7", "h0p3",
"4n7", "1i0nkin9", "7ig3r", "p4d0c0in", "0c34n", "w4v3", "5h0r3", "c4v3", "m00n", "5un",
"5tar", "7r33", "fl0w3r", "5e3d", "gr455", "b3", "4ir", "c10ud", "r41n", "5n0w", "5t0rm"
]
template = "BIP-39 SECP256k1 {} 5eed r4nd0m {} g00d 5olve c0ffe {} pe4nut 5mart"
print("[*] Brute-forcing possible message...")
m = mnemonic.Mnemonic('english')
found = False
for w1, w2, w3 in product(words, repeat=3):
msg = template.format(w1, w2, w3)
seed = m.to_seed(msg, passphrase="")
h = bip32utils.BIP32Key.fromEntropy(seed).PrivateKey().hex()
if h == private_key[2:]:
print(w1, w2, w3)
found = True
break
if not found:
print("[-] No match found.")
└─$CDDC2025{p4d0c0in_b3_5tr0ng_(private key in hex)}
DR0N3CAM
Network | Pre-CTF
Using a certain protocol, a drone was able to stream images through the network.
This challenge revolves around the Real-Time Streaming Protocol (RTSP), a network protocol commonly used to manage real-time streaming media applications and our goal is to analyze captured drone data and extract the hidden flag.
Given Files:
aaaaaa
abcdefg-01.cap
DRONE.apk
The DRONE.apk
file appeared to be the drone controller application responsible for streaming video from the drone. Running it on an Android emulator confirmed its role in managing the live video output.

The file aaaaaa
was identified as a sample of streamed data containing video frames. Running binwalk
on this file revealed multiple embedded JPEG images, which represent the individual video frames streamed from the drone.
└─$ binwalk aaaaaa
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
20 0x14 JPEG image data, JFIF standard 1.01
51 0x33 TIFF image data, big-endian, ...
5684 0x1634 JPEG image data, JFIF standard 1.01
5715 0x1653 TIFF image data, big-endian, ...
...
Next, I analyzed the network capture file abcdefg-01.cap
. Inspecting the packets revealed a protocol labeled "data"
carrying payloads of interest. Extracting the data
fields from these packets yielded several binary chunks.
Using binwalk
on these extracted binaries confirmed that they contained image frames matching those captured during the streaming session.
By reviewing these extracted images, I successfully found the flag hidden within the video frames.

└─$ CDDC2025{YOU_JUST_HACKED_CAM_DRONE_GOOD}
Last updated