IX. National IT Competition (OITM) recap
The National IT Competition (aka. OITM, Országos IT Megmérettetés) is a yearly, individual, large-scale Hungarian online competition designed for IT professionals, developers, students, and technology enthusiasts. It runs over several weeks and features practical, real-world challenges across more than twenty IT categories, such as programming, cybersecurity, DevOps, data science, and other modern, mainstream technology fields. Participants complete online tasks that test both theoretical knowledge and hands-on skills, receiving scores and feedback that allow them to compare their performance with other competitors nationwide, win prizes and gain professional recognition.
OITM IX. (2025) #
During the Autumn of 2025 the IX. OITM took place with 16 categories and 5 rounds in each category. The major update in this year's competition was that 6 categories had a 6th round which was a live final hosted before the award ceremony on the 6th of February, 2026. Another change from our side was that for the first time we were invited to create and host the IT Security category. This meant a few things:
- we could not participate in the IT Security category obviously;
- we created the challenges for all of the five offline rounds;
- we hosted the live final round;
- we streamed and commented the final round via Youtube Live;
- we gave the awards for the top players.
Three of us were responsible for creating the challenges: Gergő Krátky and Kristóf Tamás (for all rounds) and Zoltán Iuhos (for the final).
This year, our focus was on the IT Security category, but Kristóf Tamás and Balázs Gnandt also participated in other categories. We reached the top 10 multiple times, most notably Kristóf earned the 2nd place in the Technical Dept Management and in the Frontend categories and reached the 6th place on the overall scoreboard (3rd place in the online rounds) in a very tight competition. There were more than 1800 participants in the whole event and 539 in our IT Security category which was one of the most popular categories.
The motto of the competition was There's no AI without wit! (Nincs AI ész nélkül!) which was very apt. Some categories did not support the use of AI, but in our category we allowed everything, just as in a real life scenario. The challenges we created could be solved faster with the help of AI tools, but AI alone was not enough to be amongst the top players, it required criticism, experience and out-of-the-box thinking. AI alone is insufficient in this area, individual preparedness, creativity, and expertise are still a competitive advantage.
The online rounds (round 1-5) #
The first five rounds took place in October and November during five consecutive weeks. All five rounds followed a single incident investigation, where the competitors had to identify the entry point of the attacker, investigate the dropper file and the deployed ransomware, use OSINT techniques to find information about the threat actors, and finally hack the infrastructure of the attacker to obtain the ransomware decryption keys.
Solutions of the online rounds
Round 1 - #forensics #
wireshark pcap rdp dropper powershell
During the 1st round the competitors were given a PCAP file which they have to analyze:
- the initial access vector was an exposed RDP services and the
Administratoruser had weak credentials; - the PowerShell dropper was downloaded through an unencrypted HTTP connection from the C&C server;
- the PowerShell dropper used AES-CBC encryption to decrypt the ransomware payload;
- the encryption key was also visible in the PCAP.
7 players could solve all questions in this round.
Round 2 - #reverse #
python pyinstaller aes rsa kill switch darknet
The task in the 2nd round was to analyze the ransomware itself:
- the ransomware was written in Python and an EXE file was created using PyInstaller;
- it creates a random AES key which is used to encrypt some files on the local machine;
- the encryption key is encrypted with a hardcoded RSA public key and sent to the C2 server;
- a kill switch terminated the malware if it detected Hungarian or Polish keyboard layouts;
- the ransom note suggested the a site on the darknet should be visited (
.oniondomain).
45 players could solve all questions in this round.
Round 3 - #osint #
osint, tor, darknet, mastodon, github
In round 3, the competitors had to use OSINT techniques to find the attackers:
- the ransom note contained a Tor domain (ending with
.onion); - by visiting the site one could find a Mastodon handle;
- on the Mastodon page of the threat actor we could find hints to a GitHub account;
- there was an Android application in development under the found GitHub account.
25 players could solve all questions in this round.
Round 4 - #mobile #
apk, android, root detection, native library, api
Round 4 was about analyzing the mobile application of the threat actor:
- the competitors were given an Android application, which presented the current balance of the threat actor in BTC;
- the application had root detection capabilities;
- the API key was hardcoded, but encrypted with XOR in a native library;
- the competitors either had to proxy the application or reverse engineer the native library to obtain the API key;
- the
/usersendpoint was hardcoded in the application but never used, the goal was to identify the registered users.
23 players could solve all questions in this round.
Round 5 - #web #
sqli, decryption
In last online round the goal was to hack the attackers infrastructure to obtain the decryption key:
- the given web application had a hidden search functionality;
- the search functionality was vulnerable to SQL injection;
- by exploiting the SQL injection one could dump the whole database including the RSA private key and the RSA encrypted AES encryption keys;
- the specific AES encryption key had to be decrypted using the private key;
- finally the encrypted
flag.txtfile could be decrypted using the obtained AES key.
The offline final (round 6) #
The TOP 40 players were invited to the 6th round which was a live final round from which 29 players participated. We decided to create a small CTF event during the 40 minutes allocated for the final. A CTFd infrastructure was deployed to AWS and the competitors could access the challenges through CTFd. As 40 minutes is not much time, we decided to create 10 small challenges in the most common CTF categories:
- one easier crypto, one harder crypto
- one easier forensics, one harder forensics
- one easier misc, one harder misc
- one easier reverse, one harder reverse
- one easier web, one harder web
All challenges were open from the start of the final, the award for solving an easier challenges was 2 points, the award for solving a harder challenges was 3 points. Most of the challenges required a few minutes to solve (for an experiences CTF player) which meant that it was not possible to solve all challenges during 40 minutes, but that was our goal. The live scoreboard and the progress of each player was visible for everyone.
The Stream #
During the live finals three categories had an online stream and commentary: Accessibility of websites, Python, and IT Security.
Gergő and Kristóf represented Ukatemi and Szilárd Csordás from ITBN was the host. We've talked about IT security, CTF competitions and the CTF ecosystem and also narrated what is happening during the live final by visiting the screens of some players.
You can rewatch the stream here: https://www.youtube.com/watch?v=zD2nK-w08HE

Results of round 6 #
The best player kristof345 was able to solve all but one challenge (the hard web challenge), which was our expected progress, every player was able to solve at least one challenge and every challenge was solved by at least a few competitors.

The TOP 10 players were above 10 points which means that they were able to solve at least around 5 challenges, they might be more experiences CTF players. All other players were able to solve around 2-3 challenges, which is also great as getting familiar with the platform, choosing between the tasks and understanging them is not trivial within only 40 minutes. Furthermore, they had to submit all flags to the website of OITM too.
The most solved challenge was surprisingly the easy Java reverse challenge with 22 solve out of the 29 players. The other easy challenges followed: crypto, forensics, web and misc with 13-15 solves.

Solutions of the finals
Crypto - I fly like paper, get high like planes (easy) #
In this challenge we get a text file called papirrepulo.txt, containing 3 pairs of numbers.
The numbers are labeled as n1, e1, n2, e2, c1 and c2.
Having a little bit of crypto knowledge, we are suspicious, that this will be an RSA challenge.
The first thing we notice is that n1 equals n2, meaning that both moduli are the same.
We also see that the public exponents e1 and e2 are different, while their Greatest Common Denominator (GCD) is 1.
We also have two different ciphertexts c1 and c2.
At this point it is clear that we need to use a Common Modulus Attack to solve this challenge without factoring n.
The Common Modulus Attack is a well documented attack, we can find several resources explaining every detail, with even example solving scripts. Without much explanation, we can quickly write a python script based on the resources found, to solve the challenge:
from Crypto.Util.number import inverse
def egcd(e1, e2):
if e2 == 0:
return e1, 1, 0
g, x1, y1 = egcd(e2, e1 % e2)
return g, y1, x1 - (e1 // e2) * y1
def common_modulus_attack(n, e1, e2, c1, c2):
g, a, b = egcd(e1, e2)
print(a,b)
if g != 1:
raise ValueError("Exponents are not coprime")
if a < 0:
c1 = inverse(c1, n)
a = -a
if b < 0:
c2 = inverse(c2, n)
b = -b
m = (pow(c1, a, n) * pow(c2, b, n)) % n
plaintext = m.to_bytes((m.bit_length() + 7) // 8, "big")
return plaintext
Crypto - TODO test this! (hard) #
For this challenge, we are provided with two files.
The first is called messages.txt and contains 5 lines of timestamps and base64 encoded strings.
The second file is called exfiltrate_secrets_final_2.py, which is a Python script, that connects to a server and sends out encrypted messages to it.
The description of the challenge also mentions, that the encryption script contains an error, and we might not be able to decrypt the messages.
Upon closer inspection the encryption of the messages is the following: For every message, at the time of sending the message, a new random number generator is seeded with the current time, and then a XOR key is generated using this random number generator. Then the encrypted message is base64 encoded, and concatented to the current timestamp.
However, the error in the script is that the timestamp only contains the minutes, and anything beyond that is not sent to the server.
In summary, we have down to the minutes of when each random number is seeded with the current timestamp, and we have to bruteforce the rest of the timestamp to restore the original messages.
For this task we can create the following script:
import random
import time
import base64
def XOR_decrypt(ciphertext: bytes, key):
decrypted_message = bytes(b ^ k for b, k in zip(ciphertext, key))
try:
return decrypted_message.decode('utf-8')
except:
pass
def decrypt_message(ciphertext: bytes, timestamp):
for n in range(60):
random.seed(timestamp+n)
key = bytes(random.randint(0, 255) for _ in range(len(ciphertext)))
decrypted_message = XOR_decrypt(ciphertext, key)
if decrypted_message is not None:
print(decrypted_message)
def process_messages():
for line in messages.splitlines():
datetime, encoded_message = line.split(' - ')
timestamp = int(time.mktime(time.strptime(datetime, '%Y.%m.%d %H:%M')))
encrypted_message = base64.b64decode(encoded_message)
print(f'{timestamp}~{encrypted_message}')
decrypt_message(encrypted_message, timestamp)
Forensics - Data exfiltration (easy) #
In this challenge we are given a network packet capture file called capture.pcapng.
Opening and inspecting the file reveals that it has mostly DNS and TLS traffic in it.

Hoping that the flag is in the DNS data and not in the TLS, we filter the packets to the DNS traffic with the dns display filter.

Visually inspecting the remaining packages we can spot a pattern of many DNS requests for ukatemi.com, with every request querying a different, one character long subdomain.
Which is even more promising that the first few subdomain characters are the following: o, i, t, m, {.
We can extend our display filter, to only contain these interesting packages: dns contains "ukatemi" && ip.src == 10.0.2.15.
Now the only remaining task is to read the subdomain characters one after another.
Forensics - Oopsie daisy (hard) #
In this challenge we receive a QEMU disk image file called ntfs.qcow2.
Our task, according to the description of the challenge is to restore some files from this filesystem.
Based on the name of the file, we can assume that the file contains an NTFS file system.
First we need to access the filesystem, which is achieved by connecting the given file to a QEMU Disk Network Block Device Server.
The command for this is the following: sudo qemu-nbd --connect=/dev/nbd0 ./ntfs.qcow2.
For NTFS volumes there is a tool called ntfsundelete, with which we can try to restore any previously deleted file.
The command for this is as follows: sudo ntfsundelete -u -m '*' /dev/nbd0p1.
When running this command we are greeted with an output, stating that one deleted file was restored, called secret.txt.gz.
Extracting the GZIP archive reveals the flag.
Misc - What does the owl say? (easy) #
For this challenge we get a message.wav file, which - according to the description of the challenge - is a desperate sound recorded by a listening device.
Listening to the file, we can hear an intresting beeping sound, and some strange noise under it.
Our best bet for an easy misc challenge with a .wav file in it, is to open the file in Audacity.
Maybe we get lucky and spot our next clue in the waveform or the spectrogram view of the file.
And just by selecting the spectrogram view, we can already see the flag in its full glory.

Misc - Titkos üzenet száll a széllel / A secret message is carried on the wind (hard) #
In this challenge we are provided a fenykep.jpg file, which depicts an animated owl cosplaying Sherlock Holmes.

After checking the very basic CTF checklist when it comes to misc challenges (file, strings, exif, binwalk), we steer in the direction of steganography tools and techniques.
StegOnline is a great image steganography tool available as a web application, in which we start by inspecting the color and the bit planes of the image.
Upon browsing through the bit planes, we get a weird phenomenon in the blue 0 bit plane.

This is a plane with a repeating, lower entropy pattern at the top. This usually means there is some data embedded in the image, into the bitplane with the phenomenon.
To extract the data we can also use the online tool called StegOnline, or we can just as easily write a quick Python script using the Pillow package.
The extracted data is another image file, visually containing the flag.
Reverse - Flag a javából / Flag from Java (easy) #
In this challenge we are given a flag_check.jar file.
JADX-GUI is a Dex to Java decompiler, which can decompile the JAR into readable code.

The encoded flag uses a simple XOR encryption, so the same value which is used for the encryption can also be used for the decryption.
Example decode script in python:
flag = [69, 67, 94, 71, 81, 126, 66, 79, 117, 75, 68, 89, 93, 79, 88, 117, 67, 89, 117, 26, 82, 24, 107, 87]
print(''.join(chr(i^42) for i in flag))
Reverse - Útvesztő / Maze (hard) #
The challenge starts with a binary file called maze.
The binary does not use packing/obfuscation techniques, and the compilation was done without the use of optimization. The symbol table is left intact, and most of the logic in the decompiled code is very similar to the source code.
Running the binary, or by decompiling it and checking out the print_help_and_exit function, we can see that the executable expects a 15 character long command line argument consisting of the characters u, d, l and r.
Examining the code further we can deduce that these are directions used to navigate a maze, and by providing the correct input sequence, we can reach the end of the maze and get our flag, which itself consists of the input sequence.
To get the flag, we must understand how the map is stored and how the correctness of the input is checked.
The latter is handled by the take_step function.
By examining this function we can deduce that the map is a 6x6 grid stored in a 36 size array.
From the start point (index 0) we must reach the end point (marked by the value 2) without moving out of the grid and without hitting any walls (marked by the value 1).
The next step is to find the values of the map array.
It's a global variable stored in the .data segment, which can be easily read using either Ghidra or gdb.
Ghidra will most likely interpret it as a byte array instead of an int array, so it must be cast to an int array first to read the values correctly.
The values can also be read using gdb:
(gdb) p &map
$1 = ( *) 0x4040
The correct path can be easily seen by transforming the array into a 6x6 grid:
0 0 1 1 1 1
1 0 1 0 0 0
1 0 0 0 1 0
1 1 1 1 0 0
1 1 1 0 0 1
1 1 2 0 1 1
Since we start at the top left (index 0), the correct path is rddrrurrddldldl.
We can get the flag by putting this into the oitm{...} format (based on how the flag is printed by the program) or by running the binary with the sequence.
Web - Kedves naplóm / My dear diary (easy) #
We are provided a URL to a web application.
We can login using the credentials provided in the challenge description.
Our session information is stored in a JWT cookie.
If we put it into a JWT decoder (or just decode the base64), we can see that the signature is missing, and the signing algorithm is set to none.
The note after logging in gives us a hint that there's also an admin user.
We can access the admin user's notes by changing the username claim in the token to admin and refreshing the page.
Here one of the notes contains the flag.
Web - Irattár / Archives (hard) #
We are provided a URL to a web application.
Clicking the List Files button we get 5 files.
They are not too useful, only HELPME.txt gives us a hint that an "important file" (the flag) is most likely in the parent folder of static/files/public/.
We can find the REST API endpoint /api/list_public either in the javascript code, or by intercepting the API call when the button is clicked.
The request contains the parameter page=1, but in the response max_page is set to 2.
Calling the endpoint with page=2 we can find the swagger.yml file.
We can download it by going to /static/files/public/swagger.yml.
In the swagger we can find an additional root_dir parameter, and an endpoint called list_private.
Experimenting with the root_dir parameter we can find two important discoveries:
- Accessing the parent folder using
..is filtered out - It's possible to read other files by entering an absolute path like
/etc/passwd, but only inside of thestatic/filesdirectory
Unfortunately we don't know the absolute path of static/files directory.
Calling the /api/list_private endpoint will only return an error message:
{"message": "Directory '/app_2Ls9qpPF/static/files/private' does not exist"}
What a delightful turning of events! There's the absolute path!
We can call /api/list_public with root_dir=/app_2Ls9qpPF/static/files to get the name of the flag file:
{
"files": [
{ "name": "flag_KP7Rev2v.txt" },
{ "name": "public" }
],
"max_page": 1
}
And then read the flag by accessing /static/files/flag_KP7Rev2v.txt.
Award ceremony and results #
The award ceremony of the whole OITM competition was held on the evening of February 6th.
The best players through all of the 6 rounds in the IT Security category were:
- Alex Hornyai
- Máté Szén
- Bence Kádár-Szél


Congratulations to the winners and all other competitors and thank you for participating in our category!
Our history with OITM #
Employees of Ukatemi have been participating in OITM since 2019. In the last 7 competitions we have won several awards, most notably:
- won the first team category in 2021 (source)
- achieved the best national IT team in 2023 and 2024 (source, source)
- earned the Most Versatile IT Professional in Hungary title multiple times
- at least one of our colleagues was in the top 6 in the overall scoreboard in every OITM in the last 7 years
- reached the podium in the IT Security category multiple times
- reached the 1st, 2nd and 3rd places in many other categories
Closing thoughts #
Three things we learned as organizers:
- It takes much more time to create tasks than to solve them. Compared to previous years and other competitions, we wanted to create tasks that were of the highest professional quality, that could satisfy a diverse audience, that covered a sufficient range of topics, and that were crystal clear. There is nothing worse than someone losing points because of the ambiguity of a challenge.
- AI is a tool, not a solution. In our work, we have also found that AI-based, automated testing does not provide real protection. It can speed up answers to some simpler questions (which is important and good, of course), but human creativity, experience, passion, thirst for knowledge, and expertise deliver much more reliable results. The contestants illustrated this perfectly.
- It feels great to belong to communities based on professionalism. The organizers, other partner companies, the competitors were all a great source of inspiration. In all the aspects of our work, we look for similar communities, in Hungary and abroad too.

Many thanks to Human Priority who is the creator of the competition and namely many thanks to the organizers - Gellért Pulay, Levente László, Barnabás Varga - for choosing us and for making this unique event!
Links #
- 2026-02-16: The main page of the National IT Competition (OITM)
- 2026-02-16: OITM IT Security finals stream by Ukatemi
- Previous post: Notepad++ supply chain attack related samples