We presented a variety of interesting and partly obscure security bugs in as little code as possible such that a challenge can be solved during a coffee break. Some challenges addressed beginners in security, others were more advanced. Next to different vulnerability types, we sneaked in different types of user input and various methods of faulty input sanitization or validation. In case the vulnerability type was obvious there was still some sort of trick or bypass required for exploitation. At the end of each challenge a brief solution was added explaining what went wrong in the code.
If you haven’t tried out the challenges yet we highly recommend to do so before you read on about the spoilers:
The main goal of our challenges was to provide a fun time and to sharpen the mind for your own code reviews. After completing all challenges it should become evident that most of the vulnerabilities follow the same concept: User input is used unsanitized in a security sensitive operation. These are exactly the dots that our static analysis tool RIPS tries to connect in a graph representation of the source code, called taint analysis. The challenges presented a variety of user input which requires input sanitization and a variety of vulnerability types that attackers can exploit. PHP’s weak typing can easily lead to insufficient sanitization or bypasses depending on the combination of both. Let’s dig deeper into the main pitfalls of the challenges.
Most developers know that user input cannot be trusted and that it should be sanitized very carefully. In our challenges we incorporated some more unknown types of vulnerabilities that not all developers may think about when working with user input. User input is not only the data that is passed to the code via
$_REQUEST. An attacker is also able to control many other values such as e.g. cookies (see challenge 11 or 24), the referrer (see challenge 7), the HTTP accept language header (see challenge 9) or
PHP_SELF of the
$_SERVER variable (see challenge 15). It’s important to remember that everything that comes from the HTTP request is in the attacker’s control and can be malformed. Besides the user input values e.g. in the super-globals the array keys are also in the attackers control (see challenge 12).
A main weakness that spanned across the whole calendar is the weak typing of the PHP language and the resulting bugs and vulnerabilities. From using
== instead of
=== to incorrect comparison of function return values, there are several ways that unsafe type comparison or automatic typing can lead to vulnerabilities in the code. We tried to show some interesting and uncommon examples of this type to raise awareness when making security relevant checks or dealing with user input. Some examples of typing bugs were challenge 1 with a type-unsafe usage of
in_array() and challenge 22 with a type-unsafe comparison of string and integer.
Also related to weak typing were bugs that base on the incorrect usage of PHP built-in functions. In challenge 18 the return value of
openssl_verify() had a special case that would return
-1 in case of an internal error. Because of PHP’s typecasting the constraint of the if clause became true and the authentication could be bypassed.
Challenge 4 had a similar issue. Here, the return value of
strpos() was misinterpreted by the developer which lead to an input validation bypass. In challenge 19 a side effect of the function
stripcslashes() was abused.
Besides PHP’s built-in functions it is also important to understand features provided by frameworks. For example in challenge 2 we presented an XSS vulnerability that was exploitable although Twig’s auto escaping was utilized to sanitize the input.
Variety of Vulnerabilities
Last but not least our challenges demonstrated the diversity of security bugs. Everyone heard of Cross-Site Scripting, SQL Injection, and File Inclusion. But have you heard of Mass Assignment, Execution After Redirect, or Object Instantiation? Not only SQL, DQL, LDAP, or XML markup posed a security risk in our challenges, but also innocent looking functions such as
parse_str(). It’s hard to keep track of all kinds of different vulnerability types and their related exploit tricks.
The root cause for the security issues presented in our challenges are not new. But the diversity and combination of these pitfalls are sheer endless that trick even skilled developers. What looks secure at first sight quickly turns into an exploitable security bug. Particularly when the faulty code is not squeezed into a little code snippet but spread across thousands of lines in different files and functions in real applications. For example the issue in challenge 3 occurred in Shopware or the vulnerability in challenge 11 was found in multiple Wordpress plugins. We would like to thank everyone who participated, discussed, and provided great feedback and we hope our challenges helped in sharpening your security skills in a fun way!
We wish all our readers a happy and safe new year 2018!