2021/01/06 - [프로젝트/DVWA 실습] - DVWA 실습 #4 - CSRF
문제 해결 방법
Medium 단계에서는 레퍼러 헤더를 검사하는 로직이 추가되었다. 그러나 eregi() 함수를 이용한 단순한 문자열 비교기 때문에 레퍼러 헤더에 서버 이름 문자열이 포함되기만 해도 통과할 수 있다. 레퍼러는 해당 사이트에 접속하기전 방문했던 사이트로 예를 들어 DVWA의 CSRF 실습 메뉴에 접근하면 요청 헤더에는 다음과 같은 레퍼러 헤더가 존재한다(직접 URL로 접근한 게 아닌 경우).
Medium 단계 실습에서 eregi() 함수로 검사하고 있는 문자열은 $_SERVER['SERVER_NAME'] 변수로 이는 서버가 동작하고 있는 호스트인 "192.168.56.103"을 의미한다. 지금은 DVWA가 가상 머신에 설치되었기 때문에 사설 IP 주소를 갖고 있는데 만약 DVWA가 설치된 환경과 실습 환경이 동일하다면 localhost로 출력될 것이다. 아무튼 이 서버 이름을 어떻게 레퍼러 헤더에 추가해줄 수 있을까? 일단 CSRF 공격은 사용자가 위조된 요청을 보내도 공격자가 이를 중간에서 가로채거나 결과를 받아볼 수 없기 때문에 직접 레퍼러 헤더를 위조하는 방법은 통하지 않는다. 여기서는 eregi() 함수의 취약한 문자열 비교를 사용할 수 있다.
현재 eregi() 함수의 필터링 정규식으로 전달된 문자열은 서버 이름 그 자체다. 그것 말고는 특별한 정규식 지정자가 없기 때문에 이 함수는 해당 문자열이 어느 곳에 위치하든 상관없이 존재하기만 하면 필터링에 일치한다고 판단한다. 그렇기 때문에 위처럼 서버 이름이 꼭 URL의 호스트 부분이 아니라 파라미터나 파일 이름에 포함되어 있어도 해당 로직을 통과할 수 있다. 그래서 아래와 같은 내용의 "csrf_192.168.56.103.html" 파일을 작성하였다. 이때 192.168.56.103에는 실습 환경에 맞는 DVWA 호스트 이름이 들어가야 한다.
<!DOCTYPE html>
<head></head>
<body>
<a href="http://192.168.56.103/dvwa/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#"
referrerpolicy="unsafe-url">
Click to get some points at DVWA!</a>
</body>
위처럼 작성된 악성 URL을 사용자가 클릭하니 CSRF 공격이 성공하여 비밀번호가 바뀌는 것을 볼 수 있었다.
만약 정 eregi() 함수를 이용해서 호스트 부분에만 서버 주소가 있을때만 일치시키고 싶다면 다음처럼 정규표현식을 수정할 수 있다.
http, https 프로토콜을 포함한 호스트 이름을 정규표현식으로 필터링하면 된다. 인코딩되기 때문에 그럴 일은 없겠지만 프로토콜 문자열이 레퍼러 헤더 문자열의 맨 앞에만 있도록 '^' 문자를 붙여줄 수도 있다.
레퍼러 정책 strict-origin-when-cross-origin
2021년 1월 기준으로 다른 사이트로 이동하면 레퍼러 정보가 잘리는 정책이 적용됐기 때문에 만약 referrerpolicy 속성이 적용되지 않은 악성 URL을 "http://localhost/attack/csrf_192.168.56.103.html" 파일에서 클릭했더라도 DVWA로 이동하면 요청 헤더의 레퍼러 정보에는 "http://localhost"만 남는다.
이는 레퍼러 헤더에 파라미터 노출로 인한 개인정보(검색 키워드 등)가 노출되는 것을 막기 위해 기본적으로 다른 사이트간에는 레퍼러 정보를 최소화하는 정책이다. 우리가 악성 URL을 클릭한 공격자 서버(또는 악성 URL을 받은 서버)와 DVWA 서버가 다르기 때문에 맨 앞의 호스트 이름만 남고 나머지 파일명이나 하위 디렉토리, 파라미터 등은 삭제되어 Referrer 헤더로 전달되는 것이다. 이는 클라이언트 측 편의를 봐주는 정책이기 때문에 HTML 태그로 설정을 해제할 수 있는데 위처럼 <a> 태그에 referrerpolicy 속성값을 unsafe-url로 설정해주면 레퍼러 정보가 필터링되지 않고 그대로 전달되는 것을 볼 수 있다.
이 DVWA가 만들어질 시점에는 이런 정책이 존재하지 않았기 때문에 발생하는 문제점이나 그만큼 CSRF 공격에 대한 대응 방안이 많이 적용되고 있다는 것일지도 모른다.
크롬의 레퍼러 정책때문에 실습이 진행되지 않아서 여기저기 찾아보고 다녔는데 재밌는 것은 이 실습은 CSRF 실습임에도 불구하고 단순히 로컬호스트로 서버를 띄워서 Burp Suite같은 프록시 툴로 요청을 가로채서 레퍼러를 수정하는 풀이가 꽤 많이 보였다는 것이다. 그리고 크롬의 레퍼러 정책이 바뀐지 얼마 안되서 그런지 이를 모르는 사람이 많아 단순히 레퍼러 주소에 서버 문자열을 삽입해주면 된다는 풀이도 많이 보였다. 같은 사이트(same-origin)에서는 레퍼러가 그대로 유지됐지만 다른 사이트(cross-origin)에서는 개인정보를 위해 레퍼러가 거의 다 잘린다는 것에서 착안하여 레퍼러 정책 위주로 검색했더니 개인정보 때문에 호스트 이름만 남기는 정책이 기본으로 설정됐다는 것을 보고 referrerpolicy 속성값을 설정해서 실습을 원활히 진행할 수 있었다.
'프로젝트 > DVWA 실습' 카테고리의 다른 글
DVWA 실습 #5 - File Inclusion (0) | 2021.01.12 |
---|---|
DVWA 실습 #4-3 - CSRF(high) (0) | 2021.01.08 |
DVWA 실습 #4-1 - CSRF(low) (0) | 2021.01.06 |
DVWA 실습 #4 - CSRF (0) | 2021.01.06 |
DVWA 실습 #3-3 - Command Injection(high) (0) | 2021.01.06 |