Authentication Bypass in CodeIgniter Due to Empty SQL Where Clause
A while ago I came across this tweet, showing off a weird authentication bypass. Based on my experience in auditing websites this didn't make sense to me, so I tried to figure out the root cause. During this process I believe I have identified two potential coding anti-patterns that are worth checking for, when auditing web applications developed with PHP and CodeIgniter.
The architectural issues might also translate to other web frameworks with similar APIs.
Originally this bypass was found by Eslam Akl and documented on infosecwriteups.com. Since then he created an updated writeup on his personal blog including more of the details how he stumbled over this.
Empty WHERE Clauses
SQL WHERE clauses work in CodeIgniter using the query builder by passing in a PHP array containing key => value
pairs to the $builder->getWhere()
function. This is then later translated into a complete SQL query with a where clause WHERE key=value
.
Consider the following controller implementing something like a login function. You can see it takes a request, performs some basic input validation and then runs a query to find the user with the matching username and password.
The problem with the code above is that the $where
array will be empty when the username and password were not included in the original JSON request. This results in $builder->getWhere()
to be called with an empty array and it will construct a SQL query without a WHERE clause. Which then returns the complete table.
It is recommended to be extremely careful when building queries in CodeIgniter and other web frameworks. Very strict input validation and throwing of early errors could prevent the issue. It might also be useful for CodeIgniter to implement sanity checks that throw errors when empty WHERE clauses are passed to the function.
SQL Injection in $builder->getWhere()
Eslam also told me that the application was vulnerable to SQL injection issues. Having seen the requests leading to SQL errors, I believe to have identified a second likely coding-anti pattern.
The controller below takes the incoming JSON request data and passes it to the $builder->getWhere()
. Some developers might think this to be a clever way to implement query filters, for example when creating an API endpoint. The CodeIgniter documentation does not include a warning regarding completely attacker controlled arrays passed to this function.
When an attacker submits a JSON request containing an injection payload in the key part, it will not be escaped: {"username":"admin", "\" or 1=1 -- -":"asdf"}
.
It is recommended to carefully build WHERE clauses with strictly controlled keys and not let attacker controlled arrays be passed directly to $builder->getWhere()
.
Additional Resources
Does anybody know if this has been documented before? Please send me the links @LiveOverflow.