03/03/25
SSRF,GraphQLienganydememòriacau
7 reptes web | Fawazeer Cyber 2025
Thanks for sharing!
بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ

I know your browser history
Hola! És l'Omar. Benvinguts als meus escrits per al Fawazeer Cyber (cyberfz.com), preparat pel fantàstic Omar Alzughaibi i Anas Almizani.
Us explicaré pas a pas explicant la solució, per què va passar i l'aspecte tècnic, no només la part de seguretat. Submergem-nos!
Reptes
3 de març de 2025
- Tira la porta | Fàcil | Contaminació de paràmetres HTTP (HPP) per evitar les comprovacions d'identificació.
- Fora de l'abast | Mitjà | Cache Deception i SSRF per accedir als elements interns del núvol.
7 de març de 2025
- Pr1v | Fàcil | Introspecció GraphQL per trobar i explotar una mutació.
- Truca'm | Mitjà | Fuga de testimoni JWT mitjançant JS i injecció d'ordres.
10 de març de 2025
- L'altre costat | Mitjà | Travessa del camí al middleware per accedir als punts finals interns.
- L33T | Mitjà | Revisió del codi font que condueix a la injecció SQL i l'explotació de paquets maliciós.
20 de març de 2025
- Procés | Mitjà | Revisió del codi font de Javascript.
Tira la porta
A partir del primer repte, visitant el lloc veuràs un formulari de registre i inici de sessió. Vaig registrar un compte i vaig iniciar sessió. Després d'iniciar la sessió, vaig rebre una pàgina que mostra el meu nom d'usuari i un paràmetre
id=33 a l'URL.
Observant que
id=33 de seguida, em ve al cap IDOR. Així que el vaig canviar a id=1 per provar-lo.
He rebut una resposta
Unauthorized. El backend està comprovant clarament si l'identificador coincideix amb la meva sessió. Següent idea: què passa si envio dos DNI? S'ha provat id=33&id=1.
I aquí està: l'èxit. Desglossem per què va funcionar això.
Aquest és un cas de HTTP Parameter Pollution (HPP). Succeeix quan el backend no gestiona correctament diversos paràmetres amb el mateix nom. Aquí, comprova el primer
id (33) amb la meva sessió, veu que és vàlid, però després utilitza el segon id (1) per obtenir les dades. Aquest desajust és la vulnerabilitat.Això tanca el primer repte.
CyberFZ{1love_1d0r_w17h_p4r4m373r_pull1070n}
Prou fàcil? Anem a la segona.
Fora de l'abast
El segon repte és una mica més complex. En visitar el lloc, registrar-me i iniciar sessió, tinc aquesta pàgina:

És una pàgina amb el vostre nom d'usuari, algunes estadístiques, una pista i un camp d'entrada que utilitzeu per passar un camí al superadministrador.
La pista: "L'estàtica sembla segura, però és sempre la veritat?"
També hi havia el botó
VIEW_STATS que us condueix a /profile/username i podeu veure les vostres estadístiques.
També podeu veure les estadístiques d'altres usuaris canviant el nom d'usuari a l'URL.
Abans de capbussar-me a fons, normalment comprovo totes les coses que tinc, així que vaig comprovar la font de la pàgina i vaig trobar un fitxer js. Com que la pàgina esmentava
superadmin, vaig cercar superadmin al fitxer js i vaig trobar això:
El valor
isSuperAdmin s'està recuperant del vostre emmagatzematge local. I, de fet, quan vaig comprovar el meu emmagatzematge local, el vaig trobar:
Podríeu haver trobat això comprovant directament de totes maneres, és el mateix, només comproveu sempre tot el que teniu.
Ho va canviar a true i també va establir el nom d'usuari a
superadmin i va obtenir una interfície d'usuari diferent:
Teniu una bandera falsa i l'etiqueta del camp d'entrada ha canviat juntament amb la pista: "Un servei que envia sol·licituds al nostre núvol per verificar la integritat dels nostres URL."
Això és el que he trobat fins ara. Ara comencem una mica d'acció.
Tornant a la primera pàgina que tenia (la on isSuperAdmin és fals), vaig enviar una ruta ficticia i vaig rebre aquesta resposta:

Després d'una prova i error i el fet que deia "camí", quan vaig provar "perfil" (una ruta vàlida al lloc web) vaig obtenir algunes credencials:

A més, si passeu
profile/superadmin.css (una ruta d'arxiu estàtic), també obtindreu les credencials. La pista és clara ara, els fitxers estàtics no són segurs.Això està relacionat amb la vulnerabilitat de l'engany de la memòria cau, on el servidor envia una data d'usuari sensible a
/profile/username que no s'hauria d'emmagatzemar a la memòria cau, però, d'altra banda, el servidor de la memòria cau emmagatzema camins que acaben amb extensions com .js i .css, de manera que passeu_TOKEN_3X a la memòria cau. dades del SuperAdmin. Podeu obtenir més informació al respecte des d'aquí.Ara iniciant sessió amb les credencials de SuperAdmin, tenim la mateixa interfície d'usuari que la segona anterior.

Aquí vaig sospitar algun tipus de SSRF (passant
http://localhost o http://127.0.0.1/) però això no va donar res. Tornant a mirar la pista: "Un servei que envia sol·licituds al nostre núvol per verificar la integritat dels nostres URL"., va esmentar "núvol".. Es podria allotjar en algun tipus de servei al núvol que pogués llegir les seves metadades?Petita explicació
Com que això apuntava (potencialment) a un entorn de núvol, vaig començar a pensar en AWS. A AWS, les instàncies sovint exposen metadades mitjançant
http://169.254.169.254/, l'IP local d'enllaç per al servei de metadades d'instàncies. No és un host local (127.0.0.1), que allotjaria serveis directament a la màquina, sinó un punt final proporcionat al núvol accessible només dins d'una instància EC2.Si el servidor s'executava a AWS, una vulnerabilitat SSRF podria permetre'm enganyar-lo perquè l'obtingués de
http://169.254.169.254/latest/meta-data/, donant-li detalls com l'identificador de la instància, els rols IAM o encara millor... la bandera!Nota: si no enteneu completament l'anterior, podeu cercar-los i llegir-ne més als enllaços adjunts o simplement cercant a google. Aquí teniu una [escriptura sobre aquestes filtracions de metadades d'AWS] (https://infosecwriteups.com/leaking-aws-metadata-f5bc8de03284).
Ara provem-ho!
http://169.254.169.254/latest/meta-data/ no va funcionar, però només http://169.254.169.254 va funcionar i va obtenir el camí de bandera a /flag.txt

CyberFZ{cach3d_3xpl0rati0n_t0ssrf}
I això és tot pel primer dia dels Fawazeer Cyber Challenges.
Ara per al dia 2, comencem amb un repte fàcil.
Pr1v
Em vaig disparar, vaig visitar el lloc, em vaig registrar i vaig iniciar sessió, vaig rebre aquesta pàgina:

Quan faig clic a
/flag, he rebut Autorització denegada.No hi havia més funcionalitats, així que vaig saltar a eructar.

El primer que em va cridar l'atenció va ser el punt final
/graphql. Si heu estudiat algun concepte bàsic de GraphQL, sabríeu que el primer que heu de fer és comprovar la introspecció.Si la funció d'introspecció deixa activa, podeu obtenir tot l'esquema de l'API i veure totes les consultes i mutacions que podeu fer. (Estudi de Portswigger)
Utilitzant la consulta següent:
Vaig obtenir l'esquema i vaig trobar una mutació anomenada
setRole
Va enviar la següent mutació:
I va rebre la següent resposta:
Va utilitzar el testimoni per obtenir la bandera de
/flag.CyberFZ{ju5t_4_gr4phql_4774cks}
Truca'm
Segon repte... un repte del qual em va agradar molt i vaig aprendre una lliçó valuosa.
El primer que vaig fer eructar, vaig navegar pel lloc, em vaig registrar i vaig iniciar sessió

Hi havia una funcionalitat Restableix la contrasenya que accepta un nom d'usuari.
Això era tot fins ara, no hi ha gaires funcionalitats, així que vaig anar a eructar per examinar les peticions. Una de les coses que vaig veure va ser la sol·licitud de
/api/admin, tot i que em va negar l'accés.La descripció del repte era "Una única trucada, un sol testimoni. El trobareu?"
Així que el primer amb què vaig començar a jugar va ser el token JWT. Havia provat gairebé totes les tècniques que conec, però això no em va donar res.
(La majoria d'aquestes tècniques són aquí)
"Comprova sempre tot el que tinguis". No vaig seguir aquesta regla i vaig anar directament a provar JWT, això em va costar temps. Així que vaig tornar al lloc i vaig comprovar la font de la pàgina i vaig trobar un fitxer js.

Com que es tractava d'una aplicació React que es basa en gran mesura en js del costat del client (pots saber que utilitzant extensions com Wappalyzer),
Vaig cercar
api i vaig obtenir alguns resultats:
No estava tan organitzat, així que vaig descarregar el fitxer i el vaig obrir a VSCode i després vaig fer servir més bonic per formatar-lo. (També podeu utilitzar la versió en línia)
Vaig comprovar aquestes trucades a l'API i vaig trobar un nou punt final
/api/clone, però també em va negar l'accés. Tots els altres punts finals eren normals excepte aquest /api/reset-password:
Hi havia aquest paràmetre anomenat
callbackUrl que no em vaig adonar de cap lloc a l'eruc.El fitxer js pot semblar difícil per a alguns que no mencionin que també és obfsticat, una manera d'evitar-lo és passar-lo a qualsevol model d'IA i us ho explicarà.
De qualsevol manera per mantenir les coses senzilles, ho vaig provar a la meva sol·licitud amb el meu enllaç de col·laborador de burp i va ser un èxit! (Podeu utilitzar webhook.site gratuïtament)


Vaig posar el testimoni al meu emmagatzematge local i vaig obtenir una nova interfície d'usuari:

Va enviar una sol·licitud de Clone Repository i va anar a eructar. Va rebre la resposta següent:
Interessant.. Tinc
/bin/sh: git: not found, això és una indicació que l'URL que he passat s'insereix a una ordre d'intèrpret d'ordres i s'executa, però com que git no s'ha instal·lat, he rebut aquest error.Ara tenim una vulnerabilitat d'injecció d'ordres (Preferit personal <3). L'ordre probablement sigui una cosa així com
git clone <url>. Si heu provat de passar qualsevol ordre com ls o whoami, obtindreu el mateix error, la raó és que la vostra ordre s'està executant com a argument per a git, així que l'hem de separar d'alguna manera.Per fer-ho, podem utilitzar
; o && perquè s'executi sol. Però s'estava filtrant.Vaig provar altres tècniques com
| (Pipe), ( ) (subshell)... fins que vaig tenir èxit amb \n (caràcter de nova línia)
I ja està! S'ha trobat el falg al directori arrel.

CyberFZ{J5_R3c0n_70_1npu7Byp455_70_RC3}
Al final, només necessitava una mica de reconeixement i excavació. La lliçó apresa és començar senzill i després anar complex! Això embolica el dia 2. Espero que us ho passeu molt bé llegint això!
Dia 3! Avui tenim un repte de caixa blanca! Genial, he? mantenim les coses bones al final i comencem amb la de la caixa negra
L'altre costat
El lloc era bastant bàsic, registre i inici de sessió, alguns punts finals amb un per recuperar productes, la majoria estàtics, amb poca funcionalitat.
Vaig saltar a eructar per investigar més.

Hi havia 2 pistes:
- Diferents trucades, diferents veritats. Els escoltes?
- Les API estan trucant, però saps què diuen?
"Tricades diferents".. que podria estar relacionat amb algun tipus d'API de middleware entre el client i el servidor intern. També a la segona pista "API estan trucant", que admet l'assumpció d'una API de middleware.
De què estic parlant?
Aquest programari intermediari es troba just entre el client i el servidor intern. És el pont que manté tot connectat, movent dades d'anada i tornada. Penseu en això com un intermediari, pren el que el client demana (com una llista de productes o un inici de sessió) i ho passa al servidor, després agafa la resposta del servidor i la torna.
Pot modificar o comprovar coses al llarg del camí. Per exemple, podeu colpejar un punt final com
/api/{something-you-passed-here} i el programari intermedi lliuri aquest {something-you-passed-here} al servidor per processar-lo.A la part del servidor, probablement és un altre punt final local, per exemple
http://127.0.0.1:3000/internal-endpoint/{something-you-passed-here}, de manera que en el nostre exemple el middleware analitza això després del /api/ i l'envia al servidor. El servidor fa les seves coses, com ara obtenir dades o executar una comprovació, i el programari intermediari s'assegura que us torni.Llavors, què passa si el programari intermedi no desinfecta ni comproveu el que passeu? Podríeu enganyar-lo perquè enviï la vostra sol·licitud a un punt final diferent mitjançant el recorregut del camí o tècniques similars. I això és el que tenim aquí!
Al punt final
/api, passant ../../../../ després, vaig rebre la resposta següent:
Aquesta és la pàgina arrel del punt final intern amb el qual està interactuant el servidor. Tenim un punt final
/admin-login que vam descobrir mitjançant el recorregut del camí. Hi vaig accedir per /api/../../../../admin-login.A continuació, només va ser una simple injecció SQL per obtenir la bandera:

CyberFZ{3c0nd4ry_c0nt3xt_c4n_b3_h4rmful!}
L33T
Ara entrem al portal Mystery Vibes!

Aquest és un repte de caixa blanca. Primer vaig navegar pel lloc, em vaig registrar i vaig iniciar sessió. Vaig iniciar sessió com a usuari estàndard. No hi ha gaire, així que vaig entrar a VSCode per comprovar el codi font.

És una aplicació node.js, el primer que comprovo són els paquets npm. Pot ser que hi hagi una versió antiga d'un paquet que tingui una vulnerabilitat coneguda.
Però no n'hi havia, així que passem al fitxer principal
server.js.Per fer les coses breus, aquí teniu el fitxer
server.js: crea taules en base de dades, afegeix un compte d'administrador, inicialitza algunes funcions importants per a l'autenticació i l'autorització i defineix les rutes.Podeu comprovar el codi font vosaltres mateixos des d'aquí, només inclouré les parts importants.
Aquesta és la part on es crea la taula d'usuaris. tingueu en compte que la columna
role està establerta a user de manera predeterminada.Aquí tenim una funció que verifica el rol de l'usuari i si no coincideix amb el rol requerit, retorna Accés denegat.
La lletra del codi notem que
authorizeRole('admin') s'utilitza per protegir les rutes d'administració. Així que ara sabem que tenim 2 rols, user i admin.Després d'algun codi, podem notar una injecció SQL clara al punt final d'inici de sessió.
L'he aprofitat per actualitzar el meu rol a
admin.

Aquí tinc una nova funcionalitat (Calculadora), era el punt final
/api/eval.Aquesta expressió és força sòlida, només permet els nombres i els operadors matemàtics bàsics. JSFuck em va venir al cap, és una tècnica per escriure qualsevol codi javascript utilitzant només 6 caràcters. però aquests personatges no estaven permesos aquí.
Després d'un temps al codi, no es van trobar cap problema de lògica, així que vaig comprovar els paquets:
Tots eren habituals per a una aplicació nodejs excepte una:
tasks_mangement (Si no teniu experiència en desenvolupament, podeu passar-la a AI i demanar-li paquets poc comuns)Una nota al marge: qualsevol persona del món pot publicar un paquet a npm, penseu-hi com un dipòsit públic de paquets.
Vaig visitar npmjs.com i vaig cercar
tasks_mangement, vaig trobar un paquet que es va publicar fa pocs dies.
Vam comprovar el codi font del paquet i vam buscar la funció
tasks_viewer utilitzada al nostre codi font:Explicació: La funció
atob descodifica una cadena codificada en base64, després s'utilitza la Function["constructor"] per crear una nova funció a partir de la cadena descodificada i, finalment, s'executa a causa de la () al final.Function["constructor"]: Això accedeix directament al constructor de l'objecte Function. El constructor de funcions a JavaScript us permet crear una funció nova a partir d'una cadena de codi en temps d'execució. És similar a eval(), però crea una funció autònoma en lloc d'executar codi en l'àmbit actual.(Si no ho enteneu completament, us recomano xatejar una mica amb IA per entendre com funciona)
Ara... on s'utilitza
tasks_viewer al nostre codi?Per tant, la nostra càrrega útil estarà en una descripció de la tasca i l'executem accedint al punt final
/api/tasks/:id.La sortida no es retorna directament, de manera que es troba fora de banda (OOB). Utilitzarem curl ja que podem veure al Dockerfile que està instal·lat.

El meu comandament serà:
Ara per fer-ho executar utilitzarem el paquet
child_process, per fer-ho en una línia faríem:Codificar-lo en Base64 -> Posa-lo a la descripció de la tasca -> Accedir al punt final -> Obtenir la bandera!

CyberFZ{1s_th3_p4ck4ge5_b3_vuln3r4bl3}
I això és tot pel dia 3 del Fawazeer Cyber Challenges! Espero que hagis gaudit llegint això!
Últim dia! Comencem!
Procés
Eruc disparat, navegat pel lloc, registrat i iniciat sessió.
No he trobat gaires funcionalitats, així que... javascript temps! (Aquests Fawazeer realment em van fer voler cavar més en fitxers js :D)
Ara això no trigarà gaire, tot el que heu de fer és obtenir els punts finals i entendre el flux :) (descarregueu el fitxer js des d'aquí)
Vaig poder veure al meu historial d'eructes alguns punts finals que començaven per
/api/, així que ho vaig cercar i vaig obtenir els punts finals següents:/api/login/api/register/api/profile/api/reset-password/api/user/details/api/notes
Ja hem vist els endpoints
/api/login, /api/register i /api/profile en burp, així que comprovem la resta.Començant amb
/api/user/details un:Aquí provant només aquest punt final no us aconseguirà res, així que vaig provar d'afegir
1 (suposant que aquest és el primer usuari que és admin): /api/user/details/1 i vaig obtenir el següent uuid:Què fer-hi? Continuem amb els altres punts finals.
en aquest punt final de restabliment de la contrasenya, requereix un
uuid i un newPassword. Això ho tinc! Anem a provar doncsI va rebre la següent resposta:
Va bé, oi? 😅
El punt final restant és
/api/notes, mirem-ho:Aquí requereix
Authorization capçalera i note al cos de la sol·licitud. Si heu intentat enviar una sol·licitud amb el vostre testimoni normal, obtindreu:Així que vaig utilitzar el testimoni que vaig obtenir abans amb una nota simulada i vaig obtenir:
Interessant, podria ser LFI llavors. S'ha provat
../../../etc/passwd
Bingo! A continuació s'ha provat
../../../flag.txt
Teniu
Invalid character detected!, hi ha algun tipus de filtre. Després de jugar una mica, va ser ../flag el que s'està filtrant, així que passar ../../.././flag.txt o ../../..//flag.txt em va aconseguir la bandera!
CyberFZ{pr0c_pr00c_1t_sh0uld_b3_l34rn}
Tot estava al js! Pareu molta atenció als vostres pentests! 🚀 Troba'm a X | Twitter. Estigueu atents per a més! 🚀
Etiquetes:

