Cyberleague 2025
Uncover Me
Forensics | Pre-CTF
Uncover me!
fcrackzip -D -p rockyou.txt -v -u hello_there.zip
The password is 2hot4u
└─$ CYBERLEAGUE{Y0U_Fo|_|nD_3e!}
Baby LCG
Crypto | Pre-CTF
I just started learning about LCG!
Unfortunately, it seems that LCG is quite weak, given how there are so many papers showing how easily you can crack LCG parameters.
Findings from the given source file:
An AES-CBC encrypted ciphertext with its IV
The modulus and three terms (19th, 38th, and 57th) from a Linear Congruential Generator (LCG)
The 1st term of the LCG serves as the AES encryption key
The solution approach is to reverse the given LCG numbers to get the initial term for the decryption key. Here is a good read on LCG Attack : https://msm.lt/posts/cracking-rngs-lcgs/
The LCG generator is defined by the recurrence relation:
What makes this challenge unique is that instead of consecutive terms, we're given values at fixed intervals of 19. However, this property can still be exploited to recover the initial seed.
For any LCG sequence, we can express terms with fixed intervals using the same coefficient structure. Consider the following relations:
Notice that despite the gaps between terms, the coefficient patterns remain consistent at equal intervals. We can apply this principle to our given terms , and to determine the coefficients needed to calculate the initial term .
Here is the solution script:
from Crypto.Util.number import long_to_bytes
from Crypto.Util.Padding import unpad
from Crypto.Cipher import AES
from sympy import mod_inverse
import functools
import binascii
import math
R19 = 101273243801089515795834486273327091034
R38 = 142935056647570887854437422902380586165
R57 = 63472453299747839124695261376587470430
mod = 206448685018571863403655106945756783931
# https://ctftime.org/writeup/12046
reduce = functools.reduce
gcd = math.gcd
def crack_unknown_increment(states, modulus, multiplier):
increment = (states[1] - states[0]*multiplier) % modulus
return multiplier, increment
def crack_unknown_multiplier(states, modulus):
multiplier = (states[2] - states[1]) * mod_inverse(states[1] - states[0], modulus) % modulus
return crack_unknown_increment(states, modulus, multiplier)
# Getting the (a) coefficent & (c) coefficient
mult, inc = crack_unknown_multiplier([R19, R38, R57], mod)
# Calculate the key and decrypt the ciphertext
key = (mod_inverse(mult, mod) * (R19 - inc)) % mod
ct = binascii.unhexlify(b'6e573d15e915e7d9a321b77bec1f21ebcbfddd1755b216f6971ac5382f6d787836dd1397fea445ed453fd6a12bd610b103affdc17334e923b0f4d6856c716488')
iv = binascii.unhexlify(b'e1735ebc3148a450327887b2186ffa61')
cipher = AES.new(long_to_bytes(key), AES.MODE_CBC, iv)
decrypted_data = cipher.decrypt(ct)
print(decrypted_data.decode())
└─$ CYBERLEAGUE{LCG_W1th_N0n-C0n53cu71v3_0u7pu7_15_57111_W34k!}
Baby PCAP
Forensics
I want to be like the cool kids, so I got chatGPT to write me a custom DNS C2 framework!

Findings from the given capture.pcap
file:
DNS query with appended base64 string
exfil.py
Grab the decrypt function from exfil.py
and decrypt the found base64 string.
import base64
def decrypt(data, key="Sup3rS3cur3P@ssW0Rd!!!"):
key_length = len(key)
decoded_data = base64.b64decode(data)
decrypted_result = bytes(
b ^ ord(key[i % key_length]) for i, b in enumerate(decoded_data))
return decrypted_result.decode('utf-8', errors='ignore')
strings = ["ECwydiAfdiIyJ3YrIhIRLm8lBVNMVCMqA0cdPVgQKkoKZCUZFT9DOAFEUFw="]
for i in strings:
print(decrypt(i))
└─$ CYBERLEAGUE{baby_warmup_stonks_894ejfhsjeeq}
Log Analysis 1
Misc
Strange traffics were observed at endpoint "supersecure". Just what is going on in the network?
HTTP requests with the f1a9
query string were observed in the given log file, e.g.
POST /supersecure/search.jsp?f1a9=43
Simple extract all the values from the query string using the below command and unhex.
grep -o 'f1a9...' log_challenge.log | sed 's/f1a9=//'
└─$ CYBERLEAGUE{l0gs_R_b0RiNg}
One Time Pin
Crypto
Crack the pin!
The program takes a pin and return the difference of the input pin and the random generated num.
Welcome Admin!
Please enter your 8-char one time pin to continue [00000000 - ffffffff]:0
Error 0x1a6bfcc8: Incorrect PIN.Welcome Admin!
Please enter your 8-char one time pin to continue [00000000 - ffffffff]:0
Error 0x6114cfe9: Incorrect PIN.Welcome Admin!
Please enter your 8-char one time pin to continue [00000000 - ffffffff]:0
Error 0x33665050: Incorrect PIN.Welcome Admin!
pin = await read_pin(reader, writer)
num = rand.randrange(2**32 - 1)
if pin != num:
delta = abs(pin - num)
writer.write(f"Error {hex(delta)}: Incorrect PIN.".encode())
Since the program does not reset the seed and it is known that the random
module from python is not cryptographically secure, we can simply crack it using the randcrack
module by submitting the generated numbers.
import random
from randcrack import RandCrack
from pwn import *
import re
## https://github.com/tna0y/Python-random-module-cracker
server_address = ('xx.xxx.xxx.xxx', 10008)
r = remote(*server_address)
rc = RandCrack()
for i in range(624):
r.sendline("0")
response = r.recvuntil("Incorrect PIN").decode()
pattern = r"Error 0x([a-fA-F0-9]{1,8}): Incorrect PIN"
match = re.search(pattern, response)
print(i)
rc.submit(int(match.group(1), 16))
predict = rc.predict_randrange(0, 4294967295)
r.sendline(hex(predict))
response = r.recvuntil("}").decode()
print(response)
r.close()
└─$ CYBERLEAGUE{r@nd0m_15_d3t3rmIn1St1c}
Pool Party
OSINT
Important message from the organisers of FlagIsland:
Please be at this location in 48 hours with your ticket ready. Transport will be arranged to take you to the event. Due to the short notice, we'll throw in an additional hint: it's less than 5km off the coast of the cotton state ;)
The flag is CYBERLEAGUE{phone_number_of_the_estate}
E.g. CYBERLEAGUE{111-111-1111}
Note: No contact with real people or entities is required to solve this challenge.

Based on the given challenge description and image, we can tell that:
The location is near the coast of Alabama
Possibly an apartment complex featuring a swimming pool
I simply search for apartments near the coast around Alabama and ta-da:

It is definitely a better choice to use Overpass Turbo instead...
└─$ CYBERLEAGUE{251-625-8585}
Last updated