CCS’14 – Securing SSL Certificate Verification through Dynamic Linking

Our paper ‘Securing SSL Certificate Verification through Dynamic Linking‘ is ready for download from CCS’14. This post gives a brief introduction of main idea of this paper – certShim, and then concentrates on bytecode instrumenting in JVM to fix some security issues mentioned in the TMDC paper ‘The most dangerous code in the world‘. Happy hacking!

0. certShim

The TMDC paper has revealed some crucial breakage of the SSL certificate verification procedure because of the badly designed SSL libraries. To conquer these issues, the solution of certShim is dynamic linking, simple yet powerful. Under the certShim environment, when the SSL library entry function is called, instead of falling into the original SSL library implementation, the code flow will be redirected to the certShim SSL implementation, which is also built upon the original SSL libraries but provides the ability to enforce the correct SSL certification verification procedure even the application code fails to do so. For sure, there are more stuffs in certShim. Please check the paper.

1. Java

certShim uses dynamic linking, which means it only works for C/C++ SSL implementations, such as OpenSSL/GnuTLS. The other big part of applications is Java and we also want to support it. Section 3.5 Java Instrumentation of the paper gives a solutions. First, we do not want to change the application code; second, we do not want to change the JDK code as well, which contains the default SSL implementation. Unfortunately, there is no such a thing in Java called dynamic linking. Then the solution is straightforward – bytecode instrumenting.

2. Bytecode Instrumentation

Thanks to the powerful JVM interface, there is a JVM option which is used to do the bytecode injection for the running classes – Java agent (http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html). Then another problem comes along – we do not want to write bytecode. So what? Luckily, we have got another powerful tool called Javassist (http://www.javassist.org/), which is used to translate the Java code into the bytecode. Note that we do not provide details on how to play with Java agent or Javassist. Instead, please check the csa (certShimAgent) source code below.

3. Bug & Fix

The TMDC paper shows an issue where SSL hostname verification is ignored if SSLSocketFactory is used to create a SSL socket because this method leaves ‘algorithm’ parameter NULL used by hostname verification functions. In OpenJDK 6, this function is checkIdentity(); in OpenJDK 7, the functions are checkTrusted() and checkIdentity(). Then our fix is clear. Reset the ‘algorithm’ parameter if null before the JVM runs into the checkX() function. Even if SSLSocketFactory is called in the application code, we do not need to worry as the hostname is guaranteed anyway. For implementations details, please check csa code repo.

4. Test

For sure, we could write a simple Java app calling SSLSocketFactory and connecting to a website with a bad hostname. But my personal favorite would be hacking the OpenJDK, printing the ‘algorithm’ parameter before checkX() and printing it again within the checkX(). There is a simple OpenJDK hack in the following section.

5. Done?

We have talked about the certShim paper and the Java instrumentation mentioned in the paper. Are we done? Apparently, no. There are still a lot of things on going in the SENSEI lab. I am sure I will post sth cooler in the near future.

6. Code

certShimhttps://bitbucket.org/uf_sensei/cert-shim
certShimAgenthttps://github.com/daveti/csa

7. OpenJDK Hack Howto (by daveti)

1. Download the OpenJDK source (OpenJDK6)
https://java.net/projects/openjdk6/downloads/
1.1 OpenJDK7
http://openjdk.java.net/projects/jdk7u/
hg clone http://hg.openjdk.java.net/jdk7u/jdk7u60/
cd jdk7u60
chmod +x ./get_source.sh
./get_source.sh

2. Hack (Sun SSL Implementation)
jdk/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java

3. Build (Ubuntu 14.04 LTS x86_64)
sudo aptitude build-dep openjdk-6
sudo aptitude install openjdk-6-jdk gcc-4.8 g++-4.8
sudo aptitude install libmotif-dev
export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-6-openjdk-amd64
make all CC=gcc-4.8 CPP=g++-4.8

4. Install
The whole SDK suite could be found at
build/linux-amd64/j2sdk-image
The whole JRE suite could found at
build/linux-amd64/j2re-image

5. Test
build/linux-amd64/j2sdk-image/bin/java -version
build/linux-amd64/j2sdk-image/bin/javac Hello.java
build/linux-amd64/j2sdk-image/bin/java Hello

root@daveti-virtual-machine:~/java# /root/openjdk6_hack/build/linux-amd64/j2sdk-image/bin/java -version
openjdk version “1.6.0-internal”
OpenJDK Runtime Environment (build 1.6.0-internal-root_07_may_2014_21_37-b00)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)

6. SSL Test
Update CA certs to avoid – Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
Under build/linux-amd64/j2sdk-image/jre/lib/security/
mv cacerts cacerts.orig
ln -s /etc/ssl/certs/java/cacerts cacerts

root@daveti-virtual-machine:~/java# /root/openjdk6_hack/build/linux-amd64/j2sdk-image/bin/java SSLSocketClient
getCipherSuites(): [Ljava.lang.String;@eee2024
getNeedClientAuth(): false
getProtocols(): [Ljava.lang.String;@33802324
getWantClientAuth(): false

daveti: algorithm = null
HTTP/1.1 200 OK
7. Java Agent (Needs Javassit)
git clone https://github.com/jboss-javassist/javassist
cp javassist/javassist.jar build/linux-amd64/j2sdk-image/jre/lib/ext

root@daveti-virtual-machine:~/java/org/davejingtian/certshim/agent# /root/openjdk6_hack/build/linux-amd64/j2sdk-image/bin/javac -cp ../lib/javassist.jar Agent.java
warning: ../lib/javassist.jar(javassist/CannotCompileException.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
warning: ../lib/javassist.jar(javassist/ClassPool.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
warning: ../lib/javassist.jar(javassist/CtClass.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
warning: ../lib/javassist.jar(javassist/CtMethod.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
warning: ../lib/javassist.jar(javassist/LoaderClassPath.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
warning: ../lib/javassist.jar(javassist/NotFoundException.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
warning: ../lib/javassist.jar(javassist/ClassPath.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
warning: ../lib/javassist.jar(javassist/CtBehavior.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
warning: ../lib/javassist.jar(javassist/CtMember.class): major version 51 is newer than 50, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
9 warnings

ROOT CAUSE: javassist lib is compiled using JDK 7, which has major version 51. We are using JDK 6 for the compiling which has major version 50.
FIX: Build javassist lib using JDK 6 again.
THEN: cp the new javassist.jar into j2sdk/jre/lib/ext

root@daveti-virtual-machine:~/git/javassist# echo $JAVA_HOME

root@daveti-virtual-machine:~/git/javassist# export JAVA_HOME=/root/openjdk6_hack/build/linux-amd64/j2sdk-image
root@daveti-virtual-machine:~/git/javassist# echo $JAVA_HOME
/root/openjdk6_hack/build/linux-amd64/j2sdk-image
root@daveti-virtual-machine:~/git/javassist# ll
total 808
drwxr-xr-x 8 root root 4096 May 8 13:15 ./
drwxr-xr-x 3 root root 4096 May 7 23:38 ../
-rw-r–r– 1 root root 10677 May 8 13:15 build.xml
drwxr-xr-x 8 root root 4096 May 7 23:39 .git/
-rw-r–r– 1 root root 103 May 7 23:39 .gitignore
-rw-r–r– 1 root root 707490 May 7 23:39 javassist.jar.orig
-rw-r–r– 1 root root 25890 May 7 23:39 License.html
-rw-r–r– 1 root root 9526 May 7 23:39 pom.xml
-rw-r–r– 1 root root 26631 May 7 23:39 Readme.html
drwxr-xr-x 2 root root 4096 May 8 13:12 runtest/
drwxr-xr-x 9 root root 4096 May 7 23:39 sample/
drwxr-xr-x 4 root root 4096 May 7 23:39 src/
drwxr-xr-x 5 root root 4096 May 8 13:12 target/
drwxr-xr-x 2 root root 4096 May 7 23:39 tutorial/
root@daveti-virtual-machine:~/git/javassist# ant
Buildfile: /root/git/javassist/build.xml

prepare:

compile14:
[javac] /root/git/javassist/build.xml:80: warning: ‘includeantruntime’ was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
[javac] Compiling 212 source files to /root/git/javassist/target/classes

jar:
[jar] Building jar: /root/git/javassist/javassist.jar
[jar] Building jar: /root/git/javassist/javassist-src.jar

BUILD SUCCESSFUL
Total time: 4 seconds
root@daveti-virtual-machine:~/git/javassist# ll
total 1976
drwxr-xr-x 8 root root 4096 May 8 13:16 ./
drwxr-xr-x 3 root root 4096 May 7 23:38 ../
-rw-r–r– 1 root root 10677 May 8 13:15 build.xml
drwxr-xr-x 8 root root 4096 May 7 23:39 .git/
-rw-r–r– 1 root root 103 May 7 23:39 .gitignore
-rw-r–r– 1 root root 677599 May 8 13:16 javassist.jar
-rw-r–r– 1 root root 707490 May 7 23:39 javassist.jar.orig
-rw-r–r– 1 root root 513625 May 8 13:16 javassist-src.jar
-rw-r–r– 1 root root 25890 May 7 23:39 License.html
-rw-r–r– 1 root root 9526 May 7 23:39 pom.xml
-rw-r–r– 1 root root 26631 May 7 23:39 Readme.html
drwxr-xr-x 2 root root 4096 May 8 13:12 runtest/
drwxr-xr-x 9 root root 4096 May 7 23:39 sample/
drwxr-xr-x 4 root root 4096 May 7 23:39 src/
drwxr-xr-x 5 root root 4096 May 8 13:12 target/
drwxr-xr-x 2 root root 4096 May 7 23:39 tutorial/
root@daveti-virtual-machine:~/git/javassist# cp ./javassist.jar /root/openjdk6_hack/build/linux-amd64/j2sdk-image/jre/lib/ext
root@daveti-virtual-machine:~/git/javassist# cp ./javassist.jar /root/java/org/davejingtian/certshim/lib
root@daveti-virtual-machine:~/git/javassist#

root@daveti-virtual-machine:~/java/org/davejingtian/certshim/agent# /root/openjdk6_hack/build/linux-amd64/j2sdk-image/bin/javac Agent.java

root@daveti-virtual-machine:~/java# /root/openjdk6_hack/build/linux-amd64/j2sdk-image/bin/jar cmf ./manifest.txt certShimAgent.jar ./org/*

root@daveti-virtual-machine:~/java# /root/openjdk6_hack/build/linux-amd64/j2sdk-image/bin/java -javaagent:certShimAgent.jar SSLSocketClient
daveti: Agent starts!

About daveti

Interested in kernel hacking, compilers, machine learning and guitars.
This entry was posted in Security and tagged , , , , , , , , . Bookmark the permalink.

1 Response to CCS’14 – Securing SSL Certificate Verification through Dynamic Linking

  1. tbaby says:

    niu bai

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.