Relative Path Overwrite(RPO)는 브라우저와 서버가 상대경로를 해석하는 과정에서의 동작 차이를 악용한 공격기법이다.
절대경로는 프로토콜과 도메인 이름을 포함한 목적지 주소의 전체 URL을 의미한다. 반면에 상대경로는 목적지의 프로토콜이나 도메인을 특정하지 않는다.
2014년 Gareth Heyes 에 의해 발견된 공격 기법이다.
<!-- URL : http://www.test.com/path/traversal/index.html -->
<html>
<head>
<link href="style.css" rel="stylesheet" type="text/css"/>
</head>
</html>
: 위의 HTML 파일은 상대경로를 사용해 style.css를 참조함. 즉, 유저가 "http://www.test.com/path/traversal/index.html" 라는 주소에서 참조를 했다면 "http://www.test.com/path/traversal/style.css" 이라는 주소에서 파일이 호출 될 것이다.
URL : http://www.test.com/path/traversal/..%2f/..%2findex.html
%2f 는 URL Decoding 을 해보면 '/'(슬래쉬) 이다. 즉, ../ 가 되는 것이고 서버는 위의 주소를 해석한 Path은 아래와 같다.
URL : http://www.test.com/index.html
: 그래서 서버는 저 주소의 html 파일을 보낸다. 그리고 브라우저는 ..%2f를 상위 경로로 해석하지 못하기에 다음과 같은 주소에 있는 css 파일을 로드한다.
RPO 공격기법을 이용하면 임의의 js 또는 css 파일을 로드할 수 있다.
즉, 서버에 js 파일을 올릴 수 있다면 XSS를 트리거 할 수 있다는 것이다!! 실습을 해보자.
다음과 같은 주소가 있다고 하자. URL : http://localhost/RPO/post/index.html
또한 alert를 띄우기 위해 우리는 http://localhost/RPO/uploads/app.js 위치에 악성 스크립트를 업로드해뒀다. 이제 RPO를 이용해 악성 스크립트 파일을 로드하게 만들어 보자.
<!-- http://localhost/RPO/post/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>RPO Test</title>
<link href="style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<h1 class="title">
This is Very Simple Page.
</h1>
<hr>
<div class="box">
<h2 class="hello">
Hello, World! If you click on me, the color will change.
</h2>
</div>
<script src="app.js"></script>
</body>
</html>
// http://localhost/RPO/post/app.js
const helloClass = document.querySelector(".box > .hello");
function changeColor() {
this.classList.toggle("clicked")
}
helloClass.addEventListener("click", changeColor);
// http://localhost/RPO/post/app.js
body {
background-color: beige;
}
.hello {
color: blueviolet;
}
.clicked {
color: red;
}
: 이 페이지는 그냥 h2 태그를 누르면 색깔이 blueviolet과 red 색으로 계속 바뀌는 것이다.
const helloClass = document.querySelector(".box > .hello");
function changeColor() {
alert(1);
}
helloClass.addEventListener("click", changeColor);
현재 URL : http://localhost/RPO/post/index.html
alert를 띄우는 스크립트 파일을 uploads 폴더에 app.js 라는 이름으로 올려뒀다. 이를 브라우저가 로드시키게 해보자.
: 이렇게 하면 서버 입장에서는 uploads/../post/index.html 이기에 결국 /post/index.html이 된다.
그래서 /post/index.html 파일을 클라이언트에게 주는데, 브라우저는 html을 해석하는 과정에서 src="app.js" 를 불러오기 위해 "현재 directory/app.js" 를 요청을 보내겠지만 브라우저는 ..%2F를 모른다. 그래서 그 부분은 다 짤라버리기에 http://localhost/RPO/uploads 가 현재 주소로 인식하고 http://localhost/RPO/uploads/app.js 에 요청을 보내 파일을 받아온다.
: 눌렀을 때, 색깔이 바뀌지 않고 alert창을 띄우는 것을 볼 수 있다.