To Catch A Thief
Or: Why Penetration Testing is Time & Money Well Spent
Security requires regular outside testing, because small vulnerabilities can often be leveraged into a full-scale breach. A door left ajar can let in a family of raccoons, a small crack in the hull can sink a ship, and — in the case of a recent webserver penetration test — a poorly validated text input field can lead to an internal subnet hiding secured assets.
When I began working on this external penetration test, I discovered a web server with a vulnerable text input field. I was able to input OS commands and get the command output to display on the web page. The web user had limited access, but I was able to view much of the file system for the web server and do reconnaissance. In doing so I found that the web server was multi-homed, and had access to not only the Web DMZ but another unknown subnet.
I decided to use this to penetrate further into the network, but first I would need a fully interactive shell. The web server was running Windows and had powershell 2.0 installed by default, so I used that as my attack vector to download a shell. First I uploaded an obfuscated powershell script to my target system, with a Metasploit Meterpreter callback to the public IP on my own web server. Then I used the command injection vulnerability I’d found to execute powershell using the Invoke-Expression command to download and execute my Meterpreter payload and the Execution Policy Bypass flag to make sure it would run even though it is an untrusted executable.
Once I had my Meterpreter shell callback, I set up a route to point to the unknown subnet I wanted to explore and used the tcp portscan command built into Metasploit. This turned out to be too slow however and I had problems with hosts having DHCP IPs changing IP before I could even complete a single pass with the scanner. So I installed the MSFmap extension to accelerate the scan and found none of the hosts on the subnet had any interesting or useful open ports. I was confident if I persisted I would find something, so I went back and did another, more thorough scan. On the 2nd pass, I found an odd service listening on port 1337, obviously a custom application because that is not a default port.
Probing the port I got some weird responses that told me there was something listening and expecting data. One thing in particular which caught my eye was an error about a missing command interpreter. That meant it was trying to execute the data I sent as a command. Part of the error message included a path variable which was using the default ruby path for a linux system. I did some research and discovered the error message was being generated by an installation of druby (distributed ruby). Further research uncovered some pretty juicy known vulnerabilities in druby. I launched all the exploits that I had in Metasploit, but nothing was successful. I also checked the exploit-db library and tested everything they had. Still nothing. I wasn’t about to give up though, because I knew there was a vulnerability there. I knew there was a command execution waiting to happen if I could just figure it out.
After more research on druby, I found some sample scripts I was able to repurpose for my own ends. I set my Meterpreter up to forward the output from my test script to the vulnerable host on the internal network, forwarding through the DMZ using the vulnerable webserver as a pivot. I modified a sample script which was intended to test to see if the $SAFE environment variable was set. Turns out the variable wasn’t and I was able to execute privileged commands on the linux box hosting the vulnerable druby API.
The linux host was completely isolated and couldn’t connect out to the internet, only to the DMZ, however the druby installation was running public SSH key into the terminal window and used echo to write it to /root/.ssh/authorized_keys and was able to ssh into the linux box over my pivot. My recon showed it had been used as a development box as root, and I could execute any command. First I had a quick peek at the /etc/shadow file, but I didn’t want to waste time cracking passwords since I already had root access, so I just copied and pasted from my own server. It was unpatched and unmaintained; nobody had logged in for months.
I captured the root ssh private key in case that may be useful elsewhere, left an IWASHERE flag in the root home directory, took screenshots to document my activity and all the many vulnerabilities I’d discovered on this journey and added this little gem to my report. Starting from an unprivileged access to a public webserver I’d managed to penetrate into an internal subnet which wasn’t supposed to be internet accessible at all and gotten root access, a list of developer password hashes to crack offline at my leisure, and an ssh key used for developer access.
Vulnerabilities like this exist in every architecture, and the right combination can allow a malicious hacker deep into your formerly secure system. There are many ways to address these vulnerabilities systematically, including the evergreen architectural patterns that Greenfield recommends. First and foremost is a regular regimen of penetration tests like this one, so you can fix existing vulnerabilities before hackers find them.