오늘은 CSRF 공격 문제를 풀어보았습니다.
먼저 vuln page를 누르고 들어가니 param에 넘긴 <script>alert(1)</script>
가 필터링 된 모습이다.
소스코드를 확인하니 frame
, script
, on
을 필터링하는 코드가 있었다.
@app.route('/vuln')
def vuln():
param = request.args.get('param', '').lower()
xss_filter = ['frame', 'script', 'on']
for _ in xss_filter:
param = param.replace(_, '*')
return param
그리고 /admin/notice_flag
에 userid
라는 쿼리 파라미터로 admin을 주면 플래그를 얻을 수 있다는 것을 발견했다.
@app.route("/admin/notice_flag")
def admin_notice_flag():
global memo_text
if request.remote_addr != "127.0.0.1":
return "Access Denied"
if request.args.get("userid", "") != "admin":
return "Access Denied 2"
memo_text += f"[Notice] flag is {FLAG}\n"
return "Ok
필터링을 피하면서 해당 경로로 접근하기 위해 img
태그의 src
속성을 이용했다.
실행하니 메모페이지에 플래그가 나온 모습이다. 굿
이번엔 memo 페이지가 사라지고 로그인이 생겼다.
소스코드를 확인하니 vuln 페이지는 이전 문제와 동일한 모습이었다.
flag 페이지는 다음과 같았다.
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param", "")
session_id = os.urandom(16).hex()
session_storage[session_id] = 'admin'
if not check_csrf(param, {"name":"sessionid", "value": session_id}):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
어드민으로 로그인 해야 플래그를 얻을 수 있다는걸 알 수 있었다.
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
elif request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
try:
pw = users[username]
except:
return '<script>alert("not found user");history.go(-1);</script>'
if pw == password:
resp = make_response(redirect(url_for('index')) )
session_id = os.urandom(8).hex()
session_storage[session_id] = username
resp.set_cookie('sessionid', session_id)
return resp
return '<script>alert("wrong password");history.go(-1);</script>'
추가로 현재 게스트 계정과 어드민 계정이 있는데, 게스트 계정은 username, password가 guest이고 어드민은 username이 admin, password는 플래그이다.
users = {
'guest': 'guest',
'admin': FLAG
}
또한, /change_password
에서 pw라는 쿼리 파라미터로 비밀번호를 바꿀 수 있다.
@app.route("/change_password")
def change_password():
pw = request.args.get("pw", "")
session_id = request.cookies.get('sessionid', None)
try:
username = session_storage[session_id]
except KeyError:
return render_template('index.html', text='please login')
users[username] = pw
return 'Done'
flag 페이지에서 post 요청을 보내면 session_id
를 admin으로 고치므로 이전 문제처럼 img
태그를 이용해 /change_password
로 요청을 보내면 될 것 같다.
바꾼 비밀번호로 어드민 계정에 로그인을 해보면?
로그인이 잘 된 모습이다. 굿