[KakaoTalk] Session Key (3)

Today, I’m going to explain one of the most critical parts in KakaoTalk: Session Key.
KakaoTalk has only one mechanism to authenticate the user. It is the session key that is generated in the process of registering yourself to the KakaoTalk server when you first install on your mobile device. This, then, is stored in the device until the user deletes KakaoTalk.
What’s interesting here is that this session key acts as user identification AND user authentication on server side. Thus, this session does not act the same as the usual ‘web’ session keys, which expires after some time. KakaoTalk Session Key never expire or change — well, I shouldn’t say ‘never’ because there’s a case that the key is purged. It is used throughout until the user deletes his/her account or KakaoTalk app from the phone. (BTW, deleting an app doesn’t cause the account to be deleted.)
As you saw last time, the Session Key is required for every request that is sent to the server, and included in HTTP header with the field name of ‘S’.
사용자 삽입 이미지
So, how is this key generated, and what does the life cycle of the key look like?
    1. Session Key Generation
    • Session Key is consisted of two parts: X-Y
    • First part (X) is generated during the SMS verification in registration step.
      • I tested on Android KakaoTalk, and the following is the steps in detail what’s happening in the process of the verification.
      1. Client requests a SMS verification to KakaoTalk server (ac-talk.kakao.com)
          – This is done through /android/account/request_sms.json
          – POST data: device_uuid, phone_number, country_iso
      2. Server responds with the one-time ‘token’ in json format
          – Meanwhile, the server also sends actual SMS message (which contains passcode) to the number.
      3. Once the user puts in the passcode, the client submits to the server.
          – /android/account/verify_sms.json
          – POST data: token (to verify it’s you), phone_number, country_iso, passcode, device_uuid, old_session_key
          – Here, old_session_key is set when you have changed your phone but still has old_session_key backed up in the system.
      4. Server responds with status code ’11’ and a new token is returned when successful.
      5. Finally, the client requests [/android/account/verify.json] along with the nickname that the user specified.
          – POST data: phone_number, country_iso, device_uuid, new token, nickname, old_session_key
      6. The server generates and sends ‘sessionKey’ in JSON data with other information as well.
          – JSON data includes: sessionKey, ‘member’ object (type is set to -10, which means it’s myself), userid (unique number that differentiates users), nickname, etc.
      7. At this point, the session key has been given to the client, and the client saves it locally.
          – The subsequent requests must contain this session key, otherwise the request is rejected with error code -500 (session key not specified).
      8. Client then sends a query to [/android/account/update_settings.json] to sync the information on the server and the client.
          – POST data: model, simOperator, screen_resolution, os_name, os_version, etc.
          – I wonder why they need all this much information.
      • I haven’t tested on iPhone, but it’s just basically the same with different URL for iPhone.
    • Second part (Y) is generated based on the device id.
      • On Android:
        • This is just plain device ID, it seems. But I haven’t done much reversing on this part, so I may be slightly wrong :p
      • On iPhone:
        • It uses something called ‘encryptedDeiceID’ which it derives from the property named ‘cryptedUniqueIdentifider’ (notice their typo :p)

          사용자 삽입 이미지

        • Again, as the name indicates, it does something with the device ID, but I haven’t reversed this part yet.
    • The reason I didn’t go deep enough to actually understand how they generate the device ID is because while it’s still possible to reverse engineer and reconstruct the encrypted device ID, there’s no way to reconstruct the first part of the session key since it comes directly from the server.
      • Thus, unfortunately, there doesn’t seem to be a good way to regenerate the session key. Once it’s generated and given to the client, both client and server just save it locally and use that to authenticate.

    2. Session Key Life Cycle

    • As I mentioned above, the usage of the session key is blatantly obvious. They use it to authenticate. Once it’s set, it never changes — unless the device is changed.
    • The session key must be included to the request header.
    • If the device ID changes (due to changing the device, etc.), KakaoTalk asks the user to re-verify the mobile device. In this process, old_session_key is set to the previous session key and the newly generated session key is returned.
      • Session Revocation
        • I was little surprised and impressed that KakaoTalk does this correctly ;)
        • When the user  verifies with the existing (same) number, KakaoTalk server revokes (deletes) old association with the account and the session key.
        • Thus, it is not possible to impersonate a user with his/her old session key.
    • Local storage of the key:
      • Android: /data/data/com.kakao.com/shared_prefs/KakaoTalk.perferences.xml
      • iPhone: /User/Applications/XXXXX…XXXX/Library/Preferences/com.iwilab.KakaoTalk.plist

        사용자 삽입 이미지

I mean, their one-factor, fixed token authentication mechanism scares me a little, but I had an impression that they actually somewhat care about security. However, they would need to come up with the better solution to this, since it’s basically game-over situation if someone is able to extract the session key. (You can basically become anyone, and KakaoTalk wouldn’t know shit.)
Anyways, that’s what I have and know about KakaoTalk’s session key system.
I don’t know how they generate the first part, so I wouldn’t go ahead and reverse the algorithm for the second part. If someone knows more about this, feel free to contact me! Maybe we can collaborate to do cool things :p
Thanks for reading!

You may also like...

13 Responses

  1. 6l4ck3y3 says:

    PC버전 포스트를 올리셨다가 내리셨던데… (잽싸게 스크랩 해놓은 1인…)
    혹시 PC버전 프로토타입으로 퍼징 해보셨어요?

    • Cai says:

      어라 -_-; 왜 내려갔는지 모르겠네요 ㅋㅋ 해킹이라도 당했는지..음
      개인적으로 내린적은 없는데 말이죠 ㅎㅎ

      사실 요즘은 연구실 상황이 좀 바빠서 이쪽은 거의 손을 못대고 있네요 ㅎㅎ
      말씀하신것을 해본적은 없구요, 사실 해서 얻을게 그리 없기때문에.. :)

  2. Externalist says:

    Interesting Read! :)

  3. UseZMap says:

    잘 읽었습니다.

    그런데 여기서 https://ac-talk.kakao.com/android/account/request_sms.json의 Post Data의 phone_number은 010-XXXX-XXXX의 형식으로 보내면 되나요 아니면 그냥 010XXXXXXXX로 보내야하나요 아니면 다른 형식으로 보내야하는건가요?

    • Cai says:

      제기억상으로는 대쉬(-) 없는 번호그대로 보내시면 됬었던것 같습니다. 손을 안댄지 좀 되었더만 벌써 가물가물하네요 ㅠㅠ;

  4. UseZMap says:

    지금 카카오톡 대화 프로그램을 제작하고 있는데 저기서 막히는군요.

    안드로이드를 기준으로 했을때 country_iso는 82를 대입해주면 되는건가요?

    device_id는 안드로이드의 uuid를 넣어주면 되는건가요?

    • Cai says:

      제가 기억하기로는 안드로이드에서의 device_id는 말그대로 uuid였던것 같습니다.. 아이폰에서는 uuid에다가 이상한짓을 한다음에 넘기더군요 (encrypted uuid라고 부르는..) country_iso는 KR이나 KO였던것 같습니다…. 분석한지가 좀 되서 기억이 흐릿하네요 ^^;

    • Cai says:

      만약에 그냥 대화 프로그램만 만드실것이라면 (즉, 폰이랑 연동 안되는 계정 생성) device_id는 사실 아무거나 넣으셔도 크게 상관이 없습니다. 문자만 제대로 받으면 되니까요 :) — 구글보이스 번호를 사용하셔도 됩니다.

  5. 서천주 says:

    안녕하세요 님글 아주 유용하게 잘 읽었습니다…
    저도 님과 같은 방법으로 여러가지를 시도해봤는데요..
    역시나 인증 sms 및 인증 토크 받는 부분은 3G 에서도 SSL 을 사용하고 있어서 거기서 막혀버렸네요..
    https://ac-talk.kakao.com/android/account/request_sms.json 에서
    {“status”:-502,”message”:”잘못된 형식의 전화번호 입니다. 정확한 전화번호를 입력해주세요.”} 라는 메시지가
    계속 뜨는데 device_uuid, phone_number, country_iso 및 정확한 전화번호 형식이 어떻게 되는지 알 수 있을까요?
    아니면 님이 알고 있는 ssl bypass 하는 방법이 어떤건지 알려주실수 있으신지요~~~
    아참 제 이메일 주소는 [email protected] 입니다….

    • Cai says:

      안녕하세요 :)

      시간이 나는대로 아예 바이너리 레벨에서 SSL을 없애는 방법에 대해서 쓸까 합니다.. 요즘 너무 바빠서 시간이 안나네요 ㅠㅠ

  6. test says:

    안녕하세요 :D

    글은 잘 읽어보았습니다.
    허나, 몇 시간동안 삽질을 해보니, verify.json으로 POST 넘겨주는부분에서 자꾸 걸리네요..
    -500을 반환 하더라구요..

    뭐, 헤더 부분쪽에 SetRequestHeader “A”, “android/2.7.1/ko” 이런 부분을 넣어보면 가끔 해결되는 경우도 있던데…그것도 아니고.. 그렇다고 지금 packet을 dump 할 수도 없는 상황이라서 바이러니를 분석해보며 끙끙하고 있네여 ㅠ.ㅠ 도움 주실 수 있으신가요?

    –수정 합니다..
    이거 혹시, iphone와 android 의 인증이 따로따로 되나요? 그래서 자꾸 이상한 에러가 난건가..

    https://ac-talk.kakao.com/android/account/verify.json
    이부분의 post 전송시
    user-agent와 A 헤더가 도대체 어떻게되야하는지 정말 궁굼합니다.. 도움좀 주세요..
    안드로이드용 헤더를 찾아서 넣어보면 자꾸 반환값이 -500이 나고.
    iphone 헤더를 구해서 넣어보면 자꾸 -998이 반환되네요.. 도대체 왜이럴까요 ㅠㅠ맨날 삽질이네요..

  7. thomas says:

    Thanks for this analysis. I have been looking over the various alternative messaging apps, particularly at security, and this has been very informative.

  8. 안녕하세요! 카카오톡 웹버전 개발을 하고싶어하는 학생입니다..(지금 세션키 Get 부분이 잘 안되서 혹시가능하시다면 세션키 Get하는 부분만 좀 도와주실 수 있으신가요 ㅠㅠ

    katalk_pc_login_poc.py
    라고 올려주신 부분에서 이렇게 오류거 뜨네요 ㅠㅠ
    임포트는
    import requests
    import json
    import urllib2
    import sys
    이까지 했습니다ㅠ 3버전대에서 작동을 안하길레 2.7로 내려도 안되네요 ㅠㅠ 도움부탁드립니다 ㅠㅠㅠㅠㅠ
    C:\Python27\python.exe C:/Users/Administrator/PycharmProjects/untitled/kako.py
    C:\Python27\lib\site-packages\requests\packages\urllib3\util\ssl_.py:334: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
    SNIMissingWarning
    C:\Python27\lib\site-packages\requests\packages\urllib3\util\ssl_.py:132: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
    InsecurePlatformWarning
    C:\Python27\lib\site-packages\requests\packages\urllib3\connection.py:340: SubjectAltNameWarning: Certificate for sb-talk.kakao.com has no subjectAltName, falling back to check for a commonName for now. This feature is being removed by major browsers and deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 for details.)
    SubjectAltNameWarning
    Error in step 1

    Process finished with exit code 0

Leave a Reply

Your email address will not be published. Required fields are marked *