CSRF Advanced


소스코드 분석

def flag()

  • /flag 경로로 POST 요청이 들어오면, 조건문 안의 check_csrf 함수가 호출된다.

def check_csrf()

  • 전달받은 인자(param) 값을 url 변수에 저장하고 read_url 함수를 호출한다.

def read_url()

  • 42-27 라인이 이 함수의 핵심 코드이다.
  • /login 경로로 이동하여 admin 계정으로 로그인을 시도한 후에 /vuln?param={사용자 입력 값} 으로 요청을 보낸다.

def login()

  • read_url 함수의 46라인에 의해 /login 경로로 관리자 계정 접속이 시도된다.
  • 해당 요청은 유효한 아이디/패스워드가 전달되었으므로 정상적으로 세션과 CSRF 토큰이 저장된다.
    • sessiond_id = os.urandom(8).hex()
    • csrftoken = md((username + request.remote_addr).encode()).hexdigest()

def vuln()

  • vuln 함수에서는 /vuln?param={사용자 입력 값} 에 대한 문자열 필터링 로직이 존재한다.
  • 이미지(img) 태그 등을 사용하면 우회가 가능해 보인다.

def change_password()

  • /change_password 경로로 요청이 보내지면 요청 헤더로부터 sessionid 값을 가져와 저장한다.
  • 이후 서버에 저장된 세션 및 CSRF 토큰 값이 존재하면 아래 조건문(128 라인)으로 넘어간다.
    • (1) pw는 새로 설정할 패스워드 값이다. (/change_password 요청 시 인자로 함께 넘겨주어야 한다.)
    • (2) csrf_token은 로그인 시 생성된 CSRF 토큰 값이다. (관리자 계정의 CSRF 토큰 값을 함께 넘겨줘야 한다.)

  • 관리자 계정의 CSRF 토큰 값은 아래와 같이 취약하게 생성되고 있어 값 탈취가 가능했다.
    • (username + request.remote_addr) 값이 MD5 단방향 해시화 된 후 헥스 값으로 표현된 형태다.

  • 유저명(username)은 “admin” 이며, 요청을 보낸 원격지 주소(remote_addr)은 로컬 호스트이다.
  • 이를 통해 관리자 계정의 CSRF 토큰 값을 생성했다.

  • /flag 경로에서 관리자 계정의 패스워드를 변경을 시도했다.
    • <img/src='http://127.0.0.1:8000/change_password?pw=admin&csrftoken=7505b9c72ab4aa94b1a4ed7b207b67fb'>

  • 변경된 패스워드로 관리자 계정 접속에 성공했다.

🐛.. 🐛.. 🐛..