Questions about this topic? Sign up to ask in the talk tab.

Difference between revisions of "Unsafe string replacement"

From NetSec
Jump to: navigation, search
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), the secure way of doing so would be to loop until no more dangerous strings are found in the source string. The example program implemented in this fashion would look like this:
+
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">
<?php
+
function safe_str_replace($search, $replace, $subject)
$filepath = $_GET['file'];
+
{
 +
        while(strstr($subject, $search) != FALSE) {
 +
                $subject = str_replace($search, $replace, $subject);
 +
        }
  
$safe_filepath = $filepath;
+
         return $subject;
 
+
while(strstr($safe_filepath, '../') != FALSE) {
+
         $safe_filepath = str_replace('../', '', $safe_filepath);
+
 
}
 
}
 
echo("Safe filepath is '" . $safe_filepath . "'<br />");
 
include($safe_filepath);
 
?>
 
 
</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 19: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.