Ceci est une ancienne révision du document !
Enonce
We'll start you out with Level 0, the Secret Safe. The Secret Safe is designed as a secure place to store all of your secrets.
It turns out that the password to access Level 1 is stored within the Secret Safe. If only you knew how to crack safes…
You can access the Secret Safe at https://level00-1.stripe-ctf.com/user-kfsvkinufw.
The Safe's code is included below, and can also be obtained via git clone https://level00-1.stripe-ctf.com/user-kfsvkinufw/level00-code.
Code
Here's the code for level00.js, the main server file:
// Install dependencies with 'npm install' // Run as 'node level00.js' var express = require('express'), // Web framework mu = require('mu2'), // Mustache.js templating sqlite3 = require('sqlite3'); // SQLite (database) driver // Look for templates in the current directory mu.root = __dirname; // Set up the DB var db = new sqlite3.Database('level00.db'); db.run( 'CREATE TABLE IF NOT EXISTS secrets (' + 'key varchar(255),' + 'secret varchar(255)' + ')' ); // Create the server var app = express(); app.use(express.bodyParser()); function renderPage(res, variables) { var stream = mu.compileAndRender('level00.html', variables); res.header('Content-Type', 'text/html'); stream.pipe(res); } app.get('/*', function(req, res) { var namespace = req.param('namespace'); if (namespace) { var query = 'SELECT * FROM secrets WHERE key LIKE ? || ".%"'; db.all(query, namespace, function(err, secrets) { if (err) throw err; renderPage(res, {namespace: namespace, secrets: secrets}); }); } else { renderPage(res, {}); } }); app.post('/*', function(req, res) { var namespace = req.body['namespace']; var secret_name = req.body['secret_name']; var secret_value = req.body['secret_value']; var query = 'INSERT INTO secrets (key, secret) VALUES (? || "." || ?, ?)'; db.run(query, namespace, secret_name, secret_value, function(err) { if (err) throw err; res.header('Content-Type', 'text/html'); res.redirect(req.path + '?namespace=' + namespace); }); }); if (process.argv.length > 2) { var socket = process.argv[2]; console.log("Starting server on UNIX socket " + socket); app.listen(socket); } else { console.log("Starting server at http://localhost:3000/"); app.listen(3000); }
And here's the code for level00.html, its mustache.js template:
<html> <head> <title>Secret Safe</title> </head> <body> {{#namespace}} <div style="border-width: 2px; border-style: outset; padding: 5px"> Showing secrets for <strong>{{namespace}}</strong>: <table> <thead> <tr> <th>Key</th> <th>Value</th> </tr> </thead> <tbody> {{#secrets}} <tr> <td>{{ key }}</td> <td>{{ secret }}</td> </tr> {{/secrets}} {{^secrets}} <tr> <td span="2"> You have no secrets stored with us. Try using the form below. </td> </tr> {{/secrets}} </tbody> </table> <hr /> </div> {{/namespace}} <form action="" method="POST"> <p> <label for="namespace">Namespace:</label> <input type="text" name="namespace" id="namespace" value="{{ namespace }}" /> </p> <p> <label for="secret_name">Name of your secret:</label> <input type="text" name="secret_name" id="secret_name"> </p> <p> <label for="secret_value">Your secret:</label> <input type="password" name="secret_value" id="secret_value"> </p> <p> <input type="submit" value="Store my secret!" /> </p> </form> <form action="" method="GET"> <label for="change_namespace"> Want to retrieve your secrets? View secrets for: </label> <input name="namespace" id="change_namespace" /> <input type="submit" value="View" /> </form> </body> </html>
Solution
Pour ajouter un secret, il faut definir le namespace, une cle et une valeur, secret qui sera stocké sous la forme key = namespace.cle
et secret = valeur
app.post('/*', function(req, res) { var namespace = req.body['namespace']; var secret_name = req.body['secret_name']; var secret_value = req.body['secret_value']; var query = 'INSERT INTO secrets (key, secret) VALUES (? || "." || ?, ?)'; db.run(query, namespace, secret_name, secret_value, function(err) {
La requete GET pour afficher les secrets requiert un parametre, le namespace et est construite avec
app.get('/*', function(req, res) { var namespace = req.param('namespace'); if (namespace) { var query = 'SELECT * FROM secrets WHERE key LIKE ? || ".%"'; db.all(query, namespace, function(err, secrets) {
Cette requete affiche donc tous les secrets du namespace passé en argument. Il suffit d'utiliser % comme parametre pour afficher tous les secrets de tous les namespaces et donc le mot de passe.