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
此结果值针对与此场景
实际网站演示