National Cybersecurity Olympiad (NCO) 2025 - Practice Platform : Writeups
A month before the International Cybersecurity Olympiad (ICO) 2025, we got access to the National Cybersecurity Olympiad (NCO) 2025 as a practice platform. The NCO is a national-level competition in cybersecurity, and the practice platform provides a range of challenges to help participants prepare for the ICO.
Challenges (In no particular order)
Challenge | Category |
---|---|
Challenge 3 | Steganography |
Reverse Engineering | Reverse Engineering |
Mystery_1 | Forensics |
Mystery_2 | Forensics |
Mystery_3 | Forensics |
Analyse Packet II | Networking |
Pentest Challenge | Pentest |
Challenge 3
We were given 2 png files. Both of the images looked to be the same, but some pixels were different. The task was to find the difference between the two images.
Files:
We used the compare
command from the ImageMagick suite to find the differences between the two images. The command is as follows:
compare -metric AE Steganography1.png Steganography2.png difference.png
Result:
Flag: NCO2025{H@ck_F@st3r}
Reverse Engineering
We were given a binary file and the task was to reverse engineer it to find the flag.
File:
We use https://dogbolt.org/ to disassemble the binary file. The disassembly shows that the binary is checking for a password. The password is hardcoded in the binary, and we can find it by looking at the disassembly.
In the disassembly, we find the “check_password” function:
int64_t check_password(char* arg1)
{
void* fsbase;
int64_t rax = *(fsbase + 0x28);
int32_t var_7c = 0;
int32_t var_70 = 0x17;
int64_t var_48;
__builtin_strncpy(&var_48, " ", 0x21);
int64_t var_69;
__builtin_strcpy(&var_69, "tHardiCKET");
int64_t var_5e;
__builtin_strcpy(&var_5e, "HErAbIogYm");
int64_t var_53;
__builtin_strcpy(&var_53, "oRtumbaRVa");
strcat(&var_53, &var_69);
strcat(&var_53, &var_5e);
if (strlen(arg1) != strlen(&var_53))
puts("Invalid password! Access denied.");
else
{
int32_t var_78_1 = 0;
while (var_78_1 < strlen(arg1))
{
if (arg1[var_78_1] != *(&var_53 + var_78_1))
{
var_7c = 0;
break;
}
var_7c = 1;
var_78_1 += 1;
}
if (!var_7c)
puts("Invalid password! Access denied.");
else
{
puts("Password accepted! Access grante…");
int32_t var_74_1 = 0;
while (var_74_1 < strlen(&var_48) - 1)
{
*(&var_48 + var_74_1) = (*(&var_53 + var_74_1) - 0x4a) % 0x1a + 0x61;
var_74_1 += 1;
}
printf("The reverse engineer flag is'%s'…", &var_48);
}
}
if (rax == *(fsbase + 0x28))
return rax - *(fsbase + 0x28);
__stack_chk_fail();
/* no return */
}
If we enter the password oRtumbaRVatHardiCKETHErAbIogYm
into the binary, it will print the flag.
Flag: NCO2025{liqrjyximxqifnogvum}
Mystery_1
We were given a file named a.zip
and the task was to find the password, which was the flag.
File:
We can use zip2john
to extract the hash from the zip file:
zip2john a.zip > hashes.txt
Then we can use john
to crack the hash using a wordlist:
john hashes.txt --wordlist=/usr/share/wordlists/rockyou.txt
Flag: NCO2025{pineapple}
Mystery_2
We were given a file named capture.pcap
and using the sslkeylog file from the last challenge, we can decrypt the pcap file using Wireshark
.
Next, we can filter the decrypted traffic for HTTP requests and look for the flag, which is the name of a document that was transferred.
File:
Flag: NCO2025{Merlion_Battle_Newsletter_April_1_2025.docx}
Mystery_3
With the document we got from the previous challenge, we at the end of the document find a base64 encoded string. We can decode it using the base64
command.
File:
echo TDBuOV9sMXYzXzRoM19NM3JsMTBu | base64 -d
L0n9_l1v3_4h3_M3rl10n
Flag: NCO2025{L0n9_l1v3_4h3_M3rl10n}
Analyse Packet II
We were given a pcap file and the task was to analyze the packets to find the flag.
File:
One way to solve this challenge is to use strings
to extract all the strings from the pcap file:
strings packet2.pcap
This leaves us with 4 flags, but only one of them is correct.
NCO2025{F@ls3Fl@9}
NCO2025{H1d3_th3_Fl4g5}
NCO2025{R34l_F1@9}
NCO2025{H1dd3n_1n_Ipv6}
The correct flag is NCO2025{H1dd3n_1n_Ipv6}
.
Flag: NCO2025{H1dd3n_1n_Ipv6}
Pentest Challenge
We were given a python script that looks like a classic obfuscation challenge. The task was to find the flag.
File:
Changing the exec()
to print()
in the script allows us to see the code without executing it. The code is obfuscated, but after 50 rounds of deobfuscation, we can see the original code. This can be automated using the replace
function and a loop.
import socket
# Define server address and port
UDP_IP = "0.0.0.0" # Listen on all available network interfaces
UDP_PORT = 5033 # Choose any available port
BUFFER_SZ = 4096
CODE_FMT = 'utf-8'
# Create a UDP socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind((UDP_IP, UDP_PORT))
keyVal = 2025
while True:
# Receive message from client
data, addr = server_socket.recvfrom(1024)
dataStr = None
try:
dataStr = data.decode(CODE_FMT)
except Exception as err:
msg = b"Input data format incorrect.Please Try again."
server_socket.sendto(msg, addr)
continue
result = ''
for char in dataStr:
result += chr((ord(char) + keyVal - 97) % 26 + 97)
if result == 'pentestpass':
msg = b"Processed message:pentestpass, You have input the correct flag string"
server_socket.sendto(msg, addr)
continue
msg = "Processed message:"
msg += result
msg = msg.encode(CODE_FMT)
server_socket.sendto(msg, addr)
Looking at the code, we can see that it is a simple UDP server that listens for messages. The server processes the message by shifting each character by 2025 positions in the alphabet.
First we need to find the shift, this is done by taking the modulo of the shift value with 26, which is the number of letters in the alphabet.
2025 % 26 = 23
We can then reverse the shift by subtracting 23 from each character in the message.
print(''.join([chr((ord(c) - 23 - 97) % 26 + 97) for c in "pentestpass"]))
Flag: NCO2025{shqwhvwsdvv}
Conclusion
I found the NCO 2025 practice platform to be a great way to prepare for the ICO 2025. The challenges were well-designed and but pretty easy for me. I only spend 1 hour on the platform, but I was able to solve all the challenges you see here. I hope the challenges will be more difficult in the actual competition!