Would you like to see what data is coming out of TikTok when you first open it up? Let’s get to it.
Didn’t this used to be easy to do?
As security for iPhones and Androids increased it continually made viewing the traffic leaving your own device more difficult. This is in stark contrast to a regular web browser where you can easily open the network traffic for any site to see the back and forth of the network calls while you visit that site. For mobile apps, if you want to see the traffic on a computer, you need to do a proxy with a custom CA certificate. For years this was with Charles Proxy, Burpsuite and Wireshark. But apps continued to evolve and many began to put their own custom CA certificates inside the apps, meaning it was no longer enough to just forward the traffic to a proxy, you now had to unpin the SLL certificate within the app. This flow below is still possible with Charles or others, but in the end I ended up using the following tools.
- Waydroid – Android Emulator: To install the target app
- + Magisk for root + allowing user certificates
- + LSPosed for SSL unpinning
- MITM Proxy: to capture and view the decrypted traffic
If you’d like more detailed instructions for viewing TikTok HTTPS traffic you can find them on GitHub.
Installing TikTok
I got the APK from APKpure.net and installed it into the emulator. We rolled the dice on a lucky day and happened to download TikTok v33.3.3 so you’ll be seeing that number a lot later. Then with the MITM proxy running, I opened the app for the first time.
Launching TikTok
All the request in the rest of the post are fired within 2-3 seconds of launching, so lots of back and forth within the app and on the network.
Keep in mind, this is all traffic from the emulator, so there are other network requests mixed in that are not from TikTok.
The first one that is for sure from TikTok. You you can see the request to tiktokv.com/monitor/appmonitor/v3/settings
with some basic settings being recorded.
GET https://mon-va.tiktokv.com/monitor/appmonitor/v3/settings?update_version_code=30107125&os=Android&app_version=3.1.7-rc.75.oversea&device_id=&channel=release&aid=2010&crash=npth HTTP/1.1 Content-Type: application/json; charset=utf-8 Query update_version_code: 30107125 os: Android app_version: 3.1.7-rc.75.oversea device_id: channel: release aid: 2010 crash: npth
This is followed shortly after with a Firebase installation:
POST https://firebaseinstallations.googleapis.com/v1/projects/musically-c51f4/installations HTTP/1.1 Content-Type: application/json { "appId": "1:340331662088:android:3c6c52c4762af402", "authVersion": "FIS_v2", "fid": "cMbnNXy6QCGDpHT_mB3TXN", "sdkVersion": "a:17.0.1" }
User Data
Here we see TikTok trying to figure out the carrier_region
and network_sim_region
all of which are empty due to Waydroid emulator not having a sim card.
POST https://api-boot.tiktokv.com/region/submit/?sdk_version=1.2.2&ac=mobile&channel=googleplay&aid=1233&app_name=musical_ly&version_code=330303&version_name=33.3.3&device_platform=android&os=android&ab_version=33.3.3&ssmix=a&device_type=WayDroid+x86_64+Device&device_brand=waydroid&language=en&os_api=30&os_version=11&openudid=6b623cdca1a14c25&manifest_version_code=2023303030&resolution=3456*1970&dpi=360&update_version_code=2023303030&_rticket=1706845427021&is_pad=1&app_type=normal&sys_region=US&timezone_name=Asia%2FTaipei&app_language=en&ac2=unknown&uoo=1&op_region=US&timezone_offset=28800&build_number=33.3.3&host_abi=armeabi-v7a&locale=en®ion=US&ts=1706845427&cdid=e1907a45-45ae-4508-b5e2-171d7964d125 HTTP/1.1 Content-Type: application/json JSON { "carrier_region": "", "locale": "en_US", "mcc_mnc": "", "network_sim_region": "", "system_language": "en", "system_region": "US" }
Now we see the main set of data coming out of the device. This information is repeated in most other requests back and forth. Let’s note some of the interesting ones:
- op_region/sys_region: US
- device_type: WayDroid x86_64 Device
- device_brand: waydroid
- language: en
- os_api: 30
- os_version: 11
- openudid: 6b623cdca1a14c25
- manifest_version_code: 2023303030
- resolution: 3456*1970
- dpi: 360
These are all accurate to the emulator Waydroid, running on my laptop, note the resolution. The op_region/local US and en are related to the Google Play account I am signed into with on the phone, while Asia/Taipei is the current timezone.
GET https://api-boot.tiktokv.com/passport/account/info/v2/?scene=normal&multi_login=1&account_sdk_source=app&passport-sdk-version=19&ac=mobile&channel=googleplay&aid=1233&app_name=musical_ly&version_code=330303&version_name=33.3.3&device_platform=android&os=android&ab_version=33.3.3&ssmix=a&device_type=WayDroid+x86_64+Device&device_brand=waydroid&language=en&os_api=30&os_version=11&openudid=6b623cdca1a14c25&manifest_version_code=2023303030&resolution=3456*1970&dpi=360&update_version_code=2023303030&_rticket=1706845427440&is_pad=1&app_type=normal&sys_region=US&timezone_name=Asia%2FTaipei&app_language=en&ac2=unknown&uoo=0&op_region=US&timezone_offset=28800&build_number=33.3.3&host_abi=armeabi-v7a&locale=en®ion=US&ts=1706845427&cdid=e1907a45-45ae-4508-b5e2-171d7964d125&support_webview=1&okhttp_version=4.2.137.48-tiktok&use_store_region_cookie=1 HTTP/1.1 Accept-Encoding: gzip x-tt-app-init-region: carrierregion=;mccmnc=;sysregion=US;appregion=US sdk-version: 2 x-tt-dm-status: login=0;ct=0;rt=7 X-SS-REQ-TICKET: 1706845427445 passport-sdk-version: 19 pns_event_id: 9 x-vc-bdturing-sdk-version: 2.3.5.i18n User-Agent: com.zhiliaoapp.musically/2023303030 (Linux; U; Android 11; en_US; WayDroid x86_64 Device; Build/RQ3A.211001.001;tt-ok/3.12.13.4-tiktok) X-Ladon: T3YLBE4LXYRR2+5qAqfacGfZklgSFiMMsQJG+LLwWS/K2KTv X-Khronos: 1706845427 X-Argus: 7GLcN9rck1opShLax2FYZ6IEse0/+7WsuaKmyIiBDG+6fGK3w28aOXo0P7vp+fn22ye3LeqP7I4Ae7hQ/WjqBfQLsgEqgEj/jXsiIw7KXBcp/70AXu0vGG/KKiwGBTCmPaGv38VAQGTzWfyiwLU1K7IcxJ4QInnEhmQjmzf2A6trku+NcY0FBApGxTeWBHipRBSvOrkMnuzT5hIq/99QXXgTId9ylIiqjilm9iGrk0aU3JnpA9BKsXQonstxlmpQrJqApi3c7FOVdHJs5ZwatAkRNVNXvQP5gVdQZcCrILMDcw== X-Gorgon: 0404c05b000015eb3032a8aa4fd780a54ff4e00eabc7dc70d487 Host: api-boot.tiktokv.com Connection: Keep-Alive Query scene: normal multi_login: 1 account_sdk_source: app passport-sdk-version: 19 ac: mobile channel: googleplay aid: 1233 app_name: musical_ly version_code: 330303 version_name: 33.3.3 device_platform: android os: android ab_version: 33.3.3 ssmix: a device_type: WayDroid x86_64 Device device_brand: waydroid language: en os_api: 30 os_version: 11 openudid: 6b623cdca1a14c25 manifest_version_code: 2023303030 resolution: 3456*1970 dpi: 360 update_version_code: 2023303030 _rticket: 1706845427440 is_pad: 1 app_type: normal sys_region: US timezone_name: Asia/Taipei app_language: en ac2: unknown uoo: 0 op_region: US timezone_offset: 28800 build_number: 33.3.3 host_abi: armeabi-v7a locale: en region: US ts: 1706845427 cdid: e1907a45-45ae-4508-b5e2-171d7964d125 support_webview: 1 okhttp_version: 4.2.137.48-tiktok use_store_region_cookie: 1
Next we see calls for api-boot.tiktokv.com/aweme/v1/compliance
which note that I am not a teen or child. Additionally is_new_user=0 which must mean that I’ve before downloaded TikTok with this Google account. Keep in mind, this is all within a second or two of running the app, so I assume this must be coming from Android operating system, and it’s possible last year I had installed TikTok at some point on the emulator, though I don’t remember that.
GET https://api-boot.tiktokv.com/aweme/v1/compliance/settings/?teen_mode_status=0&ftc_child_mode=-1&is_new_user=0&ac=mobile&channel=googleplay&aid=1233&app_name=musical_ly&version_code=330303 Query teen_mode_status: 0 ftc_child_mode: -1 is_new_user: 0
Bytes & Encoded data
Now we get to several sets of data that I am unsure how to decode. They generally were mixed in and looked like raw data as well as base64 looking encoded data inside JSONs. These were usually outgoing to log-boot.tiktokv.com/service/2/
. If anyone has some advice for how I can decode those, please let me know, I’d love to try. Below is one of the ones in a json called ‘tt_info’
tt_info: dGMFEAAAlvLESZ997zk5Px-2kAYlx-kHxuOSdiZnulg3tu52u3oUB2f5Q4YZlXJbWNffksbeHYS8 fVPOICA0eRZ_HNph_GdODKIqUG7rHpJXoyo_MaqR8AAtXHFVaHOflwjqxcMO6hq_94eqktKGSD2b geQOYn4dT9SegkOvBAgp8EK_wvB88CIeiF9nydl1ep-BmZfiz4PTVQTRiLzlQCOlP-Y4zhzSMVip w5T1oZmsVg0AwkLVMEO0pm56uIxxtKJDwH00px-oSnnf8P5CxtAWxNaVHTRUw27sLRxggc6O5Y0Z 6LZdcORCFTwTEqTEpzbAtxIZmutVjU_IXYenztd5Xqv6OoQBYtDsuB6cHBihG4GUW-lRF3f6z6-C Mi55QsM9_8EE2pRZr2Z4xNZPWnJHQMWvfHHPGF0hvbaYDls-EhnH1HNK0wZaRGbCBxE0SDd8kDB1 G8buDOg4XsqsaKKZWIQTe9EAZLkhMWRpOja1_mUXxhHFDOcJoZcxo2rErrQRLjTnK40FktrjiD3U jedjB_6Pq3VNVQO_vuXoC5NsepWQyqWbBIwu7VtAcLQoa_AAlqYt7zn9wvcfii1rhHaS7f2V6E3U sIouBAgQAjX6MKePQWRlEhOggFBQHoLd74z4ccrRxdu1wj0QmeGVcQdzXY7nyKQ8z8qF5CnohC3F gSb0ar6vgGuZNmBng-FiLe7N7lY32lyLRZO3B1hZEe04tms_OFta-nDyJocxKjn0vGIaYvFdV4HF H3JdVClIpd6Iomd4
Here’s another interesting one, maybe it’s reading into it too much, but it goes to passport/device/trust_users
and the response trusted_users: null
makes me think I’m not yet a trusted user 🤔
POST https://api22-normal-c-useast1a.tiktokv.com/passport/device/trust_users/?iid=7330845107434735365&device_id=7330843323034600966&ac=mobile&channel=googleplay URLEncoded form last_sec_user_id: d_ticket: last_login_way: -1 last_login_time: 0 last_login_platform: RESPONSE: { "data": { "trust_users": null }, "message": "success" }
This one libra
was super interesting, in the RESPONSE we see some interesting things. Looks like they are testing AppsFlyer as well as something related to mac address, though unclear what it is:
GET https://libra-va.tiktokv.com/common? ... RESPONSE: { "client_hash_value": "lCGnf1lHGbMNzL6XcO6aHA==", "code": 0, "data": { "AWERouter_schema_intercept_switch": { "type": 2, "val": false, "vid": 121360057 }, "AppLog_sample_switch": { "type": 2, "val": 1, "vid": 121347504 }, "AppLog_send_callback_config": { "type": 2, "val": { "ban_header_list": [ "mc", "mac_address" ], "enableDefault": true }, "vid": 121347516 }, "AppsFlyRresourceExperiment": { "type": 2, "val": 1, "vid": 121345122 }, "BA_policy_number": { "type": 2, "val": 1, "vid": 121376992 }, ...
Setting permissions
Later on in that we also see some lists of whitelisted js (javascript?) services that likely can run in the Webview. Interestingly, there is also a large list for music as well. I tried looking into these services and many seem like likely partners for tools like captcha, payment. faceueditor
I couldn’t find though.
"_jsmanage_tt_js_auth": { "type": 2, "val": { "allowList": [ ".sgsnssdk.com", ".isnssdk.com", ".byteoversea.com", ".tiktokcdn.com", ".whizsolve.com", ".snapsolve.com", ".faceueditor.com", ".tiktok.com", ".tiktokv.com", ".ibytedtos.com", ".immers.page", ".capcut.net", ".byteintl.com", ".tiktokcdn-us.com", ".tiktokv-us.com", ".ttwstatic.com", ".soundon.global", ".pipopay.com", ".oneunita.com", ".pipopayment.com", ".g-p-static.com", ".ttlstatic.com", ".tiktokv-eu.com", ".oecstatic.com", ".tiktokv.eu", ".tiktokv.us", ".ttadsmanager.com" ], "blockList": [], "businessLine": 3, "geckoUrl": "https://lf16-gecko-source.tiktokcdn.com/obj/tiktok-teko-source-sg/tt/webview/js_manage/tiktok_webview_js_inject_manage/assets/js/tt_js_auth.js", "injectTime": "very_beginning", "isUseHardCode": false, "name": "_jsmanage_tt_js_auth" }, "vid": 121373567 }, "_jsmanage_tt_music_perf": { "type": 2, "val": { "allowList": [ ".tickets.com", "ticketmaster.", "ticketmaster.at", "ticketmaster.be", "ticketmaster.ch", "ticketmaster.co.nz", "ticketmaster.co.uk", "ticketmaster.com", "ticketmaster.com.au", "ticketmaster.cz", "ticketmaster.ca", "ticketmaster.de", "ticketmaster.dk", "ticketmaster.es", "ticketmaster.fi", "ticketmaster.fr", "ticketmaster.ie", "ticketmaster.it", "ticketmaster.no", "ticketmaster.pl", "ticketmaster.se", "ticketmastergiftcard", "ticketmastergiftcard.com", "ticketmasterpartners.", "tickets.janto.es", "ticketweb.co.uk", "ticketweb.uk", "universe.com", "ticketmaster.evyy.net", ".ticketmaster.", ".ticketmaster.net", ".admission.", ".altitudetickets.", ".amptickets.", ".artsiowa.", ".austintheatre.org.", ".axs.", ".baltimoresoundstage.", ".banknhpavilion.", ".broadwaycenter.org.", ".carolinatix.org.", ".centurylinkarenaboise.", ".chastainseries.", ".cirk.me.", ".cirquedusoliel.", ".cubs.", ".etix.", ".eventbrite.", ".evenue.", ".evenue.net.", ".fgtix.", ".fgtix.to.", ".frontgatetickets.", ".gracelandlive.", ".houstontoyotacenter.", ".ictickets.", ".indians.", ".insomniacshop.", ".instagram.", ".kcstarlight.", ".knoxvilletickets.", ".legendsinconcert.", ".livemu.sc.", ".livenation.", ".livenationpremiumseats.", ".livenationpremiumtickets.", ".lnpromos.com.", ".megaticket.", ".metrapark.", ".mets.", ".mlb.", ".mobilitus.net", ".moshtix.co.nz", ".moshtix.com.au", ".mountbakertheatre.", ".nationals.", ".oceanicentertainment.", ".osheaga.", ".pabsttheater.org.", ".playhousesquare.org.", ".redsox.", ".rutheckerdhall.", ".seetickets.us", ".selectaseat.", ".selectaseatlubbock.", ".shops.ticketmasterpartners.", ".smithstix.", ".spokanearena.", ".strazcenter.org.", ".stubwire.", ".theqarena.", ".ticketalternative.", ".ticketexchangebyticketmaster.", ".ticketf.ly.", ".ticketfly.", ".ticketingcentral.", ".ticketomaha.", ".tickets.", ".ticketsnow.", ".ticketstoday.", ".ticketweb.", ".tigers.", ".toyotacenter.", ".twitch.", ".universe.", ".unlvtickets.", ".upstreammusicfestival.", ".veeps.", ".vendini.", ".vipnation.", ".visulite.", ".waneefestival.", ".wellsfargocenterphilly.", ".wolsteincenter.", ".youtube.", "fgtix.to.", "found.ee.", ".tmdev.co", ".tmtickets.se", "billetnet.dk", "downloadfestival.co.uk", "eticketing.co.uk", "frontgatetickets.com", "moshtix.co.nz", "moshtix.com.au", "rlwc2021.com", "shops.ticketmasterpartners.com" ], "blockList": [], "businessLine": 4, "geckoUrl": "https://lf16-gecko-source.tiktokcdn.com/obj/tiktok-teko-source-sg/tt/webview/js_manage/tiktok_webview_js_inject_manage/assets/js/tt_music_perf.js", "injectTime": "custom_manual", "isUseHardCode": true, "name": "_jsmanage_tt_music_perf" }, "vid": 121377589 },
Advertising
And finally we see the first indications of ads with the Google Advertising ID gaid
from the Waydroid device.
GET https://api-boot.tiktokv.com/tiktok/ug/landing/ads/dest/get/v1/ Query gaid: d5f9e1fb-d518-4efe-86d7-250787a2a1a7 ac: mobile channel: googleplay aid: 1233 app_name: musical_ly ...
Followed by the install conversion event for AppsFlyer, the contents of which are just a raw hex dump I’m not sure what to do with.
POST https://conversions.appsflyer.com/api/v6.4/androidevent?app_id=com.zhiliaoapp.musically&buildnumber=6.4.0 HTTP/1.1 0000000000 b9 ce ac 61 47 19 b4 f7 4f e0 2e 56 6f 9c 0b 82 ...aG...O..Vo... 0000000010 3f 72 47 4f 50 f4 14 6e 46 f6 d6 82 37 6f 55 0a ?rGOP..nF...7oU. 0000000020 b7 91 d0 93 7f 08 4a fb d5 93 51 cb 23 32 56 52 ......J...Q.#2VR 0000000030 7a b9 f2 49 ac f8 d4 b2 6b 40 bf 7b 52 ed 61 c9 z..I....k@.{R.a. 0000000040 18 07 29 ac 61 37 9b 4c 8a 51 7a 8d 62 3d eb ed ..).a7.L.Qz.b=.. ...
The response from AppsFlyer shortly after correctly identifies me as an organic (I didn’t arrive from an ad) user:
{ "af_message": "organic install", "af_status": "Organic", "install_time": "2024-02-02 03:43:50.386" }
Content & Terms of Service
And now we’re getting to some content, like this still JPEG:
So, now it’s 3 seconds later, and let’s see where we are in the app experience:
{ "data": { "/aweme/v1/compliance/settings/": { "body": { "about_privacy_policy_url": "https://www.tiktok.com/legal/privacy-policy-row", "ad_personality_settings": { "att_status": 255, "is_follow_sys_config": false, "is_np_user": 1, "is_show_settings": false, "limit_ad_tracking": false, "mode": 0, "need_pop_up": false, "pa_revising_switch": false, "pers_ad_data_received_partner_mode": 0, "pers_ad_show_data_received_partner": false, "pers_ad_show_third_party_networks": false, "pers_ad_third_party_networks_mode": 0, "unified_mode": 0 }, "age_gate_info": { "age_gate_action": 0, "age_gate_post_action": 0, "register_age_gate_action": 0 }, "cmpl_enc": "UNKNOWN", "commercial_content_library_url": "https://www.tiktok.com/adlibrary", "device_limit_register_expired": true, "extra": { "fatal_item_ids": [], "logid": "20240202034347AC84497362B5DDABA59B", "now": 1706845428000 }, "idfa_popup_allow": false, "interface_control_settings": "{\"rules\":null,\"use_new_control\":true,\"user_type\":\"-1\",\"version\":\"11\"}", "log_pb": { "impr_id": "20240202034347AC84497362B5DDABA59B" }, "parental_guardian_name": "Family Pairing", "policy_info_list": [ { "policy_key": "privacy-policy", "policy_url": "https://www.tiktok.com/legal/privacy-policy" }, { "policy_key": "terms-of-service", "policy_url": "https://www.tiktok.com/legal/terms-of-service" }, { "policy_key": "tiktok-shoutouts-user-terms-of-service", "policy_url": "https://www.tiktok.com/legal/tiktok-shoutouts-user-terms-of-service" }, { "policy_key": "cookie-policy", "policy_url": "https://www.tiktok.com/legal/cookie-policy" }, { "policy_key": "virtual-items", "policy_url": "https://www.tiktok.com/legal/virtual-items" }, { "policy_key": "rewards-policy-eea", "policy_url": "https://www.tiktok.com/legal/rewards-policy-eea" }, { "policy_key": "privacy-policy-for-younger-users", "policy_url": "https://www.tiktok.com/legal/privacy-policy-for-younger-users" }, { "policy_key": "copyright-policy", "policy_url": "https://www.tiktok.com/legal/copyright-policy" }, { "policy_key": "changes-to-personalised-advertising-in-the-eea", "policy_url": "https://www.tiktok.com/legal/changes-to-personalised-advertising-in-the-eea" } ], "policy_notice_enable": true, "status_code": 0, "terms_consent_for_register_info_new_users": { "checkbox_agree_all_terms": "Agree to all", "checkbox_privacy_policy": "Consent to the collection and use of personal information (Required)", "checkbox_terms_of_use": "Consent to the Terms of Service (Required)", "checkbox_tr_notification_subtitle": "Get notifications about trending videos and promotions on TikTok. You can review and edit your settings at any time. Not allowing this type of notification does not limit your use of the TikTok service.", "checkbox_tr_notification_title": "Consent to the receipt of trending content and promotional notifications (Optional)", "tiktok_privacy_policy_url": "https://www.tiktok.com/legal/terms-and-conditions-kr?lang=ko-KR", "tiktok_terms_of_use_url": "https://www.tiktok.com/legal/page/row/terms-of-service/ko-KR", "title": "Terms and conditions" } }, ...
Let’s tap agree and see what happens.
POST https://api22-normal-c-useast1a.tiktokv.com/consent/api/record/create/v1?... entity_keys: conditions-policy-device-consent business_flow: consent_box status: 1
And an updated set of compliance, similar to the one from above.
GET https://api22-normal-c-useast1a.tiktokv.com/aweme/v1/compliance/settings/?teen_mode_status=0&ftc_child_mode=-1&is_new_user=0 ... RESPONSE: { "about_privacy_policy_url": "https://www.tiktok.com/legal/privacy-policy-row", "ad_personality_settings": { "ad_free_subscription": { "subscription_mode": 0 }, "att_status": 255, "description": "With this setting, the ads you see on TikTok can be more tailored to your interests based on data that advertising partners share with us about your activity on their apps and websites.\nYou will always see ads on TikTok based on what you do on TikTok or other data described in our privacy policy.", "disable_att_overwrite_pa": 1, "enable_toggle_decoupling": true, "is_follow_sys_config": false, "is_new_user": 1, "is_np_user": 0, "is_show_3p_data_control": false, "is_show_reset_entry": false, "is_show_settings": true, "is_teenager_mode": 0, "limit_ad_tracking": false, "mode": 1, "need_pop_up": false, "pa_revising_switch": false, "pers_ad_data_received_partner_mode": 0, "pers_ad_main_mode_title": "Using Off-TikTok activity for ad targeting", "pers_ad_show_data_received_partner": false, "pers_ad_show_interest_label": true, "pers_ad_show_third_part_measurement": false, "pers_ad_show_third_party_networks": false, "pers_ad_third_party_networks_mode": 0, "show_advertiser_settings": true, "unified_mode": 0, "use_new_interests": 1 }, "age_gate_info": { "age_gate_action": 0, "age_gate_post_action": 0, "register_age_gate_action": 2 },
After Terms Of Service: And we’re off!
The app shows the video stream and the API requests are flying back and forth now, many a second, so there’s lots more to look at next time. Overall the data seems pretty standard with a few interesting things to look into like the still encrypted data, the connected services and of course, everything after you agree to those Terms of Service.