Difference between revisions of "Unsafe string replacement"
Line 1: | Line 1: | ||
=Overview= | =Overview= | ||
− | Unsafe use of string replacement functions to sanitize user input is extremely common. Because string replace ([http://php.net/manual/en/function.str-replace.php str_replace] in PHP) functions only do a single replacement, it is necessary to loop over them until all unsafe characters or strings are removed if you are replacing more than a single character. This is a language agnostic vulnerability, effecting any application which incorrectly uses string replacement for sanitization . | + | Unsafe use of string replacement functions to sanitize user input is extremely common. Because string replace ([http://php.net/manual/en/function.str-replace.php str_replace] in PHP) functions only do a single replacement, it is necessary to loop over them until all unsafe characters or strings are removed if you are replacing more than a single character. This is a language agnostic vulnerability, effecting any application which incorrectly uses string replacement for sanitization. |
+ | |||
==Example== | ==Example== | ||
A trivial example: | A trivial example: | ||
Line 60: | Line 61: | ||
==Defense== | ==Defense== | ||
− | If one must use str_replace for sensitization (which is strongly advised against), | + | If one must use str_replace for sensitization (which is strongly advised against), it must be done recursively (thought I will show it implemented in a loop, for efficiency reason): |
{{code | {{code | ||
|text= | |text= | ||
<source lang="php"> | <source lang="php"> | ||
− | + | function safe_str_replace($search, $replace, $subject) | |
− | $ | + | { |
+ | while(strstr($subject, $search) != FALSE) { | ||
+ | $subject = str_replace($search, $replace, $subject); | ||
+ | } | ||
− | + | return $subject; | |
− | + | ||
− | + | ||
− | $ | + | |
} | } | ||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
}} | }} | ||
However, the use of whitelists of 'positive' regex matching (i.e. does the input match /[a-z]+/) is consider more effective. | However, the use of whitelists of 'positive' regex matching (i.e. does the input match /[a-z]+/) is consider more effective. |
Revision as of 18:57, 5 May 2012
Overview
Unsafe use of string replacement functions to sanitize user input is extremely common. Because string replace (str_replace in PHP) functions only do a single replacement, it is necessary to loop over them until all unsafe characters or strings are removed if you are replacing more than a single character. This is a language agnostic vulnerability, effecting any application which incorrectly uses string replacement for sanitization.
Example
A trivial example:
<?php $filepath = $_GET['file']; $safe_filepath = str_replace('../', '', $filepath); echo("Safe filepath is '" . $safe_filepath . "'<br />"); include($safe_filepath); ?> |
First an attacker may try a simple [File Inclusion] attack, using '../' to escape. The result:
Safe filepath is 'etc/passwd'
No dice, the dangerous string ('../') is dutifully sanitized by str_replace. But, our attacker isn't going to give up yet, now armed with the knowledge that '../' is being filtered out, he may try:
test.php?file=....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd
The result:
Safe filepath is '../../../../../../../../../../../etc/passwd' [contents of /etc/passwd]
Even if '../' is replaced twice, it can be easily bypassed by using ......///. No matter how many times the replacement is made, the attacker simply needs to nest another layer.
Other examples of unsafe uses of string replacement include:
str_replace('<?', '', $source); |
Bypassed by '<<??'
str_replace(array('<script', '<img'), '', $source); |
Bypassed by '<<imgscript>'
str_replace('file://', '', $source); |
Bypassed by 'file:/file:///'
Defense
If one must use str_replace for sensitization (which is strongly advised against), it must be done recursively (thought I will show it implemented in a loop, for efficiency reason):
function safe_str_replace($search, $replace, $subject) { while(strstr($subject, $search) != FALSE) { $subject = str_replace($search, $replace, $subject); } return $subject; } |
However, the use of whitelists of 'positive' regex matching (i.e. does the input match /[a-z]+/) is consider more effective.