Les injeccions ocupen la tercera plaça al podi de les vulnerabilitats web més rellevants, segons la classificació d’OWASP (Open Web Application Security Project), al seu darrer rànquing publicat l’any 2021.
Una injecció és un atac que es produeix quan un agent maliciós aconsegueix passar informació no validada a un intèrpret, com a part d’una petició. El receptor, pensant que les dades són legítimes les executa, o permet l’accés a elements privilegiats. Els atacs més comuns d’injecció són a SQL, NoSQL, comandes del sistema operatiu i LDAP.
En aquest article trobareu eines per poder detectar l’existència d’injeccions al nostre codi, i recomanacions per poder prevenir-les, mitigant així les possibles conseqüències.
Es pot considerar que una aplicació és vulnerable a un atac d’aquest tipus en les següents situacions:
- Les dades proporcionades per l’usuari no són validades, filtrades, ni sanejades pel sistema.
- S’invoquen consultes dinàmiques o no parametritzades, sense codificar els paràmetres de forma adient segons el context.
- S’utilitzen dades malicioses dins dels paràmetres de cerca en consultes Object-Relational Mapping (ORM), per extreure registres addicionals sensibles.
- S’usen dades malicioses directament, o es concatenen. De forma que la sentència SQL o comanda resultant conté informació, i estructures amb consultes dinàmiques o procediments alterats.
Les accions recomanades per prevenir aquest problema són les següents:
- Emprar una API segura, que eviti totalment l’ús d’un intèrpret o proporcioni una interfície parametritzada.
- Implementar validacions d’entrades de dades en el servidor, utilitzant entrada positiva o “whitelist”.
- Fer ús de LIMIT i altres controls SQL sobre el número i el tipus de consultes, per a evitar la divulgació massiva de registres en cas d’injecció SQL.
- Fer servir la sintaxi d’escapament específica, per a evitar l’ús de caràcters especials que validen una consulta.
- Filtrar segons la semàntica de l’aplicació, per exemple:
- Barcelona com a nom vàlid de ciutat.
- <b>destacat</b> pot resultar un comentari vàlid si l’aplicació permet un camp amb text enriquit, però no si no és així.
A continuació, es mostra un exemple d’escenari on seria possible realitzar un atac per injecció.
Un cas d’injecció es podria produir en rebre dades de l’usuari i utilitzar-les per fer sentències sobre una base de dades, sense que aquestes passin per cap mena de procés de validació.
El codi de la imatge correspon a un fragment d’una funció Java vulnerable. En aquesta s’utilitzen paràmetres extrets directament de la consulta, sense cap procediment de sanejament, per realitzar una query SQL on s’obté l’usuari amb nom i contrasenya iguals als rebuts. Aquest fet permetria a un atacant enviar sentències SQL malicioses, com ara ‘username=admin;– –‘. El programa, en rebre aquest valor per al nom d’usuari, obté l’entrada vinculada de la base de dades sense importar les credencials vàlides, i retorna true com a resultat. Això succeeix perquè com que no s’escapa l’element, aquest pot passar a formar part de la sentència, en comptes d’únicament ser l’atribut d’un camp. Llavors el que s’executa finalment és “SELECT * FROM usuarios WHERE id_usuario=’admin’;– -“ de forma que la part “AND password='” + password ‘+ “‘”; s’ignora per trobar-se ara comentada. L’atacant, coneixent el nom d’usuari de l’administrador, i suposant que aquesta funció és la que s’utilitza per gestionar l’inici de sessió, aconseguiria accés privilegiat al sistema.
Per solucionar el problema en aquesta situació concreta, podem usar prepared statement per fer la petició, ja que aquesta funció separa el que ha enviat l’usuari de la query, proporcionant així una validació de les dades. En rebre el mateix valor que en el cas anterior, “userrname=admin;– -”, aquesta nova implementació no patiria el mateix problema. El codi en aquest cas escaparia el paràmetre, de forma que “admin;– -” no s’entendria com una part de la sentència, sinó que únicament seria el valor del camp id_usuario.
En qualsevol altre cas, el procediment seria el mateix, s’hauria de buscar la forma d’aconseguir aïllar allò que rebem del front-end de les connexions amb la base de dades. Per fer-ho podem utilitzar un procediment ja existent, com a l’exemple, o bé realitzar les comprovacions necessàries pel nostre compte, de manera curosa, perquè no s’escapi cap cas que pugui comprometre el sistema.
Seguidament, s’adjunta un exemple més visual de les conseqüències que tindria fer ús d’un codi insegur com l’anterior a una aplicació. Per aquesta demostració s’ha utilitzat l’OWASP Juice Shop, una aplicació insegura creada per poder practicar l’explotabilitat de les vulnerabilitats en un entorn segur.
Encara que es poden trobar forats de tots els tipus, l’exemple se centrarà en un panell d’inici de sessió vulnerable a injeccions. L’objectiu és fer login com un usuari administrador sense conèixer les seves credencials.
La primera tasca a realitzar és descobrir una adreça electrònica privilegiada. Inspeccionant els productes a la pàgina principal es poden veure ressenyes dels usuaris, on s’exposa el seu correu com es pot apreciar a la imatge anterior. Com admin@juice-sh.op és gairebé amb total seguretat la direcció de l’usuari admin, provarem d’iniciar sessió al panell utilitzant aquesta nova informació, però encara sense saber la seva contrasenya.
S’ha utilitzat la tècnica descrita a l’anterior exemple: al camp de l’email es col·loca el correu al qual es vol accedir admin@juice-sh.op, en aquest cas, seguit de la condició SQL OR 1=1– –. El servidor en rebre aquests valors per part del client i no realitzar cap validació, entendrà els camps com a part de la sentència SQL que es realitza sobre la base de dades. D’aquesta forma es busca l’usuari que té aquesta adreça (finalitzant el contingut del camp amb la ‘ ) i s’executa la clàusula OR 1=1, que en avaluar-se és true. Finalment, s’inclou “– -“ per comentar la resta de la query, perquè si s’executés, es faria igualment la comprovació de la contrasenya retornant false. En conclusió, allò que s’executaria al servidor seria molt semblant a: SELECT * FROM Usuaris WHERE email = ‘mail enviat’ OR 1=1 – – (AND contrasenya = ‘contrasenya enviada’; comentat, no s’executa). Sempre retornarà true si existeix algun usuari amb la direcció enviada, sense importar la contrasenya que s’adjunti al formulari, aconseguint accedir al seu compte sense conèixer les credencials.
Com es veu a la imatge, els valors anteriors ens han permès obtenir accés al compte de l’administrador, ara ens trobem loguejats com l’usuari admin.
Es podria pensar que protegint el client amb algun tipus d’script que denegués inserir sentències malicioses seria suficient per garantir la seguretat del sistema. La realitat és que les comprovacions en l’àmbit del navegador són molt senzilles de saltar, i resulten totalment inútils si no es prenen les mesures adients al costat del servidor, com les descrites al primer exemple on es mostra el codi.
Un atacant podria evadir el control a client side interceptant les peticions amb un proxy, i modificant els camps amb els valors desitjats fora del buscador.
Com a exemple, se suposa que el panell bloqueja els valors, i aquests es modifiquen pels anteriors interceptant les dades amb BURPSUITE.
Ara s’ha introduït al login els valors “SANTI”, “SANTI” com es pot veure a la primera imatge. En enviar les dades s’ha interceptat la petició amb el proxy i, com es pot apreciar a la segona imatge, els camps email i password són equivalents als del formulari. El següent pas serà canviar els valors per realitzar la mateixa sentència maliciosa que en un panell sense protecció.
En aquesta imatge es mostra el valor maliciós per al camp email. Com el servidor no fa cap comprovació, el resultat serà el mateix: aconseguir accés al compte administrador, sense importar les noves mesures al navegador.
En conclusió, els atacs per injecció succeeixen en confiar en les dades enviades per qualsevol usuari amb accés a l’aplicació. Per tant, és important protegir-se fent comprovacions sobre tot allò que es rep. Tenint en compte sempre que, encara que les proteccions al costat del client poden resultar útils per l’experiència de l’usuari legítim, les mesures de seguretat sempre s’han de prendre al costat del servidor, on la informació és realment processada.