How does the PHP Ghost one-liner work?
| From: | Robert Williams | Date: | Fri, 30 Jan 2015 18:42:50 +0000 |
| Subject: | How does the PHP Ghost one-liner work? | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-81443@lists.php.net to get a copy of this message | ||
A PHP one-liner is being bandied about as one test of the recently discovered Ghost vulnerability in
gethostbyname(). Taken from:
http://ma.ttias.be/quick-tests-ghost-gethostbyname-vulnerability-cve-2015-0235/
Here it is:
% php -r '$e="0";for($i=0;$i<2500;$i++){$e="0$e";} gethostbyname($e);’
What’s not being discussed is how it works. From the naive viewpoint of a PHP end-user, I’d
expect this one-liner to have the same effect:
% php -r '$e="0$e"; gethostbyname($e);’
But it doesn’t. Can someone familiar with PHP’s internals explain why this code triggers the
overflow, and whether it will actually do so reliably?
More importantly, does this indicate any problems with PHP? It seems like the loop should just be
optimized away to a single assignment, but even if the engine isn’t smart enough to do that, I’d
still expect that the same few bytes of memory at the same memory address would simply get set to
the same value over and over. This code suggests that’s not the case, though, that there are
side-effects. Also, just by lowering the counter to 2499, I get a completely different outcome on
one particular server:
*** glibc detected *** double free or corruption (out): 0x0000000000acce20 ***
Aborted
FWIW, here’s some C that was provided to more directly check for the vulnerability:
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define CANARY "in_the_coal_mine"
struct {
char buffer[1024];
char canary[sizeof(CANARY)];
} temp = { "buffer", CANARY };
int main(void) {
struct hostent resbuf;
struct hostent *result;
int herrno;
int retval;
/*** strlen (name) = size_needed - sizeof (*host_addr) - sizeof (*h_addr_ptrs) - 1; ***/
size_t len = sizeof(temp.buffer) - 16*sizeof(unsigned char) - 2*sizeof(char *) - 1;
char name[sizeof(temp.buffer)];
memset(name, '0', len);
name[len] = '\0';
retval = gethostbyname_r(name, &resbuf, temp.buffer, sizeof(temp.buffer), &result,
&herrno);
if (strcmp(temp.canary, CANARY) != 0) {
puts("vulnerable");
exit(EXIT_SUCCESS);
}
if (retval == ERANGE) {
puts("not vulnerable");
exit(EXIT_SUCCESS);
}
puts("should not happen");
exit(EXIT_FAILURE);
}
--
Bob Williams
Business Unit Information Officer and
Senior Vice President of Software Development
Newtek Business Services Corp.
(602) 263-0300 x12458 | http://www.thesba.com/
________________________________
Notice: This communication, including attachments, may contain information that is confidential. It
constitutes non-public information intended to be conveyed only to the designated recipient(s). If
the reader or recipient of this communication is not the intended recipient, an employee or agent of
the intended recipient who is responsible for delivering it to the intended recipient, or if you
believe that you have received this communication in error, please notify the sender immediately by
return e-mail and promptly delete this e-mail, including attachments without reading or saving them
in any manner. The unauthorized use, dissemination, distribution, or reproduction of this e-mail,
including attachments, is prohibited and may be unlawful. If you have received this email in error,
please notify us immediately by e-mail or telephone and delete the e-mail and the attachments (if
any).