MITMing an SSLized Java App
Dave G. | May 1st, 2007 | Filed Under: Bitching About Protocols, Reversing
I was recently working on a Java-based application that communicated exclusively over SSL. This is a good thing for the application, but a bad thing for someone trying to test it. I naively thought that I could edit a couple of files and boom, be on my way. Alas, what follows is what I had to do to get in between and start understanding the application:
My initial take was that I would use two instances of stunnel (I use 3.x because I am old, crusty, and like the simplicity of the 3.x command line interface), with Blackbag’s replug in between so I can view the traffic.
So, here is my simple setup (monitoring a connection to www.amazon.com as an example):

All I do is test it with another instance of stunnel and we see that traffic is passing through our rat’s nest of proxying.
Of course, the first wrinkle is that I need to actually test from Windows.
So we load up Parallels and get the application pointing at our
tunnels. Easiest way to do this is to just edit the hosts file, located
at \WINDOWS\System32\Drivers\etc. Looks just like /etc/hosts, so we just add:
Which should work as long as IP addresses aren’t hardcoded into the application. Thankfully, they weren’t. Now I just run the app, and everything works.
Except that it doesn’t work at all. Turns out that the JVM does certificate validation. When web browsers encounter certificate problems, they let the user decide if they want to continue to connect. When just about any other kind of application encounters validation problems, they will just fail.
There are two basic validation steps it will perform:
Valid Certificate: Is this signed by someone that we trust (e.g. Verisign)?
Hostname: Does the hostname inside of the certificate match the hostname we are trying to connect?
This is where I feel like I must have missed something. I can’t find anywhere inside of the Java documentation where I can disable this using JVM configuration files. After poking around for a bit, and using google, I see two options.
- Install a new certificate into the instance of Java I am using
- Decompile, edit and recompile (you can turn off certificate validation programmatically)
So, I go with Option #1. I start by generating a new certificate using the stunnel Makefile (you can just use OpenSSL):

The most important parameter you are setting is the Common Name. It must match the server that our application thinks that it is going to communicate with.
Then I cheat and use InstallCert, a Java app written by Andreas Sterbenz who also beat his head against Java certificate validation issues. The neat thing about InstallCert is that you just give it a URL and it will grab the cert and create a keystore you can use. You just copy over your old cacerts file with the newly created one, and your cert will now be accepted for future use. We just point InstallCert at our stunnel instance:

You can safely ignore the SSLHandshake errors. You should really run InstallCert on the machine you intend to test from (in my case the Windows box), but it was faster for me to create screencaps in OS X. Then InstallCert will ask you to if you want to accept the cert:

InstallCert will create a file called jssecacerts in the current working directory. You will want to copy that file over the actual keystore usually located in JAVAPATH/lib/security/cacerts.
Note: Backup the cacerts file before overwriting it.
This is where someone comments, “but all you had to do was edit java.security to say XXX and you could have disabled certificate validation”, and where I wish there was a phrase that meant both Thank You and I Hate You. If it turns out that I am correct, then I have to ask: Why on Earth isn’t this a configuration file option?


wrc
May 1st, 2007 10:41 amYes, annoying!
It makes keeping a test CA that you can issue certs on the fly from around worthwhile.
Know what’s even more annoying? When the Java app keeps its keystore in the .jar file. I hate extra steps.
www.andrewhay.ca » Suggested Blog Reading - Tuesday May 1st, 2007
May 1st, 2007 12:04 pm[…] MITMing an SSLized Java App - Good article I was recently working on a Java-based application that communicated exclusively over SSL. This is a good thing for the application, but a bad thing for someone trying to test it. I naively thought that I could edit a couple of files and boom, be on my way. […]
Shawn F
May 1st, 2007 1:05 pmYeah SSL is real cool till you have to test with it and can’t turn it off. So how long did all this take you?
Dan Moniz
May 1st, 2007 2:00 pmI nominate “Thankate You!” to be that phrase.
Jason
May 1st, 2007 3:39 pmI implemented a similar tool using Twisted (http://www.twistedmatrix.com) to help debug a proprietary binary protocol. Its generic enough that it will MITM anything, but you can add decoders to text-ify the protocol.
Lucky for us, we can tweak the verification of the certificate.
Mike F.
May 1st, 2007 4:17 pmWhy couldn’t you use sslsniff or something similar?
Andrew Jaquith
May 1st, 2007 8:48 pmYup, the SSL certificate trust store issue with Java is an issue I’ve dealt with as well. I have a little library called freshcookies-security that works like InstallCert. It actually goes a little further and will inject the cert directly into your global JVM CA trust store, assuming you’ve got privileges to do it. It prints the certificate details in an identical fashion as keytool (issuer, fingerprint, etc.) and dumps the certs to the desktop too as nicely encoded DER file, which you can double-click and add to your Apple keychain or Windows certificate store. Works just dandy.
Andrew Jaquith
May 1st, 2007 9:11 pmI should have also said, “and I wrote the thing too, and would be happy to share.” It is BSD-licensed.
Freshcookies-security is here: http://www.freshcookies.org/freshcookies-security/
If it’s useful to people, that’s great.
Thomas Ptacek
May 1st, 2007 10:03 pmMike: if you mean something like ssldump, it’s because he needs to inject traffic as well as just read it; also, with ssldump, he needs the server’s private key, and can’t handle EDH.
Stephen de Vries
May 2nd, 2007 4:09 amI regularly run into a similar issue when testing Java clients, but sometimes they don’t even use SSL but their own bespoke crypto packages. For these cases, I inject a BeanShell instance into the code which effectively gives you an interactive Java shell in the app. Paper describing the process can be found here:
http://research.corsaire.com/whitepapers/060816-assessing-java-clients-with-the-beanshell.pdf
Jon Bowie
May 2nd, 2007 9:46 amHey, I would’ve thought to forge a cert and store it locally in the keystore before I would’ve thought of overloading the validation method too.
A configuration option for disabling Certificate Validation seems a bit much though. Why make it easier for XXXotMBot to disable certificate validation in the JRE and locally MITM all java-based SSL traffic at layer 5 transparently?
It’s been awhile since I’ve done any work with Java, but does it support preloads or imports? If so, setup a test environment where you can overload the cert validation methods arbitrarily based on a toggle in your local environment variables. Why make it any easier to disable certificate validation, with exception to places where it makes sense (from a research perspective) to?
Making the researcher kludge a bit is a better solution than potentially leaving the end-user with their pants down.
I can “Thankate You” for your comments later.
Thomas Ptacek
May 2nd, 2007 10:02 amOn 9 out of 10 of my J2EE engagements, I may get access to the JAR files, but I certainly can’t modify them or the running image.
Matt
May 2nd, 2007 2:57 pmThomas (and Dave): Do you actually run into apps that use SSL-EDH?
Thomas Ptacek
May 2nd, 2007 3:44 pmJust once (for those who aren’t TLS geeks: EDH is Ephemeral Diffie-Hellman; it uses a DH key exchange to generate the session key, and the public/private keypair only to authenticate the exchange — good for the participants, who have forward secrecy, but bad for monitors, who have no fixed key to use to watch the session).
Being able to inject into the middle of the stream is the real reason SSLdump doesn’t solve the problem.
Joe
June 3rd, 2007 9:38 amGreat article!
Is it possible to do this when the keystore is stored in the jar file?
Leave a reply