oss-sec mailing list archives

Re: PoC for fdroidserver AllowedAPKSigningKeys certificate pinning bypass


From: Jeffrey Walton <noloader () gmail com>
Date: Sat, 20 Apr 2024 19:38:26 -0400

On Mon, Apr 8, 2024 at 3:15 PM Fay Stegerman <flx () obfusk net> wrote:

Hi!

This is published here: https://github.com/obfusk/fdroid-fakesigner-poc.

I've attached the PoC and patch and included the text from the README
below.

- Fay


============================================================================

# F-Droid Fake Signer PoC

PoC for fdroidserver AllowedAPKSigningKeys certificate pinning bypass.

## Background

We started looking into Android APK Signing Block oddities at the request
of
F-Droid [1] on 2021-08-25; we opened F-Droid issue "APK Signing Block
considerations" [2] on 2022-10-19.  No action was taken as a result.

We published the "Android APK Signing Block Payload PoC" [3] to the
Reproducible Builds mailing list [4] on 2023-01-31.

But the Android APK Signature Scheme v2/v3 actually allows embedding
arbitrary data (or code) in the signing block, meaning that two APKs with
the exact same valid signature -- though not a bit-by-bit identical
signing block -- can behave differently.

Jason Donenfeld reported "Potential security hazard:
apk_signer_fingerprint() looks at certs in reverse order that Android
checks
them" [5] on 2023-05-05; no action was taken to fix this bug.

However, there's a discrepancy between how these certificates are
extracted and how Android actually implements signature checks. [...]
Notice how [the google flowchart [6]] checks v3, then v2, and then v1.
Yet the [F-Droid] code above looks at v1, then v2, and then v3, in
reverse
order. So v1 could have a bogus signer that some versions of Android
never
even look at, yet fdroid makes a security decision based on it. Yikes!
Also, it's worth noting that apk_signer_fingerprint() also does not
bother
validating that the signatures are correct.

Andreas Itzchak Rehberg (IzzyOnDroid) reported about "BLOBs in APK signing
blocks" in "Ramping up security: additional APK checks are in place with
the
IzzyOnDroid repo" [7] on 2024-03-25.  The accompanying German article
"Android-Apps auf dem Seziertisch: Eine vertiefte Betrachtung" [8] points
out that we noticed that that apksigner and androguard handle duplicate
signing blocks rather differently: the former only sees the first, the
latter only the last, which allows all kinds of shenanigans.

## Observations

We observed that embedding a v1 (JAR) signature file in an APK with minSdk
= 24 will be ignored by Android/apksigner, which only checks v2/v3 in that
case.  However, since fdroidserver checks v1 first, regardless of minSdk,
and does not verify the signature, it will accept a "fake" certificate and
see an incorrect certificate fingerprint.

We also realised that the above mentioned discrepancy between apksigner and
androguard (which fdroidserver uses to extract the v2/v3 certificates) can
be abused here as well.  Simply copying the v2/v3 signature from a
different
APK and appending it to the APK Signing Block will not affect apksigner's
verification, but androguard, and thus also fdroidserver, will see only the
second block.  Again, the signature is not verified, a "fake" certificate
accepted, and an incorrect fingerprint seen.

As a result, it is trivial to bypass the AllowedAPKSigningKeys certificate
pinning, as we can make fdroidserver see whatever certificate we want
instead of the one Android/apksigner does.  Note that we don't need a valid
signature for the APK (we really only need a copy of the DER certificate,
though having another APK signed with the certificate we want to use makes
things easy).

## PoC

NB: you currently need the signing branch of apksigtool [9].

NB: the "fake" signer shown here is from the official F-Droid client (its
APK has a v1+v2+v3 signature), the one apksigner sees is randomly generated
by make-key.sh; the app.apk used for testing had minSdk 26 and a v2
signature only.  Using APKs with other signature scheme combinations is
certainly possible, but might require adjusting the PoC code accordingly.

```
$ ./make-key.sh             # generates a dummy key
$ python3 make-poc-v1.py    # uses app.apk (needs minSdk >= 24) as base,
adds fake.apk .RSA
$ python3 fdroid.py         # verifies and has fake.apk as signer
according to F-Droid
True
43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab
$ python3 make-poc-v2.py    # uses app.apk as base, adds signing block
from fake.apk
$ python3 fdroid.py         # verifies and has fake.apk as signer
according to F-Droid
True
43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab
$ apksigner verify -v --print-certs poc.apk | grep -E '^Verified
using|Signer #1 certificate (DN|SHA-256)'
Verified using v1 scheme (JAR signing): false
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): true
Verified using v4 scheme (APK Signature Scheme v4): false
Signer #1 certificate DN: CN=oops
Signer #1 certificate SHA-256 digest:
029df1354735e81eb97c9bbef2185c8ead3bc78ae874c03a6e96e1e1435ac519
```

```
$ mkdir fakesigner
$ cd fakesigner
$ fdroid init -d oops --repo-keyalias fakesigner
$ mkdir metadata
$ printf 'Name: MyApp\nAllowedAPKSigningKeys:
43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab\n' >
metadata/some.app.id.yml
$ cp /path/to/poc.apk repo/
$ fdroid update
$ jq '.packages[].versions[].manifest.signer.sha256' < repo/index-v2.json
[
  "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
```

## Patch

The fdroidserver.patch changes the order so it matches Android's v3 before
v2 before v1, and monkey-patches androguard to see the first block instead
of the last one if there are duplicates.  This is still likely to be
incomplete, but prevents the known bypasses described here.

## References

* [1] https://salsa.debian.org/reproducible-builds/diffoscope/-/issues/246
* [2] https://gitlab.com/fdroid/fdroidserver/-/issues/1056
* [3] https://github.com/obfusk/sigblock-code-poc
* [4]
https://lists.reproducible-builds.org/pipermail/rb-general/2023-January/002825.html
* [5] https://gitlab.com/fdroid/fdroidserver/-/issues/1128
* [6] https://source.android.com/docs/security/features/apksigning/v3
* [7] https://android.izzysoft.de/articles/named/iod-scan-apkchecks
* [8]
https://www.kuketz-blog.de/android-apps-auf-dem-seziertisch-eine-vertiefte-betrachtung/
* [9] https://github.com/obfusk/apksigtool

## Links

* https://github.com/obfusk/apksigcopier


ASOP has been aware their APK signing lacked semantic authentication for
decades. This is from the defunct and now removed android-security-discuss
Google Group. It is a reply of mine on a thread the discusses APK signing
from 2012:

You should also look at the threat model. [Partially] signed APKs only
provide the ability to update a previously published APK. The APK can
be updated *IFF* it was previously published under the same signing
key. In essence, the threat here is the bad guy will be able to
provide an update to a good guy's code (which can be farily
troublesome). Due to the signing model and process, there is no
effective identity assurances for the users of the APK. So we will
never really know who the good guy or bad guy is/was.

I say "partially signed" because the signing process violates Schneier
and Wagner's semantic authentication
(http://www.schneier.com/paper-ssl.html). Confer: one signs an APK,
then zip aligns the APK. Will anyone be surprised when Apple and
Android code signing fails in the field like
http://www.kb.cert.org/vuls/id/845620
<http://www.kb.cert.org/vuls/id/845620>? Or perhaps un-signed data will
be used/consumed by an application?

A year later, the Bluebox "Master Key" exploit was released <
https://www.esecurityplanet.com/mobile/inside-the-bluebox-android-master-key-vulnerability/>.
That was quickly followed by another "Master Key" exploit, <
http://www.androidpolice.com/2013/07/11/second-all-access-apk-exploit-is-revealed-just-two-days-after-master-key-goes-public-already-patched-by-google/
.

And in 2024, we're again reading about more problems. (Your disclosure).

Android signing will continue to be a problem until signing achieves the
level of semantic authentication as discussed by Wagner and Schneier back
in 1996, <https://www.schneier.com/wp-content/uploads/2016/02/paper-ssl.pdf
.

Jeff

Current thread: