CTF/웹해킹

[HSCTF9] squeal - 웹해킹 / SQL Injection

SecurityMan 2022. 7. 11. 11:00

 

정말 간단한 SQL Injection 문제

 

문제 제목부터 SQueaL 이라고 힌트를 주고 있어서

 

어떤 공격 기법으로 접근해야 하는지 쉽게 알 수 있다.

 

반응형

 

문제 설명을 읽어보면

 

super secret 사이트에 admin 으로 접속할 수 있겠냐고 물어본다.

 

해킹 대회에서 super secret 이라는 수식어가 붙으면

 

무조건 아주 취약하다는 의미이다.

 

이번 문제는 문제페이지 주소와 함께 소스코드도 같이 주어진다.

 

 

문제페이지에 접속했을때의 화면이다.

 

간단한 로그인 페이지가 보인다.

 

 

시험삼아 ID, 비밀번호에 123 / 123 이라고 입력해봤는데

 

위에 Incorrect username or password 라는 알림창이 뜬다.

 

사실 여기서 바로 문제를 풀 수 있지만

 

소스코드가 제공되었으니 예의상 한번 봐준다.

 

const express = require("express");
const db = require("better-sqlite3")("db.sqlite3");
const app = express();

app.use(express.json());

app.post("/api/flag", (req, res) => {
	const username = req.body.username;
	const password = req.body.password;
	if (typeof username !== "string") {
		res.status(400);
		res.end();
		return;
	}
	if (typeof password !== "string") {
		res.status(400);
		res.end();
		return;
	}

	let result;
	try {
		result = db
			.prepare(
				`SELECT * FROM users
            WHERE username = '${username}'
            AND password = '${password}';`
			)
			.get();
	} catch (error) {
		res.json({ success: false, error: "There was a problem." });
		res.end();
		return;
	}

	if (result) {
		res.json({ success: true, flag: process.env.FLAG });
		res.end();
		return;
	}

	res.json({ success: false, error: "Incorrect username or password." });
});

app.use(express.static("/app/public"));
app.listen(process.env.PORT || 3000);

db.prepare(
	`CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT,
    password TEXT);`
).run();
db.prepare(
	`INSERT INTO
    users (username, password)
    VALUES ('${process.env.USERNAME}', '${process.env.PASSWORD}');`
).run();

 

주어진 index.js 파일의 내용이다.

 

 

이 부분을 보면 된다.

 

사용자가 입력한 아이디와 비밀번호를

 

${username}, ${password} 변수로 받아서 SQL 쿼리에 집어넣고,

 

SQL 쿼리의 결과에 따라

 

성공하면 플래그를, 실패하면 Incorrcet username or password 메세지를 출력한다.

 

문제는 SQL 구문에서 사용자의 입력값에 대해서 필터링을 전혀 하고 있지 않다는 것이다.

 

만약 사용자가 username에 작은따옴표(')를 입력한다면

 

SELECT * FROM users WHERE username = ' ' '  AND password = '${password}';

 

이렇게 쿼리 사이에 작은따옴표가 들어가서 뒤쪽의 SQL 구문을 변경시킬 수 있게 된다.

 

' or 1=1-- - 이라고 입력을 한다면,

 

SELECT * FROM users WHERE username = ' ' or 1=1-- - '  AND password = '${password}';

 

이렇게 입력값이 들어가서 

 

WHERE 절이 항상 참이되고, 

 

-- - 뒤에는 모두 주석처리 되어 없어지게 된다.

 

따라서 SELECT * FROM users; 와 동일한 결과가 출력되게 되고,

 

만약 users 테이블의 맨 위에 admin 이 있다면, 플래그가 출력될 것이다.

 

 

실제로 username에 admin' or 1=1-- - ,

 

password에 아무거나 입력하고 로그인을 시도하면

 

로그인이 성공하여 플래그가 출력되는것을 볼 수 있다.

반응형