So around now is the annual SSL certificate renewal for most of our internal servers, and I thought it would be a good idea to check them all for SSL/TLS vulnerabilities. A quick Google later, and I’m looking at Qualys Labs SSL Server Test. The scan is nice and shiny, and give an instant (2-3 minute) overview of a server’s security. It also takes care of DNS round-robin to make sure all your servers are handled (though sites with HLBs or similar may need more attention).
Qualys is all well and good for public servers on port 443, but that’s all it’ll scan. For anything internal only, or services other than HTTPS, it’ll give you a nice fat error. That’s where testssl.sh comes in. testssl.sh is a bash shell script that uses openssl and socket interfaces to test any SSL or TLS connection.
That includes services like SMTP, that require extra bits (like STARTTLS) to get the encryption up and running. The only service that it doesn’t like is Microsoft’s RPC server, which causes the scan to hang (Ctrl+C to exit). testssl.sh checks for general issues (like insecure cipher/hashing algorithms) as well as more specific issues like Heartbleed, POODLE, and other vulnerabilities. It can even tell you when your remote desktop services RDP certificate is about to expire (assuming you run it regularly).
The only thing left is to make it nice and simple so the service desk can run it. That’s where aha comes in. Aha (or the ANSI HTML Adapter) takes terminal output with ANSI colour and formatting codes, and turns it into nice neat HTML for your browser. It’s directly compatible with testssl.th, though I’d recommend setting –warnings batch to avoid any errors hanging your web server. The full command I’m using to scan servers is
./testssl.sh --warnings batch wsus:8531 | aha > wsus-SSL.html
but that doesn’t quite handle everything, I’ve still got to start the scan manually. PHP to the rescue! we can use shell_exec() to run the script. But hold on, that’s rather dangerous, I hear you say. Well, you’re right. That could allow any command to be run on my server. So, let’s fix that. Luckily, PHP can take care of that for us as well, that’ what escapeshellcmd() is for, it gets rid of all the nasty stuff. That leaves us with a rather nice one-liner:
echo shell_exec( escapeshellcmd( "/root/testssl.sh/testssl.sh --warnings batch ".$_GET['server']." | aha" ) );
Unfortunately, it doesn’t quite work like we expected. The first results gave me a blank page for a while, then a garbled mess of rendered ANSI codes, and took me a little while to work out what was going on. Our first issue is that escapeshellcmd() is escaping everything, including the control characters we need to send the output through aha. Right, that solves the mess of characters, but the output still takes a while to show up. That’s understandable, as the scans take a while to run. Let’s try turning off output buffering, which should make the results show up slowly in the browser as aha outputs them (it does everything in real-time, which is nice for stuff using stdin). That gives us this:
disable_ob(); passthru( "bash ./testssl.sh/testssl.sh --warnings batch ".escapeshellcmd($_GET['server'])." | aha" );
Not quite a one-liner any more, but it gets the job done.
The first line is a function I wrote for another project that gets through any kind of output buffering, including inside PHP, Apache, GZip and the browser (Note to self: write an article about it). The second line is similar, but not quite identical to what we had before. The shell_exec() command has been replaced has been replaced with a call to passthru() which sends the command’s STDOUT straight to PHP’s output, without the need for regular flushing. We’ve also moved the escapeshellcmd() call to cover just the $_GET variable, this makes sure we don’t mess up our control characters. I’ve also explicitly called bash, and moved the script into the web root to take care of permissions.
All that leaves is a form for the service desk team to fill in with what they want scanning. I’ll leave that one as an exercise for the reader, answers on the back of a postcard to the usual address.