首页 > 编程语言 >python原型链污染

python原型链污染

时间:2024-07-10 22:31:30浏览次数:22  
标签:__ python dst merge 污染 globals 原型 模块 字典

python原型链污染

原型链污染

  • python中,对象的属性和方法可以通过原型链来继承和获取
  • 每一个对象都有一个原型,定义了其可以访问的属性和方法,所以可以通过修改原型链中的属性来利用漏洞攻击
  • 当对象访问属性或方法时,会先对自身进行查找,找不到就一次往上级查找
  • 只能污染类的属性,不能污染类的方法

污染条件

merge合并函数,用merge函数来修改父类函数

原型链污染

def merge(src, dst):  #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)

合并过程,先判断dst目标字典是否为字典形式

是字典形式

  • 如果是字典形式,k存在,且值为字典,合并嵌套字典
  • 如果是字典形式,k不存在,或值不是字典,将键值对 (k, v) 添加到 dst

如果dst并不是字典是类

  • 类的形式,存在属性k且为字典,合并字典
  • 类的形式,不存在属性k,或者k值不是字典,dst将添加k,设置值为v
分析
class father:
    secret = "hello"

class son_a(father):
    pass

class son_b(father):
    pass

def merge(src, dst):
    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)


instance = son_b()
payload = {
    "__class__": {
        "__base__": {
            "secret": "world"
        }
    }
}
print(son_a.secret)
print(instance.secret)
merge(payload, instance)
print(son_a.secret)
print(instance.secret)

image-20240710165425278

merge(payload, instance)payload为原字典,instance为目标字典

instance是对象类型,则判断语句为

elif hasattr(dst, k) and type(v) == dict:
    merge(v, getattr(dst, k))
  • 第一次递归:执行语句 merge(v, getattr(dst, k))

因为instance=son_b,所以当instance与__class__合并时,其属性就变成了instance对象所属的类son_b

  • 第二次递归:执行语句 merge(v, getattr(dst, k))

接着与 __base__合并,属性就变成了son_b所属类的父类father

  • 第三次递归:执行语句为 type(v) == dict结果为FALSE,因为 v=world不是字典型,递归结束,执行语句 setattr(dst, k, v)。此时father的属性被重置为 world

__base__继承关系获取目标类

如果我们想要污染的目标类 和 作为切入点的类,两者没有父子继承关系,就无法使用 __base__

获取全局变量

__init__,__globals__

__init__初始化方法,类的内置方法

__globals__返回字典,包含该函数所在模块的全局变量

image-20240710201044949

返回True,代表demo.__globals__globals() 以及 A.__init__.__globals__ 三者相等

  • demo.__globals__demo函数的全局命名空间,因为德莫实在全局命名空间时定义的,所以 demo.__globals__ 等于 全局命名空间 globals()
  • A.__init__.__globals__是类A.__init__的全局命名空间 = globals()
#demo.py
a = 1

def merge(src, dst):
    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)


def demo():
    pass


class A:
    def __init__(self):
        pass


class B:
    classa = 2


instance = A()
payload = {
    "__init__": {
        "__globals__": {
            "a": 4,
            "B": {
                "classa": 5
            }
        }
    }
}
print(B.classa)
print(a)
merge(payload, instance)
print(B.classa)
print(a)

image-20240710202924509

获取其他模块

以上实例是基于,操作对象或者类是在入口文件当中,如果目标对象不在入口文件中,需对其他啊记载过的模块进行获取

import模块加载获取

通过payload模块重新定位加载

image-20240710211347150

sys模块加载获取

引用sys模块下的module属性,这个属性能够加载出来在自运行开始所有已加载的模块,从而我们能够从属性中获取到我们想要污染的目标模块

同样用其加载demo.py

image-20240710211329951

注:在使用payload传参时,需要在有源码的基础上传参

加载器loader获取

通过 loader.__init__.__globals__['sys']来获取sys模块

(loader加载器的作用是实现模块加载,在内置模块importlib中具体实现,而importlib模块下所有的py文件中均引入了sys模块)

image-20240710212814103

math模块的__loader__属性包含了一个loader对象,负责加载math模块

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

函数形参默认值替换

__defaults__元组,储存函数或方法的默认参数值,定义函数时,可为其参数指定默认值

image-20240710213640756

标签:__,python,dst,merge,污染,globals,原型,模块,字典
From: https://www.cnblogs.com/Yolololo/p/18295135

相关文章

  • Python潮流周刊的优惠券和精美电子书(EPUB、PDF、Markdown)
    Python潮流周刊从2023.05.13连载至今,本周即将发布第60期,这意味着我们又要达成一个小小的里程碑啦!每周坚持做分享,周复一周,这对自己的精力和意志是一项不小的挑战。于是,为了让自己获得一些仪式感,我给自己定了一个较为合理的时间目标,就是每30期周刊作为一季。划分出“每一季......
  • Python 数组类型转树形结构
    今天突然想用到这个功能 结果百度到的 基本是写乱糟糟的一堆代码 无奈只好亲自操刀话不多说,先上代码:classTools:@staticmethoddeflist_to_tree(data,pid=0):children=[itemforitemindataifitem['pid']==pid]forchildinchi......
  • Python 数据挖掘
    数据挖掘基础数据挖掘:这种从数据中“淘金”,从大量数据(包括文本)中挖掘出隐含的、未知的、对决策有潜在价值的关系、模式和趋势,并用这些知识和规则建立用于决策支持的模型,提供预测性决策支持的方法、工具和过程,就是数据挖掘;它是利用各种分析工具在大量数据中寻......
  • Python Selenium+cookie+XPATH爬取数据
    以某科研基金信息平台为例,写了一个基于selenium的web自动化爬虫。不带验证码防反爬以及代理ip池,是最基础的自动化工具爬虫。一、首先,此平台需要登录后才能正常访问,否则数据不全,因此需要登录后获取cookie,以便selenium能够以登录状态运行1.F12打开开发者工具,找到network(网络),在登录......
  • Python中的元组:为什么它们比列表更快?
    引言        在Python编程语言中,数据结构是存储和组织数据的强大工具。Python提供了多种内置数据结构,如列表(List)、字典(Dictionary)、集合(Set)等。元组(Tuple)是其中一种非常重要的数据结构,它因其独特的特性和用途,在Python编程中占有一席之地。一、元组的定义     ......
  • 【每日一练】python文件读.写.追加基本用法
    """本节课程内容:1.打开一个文件,模式为写入2.用传参方式写入文件内容3.如何追加文件内容4.如何读取新写入的文件5.牢记操作完一定要关闭程序使用close()函数Ps:如果写完文件后就读取文件,需要使用seek(0)把指针复位到开头。否则,下面读取文件为空,因为写完后指针会停留在尾......
  • python+flask计算机毕业设计小型社区疫情期间应急线上管理系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着全球疫情的持续蔓延,小型社区作为社会的基本单元,其疫情防控能力直接关系到居民的生命安全与社会的稳定。疫情期间,传统的管理方式面临诸......
  • TIOBE 7月编程排行榜出炉!Python再次出圈
    又到了周三,本周有过半了,大家好呀~~每月的TIOBE编程排行榜都是技术社区关注的焦点,作为编程语言流行度的晴雨表,它反映了行业趋势和技术走向。2024年7月的榜单揭晓了一个重要变化:Python再次登上榜首,成为最受欢迎的编程语言。这个消息对于开发者和企业来说,都具有非凡的意义。 ......
  • Python TensorFlow Keras深度学习模型RetinaNet进行目标检测分析车牌数据
    全文链接:https://tecdat.cn/?p=36968原文出处:拓端数据部落公众号目标检测作为计算机视觉领域的关键任务之一,在交通管理、智能安防、自动驾驶等众多应用场景中具有重要意义。车牌作为车辆的重要标识,其准确检测对于车辆识别、交通监控等系统的性能提升至关重要。传统的目标检测方......
  • 量化交易入门:如何在QMT中配置Python环境,安装第三方依赖包
    哈喽,大家好,我是木头左!引言QMT,作为量化交易系统中的佼佼者,以其强大的功能和灵活的操作性,受到了广大投资者的青睐。但是,对于很多新手来说,如何在QMT中配置Python环境,安装第三方依赖包,却是一个让人头疼的问题。本文将从零开始,手把手教你如何在QMT中配置Python环境,安装第三方依赖包......