3.4 KiB
Secret Chat
Secret Chat is KakaoTalk's E2E encryption feature. It was added on top of the existing LOCO protocol which has a couple of flaws including missing integrity protection of the ciphertext.
Secret Chat is opt-in only and not enabled by default in the KakaoTalk mobile app. Most users might not use Secret Chat as it doesn't have the same feature set as regular non-E2E encrypted chat rooms.
We've created a simple script to man-in-the-middle Secret Chat communications with Frida
and mitmproxy
. It demonstrates a well-known server-side attack in which the operator (i.e. KakaoTalk) can spoof a client's public key to intercept and read E2E encrypted chat messages.
After the MITM attack there's no immediate warning message that is prompted to the user. Only if both parties go to Chatroom Settings
-> Public Key
and compare their public key fingerprints, the attack can be detected.
This is how one can run the PoC:
- Assumption: You've already set up your test environment (see setup description here)
- Wipe all entries in the
public_key_info
andsecret_key_info
tables from theKakaoTalk.db
database - Start
mitmproxy
:$ mitmdump -m wireguard -s mitm_secret_chat.py
- Start
Frida
:$ frida -U -l loco-tracer.js -f com.kakao.talk
- Create new Secret Chat room in the KakaoTalk app and send a message
- View message in
mitmproxy
terminal window
How it works:
- Server-side
GETLPK
packet gets intercepted -> Inject MITM public key - Server-side
SCREATE
packet gets intercepted -> Remove an already existing shared secret (if any) - Sender sends a
SETSK
packet ->mitmproxy
script grabs shared secret and re-encrypts it with the recipient's original public key - Using the shared secret, the script computes the E2E encryption key
MSG
andSWRITE
packets are decrypted and dumped in themitmproxy
terminal
Known issues / TODOs:
- Mitmproxy splits large
SCREATE
packets into multiple messages. There's no built-in packet reassembly. As such, fragmentedSCREATE
packets lead to parsing errors -> work-around:- Delete the Secret Chat chatroom and delete all rows from the
public_key_info
andsecret_key_info
tables in theKakaoTalk.db
database - Restart the mitmproxy and Frida scripts
- Create a new chatroom. Also try to create a new chatroom with a different friend.
- Delete the Secret Chat chatroom and delete all rows from the
- If the MITM public key can't be injected, the shared secret can't be decrypted and the script fails with a
ValueError
exception (Encryption/decryption failed
) -> just try again 😉 - The removal of server-side stored shared secrets doesn't seem to work in some cases (flaky)
Android implementation specifics:
- Main Secret Chat implementation in package
com.kakao.talk.secret
and in theLocoCipherHelper
class - Sender's RSA public key pair in
TalkKeyStore.preferences.xml
- Receiver's public keys in table
public_key_info
ofKakaoTalk.db
database - Shared secret stored in table
secret_key_info
ofKakaoTalk.db
database
TO-DOS:
- Reinstall the app and check whether a warning shows up
- Test CFB bit flipping
- How are the msgId and chatId generated? -> nonce for CTR mode!
Demo: