MISC-黑白琴弦
ISCC2026 WriteUp 提交模板
MISC-黑白琴弦
你是一位钢琴学徒,这天,著名的钢琴大师传授给你一个特殊的琴谱,请耐心参悟琴谱中蕴含的秘密,得到大师的真传吧。·
解题思路
1.解压后是一个rar和一堆条形码

2.分析条形码
元数据有Comment字段


其次还有低位隐写:

其次发现按照(R,G,B)输出时有的图片第一行有些像素是 (254,255,255),有些是 (255,255,255)。很明显存在数据流,可以按照一种是0,另一种是1组成数据。

3.拿到条形码内容
这些图片是 Code128 条形码,解码后能拿到一部分形如 B105d41B、E17485dE、S175facS 的内容。
4.拿到PNG Comment信息
查看图片元数据可以拿到另一部分内容,例如
D175a5dD
U1fda12U
H000a00H
T105b8cT
...
5.拿到第一行隐写
读取图片第一行前 72 个像素:
(254,255,255)记作1- 其它记作
0 - 然后再异或翻转一次
- 每 8 bit 组成一个字节
- 丢掉第一个字节,后面 8 个字节转字符串
可以得到第三部分内容,例如:
F105341F
A1fc57fA
O1fdf00O
P104a2fP
...
经过分析,正确的数据格式应该是:
- 首尾是同一个大写字母
- 中间是 6 位十六进制
- 字母范围是
A-U
使用正则^([A-U])([0-9a-f]{6})\1$去匹配即可。
内容如下:
A 1fc57f
B 105d41
C 17445d
D 175a5d
E 17485d
F 105341
G 1fd57f
H 000a00
I 1f71aa
J 0f0751
K 116b26
L 1c81bc
M 0fc356
N 001eff
O 1fdf00
P 104a2f
Q 175dcf
R 175850
S 175fac
T 105b8c
U 1fda12
总共21组,又是杂项题,自然联想到二维码
每组是 6 位十六进制:
6 hex = 24 bit- QR version 1 的尺寸是
21 x 21
所以做法是:
- 每组十六进制转成 24 位二进制
- 每行丢掉前 3 位
- 保留后 21 位
- 21 行拼成一个
21 x 21的黑白矩阵 - 渲染成二维码图片后扫码


扫码结果:4hFYm4n8l9MctSn,这就是rar的密码了
6.解压后得到的就是钢琴谱,打开这个pdf,CTRL+A发现选中了一些不可见字符

KEY+bnVtYmVyYWJvdmVsaW5l3,粘贴后发现是这个。
base64解码后面的

bnVtYmVyYWJvdmVsaW5l
-> number above line 3,暗示第三行的数字呗,读一下是4151515,KEY的话就是压缩包密码呗

所以flag出来了:ISCC{4hFYm4n8l9MctSn4151515}
Exp
from pathlib import Path
from PIL import Image
import zxingcpp
import re
# ============== 自动找图片,绝对不会找不到 ==============
current_dir = Path(__file__).parent
work = current_dir / "work"
print("📂 图片目录:", work)
print("📂 是否存在:", work.exists())
# 列出所有 barcode_*.png 文件
files = sorted(work.glob("barcode_*.png"))
print("🖼️ 找到图片数量:", len(files))
# ============== 修复正则 ==============
pat = re.compile(r"^([A-U])([0-9a-f]{6})\1$", re.I) # 大小写都匹配
rows = {}
# ============== 开始处理 ==============
for p in files:
print("▶️ 处理:", p.name)
try:
im = Image.open(p).convert("RGB")
except:
print("❌ 打开图片失败")
continue
# 读条形码
try:
barcodes = zxingcpp.read_barcodes(im)
barcode = barcodes[0].text if barcodes else ""
except:
barcode = ""
# 读注释
comment = Image.open(p).info.get("Comment", "")
# 读顶部隐写
bits = []
for x in range(72):
try:
pixel = im.getpixel((x, 0))
bit = 1 if pixel == (254, 255, 255) else 0
bit ^= 1
bits.append(bit)
except:
bits.append(0)
data = bytearray()
for i in range(0, 72, 8):
v = 0
for b in bits[i:i+8]:
v = (v << 1) | b
data.append(v)
top = data[1:].decode(errors="ignore")
# 打印所有内容(关键!)
print(" barcode:", repr(barcode))
print(" comment:", repr(comment))
print(" top steg:", repr(top))
# 匹配
for s in (barcode, comment, top):
m = pat.match(str(s).strip())
if m:
print("✅ 匹配成功:", m.group(1), m.group(2))
rows[m.group(1)] = m.group(2)
break
# ============== 输出结果 ==============
print("\n最终结果:")
for k in sorted(rows):
print(k, rows[k])


浙公网安备 33010602011771号