DiceCTF2026 – Good Vibes [ Forensics ]
Full solution and analysis of the DiceCTF "Good Vibes" challenge involving reversing a custom VPN client and decrypting AES-GCM traffic.
Challenge Overview
operating on good vibes has no real consequences… surely…
The challenge provides two files:
1
2
3
4
challenge.pcap
vibepn-client
Our goal is to analyze the network traffic and recover the hidden flag.
Step 1 — Inspecting the PCAP
Opening the capture in Wireshark reveals two different phases of communication.
Phase 1 – Plaintext Chat
The first communication occurs over:
1
2
3
TCP/6767
Following the TCP stream reveals a conversation between two operators.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
hi
hi
did anyone tell you you're an idiot
what
did you not get the memo
use the damn vpn#
what's a vpn
how do you not
ok
what
how are you so stupid
whatever
i coded it myself so its super secure
i'm sure it is
i dont want your sarcasm
you got one of us killed before, i dont want another incident.
just like [https://gofile.io/d/l6XqnD](https://gofile.io/d/l6XqnD)
you know the rest
is this malware??
what the
i give up with you
only speak to me over the vpn from now on
This conversation tells us two important things:
- Their previous communications were exposed.
- They decide to switch to a custom VPN.
Immediately after this chat ends, we see new traffic.
Step 2 — Suspicious UDP Traffic
The new traffic appears on:
1
2
3
UDP/5959
Inspecting the packets reveals a consistent structure.
1
2
3
0xbe <type> <length> <sequence> ...
From observing the capture we can infer the protocol:
| Type | Meaning |
|---|---|
| 0x01 | HELLO |
| 0x02 | CHALLENGE |
| 0x03 | RESPONSE |
| 0x04 | ESTABLISHED |
| 0x10 | encrypted data |
This traffic likely originates from the provided binary:
1
2
3
vibepn-client
To decrypt the tunnel we must reverse this client.
Step 3 — Reversing vibepn-client
Running strings on the binary reveals debugging messages:
1
strings vibepn-client
Important output:
1
2
3
4
[client] Starting handshake...
[client] Sent HELLO
[client] Sent RESPONSE
[client] Session ESTABLISHED! Tunnel is active.
The binary also imports OpenSSL encryption functions:
1
2
3
4
EVP_aes_256_gcm
EVP_EncryptInit_ex
EVP_DecryptInit_ex
RAND_bytes
So the VPN tunnel uses:
1
AES-256-GCM
At first glance this appears secure.
However, reversing the key generation function reveals a major flaw.
Step 4 — Key Derivation Bug
The session key is generated using the following function:
1
2
3
4
5
6
7
8
void vpn_derive_session_key(uint8_t key[32]) {
uint32_t x = time(NULL);
for (int i = 0; i < 32; i++) {
x = x * 0x19660D + 0x3C6EF35F;
key[i] = x & 0xff;
}
}
The key is derived from:
1
time(NULL)
This means the key depends only on the Unix timestamp of the handshake.
Since PCAP files store packet timestamps, we can recover this value.
Step 5 — Reconstructing the Session Key
From the PCAP we locate the CHALLENGE packet (type = 0x02).
The packet timestamp gives us the handshake time.
Using that timestamp as the seed we reproduce the key.
1
2
3
4
5
6
7
8
9
def derive_key(seed):
x = seed
key = []
for i in range(32):
x = (x * 0x19660D + 0x3C6EF35F) & 0xffffffff
key.append(x & 0xff)
return bytes(key)
This recreates the AES-256-GCM session key used by the VPN.
Step 6 — Decrypting VPN Packets
Tunnel packets contain encrypted payloads.
Packet layout:
1
2
3
4
nonce = packet[8:20]
ciphertext = packet[20:-16]
tag = packet[-16:]
AAD = first 20 bytes
Using AES-GCM we can decrypt the payload.
1
2
3
4
from Crypto.Cipher import AES
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
Running this against the encrypted packets reveals the tunneled data.
Step 7 — Recovering the Flag
After decrypting the VPN traffic we recover plaintext messages including the flag:
1
dice{y0u_sh0uld_alw@ys_vib3_y0ur_vpns_82bc3}
Final Flag
1
dice{y0u_sh0uld_alw@ys_vib3_y0ur_vpns_82bc3}
Attack Chain Summary
- Analyze the PCAP in Wireshark.
- Identify plaintext chat over TCP.
- Observe switch to custom VPN traffic.
- Reverse the
vibepn-clientbinary. - Identify AES-256-GCM encryption.
- Discover the key is derived from
time(NULL). - Reconstruct the key using the packet timestamp.
- Decrypt VPN traffic and extract the flag.
Key Lesson
Never roll your own crypto.
Although the VPN used strong encryption:
1
AES-256-GCM
the security completely failed because the key was generated from a predictable value:
1
time(NULL)
With access to the packet capture, an attacker can reconstruct the session key and decrypt all traffic.
This challenge perfectly demonstrates why custom cryptographic protocols are dangerous.
```