In the SonarSource R&D team we are equally driven by studying and understanding real-world vulnerabilities, then by helping the open-source community secure their projects. This recently led us to uncover and report multiple security vulnerabilities in Codoforum, an open source forum software developed in PHP. The vulnerabilities enable different attack vectors for a complete take over of any Codoforum board with version <4.9 and are rated as critical. No prior knowledge or privileges are required by a remote attacker. We reported all issues responsibly to the affected vendor who released a security patch immediately.
In this blog post we analyze the technical root cause of three vulnerabilities, what security measures were found and bypassed, and how to correctly prevent these in your code. We will look at the vulnerabilities from an attacker’s perspective and demonstrate how various exploitation techniques are used in an attack to sharpen your defender’s mindset.
We found two SQL Injection vulnerabilities and one of these can be exploited as an unauthenticated forum user to extract data from the database. These allow an attacker to fully compromise an administrator account by retrieving a password reset token. Once an administrator account is accessed, the attacker can gain Remote Code Execution on the targeted web server and compromise the system’s host and data.
For demonstration purposes we’ve created a short video that shows the most critical SQL injection vulnerability and its impact.
The vulnerability hides within the API call for fetching forum posts. Its code is defined in the routes.php file. Here, a dispatch function maps a route to a function that processes certain URL parameters. As shown in line 165, a topic ID
$tid (:tid) is processed from the route that can be modified by a malicious user.
This route has neither CSRF protection nor a permission check and can be accessed from any visitor without authentication. The user input $tid is then passed to the get_topic_info() function without any sanitization.
get_topic_info() function, the user controlled variable
$tid is concatenated directly into a SQL query in line 462 which is executed in line 464. This is a textbook SQL injection that allows an attacker to malform the SQL query in order to access other SQL tables and columns than intended. Erroneously, the developer assumed that the parameter
$tid is an integer before it is included into the query as we can see from the comment in line 461.
Although the SQL injection is easily triggered via the get_posts route, the challenge for an attacker is that there is no access to the SQL query’s result (blind SQL injection). Worst-case, an attacker would need to extract data character by character by using timing techniques. However, there is the possibility to extract the result via an uncaught
PDOException because error reporting is enabled by default in Codoforum. This requires less HTTP requests and the data can be extracted in chunks.
The MySQL function
extractvalue() can be abused during a SQL injection attack for this purpose. It constructs an XPath query and checks for correct syntax. When we define a faulty XPath that includes information that we want to read, e.g. the MySQL version number, then this is leaked as part of the error message.
With the help of this error-based technique, an attacker can extract data from the database quickly and efficiently. For example, the attacker could extract all passwords from the users table. This is very inefficient though because Codoforum stores only the hashes of all passwords using the bcrypt algorithm. The attacker would need to make the effort of cracking these hashes in order to login.
There is a more clever way. By requesting a password reset for a user, for example the forum’s administrator, a password reset token is generated and stored in the database. Although the attacker does not have access to the admin’s email to receive this token, he can now abuse the SQL injection to extract that token directly from the database. As a result, the attacker can reset the admin’s password with that token and then login as administrator. From here, the attacker can abuse administrator features to compromise the server as we will see in the last section of this post.
By using prepared statements or an integer typecast it is prevented that an attacker can inject arbitrary SQL syntax and mix user input with the SQL query. This way, the attacker cannot modify the SQL query to its advantage anymore.
But there were alternative ways for an attacker to compromise the Codoforum board software.
The second vulnerability type found was a Path Traversal that allows an unauthenticated attacker to download arbitrary files from the server, such as sensitive configuration files. Although the developers tried to prevent this vulnerability with input sanitization, the filter could be bypassed. Let’s have a look at the details.
The vulnerability resides in the file attachment feature of the forum. Via the route serve/attachment the
attachment() function is called as shown in the code below. Here, in line 64, it calls the constructor
Serve(). Note that there are several routes that lead to the vulnerable
Serve() function and this route can be used as an unauthenticated user.
We now inspect what happens in this
serve() function. In line 37, a user controlled input
$_GET['path'] is retrieved and sanitized. It is concatenated with other strings and then used as a file path in line 42 to open a file that is offered for download. The whole security is based on the
sanitize() function in line 37 which is supposed to prevent a path traversal attack.
The following code listing shows the sanitization approach. In line 123, the characters
.. are removed and then the url encoded representation
%2e%2e is also removed in the next line.
The problem is that the PHP function
str_replace() does not replace the string recursively and is only processed once from left to right. This means that if the variable
$name contains something like
/.%2e%2e./ it will be replaced back to
/../ and the sanitization is bypassed.
Thus a path traversal attack is possible and an unauthenticated attacker can read arbitrary files from the server by traversing in the file system and accessing sensitive files (
…/…/…/other/path/file). This can lead to a full takeover of certain servers hosted with Codoforum.
The faulty sanitization can be fixed by first using
urldecode() and then using
str_replace("..") or by removing the second replacement altogether.
Let’s have a look at how this works. When registering a new user, we can specify an e-mail address which is then reflected in the admin backend. In the following code snippet, in line 679, the registration process is initialized.
The following code shows the simplified
register() function. Here, in line 3, the user input
$_REQUEST['mail'] is retrieved and checked with other information in line 4. If there is no error, such as an invalid or already existing email address, the user will be registered.
For this purpose, the user controlled
filter_var() and its filter option
FILTER_VADLIDATE_EMAIL in line 108. If
According to the PHP documentation, the
"><script>alert(1)</script>firstname.lastname@example.org is valid and will not be rejected by the filter.
Since Codoforum uses the PHP template engine Smarty, the escape modifier of Smarty can be used as a patch by replacing line 51 with the following content:
If an admin visits the user profile to edit (block/delete) our registered user, the XSS payload is rendered in the admin’s web browser and we can perform any action as admin on the page. For example, administrator features can be abused to upload a PHP shell and to execute arbitrary code on the server. A similar XSS issue was found earlier that affected the user name.
As a result, an attacker can smuggle an XSS payload within the email address of a new user which is reflected unfiltered in the HTML response of the admin backend.
In this blog post we analyzed three different security vulnerabilities in Codoforum, a popular board software. Each of these issues could lead to a complete takeover of the application. We’ve learned that a malicious user can take multiple paths when attacking an application and that finding only one single vulnerability is enough to fully compromise its security. Hence it is our task to make our applications as robust and secure as possible. Checking all user inputs properly and leveraging existing and proven sanitization and validation mechanisms is the first step towards a solid defense.
Due to the severity of the issues we’ve postponed the release of our blog post since the release of a fix in March. If you are hosting a Codoforum and didn’t update your installation yet, we highly recommend to do so now. Thanks to the Codoforum team, a patch version was quickly released after our reports.
You can join the discussion about this vulnerability in our community forum.