
io.joern.scanners.android.ExternalStorage.scala Maven / Gradle / Ivy
package io.joern.scanners.android
import io.joern.console.*
import io.joern.dataflowengineoss.language.*
import io.joern.dataflowengineoss.queryengine.EngineContext
import io.joern.dataflowengineoss.semanticsloader.Semantics
import io.joern.macros.QueryMacros.*
import io.joern.scanners.*
import io.shiftleft.semanticcpg.language.*
object ExternalStorage extends QueryBundle {
implicit val engineContext: EngineContext = EngineContext(Semantics.empty)
implicit val resolver: ICallResolver = NoResolve
// TODO: improve matching around external storage permissions
@q
def externalStorageToDexClassLoader()(implicit engineContext: EngineContext): Query =
Query.make(
name = "external-storage-to-dex-classloader",
author = Crew.claudiu,
title = "Data from external storage ends up in dex classloader, leading to code execution.",
description = "-",
score = 9,
withStrRep({ cpg =>
import io.joern.x2cpg.Defines.ConstructorMethodName
import io.shiftleft.semanticcpg.language.android.*
def externalStorageReads =
if (cpg.appManifest.hasReadExternalStoragePermission.nonEmpty)
cpg.getExternalStorageDir
else Iterator.empty
def dexClassLoadersWithExternalStorageInit =
cpg.dexClassLoader
.where(
_.method.call
.nameExact(ConstructorMethodName)
.where(_.argument(0).isIdentifier.typeFullNameExact("dalvik.system.DexClassLoader"))
.where(_.argument(1).reachableBy(externalStorageReads))
)
def loadClassCalls =
dexClassLoadersWithExternalStorageInit.referencingIdentifiers.inCall.nameExact("loadClass")
def reflectInvoke = cpg.call.methodFullNameExact(
"java.lang.reflect.Method.invoke:java.lang.Object(java.lang.Object,java.lang.Object[])"
)
reflectInvoke.where(_.argument(1).reachableBy(loadClassCalls))
}),
tags = List(QueryTags.android),
multiFileCodeExamples = MultiFileCodeExamples(
positive = List(
List(
CodeSnippet(
"""|package io.vroooom.vulnerableapp;
|
|import android.Manifest;
|import android.content.pm.PackageManager;
|import android.os.Bundle;
|import android.os.Environment;
|import android.support.v4.app.ActivityCompat;
|import android.support.v4.content.ContextCompat;
|import android.support.v7.app.AppCompatActivity;
|import android.util.Log;
|
|import java.io.File;
|import java.lang.reflect.Method;
|
|import dalvik.system.DexClassLoader;
|
|public class DexClassLoaderActivity extends AppCompatActivity {
|
| @Override
| protected void onCreate(Bundle savedInstanceState) {
| super.onCreate(savedInstanceState);
| setContentView(R.layout.activity_main);
|
| if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
| != PackageManager.PERMISSION_GRANTED) {
| ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.READ_EXTERNAL_STORAGE }, 1234);
| } else {
| String externalStorageRoot = Environment.getExternalStorageDirectory().toString();
| listFiles(externalStorageRoot);
|
| String pathToDex = externalStorageRoot + "/Beep.zip";
| loadDexFromPath(pathToDex);
| }
| }
|
| private void listFiles(String path) {
| Log.d("Files", "Path: " + path);
| File directory = new File(path);
| File[] files = directory.listFiles();
| Log.d("Files", "Size: "+ files.length);
| for (int i = 0; i < files.length; i++) {
| Log.d("Files", "FileName:" + files[i].getName());
| }
| }
|
| private void loadDexFromPath(String path) {
| try {
| File tmpDir = getDir("dex", 0);
|
| DexClassLoader classloader = new DexClassLoader(path, tmpDir.getAbsolutePath(), null, this.getClass().getClassLoader());
| final Class
© 2015 - 2025 Weber Informatics LLC | Privacy Policy