https://dreamhack.io/wargame/challenges/26
웹 서비스는 쿠키 또는 세션을 사용해 이용자를 식별한다. 임의 이용자의 쿠키를 사용할 수 있다면, 이는 곧 임의 이용자의 권한으로 웹 서비스의 기능을 사용할 수 있다. CSRF(Cross Site Request Forgery) 는 임의 이용자의 권한으로 임의 주소에 HTTP 요청을 보낼 수 있는 취약점이다. 공격자는 임의 이용자의 권한으로 서비스 기능을 사용해 이득을 취할 수 있다.
CSRF 공격에 성공하기 위해서는 공격자가 작성한 악성 스크립트를 이용자가 실행해야 한다. 이는 공격자가 이용자에게 메일을 보내거나 게시판에 글을 작성해 이용자가 이를 조회하도록 유도하는 방법이 있다. 여기서 말하는 악성 스크립트는 HTTP 요청을 보내는 코드이다.
CSRF 공격 스크립트는 HTML 또는 Javascript를 통해 작성할 수 있다. 이미지를 불러오는 img
태그를 사용하거나 웹 페이지에 입력된 양식을 전송하는 form
태그를 사용하는 방법이 있다. 이 두 개의 태그를 사용해 HTTP 요청을 보내면 HTTP 헤더인 Cookie에 이용자의 인증 정보가 포함된다.
XSS와 CSRF는 모두 클라이언트를 대상으로 하는 공격이며, 이용자가 악성 스크립트가 포함된 페이지에 접속하도록 유도해야 한다.
반면 차이점으로 XSS는 인증 정보인 세션 및 쿠키 탈취를 목적으로 하는 공격이며, 공격할 사이트의 오리진에서 스크립트를 실행시킨다.
CSRF는 이용자가 임의 페이지에 HTTP 요청을 보내는 것을 목적으로 하는 공격이다. 또한, 공격자는 악성 스크립트가 포함된 페이지에 접근한 이용자의 권한으로 웹 서비스의 임의 기능을 실행할 수 있다.
먼저 csrf를 유도하기 위해 vuln(csrf) page에 접속해보자
스크립트를 제공했으나, script라는 단어가 * 처리 되었다
이게 어떻게 된건지 확인하기위해 python코드를 살펴보자
param= 뒤의 값을 param 변수에 저장하고, 반복문을 통해 "frame", "script", "on" 이라는 단어가 들어간 부분을 모두 *로 처리해주고있다.
이런 이유로 script라는 단어가 *로 나오게 된 것이다.
이제 csrf처럼 html태그 안에서 스크립트가 실행되도록 하면 되는 것을 알았다!
전에 먼저 notice flag라는 곳을 살펴보자.
notice flag의 경로는 /admin/notice_flag
이다.
이곳의 코드를 보면 도메인이 127.0.0.1이 아니면 거절되고, userid의 파라미터로 admin이 주어지지 않으면 거절된다.
우리의 현재 도메인은 host3.dreamhack.games 이므로 당연히 접근이 거절된다.
이전에 xss-1에서 로컬 호스트 도메인으로 접근이 가능해지는 방법을 설명했다.
그때와 같이 selenium을 통해 생성된 웹 드라이버는 127.0.0.1을 도메인으로 하여 /admin/notice_flag에 접근이 가능해진다.
1번째 조건문에 대한 문제는 해결했다. 그 다음 2번째 조건문에서 userid에 대한 파라미터를 받는데,
vuln(csrf) page에서 실행하는 코드에서 param을 받는 코드를 보면 같은 메소드를 사용하는 것을 알 수 있으며, value = request.args.get("key", "")
형태로 사용하는데,
첫 번째 인자로 key를 넘겨주면 딕셔너리에 있는 첫 번째 value을 얻고, 만약 key에 해당하는 value가 딕셔너리에 없다면 두 번째 인자를 default value로써 반환한다. 두 번째 인자의 기본 값은 None이므로 "" 처리한다.
URL의 ?key=value
와 같이 ? 뒤는 쿼리 문자열을 받는 부분이며, key에 대응하는 value값을 reqeust.args.get()을 통해 얻을 수 있는 것이다.
따라서 2번째 조건문을 벗어나기 위해서 쿼리로 ?userid=admin
을 추가하여 스크립트가 해당 사이트를 방문하도록 유도하면 될 것이다!
그리고 memo_text에 전역 변수로 접근됨으로써 플래그 값을 memo_text에 저장할 수 있고,
저장된 memo_text는 memo 카테고리를 들어가면 memo_text의 내용이 웹 렌더링 되면서 플래그가 출력될 수 있게된다.
이미 /admin/notice_flag에서 memo_text에 플래그를 저장해주므로, location.href 등을 통해 /memo?memo=
로 이동하는 과정은 필요하지 않다!
지금까지의 정보를 조합해 다음 값을 /flag에서 param에 전달해 줄 수 있다.
<img src=/admin/notice_flag?userid=admin>
alert창으로 good이 표시된 후, /memo에 들어가면, 플래그가 저장되었던 memo_text가 웹 렌더링 되면서 확인할 수 있게된다!