What it is..
Here’s the scoop according to the Open Source Vulnerability DataBase:
PHP contains a flaw that may lead to an unauthorized information disclosure. The issue is triggered when a remote attacker makes certain HTTP requests with crafted arguments, which will disclose PHP version and another sensitive information resulting in a loss of confidentiality.
Couldn’t have said it better myself. Basically if you’re running PHP it may be possible for someone to discover the PHP-version and other sensitive information. Also referred to as a type of “fingerprinting” attack. It’s not “threat level midnight” or anything like that, but certainly worth a few moments to lock it down: another layer of protection to increase the security of your website[s].
How it works..
On servers running PHP, visit any page, remove the trailing slash, and append any of the following query-strings:
?=PHPE9568F36-D428-11d2-A769-00AA001ACF42
?=PHPE9568F35-D428-11d2-A769-00AA001ACF42
?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000
?=PHPE9568F34-D428-11d2-A769-00AA001ACF42
If the vulnerability is present, requests made with these query-strings results in a variety of easter eggs and
detailed PHP credits [see screenshots]. When these easter eggs are visible, it means that expose_php
is enabled on the server. And when expose_php
is enabled, PHP-generated pages are sent with X-Powered-By
response-headers that give PHP/version infos, such as “X-Powered-By: PHP/5.4.7
”. Knowing the version number of software makes it easier for bad guys to research and exploit known
vulnerabilities. So let’s take a moment to “plug the leak” by disabling expose_php
.
Disable expose_php via php.ini
If you have access to [and can edit] your server’s php.ini
file, the recommended solution is to set expose_php = Off
and be done with it. In addition to preventing access to the PHP easter eggs and credit information, disabling expose_php has the added benefit of preventing
PHP from sending version information in X-Powered-By HTTP Headers. So instead of sending the following response for PHP-generated pages [e.g., WordPress]:
..we send this:
Note that in addition to PHP sending its info via the X-Powered-By
header, Apache is sending its version information as well. We can’t disable
Apache directives via PHP, but as discussed in my book, it’s simple to do with the following directives placed in Apache’s main configuration file [httpd.conf]:
ServerTokens Prod
ServerSignature Off
This simply uses the ServerTokens directive to disable the version number. The ServerSignature directive disables the version info on server-generated pages, which is an added bonus.
Prevent access via .htaccess
If you don’t have access to php.ini
[as is the case for shared-server hosting], we can use a thin slice of .htaccess to deny access to the PHP credits and easter eggs:
RewriteCond %{QUERY_STRING} PHP[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} [NC]
RewriteRule .* - [F]
Just place that code in your site’s root .htaccess file and you’re good to go [no editing required]. How does it work? In the first line we’re matching our regular expression against query-string requests [via RewriteCond
]. The regex pattern may look complicated, but it’s actually using variations on the same pattern, for example:
“[0-9a-f]{8}
” matches any sequence of eight numbers
and letters “a” thru “f”.
Here’s a comparison to help visualize the pattern:
String: PHPE9568F34-D428-11d2-A769-00AA001ACF42
Regex: PHP[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} [NC]
Translated: “escaped equals sign, the sequence “PHP”, any sequence of eight, hyphen, any sequence of four, hyphen, any sequence of four, hyphen, etc.”
The line terminates with a “no-case” [NC]
flag, making the pattern-match case-insensitive and increasing its effectiveness. Then in the second line,
the RewriteRule
simply denies access to any matching requests. The terminating [F]
flag instructs the server to send along a 403 “Forbidden” status along with the request.
All together then
Combining our two Apache techniques, we get an equivalent to disabling expose_php
. Again, editing php.ini
is the best route, but when that’s not possible, these two code snippets will get you there.
1] Add to Apache’s main configuration file [httpd.conf]:
# m0n.co/9
ServerTokens Prod
ServerSignature Off
1] Add to Apache httpd.conf or .htaccess:
# m0n.co/9
RewriteCond %{QUERY_STRING} PHP[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} [NC]
RewriteRule .* - [F]
By combining our two methods we deny access to PHP credits/info and disable broadcasting of the Apache version. That’s effective, but unfortunately there’s no way to prevent expose_php
from sending its X-Powered-By
headers using .htaccess [afaik].
Note also that Apache’s mod_rewrite
must be enabled on the server for this to work. If it’s not, remove the second two lines [the rewrite directives] and
just use the first two. They’re part of the Apache core and should work to disable the Apache infos.
PHP easter eggs
When something is intentionally hidden within a book, app, or whatever, it’s referred to as an “easter egg”. PHP has at least four of them:
PHP Credits | [server with expose_php = on] ?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000 Click here for larger view | |
PHP Logo | [server with expose_php = on] ?=PHPE9568F34-D428-11d2-A769-00AA001ACF42
| |
Zend Logo | [server with expose_php = on] ?=PHPE9568F35-D428-11d2-A769-00AA001ACF42
| |
PHP Logo | [server with expose_php = on] ?=PHPE9568F36-D428-11d2-A769-00AA001ACF42
|
So what’s the deal?
This is all fine and interesting, but is it worth it? It’s been reported that cPanel requires the PHP version info, so some hosts may leave expose_php
enabled for that reason, but isn’t there a better way of communicating sensitive data?
Shouts out
Thank you to Warner Nanninga for bringing this to my attention and helping with further information. Cheers!
About the Author
Jeff Starr = Fullstack Developer. Book Author. Teacher. Human Being.