DOMDOM
0posts
today
total
personal posts · since 2021

Fragments
of a day.

A small notebook for slow moments slipping by.

2023 IT Creator
2024 Food Creator
2025 News Creator
2026 News Creator

Latest Posts최근

tistory view

Back to Home

[Hackthebox] - sanitize Writeup(문제풀이)

728x90
반응형

문제 설명

Can you escape the query context and log in as admin at my super secure login page?

 

문제 설명을 보면 로그인 페이지로부터 admin 계정으로 접속하라는 것 같네요.

아래는 제공 받은 URL로 접속하면 나오는 첫 페이지입니다.

 

 

소스코드 보기를 하면 /debug 라는 경로가 있다는 것을 주석문에서 확인할 수 있는데요.

접속해보면 아래 Python Flask 의 서버 코드를 확인할 수 있습니다.

 

from flask import Flask, request, render_template, Response, url_for, g
from sqlite3 import dbapi2 as sqlite3
from functools import wraps

app = Flask(__name__)

def get_db():
	db = getattr(g, '_database', None)
	if db is None:
		db = g._database = sqlite3.connect(':memory:', isolation_level=None)
		db.row_factory = sqlite3.Row
		with app.app_context():
			db.cursor().execute('CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT);')
			with app.open_resource('schema.sql', mode='r') as f:
				db.cursor().executescript(f.read())
	return db

@app.teardown_appcontext
def close_connection(exception):
	db = getattr(g, '_database', None)
	if db is not None: db.close()

def query_db(query, args=(), one=False):
	try:
		with app.app_context():
			cur = get_db().execute(query, args)
			rv = [dict((cur.description[idx][0], value) for idx, value in enumerate(row)) for row in cur.fetchall()]
			return (rv[0] if rv else None) if one else rv
	except Exception as e:
		return e

	return None

@app.route('/', methods=['GET', 'POST'])
def login():
	if request.method == 'POST':
		q = "select * from users where username = '%s' AND password = '%s';" % (request.form.get('username', ''), request.form.get('password', ''))

		login = query_db(q, one=True)

		if isinstance(login, Exception):
			error = '%s : %s' % (login.__class__, login)
			return render_template('index.html', query=q, error=error, image=url_for('static', filename='images/dog.png'))

		if login is None:
			return render_template('index.html', query=q, image=url_for('static', filename='images/dog.png'))

		if login.get('username', '') == 'admin':
			return render_template('index.html', query=open('flag').read())

	return render_template('index.html')

@app.route('/debug')
def debug():
	return Response(open(__file__).read(), mimetype='text/plain')

if __name__ == '__main__':
	app.run('0.0.0.0', port=1337)

 

중요한 부분은 login 함수입니다. POST 요청으로 들어왔을 때 form 의 파라미터로 username과 password를 받습니다.

하지만 이 때 python 의 문자열 포맷팅 방식으로 sql query 문을 만들게 되는데요.

 

이렇게 되면 SQL Injection 에 취약한 코드가 만들어집니다.

그리고 SQL 구문의 결과로써 username 이 admin 인 경우에는 flag 라는 파일의 내용을 화면에 출력해준다고 하네요.

 

여기서 또 문제는 admin 의 password 마저 확인하지 않고 단순히 username 이 admin 이기만 한다면

통과되는 방식도 문제라고 할 수 있겠습니다.

물론 근본적인 원인은 파라미터를 문자열 포맷팅한 것이지만 말이죠.

 

select * from users where username = '아이디' AND password = '비밀번호';

 

SQL 구문은 위와 같습니다.

어떤한 특수문자 필터링도 존재하지 않기 때문에 아래와 같이 구문이 만들어질 수 있겠죠.

 

select * from users where username = 'admin'-- -' AND password = '비밀번호';

 

위 구문처럼 실행될 수 있도록 username 에 admin'-- - 라고 입력하고 로그인 버튼을 눌러보겠습니다.

비밀번호는 그냥 123 이라고 입력했습니다.

 

 

그랬더니 위와 같이 Flag 값이 출력된 것을 확인할 수 있었습니다.

 

- 끝 -

728x90
반응형

Comments

Thanks for staying up late.

keep wandering · keep listening