TikiWiki comes with many built-in features. A manual audit of such a huge code base for security issues would require a tremendous amount of time and expertise. The automated security analysis of TikiWiki’s 1.7 million lines of code with RIPS took roughly 14 minutes. Once the scan finished, a vulnerability of type SQL Injection was reported in the user interface.

Analysis Overview

By selecting the SQL injection category in the RIPS UI, we can see a summary of the affected code lines (top), an issue description (right), and the original code as reference (bottom).

Code Summary

In the code summary we can see that the entry point for the attacker, a $_REQUEST parameter, is in tiki-user_tasks.php and that the vulnerable SQL query is executed in the file tasklib.php.

The unique SQL Context Tab feature shows at one glance how the vulnerable SQL query looks like and where the user input ends up (highlighted red):

SQL Injection Context

It becomes clear why RIPS reported this injection as an unquoted SQL injection: Unsanitized user input is concatenated into a SELECT query in a context where no quotes are used. It looks like an attacker can inject own SQL syntax as show_history parameter, for example the traditional 1 or 1=1-- -.

At this point we change the Review Label of the issue to Suspicious, to inform our team that we are investigating this issue, and we proceed to check under what circumstances the issue is exploitable.


The entrypoint for the reported SQL injection vulnerability lies in the file tiki-user_tasks.php:

User Input

The user input $_REQUEST['show_history'] is used as the third argument of the method TaskLib::get_task() which is defined in the file lib/tasks/tasklib.php:

SQL Injection

Here, this third parameter $task_version is indeed embedded unsanitized into a SQL query. Note how this SQL query is constructed over multiple concatenation statements and was already shown as a full reconstructed query in the SQL Context tab.


RIPS provides a general description of what a SQL injection is, how an attacker can abuse it, where to find more information and what industry standards are related. In general, RIPS suggests to use prepared statements but this is not always possible in legacy code. As a solution, RIPS then proposes the following patch for this specific SQL injection which is easily implemented:

No quotes are used around the detected injection point in the SQL query. Thus, all applied operations to escape the data are insufficient because no quotes have to be broken in order to inject SQL syntax. In case a numerical value is expected, a typecast operation should be performed on the user input.

$query .= "`t_history`.`task_version` = ".(int)$task_version." and ";


The detected issue hides in the User Tasks feature of TikiWiki. Once this feature is activated, any authenticated user with permissions to use it can exploit the vulnerability to extract confidential data that he should not have access to from the database. A small test revealed that the vulnerable code gets called when a user creates a task and then previews it:

SQL Injection Test

The point of injection in the executed SQL query is in the WHERE clause. We do not have the full output of the run query displayed on the page and thus, this a blind SQL injection. At this point an attacker can easily extract the hash representing the password of the administrator by sending a series of time-based injections to iterate over and unveil the characters constituting it. Such an injection can for example be done by using the following payload:

/tiki-user_tasks.php?taskId=1&offset=0&sort_mode=priority_desc&tiki_view_mode=view&find=&show_history=0 and if(substring((SELECT hash FROM users_users WHERE userId = 1),1,1)='x', sleep(5), false) --

This leads to the following SQL query being executed:

select distinct `t_head`.*, `t_history`.* FROM `tiki_user_tasks_history` AS `t_history`, `tiki_user_tasks` AS `t_head`, `users_users`, `users_usergroups` WHERE `t_head`.`taskId` = `t_history`.`belongs_to` AND`t_history`.`task_version` = 0 and if(substring((SELECT hash FROM users_users WHERE userId = 1),1,1)='x', sleep(5), false) -- AND `t_head`.`taskId`= 1 ...

In the example injection, the response of the server will be delayed by 5 seconds if the first character of the password hash is an x. One can easily iterate over all possible characters and positions with the aid of a script to extract the whole hash.

Time Line

Date What
2017/10/25 Vulnerability reported to the development team.
2017/12/05 Asked for progress.
2017/12/07 Vendor asked for patch review.
2017/12/10 Reviewed and confirmed patch.
2018/03/08 Vendor released patch.


In this blog post we demonstrated how efficient and time saving RIPS Code Analysis is in detecting security vulnerabilities in complex and large codebases. As an example application, we looked at TikiWiki version 17.1 which consists of more than 1.7 million of lines of code. The code base of TikiWiki was scanned in around 14 minutes. We looked at a typical SQL injection vulnerability and demonstrated how it can be easily verified and patched with the aid of helpful features.

The vulnerability was responsibly disclosed to the developers of TikiWiki and was patched in version 17.2. Patches for the different release branches 12.x, 15.x, and 16.x are also available. If you are still using an older version, we encourage updating.