php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #63455 SIGSEGV with preg_match
Submitted: 2012-11-07 14:13 UTC Modified: 2012-11-07 23:09 UTC
From: jakub dot galczyk at gmail dot com Assigned:
Status: Not a bug Package: PCRE related
PHP Version: 5.4.8 OS: Ubuntu
Private report: No CVE-ID: None
 [2012-11-07 14:13 UTC] jakub dot galczyk at gmail dot com
Description:
------------
I was checking one bug in CMS (found by someone else) and accidently there was a SIGSEGV ;]



Test script:
---------------
Exploit code ('script to test') is here:
http://www.exploit-db.com/exploits/15369/

CMS (I saw that we need to have this CMS in /wwwroot) to test:
http://www.geardownload.com/webdevelopment/auto-cms-download.html

(Below I added a little description grepped from .c file, gdb and valgrind.

Expected result:
----------------
No sigsegv? ;)

(and shell output from this sploit for autocms wroted by giudinvx)


Actual result:
--------------
kuba@box:~/src/php-5.4.8$ /usr/local/bin/php -v
PHP 5.4.8 (cli) (built: Nov  7 2012 13:36:10)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
kuba@box:~/src/php-5.4.8$ /usr/local/bin/php ../../public_html/spl.php localhost /

Auto CMS <= 1.8 Remote Code Execution
Exploit by giudinvx
ShellCMD
WHATEVERGOESHERE:*:*:*
Segmentation fault (core dumped)
kuba@box:~/src/php-5.4.8$

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-11-07 14:26 UTC] pajoye@php.net
Increase the stack and the problem should go away.

Actually the reproduce script could be reduce to:

preg_match("/(\n|.)*/i", $res, $match);

with the content of $res and $match being previously set.
 [2012-11-07 14:34 UTC] jakub dot galczyk at gmail dot com
More info:
                                       
(gdb) bt
(...)
#21790 0x080b8f3b in php_pcre_exec (argument_re=0x4657380, extra_data=0xbe9e6ed4,
    subject=0x43c3abc "HTTP/1.1 302 Found\r\nDate: Wed, 07 Nov 2012 13:14:24 GMT\r\nServer: Apache/2.2.22 (Ubuntu)\r\nX-Powered-By: PHP/5.3.10-1ubuntu3.4\r\nCache-Control: no-cache, must-revalidate\r\nExpires: Sat, 26 Jul 1997 05:00:"..., length=11527, start_offset=0, options=0, offsets=0x43bad0c, offsetcount=6)
    at /home/kuba/src/php-5.4.8/ext/pcre/pcrelib/pcre_exec.c:6098
#21791 0x080bd6cd in php_pcre_match_impl (pce=0x46574d8,
    subject=0x43c3abc "HTTP/1.1 302 Found\r\nDate: Wed, 07 Nov 2012 13:14:24 GMT\r\nServer: Apache/2.2.22 (Ubuntu)\r\nX-Powered-By: PHP/5.3.10-1ubuntu3.4\r\nCache-Control: ---Type <return> to continue, or q <return> to quit---
no-cache, must-revalidate\r\nExpires: Sat, 26 Jul 1997 05:00:"..., subject_len=11527, return_value=0x43c20a4, subpats=0x43bd784, global=0, use_flags=0, flags=0,
    start_offset=0) at /home/kuba/src/php-5.4.8/ext/pcre/php_pcre.c:634

#21792 0x080be13d in php_do_pcre_match (ht=3, return_value=0x43c20a4, global=0, return_value_ptr=<optimized out>, this_ptr=<optimized out>,
    return_value_used=<optimized out>) at /home/kuba/src/php-5.4.8/ext/pcre/php_pcre.c:528
#21793 0x08374d58 in zend_do_fcall_common_helper_SPEC (execute_data=<optimized out>) at /home/kuba/src/php-5.4.8/Zend/zend_vm_execute.h:642
#21794 0x08337ced in execute (op_array=<optimized out>) at /home/kuba/src/php-5.4.8/Zend/zend_vm_execute.h:410
#21795 0x082d9a93 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/kuba/src/php-5.4.8/Zend/zend.c:1309
#21796 0x0827a6b2 in php_execute_script (primary_file=0xbe9e93dc) at /home/kuba/src/php-5.4.8/main/main.c:2482
#21797 0x0837749e in do_cli (argc=4, argv=0xbe9ea664) at /home/kuba/src/php-5.4.8/sapi/cli/php_cli.c:988
#21798 0x08067254 in main (argc=4, argv=0xbe9ea664) at /home/kuba/src/php-5.4.8/sapi/cli/php_cli.c:1364
(gdb)
(gdb)
(gdb) x/10i 0x80a99bb
=> 0x80a99bb <match+5787>:      mov    %edi,0x8(%esp)
   0x80a99bf <match+5791>:      mov    %ebp,0x14(%esp)
   0x80a99c3 <match+5795>:      mov    0x40(%esp),%ebp
   0x80a99c7 <match+5799>:      movzbl 0x83e2dc0(%eax),%eax
   0x80a99ce <match+5806>:      mov    %ebp,0x10(%esp)
   0x80a99d2 <match+5810>:      mov    0x3c(%esp),%ebp
   0x80a99d6 <match+5814>:      lea    (%esi,%eax,1),%edx
   0x80a99d9 <match+5817>:      mov    0x30(%esp),%eax
   0x80a99dd <match+5821>:      mov    %ebp,0xc(%esp)
   0x80a99e1 <match+5825>:      mov    0x184(%esp),%ebp
(gdb) p $1
History has not yet reached $1.
(gdb) p $eip
$1 = (void (*)()) 0x80a99bb <match+5787>
(gdb) i r
eax            0x43bad20        71019808
ecx            0x43c3abc        71056060
edx            0x2a8e   10894
ebx            0x43c654a        71066954
esp            0xbe1ebfd0       0xbe1ebfd0
ebp            0x0      0x0
esi            0x46573ac        73757612
edi            0xbe9e6d80       -1096913536
eip            0x80a99bb        0x80a99bb <match+5787>
eflags         0x4      [ PF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x0      0
fs             0x0      0
gs             0xb      11
(gdb) list
817             (int)(eptr - md->start_subject);
818
819           flags = (op == OP_SCBRA)? match_cbegroup : 0;
820           do
821             {
822             RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md,
823               ims, eptrb, flags, RM1);
824             if (rrc != MATCH_NOMATCH &&
825                 (rrc != MATCH_THEN || md->start_match_ptr != ecode))
826               RRETURN(rrc);
(gdb)
827             md->capture_last = save_capture_last;
828             ecode += GET(ecode, 1);
829             }
830           while (*ecode == OP_ALT);
831
832           DPRINTF(("bracket %d failed\n", number));
833
834           md->offset_vector[offset] = save_offset1;
835           md->offset_vector[offset+1] = save_offset2;
836           md->offset_vector[md->offset_end - number] = save_offset3;
(gdb) \q
kuba@box:~/src/php-5.4.8$ grep -n -r -e RMATCH ./
(...)
kuba@box:~/src/php-5.4.8$ vim ext/pcre/pcrelib/pcre_exec.c
/RMATCH
(...)
line 235:
"The original heap-recursive code used longjmp(). However, it seems that this
can be very slow on some operating systems. Following a suggestion from Stan
Switzer, the use of longjmp() has been abolished, at the cost of having to
provide a unique number for each call to RMATCH. There is no way of generating
a sequence of numbers at compile time in C. I have given them names, to make
them stand out more clearly."
(...)
"/* These versions of the macros use the stack, as normal. There are debugging
versions and production versions. Note that the "rw" argument of RMATCH isn't
actually used in this definition. */

#ifndef NO_RECURSE
#define REGISTER register

#ifdef PCRE_DEBUG
#define RMATCH(ra,rb,rc,rd,re,rf,rg,rw) \
" 
(...)
"
/* These versions of the macros manage a private stack on the heap. Note that
the "rd" argument of RMATCH isn't actually used in this definition. It's the md
argument of match(), which never changes. */"

No to ja go chyba troche zmieniƂem ;]

"register int  i;           /* Used for loops not involving calls to RMATCH() */"
"
/* OK, now we can get on with the real code of the function. Recursive calls
are specified by the macro RMATCH and RRETURN is used to return. When
NO_RECURSE is *not* defined, these just turn into a recursive call to match()
and a "return", respectively (possibly with some debugging if PCRE_DEBUG is
defined). However, RMATCH isn't like a function call because it's quite a
complicated macro. It has to be used in one particular way. This shouldn't,
however, impact performance when true recursion is being used. */"

818:833:
(...)
      flags = (op == OP_SCBRA)? match_cbegroup : 0;
      do
        {
==>        RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, eptrb, flags, RM1);
        if (rrc != MATCH_NOMATCH &&
            (rrc != MATCH_THEN || md->start_match_ptr != ecode))
          RRETURN(rrc);
        md->capture_last = save_capture_last;
        ecode += GET(ecode, 1);
        }
      while (*ecode == OP_ALT);

      DPRINTF(("bracket %d failed\n", number));
(...)
 [2012-11-07 14:37 UTC] tony2001@php.net
-Status: Open +Status: Not a bug -Package: *Math Functions +Package: PCRE related
 [2012-11-07 14:37 UTC] tony2001@php.net
This is PCRE overflowing the stack due to an (endless?) recursion in your regular 
expression.
It's a well known PCRE problem and solutions to it are described here:
http://manpages.courier-mta.org/htmlman3/pcrestack.3.html
and here:
http://pcre.org/pcre.txt (look for "STACK USAGE")
 [2012-11-07 23:09 UTC] sixd@php.net
-Summary: SIGSEGV +Summary: SIGSEGV with preg_match
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 00:01:29 2024 UTC