1) TikTok TLS connections with several Cert Pinning bypasses (targeting Java layer of common SSL implementations, not custom native implementations)
65% error
vs
2) CertPinning bypasses disabled (CA cert is still placed in Android's system store)
100% error
The "success to error ratio" of intercepted requests with CertPinning largely depends on the app and the respective SSL pinning implementation(s) in use. The 65% error of "TikTok" are the "worsed case".
Here's a broader look showing this ration for other apps (no captions)
Did additional event enrichment for failed connection (caused by client disconnect, likely CertPinning).
I want to share an idea for a generic Cert Pinning bypass, cause I have no time to implement it.
First some details on the event, which mainly consists of data from @mitmproxy and associated data from the client device's process (Android device, connection associated based on TCP source IP/port)
...
The correctly associated request source is the "TikTok" app from the Android device "SM-G900F".
The target IP "104.96.1.32" was resolved by mitmproxy and enriched with GeoIP data from MaxMind databases (Netherlands)
The TLS handshake failed with an "sslv3 alert certificate unknown" error, which was collected by mitmproxy, but caused by the (app's) SLL client (CertPinning).
The request method is "CONNECT", because the proxy is not working transparently, and thus includes request headers.
...
The user-agent string from the request headers hints to "Cronet/TTNetVersion:d76f478b" ... which means Cronet was modded by TikTok.
Further down in the event data, under 'event.sockEvent', the information from the device's 'libc.so connect' syscall is included
The TCP connect syscall does not correspond to the actual SSL handshake, but the app code responsible should be closely related. I added in a stack trace for this syscall, which consists of native pointers and debug symbols (if available)
...
This stack trace, again, points to cronet - namely 'libcronet.so' which is shipped with TikTok's native libraries
(see screenshot from device console)
Now the common approach would be to use the known data as starting point for reversing of the 'libcronet.so' cert pinning implementation. To develop a bypass would be time consuming and only apply to this exact case
My idea is the following:
The error events could be further enriched with the public key of the legit TLS server certificate of the request target.
Whenever a TLS client error (like the one shown above) occurs, it gets extracted and forwarded to the @fridadotre which ...
...is instrumenting the associated process.
The Frida agent now could search the heap of the app process for the public key (which should be there, as it is needed for pin checks). Once found, the pinned key could be replaced with the one from the proxy generated certificate
..
...
This would allow successive connections to succeed (bypass cert pinning check). The "key replacement pattern" generated in this manor could further be stored persistently and ultimately be re-applied to process related to the app, right when they start (Frida spawn gating)...
... or once Frida attaches to the already running process.
Also reads on the memory addresses holding the keys could be traced, to ease up reversing of native code.
Not sure if this idea would work, butI am keen to hear some feedback
You want to know what the Facebook app sends home?
Let's look into 1 out of many GraphQL requests ("LocationUpdateMutation" serves as example)
The excerpt of the full request is hard to read, so let's get into some details...
1/n
1) Top-level message object, contains device identifiers and stats.
Pay attention on the empty "scan_result" and "connected" array under "cell_info" ... this likely would be filled, if my test device would have a mobile connection (operator info is included, anyways)
2/n
And here are the scan results with proper BSSIDs and RSSI values for all WiFi networks in range.
Helps to determin your precise position, also great for creation of WiFi maps, if GPS data would be included
Hatte noch Fragen zu 3rd-party data sharing und deshalb nochmal drauf geschaut.
Vor der Registrierung werden scheinbar nur die "üblichen" Daten an 3rd party services gesendet, aber...
...das liegt daran, dass die mit AppsFlyer ausgetauschten Daten nochmals verschlüsselt sind. Öffnet man die, sieht das ganze schon wie folgt aus (2. Bild: exemplarische Daten EINES AppsFlyer events von Scoolio)
PS: die Facebook Attr ID gab's schon einmal letzten Tweet
...
Noch ohne Registrierung, lege ich einen Stundenplan an. Die Speicherung erfolgt nicht in einer eigenen Datenbank, sondern bei "Google Firebase"
Thx @oleavr for the tip to run @fridadotre onetime Android system-level tasks inside 'system_server'.
Example: collect per-app AndroidIDs
1) Agent (TypeScript) 2) App excerpt (calls function of compiled agent in 'system_server' once device connects and detaches) 3) App output
For this use-case alone, it is a big time-saver.
Previous approach:
Monitor 'Binder' (native) or 'android.provider.Settings$Secure' (Java) for AndroidID retrieval **for each process of relevance** (lots of processing overhead).
Add up info on "Android IDs".
While the Android ID could be assumed to be persistent Identifier (unless a device is re-installed), it differs per Android user (usually only one) and package-signer.
For Android SDK <26 Android IDs do not differ on a single device.
Um Klarheit zu schaffen ob/wie die #LucaApp Nutzer warnt, habe ich eine Abfrage eines Locationbesuches durch "Gesundheitsamt Saalfeld-Rudolstadt" gespooft:
1) Popup Notification 2) !!generische!! Abfragebenachrichtigung 3) Info welches GA welche Location abgefragt hat (gepixelt)
Es gibt keine spezifische Warnung über Infektionsrelevanten Kontakten, noch eine ereignisspezifische Nachricht vom Gesundheitsamt INNERHALB der #LucaApp (da kein Rückkanal zum Nutzer existiert).
Alles weitere (so nötig) muss MANUELL durch Direktkommunikation mit GA erfolgen.
Wie es der @kreis_rostock geschafft hat über #LucaApp eine angepasste Warnmeldung zu versenden, um "Betroffene direkt anzusprechen" bleibt unklar.
Getestet wurde von mir die aktuellste Android Version der App v1.11.1