一、序列化
1.序列化示例:
空字符 null->N;
整形 666->i:666;
浮点型 66.6->d:66.6;
Boolean型 true->b:1;
false->b:0;
字符串 'benben'->s:6:"benben";
2.序列化php运行
- 数组序列化
- 对象序列化
当private私有属性序列化时在变量名前加“%00类名%00”
当protected受保护属性序列化时在变量名前加“%00*%00”
- 序列化中包含序列化
o:5:"test2":1:{s:3:"ben";o:4:"test":1:{s:3:"pub";s:6:"benben";}}
二、反序列化
1.反序列化之后的内容为一个对象
2.反序列化生成的对象里的值,由反序列化里的值提供;与原有的类预定类的值无关;
3.反序列化不触发的成员方法;需要调用方法后才能触发
示例解析:
1.反序列化之后的内容为一个对象
2.反序列化生成的对象里的值,由反序列化里的值提供;与原有的类预定类的值无关;
3.反序列化不触发的成员方法;需要调用方法后才能触发
三、反序列化漏洞
四、魔术方法
- 什么是魔术方法?
一个预定义好的,在特定情况下自动触发的行为方法。
- 魔术方法的作用?
魔术方法在特定条件下自动调用相关方法,最终导致触发代码。
- 魔术方法的相关机制?
__construct(),类的构建函数
__destruct(),类的析构函数
__sleep(),执行serialize()时,先会调用这个函数
__wakeup(),执行unserialize()时,先会调用这个函数
__toString(),类被当作字符串时的回应方法
__invoke,调用函数的方式调用一个对象时的回应方法
1.__construct(),类的构建函数
实例化对象时触发构造函数__construct()
2.__destruct(),类的析构函数
实例化对象结束后,代码运行完全销毁,触发析构函数__destruct()
3.漏洞示例:
利用了__destruct()的特性,当实例化对象结束后,进行unserialize结束时,就会销毁代码,触发__destruct()
3.__sleep(),执行serialize()时,先会调用这个函数
序列化serialize()函数会检查当中是否存在一个魔术方法__sleep。(触发时机:在序列化serialize()之前)
如果存在,该方法会先被调用,然后才执行序列化操作。
4.__wakeup(),执行unserialize()时,先会调用这个函数
unserialize()会检查是否存在一个__wakeup()方法。(触发时机:反序列化unserialize()之前)
如果存在,则会先调用__wakeup()方法,预先准备对象需要的资源。
5.__toString(),类被当作字符串时的回应方法
表达方式错误导致魔术方法触发
6.__invoke,调用函数的方式调用一个对象时的回应方法
格式表达错误导致魔术方法触发
7.错误调用相关魔术方法
1.__call()
调用一个不存在的方法
2.__callStatic()
静态调用或者调用成员常量的时候使用的方法不存在
3.__get()
调用的成员属性不存在
4.__set()
给不存在的成员属性赋值
5.__isset()
对不可访问的属性使用isset()或empty()时,isset()会被调用
6.__unset()
对不可访问的属性使用unset()时,unset()会被调用
7.__clone()
当使用clone关键字拷贝完成一个对象后,新对象会自动调用定义的魔术方法__clone()
五、pop链前置知识1(了解调用链)
反推法:
1.可利用漏洞点在函数eval()【可执行指令】
2.eval()调用$test2
3.反序列化unserialize()触发魔术方法destruct()
4.destruct()从$test()调用action()
关键点:如何让$test调用evil里的成员方法action()
解决思路:给$test赋值为对象 test = new evil()
构造pop(方法一):
构造pop(方法二):
六、pop链前置知识2(魔术方法的触发规则)
魔术方法触发前提:魔术方法所在类(或对象)被调用
目标:不触发__wakeup方法
目标:触发__tostring方法并输出tostring is here!!
目标:触发__tostring方法和__wakeup方法并输出tostring is here!!和wakeup is here!!
七、POP链构造、POC编写
1.POP链
在反序列化中,能控制的数据就是对象中的属性值(成员变量),所以在PHP反序列化中有一种漏洞利用方法叫“面向属性编程”,即POP
POP链就是利用魔法方法在里面进行多次跳转然后获取敏感数据的一种payload。
2.POC编写
POC中文译作概念验证。在安全界可以理解成漏洞验证程序。POC是一段不完整的程序,仅仅是为了证明提出者的一段代码。
例题:
目标:触发echo,调用$flag
步骤:1.触发invoke,调用append,并使$var=flag.php
2.invoke触发条件:把对象当作函数
3.给$p赋值为对象,即function成为对象Modifier,却被当成函数调用,触发Modifier中的invoke
4.触发get方法(触发条件:调用不存在的成员属性)
5.给str赋值为对象Test,而Test中不存在成员属性source,则可触发Test里的成员方法get
6.触发toString(触发条件:把对象当成字符串)
7.给source赋值对象Show,当成字符串被echo调用,触发toString
8.触发wakeup(触发条件:反序列化unserialize)
构造pop链:
八、字符串逃逸基础(字符减少)
1.反序列化分隔符
反序列化以;}结束,后面的字符串不影响正常的反序列化
2.属性逃逸
一般在数据先经过一次serialize在经过unserialize,在这个中间反序列化的字符串变多或者变少的时候有可能存在反序列化属性逃逸
例题:
例题:
1.判断过滤后减少还是增多
2.构造出关键成员属性序列化字符串
$vip=true
3.变少判断吃掉的内容,并计算长度
即:user=flagflagflagflagflagflagflagflagflagflag&pass=1";s:4:"pass";s:6:"benben";s:3:"vip";b:1;}
九、字符串逃逸基础(字符增多)
例题:
目标:判断是否pass=='escaping'
1.定位目标逃逸代码($user值可控)
2.new test($param)时触发test类中的__construct魔法方法,赋值给$user
O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}
3.得到flag.php
十、wakeup绕过
如果存在__wakeup方法,调用unserilize()方法之前先调用__wakeup方法,但是序列化字符串中表示对象属性个数的值大于真实属性个数时,会跳过__wakeup的执行。
构造POP链 再进行url编码
得到flag
十一、引用的利用方式
题目说明:
要求secret和enter的值相等,而secret等于*,要让enter的值也等于*
做法:引用的方式(使secret与enter的值恒等于)
得到flag:
十二、session反序列化
session
当session_star()被调用或者php.ini中session.auto_start为1时,PHP内部调用会话管理器,访问用户session被序列化以后,存储到指定目录(默认为/tmp)
漏洞产生:写入格式和读取格式不一致
第一种格式:PHP
第二种格式:PHP_serialize
第三种格式:PHP_binary
session反序列化漏洞例题:
save.php:(提交页面)
vul.php:(执行页面)
当当站序列化并存储session,与反序列化并读取session的方式不同,就可能导致session反序列化漏洞的产生。
1.首先将要执行的语句进行序列化
2.可以看到上传页面是使用php_serialize方式存储,构造pyload:
?a=|O:1:%22D%22:1:{s:1:%22a%22;s:13:%22system(%27id%27);%22;}
3.运行页面使用php方式存储,刷新页面得到答案
session例题:
1.首先看题分析题目要求name=her,而her是从1-10000中随机抽取并进行md5加密的数值,这里考虑用到引用的方式进行赋值。
2.得到后看到页面有hint.php页面,进入后显示可以进行提交,并提示是session读取漏洞
3.将得到的pyload进行构造 提交到页面中
4.返回index页面 刷新页面得到flag
十三、phar反序列化
phar是php里类似于jar的一种打包文件。
文件包含:phar伪协议,可读取 .phar文件
phar结构
manifest压缩文件的属性等信息,以序列化存储
phar协议解析文件时,会自动触发对manifest字段的序列化字符串进行反序列化
例题:
原理:
phar使用条件:
1.phar文件能上传到服务器端
2.要有可用的反序列化魔术方法作为跳板
3.要有文件操作函数,如file_exists、fopen()、file_get_contents()
4.文件操作函数参数可控,且:、/、phar等特殊字符没有被过滤
phar反序列化漏洞:
目标:echo $flag
反序列化TestObject()触发__destruct执行echo $flag
$POST提交file赋值$filename
if判断语句isset判断$filename内容生成md5哈希值
测试:file=/etc/passwd
判断是否可以用phar反序列化:可以
写入文件:text.phar
更改为text.jpg(文件后缀不影响运行) 得到flag