小迪安全46WEB 攻防-通用漏洞PHP 反序列化原生类漏洞绕过公私有属性

本文主要是介绍小迪安全46WEB 攻防-通用漏洞PHP 反序列化原生类漏洞绕过公私有属性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

#知识点:

1、反序列化魔术方法全解

2、反序列化变量属性全解

3、反序列化魔术方法原生类

4、反序列化语言特性漏洞绕过

-其他魔术方法

-共有&私有&保护

-语言模式方法漏洞

-原生类获取利用配合 

#反序列化利用大概分类三类

-魔术方法的调用逻辑-如触发条件

-语言原生类的调用逻辑-SoapClient

-语言自身的安全缺陷-CVE-2016-7124

#反序列化课程点:

-PHP&Java&Python

序列化:对象转换为数组或字符串等格式

反序列化:将数组或字符串等格式转换成对象

serialize() //将一个对象转换成一个字符串

unserialize() //将字符串还原成一个对象

#PHP 反序列化漏洞

原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而

导致代码执行,SQL 注入,目录遍历等不可控后果。在反序列化的过程中自动触发了某些

魔术方法。当进行反序列化的时候就有可能会触发对象中的一些魔术方法。

#魔术方法利用点分析:

触发:

unserialize 函数的变量可控,文件中存在可利用的类,类中有魔术方法:

__construct(): //构造函数,当对象 new 的时候会自动调用

__destruct()//析构函数当对象被销毁时会被自动调用

__wakeup(): //unserialize()时会被自动调用

__invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用

__call(): //在对象上下文中调用不可访问的方法时触发

__callStatci(): //在静态上下文中调用不可访问的方法时触发

__get(): //用于从不可访问的属性读取数据

__set(): //用于将数据写入不可访问的属性

__isset(): //在不可访问的属性上调用 isset


Ø 方法&属性-调用详解&变量数据详解

Ø CTF-语言漏洞-__wakeup()方法绕过

Ø CTF-方法原生类-获取&利用&配合其他


#方法&属性-调用详解&变量数据详解

对象变量属性:

public(公共的):在本类内部、外部类、子类都可以访问

protect(受保护的):只有本类或子类或父类中可以访问

private(私人的):只有本类内部可以使用

序列化数据显示:

private 属性序列化的时候格式是%00 类名%00 成员名

protect 属性序列化的时候格式是%00*%00 成员名

__destruct方法:

具体代码:

//__construct __destruct 魔术方法 创建调用__construct 2种销毁调用__destruct
class Test{public $name;public $age;public $string;// __construct:实例化对象时被调用.其作用是拿来初始化一些值。public function __construct($name, $age, $string){echo "__construct 初始化"."<br>";$this->name = $name;$this->age = $age;$this->string = $string;}// __destruct:当删除一个对象或对象操作终止时被调用。其最主要的作用是拿来做垃圾回收机制。//     * 当对象销毁时会调用此方法//    * 一是用户主动销毁对象,二是当程序结束时由引擎自动销毁//    *//*function __destruct(){echo "__destruct 类执行完毕"."<br>";}
}
// 主动销毁
$test = new Test("Spaceman",566, 'Test String');
unset($test);
echo '第一种执行完毕'.'<br>';
echo '----------------------<br>';
// 程序结束自动销毁
$test = new test("Spaceman",566, 'Test String');
echo '第二种执行完毕'.'<br>';

分析

__destruct:当删除一个对象或对象操作终止时被调用。其最主要的作用是拿来做垃圾回收机制    

一是用户主动销毁对象(unset),二是当程序结束时由引擎自动销毁

__toString方法

具体代码:

class Test
{public $variable = 'This is a string';public function good(){echo $this->variable . '<br />';}// 在对象当做字符串的时候会被调用public function __toString()
{return '__toString <br>';}
}$a = new Test();
$a->good();
//输出调用
echo $a;

在对象当做字符串的时候会被调用,即输出变量a——则表示以字符串的形式输出

__CALL方法:

具体代码:

class Test{public function good($number,$string){echo '存在good方法'.'<br>';echo $number.'---------'.$string.'<br>';}// 当调用类中不存在的方法时,就会调用__call();public function __call($method,$args){echo '不存在'.$method.'方法'.'<br>';var_dump($args);}
}$a = new Test();
$a->good(566,'nice');
$b = new Test();
$b->spaceman(899,'no');

调用某个方法, 若方法存在,则直接调用;若不存在,则会去调用__call函数。

__get()

具体代码:

class Test {public $n=123;// __get():访问不存在的成员变量时调用public function __get($name){echo '__get 不存在成员变量'.$name.'<br>';}
}$a = new Test();
// 存在成员变量n,所以不调用__get
echo $a->n;
echo '<br>';
// 不存在成员变量spaceman,所以调用__get
echo $a->spaceman;

读取一个对象的属性时,若属性存在,则直接返回属性值;若不存在,则会调用__get函数与__call方法类似,只不过是其对象属性

__set()方法

具体代码:

class Test{public $data = 100;protected $noway=0;// __set():设置对象不存在的属性或无法访问(私有)的属性时调用//__set($name, $value)// * 用来为私有成员属性设置的值// * 第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。public function __set($name,$value){echo '__set 不存在成员变量 '.$name.'<br>';echo '即将设置的值 '.$value."<br>";$this->noway=$value;}public function Get(){echo $this->noway;}
}$a = new Test();
// 读取 noway 的值,初始为0
$a->Get();
echo '<br>';
// 无法访问(私有)noway属性时调用,并设置值为899
$a->noway  = 899;
// 经过__set方法的设置noway的值为899
$a->Get();
echo '<br>';
// 设置对象不存在的属性spaceman
$a->spaceman = 566;
// 经过__set方法的设置noway的值为566
$a->Get();

设置一个对象的属性时,若属性存在,则直接赋值;若不存在,则会调用__set函数。

__sleep()方法:

具体代码:

class Test{public $name;public $age;public $string;// __construct:实例化对象时被调用.其作用是拿来初始化一些值。public function __construct($name, $age, $string){echo "__construct 初始化"."<br>";$this->name = $name;$this->age = $age;$this->string = $string;}//  __sleep() :serialize之前被调用,可以指定要序列化的对象属性public function __sleep(){echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>";// 例如指定只需要 name 和 age 进行序列化,必须返回一个数值return array('name', 'age');}
}$a = new Test("Spaceman",566, 'Test String');
echo serialize($a);

serialize之前被调用,可以指定要序列化的对象属性。

__wakeup方法:

具体代码:

class Test{public $sex;public $name;public $age;public function __construct($name, $age, $sex){$this->name = $name;$this->age = $age;$this->sex = $sex;}public function __wakeup(){echo "当在类外部使用unserialize()时会调用这里的__wakeup()方法<br>";$this->age = 566;}
}$person = new Test('spaceman',21,'男');
$a = serialize($person);
echo $a."<br>";
var_dump (unserialize($a));

Unserialize反序列化恢复对象之前调用该方法

__isset()方法

具体代码:

class Person{public $sex;private $name;private $age;public function __construct($name, $age, $sex){$this->name = $name;$this->age = $age;$this->sex = $sex;}// __isset():当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。public function __isset($content){echo "当在类外部使用isset()函数测定私有成员 {$content} 时,自动调用<br>";return isset($this->$content);}
}$person = new Person("spaceman", 25,'男');
// public 成员
echo ($person->sex),"<br>";
// private 成员
echo isset($person->name);

检测对象的某个属性是否存在时执行此函数。当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用

__unset()方法

具体代码:

class Person{public $sex;private $name;private $age;public function __construct($name, $age, $sex){$this->name = $name;$this->age = $age;$this->sex = $sex;}// __unset():销毁对象的某个属性时执行此函数public function __unset($content) {echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br>";echo isset($this->$content)."<br>";}
}$person = new Person("spaceman", 21,"男"); // 初始赋值
echo "666666<br>";
unset($person->name);//调用 属性私有
unset($person->age);//调用 属性私有
unset($person->sex);//不调用 属性共有

在不可访问的属性(private)上使用unset()时触发

__INVOKE()

具体代码:

class Test{// _invoke():以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用public function __invoke($param1, $param2, $param3)
{echo "这是一个对象<br>";var_dump($param1,$param2,$param3);}
}$a  = new Test();
$a('spaceman',21,'男');

将对象当做函数来使用时执行此方法,通常不推荐这样做。

#私有和公有属性——案例
public(公共的):在本类内部、外部类、子类都可以访问

protect(受保护的):只有本类或子类或父类中可以访问

private(私人的):只有本类内部可以使用

序列化数据显示:

private 属性序列化的时候格式是%00 类名%00 成员名

protect 属性序列化的时候格式是%00*%00 成员名

具体代码:

class test{public $name="xiaodi";private $age="29";protected $sex="man";
}
$a=new test();
$a=serialize($a);
print_r($a);

将age改为public

所以通常对于序列化的数据,要进行一次编码,要考虑到%00的因素

#CTF-语言漏洞-__wakeup()方法绕过——案例

https://buuoj.cn/challenges

通过路径扫描,扫到一个www.zip的地址,访问便可进行下载去文件

此页面以GET方式select的变量接收,根据代码逻辑,得知__destruct方法在程序结束后被调用且password需等于100,__construct方法用new进行构造接收name和password 的值,__wakeup方法,在使用unserializ后自动调用,此时这里就出现了问题

我们要的是admin,而自动调用的是wakeup方法里的guest,那么就需想想wakeup方法该怎么绕过,通过历史漏洞得知——语言特性漏洞

靶场PHP版本符合

即将构造的序列化,变量个数改为3个,符合条件即可

(修改原理)

成功

#CTF-方法原生类-获取&利用&配合其他 

参考:浅析PHP原生类-安全客 - 安全资讯平台

版本会与原生类有直接的关系

-PHP有那些原生类-见脚本使用

Get.php

<?php
$classes = get_declared_classes();
foreach ($classes as $class) {$methods = get_class_methods($class);foreach ($methods as $method) {if (in_array($method, array('__destruct','__toString','__wakeup','__call','__callStatic','__get','__set','__isset','__unset','__invoke','__set_state'))) {print $class . '::' . $method . "\n";}}
} 

会将魔术方法里自带的类给打印出来

-常见使用的原生类-见参加案例

1.ctf-xss

从此代码可以猜测要用的方法可能是To_string,由于它的本身代码就只有这一点,那么无法通过其他对象进行触发To_string,故需要用原生类的To_string,通过get.php,可以得到相关的To_string对象

Exception对象

对其进行构造,并加入xss攻击

成功

2.Ctfshow259

由于此题的getflag();方法,不知道它的具体是什么才可触发,所以先把它姑且为不可访问的类型,也就是可被__call()、__get()所触发,

查看自身的原生类

对其进行搜索

找到构造payload(题目中要求,ip为127.0.0.1,token为ctfshow)

将flag.txt发送到本地

-原生类该怎么使用-见官方说明

0、生成原生类

补:phar、字符串逃逸

反序列化:自身不是漏洞,只是一种方法,在方法中会引发一些危险函数。

这篇关于小迪安全46WEB 攻防-通用漏洞PHP 反序列化原生类漏洞绕过公私有属性的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/845538

相关文章

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程

《在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程》本文介绍了在Java中使用ModelMapper库简化Shapefile属性转JavaBean的过程,对比... 目录前言一、原始的处理办法1、使用Set方法来转换2、使用构造方法转换二、基于ModelMapper

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

SQL注入漏洞扫描之sqlmap详解

《SQL注入漏洞扫描之sqlmap详解》SQLMap是一款自动执行SQL注入的审计工具,支持多种SQL注入技术,包括布尔型盲注、时间型盲注、报错型注入、联合查询注入和堆叠查询注入... 目录what支持类型how---less-1为例1.检测网站是否存在sql注入漏洞的注入点2.列举可用数据库3.列举数据库

Java如何通过反射机制获取数据类对象的属性及方法

《Java如何通过反射机制获取数据类对象的属性及方法》文章介绍了如何使用Java反射机制获取类对象的所有属性及其对应的get、set方法,以及如何通过反射机制实现类对象的实例化,感兴趣的朋友跟随小编一... 目录一、通过反射机制获取类对象的所有属性以及相应的get、set方法1.遍历类对象的所有属性2.获取

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

PHP执行php.exe -v命令报错的解决方案

《PHP执行php.exe-v命令报错的解决方案》:本文主要介绍PHP执行php.exe-v命令报错的解决方案,文中通过图文讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下... 目录执行phpandroid.exe -v命令报错解决方案执行php.exe -v命令报错-PHP War