How to detect OpenSSL v3.0 and Heartbleed vulnerabilities in mobile apps

On 25 Oct 2022, OpenSSL began pre-notifying organizations of two critical vulnerabilities in OpenSSL 3.0.x. On the positive side, OpenSSL 3.0 had not been widely deployed and on 1 Nov 2022, the two vulnerabilities were downgraded to a high. However, on the heels of recent highly impactful vulnerabilities like Log4j and the devastating impacts of the OpenSSL “Heartbleed” vulnerability from 2014, defenders went on high alert.

Popular mobile apps with OpenSSL

With the recent tutorials I’ve been sharing on Software Bill of Materials, I decided to take a look at 3,845 very popular mobile apps to see if I could determine if an app contained a direct or transient OpenSSL dependency and if so, was that version vulnerable.

What I discovered was troubling not because of the recent 3.0.x vulnerabilities just announced. Instead, I found 1,529 instances of OpenSSL across 608 apps (~16%) with the following issues:

  • 98% of OpenSSL versions in popular mobile apps have publicly disclosed vulnerabilities
  • 86% of the vulnerable versions have a severity of High
  • 30% are of OpenSSL versions in popular mobile apps are fully unsupported
  • 57% are either unsupported or require premium support (1.0.2 branch)

In general, OpenSSL is included in mobile apps via 3rd party SDKs (transient dependencies). I’ve included the top 25 most common below for reference but SQLCipher is the top source.

Android apps represent roughly 90% of popular mobile apps with OpenSSL present with iOS hovering around 10%.

It’s also interesting to look at the impacted mobile apps by industry vertical:

IndustryInstancesPercentage
Finance27818.2%
Healthcare24716.2%
HiTech20513.4%
Automotive20413.3%
Retail16710.9%
Pharma1298.4%
Parking1157.5%
Energy754.9%
Social473.1%
Travel332.2%
FinTech261.7%
Airline30.2%

How to detect OpenSSL in your mobile app

There are two primary categories of mobile apps you should consider checking:

  1. Apps you build
  2. Apps you use

The good news is the team at NowSecure (full disclosure: I’m a co-founder) can help you answer both questions. As you can tell from the data above, we continuously scan mobile apps and leverage binary analysis to generate a SBOM for every mobile app. So if you are an enterprise and worried about your software supply chain, you can Contact Us and we can run large volume vulnerability exposure analysis (we have millions of assessments in our database).

However, I’d like to quickly demonstrate how you can detect OpenSSL in a specific mobile app with NowSecure’s binary analysis. If you’d like to do this on your own, you can sign up for 10 free SBOMs and access the results in from NowSecure Platform UI, REST API or via our Mobile SBOM GitHub Action.

I’ve already largely documented the steps in a previous post for how to generate an Android (React Native) SBOM in CycloneDX format but I’m going to generalize the steps here as we support both Android and iOS mobile apps.

Build your mobile app

Since we operate on mobile app binaries, the first thing you need is the binary itself! NowSecure Platform can automatically pull the latest version of the mobile app from the Apple App or Google Play Stores so if you are not a developer or don’t have access to the mobile app source code, we can still test the app.

As a quick example for an Android developer, you could build a release (preferred) or debug version of your app, e.g.

$ ./gradlew assembleDebug

Once you have the binary (located in the app/build/outputs/apk/debug/ folder for this example):

$ ls -lh app/build/outputs/apk/debug/
total 165856
-rw-r--r--  1 hiro  staff    66M Sep 12 09:50 app-debug.apk
-rw-r--r--  1 hiro  staff   325B Sep 12 09:50 output-metadata.json

you can then upload it to NowSecure Platform via our web UI or below via command line.

Upload to NowSecure

You need to first sign up for 10 free SBOMs if you’d like to follow these steps.

I’m not going to detail the sign up process but after you have an account, you can create a JWT token you then use for API access.

From there, you can kick off an assessment command line with the following steps (note: the group uuid is specific to an account and a group so you will need to grab that from the web UI or API as well):

$ export API_TOKEN=<your token here>

$ curl -H "Authorization: Bearer ${API_TOKEN}" -X POST https://lab-api.nowsecure.com/build/?group=ad2c4c53-7fbf-4f81-8170-ee9b97a1ea5c --data-binary @app/build/outputs/apk/debug/app-debug.apk

{
  "ref": "884a9f76-2f94-11ed-8006-bf3e96875a84",
  "application": "b8d29eca-2552-11ec-802b-0706d3896177",
  "group": "ad2c4c53-7fbf-4f81-8170-ee9b97a1ea5c",
  "account": "<snip>",
  "platform": "android",
  "package": "net.cozic.joplin",
  "task": 1662996718029,
  "creator": "<snip>",
  "created": "2022-09-12T15:31:58.179Z",
  "favorite": false,
  "binary": "8d1f8023da6900e6b937323a73c77dd8ed2f3bb2a010ec054d7c1787bf557b54",
  "config": { <snip> },
  "status": {
    "static": {
      "state": "pending"
    },
    "dynamic": {
      "state": "pending"
    }
  },
  "cancelled": false,
  "task_status": "pending",
  "events": {
    "dynamic": []
  }
}

After the scan is complete, you can use the assessment reference (884a9f76-2f94-11ed-8006-bf3e96875a84 in this example) to pull the results.

Pull CycloneDX from REST API

NowSecure provides a REST API to transform the binary component analysis into CycloneDX format:

$ curl -H "Authorization: Bearer ${API_TOKEN}" https://api.nowsecure.com/assessment/884a9f76-2f94-11ed-8006-bf3e96875a84/cyclonedx/ > joplin-bom.xml

and here’s a snippet of the results:

<?xml version="1.0"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1">
  <metadata>
    <timestamp>2022-09-08T16:52:40.226Z</timestamp>
    <tools>
      <tool>
        <vendor>NowSecure</vendor>
        <name>Platform</name>
      </tool>
    </tools>
    <component type="application" bom-ref="net.cozic.joplin@2.9.2">
      <name>Joplin</name>
      <version>2.9.2</version>
    </component>
  </metadata>
  <components>
    <component type="library">
      <name>OpenSSL</name>
      <version>1.1.0h</version>
      <description>/lib/x86_64/libflipper.so</description>
      <purl>pkg:generic/openssl@1.1.0h</purl>
    </component>
</bom>

As you can see from the above example (a debug version, not production!), binary analysis was able to identify transitive versions of OpenSSL that source code analysis missed. For the above snipper, OpenSSL v1.1.0h was included as a dependency in Flipper and it has 8 known vulnerabilities including CVE-2018-0732 (7.5) and CVE-2019-1543 (7.4)

If you wanted to use grep to quickly search for OpenSSL components, you can use this command:

$ curl -s -H "Authorization: Bearer ${API_TOKEN}" https://api.nowsecure.com/assessment/5c46b91e-4b28-11ed-8006-a7b57d5286eb/cyclonedx/ | grep -i openssl
      <name>OpenSSL</name>
      <purl>pkg:generic/OpenSSL@1.1.0h</purl>
      <name>OpenSSL</name>
      <purl>pkg:generic/OpenSSL@1.1.0h</purl>
      <name>OpenSSL</name>
      <purl>pkg:generic/OpenSSL@1.1.0h</purl>
      <name>OpenSSL</name>
      <purl>pkg:generic/OpenSSL@1.1.0h</purl>

OpenSSL data

Given the frequency and severity of vulnerable versions of OpenSSL found in popular mobile apps, I am not going to release the raw data at this time. However, below are queries I ran for basic analysis and omit the specific mobile apps.

Highest impacted industries:

sqlite> select industry, count(component) as instances from openssl group by industry order by instances desc;
Finance|278
Healthcare|247
HiTech|205
Automotive|204
Retail|167
Pharma|129
Parking|115
Energy|75
Social|47
Travel|33
FinTech|26
Airline|3

OpenSSL versions identified

Obviously some incorrect data in here and binary analysis was not able to determine the OpenSSL version in 267 instances:

sqlite> select version, count(version) as instances from openssl group by version order by instances desc;
undefined,267
1.1.0g,167
1.0.2k,144
1.1.0c,99
1.1.1b,87
1.1.1g,85
1.1.1l,68
1.1.1j,65
1.1.1d,58
1.1.1e,48
1.1.1h,43
1.1.0,42
1.0.2s,40
1.0.2n,32
1.0.2t,31
1.0.2g,29
1.1.1,24
1.1.0h,24
1.1.1q,15
1.1.1k,15
1.0.1t,14
1.0.2o,13
1.1.1n,12
0.9.8z,12
1.1.1m,10
1.0.2l,8
1.0.2r,7
1.0.2q,7
1.0.2j,7
1.0.2h,7
1.0.1p,6
4270.3,4
1.1.1f,4
1.1.180,3
1.0.1l,3
1.1.1c,2
1.1.0b,2
1.0.2e,2
1.0.1s,2
1.0.1r,2
1.0,2
8.0,1
4.9,1
3.5.0,1
2.7.0,1
2.4.2,1
2.1.2,1
2.1,1
10.0.450,1
1.5.0,1
1.2.4,1
1.1.1i,1
1.1.1a,1
1.1.0j,1
1.1.0f,1
1.0.2p,1
1.0.1m,1
0.0.7,1

OpenSSL components

sqlite> select component, count(component) as instances from openssl group by component order by instances desc;
OpenSSL,1303
openssl_grpc,78
org.bouncycastle.openssl,57
org.spongycastle.openssl,38
openssl,20
libopenSSL.so,10
org.spongycastle.openssl.jcajce,6
libopenSSL,6
org.spongycastle.openssl.bc,4
libOpenSSL,2
org.bouncycastle.openssl.jcajce,1
org.bouncycastle.openssl.bc,1
libopenssl_fips.so,1
fipsOpenSSL,1
com.safenet.openssl,1

Top 40 “SDKs”

When we detect dependencies via binary analysis, we can often attribute it to specific SDKs, libraries and/or included frameworks. Mobile app developers can also include OpenSSL directly into their app but in general we find that developers are avoiding low-level crypto and instead relying on third party implementations:

sqlite> select source, count(component) as instances from openssl group by source order by instances desc limit 50;
lib/arm64-v8a/libsqlcipher.so|84
lib/armeabi-v7a/libsqlcipher.so|57
lib/x86_64/libsqlcipher.so|52
lib/x86/libsqlcipher.so|52
/lib/arm64-v8a/libsqlcipher.so|52
/lib/armeabi-v7a/libsqlcipher.so|51
/lib/x86_64/libsqlcipher.so|50
/lib/x86/libsqlcipher.so|50
lib/armeabi/libsqlcipher.so|26
/config.arm64_v8a.apklib/arm64-v8a/libsqlcipher.so|26
lib/arm64-v8a/libopenSSL.so|20
/config.arm64_v8a.apklib/arm64-v8a/libopenSSL.so|20
/lib/armeabi/libsqlcipher.so|19
/base.apkclasses3.dex|19
lib/arm64-v8a/librealm-jni.so|18
classes3.dex|18
classes2.dex|18
lib/arm64-v8a/libzData.so|15
lib/arm64-v8a/libssl_sb.so|15
lib/arm64-v8a/libcrypto_sb.so|15
lib/x86_64/librealm-jni.so|13
lib/x86/librealm-jni.so|13
lib/armeabi-v7a/librealm-jni.so|13
classes.dex|12
/config.arm64_v8a.apklib/arm64-v8a/librealm-jni.so|12
lib/mips/librealm-jni.so|11
/lib/x86_64/librealm-jni.so|8
/lib/x86/librealm-jni.so|8
/lib/armeabi-v7a/librealm-jni.so|8
/lib/arm64-v8a/librealm-jni.so|8
/classes3.dex|8
/Payload/Thrive.app/Frameworks/openssl_grpc.framework/Info.plist|8
/lib/mips/librealm-jni.so|7
/config.arm64_v8a.apklib/arm64-v8a/libssl_sb.so|7
/config.arm64_v8a.apklib/arm64-v8a/libcrypto_sb.so|7
lib/arm64-v8a/libssl_here.so|6
lib/arm64-v8a/libepos2.so|6
lib/arm64-v8a/libcrypto_here.so|6
/lib/armeabi-v7a/libD3fAndroid.so|6
/lib/arm64-v8a/libD3fAndroid.so|6
/config.arm64_v8a.apklib/arm64-v8a/libnode.so|6
/base.apkclasses2.dex|6
/Payload/Revolut.app/Frameworks/OpenSSL.framework/Info.plist|6
/Payload/Bolt.app/Frameworks/openssl.framework/Info.plist|6
lib/x86_64/libepos2.so|5
lib/armeabi/libepos2.so|5
lib/armeabi-v7a/libepos2.so|5
/lib/arm64-v8a/libssl_1_1.so|5
/lib/arm64-v8a/libcrypto_1_1.so|5
/config.arm64_v8a.apklib/arm64-v8a/libzData.so|5
sqlite> select source, count(component) as instances from openssl group by source order by instances desc limit 25;
lib/arm64-v8a/libsqlcipher.so|84
lib/armeabi-v7a/libsqlcipher.so|57
lib/x86_64/libsqlcipher.so|52
lib/x86/libsqlcipher.so|52
/lib/arm64-v8a/libsqlcipher.so|52
/lib/armeabi-v7a/libsqlcipher.so|51
/lib/x86_64/libsqlcipher.so|50
/lib/x86/libsqlcipher.so|50
lib/armeabi/libsqlcipher.so|26
/config.arm64_v8a.apklib/arm64-v8a/libsqlcipher.so|26
lib/arm64-v8a/libopenSSL.so|20
/config.arm64_v8a.apklib/arm64-v8a/libopenSSL.so|20
/lib/armeabi/libsqlcipher.so|19
/base.apkclasses3.dex|19
lib/arm64-v8a/librealm-jni.so|18
classes3.dex|18
classes2.dex|18
lib/arm64-v8a/libzData.so|15
lib/arm64-v8a/libssl_sb.so|15
lib/arm64-v8a/libcrypto_sb.so|15
lib/x86_64/librealm-jni.so|13
lib/x86/librealm-jni.so|13
lib/armeabi-v7a/librealm-jni.so|13
classes.dex|12
/config.arm64_v8a.apklib/arm64-v8a/librealm-jni.so|12

OpenSSL by mobile operating system

Here’s the breakdown between OpenSSL versions in popular mobile apps by OS version:

sqlite> select os, count(component) as instances from openssl group by os order by instances desc;
android|1369
ios|160