Party Cat0%

18/09/25

Encadenant6errorsaRCE

Redacció oficial: Full Stack Disaster | ConnectorsCTF 2025

Thanks for sharing!

بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ

Encadenant 6 errors a RCE
I know your browser history
Doncs bé... un altre repte del Sr. Bolet. Aquest té moltes coses que encadenaràs per aconseguir un RCE!
Aquest escrit podria ser llarg, així que... comencem de seguida. Descarregueu el repte des de aquí
Solucionador d'aquí

Codi font

Comencem pel nostre punt d'entrada: index.js. El més notable són les capçaleres csp:
Que en resum vol dir:
  • Només permeteu recursos del mateix origen (self) i cdnjs.cloudflare.com
  • Permetre l'avaluació (avaluació no segura)
Això ens pot limitar una mica si hi ha un XSS. ja ho veurem.

A continuació les nostres rutes:

Les rutes d'autenticació són bastant estàndard, l'única cosa que cal esmentar és que després d'iniciar sessió obtindreu una galeta csrf_token addicional.

Per a les rutes d'enganxament on podeu crear enganxes (notes), hi ha un programari intermedi pesat de llista negra:
Després d'una anàlisi, podeu dir que només permet un conjunt molt limitat d'etiquetes HTML, inclosa l'etiqueta <script>..?? però no em permet escriure entre <script> i </script>. Puc utilitzar <script src=...>, però, puc utilitzar qualsevol atribut a les etiquetes permeses.
Això és interessant. Aleshores, hauré d'allotjar la meva càrrega útil en algun lloc i carregar-la? però què passa amb el CSP? En breu ho veurem.

Les rutes d'informes també són bastant estàndard, només cal que informeu d'una enganxa per ID perquè l'administrador la revisi.

Les rutes de pujada només es limiten a l'administrador amb alguns filtres i lògica a l'interior, així que les mantindrem després de tractar primer aquest XSS.

A utils/bot.js, el bot inicia sessió com a administrador, elimina csrf_token i visita la pega informada:
La galeta és httpOnly

A l'arrel de la base de codi hi ha el fitxer nginx.conf:
Podem veure que la ruta /report només està permesa des de localhost. Aquest és un punt final crucial per a nosaltres per lliurar la càrrega útil XSS a l'administrador, de manera que hem de trobar una manera d'accedir-hi.

Primer error: configuració incorrecta de Nginx

Si cerqueu una mica sobre les configuracions incorrectes de nginx, podeu esbrinar que el problema es troba a la ubicació /api. S'aplica a /auth/. El problema és amb la barra inclinada final, ha d'haver estat /api/ per proxy correctament.
Explicació ràpida: Quan es fa una sol·licitud a /api/something, nginx eliminarà la part /api i reenviarà la sol·licitud a http://app:3000/auth//something (observeu la doble barra). Si passeu /apisomething, nginx eliminarà la part /api i l'enviarà a http://app:3000/auth/something. Ho entens? Podem tornar a l'arrel utilitzant /api../, es resoldrà a /auth/../ que és /. I així podem accedir a qualsevol ruta que vulguem inclosa /report.
Nginx misconfigiration
Consulteu aquest article per obtenir més informació.

Segon error: bypass XSS i CSP

Ara podem accedir a la ruta /report, però com entreguem la càrrega útil XSS a l'administrador? Hem de crear una pega amb la nostra càrrega útil i informar-ne.
Sabem que podem utilitzar <script src=...> per carregar un script extern, però el CSP només permet self i cdnjs.cloudflare.com. No podem allotjar la nostra càrrega útil en cap d'ells. Però espera, què passa si podem penjar la nostra càrrega útil a cdnjs.cloudflare.com?
Després d'algunes cerques, descobrireu que, de fet, podeu allotjar els vostres escrits en alguns CDN com jsDelivr, però no podeu al CDN de CloudFlare. Comprovem la llista negra una vegada més.
L'etiqueta <div> està permesa i permet qualsevol atribut. Aleshores, hi ha alguna manera de poder executar js des d'un atribut <div>? Hi ha marcs que ho permeten, com AngularJS i AlpineJS. Què passa si podem carregar un d'aquests marcs des de cdnjs.cloudflare.com i utilitzar-lo per executar la nostra càrrega útil?
Podem utilitzar AlpineJS per a això, està disponible a cdnjs.cloudflare.com. Podem utilitzar l'atribut x-init per executar la nostra càrrega útil. Creem una càrrega útil senzilla per provar-ho:
XSS PoC
Increïble! Ja tenim el nostre XSS...
Ara què?

Truc lateral (no relacionat amb el repte)

Si la galeta no fos httpOnly podríem haver-la robat. Et preguntes com ho faries amb aquest csp estricte?
Si teniu una galeta que no és httpOnly amb un csp estricte, podeu fer que l'administrador afegeixi una nota de les seves galetes utilitzant les vostres galetes i simplement vegeu la nota al vostre perfil. Exemple de càrrega útil:

Ara tornem al repte, com que no podem robar la galeta, podem intentar que l'administrador faci alguna cosa per nosaltres a l'aplicació (recordeu que només podem interactuar amb l'aplicació, no podem fer-lo fer cap extern a causa del csp), encara tenim aquesta funcionalitat de pujada a la qual només l'administrador pot accedir. Anem a comprovar-ho.

Tercer error: càrrega de fitxers i recorregut de ruta

upload.controller.js:
Analitzem aquests filtres: primer elimina qualsevol ../ del nom del fitxer, després comprova si el nom del fitxer acaba amb .jpg, .jpeg o .png (no distingeix entre majúscules i minúscules). Finalment, limita el nom del fitxer a 20 caràcters.
Tenim una protecció de travessa del camí, però observem que s'utilitza .normalize("NFKC"). Aquesta funció normalitza els caràcters Unicode, de manera que podem utilitzar alguns trucs Unicode per evitar els filtres.
utilitzant (U+ff0f) en comptes de / podem evitar el recorregut del camí ja que la normalització s'està produint després de l'eliminació de ../. Podeu accedir a diferents codificacions com aquesta des d'aquí (Descarregueu-la i obriu-la amb un navegador).
Genial! Ara podem pujar un fitxer a qualsevol camí que vulguem. Però què passa amb la comprovació d'extensió? Hem observat que trunca el nom del fitxer a 20 caràcters, de manera que podem construir el nostre nom de fitxer perquè tingui exactament 20 caràcters i després afegir .jpg al final perquè es trunqui. Exemple:
Ara podem pujar un fitxer a qualsevol camí que vulguem amb el nom que vulguem!

Provem-ho! Inicieu la sessió com a administrador a la vostra instància local i proveu de pujar una imatge de prova, inspeccioneu la sol·licitud en burp:
Upload Request
Upload Request
Hem penjat correctament un fitxer a un altre camí! Què podem fer amb això?
A views/ hi ha algunes plantilles ejs, podem sobreescriure una d'aquestes plantilles i obtenir un SSTI > RCE!
Views index.ejs upload
S'ha sobreescrit index.ejs correctament! Tingueu en compte que he utilitzat /// a la càrrega útil per assolir aquest límit de 20 caràcters.
index.ejs overwritten
Ara per a la nostra càrrega útil SSTI, he utilitzat:
SSTI PoC
I aquí el tenim! RCE aconseguit!

Encara no s'ha fet, ho hem implementat com a administrador, però necessitem que l'administrador ho faci per nosaltres.
Utilitzarem l'XSS per fer que l'administrador ens carregui un fitxer.
Però... està protegit per csrf:
Programari intermedi CSRF:
És un simple hash md5 de username:SALT. Sabem que el nom d'usuari és admin, però el SALT s'Esborra. Sense complicar massa les coses, si proveu de força bruta descobrireu que és mushrooms.
Només heu de registrar un usuari (anomenar-lo test), iniciar sessió i obtenir el vostre testimoni csrf de la galeta i, a continuació, forçar la sal fins que obtingueu el mateix testimoni. Al final la sal és mushrooms.
Ara forgeu el testimoni csrf per a l'administrador i feu que la càrrega útil XSS carregui el nostre fitxer ejs maliciós:
Afegiu-ho a una pega, informeu-ho mitjançant la configuració incorrecta /api../report nginx i espereu que l'administrador la visiti.
Final
I aquí el teniu, podeu obtenir la bandera del fitxer config/constants.js. Baixeu l'script del solucionador des d'aquí.

Aquest repte tenia una mica de tot. L'objectiu principal del repte és aprendre a encadenar múltiples vulns en un sol atac. Sé que simplement pots explotar cadascun per separat, però encadenar-los és la part complicada! Espero que l'hagueu gaudit tant com jo mentre l'escrius. Gràcies per llegir!
Estic obert a qualsevol sol·licitud de creació de reptes, podeu contactar-me a X/Twitter @MushroomWasp o enviar-me un correu electrònic a MushroomWasp@gmail.com!
Ens veiem a la propera!

També et pot interessar