talsec / Free-RASP-Flutter

Flutter library for improving app security and threat monitoring on Android and iOS mobile devices.
https://github.com/talsec/Free-RASP-Community
MIT License
192 stars 19 forks source link

The App uses the encryption mode CBC with PKCS5/PKCS7 padding with High Risk - MobSF #132

Open sed1ka opened 1 month ago

sed1ka commented 1 month ago

Describe the bug When my android apps implementing FreeRASP, the Mobile Security Platform (aka MobSF) giving a high risk result with "The App uses the encryption mode CBC with PKCS5/PKCS7 padding. This configuration is vulnerable to padding oracle attacks."

The MobSF also explaining about their result on this article

The code:

package t;
import android.hardware.biometrics.BiometricPrompt;
import android.os.Build;
import android.security.identity.IdentityCredential;
import android.security.keystore.KeyGenParameterSpec;
import android.util.Log;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Signature;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
/* loaded from: classes.dex */
abstract class d {
    /* loaded from: classes.dex */
    private static class a {
        static KeyGenParameterSpec a(KeyGenParameterSpec.Builder builder) {
            return builder.build();
        }
        static KeyGenParameterSpec.Builder b(String str, int i10) {
            return new KeyGenParameterSpec.Builder(str, i10);
        }
        static void c(KeyGenerator keyGenerator, KeyGenParameterSpec keyGenParameterSpec) {
            keyGenerator.init(keyGenParameterSpec);
        }
        static void d(KeyGenParameterSpec.Builder builder) {
            builder.setBlockModes("CBC");
        }
        static void e(KeyGenParameterSpec.Builder builder) {
            builder.setEncryptionPaddings("PKCS7Padding");
        }
    }
    /* loaded from: classes.dex */
    private static class b {
        static BiometricPrompt.CryptoObject a(Signature signature) {
            return new BiometricPrompt.CryptoObject(signature);
        }
        static BiometricPrompt.CryptoObject b(Cipher cipher) {
            return new BiometricPrompt.CryptoObject(cipher);
        }
        static BiometricPrompt.CryptoObject c(Mac mac) {
            return new BiometricPrompt.CryptoObject(mac);
        }
    }
    /* loaded from: classes.dex */
    private static class c {
        static BiometricPrompt.CryptoObject a(IdentityCredential identityCredential) {
            return new BiometricPrompt.CryptoObject(identityCredential);
        }
    }
    /* JADX INFO: Access modifiers changed from: package-private */
    public static t.c a() {
        try {
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            KeyGenParameterSpec.Builder b10 = a.b("androidxBiometric", 3);
            a.d(b10);
            a.e(b10);
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES", "AndroidKeyStore");
            a.c(keyGenerator, a.a(b10));
            keyGenerator.generateKey();
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");    /* The code suspect */
            cipher.init(1, (SecretKey) keyStore.getKey("androidxBiometric", null));
            return new t.c(cipher);
        } catch (IOException | InvalidAlgorithmParameterException | InvalidKeyException | KeyStoreException | NoSuchAlgorithmException | NoSuchProviderException | UnrecoverableKeyException | CertificateException | NoSuchPaddingException e10) {
            Log.w("CryptoObjectUtils", "Failed to create fake crypto object.", e10);
            return null;
        }
    }
    /* JADX INFO: Access modifiers changed from: package-private */
    public static BiometricPrompt.CryptoObject b(t.c cVar) {
        IdentityCredential b10;
        if (cVar == null) {
            return null;
        }
        Cipher a10 = cVar.a();
        if (a10 != null) {
            return b.b(a10);
        }
        Signature d10 = cVar.d();
        if (d10 != null) {
            return b.a(d10);
        }
        Mac c10 = cVar.c();
        if (c10 != null) {
            return b.c(c10);
        }
        if (Build.VERSION.SDK_INT < 30 || (b10 = cVar.b()) == null) {
            return null;
        }
        return c.a(b10);
    }
}

And I have another high risk issue when implementing with FreeRASP. The file or SharedPreference is World Writable. Any App can write to the file

The Code:

package n5;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.StrictMode;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/* loaded from: classes.dex */
public final class o7 implements r6 {
    /* renamed from: g  reason: collision with root package name */
    private static final Map f11471g = new w.a();
    /* renamed from: a  reason: collision with root package name */
    private final SharedPreferences f11472a;
    /* renamed from: b  reason: collision with root package name */
    private final Runnable f11473b;
    /* renamed from: c  reason: collision with root package name */
    private final SharedPreferences.OnSharedPreferenceChangeListener f11474c;
    /* renamed from: d  reason: collision with root package name */
    private final Object f11475d;
    /* renamed from: e  reason: collision with root package name */
    private volatile Map f11476e;
    /* renamed from: f  reason: collision with root package name */
    private final List f11477f;
    private o7(SharedPreferences sharedPreferences, Runnable runnable) {
        SharedPreferences.OnSharedPreferenceChangeListener onSharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() { // from class: n5.n7
            @Override // android.content.SharedPreferences.OnSharedPreferenceChangeListener
            public final void onSharedPreferenceChanged(SharedPreferences sharedPreferences2, String str) {
                o7.this.d(sharedPreferences2, str);
            }
        };
        this.f11474c = onSharedPreferenceChangeListener;
        this.f11475d = new Object();
        this.f11477f = new ArrayList();
        this.f11472a = sharedPreferences;
        this.f11473b = runnable;
        sharedPreferences.registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }
    private static SharedPreferences a(Context context, String str) {
        StrictMode.ThreadPolicy allowThreadDiskReads = StrictMode.allowThreadDiskReads();
        try {
            if (str.startsWith("direct_boot:")) {
                if (j6.a()) {
                    context = context.createDeviceProtectedStorageContext();
                }
                return context.getSharedPreferences(str.substring(12), 0);    /* The code suspect */
            }
            return context.getSharedPreferences(str, 0);
        } finally {
            StrictMode.setThreadPolicy(allowThreadDiskReads);
        }
    }
    /* JADX INFO: Access modifiers changed from: package-private */
    public static o7 b(Context context, String str, Runnable runnable) {
        o7 o7Var;
        if ((!j6.a() || str.startsWith("direct_boot:")) ? true : j6.c(context)) {
            synchronized (o7.class) {
                Map map = f11471g;
                o7Var = (o7) map.get(str);
                if (o7Var == null) {
                    o7Var = new o7(a(context, str), runnable);
                    map.put(str, o7Var);
                }
            }
            return o7Var;
        }
        return null;
    }
    /* JADX INFO: Access modifiers changed from: package-private */
    public static synchronized void c() {
        synchronized (o7.class) {
            for (o7 o7Var : f11471g.values()) {
                o7Var.f11472a.unregisterOnSharedPreferenceChangeListener(o7Var.f11474c);
            }
            f11471g.clear();
        }
    }
    /* JADX INFO: Access modifiers changed from: package-private */
    public final /* synthetic */ void d(SharedPreferences sharedPreferences, String str) {
        synchronized (this.f11475d) {
            this.f11476e = null;
            this.f11473b.run();
        }
        synchronized (this) {
            Iterator it = this.f11477f.iterator();
            if (it.hasNext()) {
                c.a.a(it.next());
                throw null;
            }
        }
    }
    @Override // n5.r6
    public final Object f(String str) {
        Map<String, ?> map = this.f11476e;
        if (map == null) {
            synchronized (this.f11475d) {
                map = this.f11476e;
                if (map == null) {
                    StrictMode.ThreadPolicy allowThreadDiskReads = StrictMode.allowThreadDiskReads();
                    Map<String, ?> all = this.f11472a.getAll();
                    this.f11476e = all;
                    StrictMode.setThreadPolicy(allowThreadDiskReads);
                    map = all;
                }
            }
        }
        if (map != null) {
            return map.get(str);
        }
        return null;
    }
}

Please complete the following information: OS: Android FreeRASP: 6.6.0 Flutter: 3.24.2

yardexx commented 1 month ago

Hello.

Thanks for raising the issue. We will take a closer look at it.

Kind regards, Jaroslav from Talsec Team