CSRF Advanced | Write-Up

0xqury·2025년 5월 15일

WebWriteups

목록 보기
6/8

1. 문제


2. 풀이

문제 코드는 Flask 기반이며, 핵심 흐름은 다음과 같다.

  1. /login 경로에서 admin 계정으로 로그인할 경우, 랜덤한 sessionid가 발급되고 해당 세션에 대해 md5(username + IP) 기반 CSRF 토큰이 저장된다.
  2. /change_password는 CSRF 토큰이 일치하고, 해당 세션이 로그인된 상태일 경우 비밀번호를 변경할 수 있는 GET 요청 기반 엔드포인트이다.
  3. /flag에 POST 요청을 보내면, 내부적으로 read_url()을 통해 admin으로 로그인한 후 우리가 제공한 URL(param)을 실제 브라우저로 렌더링한다.
  4. /vuln?param=...을 통해 우리가 조작한 HTML을 admin 세션에서 렌더링할 수 있으며, 여기에 <img src=...>를 넣으면 자동으로 해당 경로로 GET 요청을 유도할 수 있다.
  5. <img> 태그를 통해 /change_password?pw=1234&csrftoken=... 요청을 admin 세션에서 발송하도록 유도하면, 비밀번호 변경이 가능하다.

이를 바탕으로 최종 페이로드는 다음과 같다.

<img src="/change_password?pw=1234&csrftoken=7505b9c72ab4aa94b1a4ed7b207b67fb">

여기서 csrf_token은 파이썬 코드를 통해 계산되었다.

import hashlib
hashlib.md5(b"admin127.0.0.1").hexdigest()
# → '7505b9c72ab4aa94b1a4ed7b207b67fb'

이 HTML을 param에 넣어 /flag로 POST 요청을 보내면, 내부 브라우저가 이 URL을 방문하면서 admin 세션으로 비밀번호가 변경된다. 이후 admin:1234로 로그인하면 / 페이지에서 플래그를 확인할 수 있다.


3. 정리 및 느낀점

처음엔 XSS로 세션을 탈취해야 한다고 생각했지만, 필터링이 강력하게 적용되어 <script>, onload, onerror, <iframe> 등 주요 벡터들이 모두 차단되었다. 이 과정에서 남은 유일한 자동 요청 벡터였던 <img> 태그를 통해 GET 요청을 유도하고, 그걸로 비밀번호를 바꾸는 구조를 떠올린 것이 핵심이었다.

특히 CSRF 토큰이 단순히 md5(username + IP)로 생성된다는 점을 역으로 이용해 계산한 뒤, admin 세션을 우리가 조종할 수 있게 만든 과정이 인상 깊었다. 한 줄 HTML로 admin 계정의 비밀번호를 바꾸고, 그걸로 로그인해서 플래그를 보는 이 깔끔한 흐름이 상당히 흥미로운 문제였다.


profile
지망생

0개의 댓글