본문 바로가기
정보보안/Web Hacking

드림핵 문제풀이 - Simple_sqli // SQL Injection, query, 로그인우회, SQL

by 우동이 2022. 5. 9.
300x250

문제 분류


난이도 : 하하

 

dreamhack - simple_sqli


1. 사전 탐색&정찰 (reconnaissance)

/index

사이트에 접속해보면 Login이 보입니다.

 

그리고 코드를 함께 살펴봅시다.

 

#!/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)

/(index) /login 두 탭이 존재하는 걸 알 수 있고

 

guest계정과 admin 계정 두가지가 생성되어 있음을 알 수 있습니다.


2. 스캐닝 및 취약점 분석(Scanning and Enumeration)

위에 공개되어 있는 코드 중 우리가 주목해야 할 코드만 간추려서 살펴봅시다.

#query 문을 통해 계정 두개가 생성되어있음
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()

해당 코드를 통해 db에 query문이 삽입되어 계정이 생성되었음을 알 수 있고

 

admin계정의 암호는 dict 형태로 16진수 난수 형태로 생성됨을 알 수 있습니다.(binascii.hexlify : binary 데이터 16진수 표현법)

 

@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>'

또한 login 탭의 코드를 살펴보면 

 

res라는 값이 userid와 userpassword값이 담겨 반환되는 걸 알 수 있습니다.

 

즉 admin 계정으로 로그인해야 하므로 이는 기본적인 Injection을 통해 관리자(admin) 계정을 탈취하거나

 

조회하는 방식이 아닌 단순히 로그인만 하면 되는 문제입니다.

 

거기에 따로 인증 우회를 해야하도록 injection 방지 코드sql 구문 필터링이 없기 때문에

 

아주 간단한 방식의 sql injection을 통해 로그인 우회를 할 수 있습니다.


3. 침투 (Gaining Access)

/login

userid와 password를 입력해야 합니다.

 

먼저 guest계정으로 로그인 해봅시다.

guest 로그인
guest login

guest로의 로그인은 잘 됩니다.

 

다음은 관리자인 admin계정에 로그인해봅시다.

admin - login - failure

일반적으로 로그인을 시도하면 로그인이 되질 않습니다.

 

admin계정의 암호는 난수 값(random)이므로 서비스 이용자인 우리는 알 수 없습니다.

login fail

당연하게도 틀린 값이라고 나옵니다.

 

자 그러면 이제 admin계정으로 로그인하는 코드를 짜 봅시다.

 

제 다른 글들에도 나오듯 SQL Injection의 기본 원리는 코드를 참값으로 만드는 데 있습니다.

 

//SQL의 원리
‘1 'or' 1 '=' 1
1 ‘or’ 1 ‘like’ 1

//양쪽이 참값이 되는 코드를 query문에 붙인다.

SELECT * FROM users WHERE userid="admin"-- " AND userpassword="---"

//userid 가 admin인 계정을 우리는 알고있다.
//--(주석) 을 통해 뒤에 userpassword 조회 쿼리는 주석처리 한다.
//userid 조회 값은 뒤의 AND 구문이 사라지므로 (1) 참값이 된다.

두 번째 과정인 취약점 분석 항목에서 res에 담기는 쿼리문을 살펴보았을 때

 

  • 'select * from users where userid="{userid}" and userpassword="{userpassword}"'

위와 같은 쿼리문이 결과로 반환되는 걸 알 수 있는데

 

우리는 이미 admin계정의 userid 값이 admin인걸 알고 있습니다.

 

이 또한 취약점 분석 탭에서 admin계정이 생성되어 있는 걸 확인했습니다.

 

그러므로 SQL 문의 주석 처리 문법인 -- 을 통해 ID 검색 조건만을 처리하도록 두고

 

뒤의 userpassword 조회 부분은 주석처리해버리면 참값이 됩니다.

 


4. 권한상승 및 탈취 (Privilege Escalation)

userid에 admin계정 그리고  "-- 주석처리 문을 넣어줍니다.

 

이렇게 되면 res에 담기는 쿼리문은 아래와 같습니다.

SELECT * FROM users WHERE userid="admin"-- " AND userpassword="??"

이러면 query문은 참값으로 판정됩니다.

flag

admin계정으로 로그인되어 flag가 출력됩니다.


 

 

기본 숙지 개념 : flask, SQL Injection, SQL 구문(주석, 조회문), python3

작업환경 :  VIsual Studio Code, Web

버전 : 3.10.0

사용언어 : Python_flask, Python, SQL

작업도구 : -

추천 자료 : 

 

 

모의해킹 문제풀이 - 6번(답 포함) - 써니나타스(SuNiNaTaS) // Sql injection, query

문제 분류 난이도 : 하 문제 사이트에 접속하면 5개의 게시글이 보인다. 이 중 waiting, 열공열공 reference! 등 세 개의 게시글은 그냥 있는듯하고 readme랑 hint 게시글을 확인해보자 hint게시글에서는 su

hobbylists.tistory.com

 

 

[웹 해킹] SQL Injection - <injection>용 SQL구문 모음 (1.1v)

▶SQL Injection Injection ▶ 주입, 삽입하다 SQL ▶ 데이터베이스 관리용 언어 SQL Injection ▶ OWASP 10대 웹 취약점 2020년 기준으로 1순위(Injection)에 기재될정도로 단순하고 강력한 공격법 SQL의 단위 :..

hobbylists.tistory.com

 

 

[DB별 SQL 쿼리문]-(웹해킹용 , SQL Injection, Oracle, MySql, Ms-Sql) (1.11v)

My-SQL version My-Sql의 모든 DB정보 저장소 INFORMATION_SCHEMA: INFORMATION_SCHEMA는 My-SQL서버가 운영하는 모든 데이터베이스의 정보를 저장하는 장소이며 DB명, Table명, Column의 자료형과 접근 권한 등..

hobbylists.tistory.com

 

 

 

300x250

댓글