Reversing The New CyberPatriots National Scoring Engine - 2025 Update
In the interest of restoring the integrity of the CyberPatriot competition, this article shows how an attacker can easily reverse-engineer and uncover the new CyberPatriot CCS (2024-2025) engine's hardcoded decryption keys through dynamic and static code analysis.
This all began back in December of 2024. I was browsing the web and came across an article by Bill Demirkapi; in his five-year-old blog post, he explained how to decrypt the scoring configs for the 2018 competition images. After his blog post, AFA claimed they had reworked this encryption algorithm and made it much harder to obtain access to the hardcoded decryption key. This caught my attention because, at the start of the 2024-2025 competition season, AFA said they had rewritten the CyberPatriots CCS engine with additional security measures, after some teams managed to decrypt the config to obtain quick answers. Since then, I had begun experimenting with tools like IDA, GDB, and strace, and I couldn't wait to retest the “improved defenses.”
After some searching through my backups, I stumbled upon a CyberPatriots practice VM from the 2024-2025 training round 2. This was supposedly the first VM setup using CyberPatriots' "new CCS engine," which was claimed to be more secure than previous versions. After some analysis, I found that the encryption key for the config containing all the answers was hardcoded into the binaries on competitors' machines—just as they were back in 2019.
The CyberPatriots program is the Air Force Association's (AFA) "national youth cyber education program." In the remote competition, thousands of teams across the nation receive 3-4 virtual machines (VMs) that are vulnerable to various types of attacks due to poor configurations. To earn points, competitors identify and remediate these vulnerabilities. These remediations are validated by the CyberPatriots Competition Scoring Engine (CCS), which runs on the VM, reads the encrypted XML file to determine which vulnerabilities have been fixed, and assigns a score to the team in real time. As teams compete, this data is shared with a central server, which stores all the scores collected by the CCS program and publicly ranks each team.
You might say, "What's the big deal? This is a competition for high school students." However, the results have the potential to change lives and futures. In my town, internships, scholarships, and thousands of dollars in award money go to winners. If one makes it to DC, they have guaranteed employment for the rest of their lives, since CyberPatriots is respected among organizations such as Booz Allen and many 3-letter agencies. Retaining the integrity of this competition is essential to maintaining its positive externalities, which include cybersecurity training in high schools, the opportunity to attend university, and access to high-paying tech jobs.
The Big Vulnerability
Once I realized that a copy of the decryption key was stored locally, I didn’t have to search long before I found it. Since the CCS program needed to read this config to understand how to start scoring the system, the decryption key for the encrypted XML file was also stored locally. If an attacker knows the program that reads the encrypted file and the decryption key is hard-coded, it’s like leaving your house keys under your doormat with a sign on your front door that says, “move the doormat to find the keys to this door.”
After examining whether anyone had previously exploited this vulnerability, I found a blog post by Bill Demirkapi written in 2019. Although he prefaced his article by saying the CyberPatriots team had changed their encryption algorithm, just as Demirkapi had, I was still able to decrypt their modern images (2024-2025) after some debugging.
To be fair to CyberPatriot, I only realized this in December of my senior year. Having participated in the CyberPatriots competitions from 2020 to 2025, I understand that their updates mainly prevent beginners from decrypting the system, while those who can already decrypt it could have solved the image. Nonetheless, there is still a security vulnerability that could give competitors an unfair advantage. Knowing some individuals who have used similar exploits before—most often spoofing requests to the central scoring server—I felt it was important to disclose this to the CyberPatriots team.
That said, after seeing the backlash against the initial blogger from CyberPatriots, and living in a state that has a history of prosecuting security researchers for pressing F12. Knowing my team was most likely going to make it to nationals, my coach and I decided it was better to keep this secret until after the competition season. Since I didn’t want to jeopardize our chances, I kept this attack method secret despite some pushback from the team. Now that the competition has ended, and we’ve moved on in our lives, my team has been patiently waiting for me to publish this article. Out of respect for the competition's integrity, I am fulfilling that request, hoping to alert the CyberPatriots team and see updates—possibly remote scoring—in the CCS program.
Disclaimer
These images have additional safety measures in place to prevent people from gaining an unfair advantage. This includes, but is not limited to, network checks, debugger flags, and code obfuscation. In this article, I will not explain how to bypass these measures. Furthermore, please view my article solely as an educational curiosity, rather than a way to get quick answers. The information and techniques presented were not used during any active CyberPatriots competition, nor were they shared to provide an unfair advantage. If you're looking for quick and easy points, this article is not for you.
If anyone from CyberPatriots is reading this, I encourage you to store the files on an off-site server, using encryption and obfuscation both during transit and at rest, with remote scoring and monitoring. I must stress the importance of implementing these additional security measures to maintain the integrity of the CyberPatriots remote competitions and ensure they remain fair and equitable for future teams.
The plan
In my research, I employed two methods: dynamic and static code analysis. Although I found more in my static code analysis, the dynamic code analysis was equally crucial, as it allowed me to understand how the executable operates at a low level. In my dynamic code analysis, I uncovered the process in which it communicates with the scoring server and roughly where it reads the file.
Beginning The PenTest
Dynamic Code Analysis
When looking for the encryption key, I decided to start with dynamic code analysis to understand how the script operates. When running the script on an isolated network with tcpdump I noticed that the CCS program connects to two IP addresses on port 80: 52.202.17.90 for a connectivity check and 54.243.182.228 for scoring updates. Shocked that the scoring engine communicated through an unencrypted connection with the main scoring server, I decided to set up a fake CCS server. Without giving too much away, I configured an isolated environment with an additional Ubuntu server connected to two separate networks. I then connected the executable machine and the Ubuntu server to the network using the required IP addresses so the competition engine would treat my Ubuntu server as the official CyberPatriot server.
With this setup, on my Ubuntu machine, I used the netcat command to accept any connection, log the HTTP request, and always return a 200 response. This showed that the executable expects 52.202.17.90 upon request, to return a file named download with a length of 0. It then sends a scoring update through a PUT request to 54.243.182.228/ccs/upload. Once this succeeded, the script would read the ScoringResource.dat file, letting me capture the location of the ReadMe with strace. Knowing that teams in the past gained a leg up by sharing this ReadMe before the competition, this is just another vulnerability CyberPatriots needs to take seriously.
Someone from CyberPatriot might say, "No, no, no, this shouldn't be possible because we look for the debugger byte." This is partially correct, executing CCSClient with strace will fail because, at startup, the CCS program looks for the CPU's debug byte; if it's present, it will reboot the instance. However, since the program only runs this check once, I could bypass this by binding strace to the process after startup. I still needed to capture the calls made in the first few seconds of execution. Still, I solved this by writing a one-liner that takes the background PID as input and automates running strace.
./CCSClient & sudo strace -f -e trace=open,openat,read,write,mmap,munmap,brk,mremap,mprotect -p $! 2> output.txtStatic Code Analysis
Although not as exciting, I spent hours commenting and navigating the execution tree in IDA. CyberPatriots made this painful to load into IDA because the program had strong code obfuscation. Results from this attack vector were more successful at obtaining the decryption key. Even though it may not look like much, after hours of this tedious process, I stumbled upon this function:

The important takeaway is the following code block:
if ( !*(_QWORD *)(Context + 248) ) {
v4 = allocateWithHandler(0x38uLL); // Create space in memory to read the file
aesKeyHere((__int64)v4); // Defines AES key, sets up decryption object, and decrypts
*(_QWORD *)(Context + 248) = v4; // Store the pointer to the decryption object in Context + 248
}
The key is defined in the function I like to call aesKeyHere or if you prefer IDA's name sub_42FDCC.

The function above does the following:
- Embeds a hard-coded key within the constants that are later used to derive it via XOR operations.
- It sets up a Crypto++ AES-based cryptographic environment for the decryption of the
ScoringResource.datfile.
Finding the key
By writing some basic Python that mimicked the original program's execution and its XOR process (see Decryption.ipynb linked below), I was able to derive the key. The training round 2 key of 2024 is:
Decrypting the contents
Although CyberPatriots said they changed the algorithm since the initial publication in 2019, I found the initial article invaluable for identifying the nonce (CV) in the XML file. Demirkapi's article stated that the first 12 bytes are the CV. With this knowledge in hand, I was able to load the ScoringResource.dat file, decrypt it, decompress it, and extract the fully unencrypted XML (ScoringResource.xml). For my decryption script, see Decryption.ipynb linked below.
Moving Forward
Even though changes have been made to improve the integrity of this competition, there is still some room for improvement. Even if you're not the author of the CCS program, there's a lesson to be learned: embedding encryption keys directly into a program that handles sensitive content isn't a reliable method for keeping that content secret, as demonstrated by the scoring configuration dump. This article was not written to shame CyberPatriots, who put in place many, many hurdles to prevent the reverse engineering of their executables, but rather as a notice, in hopes that someone will improve the security measures moving forward. If someone from CyberPatriots wants to work with me to improve their systems, please don't hesitate to reach out in the comments.
If you enjoyed this article, please consider creating a free account. With an account, you can obtain members-only files, such as my full IDA Analysis and the original files, to test this for yourself. As I work on cybersecurity research, I have many more articles in progress that I guarantee you'll find interesting. By creating an account and enabling notifications, you'll be notified when I publish additional articles like this one.
Assets & Files
The complete list of files, references, and assets: