[Dreamhack] simple_sqli_chatgpt WriteUp
문제 파악

주어진 문제의 홈페이지를 들어가보니 userlevel을 입력 받을 수 있는 홈페이지가 있다.
문제에서 챗지피티와 함께 풀어보라고 힌트(?)가 주어진다.
파일에서 로그인 입력을 받는 라우팅 부분은 다음과 같다.
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
userlevel = request.form.get('userlevel')
res = query_db(f"select * from users where userlevel='{userlevel}'")
if res:
userid = res[0]
userlevel = res[2]
print(userid, userlevel)
if userid == 'admin' and userlevel == 0:
return f'hello {userid} flag is {FLAG}'
return f'<script>alert("hello {userid}");history.go(-1);</script>'
return '<script>alert("wrong");history.go(-1);</script>'
챗지피티에게 그대로 물어본다.

접근 방법 with GPT(?)
GPT는 정확하게 뭘 넣어야 하는지 정확히는 답변이 안나오지만, admin이나 '1'='1'과 같은 문장을 사용하여
접근할 수 있다는 사실을 알 수 있다.
풀이
SQL를 공부하기 위해 하나하나 해석해가며 정석으로 풀어보겠다.
res = query.db(select * from users where userlevel='0' and userid='admin')라고 할 때 해석해보면
users 테이블에 칼럼이 userlevel='0'이고 칼럼이 userid='admin'인 것을 찾아서 res변수에 넣으라는 뜻이다.
표로 나타내면 다음과 같다.
users 테이블
| userlevel | userid |
| 0 | admin |
| 1 | guest1 |
| 2 | guest2 |
| ... | ... |
따라서 res변수에 데이터베이스형태로 userlevel='0'과 userid='admin'이 저장될 것이고,
if res:
userid = res[0]
userlevel = res[2]
print(userid, userlevel)
if userid == 'admin' and userlevel == 0:
res에 값이 존재할때:
userid = res[0] # '0'이 들어가게 될것이고
userlevel = res[2] # 'admin'이 들어가게 될 것이다. 숫자는 몇 번째 칼럼인지 나타내는 거 같다. (신경안써도됨.)
따라서 해당 로직을 통해 admin의 값을 알아내고자 한다면,
변수가 userlevel인 곳에 입력값 그대로를
res = query_db(f"select * from users where userlevel='{userlevel}'") 를 통해서
res 변수에 넣기 때문에,
select * from users where userlevel='0' and userid='admin' 과 같은 쿼리가 입력된다면 아래에 있는
if userid == 'admin' and userlevel == 0:
에 의해 플래그가 출력될 것이다.
따옴표 기호를 생각하여 입력값은 다음과 같다.
0' and userid='admin
너무나도 당연하지만, userlevel의 변수를 입력 받을 수 있는 곳은 로그인 창인데, 이것은 개발자 도구를 활용하여 확인할 수 있다.


name이 userlevel인 것을 get메서드로 통신한다는 것은 코드를 통해서 알 수 있다.