- cookie[web]2024년 12월 28일 04시 24분 40초에 업로드 된 글입니다.작성자: sonotree
문제 설명
쿠키로 인증 상태를 관리하는 간단한 로그인 서비스입니다.
admin 계정으로 로그인에 성공하면 플래그를 획득할 수 있습니다.
플래그 형식은 DH{...} 입니다.
Approach: Code
<login 엔드포인트>
users = { 'guest': 'guest', 'admin': FLAG } @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')) ) resp.set_cookie('username', username) return resp return '<script>alert("wrong password");history.go(-1);</script>' app.run(host='0.0.0.0', port=8000)
request.from
클라이언트가 POST 요청을 보낸 데이터를 포함하는 딕셔너리 형식의 객체이다.
.get('[key]')
request.form은 딕셔너리처럼 동작하므로, .get() 메서드를 사용해 특정 키 값을 가져올 수 있다.username = request.form.get('username') 부분을 통해 POST 요청의 폼 데이터에서 name='username' 필드 값을 가져온다. password도 마찬가지이다.
그리고 try: pw = users[username]를 살펴보자. users는 위에서 딕셔너리 형태로 정의되어있다. request.form.get('username')에서 받아온 username 변수 값이 딕셔너리의 key 값으로 존재하는지 확인하며, 해당 값을 pw 변수에 저장한다. 만약 username이 users 딕셔너리의 키 값으로 존재하지 않으면 except 부분이 실행된다.
make_responese:
이 함수는 HTTP 응답 객체를 생성한다. 여기서는 redirect(url_for('index'))를 사용하여 사용자를 / 페이지(index)로 리디렉션 한다.
redirect
클라이언트를 지정된 URL로 이동시키는 HTTP 응답
set_cookie
응답 객체에 쿠키를 추가한다. resp.set_cookie('username', username) 여기서는 username 쿠키를 생성하고, 그 값으로 사용자가 입력한 username을 설정한다. 이후 클라이언트는 쿠키에 username 값을 저장하게 된다.
return resp
설정된 응답 객체 resp를 클라이언트로 보낸다.
-> 클라이언트는 /로 리디렉션 되고, 쿠키에 username이 설정된다.</ 엔트포인트>
@app.route('/') def index(): username = request.cookies.get('username', None) if username: return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}') return render_template('index.html')
request.cookies.get('username', None)을 통해 클라이언트가 보낸 쿠키중 username 값을 가져온다.
Approach
login 페이지에서 guest-guest 값을 입력하고 버프 스윕트로 인터셉트한 값은 아래와 같다. username과 password에 내가 입력한 guest-guest 값이 매핑된다.
POST /login HTTP/1.1 Host: host1.dreamhack.games:10573 Content-Length: 29 Cache-Control: max-age=0 Origin: http://host1.dreamhack.games:10573 Content-Type: application/x-www-form-urlencoded Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://host1.dreamhack.games:10573/login Accept-Encoding: gzip, deflate, br Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7 Cookie: username=guest Connection: keep-alive username=guest&password=guest
내가 guest-guest로 로그인하면 cookie에는 아래와 같이 guest라고 뜰 것이다. 로그인 한 상태에서 username을 admin으로 바꾸면? 아래 코드를 살펴보면 username 즉 value 값만 검사하기 때문에 flag가 출력될 것이다.
@app.route('/') def index(): username = request.cookies.get('username', None) if username: return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}') return render_template('index.html')
Solve
guest-guest로 로그인한 뒤, 개발자 도구로 value를 admin으로 바꿨더니 flag가 출력되었다.
Hello admin, flag is DH{7952074b69ee388ab45432737f9b0c56}
Dreamhack: 취약점 분석
username 변수가, 요청에 포함된 쿠키에 의해 결정되어 문제가 발생한다. 쿠키는 클라이언트의 요청에 포함되는 정보로, 이용자가 임의로 조작할 수 있다.
@app.route('/') # / 페이지 라우팅 def index(): username = request.cookies.get('username', None) # 이용자가 전송한 쿠키의 username 입력값을 가져옴 if username: # username 입력값이 존재하는 경우 return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}') # "admin"인 경우 FLAG 출력, 아닌 경우 "you are not admin" 출력 return render_template('index.html')
'Dreamhack > Web Hacking' 카테고리의 다른 글
session-basic[web] (0) 2024.12.28 chocoshop [Web] (0) 2024.11.28 Tomcat Manager [web] (1) 2024.11.28 다음글이 없습니다.이전글이 없습니다.댓글