safetynet-fix icon indicating copy to clipboard operation
safetynet-fix copied to clipboard

Play Integrity Api bypass

Open Displax opened this issue 1 year ago • 34 comments

Bypass PIA (for now?) by changing fingerprint to old "marlin" 7.1.2 (does not required to apply other security patch level). This kills two rabbits: • fix old SN CTS profile check on some weird Custom ROMs • bypass Integrity (MEETS_DEVICE_INTEGRITY) for now.

Other commit fix OnePlus OOS 12 problems ( thanks to @HuskyDG )

Displax avatar Jul 25 '22 19:07 Displax

Close https://github.com/kdrag0n/safetynet-fix/issues/224, https://github.com/kdrag0n/safetynet-fix/issues/222, https://github.com/kdrag0n/safetynet-fix/issues/220, https://github.com/kdrag0n/safetynet-fix/issues/218, https://github.com/kdrag0n/safetynet-fix/issues/212, https://github.com/kdrag0n/safetynet-fix/issues/211, https://github.com/kdrag0n/safetynet-fix/issues/210, https://github.com/kdrag0n/safetynet-fix/issues/204, https://github.com/kdrag0n/safetynet-fix/issues/203, https://github.com/kdrag0n/safetynet-fix/issues/201, https://github.com/kdrag0n/safetynet-fix/issues/196, https://github.com/kdrag0n/safetynet-fix/issues/188, https://github.com/kdrag0n/safetynet-fix/issues/171, https://github.com/kdrag0n/safetynet-fix/issues/170

Displax avatar Jul 25 '22 21:07 Displax

Nice solution, thanks for looking into this. Have you noticed any features acting up with the old fingerprint?

Ideally, I think this should be scoped to Play Integrity code by identifying methods it calls near the beginning and end of integrity checks, and adding hooks to set and restore the fingerprint. I feel like setting a fingerprint that doesn't match the system in so many ways is bound to cause an issue somewhere.

kdrag0n avatar Jul 26 '22 13:07 kdrag0n

For example, the existing attestation hook could probably be used as a begin or end hook, depending on when Play Integrity calls it. We'd have to find another hook that can be installed within the constraints of reflection.

kdrag0n avatar Jul 26 '22 13:07 kdrag0n

@kdrag0n Hi, thank you for attention! Yes, I agree with you. We need separate target hook for this (if feasible) - will be more polite solution. My solution - just quick example (and core resolve) with temp fix for impatient people)) Though to be honest I didn't notice any problems on my side (and no one report it for now). But need more testing with various devices. Anyway, you have more knowledge than me on how to do it correctly and in better way ;)

Target process (one of?) "com.android.vending/com.google.android.finsky.integrityservice.IntegrityService"

Displax avatar Jul 26 '22 20:07 Displax

@Displax i suggested to let user choose the fingerprint by their own (see the example here http://github.com/huskydg/riru-integrityfix)

HuskyDG avatar Jul 31 '22 10:07 HuskyDG

Random thought: maybe the "delete key" method on the existing security provider could serve as an end hook. GMS generates a new keypair for each attestation so it probably deletes the keypair shortly afterwards.

Of course, this is all theoretical as it depends on the exact order of steps in the integrity checking process. Worst case scenario, we could just sleep for 1 second or so and revert the fingerprint change in a background thread. Not sure when I'll have time to look into it myself, but feel free to try implementing this idea:

  • Set the fingerprint in the key attestation hook
  • Spawn a thread to revert it after 3 seconds:
thread(daemon = true) {
    Thread.sleep(3000)
    /* revert */
}

kdrag0n avatar Jul 31 '22 14:07 kdrag0n

@kdrag0n Some theoretical thought... Can we simulate device with broken keystore (like some zenfone, oneplus models)? Reported that they pass STRONG_INTEGRITY even that it completely broken.

Displax avatar Aug 02 '22 19:08 Displax

I applied the mod version, I got

✔️ MEETS_DEVICE_INTEGRITY ✔️ MEETS_BASIC_INTEGRITY ❌ MEETS_STRONG_INTEGRITY on integritycheck app.

Other apps like RootBeet Sample and SafetyNet Test all work great too, but they also did before this issue.

My device is an Zenfone 6 (2019), fingerprint is itself.

Google Pay/Wallet working just fine (YAAAAY)

I have MagiskHideProps, Shamiko, this and a module that enables stuff on my camera. I'm new to root, but I feel great KEKW Thank you ;P

Lohkdesgds avatar Aug 02 '22 22:08 Lohkdesgds

@kdrag0n Some theoretical thought... Can we simulate device with broken keystore (like some zenfone, oneplus models)? Reported that they pass STRONG_INTEGRITY even that it completely broken.

Seems what is broken in keymaster implementations varies.

Reports I've seen indicate that affected OnePlus devices generally don't pass STRONG_INTEGRITY, whereas Rog phone 3 (for one) passes...

pndwal avatar Aug 05 '22 03:08 pndwal

Hi guys, just want to let you know... I have a OnePlus 8T with the latest Android 12, rooted with latest Magisk, etc. Installing the module from this PR fixed my play store certification problem. I did have to wipe the past store app data after installing the module in order for it to pass certification. The Integrity checker app shows the strong integrity test failing, but that doesn't seem to make a difference with anything. Basic safety net stuff passes just fine.

Thank you!

Efpophis avatar Aug 07 '22 21:08 Efpophis

Re. "Req version that doesn't append a space character to the device model name" #211

@Displax, that issue makes me wonder...

It seems to me that if fingerprint should match the (expected) model as the issue suggests, then @kdrag0n's original model prop mismatch (to bypass hardware attestation enforcement) might also be produced by using a mismatched fingerprint, as your mod already does... (It is also apparent that this mismatch, at least with a very old print, causes no (known) problems for passing new MEETS_DEVICE_INTEGRITY.)

I haven't been able to test this*, but I now wonder if anyone using USNF with your 'Play Integrity Api bypass' (which introduces targeted fingerprint spoofing for gsm attestation process) actually needs altered model in addition if mismatch is achieved without it... Perhaps fingerprint spoofing can / does kill two birds... as well as two rabbits... 😛

*- On my Xiaomi RN8T w/ Android 10, if I restore ro.product.model using MHPC (ie. remove appended space) and reboot, I still have S/N passing w/ official USNF, so my device doesn't need the mismatch anyway...

pndwal avatar Aug 08 '22 12:08 pndwal

I haven't been able to test this*, but I now wonder if anyone using USNF with your 'Play Integrity Api bypass' (which introduces targeted fingerprint spoofing for gsm attestation process) actually needs altered model in addition if mismatch is achieved without it...

Tested already, mismatched "model" still needed anyway

Displax avatar Aug 08 '22 23:08 Displax

Pixel 6 Pro, rooted with base rom with Magisk 25.2, failing STRONG_INTEGRITY with patch. Android 12

ImperatorStorm avatar Aug 09 '22 07:08 ImperatorStorm

Pixel 6 Pro, rooted with base rom with Magisk 25.2, failing STRONG_INTEGRITY with patch. Android 12

Expected

Displax avatar Aug 09 '22 11:08 Displax

Anyone with ROG 3 can test? Spoofing/Replicating should be fairly easy but someone please test and post the results here

xAffan avatar Aug 30 '22 10:08 xAffan

@kdrag0n Some theoretical thought... Can we simulate device with broken keystore (like some zenfone, oneplus models)? Reported that they pass STRONG_INTEGRITY even that it completely broken.

Wouldn't doing this require you to reverse engineer the hardware keystore of one of the phones that have this problem?

DavidBerdik avatar Sep 14 '22 17:09 DavidBerdik

I have Displax's mod version running on both a Pixel 3a running Android 10 and a Pixel 6a on Android 13 . The 3a shows up on my google account as a Pixel 3a, but the 6a shows up as a Nexus 6P. Is this to be expected?

zanhecht avatar Sep 22 '22 14:09 zanhecht

I have Displax's mod version running on both a Pixel 3a running Android 10 and a Pixel 6a on Android 13 . The 3a shows up on my google account as a Pixel 3a, but the 6a shows up as a Nexus 6P. Is this to be expected?

Yes

Displax avatar Sep 22 '22 17:09 Displax

I have Displax's mod version running on both a Pixel 3a running Android 10 and a Pixel 6a on Android 13 . The 3a shows up on my google account as a Pixel 3a, but the 6a shows up as a Nexus 6P. Is this to be expected?

Yes

If I can ask. Why the Pixel 3a android 10 show it as himself but the Pixel 6a android 13 as Nexus 6P? (Like the fingerprint in this mod)

VisionR1 avatar Sep 24 '22 06:09 VisionR1

@Displax , i have tried your mod, downloaded from https://forum.xda-developers.com/t/magisk-module-universal-safetynet-fix-2-3-1.4217823/page-91#post-87198517

but unfortunately my banking app (https://play.google.com/store/apps/details?id=ro.ing.mobile.banking.android.activity) still detects something different.

More specifically: if i wipe my pixel 4a, the ING app starts and works as expected even though my bootloader is unlocked. After i install magisk app (and hide it) and flash the magisk modded boot image and flash your mod, the ing app does not work. Google Wallet and another banking app do work as expected with your mod, it's just the ING Homebank app which still detects root.

IDK if this is the right place to give you this feedback, so if you want another forum please say and mark this as spam.

TheBestPessimist avatar Sep 29 '22 08:09 TheBestPessimist

but unfortunately my banking app (https://play.google.com/store/apps/details?id=ro.ing.mobile.banking.android.activity) still detects something different.

@TheBestPessimist it works with magiskhide and riru

HuskyDG avatar Sep 29 '22 09:09 HuskyDG

IDK if this is the right place to give you this feedback, so if you want another forum please say and mark this as spam.

It's really not; XDA Magisk General Support / Discussion or Magisk - The Age of Zygisk would be...

The purpose of USNF and this mod are to "work around Google's SafetyNet attestation" and that of the updated API, Play Integrity. It's a 'universal fix' to allow these attestations to pass...

This module is not for hiding 'root' or associated customisations other than from processes in gms (ie. Google Play Services)... That's the role of Shamiko, Hide My Applist and the like... If you can pass S/N (and achieve passing deviceIntegrity verdict with this mod), USNF is doing its job! 🙂

pndwal avatar Sep 29 '22 11:09 pndwal

Not saying against shamiko but few people don't trust closed source thing like shamiko...

HuskyDG avatar Sep 30 '22 03:09 HuskyDG

Very strange, today Google play store show me again the Netflix and some other apps which had been missing since July, I don't have changed anything in my phone, I have Xiaomi Poco X3 NFC android 10, magisk 23 with magisk hide com.google.android.gms.unstable and module riru 26.1.3 and Universal SafetyNet Fix 2.1.1 by kdrag0n

VisionR1 avatar Oct 01 '22 17:10 VisionR1

Any progress on this PR? Seems inactive by the part of kdrag0n

josesilveiraa avatar Oct 03 '22 21:10 josesilveiraa

Any progress on this PR? Seems inactive by the part of kdrag0n

I wouldn't be surprised if he's waiting for SafetyNet to get killed off before making any moves.

DavidBerdik avatar Oct 05 '22 02:10 DavidBerdik

Any progress on this PR? Seems inactive by the part of kdrag0n

I wouldn't be surprised if he's waiting for SafetyNet to get killed off before making any moves.

People, he's a busy guy (check his bio / 114 repos here)...

S/N is already depreciated (practically 'killed off') w/ a June 2023 | Migration deadline and Full turndown slated for June 2024.

This mod is working for nearly everyone already however, and, in case any are unaware, has been available for some time now from here: https://forum.xda-developers.com/t/magisk-module-universal-safetynet-fix-2-3-1.4217823/post-87198517

So as long as @kdrag0n is ok with this interim solution it seems merging official fix for new deviceIntegrity verdict is not an urgent priority... But I'm sure it's somewhere on the list. 😛

pndwal avatar Oct 05 '22 05:10 pndwal

As I explained at the beginning of this thread, I don't plan to merge this solution because it can cause issues like devices showing up as "Nexus 6P" and some device-specific features potentially not working properly. I haven't had time to work on my proposed solution, but I've already posted my thoughts on implementation details if anyone wants to take a shot at it: https://github.com/kdrag0n/safetynet-fix/pull/207#issuecomment-1200437447

Not much has changed since I posted that.

kdrag0n avatar Oct 05 '22 05:10 kdrag0n

I did try this suggestion from @Displax though:

@kdrag0n Some theoretical thought... Can we simulate device with broken keystore (like some zenfone, oneplus models)? Reported that they pass STRONG_INTEGRITY even that it completely broken.

How broken specifically? Throwing UnsupportedOperationException from every method causes GMS to crash repeatedly in the background, so it can't be that broken. I assume that at least load works, but I think we'd need a more accurate of what methods are and aren't broken if we go that route.

Breaking attestation for the unstable process was fine AFAIK, but breaking most/all of keystore seems risky and likely needs further investigation as well (if this method works).

This is what I tried:

diff --git a/java/app/src/main/java/dev/kdrag0n/safetynetfix/proxy/ProxyKeyStoreSpi.kt b/java/app/src/main/java/dev/kdrag0n/safetynetfix/proxy/ProxyKeyStoreSpi.kt
index 9005f66..314340e 100644
--- a/java/app/src/main/java/dev/kdrag0n/safetynetfix/proxy/ProxyKeyStoreSpi.kt
+++ b/java/app/src/main/java/dev/kdrag0n/safetynetfix/proxy/ProxyKeyStoreSpi.kt
@@ -39,6 +39,7 @@ class ProxyKeyStoreSpi private constructor(
 
     override fun engineGetCertificateChain(alias: String?): Array<Certificate>? {
         logDebug("Proxy key store: get certificate chain")
+        unsupported()
 
         if (isCallerSafetyNet()) {
             logDebug("Blocking call")
@@ -51,23 +52,28 @@ class ProxyKeyStoreSpi private constructor(
 
     // Direct delegation. We have to do this manually because the Kotlin compiler can only do it
     // for interfaces, not abstract classes.
-    override fun engineGetKey(alias: String?, password: CharArray?): Key? = orig.engineGetKey(alias, password)
-    override fun engineGetCertificate(alias: String?): Certificate? = orig.engineGetCertificate(alias)
-    override fun engineGetCreationDate(alias: String?): Date? = orig.engineGetCreationDate(alias)
-    override fun engineSetKeyEntry(alias: String?, key: Key?, password: CharArray?, chain: Array<out Certificate>?) = orig.engineSetKeyEntry(alias, key, password, chain)
-    override fun engineSetKeyEntry(alias: String?, key: ByteArray?, chain: Array<out Certificate>?) = orig.engineSetKeyEntry(alias, key, chain)
-    override fun engineSetCertificateEntry(alias: String?, cert: Certificate?) = orig.engineSetCertificateEntry(alias, cert)
-    override fun engineDeleteEntry(alias: String?) = orig.engineDeleteEntry(alias)
-    override fun engineAliases(): Enumeration<String>? = orig.engineAliases()
-    override fun engineContainsAlias(alias: String?) = orig.engineContainsAlias(alias)
-    override fun engineSize() = orig.engineSize()
-    override fun engineIsKeyEntry(alias: String?) = orig.engineIsKeyEntry(alias)
-    override fun engineIsCertificateEntry(alias: String?) = orig.engineIsCertificateEntry(alias)
-    override fun engineGetCertificateAlias(cert: Certificate?): String? = orig.engineGetCertificateAlias(cert)
-    override fun engineStore(stream: OutputStream?, password: CharArray?) = orig.engineStore(stream, password)
-    override fun engineLoad(stream: InputStream?, password: CharArray?) = orig.engineLoad(stream, password)
+    override fun engineGetKey(alias: String?, password: CharArray?): Key? = unsupported()
+    override fun engineGetCertificate(alias: String?): Certificate? = unsupported()
+    override fun engineGetCreationDate(alias: String?): Date? = unsupported()
+    override fun engineSetKeyEntry(alias: String?, key: Key?, password: CharArray?, chain: Array<out Certificate>?) = unsupported()
+    override fun engineSetKeyEntry(alias: String?, key: ByteArray?, chain: Array<out Certificate>?) = unsupported()
+    override fun engineSetCertificateEntry(alias: String?, cert: Certificate?) = unsupported()
+    override fun engineDeleteEntry(alias: String?) = unsupported()
+    override fun engineAliases(): Enumeration<String>? = unsupported()
+    override fun engineContainsAlias(alias: String?) = unsupported()
+    override fun engineSize() = unsupported()
+    override fun engineIsKeyEntry(alias: String?) = unsupported()
+    override fun engineIsCertificateEntry(alias: String?) = unsupported()
+    override fun engineGetCertificateAlias(cert: Certificate?): String? = unsupported()
+    override fun engineStore(stream: OutputStream?, password: CharArray?) = unsupported()
+    override fun engineLoad(stream: InputStream?, password: CharArray?) = unsupported()
 
     companion object {
         @Volatile internal var androidImpl: KeyStoreSpi? = null
     }
 }
+
+private fun unsupported(): Nothing {
+    logDebug("callKS unsupported", Exception())
+    throw UnsupportedOperationException()
+}

kdrag0n avatar Oct 05 '22 05:10 kdrag0n

I did actually look at this briefly in July but I was passing Play Integrity (excl. strong, of course) out-of-the-box with the last stable version of the module, so I couldn't test any attempted fixes. Testing setup was Pixel 6 + Android 13 Beta 3. Is there something I'm missing?

kdrag0n avatar Oct 05 '22 05:10 kdrag0n