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
(Overview)
(Example)
Line 5: Line 5:
 
Unsafe use of string replacement functions to sanitize user input is extremely common. Because string replacement ([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 also applies to replacements powered by regular expressions.
 
Unsafe use of string replacement functions to sanitize user input is extremely common. Because string replacement ([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 also applies to replacements powered by regular expressions.
  
=Example=
+
=Examples=
 +
 
 +
==PHP==
 
A trivial example:
 
A trivial example:
  
Line 61: Line 63:
 
}}
 
}}
 
   Bypassed by 'file:/file:///'
 
   Bypassed by 'file:/file:///'
 +
 +
== PCRE ==
 +
To test if perl compatible regular expressions are vulnerable to the attack, a small example perl script, ''rexpose.pl'', is attached:
 +
{{code|text=<source lang="perl">
 +
#!/usr/bin/perl
 +
use strict;
 +
use Getopt::Std;
 +
 +
my %opts = ();
 +
getopts('s:p:',\%opts);
 +
 +
my $string  = $opts{s} if ($opts{s}) or usage();
 +
my $pattern;
 +
$pattern = $opts{p} if ($opts{p});
 +
$pattern = '[.]{2}\/' unless (defined $pattern);
 +
$string =~ s/$pattern//g;
 +
print "$string\n";
 +
 +
 +
 +
sub usage
 +
{
 +
    print "rexpose.pl -s [string] [-p pattern]\n";
 +
    print "Regex exposure will display string replacements using s/\$pattern//g.  Pattern defaults to '[.]{2}\\/' to match '../'.\n";
 +
    exit(0);
 +
}
 +
</source>}}
 +
 +
* First, a check is performed to make sure that the string is being stripped at all to being with:
 +
  [user@host ~]$ perl rexpose.pl -s ../../../../../../path/to/file
 +
  path/to/file
 +
* To identify if the replacement is vulnerable, a check using '''....//''' in stead of '''../''' is performed:
 +
  [user@host ~]$ perl rexpose.pl -s ....//....//....//....//....//....//path/to/file
 +
  ../../../../../../path/to/file
  
 
=Defense=
 
=Defense=

Revision as of 14:25, 6 May 2012

c3el4.png This is a programming language agnostic vulnerability, effecting any application which incorrectly uses string replacement to sanitize data.


Overview

Unsafe use of string replacement functions to sanitize user input is extremely common. Because string replacement (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 also applies to replacements powered by regular expressions.

Examples

PHP

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 directory transversal 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:///'

PCRE

To test if perl compatible regular expressions are vulnerable to the attack, a small example perl script, rexpose.pl, is attached:

 
#!/usr/bin/perl
use strict;
use Getopt::Std;
 
my %opts = ();
getopts('s:p:',\%opts);
 
my $string  = $opts{s} if ($opts{s}) or usage();
my $pattern;
$pattern = $opts{p} if ($opts{p});
$pattern = '[.]{2}\/' unless (defined $pattern);
$string =~ s/$pattern//g;
print "$string\n";
 
 
 
sub usage
{
    print "rexpose.pl -s [string] [-p pattern]\n";
    print "Regex exposure will display string replacements using s/\$pattern//g.  Pattern defaults to '[.]{2}\\/' to match '../'.\n";
    exit(0);
}
 
  • First, a check is performed to make sure that the string is being stripped at all to being with:
 [user@host ~]$ perl rexpose.pl -s ../../../../../../path/to/file
 path/to/file
  • To identify if the replacement is vulnerable, a check using ....// in stead of ../ is performed:
 [user@host ~]$ perl rexpose.pl -s ....//....//....//....//....//....//path/to/file
 ../../../../../../path/to/file

Defense

If one must use str_replace for sensitization, it must be done using a loop or called recursively:

  • Loop
 
function safe_str_replace($search, $replace, $subject) {
        while(strstr($subject, $search) !== FALSE) {
                $subject = str_replace($search, $replace, $subject);
        }
 
        return $subject;
}
 
  • Recursion
 
function safe_str_replace($search, $replace, $subject) {
        if (strstr($subject, $search) !== FALSE) {
                return safe_str_replace($search,$replace,str_replace($search, $replace, $subject));
        }
        return $subject;
}
 

However, the use of whitelists with 'positive' regex matching (i.e. does the input match /[a-z]+/) is more effective.


Unsafe string replacement is part of a series on exploitation.
<center>
Unsafe string replacement is part of a series on programming.
<center>
</center>