Thinkphp3.2.3 SQL注入漏洞
下载:ThinkPHP3.2.3完整版 - ThinkPHP框架
配置
ThinkPHP/Conf/convention.php
配置下数据库,我这里直接用的sqllabs的数据库
写个查询入口Application/Home/Controller/IndexController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {public function index(){highlight_file(__FILE__);$data = M('users')->find(I('GET.id'));var_dump($data);}
}
用的是users表
thinkphp3内置了很多大写函数
A 快速实例化Action类库
B 执行行为类
C 配置参数存取方法
D 快速实例化Model类库
F 快速简单文本数据存取方法
I 获取系统输⼊变(与tp5input方法类似)
L 语言参数存取方法
M 快速高性能实例化模型
R 快速远程调用Action类方法
S 快速缓存存取方法
U URL动态生成和重定向方法
W 快速Widget输出方法
常规注入
既然审计SQL注入漏洞了,那常规的注入方式1' or 1=1#
肯定是不行的了,但具体为什么不行这里简单的分析下
int型
id若是int类型的,会经过intval()
处理,最后1' or 1=1#
就变成了1
,看下大体流程
I方法
首先是进入D方法
但D方法就是实例化⾃定义模型类,没啥东西,就直接调到I方法
了,I方法前边也是一些常规操作,跟一边就能看懂很容易理解,直接看下边的取值部分
经过前边的一系列操作后,$input
的值就是我们传入的1' or 1=1#
,$name
就是id,$filters
取得是默认值htmlspecialchars
,之后就进入了下边的一些没影响的if判断和操作
进到这里,判断$data
是否为数组(很明显不是),所以$data的值就是htmlspecialchars(1' or 1=1#)
, htmlspecialchars
不会处理单引号所以经过此次过滤后,其实$data的值并没变
最后经过一系列判断retrun $data;
了
find方法
retrun给了find方法,还是跳过没影响的部分,$options
的值就是retrun $data;后来又经过746这行加了个limit
直接进入_parseOptions()
前边通过$options['table'] = $this->getTableName();
,获取了表名users,之后就进入了_parseType()
方法
跟进后先看下执行到683行的值$data[$key]=$data[id]=1' or 1=1#
之后经过了if判断,由于id定义的是int型,所以这里直接就执行intval了,id的值就变成了1,所以这里无法闭合也就结束了
varchar型
int型不行后我又改成了varchar类型(修改时需要关闭AUTO_INCREMENT选项)
接着上边的分析,在经过_parseType()
方法后,下边又执行了select()
在经过944行的parseBind
后,id的值仍为1' or 1=1#
,但经过945后,值发生转义了,所以跟进一下buildSelectSql()
方法
跟进parseSql()
我们的值在where里所以直接跟进parseWhere
这一条
parseWhere
中会执行parseWhereItem
,之后又会执行parseValue
进入第一个if会执行 $this->escapeString($value) : '\''.$this->escapeString($value).'\'';
escapeString对单引号进行转义,所以这里varchar型也就失败了
public function escapeString($str) {return addslashes($str);
}
数组绕过
传入?id[where]=1
I方法
前边都一样,在最后retrun的前一步由于本次传入的是数组,所以进入了think_filter
方法
但其实也没啥东西只对开头部分做检测,根本不需要绕过
function think_filter(&$value){// TODO 其他安全过滤// 过滤查询特殊字符if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){$value .= ' ';}
}
之后就还是进入_parseOptions()
,再次看_parseType()
这部分,注意options的值,前后对比:
之前:
现在:
很明显where不是数组了,所以在经过第一条if检测时就不满足is_array($options['where'])
了,所以这里就绕过了_parseType()
,从而就绕开了int型中提到的intval
转换
if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) {
之后就是解决第二个问题——varchar类型中的escapeString()
转义。前边的select()->buildSelectSql()->parseSql()
就不说了跟之前都一样,直接看parseWhere()
这里
protected function parseWhere($where) {$whereStr = '';if(is_string($where)) {// 直接使用字符串条件$whereStr = $where;}else{ // 使用数组表达式
之前是由于where是数组进入了else再执行一步步操作后,执行到了escapeString()
,但这里where变成了字符串所以直接就走if里的语句了,执行后就直接retrun返回了
在执行完parseSql()
后,看下returun返回值SELECT * FROM
usersWHERE 1 LIMIT 1
之后就返回到select中被query成功执行了
payload
?id[where]=0 union select 1,group_concat(username,0x2a,password),3 from users#
?id[where]=1 and 1=updatexml(1,concat(0x7e,(select password from users limit 1),0x7e),1)#
EXP注入
改下controller
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {public function index(){highlight_file(__FILE__);$User = D('Users');$map = array('username' => $_GET['username']);// $map = array('username' => I('username'));$user = $User->where($map)->find();var_dump($user);}
}
先贴payload:
?username[0]=exp&username[1]==-1 union select 1,2,3
exp注入这里用到的是where、而之前数组注入时用的是I方法
,原因在于若执行I方法
,会执行到think_filter
对exp开头的数据进行过滤,而从payload也可以看出这里是以exp开头的,所以这里选用了where
方法
先看where方法
,这里直接跳到最后(因为前边的if判断都没有执行),这里通过值也能看出,其实就是我们GET传参的内容
之后的操作就一样了,到find()
方法,执行_parseOptions()
,然后就到了下边这里,通过foreach将$options[‘where’]的值给$val
再通过is_scalar($val)
进行标量 (integer、float、string 或 boolean)
判断,很明显$val是数组不是标量,所以直接绕过了_parseType()
,也就绕开了intval
转换
之后又一样了,select()->buildSelectSql()->parseSql()->parseWhere()
,再执行parseWhereItem()
,正则部分为false,所以直接跳到了下方的elseif,对$whereStr赋值,此时$key=username $var[1]=“=-1 union select 1,2,3”,所以最终的$whereStr=username=-1 union select 1,2,3
最终就是return 一步步返回 成功执行sql语句
SELECT * FROM `users` WHERE `username` =-1 union select 1,2,3 LIMIT 1
payload
http://127.0.0.1/thinkphp/tp3.2.3/?username[0]=exp&username[1]==1 and updatexml(1,concat(0x7e,user(),0x7e),1)
BIND注入
还是先写controller
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {public function index(){highlight_file(__FILE__);$User = M("Users");$user['id'] = I('id');$data['password'] = I('password');$value = $User->where($user)->save($data);var_dump($value);}
}
先执行where()
,跟之前一样
之后就是save()
方法,416又看到了我们熟悉的方法_parseOptions
,还是跟之前一样将$options
和$this->$options
合并给$options
这里就不看了
继续向下执行进入451行的update()
方法,主要是这几个方法一个个看一下。
跟进parseSet()
跟进bindParam()
,$value
就是之前传入的$password
的值——1
,执行结束后bind[:0]=1
protected function bindParam($name,$value){$this->bind[':'.$name] = $value;
}
再跟进parseWhere()->parseWhereItem()
,这里跟exp注入是一样的,主要区别在于elseif这里,之前$exp=exp
,这里$exp=bind
,最后拼接后的$whereStr
值在下边
结束后进入execute
先看①处的闭包
array_map
function add2($value) {return $value + 2;
}$arr = array(1, 2, 3, 4, 5);$result = array_map(add2, $arr);print_r($result);
结果
Array
([0] => 3[1] => 4[2] => 5[3] => 6[4] => 7
)
所以这里就是对$this->bind()
执行闭包中的操作,bind的值为1,所以就相当于$val=1执行了function($val) use(\$that){ return '\''.$that->escapeString($val).'\''; }
,而1
执行escapeString()
后,返回结果还是1
最后再加上前后的单引号就变成了 ‘1’
即bind[:0]=1
变为bind[:0]='1'
strtr
所以源代码中的strtr部分经过array_map
,就可以理解为这种形式
strtr($this->queryStr,":0"=>"1");
执行后将$this->queryStr
中的:0
替换成了1
,这也就是payload中是0而不是其它值的原因
替换后的$this->queryStr
UPDATE `users` SET `password`='1' WHERE `id` = '1' and updatexml(1,concat(0x7e,user(),0x7e),1)
最后就成功执行了
总结
看似三个链子很长,其实都是常规注入流程的一种bypass扩展,并且在代码上经过调试也能慢慢理解,tp小白不足之处敬请师傅指点。
thinkphp3.2.3 SQL注入漏洞复现_bfengj的博客-CSDN博客_thinkphp3.2.3漏洞利用工具
ThinkPHP中的常用方法汇总总结:M方法,D方法,U方法,I方法 - 谦信君 - 博客园 (cnblogs.com)
Thinkphp3.2.3 SQL注入漏洞相关推荐
- ThinkPHP3.2 框架sql注入漏洞分析(2018-08-23)
0x00 前言 北京时间 2018年8月23号11:25分 星期四,tp团队对于已经停止更新的thinkphp 3系列进行了一处安全更新,经过分析,此次更新修正了由于select(),find(),d ...
- 从一个Laravel SQL注入漏洞开始的Bug Bounty之旅
事先声明:本次测试过程完全处于本地或授权环境,仅供学习与参考,不存在未授权测试过程.本文提到的漏洞<Cachet SQL注入漏洞(CVE-2021-39165)>已经修复,也请读者勿使用该 ...
- 易想团购 注入 user.php,易想团购系统通杀SQL注入漏洞分析及利用漏洞预警 -电脑资料...
刚打开红黑看到J8基友写的一个{易想团购系统 最新版 通杀}的文章,看他贴的代码里面有个get_client_ip()函数,哈哈,我猜没过滤,果断下了一套程序, 找到get_client_ip()函数 ...
- SQL注入漏洞的检测与防范技术
提 要 本文从SQL注入的基本概念和注入原理入手,分析总结了SQL注入漏洞的检测及其防范技术措施. 关键词 SQL注入漏洞 检测 防范技术 引 言 近几年来随着计算机网络和WEB技术的飞速 ...
- Apache 'mod_accounting'模块SQL注入漏洞(CVE-2013-5697)
漏洞版本: mod_accounting 0.5 漏洞描述: BUGTRAQ ID: 62677 CVE ID: CVE-2013-5697mod_accounting是Apache 1.3.x上的流 ...
- guestbook.php注入,TinyGuestBook 'sign.php'多个SQL注入漏洞
发布日期:2012-09-23 更新日期:2012-10-04 受影响系统: TinyGuestBook TinyGuestBook 描述: ----------------------------- ...
- thinkphp日志泄漏漏洞_ThinkPHP框架通杀所有版本的一个SQL注入漏洞详细分析及测试方法...
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件 根据官方文档对"防止SQL注入" ...
- Backtrack5 SQL注入漏洞探测
SQLMAP,它是一个自动化的SQL注入工具,其主要功能是扫描,发现并利用给定的URL的SQL注入漏洞,目前支持的数据库是MS-SQL,,MYSQL,ORACLE和POSTGRESQL. SQLMAP ...
- WEB安全:XSS漏洞与SQL注入漏洞介绍及解决方案
对web安全方面的知识非常薄弱,这篇文章把Xss跨站攻击和sql注入的相关知识整理了下,希望大家多多提意见. 对于防止sql注入发生,我只用过简单拼接字符串的注入及参数化查询,可以说没什么好经验,为避 ...
- WordPress ProPlayer插件‘id’参数SQL注入漏洞
漏洞名称: WordPress ProPlayer插件'id'参数SQL注入漏洞 CNNVD编号: CNNVD-201305-468 发布时间: 2013-05-22 更新时间: 2013-05-22 ...
最新文章
- linux重启后出现control+D错误的解决
- SQL调优--记一次表统计信息未及时更新导致查询超级慢
- 0726------Linux基础----------线程池
- 基于SSD的自动路径规划算法
- 学习笔记之12个月提升计划
- dataset的去重计数 g2_AntV 架构演进-G2 篇
- Linux-Ubuntu下设置ufw防火墙
- RPC框架的使用场景
- 测试结果OK、NG、NT、POK的意思
- 单片机 74HC595 实例
- Spacy分词php,spaCy 第二篇:语言模型
- 基于Linux下的即时通讯聊天室项目(全代码 有注释 可直接运行)
- leetcode题目-最小栈和用两个栈实现队列
- 从0带你写插件之微信防撤回,保姆级教学代码一行一行解读
- JWS 批注参考WebService注解
- 【硬核】年底绩效面谈,涨薪,老板给加了1万块
- Lesson Forty-Seven A cup of coffee. 一杯咖啡.
- AOP相关术语(连接点、切入点、通知、引介、目标对象、织入、代理、切面)
- ACM各种输入模式总结(C++)
- 仓库基础知识之什么是SPU、SKU、ARPU
热门文章
- 线程的同步互斥之事件对象(Event)
- 树状数组--前n项和;
- 数字信号C语言——平均分布随机数
- 服务器互相备份不同步_94爱分享拍了拍你,这款好用的数据同步备份软件千万不要错过!...
- github客户端进行token认证
- 单主机多git账户多rsa密钥+根据私钥生成公钥+knownhosts+.git/config相关配置
- CentOS-7 安装mosquitto(MQTT的开源消息代理)
- Microsoft SQL Server Protocols
- java+junit百科_JUnit介绍
- qt测试代码运行时间