20/02/25
JWTAlgConfusióicondiciódecarrera
Bypass 2FA | NextGen Defense CTF 2025
Thanks for sharing!
بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ

I know your browser history
Bé, hola i benvinguts de nou a un altre nou escrit. Aquesta vegada estava jugant en solitari a "NextGen Defense CTF 2025", tenia uns reptes força interessants. S'ha aconseguit obtenir un 4 de 8 a la categoria Web. En aquest escrit, us explicaré un d'ells.
Abans de començar, assegureu-vos de provar-ho vosaltres mateixos, podeu trobar el repte aquí. Comencem.
JWT
Quan obriu el codi font, obtindreu 2 fitxers:
index.js i customcrypto.js. Comencem mirant customcrypto.js:Nota: no posaré aquí tot el codi a causa de la seva longitud, només les parts importants. Podeu descarregar el repte complet des de l'enllaç anterior.
L'objectiu principal d'aquest fitxer és bàsicament generar un testimoni JWT i verificar-lo.
La part interessant és que verifica l'algorisme utilitzat al testimoni i actua en conseqüència:

En aquestes situacions, si podem utilitzar la clau pública per validar el testimoni, podem forjar el nostre propi testimoni i evitar la verificació. Això s'anomena JWT Algorithm Confusion.
Confusió de l'algoritme JWT
Hi ha aquests dos tipus principals d'algorismes utilitzats a JWT:
HS256 i RS256.RS256 és un algorisme asimètric, el que significa que utilitza un parell de claus pública/privada. El servidor té les dues claus.- Clau priavate -> s'utilitza per signar el testimoni JWT
- Clau pública -> s'utilitza per verificar el testimoni JWT
Normalment, si la clau pública està disponible per a nosaltres, no podem fer gran cosa, perquè no tenim la clau privada per signar el nostre propi testimoni.
D'altra banda,
HS256 és un algorisme simètric, el que significa que utilitza una única clau tant per signar com per verificar el testimoni JWT.I aquí sorgeix el problema. Podem forjar el nostre propi testimoni i signar-lo amb la mateixa clau que utilitza el servidor per verificar-lo.
Tenim 2 condicions:
- El servidor no està comprovant l'algorisme utilitzat en el testimoni i simplement verifica en funció d'ell.
- Tenim la clau pública.
Aplicació principal
Ara mirem el fitxer
index.js! Quan l'obriu per primera vegada, trobareu la clau pública esperant-vos:I aquí la teniu, la vostra primera vulnerabilitat, continuem i veiem com la podem utilitzar.
Per resumir les coses, tenim un objecte d'administració i els punts finals següents:


Al punt final de
/register podem registrar un usuari nou que afegeix un objecte nou a la base de dades, aquí sospitava que hi havia contaminació de tipus Proto, però tenia una llista blanca i utilitzava Object.freeze(Object.prototype); a la part superior per evitar-ho.Al punt final
/login no tenim res especial, només un inici de sessió senzill que retorna un testimoni JWT amb el vostre id a la càrrega útil del testimoni (dades).Ara a
/2fa punt final:Valida el vostre testimoni i comprova si teniu l'identificador d'administrador.
Tingueu en compte que aquí podem utilitzar la vulnerabilitatJWT Algorithm Confusionper evitar la validació de l'identificador d'administrador.
També envia el codi 2FA a
emailServiceURL, podria tenir una vulnerabilitat SSRF per filtrar el codi?Comprovem el punt final del
/validate:Aquí també es valida el vostre testimoni i comprova si teniu l'identificador d'administrador. I com podeu veure, recuperarem la bandera si tenim el codi 2FA correcte (que s'està llegint d'un fitxer - això és important). Llavors, com ho podem aconseguir?
El
SSRF que he esmentat anteriorment no funcionarà, i aquí és per què:L'únic lloc on puc afegir el meu propi URL controlat és quan em registre.
emailServiceURL és a la llista blanca:Però aquí el problema és que hauria d'utilitzar el meu propi testimoni (que té un altre identificador que el de l'administrador) per tal de fer que el servidor utilitzi aquesta URL controlada, però com podeu veure a continuació, comprova l'administrador
id abans d'enviar el codi 2FA, així que hem d'esbrinar una altra manera.Condició de carrera
Sempre que veieu alguna cosa que requereix temps (per exemple, consultes de bases de dades, operacions de fitxers, etc.) en una aplicació web, hauríeu de pensar en
Race Condition.Condició de la cursa simplement passa quan dues o més accions intenten passar al mateix temps, i una pot dependre d'una altra, provocant resultats inesperats.
Mirem de nou el punt final
/2fa especialment la part on fa el fitxer:Desglossem-ho:
- Obre un fitxer.
- Genera una cadena aleatòria.
- Valida el
emailServiceURL. - Envia el codi 2FA al
emailServiceURL. - Escriu el codi 2FA al fitxer.
- Tanca el fitxer.
Observeu que el fitxer s'obre, després es produeixen algunes operacions, durant aquest temps el fitxer està buit, el que significa que el valor dins és
null en aquest curt període de temps.Recordeu que el 2FA s'està llegint des d'un fitxer allà dalt al punt final
/validate? aquí teniu la part corresponent:Per tant, si podem enviar la càrrega útil
null al punt final /validate al mateix temps que s'obre el fitxer però encara no s'ha escrit, podem obviar la validació 2FA.I aquesta és la nostra solució! Ara comencem l'explotació.
Explotació
Primer, forgem el nostre propi testimoni amb l'algorisme
HS256:sortida:
Ara només cal que envieu una sol·licitud POST al punt final
/2fa i al punt final /validate un darrere l'altre fent servir la funció burp tab group (No l'inclouré aquí per fer-ho breu, simplement podeu buscar-lo)La segona sol·licitud a
/validate tindrà null càrrega útil de la següent manera:Nota: pot ser que no funcioni des de la primera vegada, però seguiu intentant-ho i ho aconseguireu de manera efectiva.
Això acaba! Van ser 3:30 hores escrivint aquest escrit 🥀, espero que us hagi agradat. Si teniu cap pregunta o comentari, no dubteu a posar-vos en contacte amb mi a X | Twitter.
Feliç Hacking! 🚀
Etiquetes:

