On Wednesday the 9th of January, I attended a CTF tournament arranged by the OWASP Bristol Chapter, SecureCodeWarrior and JustEat at the JustEat offices in London and Bristol.
I thought I’d share my experience competing in the CTF, some of the challenges and what I learnt from them. On a less important note I will also share where I finished on the tournament leaderboard!
As you’d guess, this CTF was based solely on web-app vulnerabilities, to be even more specific, the OWASP Top 10 vulnerabilities in web-apps.
One not so common aspect of this CTF was that the challenges represented much more of a white-box testing scenario, I later understood this a bit more after looking further into SecureCodeWarrior’s product and target audience. I used this as an opportunity to work on my code-auditing skills, I also used it as an opportunity to view some vulnerable .NET/WebForms code implementations, I use this language/framework on a daily basis and could benefit from seeing common mistakes.
The atmosphere at the CTF was really great, the hosts ordered us pizza and there was a fridge stocked full of beers for us to drink whilst playing! (I didn’t eat anything as I was too busy concentrating!)
Challenges & Knowledge I Gained From Them
OS Command Injection
One challenge was the discovery and mitigation of an OS command injection vulnerability. I can’t look back on the code, but I can recall that some hidden-field/client-side data was being used as a command-line argument to a process being started on the server without sanitization. An attacker could therefore craft input that injects commands of their choosing to be executed by the server.
This challenge offered a lot of points, at first I couldn’t think of how I’d prevent malicious meta-character injection beyond escape sequences. However, after reviewing the OWASP Top 10 and some (quick) further reading, I chose a mitigation that included a white-list of possible input cases/values. Whilst maintaining this is more work for application security engineers, it guarantees only the input cases you permit have reachable code paths. I think it is a good solution if you don’t expect the input to vary a lot, but still don’t want to trust it as secure. It is something I will consider when handling attacker-controlled input that doesn’t vary much in future code I write.
My chosen mitigation was correct and I gained the maximum amount of points for that specific challenge. I found it useful to look at a command-injection vulnerability in a .NET context as this will help me to mitigate them in future code I write.
Another challenge category I learnt a lot from was SQL injection vulnerabilities. I had previous knowledge of how to identify and exploit SQL injection vulnerabilities, but I wasn’t 100% sure on practice (especially in .NET) to completely mitigate said vulnerabilities.
After again reading up on the OWASP Top 10 and eliminating some obvious broken mitigations, I developed an intuition for solving these challenges as I’d subconsciously formed a secure .NET SQL query formation methodology in my head that went something like:
- Sanitize input from the client.
- Prepare a parameterized query string uses .NET’s built-in SQL query object and ‘@’ string parameterization construct.
- Use .NET’s query object to fill the query’s parameters with the sanitized input, which is aware of potentially insecure input and treats it in a value context, rather than part of the query syntax (should an attacker bypass the sanitization).
Every time I recognized a solution that implemented something similar to this, I instantly selected that solution, I was successful 100% of the time doing this and this helped me make up for some time lost on other challenges where I was slow to avoid losing points with wrong answers.
Insecure Session ID Generation/Deletion
The final challenge category I recall was insecure session ID generation. The vulnerable code in question was mainly pseudo-random generation of session ID’s, or session ID generation that was very vulnerable to enumeration attacks. For example, in one case, the session ID generation was a loop that iterated 5 times, either re-initializing the session ID to a random number between 1 and 5, or incrementing it by a random number from 1 to 5.
These cases are both vulnerable as an attacker could perform an enumeration attack starting from 0 or their session ID and incrementing by 1 to potentially reach another user’s session ID within 5 or less iterations.
Whilst I’m not that knowledgeable on string entropy, I’m aware that implementing a secure session ID requires the ID being a length that prevents brute-force attacks (OWASP suggests 128-bits/16-bytes) and incorporates a certain degree of entropy to prevent guessing attacks backed by statistical analysis. (OWASP suggest roughly 64-bits) and this was enough to identify both the vulnerability and the best mitigation.
I haven’t yet mentioned what I learnt from this challenge… Surprisingly, what I learnt or rather reiterated in my brain, is that you should avoid reinventing the wheel and if you can, use the security controls available in your run-time/framework whenever possible. People have likely worked a lot longer on securing these than you have on your custom implementation. After all, hacking is simply about knowing something on a deeper level than the person who originally implemented it.
After a very intense 2 hours, the time limit for completing challenges was reached and placings and prizes were announced to various competitors!
I placed 9th! I didn’t expect this given so many talented people from different backgrounds had played. I’m really happy to have placed in the top 10 and it has motivated me to play more CTF, keep hacking and work really hard on developing myself as an information security professional.