ProjeQtOr - <10.2.2 Direct Object Injection Vulnerability

ProjeQtOr - <10.2.2 Direct Object Injection Vulnerability

As part of our Continuous Automated Red Teaming and Attack Surface Management technology within the watchTowr Platform, we perform zero-day vulnerability research in technology that we see across the attack surfaces of organisations leveraging the watchTowr Platform. This enables proactive defence for our clients and provides forward visibility of vulnerabilities while we liaise with vendors and projects for suitable fixes.

I would like to take a moment today to discuss a vulnerability that was discovered in ProjeQtOr.

"ProjeQtOr is an open-source project management software grouping in a single tool all the features needed to organize your projects. It is simple, easy to use while covering a maximum of project management features."

The watchTowr team identified an authenticated Direct Object Injection during an audit of anomalous technology across our client base, affecting versions 10.2.2 and earlier.

As a quick refresher, a Direct Object Injection vulnerability occurs when unvalidated user input is used to construct objects directly within application code.

Within PHP, the impact of such a vulnerability can be quite severe, allowing an attacker to execute arbitrary PHP code within the context of the affected application, or put simply - allow an attacker to gain control of the affected host and the data held within.

The good news is that the ProjeQtOr team has already resolved the identified vulnerability. The ProjeQtOr team released a patch on March 9th 2023, and CVE assignment is pending. It's important to note that while this patch addresses a security concern, the vendor has not labelled it as a security update.

The Bug

Despite this vulnerability class (Direct Object Injection) being somewhat uncommon, it's actually quite straightforward to understand. Better yet, these vulnerabilities are typically trivial to remediate.

The vulnerable code can be found in tool/getExtraRequiredFields.php and allows a malicious user to execute arbitrary PHP code via an identified Direct Object Injection vulnerability based on input provided within HTTP parameters.

Below is the vulnerable code that can be accessed - pasted here verbatim:

require_once "../tool/projeqtor.php";
 
$objectClass=null;
if (isset($_REQUEST['objectClassName'])) {
  $objectClass=$_REQUEST['objectClassName'];
}
$objectId=null;
if (isset($_REQUEST['id'])) {
  $objectId=$_REQUEST['id'];
} else if (isset($_REQUEST['id_detail'])) {
  $objectId=$_REQUEST['id_detail'];
}
if ($objectClass===null or $objectId===null) {
  throwError('className and/or id not found in REQUEST ('.$objectClass.'/'.$objectId.')');
}
 
$obj=new $objectClass($objectId);
tool/getExtraRequiredFields.php

Let's walk through this...

$objectClass=null;
if (isset($_REQUEST['objectClassName'])) {
  $objectClass=$_REQUEST['objectClassName'];
}

Here, the code checks if the objectClassName parameter is set in the HTTP request. If it is, the value of the parameter is assigned to the $objectClass variable.

$objectId=null;
if (isset($_REQUEST['id'])) {
  $objectId=$_REQUEST['id'];
} else if (isset($_REQUEST['id_detail'])) {
  $objectId=$_REQUEST['id_detail'];
}

This section of the code checks for two different parameters ("id" and "id_detail") in the HTTP request. If either parameter is set, the value of the parameter is assigned to the $objectId variable. If neither parameter is set, $objectId remains null.

if ($objectClass===null or $objectId===null) {
  throwError('className and/or id not found in REQUEST ('.$objectClass.'/'.$objectId.')');
}

This if statement checks if either $objectClass or $objectId is null. If either variable is null, the code calls a function named "throwError" and passes a string message as an argument. The message contains the values of $objectClass and $objectId.

$obj=new $objectClass($objectId);

Finally, the code creates a new object of the class specified by $objectClass, passing $objectId as a parameter.

As both $objectClass and $objectId are set based on user input from the HTTP request, without any validation or sanitization, an attacker could craft a malicious HTTP request that sets $objectClass and/or $objectIdto arbitrary values.

Effectively, an attacker can instantiate an arbitrary class and pass controlled arguments to this new object.

A simple Proof of Concept to demonstrate that this vulnerability is exploitable would look like the below:

https://hostname/tool/getExtraRequiredFields.php?objectClassName=SplFileObject&id_detail=http://SplFileObject.watchtowr.com

In the above PoC, to demonstrate the vulnerability, we call the PHP built-in  SplFileObject class as this class implements a constructor that allows connection to any local or remote URL - allowing us to easily confirm the vulnerability and demonstrate exploitability based on interaction with a host we control.

While this vulnerability is not exploitable by an unauthenticated user, ProjeQtOr ships with a "guest" account by default (with credentials of guest/guest) and enables exploitation of this vulnerability.

Conclusion

I hope you enjoyed this look behind the curtain of a typical codebase we see across our client base! The audit resulted in one vulnerability being reported to the vendor, with a CVE to-be-assigned.

While this is a relatively trivial bug to pull out of a code base, it is a highly-impactful vulnerability in the context of the data that ProjeQtOr is designed to hold - and of course, trivial code execution on an externally facing system is never ideal.

However, the ProjeQtOr team rapidly remediated the vulnerability, which should be commended.

At watchTowr, we believe continuous security testing is the future, enabling the rapid identification of holistic high-impact vulnerabilities that affect your organisation.

If you'd like to learn more about the watchTowr Platform, our Continuous Automated Red Teaming and Attack Surface Management solution, please get in touch.

Timeline

Date Detail
7th March 2023 Vulnerability discovered
7th March 2023 Requested security contact for the ProjeQtOr project
7th March 2023 Received security contact, disclosed to the ProjeQtOr project
7th March 2023 watchTowr hunts through client's attack surfaces for impacted systems, communicates with those affected.
9th March 2023 The ProjeQtOr project acknowledges validity of report, and releases fix in version 10.2.3
16th March 2023 Blogpost and PoC released to public