Cultural Note: Shits and giggles == englishize(for the lulz) –> Urban Dictionary Ref.
How often as penetration testers do we see SSL protected services using self signed certificates… If you’re anything like the average penetration tester, it’s probably daily. We’ve all been through the song and dance of documenting it, saying it’s bad and that it might have security consequences. I’m sure we’ve all heard every excuse under the sun as well when it comes to why it can’t be fixed. Costs too much, no internal PKI, takes too much time, and some of my favourites… “It’s just a test system”, “nobody except us uses this and we know what cert it has” and the all time classic, “it’s only internal”!
I’m not sure about you, but I don’t have the fingerprints for all the self signed certs I’ve seen in my head… and the over use of them has conditioned many of us to just click YES when prompted. Although this has become a little harder in recent times with new browsers making you click-through more than one menu, it’s still easier than getting up, walking over to an admin and saying “whats up here”. Certs, even self signed ones, expire and are replaced… which leads us to the inevitable result that users, and to some lesser extent administrators, will click-through almost anything as long as the Common Name and Issuer data looks remotely correct.
As part of my SAP Management Console research I began looking at the possibility to automatically create a self signed certificate that impersonates the certificate on a remote system as closely as possible. Not just the same CN, but everything from CN through to Issuer, Extensions… everything. With that in mind I flexed my awesome Ruby skills (note: I have no Ruby skills that I’m aware of) and created a simple Metasploit module that connects to a remote target, reads the SSL certificate and, using all the relevant data from the remote cert, creates a local self signed certificate and private key. Obviously there are some differences as I can’t match the signature (if I could that would be a big problem right ;), but to the general user, things look almost identical.
Putting your “normal user” or even “overworked sysadmin” hat on for a moment, take a look at the below side-by-side comparison.
Original Certificate | Impersonated Certificate
I’m not sure about you, but I know a few people who’d just click that away without a second thought. Even more people if self signed certs are a standard in your company.
Creating an Impersonated SSL certificate the hard way
Go to the site you want to create the impersonation certificate for, export the publicly accessible information, recreate by hand using OpenSSL… good luck with all the fine details… can you set all the options you want??? Scratch your head…. profit (later)
Creating an impersonated SSL certificate the Metasploit way
msf > use auxiliary/gather/impersonate_ssl
msf auxiliary(impersonate_ssl) > set RHOST www.metasploit.com
RHOST => www.metasploit.com
msf auxiliary(impersonate_ssl) > run
[*] Connecting to www.metasploit.com:443
[*] Copying certificate /O=metasploit.com/OU=Domain Control Validated/CN=metasploit.com from www.metasploit.com:443
[*] Beginning export of certificate files
[+] Created required files from remote server www.metasploit.com:443
[+] Files stored in ~/.msf3/loot (.key|.crt|.pem)
[*] Auxiliary module execution completed
That’s it… you now have all the files you need (key|crt|pem) in ~/.msf4/loot ready to be used in any other Metasploit module (using ‘set SSLCert’), Apache or whatever your heart desires. Go on, go wild!
Note: The module tries it’s best to match the original certificate 100%, which includes using the same key length and hashing algorithm (MD5, SHA-1, etc…). It also tries to match the serial of the cert as closely as possible (some difference is required to stop certain browsers from displaying an error when it sees a certificate with the same issuer/serial combination using a different signature –> example). You’ll notice in the above screenshots that the serial on both certificates is 00… this threw an error on my Firefox when accessing the real site, followed by the site with the impersonated SSL… hence the fixed version 😉
Even amongst the companies that have an internal CA this kind of impersonation is going to get past most people… for those special cautious people (i.e the security people) I’ve built-in an EXPIRATION option where you can set a date (or specify a shortcut such as ‘now’ or ‘yesterday’) when the impersonated SSL certificate you create will expire. This will also set the logical start date of the certificate to a year before expiration to look logical to people checking the details closely. Using this feature you can add an extra level of depth to social engineering attempts… How many times have you seen internal (or even external) SSL certs expire before people remember to renew them? People that are looking for deception and trickery need something, anything, to prove to them that it isn’t an attack… so lets give it to them. I give you the “Oops our cert expired yesterday” attack ™
I don’t claim this to be new, and I’m sure there are thousands of smart enlightened testers out there right now doing this kind of thing on a daily basis… It’s not perfect, but face it, if it was I wouldn’t be blogging about it! I’d be sitting on a beach somewhere with a Mojito and a check from ZDI in my pocket 😉 Still I hope this module will help the layman demonstrate that self signed certs, even within your companies internal network, are an easy target with a little thought, an explainable scenario and a little Ruby!
The impersonate_ssl.rb script isn’t currently in the Metasploit repository, but can be downloaded from my Google Code SVN…
Note: The above Metasploit output is based on my interpretation of where impersonate_ssl.rb will be placed (auxiliary/gather)… if it makes it into the Metasploit trunk, it may be located elsewhere –> Metasploit feature #5398
Great, that’s perfect.
Looks like the issue it the differences between OpenSSL versions.
Your version uses the notation .:
Public-Key: (1024 bit)
The test version I’m using (Backtrack5r1) uses .:
Public Key: (1024 bit)
Modulus: (1024 bit)
The original regex matched on Modulus, and was then failing on your version. Moved the regex to match on /Key: \((\d+)/i to avoid the issue… Feel free to try the new version (SVN) as it should now copy the keylength and signature hash type from the destination cert instead of erroring out and falling back to 1024/sha1 (I think either Novell.com or facebook.com use a 2048 bit for example).
Thanks for the troubleshooting! Appreciate it…
Pingback: SSL certificate impersonation… for shits and giggles! | Dis9 Team