26/01/26
ComladiscrepànciaJSON-JavaScriptcondueixaRCE(Lodash)
Redacció oficial: gap | 0xL4ugh v5
Thanks for sharing!
بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ

I know your browser history
"Un cop el veieu, no el podreu desviar".
hola!! La redacció del repte "Gap" finalment ha arribat, aquest repte no es tractava de trobar una cadena de gadget complexa a la lògica de l'aplicació. Es tractava d'explotar un desajust fonamental entre com JSON defineix les dades i com JavaScript defineix el codi. Creu-me, gaudiràs d'aquesta!
Enganyarem a
lodash.template perquè tracti una única clau d'objecte JSON com a arguments de funció múltiples, cosa que ens permetrà introduir de contraban una càrrega útil RCE mitjançant els paràmetres predeterminats d'ES6. Anem a desglossar-ho pas a pas.Descarrega el repte des d'aquí
1. El constructor Function().
Per entendre aquesta explotació, heu d'entendre exactament com funciona
new Function() a JavaScript. És el mecanisme bàsic que utilitza Lodash per compilar cadenes en plantilles executables.La majoria de desenvolupadors veuen això:
Però els primers arguments són només cadenes. Si passeu una matriu, JavaScript s'uneix automàticament amb comes.
El motor de JavaScript analitza aquesta cadena (
"a,b") com a llista formal de paràmetres. No li importa que a i b provinguin d'una matriu o d'una sola cadena. Només veu la coma com un separador.On és el dnager? Si podem controlar aquesta cadena, podem injectar comes. Si podem injectar comes, podem definir nous arguments que el desenvolupador mai va voler existir.. 😃
2. L'error: Confiar en Object.keys()
A
lodash.template, la biblioteca us permet passar un objecte imports. Això està pensat per a funcions auxiliars (com formatDate).Aquí teniu el codi vulnerable real de
lodash.js:Lodash fusiona les opcions de l'usuari amb la configuració i després extreu les claus i els valors. De manera crucial, confia cegament en
importsKeys.Unes línies més tard, construeix la funció de plantilla:
El problema aquí és que
importsKeys es passa directament com a primer argument a Function. Se suposa que aquestes claus són només noms de variables. Realitza sense validació.3. Injecció de coma
Aquí és on xoquen JSON i JS.
En JSON, aquesta és una única clau:
Quan Lodash processa això:
- Claus:
["context, injected"](Matriu amb 1 cadena) - Valors:
["value"](Matriu amb 1 cadena)
Quan
new Function() rep aquesta matriu de claus, la converteix en una cadena: "context, injected".El resultat:
Hem desincronitzat correctament la signatura de la funció de les dades.
- La funció espera 2 arguments (
context, Zinjected). - Lodash només proporciona un valor 1 (
"value").
Això crea un "Gap" (d'aquí el nom 😁). El primer argument (
context) es menja el valor ("value"). El segon argument (injected) es deixa morir de gana: rep Zundefined.4. El disparador: paràmetres per defecte de l'ES6
En JavaScript modern, podeu definir valors predeterminats per als arguments. Aquests s'executen només si l'argument és
undefined.Has d'entendre bé aquesta frase, torna a llegir-la
Si anomenem
test(undefined), el codi s'executa.No necessitem injectar a la funció body. No necessitem sortir d'un context de cadena. Executem codi durant la fase d'inicialització de l'argument, abans que s'executi el cos de la funció. Endreçat, oi?
5. Estratègia d'explotació A: el mètode "Fixat".
No podem només enviar una càrrega útil en brut perquè Lodash és "útil". Afegeix automàticament el seu propi objecte de biblioteca (
_) al final de les importacions.Si enviem a cegues la nostra càrrega útil, la llista d'arguments és així:
function(unused, payload, _)I els valors són així:
["val", lodashLibraryObject]Els valors llisquen.
unused obté "val". payload obté lodashLibraryObject. Com que payload no és undefined, el nostre codi no s'executa.La solució: fixar _
Incloem explícitament
_ al nostre JSON per controlar l'alineació.La càrrega útil:
El flux d'execució:
-
Anàlisi de claus: Lodash veu les claus:
["_", "unused, x = console.log('PWNED')"]JS Engine veu arguments:_, unused, x(més el codi d'assignació) -
Anàlisi de valors: Lodash veu els valors:
["pinned", "val"] -
El mapeig (el moment de la veritat):
| Argument de la funció | Valor rebut | Resultat |
|---|---|---|
_ | "pinned" | Tasca estàndard |
unused | "val" | Tasca estàndard |
| ZZMDX4ZZZ | ZZMDX5ZZZ | Es van quedar sense valors! S'executa el paràmetre per defecte. |
6. Estratègia d'explotació B: el mètode de la "excés d'extensió".
Alternativament, podeu triar no per combatre la injecció predeterminada de
_, sinó empassar-la.Si sabem que Lodash afegirà
_ a les claus i l'objecte biblioteca als valors, podem estructurar la nostra càrrega útil per "menjar" aquest valor addicional i encara quedar-nos curts.La càrrega útil:
El flux d'execució:
-
Anàlisi de claus:
- Clau d'usuari:
"a,b,c = ..." - Clau per defecte:
"_"(afegida per Lodash) - Signatura resultant:
function(a, b, c = ..., _)
- Clau d'usuari:
-
Anàlisi de valors:
- Valor d'usuari:
"bruh" - Valor per defecte:
lodashLibraryObject(afegit per Lodash) - Valors resultants:
["bruh", lodashLibraryObject]
- Valor d'usuari:
-
El mapeig:
| Argument de la funció | Valor rebut | Resultat |
|---|---|---|
a | "bruh" | Omple pel teu valor |
b | lodashLibraryObject | Emplenat per l'opció predeterminada _ "lliscant" sobre |
| ZZMDX5ZZZ | ZZMDX6ZZZ | Es van quedar sense valors! S'executa el paràmetre per defecte. |
_ | undefined | Irrellevant |
Aquest mètode és possiblement més net, ja que requereix menys claus a la càrrega útil JSON, però requereix entendre que esteu creant tres ranures (
a, b, c) per consumir dos valors ("bruh", lodashLib).7. Càrrega útil final
Ho combinem tot. Utilitzem la injecció de comes per crear el buit, el
_ fixat per alinear el buit (utilitzant l'estratègia A)** Sol·licitud:**
Què passa al servidor:
- Express analitza el cos JSON.
lodashagafa les claus.new Functioncrea:- La funció s'anomena amb
("pinned", "val"). _="pinned".unused="val".x=undefined.- Bingo!! El paràmetre per defecte s'avalua. S'executa l'ordre del shell.
Això va ser! Aquests detalls tècnics van ser molt divertits d'entendre. Malauradament, molts jugadors van resoldre la IA, però almenys ara sé com fer nous reptes anti-IA 😈😈. Estigueu atents per a més 💖

