21/08/25
InjecciódeCSSiinjecciód'ordres
Redacció oficial: Stylish Boss | CAT CTF 2025
Thanks for sharing!
بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ

I know your browser history
Benvingut benvingut benvingut! Avui tinc un escrit especial per a tu, el escrit oficial per al repte Stylish Boss de CAT CTF 25.
Aquest és el meu primer repte que vaig fer per a un Live CTF, i estic molt emocionat de compartir-lo amb vosaltres!
Podeu descarregar els fitxers de repte des d'aquí i provar-ho abans de llegir-lo.
Comencem!
Descripció del repte

Primera mirada
El repte és una aplicació web on els usuaris poden personalitzar el tipus de lletra de la pàgina. També inclou una API "Metadata Stripper", restringida al rol de Cap. Una funció d'informe us permet enviar el vostre perfil, fent que el cap el vegi amb la configuració de tipus de lletra que hàgiu triat.


Això és tot de la IU. Ara endinsem-nos en el nostre codi
Anàlisi de codi
A
auth.js, la funcionalitat Registrar i Login són bastant estàndard, només hi ha un ApiKey generat aleatòriament per a cada usuari en registrar-se.A
main.js, els punts finals / i /profile representen les pàgines d'inici i de perfil. Tots dos apliquen la preferència de tipus de lletra desada de l'usuari des de la base de dades i /profile també incrusta la clau de l'API de l'usuari.Atès que la ruta
/profile representa la vista profile, inspeccionem views/profile.ejs i trobem el següent codi destacable:El valor de
<%- userFont %> s'insereix directament a la propietat font-family sense desinfecció, cosa que la fa vulnerable a la Injecció CSS. A més, la clau de l'API es representa dins d'un <div> mitjançant l'atribut data-internal-api-key.A EJS,<%- %>produeix contingut sense escape, a diferència de<%= %>que escapa dels caràcters HTML i hauria evitat aquest problema.
A continuació, tenim el punt final
/set-font que permet als usuaris establir el seu tipus de lletra, que després s'emmagatzema a la base de dades.El tipus de lletra es desinfecta eliminant els caràcters
< i > per evitar la injecció d'HTML.Els altres punts finals:
/report i /boss/view-theme són una lògica senzilla per fer que el Cap vegi el seu propi perfil amb el tipus de lletra de l'usuari que ha informat.El tercer fitxer
api.js té el codi següent:El programari intermediari
apiKeyAuth comprova si la sol·licitud té una capçalera X-API-Key i la verifica amb la base de dades per assegurar-se que l'usuari és un Cap. Si la clau de l'API és vàlida, permet accedir al punt final /strip-metadata.L'objectiu és robar la clau de l'API Boss, després utilitzar-la per accedir al punt final
/strip-metadata i, finalment, recuperar la bandera. Per començar, ens centrarem a filtrar la clau de l'API del Boss mitjançant la vulnerabilitat d'injecció CSS.Explotació: injecció de CSS
Per obtenir informació sobre l'explotació de la injecció de CSS per exfiltrar dades, aquest article és una gran referència: Com podeu robar dades privades mitjançant la injecció de CSS.
Sabem que la clau de l'API es troba a l'atribut
data-internal-api-key del <div id="api-key-container"> dins de views/profile.ejs.En CSS, determinades propietats poden obtenir recursos externs, com ara:
Això fa possible l'exfiltració de dades mitjançant peticions. Per exemple:
Aquí, sempre que existeixi un
<div>, el navegador intentarà carregar una imatge des del nostre servidor.Per fer-ho condicional, podem utilitzar selectors d'atributs CSS. Per exemple:
Això només s'activa si l'element té l'atribut
data-internal-api-key. Encara millor, l'operador ^= ens permet comprovar els prefixos:Això vol dir que el navegador només enviarà una sol·licitud si la clau de l'API comença amb
sk.Amb aquest truc, podem filtrar la clau caràcter per personatge. Per exemple:
Si la clau comença amb
sk_a, el nostre servidor rep una sol·licitud. Si no, no passa res. Mitjançant la iteració de possibilitats (sk_aa, sk_ab, …) podem forçar brut la clau de l'API completa.Una càrrega útil d'injecció que funcioni pot semblar així:
Aquí sortim del
font-family, injectem el nostre CSS i tanquem netament amb un comentari.En lloc d'endevinar un per un, podem provar diversos prefixos alhora:
Qualsevol regla que coincideixi provoca la sol·licitud, revelant el caràcter correcte.
Primer podeu provar-ho al vostre propi perfil i, a continuació, activar el Boss per carregar el vostre tipus de lletra maliciós mitjançant la funció d'informe. D'aquesta manera, la seva pàgina de perfil filtra la seva clau API directament al vostre servidor.
I així... tens la clau de l'API del cap.
Anàlisi de codi
Ara que tenim la clau de l'API Boss, la podem utilitzar per accedir al punt final
/strip-metadata.El punt final
/strip-metadata espera una capçalera X-File-Name que contingui el nom del fitxer. A continuació, crida a la classe MetadataStripper per processar el fitxer i retornar la seva sortida.A primera vista, sembla que no hi ha gaire marge d'explotació. Tanmateix, com que la classe
MetadataStripper prové del paquet metadata-stripper npm i la nostra entrada es passa directament al seu mètode processFile, val la pena inspeccionar el codi del paquet en si a npmjs.com.
Podem detectar ràpidament una possible injecció de comandaments al paquet, però hi ha una mica de desinfecció que intenta bloquejar-la:
- La primera expressió regular elimina qualsevol cosa que no sigui un caràcter de paraula, un espai o un d'aquests:
${}:()" |*. - La segona expressió regular elimina qualsevol ocurrència de la subcadena
flag(no distingeix entre majúscules i minúscules).
Aleshores, què queda?
- Permès:
a-zA-Z0-9_, espais,$ { } : ( ) " | * - Bloquejat:
f,l,a,g
L'ordre executada és:
Explotació: injecció de comandaments
La nostra tasca: escapar d'aquesta ordre i injectar la nostra. Afortunadament, l'operador de canonades
| està permès, el que significa que podem encadenar una altra ordre.Des del
Dockerfile sabem que la bandera s'emmagatzema a /flag. Normalment, faríem servir cat, less o head, però tots tenen caràcters bloquejats. Tanmateix, more encara està disponible! Perfecte per llegir fitxers.Per tant, una injecció bàsica seria:
Però hi ha un problema: no podem escriure directament
flag (s'han eliminat f, l, a, g) i / també està prohibit.Els comodins
* es permeten, de manera que * podria coincidir amb el nom del fitxer, però more * només ho farà al directori actual, no /flag.Aquí és on entra un bon truc de Linux: expansió de paràmetres. A Bash, podem agafar parts de les variables d'entorn. Per exemple:
Això retorna
/, ja que el primer caràcter de $HOME és /. I com que la sintaxi ${} està permesa, la podem utilitzar per construir el camí.Càrrega útil final:
Que resol:

CATF{Y0U_M4D3_1T_B055_Y0U_D3S3RV3_4_MU5HR00M_45_4_G1FT!}
Això va ser! Has aprofitat amb èxit el repte Stylish Boss i has obtingut la bandera!
IMPORTANT: No t'atreveixes a perdre't el meu altre repte "Underground Maze" que vaig fer amb el meu fantàstic amic Corea: Fes clic aquí. Gràcies <3
Conclusió
Aquest ha estat un repte divertit de fer i espero que us hagi agradat tant com jo. Va ser una gran oportunitat per formar part del CAT CTF 25 i crear un repte alhora que és desafiant i educatiu. Espero els vostres comentaris i suggeriments per a futurs reptes. Gràcies per llegir el meu escrit i espero que hagis après alguna cosa nova avui!
Etiquetes:

