PHP sprintf considered harmful?

I learned about Format String Attacks a few years ago on the hard way. Now I recently saw some PHP code:

echo sprintf($_GET['format'], $_GET['value1'], $_GET['value2']);


I tried running it like this with $_GET['format']

set to type strings %s%s%s...

, but PHP only exists with PHP Warning: sprintf(): Too few arguments in file.php on line 2

. Isn't it still possible to do a formatted string attack?


source to share

4 answers

Not in any traditional sense as PHP sprintf

doesn't support any really dangerous conversions like %n

. A user-controlled format string might still cause some limited chaos (consider %99999999s

), but the worst I think it could do would be memory and time consumption.



I also found integer overflow. Which leads to this:

echo sprintf('%2147483646$s', "foo"); # Warning: Too few arguments
echo sprintf('%2147483647$s', "foo"); # Warning: Argument number must be greater than zero


I filed this as PHP Bug # 61531 . I'm not sure if it can be used.



Higher-level languages ​​tend to check the number of arguments passed instead of blindly trusting the programmer. You will need to find another attack vector.



Not sure if there is a PHP sprintf () vulnerability, but the sample code seems like a prime example of how not to do something.

As far as I know, sprintf should help you lock the line, not the other way around. For example, this is what I find to be a useful reason for using sprintf ():

$sql = sprintf(
    "insert into table (myname, myvalue) values ('%s', '%s')",
    mysql_real_escape_string( $_GET['name'] ),
    intval( $_GET['value'] )


A more useful reason for using sprintf is to borrow its cousin, vsprintf, and constantly reuse it:

// takes variable number of parameters
function sanitize() {
    $args = func_get_args();
    $sql = array_shift( $args );
    foreach( $args as $k => $v ) $args[$k] = mysql_escape_string( $v );
    $safe_sql = vsprintf( $sql, $args );
    return( $safe_sql );


With it, you can safely isolate parameters from requests and assume they will be sanitized:

$t = mysql_query(sanitize(
    "insert into mytable (myname, myvalue) values ('%s', '%s')",




All Articles