aszx87410 / ctf-writeups

ctf writeups
62 stars 9 forks source link

DiceCTF 2021 - Missing Flavortext #15

Open aszx87410 opened 3 years ago

aszx87410 commented 3 years ago

It'a simple login page:

source code:

const crypto = require('crypto');
const db = require('better-sqlite3')('db.sqlite3')

// remake the `users` table
db.exec(`DROP TABLE IF EXISTS users;`);
db.exec(`CREATE TABLE users(
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  username TEXT,
  password TEXT
);`);

// add an admin user with a random password
db.exec(`INSERT INTO users (username, password) VALUES (
  'admin',
  '${crypto.randomBytes(16).toString('hex')}'
)`);

const express = require('express');
const bodyParser = require('body-parser');

const app = express();

// parse json and serve static files
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('static'));

// login route
app.post('/login', (req, res) => {
  if (!req.body.username || !req.body.password) {
    return res.redirect('/');
  }

  if ([req.body.username, req.body.password].some(v => v.includes('\''))) {
    return res.redirect('/');
  }

  // see if user is in database
  const query = `SELECT id FROM users WHERE
    username = '${req.body.username}' AND
    password = '${req.body.password}'
  `;

  let id;
  try { id = db.prepare(query).get()?.id } catch {
    return res.redirect('/');
  }

  // correct login
  if (id) return res.sendFile('flag.html', { root: __dirname });

  // incorrect login
  return res.redirect('/');
});

app.listen(3000);

We need to bypass the authentication by sql injection. But it filters single quote, how to bypass this?

Actually they already gave us a hint:

// parse json and serve static files
app.use(bodyParser.urlencoded({ extended: true }));

But the comment seems wrong, it's not parse json(it should be bodyParser.json), it's to let urlencoded can be parse by qs library which support passing array or even object.

Like this:

username[] = ' or '1' = '1
password[] = ' or '1' = '1

So both username and password is an array: ["' or '1' = '1'"]. And it will be string ' or 1' = '1' when concat with other string.

aszx87410 commented 3 years ago

@kingrootdm Nope, if we use bodyParser.json, we can pass json data like:

{
  "username": ["' or '1' = '1"]
}