Monday, March 13, 2006

Format Strings in PHP

I realise that no-one actually reads what I post here, but i've got an urge to post the crap that i've written up and posted almost nowhere (and in this case nowhere at all) for some reason, even thugh its crap, and useless....

================
Format Strings
================

This small article pertains to Format String vulnerabilities in PHP applications rather than PHP itself.

Format String Vulnerabilities exist where the user is allowed to place data into a format string of a function which accepts a format string, e.g. sprintf(). These vulnerabilities are uncommon, even rare, in PHP because these functions are generally not used in PHP scripts.

In most other languages format string vulnerabilities allow:
- Viewing the Stack
- DoS attacks
- Improper validation checks

In PHP the first 2 should not be an issue since PHP makes sure the amount of unique (in the sense that they are unique if they don't reference to the same variable passed to the format function) place holders and variables it is passed, or provides an error message otherwise, and since the DoS vulnerabilities in format strings are resource exhaustion/corruption and PHP has a setting for the maximum amount of RAM it can consume (after it surpases the limit it simply kills the script and provides an error, instead of crashing) and the corruption can occur when the user is able to force the program to write to the stack, but since you cannot write to the stack using PHP's format functions those vulnerabilities do not exist.

Improper validation checks are probably the only things you need to worry about in PHP, and then only if you were fairly sloppy in your work. An example of a vulnerable script would be a script which INSERTs data into a database, which validates different fields in different ways, and therefore trusts them differently when uing data retrieved from those fields:

<?php

// Our RegExps to validate our data, the only thing that is required here is that one allows
// single quotes (or whatever is used to encase strings) and of course letters so that stored
// SQL Injection can be performedand and another be allowed percent and dollar signs and of
// course lowercase letters.
$regexps['field1'] = '/^A-Za-z0-9\'+-=!@#$%^&*()$/';
$regexps['field2'] = '/^A-Za-z0-9+-=!@#$%^&*()$/';

$errors['field1'] = "The value you supplied for field1 did not match the following RegExp: /^A-Za-z0-9'+-=!@#$%^&*()$/\n";
$errors['field2'] = "The value you supplied for field2 did not match the following RegExp: /^A-Za-z0-9+-=!@#$%^&*()$/";

$errormsg;
$err = 0;

foreach ($regexps As $key=>$value) {
if (!ereg ($regexps[$key], $_POST[$value])) {
$err = 1;
$errormsg .= $errors[$key];
}
}

if (empty($err)) {
$dbh = mysql_connect();
$sql = sprintf ("INSERT INTO table (field1, field2) VALUES ('%s', '".mysql_real_escape_string ($_POST['field2']."')",
mysql_real_escape_string($_POST['field1']));
mysql_query


}

?>


In this (highly simplified example) we want to allow users to enter single quotes into field1 for some reason, e.g. its a surname field and we want to allow names like O'Rielly, and for some reason we want to allow percent signs in field2, and we were sloppy and inserted the (already validated) value of field2 directly into the format string.

Now, how could this be bad, well it all comes back to the issue of trust, you trust that because you validated field2 to make sure there were no quotes and you do that validation every ime the user wants to update that field so you decided you weren't going to escape it to increase performance, now lets see what happens when we try and exploit the format string bug.

Lets say we provided some stored SQL Injection (this could also be done with stored XSS) code for field1, it wouldn't work since we know that field 1 could contain malicious data so we always escape it, to field2 though we provide the following value:%1\$sWhich is the format for inserting the first variable passed to the function after the formt string, and all of a sudden our format string looks like this:INSERT INTO table (field1, field2) VALUES ('%s', '%1\$s')And all of a sudden we have some malicious SQL stored in a field which you trust implicitly and don't escape.

2 comments:

Anonymous said...

I read it. ;)

Leo said...

Me too!
although I am a little insane.