php sprintf函数漏洞

0x01 了解sprintf()函数

1,sprintf(),函数是php中的函数

2,作用是将格式化字符串写入变量中

3,函数形式为sprintf(format,arg1,arg2,arg++)

参数说明:

参数 描述
format

必需。规定字符串以及如何格式化其中的变量。

可能的格式值:

%% - 返回一个百分号 %

%b - 二进制数

%c - ASCII 值对应的字符

%d - 包含正负号的十进制数(负数、0、正数)

%e - 使用小写的科学计数法(例如 1.2e+2)

%E - 使用大写的科学计数法(例如 1.2E+2)

%u - 不包含正负号的十进制数(大于等于 0)

%f - 浮点数(本地设置)

%F - 浮点数(非本地设置)

%g - 较短的 %e 和 %f

%G - 较短的 %E 和 %f

%o - 八进制数

%s - 字符串

%x - 十六进制数(小写字母)

%X - 十六进制数(大写字母)

附加的格式值。必需放置在 % 和字母之间(例如 %.2f):

+ (在数字前面加上 + 或 - 来定义数字的正负性。默认情况下,只有负数才做标记,正数不做标记)

' (规定使用什么作为填充,默认是空格。它必须与宽度指定器一起使用。例如:%'x20s(使用 "x" 作为填充))

- (左调整变量值)

[0-9] (规定变量值的最小宽度)

.[0-9] (规定小数位数或最大字符串长度)

注释:如果使用多个上述的格式值,它们必须按照以上顺序使用。

arg1 必需。规定插到 format 字符串中第一个 % 符号处的参数。
arg2 可选。规定插到 format 字符串中第二个 % 符号处的参数。
arg++ 可选。规定插到 format 字符串中第三、四等 % 符号处的参数。

**若%符号多于arg参数,则需要占位符,占位符格式为“%number\$” 其中number表示该项与第几个arg匹配,如若与第一个匹配     则占位符为“%1\$”

以下是一些例子帮助更好的理解sprintf()函数:

#1.不带占位符的:

<?php

$num1=9999;
$char=96; echo sprintf("%%b=%b",$num1)."</br>";
echo sprintf("%%c=%c",$char)."</br>";
echo sprintf("%%s=%s",$num1)."</br>";
echo sprintf("%%x=%x",$num1)."</br>"; ?>

输出结果:

%b=10011100001111

%c=`

%s=9999

%x=270f

#2.带有占位符:

<?php

$num=123;
sprintf("the number is %1\$d",&num); ?>

结果:

the number is 123

0x02 sprintf()的注入原理

sprintf()的底层实现方法

switch (format[inpos]) {
case 's':
{
zend_string * t;
zend_string * str = zval_get_tmp_string(tmp, &t);
php_sprintf_appendstring( & result, &outpos, ZSTR_VAL(str), width, precision, padding, alignment, ZSTR_LEN(str), 0, expprec, 0);
zend_tmp_string_release(t);
break;
}
case 'd':
php_sprintf_appendint( & result, &outpos, zval_get_long(tmp), width, padding, alignment, always_sign);
break;
case 'u':
php_sprintf_appenduint( & result, &outpos, zval_get_long(tmp), width, padding, alignment);
break;
case 'g':
case 'G':
case 'e':
case 'E':
case 'f':
case 'F':
php_sprintf_appenddouble( & result, &outpos, zval_get_double(tmp), width, padding, alignment, precision, adjusting, format[inpos], always_sign);
break;
case 'c':
php_sprintf_appendchar( & result, &outpos, (char) zval_get_long(tmp));
break;
case 'o':
php_sprintf_append2n( & result, &outpos, zval_get_long(tmp), width, padding, alignment, 3, hexchars, expprec);
break;
case 'x':
php_sprintf_append2n( & result, &outpos, zval_get_long(tmp), width, padding, alignment, 4, hexchars, expprec);
break;
case 'X':
php_sprintf_append2n( & result, &outpos, zval_get_long(tmp), width, padding, alignment, 4, HEXCHARS, expprec);
break;
case 'b':
php_sprintf_append2n( & result, &outpos, zval_get_long(tmp), width, padding, alignment, 1, hexchars, expprec);
break;
case '%':
php_sprintf_appendchar( & result, &outpos, '%');
break;
default:
break;
}

通过底层实现代码可以发现,sprintf()方法就是对15种类型做了匹配,15种类型以外的就直接break了没有做任何处理,所以就会导致一个问题:

如果我们输入"%\"或者"%1$\",他会把反斜杠当做格式化字符的类型,然而找不到匹配的项那么"%\","%1$\"就因为没有经过任何处理而被替换为空。

因此sprintf注入的原理就是

我们用一个15种类型之外的"\" 来代替格式字符类型让函数替换为空,则“%1$\'”后面的单引号就能闭合前面的单引号,以下是一些例子帮助我们更好的理解

#1.不带占位符的

<?php

$sql="select * from user where username='%\' and 1=1 #';";
$user='admin';
echo sprintf($sql,$user); ?>

运行结果:

select * from user where username='' and 1=1 #';

注意:username=''这里是两个单引号不是双引号

#2.带有占位符:

<?php
//addslashes()函数:在预定义前面加反斜杠,预定义符有单引号('),双引号("),反斜杠(\),NULL
$input = addslashes ("%1$' and 1=1#" );
$b = sprintf ("AND b='%s'", $input );
$sql = sprintf ("SELECT * FROM t WHERE a='%s' $b ", 'admin' );
//对$input与$b进行了拼接
//$sql = sprintf ("SELECT * FROM t WHERE a='%s' AND b='%1$\' and 1=1#' ", 'admin' );
//很明显,这个句子里面的\是由addsashes为了转义单引号而加上的,使用%s与%1$\类匹配admin,那么admin只会出现在%s里,%1$\为空
echo $sql ;
?>

运行结果:

SELECT * FROM t WHERE a='admin' AND b='' and 1=1#'

#3.%c的利用

<?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; ?>

运行结果:

select * from foo where bar in('') or 1=1 /*') and baz=39

0x04总结

漏洞利用条件

1、sql语句进行了字符拼接

2、拼接语句和原sql语句都用了vsprintf/sprintf 函数来格式化字符串

相关题目练习:https://blog.csdn.net/WQ_BCJ/article/details/85215662

解析php sprintf函数漏洞的更多相关文章

  1. PHP 函数漏洞总结

    1.MD5 compare漏洞 PHP在处理哈希字符串时,会利用"!="或"=="来对哈希值进行比较,它把每一个以"0E"开头的哈希值都解释 ...

  2. sprintf函数 %6.2f

    %6.2f6表示数据表示至少6位,后面的.2表示小数点后保留两位 比如2342.123415用这个表示的话,结果就是2342.12如果不足六位就会在前面补空格超过六位的话正常显示 代码例子:int m ...

  3. CVE-2012-0003 Microsoft Windows Media Player ‘winmm.dll’ MIDI文件解析远程代码执行漏洞 分析

    [CNNVD]Microsoft Windows Media Player ‘winmm.dll’ MIDI文件解析远程代码执行漏洞(CNNVD-201201-110)    Microsoft Wi ...

  4. php sprintf 函数的用法

    sprintf() 函数把格式化的字符串写入变量中. arg1.arg2.++ 参数将被插入到主字符串中的百分号(%)符号处.该函数是逐步执行的.在第一个 % 符号处,插入 arg1,在第二个 % 符 ...

  5. sprintf()函数的用法

    Visual C++ sprintf()函数用法 转:http://blog.csdn.net/masikkk/article/details/5634886 在将各种类型的数据构造成字符串时,spr ...

  6. sprintf函数

    sprintf函数用法举例 #include<stdio.h> int main() { //1.连接字符串 char a1[] = {'A', 'B', 'C', 'D', 'E', ' ...

  7. arduino上使用sprintf()函数输出float值出错

    如果尝试使用sprintf()函数在arduino上进行对float指转换为一个字符串的话,你会发现,it doesn't work.弄了很久,还以为是没学c++的原因.其实在arduino上,这个函 ...

  8. sprintf函数php的详细使用方法

    PHP sprintf() 函数 先说下为什么要写这个函数的前言,这个是我在微信二次开发的一个token验证文档也就是示例文档看到的一个函数,当时非常不理解,于是查了百度,但是很多结果都很笼统,结果也 ...

  9. [转]PHP echo, print, printf, sprintf函数的区别和使用

    1. echo函数: 输出函数,是命令,不能返回值.echo后面可以跟很多个参数,之间用分号隔开,如: echo $myvar1; echo 1,2,$myvar,"<b>bol ...

随机推荐

  1. JS多物体宽度运动案例

    任务 对于每一个Div区块,鼠标移入,宽度逐渐变宽,最宽值为400px,当鼠标移除时,宽度逐渐减小,最小值为100px. 任务提示: (1)多物体运动的定时器需要需要每个物体上同时最多只能开一个定时器 ...

  2. Linux内核调度分析(转,侵删)

    多任务 并发和并行 Linux作为一个多任务操作系统,必须支持程序的并发执行. 分类 非抢占式多任务 除非任务自己结束,否则将会一直执行. 抢占式多任务(Linux) 这种情况下,由调度程序来决定什么 ...

  3. linux系统克隆系统盘

    本文将介绍两种方式的系统盘的完整的备份,两种方式各有优缺点,需要根据实际情况来进行选择 使用dd的完整镜像克隆的方式 使用tar去备份数据,安装grub的方式 dd方式 优点: 简单,一条命令 dd ...

  4. C# 简易的串口监视上位机实现

    实现上位机和下位机之间的通信,通常使用的是串口通信,接下来实现一个通过上位机和串口调试助手来完成串口通信测试. 首先创建一个WInfrom窗体应用工程文件,创建过程可参考https://www.cnb ...

  5. [LeetCode题解]92. 反转链表 II | 一次遍历 + 反转

    解题思路 将链表分为三部分:[0, m).[m, n].(n, L],其中 L 为链表长度. 第一步:使用虚拟头节点 dummy,用于将 head 也能参与操作: 第二步:找到第 m-1 节点(fir ...

  6. Pinpoint 编译环境搭建(Pinpoint系列一)

    本文基于 Pinpoint 2.1.0 版本 目录 一.2.1.0 版本特性 二.编译环境准备 三.编译注意事项 四.编译目录 五.注意事项 新版本的内容参考官方文档, Pinpoint的整个搭建是历 ...

  7. nginx 负载均衡设置

    upstream lucky5{ server 127.0.0.1:3000 weight=10; server 127.0.0.1:3001 weight=5; } server{ location ...

  8. DNS域传输漏洞复现

    漏洞原理 DNS分类 常见的DNS记录类型 A IP地址记录,记录一个域名对应的IP地址 AAAA IPv6 地址记录,记录一个域名对应的IPv6地址 CNAME 别名记录,记录一个主机的别名 MX ...

  9. JVM学习之Java技术体系

    目录 一.Java技术体系 1.Java体系构成 2.JDK.JRE.JVM之前的关系 JVM介绍 (1)JVM官方文档定义 (2)中文解释 JVM结构 Java代码执行流程 JVM架构模型 1.指令 ...

  10. 去年去阿里面试,被问到ArrayList和LinkedList,我是这样回答的!

    前言 在一开始基础面的时候,很多面试官可能会问List集合一些基础知识,比如: ArrayList默认大小是多少,是如何扩容的? ArrayList和LinkedList的底层数据结构是什么? Arr ...