PDO的参数绑定问题
根据一个实际的例子
基于古老的speed框架开发的一套cms,大概搜索了一下,网上还挺多
框架流程
框架入口就是直接包含一个类库文件

此类库是相当的精简
三个类吧
控制器controller类、视图view类、数据库操作model类
view视图的解析,类似于thinkphp
看一下,model类
存在PDO的时候,采用PDO连接
1 | public function dbInstance($db_config, $db_config_key, $force_replace = false){ |
PDO在php5.0以上均可配置
通过execute和query执行SQL语句

一般情况下,这种都是key存在某些问题,或者对数组型参数值的处理不当
很是很可惜,对于参数值,都经过了转义处理
所以只能从key下手,跟进其插入语句的组装方法
可以很明显的看到,当$row完全可控时,可以控制键名达到注入的效果

这是这就一帆风顺了嘛,no no no!
错误整理
因为很明显这里进行了参数的绑定,而且和tp自定义的绑定名字不同,这里直接就用的键名
比方说给键名加一个单引号,不是报的语法错误
而是,参数绑定的问题

各种类型的报错吧,
- 参数绑定个数不匹配
- 绑定参数找不到
- …….
经过测试
在绑定的参数中一般为字母数字下划线,存在其他字符时,会找不到绑定的参数
这里就来探讨一种可以用于key注入的参数绑定的payload
探究key注入的payload
PDO知识整合
- 其实
PDO的模拟预处理,是把整条语句发送给mysql去执行 - 如果不支持多行查询,语句中存在多行,直接抛出异常
- 语句中存在占位符,
?或者:title形式都为占位符,最后是要替换掉 - 第二种占位符不能有特殊字符
首先,漏洞的触发点如下
1 | function actionAdd(){ |
这种代码并不少见
难点
- 因为绑定的参数值,不是如
tp那样固定得,而是根据传参决定的,导致闭合原有语句困难
还有一个点就是在PDO不支持多行的条件下,是否可以传入多语句的问题
感觉,实际cms的测试效果不是很好自己写个demo
1 |
|
会有如下报错

这个就和thinkphp的报错极为类似了,就是说这配置了不允许模拟预编译的情况下,是不允许多行语句的存在的
堆叠查询
在支持堆叠的情况下,操作简单了不少,主要是插入想要的数据就可以
PDO的堆叠查询,只会返回第一个语句的执行结果
不用考虑闭合的问题
首先把空格替换成/**/
经过fuzz发现--和/*放在分号后面,可以让PDO的参数绑定成功

比较需要注意的一点是
- 此两种方式需要在
php5.6以上
在php5.4中依旧会报如下错误

再次进行fuzz
很明显,上面是成功的payload,有个共同的特征,结束的组合为'--,成功绑定并注入

而且此方式在php5.6以上也可以使用
需要说明的是此处的--很明显没有注释作用,具体为什么,还需要看PDO的源代码,这里从fuzz角度测试
payload
1 | # tilte是一个已知字段 |
非堆叠查询
根据刚才对PDO禁止了模拟预编译之后,可以知道,直接就不允许传入多行语句
但是有一点,就是他报错的位置
报错位置不是分号,说明是允许分号的存在的
再次测试
发现,当存在#或者-- 注释符号的时候,会通过预处理(此处的–后面有空格)

那就比较容易构造了

但是这样会报错,因为在键名中的空格被替换成了下划线
然后提几个php中关于键名的tips
- 传参名的空格会被转化成下划线
- 传参名的点号会被转化成下划线
- 为了取数组型参数,
[后面的字符不予转化
所以进行如下构造

payload
1 | title`)/**/values/**/(updatexml(1,concat(0x7e,user()),'['));-- =aaa |
那么要想包含php5.4的多行的
一个通用payload
1 | title`)/**/values/**/(updatexml(1,concat(0x7e,user()),'['));-- '--=aaa |

end
此结果值针对与此场景
实际网站演示













