펜테스트짐
훈련을 통해 당신의 실력을 향상시켜보세요.
Open Redirect
모두 12명의 회원님이 완료했어요.
실습 환경
실습을 하시려면 로그인이 필요합니다.
이 훈련에서는 Open Redirect 취약점에 대해 학습합니다.
Open Redirect를 설명하기에 앞서 Redirect(리다이렉트)라는 용어의 개념부터 살펴보죠. 리다이렉트란 간단히 말해서 웹 브라우저가 방문한 URL을 다른 URL로 이동시켜주는 기법을 말합니다. 일반적으로 사용자가 로그인 성공 후 사용자를 인증된 메인 웹 페이지로 이동시키거나, 더 이상 유효하지 않은 URL로 접근한 사용자를 다른 유효한 웹 페이지로 이동시켜주기 위해 사용되는 기법입니다.
Open Redirect란?
Open Reidrect란 리다이렉트될 대상 URL을 사용자가 직접 조작할 수 있고 조작된 URL로 리다이렉트가 수행될 때 발생하는 클라이언트측 웹 취약점으로 피해자는 본인이 웹 브라우저에서 요청한 URL과는 다른 URL을 방문하게 됩니다. Unvalidated Redirect and Forward(검증되지 않은 리다이렉트와 전달)로 불리기도 합니다.
예를 들면 이동할 대상 URL이 매개변수로 포함된 다음과 같은 GET 요청이 있습니다.
http://example.com/redirect.php?url=login.php
example.com의 redirect.php는 "url" GET 매개변수에 지정된 URL로 웹 페이지를 이동시킵니다. 만일 웹 애플리케이션에서 "url" GET 매개변수의 값에 대한 안전한 검증없이 그대로 리다이렉트 시킨다면 공격자는 "url" 매개변수의 값을 임의로 조작하여 피해자가 악성 웹 페이지를 방문하게 하는 피싱 공격에 악용할 수 있습니다.
Open Redirect 동작 원리
웹 애플리케이션에서 일반적으로 사용되는 리다이렉트 기법을 통해 동작 원리를 알 수 있습니다.
HTTP 기반 리다이렉트
서버가 이동할 대상 URL이 지정된 Location 응답 헤더를 웹 브라우저로 보내서 리다이렉트 시키는 방법으로 이 경우 HTTP 응답 상태코드는 3xx입니다.
HTTP 응답 상태코드별 의미는 웹의 이해와 HTTP를 참고하세요.
3xx 응답 상태코드를 받은 웹 브라우저는 Location 응답 헤더에 지정되어 있는 URL로 이동합니다. HTTP 기반 리다이렉트는 리다이렉트 기법 중 최상위 우선순위로 동작하며 사용자 웹 브라우저의 자바스크립트 실행 여부에 영향을 받지 않고 항상 리다이렉트가 가능합니다.
PHP에서는 다음과 같은 함수를 통해 구현됩니다. 아래 구문은 코드에 이동할 URL이 하드코딩되어 있어 안전한 방식에 해당됩니다.
header("Location: http://redirect_url.com");
하지만 다음과 같이 개발자가 사용자로부터 받은 데이터를 안전하지 않은 방식으로 이동할 URL로 사용하는 경우 Open Redirect 취약점이 발생합니다.
header("Location: ".$_GET['url']);
기능상의 특성상 사용자로부터 받은 데이터를 사용할 수 밖에 없다면 화이트리스트 도메인을 데이터베이스 등에 별도로 관리하고 전달받은 URL이 화이트리스트 도메인에 해당되는지 등의 추가적인 보안 기능을 구현해야 합니다.
HTML 기반 리다이렉트
<meta> 태그와 http-equiv 속성을 이용하면 HTML만으로도 리다이렉트가 가능합니다. HTML 페이지의 <head>와 </head> 사이에 아래의 HTML 요소를 배치합니다.
<meta http-equiv="refresh" content="0; url='http://redirect_url.com/'" />
웹 브라우저가 HTML을 파싱하는 중 이 요소를 만나면 content 속성에 지정된 URL로 이동합니다. content 속성의 제일 처음 보이는 0은 얼마 동안의 시간을 대기했다 이동할지를 나타내는 인터벌 값(초 단위)입니다. 일반적으로는 0으로 설정하여 대기없이 바로 이동합니다.
종종 <head>...</head> 태그 사이에 HTML 인젝션이 가능한 경우 위의 구문을 주입하여 리다이렉트를 시킬 수 있지만 이런 경우 대부분 XSS로 전환하시는 게 더 좋습니다.
자바스크립트 기반 리다이렉트
자바스크립트의 window.location 객체를 이용하여 리다이렉트하는 방법입니다.
리다이렉트 기법 중 최하위 우선순위를 가지며 자바스크립트를 실행하지 않는 웹 브라우저에서는 당연히 동작하지 않습니다.
window.location.href = "http://redirect_url.com";
아래와 같이 href를 생략해도 동일하게 동작합니다.
window.location = "http://redirect_url.com";
이 기법 역시 사용자로부터 전달받은 데이터를 안전하지 않은 방식으로 location 객체에 할당하게 되면 Open Redirect 취약점에 노출됩니다.
Open Redirect의 영향
Open Redirect의 영향으로 거론되는 일반적이고 대표적인 피해로는 피싱 공격이 있습니다. Open Redirect는 웹 애플리케이션을 손상시키는 등의 직접적인 피해가 없어 간과하기 쉬운 취약점이지만 공격자는 이를 통해 피싱 공격의 효과를 증대시킬 수 있습니다. 일반적으로 사용자는 본인이 방문하는 URL의 도메인을 보고 도메인이 유명하거나 평판이 좋다면 신뢰할만한 URL이라고 판단합니다. 반면 낯선 URL은 한번이라도 의심당하기 쉽고 그만큼 공격 효과는 낮아집니다. 공격자들이 페이스북이나 구글 등과 같이 사용자가 많고 평판이 좋은 도메인과 최대한 유사한 도메인을 이용하여 공격하는 것 또한 바로 이러한 점 때문입니다. 사람들이 신뢰할만한 웹 애플리케이션에 Open Redirect 취약점이 있다면 공격자는 해당 도메인에 대한 사람들의 신뢰도를 이용해 피싱 공격의 성공율을 더 높일 수 있는 것입니다.
공격자는 Open Redirect 취약점이 존재하는 target.com을 이용해 아래와 같은 URL을 구성하여 피해자가 방문하도록 유도합니다.
http://target.com/redirect.php?goto=http://evil.com/malicious_page
target.com이라는 도메인을 보고 안전한 URL이라 판단한 피해자는 URL을 방문하고 본인의 의지와 상관없이 공격자가 제어하는 웹 사이트인 http://evil.com/malicious_page을 방문하게 됩니다.
만일 공격자가 http://evil.com/malicious_page에 target.com의 Fake(가짜) 로그인 웹 페이지를 만들어 두었다면 사용자는 의심없이 자신의 아이디와 패스워드를 입력하여 로그인을 시도할 수 있습니다. 사용자의 로그인 자격증명은 공격자의 서버에 전송되게 됩니다. 하지만 단순히 피싱 공격에 활용되는 측면은 피해로 간주할 수 없다는 의견도 있으며 버그바운티에서는 피싱을 유효 버그로 인정하지 않는 회사가 많다는 것을 참고하세요. 인정이 되지 않는 경우이거나 더 높은 등급의 버그를 제보하고 싶다면 다른 버그로 결합할 수 있는 방안을 강구해야 합니다.
Open Redirect는 경우에 따라 XSS 또는 OAuth 토큰 유출, SSRF 등의 버그와 결합하여 더 높은 심각도의 버그로 신고할 수 있습니다. 참고할만한 몇 개의 문서를 링크해두었으니 읽어보시기 바랍니다.
XSS
"XSS and Open Redirect on MoPub Login" - https://hackerone.com/reports/683298
"Bounty Tip- Open redirection escalated further into an XSS !!" - https://infosecwriteups.com/bounty-tip-open-redirection-escalated-further-into-an-xss-edec8e3abe78
"Github Open Redirect to Reflected XSS POC" - https://www.youtube.com/watch?v=_0r37EhrVeQ
OAuth 토큰 유출
- "Open redirection in OAuth" - https://hackerone.com/reports/55525
- "Stealing OAuth Tokens With Open Redirects" - https://sec.okta.com/articles/2021/02/stealing-oauth-tokens-open-redirects
SSRF
"https://hackerone.com/reports/514224" - https://hackerone.com/reports/514224
Open Redirect 예방
다음의 방법을 통해 Open Redirect를 예방할 수 있습니다.
1. 사용자 입력을 리다이렉트될 대상 URL로 사용해선 안됩니다. 사용자 입력 대신 하드코딩으로 대체가 가능하다면 대상 URL을 코드에 직접 명시하여 사용하세요.
2. 불가피하게 사용자 입력을 리다이렉트될 대상 URL로 사용해야 할 경우에는 사용자 입력에 대한 안전한 유효성 검증 기능을 구현해야 합니다.
- 절대경로 대신 상대 경로를 사용합니다. 상대 경로를 사용하더라도 우회가 가능할 수 있습니다. 사용자 입력에 공백 문자(%20, %09 등), 골뱅이문자(@), 콜론(;), 슬래시(/), 역슬래시(\) 등 우회를 위해 사용될 수 있는 문자가 포함되어 있는지 철저하게 검증하세요.
- XSS 등 다른 버그와 결합될 수 있는 CR(Carriage Return, \r, %0D), LF(Line Feed, \n, %0A), 꺽쇠괄호(< 또는 >) 등의 문자가 포함되어 있는지 철저하게 검증하세요.
3. 리다이렉트를 수행할 때 별도의 웹 페이지를 거치게 하여 사용자에게 리다이렉트가 되고 있음을 알리고 사용자가 수락한 경우에만 이동하도록 합니다.
Open Redirect 테스트 방법
Step 1. 리다이렉트를 수행하는 기능 탐색
대상 웹 애플리케이션에서 리다이렉트가 수행되는 모든 요청을 찾습니다. 요청을 찾기 위해 아래의 방법을 활용할 수 있습니다.
1. 웹 애플리케이션에서 일반적으로 리다이렉트를 활용하는 기능을 살펴보세요: 로그인/로그아웃, 언어 변경 등
2. Burp Suite과 같은 프록시 도구를 통해 웹 애플리케이션의 기능을 모두 사용해보고 HTTP 응답 상태코드가 3xx인 요청을 찾으세요.
3. 구글에서 다음의 검색어를 통해 리다이렉트가 수행되는 종단점(Endpoint)를 찾을 수 있습니다.
site:target.com inurl:url=
구글링을 할 때에는 위 검색어의 inurl: 부분에서 "url=" 대신에 리다이렉트에 일반적으로 사용되는 아래의 검색어를 사용해보거나 대상 웹 애플리케이션의 매개변수 명명(Naming) 규칙을 파악하고 사용할만한 매개변수명을 추측하여 검색해봅니다.
/{payload}
?next={payload}
?url={payload}
?target={payload}
?rurl={payload}
?dest={payload}
?destination={payload}
?redir={payload}
?redirect_uri={payload}
?redirect_url={payload}
?redirect={payload}
/redirect/{payload}
/cgi-bin/redirect.cgi?{payload}
/out/{payload}
/out?{payload}
?view={payload}
/login?to={payload}
?image_url={payload}
?go={payload}
?return={payload}
?returnTo={payload}
?return_to={payload}
?checkout_url={payload}
?continue={payload}
?return_path={payload}
Step 2. 리다이렉트 동작 여부 확인
Step 1에서 찾은 요청에서 URL이 지정된 매개변수의 URL(절대 경로이거나 상대 경로일 수 있습니다.)을 https://www.google.com과 같은 무해한 임의의 절대 경로 URL로 변경해 요청해보고 변경된 URL로 리다이렉트가 수행되는지 확인합니다.
실습 문제 풀이
Open Redirect 취약점만을 설명합니다. Open Redirect와 결합할 수 있는 XSS, SSRF 등의 버그는 다루지 않습니다.
Exercise 1
이 문제는 사용자로부터 직접 URL을 입력받고 사용자의 입력값으로 리다이렉트를 수행하고 있습니다.
1. 모든 요청과 응답을 가로채기 위해 웹 브라우저에 Burp Suite 또는 ZAP 프록시를 설정하세요. 2. "Enter the target URL" 입력 필드에 https://www.google.com을 입력하고 "Submit" 버튼을 클릭합니다. 3. 프록시 도구에서 응답 상태코드가 302인 요청을 찾습니다. 정확히 찾았다면 요청은 다음과 같을 것입니다. http://본인의 가상 실습환경 주소/openrd_ex1.php?redirect_url=https%3A%2F%2Fwww.google.com 이 요청의 응답을 살펴보세요. Location 응답 헤더에 "redirect_url" GET 매개변수로 전달된 값이 할당되고 리다이렉트가 수행된다는 것을 알 수 있습니다. HTTP/1.1 302 Found 4. Burp Suite의 Repeater 또는 ZAP 프록시의 Requester로 요청을 복사하고, "redirect_url" GET 매개변수의 값을 임의의 주소로 변경한 후 요청을 보냅니다. 5. 변경된 임의의 주소로 리다이렉트가 수행됩니다. |
Exercise 2
이 문제는 화면에서 사용자가 어떤 데이터도 입력할 수 없습니다. 그러나 화면상의 링크를 클릭하면 GET 매개변수의 값이 전달되고 리다이렉트가 수행됩니다.
1. 모든 요청과 응답을 가로채기 위해 웹 브라우저에 Burp Suite 또는 ZAP 프록시를 설정하세요. 2. 홈 화면으로 돌아갈 수 있는 링크("Click here to go back to the home.")가 있습니다. 링크를 클릭하세요. 3. 프록시 도구에서 응답코드가 302인 다음과 같은 요청을 찾습니다. http://본인의 가상 실습환경 주소/openrd_ex2.php?redirect_url=index.php 4. Burp Suite의 Repeater 또는 ZAP 프록시의 Requester로 요청을 복사하고, "redirect_url" GET 매개변수의 값을 https://www.google.com으로 변경한 후 요청을 보냅니다. http://본인의 가상 실습환경 주소/openrd_ex2.php?redirect_url=https%3A%2F%2Fwww.google.com 5. 다음과 같이 302 리다이렉트가 수행됩니다. HTTP/1.1 302 Found |
Exercise 3
이 문제는 사용자가 선택할 수 있는 이동할 웹 사이트 목록이 있으며, 선택된 웹 사이트의 URL로 리다이렉트가 수행됩니다.
1. 모든 요청과 응답을 가로채기 위해 웹 브라우저에 Burp Suite 또는 ZAP 프록시를 설정하세요. 2. 셀렉트 박스에서 "구글"을 선택하고 "Submit" 버튼을 클릭합니다. 3. 프록시 도구에서 다음과 같은 요청을 찾습니다. http://본인의 가상 실습환경 주소/openrd_ex3.php?redirect_url=https%3A%2F%2Fwww.google.com 실습 문제 1, 2와 다른 점은 요청에 대한 응답 상태코드가 200 OK라는 점입니다. 응답을 살펴보면 <meta> 태그를 이용한 HTML 기반 리다이렉트임을 알 수 있습니다. HTTP/1.1 200 OK 4. Burp Suite의 Repeater 또는 ZAP 프록시의 Requester로 요청을 복사하고, "redirect_url" GET 매개변수의 값을 임의의 주소로 변경한 후 요청을 보냅니다. 5. 변경된 임의의 주소로 리다이렉트가 수행됩니다. |
Exercise 4
이 문제는 문제3과 거의 동일하지만 조금 다른 방법을 통해 리다이렉트를 수행합니다.
1. 모든 요청과 응답을 가로채기 위해 웹 브라우저에 Burp Suite 또는 ZAP 프록시 설정하세요. 2. 셀렉트 박스에서 "구글"을 선택하고 "Submit" 버튼을 클릭합니다. 폼은 지정된 openrd_ex4-1.php로 제출됩니다. 3. 프록시 도구에서 다음과 같은 요청을 찾습니다. http://본인의 가상 실습환경 주소/openrd_ex4-1.php?redirect_url=https%3A%2F%2Fwww.google.com 응답을 살펴보면 자바스크립트에서 "redirect_url" GET 매개변수에 지정된 URL로 리다이렉트를 수행하고 있음을 알 수 있습니다. HTTP/1.1 200 OK 4. Burp Suite의 Repeater 또는 ZAP 프록시의 Requester로 요청을 복사하고, "redirect_url" GET 매개변수의 값을 임의의 주소로 변경한 후 요청을 보냅니다. 5. 변경된 임의의 주소로 리다이렉트가 수행됩니다. |
참고 문헌
- https://www.acunetix.com/blog/web-security-zone/what-are-open-redirects/
- https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
- https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/understanding-and-discovering-open-redirect-vulnerabilities/
- https://pentester.land/cheatsheets/2018/11/02/open-redirect-cheatsheet.html