Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

沙盒逃逸

在做中海的一道题,学长看一眼说是沙盒逃逸了,这里就过来看看

题目给了一个python环境,这里就具体看python沙盒逃逸

python沙盒逃逸

沙箱逃逸就是在在一个严格限制的python环境中,通过绕过限制和过滤达到执行更高权限,甚至getshell的过程

Python 的沙箱逃逸的最终目标就是执行系统任意命令,次一点的写文件,再次一点的读文件

既然我们需要命令执行,那么我们就需要了解一下python中能执行系统命令的方法,既然是执行命令,常见调用的模块就是os (sys pty subprocess plarform commands 这些模块也可以调用进行命令执行,但没有具体试过,所所以这里先简单列举出来),有时不需要文件执行,只需要读取文件时,可以直接利用open file等文件读取模块

题目给出了配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from flask import *
import io
import time

app = Flask(__name__)
black_list = [
'__build_class__', '__debug__', '__doc__', '__import__',
'__loader__', '__name__', '__package__', '__spec__', 'SystemExit',
'breakpoint', 'compile', 'exit', 'memoryview', 'open', 'quit', 'input'
]
new_builtins = dict([
(key, val) for key, val in __builtins__.__dict__.items() if key not in black_list
])

flag = "flag{xxxxxxxxx}"
flag = "DISPOSED"

@app.route("/")
def index():
return redirect("/static/index.html")

@app.post("/run")
def run():
out = io.StringIO()
script = str(request.form["script"])

def wrap_print(*args, **kwargs):
kwargs["file"] = out
print(*args, **kwargs)
new_builtins["print"] = wrap_print

try:
exec(script, {"__builtins__": new_builtins})
except Exception as e:
wrap_print(e)

ret = out.getvalue()
out.close()
return ret

time.sleep(5) # current source file is deleted
app.run('0.0.0.0', port=9001)

这里可以看到他的黑名单里过滤了很多常见的函数,而在沙盒逃逸中最常见的过滤就是过滤import,从而限制模块的调入

这道题限制的其实不是很多,但主要是我们需要去打开配置文件时发现app.py不存在,这里思路断了(看题目给出的提示后更懵了)

526

他的错误提示是不存app.py,说明前面的函数仍然可以调用,前面的语句应该是没有问题的,重点就来到了如何在没有app.py的情况下,读取配置文件,又去简单看一了proc 和 /etc/paaswd发现都被删干净了,思路彻底断了

所以重点学习一下python沙盒逃逸的知识点

对于import的导入限制绕过方法,其实绕过的方法也是比较多的

1
2
__import__
importlib

还有的就是通过一些简单的拼接和加密绕过(字符串翻转,字符串拼接,base64加密)

再者还可以使用execfileexecfile需要知道库的物理路径(物理路径可以通过sys来获取)

1
2
3
f = open(r'/usr/lib/python3.6/os.py','r')
exec(f.read())
system('whoami')
1
2
3
with open('/usr/lib/python3.6/os.py','r') as f:
exec(f.read())
system('whoami')

还有其他乱七八糟的,这里都可以试试,反正就是导入需要的库即可

导入库只是第一步,这里还需要调用命令执行的函数

除了常见的system popen 还可以通过getattr 拿到对象的方法、属性

1
2
import os
getattr(os, 'metsys'[::-1])('whoami')

不让出现 import 也没事

1
getattr(getattr(__builtins__, '__tropmi__'[::-1])('so'[::-1]), 'metsys'[::-1])('whoami')

我们在学ssti的时候,经常会在字典里调用一个键值为__builtins__,而这个模块就是内建模块,多函数不需要任何 import 就可以直接使用,例如chropen,这些函数都是放在这个模块下,有必要时可以通过这个模块进行导入

1
__builtins__.__dict__['__import__']('os').system('whoami')

但当__builtins__模块中的函数被破坏的时候我们可以利用 reload(__builtins__) 来恢复 __builtins__

通过继承关系逃逸

我们逃逸不仅可以通过绕过来进行,同时也可以通过继承关系来进行

python是支持多重继承的,也就是可以拥有多个父类

python中类都有个属性(mro),是一个元组,记录了类的继承关系。

527

当一些文件操作的函数和类型被过滤的情况下

1
"".__class__.__mro__[-1].__subclasses__()[40](filename).read()

总结而言:
1.通过__class__、mro、subclasses、__bases__等等属性/方法去获取 object.
2.根据__globals__找引入的__builtins__或者eval等等能够直接被利用的库,或者找到builtin_function_or_method类/类型
3.__call__后直接运行eval

还有一些就是对一些符号和特殊字符什么的绕过,这里就等到具体题目做到再来写

这篇文章总体就是队python沙盒逃逸做一个了解,个人感觉沙盒逃逸就是通过绕过方法进行队文件的命令执行,而其中会碰到许多过滤,但看文章还是比较抽象的,那道题目暂时还是卡着,所以先放在这里了

评论