SHCTF WP -NinaSec

这次并没有花费很多时间去做这个题目,因为要过年了嘛,事情有点多,所以就把misc做了一做,写个wp,嘿嘿~

比赛网址:https://shc.tf/(复现平台暂时没找到)

Misc-签到

题目描述:

1
2
扫码关注公众号,并发送:『马』上「赢」盛世山河
即可获取本题flag

扫描公众号即可获得flag.

flag为:

1
SHCTF{WiSh1ng_y0u_@_HaPpy_NEw_Ye@r_1n_Adv@nCe!}

Misc-薇薇安的美照

题目描述:

1
学了一天化学的Zero,决定去打打绝区零里,flag格式:SHCTF{**}记得flag是大写的呢

打开附件的jpg文件用010 editor打开,看看文件尾后面:

1
SHCTF{MV84Xzc0XzIwXzdfOTJfMTZfNV8xOF84Xzc=}

很明显的一段base64

1
MV84Xzc0XzIwXzdfOTJfMTZfNV8xOF84Xzc=

解密一下:

1
1_8_74_20_7_92_16_5_18_8_7

结合题目所说的化学,可以想到数字其实是元素周期表的编号(记得大写):

1
H_O_W_CA_N_U_S_B_AR_O_N

因此,flag为:

1
SHCTF{H_O_W_CA_N_U_S_B_AR_O_N}

Misc-问卷调查

这个就不多说了,flag为:

1
SHCTF{th@nK_y0u_FoR_pAr7icipat1n9_in_SHCTF_3rd}

Misc-Evan

题目描述:

1
so作为一位资深的CTF女师傅,却是个乙游的狂热爱好者,这是她珍藏已久的照片,找出flag

附件是一张png图片,不管你是拖入随波逐流还是使用010 editor,都能看到文件尾有504B0304这个明显的zip文件头,说明图片里藏了一个zip,用binwalk分离开来:

分离之后你可以发现,这个压缩包是加密的,一般我们拿到一个压缩包加密首先都会看看是不是伪加密,这题可以看出全局方位标记是09 00,把它改为00 00并保存就可以看到可以打开了,flag.txt里就是flag:

1
SHCTF{Evan_1s_s0_h4nds0me!}

Misc-Office

题目描述:

1
Office我只推荐MS,WPS是什么,我不知道

打开.docx文件后有这么一行字符串:

1
lRy1m2qYkmewkTqDrneCoTCQoUiFqm7zqoeRoT7DqDCAqm7QsTqRuT3PqjWUt5e7

一开始看看肯定一眼看不出来什么,那就换一种思路,我们碰到这种文档题,一般都是把它们当作zip文件去看的,所以就用binwalk分离一下,如果嫌麻烦,就用随波逐流自带的binwalk.

这里比较考察注意力了,如果你对这个不感冒的话:

1
+/0-6a-zA-Z7-9=

这是base64的一种字母表,是在这个文件(alphabet)里找到的,这里可以学到东西,base可以自定义字符:

然后直接在cyberchef就可以解密:

所以.flag为:

1
SHCTF{MS_Office_is_the_best_office_software.wps}

Misc-Open my puff

题目描述:

1
如果你也会开锁^_~

题目提示的很明显了,就是使用openpuff这个软件(就不给下载链接了)

png文件尾后面也给了hint:

1
h1nt:openpuff4.01

题目附件txt里有这个:

猜测是零宽隐写:

这里就可以得到3个key:

1
2
3
keyA:12345678
keyB:qwertyui
keyC:asdfghjk

在openpuff里用png当载体输入密钥,解密出一个加密的压缩包:

打开flag.zip太好了,是ZipCrypto!!!,使用bkcrack,flag.txt就是明文,但是不要直接用flag.txt进行明文攻击,(直接攻击会找不到密钥)因为flag.txt是这样的:

1
niimmccw????zfip

把niimmccw保存为flag.txt
bkcrack 攻击 ZipCrypto 算法本质上是在还原内部的三重密钥状态。

通常需要 12 个连续的字节,bkcrack 才能通过数学公式直接推导出唯一的内部状态。

而这个你明显可以看到,只有8个字节是连续的,后面用?断开了,所以你如果直接用这个去明攻击是找不到的,因为中间断掉的原因,他只会用前八个字节去寻找密钥,后面那四个zfip被识别成单独的字节,自然和前面结合不起来。

我们可以构造以下命令:

1
bkcrack -C flag.zip -c flag.txt -p flag.txt -o 0 -x 12 7a666970

-x: 代表 额外已知明文。

12: 代表偏移量,即从第 12 个字节开始。

7a666970:就是zfip的16进制

可能还是有点疑惑,用AI彻底把明文攻击讲明白:

第一阶段:Zip 加密到底在干什么?

ZipCrypto 是一种 流密码(Stream Cipher)。它的工作方式不像保险箱(把东西锁进去),而更像是在“对暗号”。

  1. 密钥流(Keystream)

    加密器内部有三个数字(也就是你在 bkcrack 结果里看到的 Keys: 4543d810 ...),这三个数字被称为内部状态

    这三个数字会不断变化,吐出一长串看起来像随机乱码的字节流,我们叫它 Keystream (K)

  2. 加密过程非常简单,就是把你的 明文 (P)密钥流 (K) 进行异或运算 ($\oplus$),得到 密文 (C)

    重点来了: 这是一个可逆的数学公式。如果你知道 密文 (C)(这在压缩包里),并且你猜到了 明文 (P),你就可以反推算出 密钥流 (K)

第二阶段:为什么要攻击?为什么通常要 12 字节?

我们的目标不是破解你的密码(比如 “123456”),而是直接破解那 三个内部数字(Internal Keys)。一旦拿到这三个数字,我们就能模拟出后续所有的密钥流,从而解密整个文件。

ZipCrypto 的内部状态总共有 96 位(bits) 的熵(不确定性)。

  • 1 个字节的线索:每当你提供 1 个字节的已知明文,你就获得 1 个字节的密钥流 $K$。这能帮排除掉一部分错误的内部状态。

  • 12 个字节的线索:$12 \text{ bytes} \times 8 \text{ bits} = 96 \text{ bits}$。

    数学上,当你拥有 12 个连续的已知字节时,你掌握的信息量(96位)刚好抵消了内部状态的不确定性(96位)。此时,剩下的可能状态通常只有 1 个(也就是唯一的正确答案)。

这就是为什么 bkcrack 官方文档和报错信息总是告诉你:“minimum is 12”(至少需要12字节)


第三阶段:你的操作是如何绕过限制的?

你遇到的情况是:

  • 开头只有 8 字节 (niimmccw) —— 信息量不够
  • 中间缺了 4 字节 (????) —— 链条断了
  • 后面又有 4 字节 (zfip)。

如果你只给前 8 个字节,计算机会算出几百万个“可能的钥匙”,它不知道哪一个是真的,所以它不敢给你结果,直接报错。

但是,你用了这个命令:

1
... -p flag.txt -o 0 -x 12 7a666970

这个命令相当于你对 bkcrack 说了这样一段话:

  1. “先帮我筛选第一轮”

    利用开头的 niimmccw(8字节),算出所有可能生成这 8 个字节的内部状态。

    (此时,bkcrack 找到了 281 万个嫌疑对象,也就是你截图里的 2818048 Z values)。

  2. “跨过未知的迷雾”

    虽然中间 4 个字节 (????) 我不知道,但请你把这 281 万个嫌疑对象,按照算法规则往后推演 4 步。

  3. “进行第二轮终极验证”

    推演 4 步之后,看看哪个嫌疑对象生成的密钥流,刚好能解密出 zfip(也就是十六进制的 7a 66 69 70)。

结果是: 在那 281 万个候选者中,只有一个 能够既符合开头的 niimmccw,又能在那之后第 12 个字节处准确对应上 zfip

总结

你做的事情叫做 稀疏已知明文攻击(Sparse Known Plaintext Attack)

  • 普通攻击:需要连续的 12 块拼图。
  • 你的攻击:你有 8 块拼图,中间空了 4 块,然后又拿了 4 块拼图。
  • 原理:虽然中间断开了,但只要你拥有的总拼图数量(8 + 4 = 12)足够多,逻辑链条依然可以被接上。

这就是为什么你不需要去暴力穷举中间那 4 个字符,工具利用数学逻辑直接就把它们“推导”出来了。

下面是爆出来的密钥:

1
4543d810 f89b3d67 531a63b0

再用命令去解密文件:

1
bkcrack -C flag.zip -c flag.txt -k 4543d810 f89b3d67 531a63b0 -d end.txt

打开即可得到flag:

1
2
3
4
5
6
7
8
9
10
11
niimmccwcnsizfip

All these eyes from the side under blue lights

Making you confused, I'm selfish, I know

That now's not the time, I'm sure they wouldn't mind

If you'd wanna leave and follow me home

this is flag : SHCTF{N3ur4l_Gl1tch_1n_Th3_5yst3m}
1
SHCTF{N3ur4l_Gl1tch_1n_Th3_5yst3m}   

当然这题肯定还有简单解法,可能是我想的太复杂了。

Misc-不止二维码

题目描述:

1
咦,二维码,扫一下

扫一下是:

1
Welcome to SHCTF 2025! Enjoy the QR Code!

就知道没这么简单,看看文件头,文件尾也没啥收获,那就看看LSB吧,嘿嘿~这题考的就是这个:

前后都翻翻,可以找到三部分的flag:

第一段:

1
SHCTF{55a23d24-

第二段:

1
ABBB/AABBB/AAAAA/BBBBB/ABBBBA/BBBBA/B/AABBB/ABBB

(解密等会再看)

第三段:

1
MkZkbDg3ZlY3ZEQxalNGenQyZUFYT3E0NmRrTXFV

这个能想到是base大家族,但是每一步不是那么好想,这里就直接用随波逐流一把梭了:

1
2
3
Base混合多重解码:
[解码4次] Base64 -> Base62 -> Base58 -> Base32
混合解码结果:-942e-bdd}

好,我们来看第二段:

1
ABBB/AABBB/AAAAA/BBBBB/ABBBBA/BBBBA/B/AABBB/ABBB

这种AB形式的编码是培根密码或者有啥规律的二进制或者摩斯密码,但这里不是培根密码(因为培根密码是纯AB形)也不是二进制(你自己换二进制解密试试就行了),所以这里采用摩斯密码:

A=划(-)B=点(.)(顺序你自己试试就知道了)

然后手动转化就行:

1
-.../--.../-----/...../-....-/....-/./--.../-...

再来个摩斯密码在线解密:https://www.bejson.com/enc/morse/

解密完成后:

1
B705-4E7B

对了,因为摩斯密码默认大写,所以自己手动改一下:

1
b705-4e7b

当然还有脚本解法:

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
def decrypt_ab_morse(ciphertext):
# 摩斯密码字典 (包含数字和连字符)
morse_code_dict = {
'.-': 'A', '-...': 'B', '-.-.': 'C', '-..': 'D', '.': 'E',
'..-.': 'F', '--.': 'G', '....': 'H', '..': 'I', '.---': 'J',
'-.-': 'K', '.-..': 'L', '--': 'M', '-.': 'N', '---': 'O',
'.--.': 'P', '--.-': 'Q', '.-.': 'R', '...': 'S', '-': 'T',
'..-': 'U', '...-': 'V', '.--': 'W', '-..-': 'X', '-.--': 'Y',
'--..': 'Z',
'-----': '0', '.----': '1', '..---': '2', '...--': '3', '....-': '4',
'.....': '5', '-....': '6', '--...': '7', '---..': '8', '----.': '9',
'-....-': '-' # 连字符
}

# 输入字符串
parts = ciphertext.split('/')

decrypted_text = []
morse_visualization = []

print(f"原始密文: {ciphertext}\n")
print(f"{'A/B组':<10} | {'摩斯电码':<10} | {'明文'}")
print("-" * 35)

for part in parts:
# 替换规则: A -> 划(-), B -> 点(.)
# 判定依据: ABBBBA 转换为 -....- 是连字符,反之无对应常见符号
morse_char = part.replace('A', '-').replace('B', '.')

# 解码
plain_char = morse_code_dict.get(morse_char, '?')

decrypted_text.append(plain_char)
morse_visualization.append(morse_char)

# 逐行打印转换过程
print(f"{part:<10} | {morse_char:<10} | {plain_char}")

final_string = "".join(decrypted_text)

print("-" * 35)
print(f"\n还原的摩斯串: {'/'.join(morse_visualization)}")
print(f"最终解密结果: {final_string}")



# 你的密文
code = "ABBB/AABBB/AAAAA/BBBBB/ABBBBA/BBBBA/B/AABBB/ABBB"
decrypt_ab_morse(code)

能够得到同样的结果,最后把三个flag超级拼装:

1
SHCTF{55a23d24-b705-4e7b-942e-bdd}

Misc-提问前请先搜索

题目描述:

1
2
3
4
5
很多人认为 CTF 只是关于“攻击”的艺术,但其实它更是关于“学习”的艺术
这里没有复杂的代码,也没有高深的算法,只有一篇你需要反复研读的文章
如果你无法通过搜索解决报错,你就无法通过提问获得帮助
请静下心来仔细阅读,你会有收获的
tips: 可能会分不清大写O和数字0

这题生蚝就是想让你静下心来阅读,然后在文章的某一个位置,触发特殊CG,获得flag:

这题flag要手打:

1
SHCTF{d0_noT_r3IY_ON_@I}

这题有个小巧思,不让你直接复制flag(下面是生蚝原话):

1
2
3
4
1.字体加密
在很多小说网站能见到
原理就是把文字对应的字体文件改掉.比如汉字位置的字体,换成了一些你想要展示的东西
2.我专门用了一种清晰可见的字体,可以区分所有字母数字,包括i和L,目的就是让你手打,或者OCR(

Misc-资源平权!

题目描述:

1
2
3
4
5
6
7
8
9
10
11
12
苕皮哥在网上下载资源时遇到了无良资源站,从某克网盘下了一个小时,结果发现压缩包的解压密码竟然还要支付 1 个比特币???
———————————————
感谢下载本资源!
本文件由「SHCTF 2025」独家提供!
如果觉得资源不错,请悄悄点个赞;
如果觉得一般,请大声告诉我们哪里好!
如遇问题,请联系客服:
114514@fakeEmail.example
———————————————
资源收集不易
解压密码需要支付 1 bitcoin 获取
———————————————

描述对做题没有帮助,本质上还是要明文攻击(zipcrypto):

命令是:

1
bkcrack -C 221016_CrackM3.zip -c flag.exe -x 0 4D5A90000300000004000000FFFF0000

-x后面是常规exe的文件头:

密钥得到了:

1
60101051 4cba82cb 48eac20c

命令:

1
bkcrack -C 221016_CrackM3.zip -c flag.exe -k 60101051 4cba82cb 48eac20c -d flag.exe

所以flag为:

1
SHCTF{002c158f-b4d2-4e14-bbbb-b5141bca8cb9}

解出来的有些题目懒得写了,最后提前祝大家新年快乐