【2025玄武杯】丢手绢

  • wav的deepsound,base4

alt text

alt text

十十我十一是一我十十一我一是一十十我一是一是一我十十十我十我我我十我十十一是一我十十一我一是一是十我一十十我是十十我我是十我我一十十我一一是一我十十一我十我我一十我一十十十十是十我是一十我我是十十我一一是一我十十一我十是一十十我十一一是一我十十一我十是一十十我一我一是一是一是一一一是是十
  • base4映射再base64
#!/usr/bin/env python3
import itertools, base64, binascii

cipher = "十十我十一是一我十十一我一是一十十我一是一是一我十十十我十我我我十我十十一是一我十十一我一是一是十我一十十我是十十我我是十我我一十十我一一是一我十十一我十我我一十我一十十十十是十我是一十我我是十十我一一是一我十十一我十是一十十我十一一是一我十十一我十是一十十我一我一是一是一是一一一是是十"

chars = ['十', '我', '一', '是']
digits = ['0', '1', '2', '3']

def b4decode(s: str) -> int:
num = 0
for ch in s:
num = num * 4 + int(ch)
return num

for i, perm in enumerate(itertools.permutations(digits), 1):
MAP = dict(zip(chars, perm))
b4_str = ''.join(MAP[c] for c in cipher)
big_int = b4decode(b4_str)
hex_str = format(big_int, 'X')
# 补偶数位
if len(hex_str) & 1:
hex_str = '0' + hex_str
try:
b64_text = bytes.fromhex(hex_str).decode('ascii') # 必须是纯 ASCII
plain = base64.b64decode(b64_text).decode('utf-8')
print(f'{i:02d} MAP={MAP}')
print(f' BASE64 -> {plain}\n')
except Exception:
pass
  • cdusec{dwji!_daiid_djwdjo}

【2025 LilCTF】V我50®MB

  • 没做,就是看到sq学长公众号记录一下

alt text

alt text

http://challenge.imxbt.cn:30769/api/file/download/72ddc765-caf6-43e3-941e-eeddf924f8df

alt text

  • HackBar直接下载是不完整的

青少年CTFmisc-间谍的录音

[CISCN 2022 初赛]everlasting_night

  • 学习途中为了验证cloacked-pixel工具安装结果找到的题目和我说用GIMP打开,疑惑是不是photoshop打不开,遂NSS上找题目附件尝试
  • 随波逐流
--Png文件结束标志[49 45 4E 44 AE 42 60 82]后提取信息:
fb3efce4ceac2f5445c7ae17e3e969ab

alt text

alt text

  • ohhWh04m1

alt text

  • 不是谁来告诉我藏这么严实是要干啥,我勒个

alt text

  • f78dcd383f1b574b

格式为png,所以有可能是通过lsb技术在像素上写入了额外的信息。

python lsb.py extract 1.png out f78dcd383f1b574b
  • 输出的binwalk搞出zip文件,密码是ohhWh04m1

alt text

  • 什么什么什么

  • 为什么知道是data后缀

  • 为什么gimp打开

  • 一万个问号

  • 扔tweak长这样

alt text

  • 不管了以后遇到这样的就丢gimp看看

[GKCTF 2020]Harley Quinn

题目描述
Ivy给Harley发了一个短信……算了,编不下去了,先听后看就完事了……
音频解码可能有误差,密码为有意义的无空格小写短句 解密版本为1.25
得到的flag使用NSSCTF{}格式提交。

alt text
alt text

  • #5AA55362135##222833344477773338866#
  • #222833344477773338866#
  • 23 81 33 43 74 33 82 62

alt text

  • ctfisfun

alt text

alt text

  • 嘶这工具这么古老就不搞了吧后面就纯工具了

[SCTF 2019]电单车

alt text

发现pt2422信号,选中放大,选中方法这段音频出现在0-0.10后,我们按下图选取0.00-0.12秒这个时段,连续点击CTRL+1快捷键放大

钥匙信号(PT224X) = 同步引导码(8bit) + 地址位(20bit) + 数据位(4bit) + 停止码(1bit)

短的为0,长的为1,可以打出:
0 011101001010101001100010 0 011101001010101001100010
flag为地址码:
flag{01110100101010100110}

alt text

[BUUCTF]九连环

alt text

  • 504B03041400后是0008偶数,且504B01021400后是0001
  • 改0000
  • 太复杂了这个随波逐流不了

alt text

  • 文件名给提示了(?
steghide extract -sf good-已合并.jpg

alt text

  • flag{1RTo8w@&4nK@z*XL}

[UTCTF2020]spectogram

  • audacity

alt text

  • 脚本
import matplotlib.pyplot as plt
import librosa
import numpy as np
import soundfile as sf
import python_speech_features as psf
import librosa
import librosa.display
# Spectrogram步骤,
# Step 1: 预加重
# Step 2: 分帧
# Step 3: 加窗
# Step 4: FFT
# Step 5: 幅值平方
# Step 6: 对数功率
def preemphasis(signal, coeff=0.95):
return np.append(signal[1], signal[1:] - coeff * signal[:-1])

def pow_spec(frames, NFFT):
complex_spec = np.fft.rfft(frames, NFFT)
return 1 / NFFT * np.square(np.abs(complex_spec))
def frame_sig(sig, frame_len, frame_step, win_func):
'''
:param sig: 输入的语音信号
:param frame_len: 帧长
:param frame_step: 帧移
:param win_func: 窗函数
:return: array of frames, num_frame * frame_len
'''
slen = len(sig)

if slen <= frame_len:
num_frames = 1
else:
# np.ceil(), 向上取整
num_frames = 1 + int(np.ceil((slen - frame_len) / frame_step))

padlen = int( (num_frames - 1) * frame_step + frame_len)
# 将信号补长,使得(slen - frame_len) /frame_step整除
zeros = np.zeros((padlen - slen,))
padSig = np.concatenate((sig, zeros))

indices = np.tile(np.arange(0, frame_len), (num_frames, 1)) + np.tile(np.arange(0, num_frames*frame_step, frame_step), (frame_len, 1)).T
indices = np.array(indices, dtype=np.int32)
frames = padSig[indices]
win = np.tile(win_func(frame_len), (num_frames, 1))
return frames * win

y, sr = sf.read('A:\\edgedown\\attachment.wav') # 音频文件
# 预加重
y = preemphasis(y, coeff=0.98)
# 分帧加窗
frames = frame_sig(y, frame_len=2048, frame_step=512, win_func=np.hanning)
# FFT及幅值平方
feature = pow_spec(frames, NFFT=2048)
# 对数功率及绘图.
librosa.display.specshow(librosa.power_to_db(feature.T),sr=sr, x_axis='time', y_axis='linear')
plt.title('Spectrogram')
plt.colorbar(format='%+2.0f dB')
plt.tight_layout()
plt.show()

alt text

阿里CTF热身题目

alt text

alt text

  • ai搞定的。。。其实你手打也行。。。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import wave
import numpy as np

PNG_SIG = b"\x89PNG\r\n\x1a\n"

# 一些常见文件头(用于自动挑选正确映射)
MAGICS = [
(b"\x89PNG\r\n\x1a\n", "png"),
(b"PK\x03\x04", "zip"),
(b"RIFF", "riff"),
(b"%PDF-", "pdf"),
]

def detect_magic(data: bytes):
for sig, name in MAGICS:
i = data.find(sig)
if i != -1:
return name, i
return "unknown", -1

def read_wav_mono(path: str):
with wave.open(path, "rb") as wf:
ch = wf.getnchannels()
sw = wf.getsampwidth()
fs = wf.getframerate()
n = wf.getnframes()
raw = wf.readframes(n)

# 8/16/24/32-bit PCM
if sw == 1:
x = np.frombuffer(raw, np.uint8).astype(np.float32)
x = (x - 128.0) / 128.0
elif sw == 2:
x = np.frombuffer(raw, np.int16).astype(np.float32) / 32768.0
elif sw == 3:
b = np.frombuffer(raw, np.uint8).reshape(-1, 3)
v = (b[:, 0].astype(np.int32) |
(b[:, 1].astype(np.int32) << 8) |
(b[:, 2].astype(np.int32) << 16))
v = (v << 8) >> 8 # sign extend
x = v.astype(np.float32) / 8388608.0
elif sw == 4:
x = np.frombuffer(raw, np.int32).astype(np.float32) / 2147483648.0
else:
raise ValueError(f"Unsupported sample width: {sw} bytes")

if ch > 1:
x = x.reshape(-1, ch).mean(axis=1)

return x, fs

def frame_audio(x: np.ndarray, frame_len: int, offset: int = 0):
if not (0 <= offset < frame_len):
raise ValueError("offset must be in [0, frame_len-1]")
x = x[offset:]
n = (len(x) // frame_len) * frame_len
x = x[:n]
return x.reshape(-1, frame_len)

def compute_power(frames: np.ndarray, fs: int, freqs: np.ndarray):
"""
计算每帧在每个目标频率上的能量:|sum(x[n]*e^{-j2πfn/fs})|^2
加 Hann 窗减少谱泄露。
"""
n_frames, N = frames.shape
w = np.hanning(N).astype(np.float32)
fw = frames * w

n = np.arange(N, dtype=np.float32)
ang = 2.0 * np.pi * (n[:, None] * freqs[None, :] / float(fs))
c = np.cos(ang).astype(np.float32)
s = np.sin(ang).astype(np.float32)

re = fw @ c
im = fw @ s
power = re * re + im * im
return power

def kmeans2_threshold(v: np.ndarray, iters: int = 50) -> float:
"""
1D k-means (k=2) 找两团中心,用它们中点当阈值。
v 建议传 log10(power)。
"""
c1, c2 = np.percentile(v, 25), np.percentile(v, 75)
for _ in range(iters):
d1 = np.abs(v - c1)
d2 = np.abs(v - c2)
m1 = d1 <= d2
if m1.all() or (~m1).all():
break
nc1 = v[m1].mean()
nc2 = v[~m1].mean()
if abs(nc1 - c1) + abs(nc2 - c2) < 1e-6:
c1, c2 = nc1, nc2
break
c1, c2 = nc1, nc2
lo, hi = (c1, c2) if c1 < c2 else (c2, c1)
return (lo + hi) / 2.0

def bits_from_power_kmeans(power: np.ndarray):
"""
对每个频点单独做二分类阈值(k-means),输出 bits: (frames, nfreq)
"""
logp = np.log10(power + 1e-20)
thr = np.array([kmeans2_threshold(logp[:, j]) for j in range(logp.shape[1])], dtype=np.float32)
bits = logp > thr
return bits

def pack_bits_to_bytes(bits: np.ndarray, invert=False, msb_first=False, reverse_each_byte=False) -> bytes:
"""
bits: (n_frames, n_bits_per_frame)
默认:freq0->bit0(LSB-first)
"""
bf = bits.copy()
if invert:
bf = ~bf

n_frames, n_bits = bf.shape
pad = (-n_bits) % 8
if pad:
bf = np.concatenate([bf, np.zeros((n_frames, pad), dtype=bool)], axis=1)
n_bits = bf.shape[1]

out = bytearray()
for i in range(n_frames):
row = bf[i]
for off in range(0, n_bits, 8):
chunk = row[off:off+8]
v = 0
for j in range(8):
if chunk[j]:
bitpos = (7 - j) if msb_first else j
v |= (1 << bitpos)
if reverse_each_byte:
# 8bit 内倒序
x = v
x = ((x & 0xF0) >> 4) | ((x & 0x0F) << 4)
x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2)
x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1)
v = x
out.append(v)
return bytes(out)

def cut_png_to_iend(data: bytes):
idx = data.find(PNG_SIG)
if idx < 0:
return None
b = data[idx:]
if not b.startswith(PNG_SIG):
return None
pos = 8
try:
while pos + 12 <= len(b):
ln = int.from_bytes(b[pos:pos+4], "big")
tp = b[pos+4:pos+8]
pos += 8 + ln + 4
if pos > len(b):
return None
if tp == b"IEND":
return b[:pos]
except Exception:
return None
return None

def main():
print("WAV -> PNG 多频并行编码解码(K-means 判 0/1,交互版)")
wav_path = input("WAV 路径: ").strip()
if not wav_path or not os.path.exists(wav_path):
print("文件不存在或未输入。")
return

frame_len = input("每帧采样点数 frame_len [4800]: ").strip()
frame_len = int(frame_len) if frame_len else 4800

offset = input("offset 对齐 [0]: ").strip()
offset = int(offset) if offset else 0

nfreq = input("频率个数 N [8]: ").strip()
nfreq = int(nfreq) if nfreq else 8

use_custom = input("手动输入频率列表?(y/N): ").strip().lower() in ("y", "yes")
if use_custom:
s = input("freqs(逗号分隔,例如 100,200,400,...): ").strip()
freqs = np.array([float(t.strip()) for t in s.split(",") if t.strip()], dtype=np.float32)
if len(freqs) != nfreq:
print(f"你输入了 {len(freqs)} 个频率,但 N={nfreq},退出。")
return
else:
base = input("base [100]: ").strip()
ratio = input("ratio [2]: ").strip()
base = float(base) if base else 100.0
ratio = float(ratio) if ratio else 2.0
freqs = np.array([base * (ratio ** i) for i in range(nfreq)], dtype=np.float32)

out_png = input("输出 PNG 文件名 [decoded.png]: ").strip() or "decoded.png"

x, fs = read_wav_mono(wav_path)
frames = frame_audio(x, frame_len, offset)
print(f"[+] fs={fs}, frames={len(frames)}, frame_len={frame_len}, offset={offset}")
print(f"[+] freqs={freqs.tolist()}")

power = compute_power(frames, fs, freqs)
bits0 = bits_from_power_kmeans(power)

# 试多种映射(和你之前想要的那几种一致)
trials = []
for revfreq in (False, True):
bits = bits0[:, ::-1] if revfreq else bits0
for invert in (False, True):
for msb_first in (False, True):
for revbyte in (False, True):
data = pack_bits_to_bytes(bits, invert=invert, msb_first=msb_first, reverse_each_byte=revbyte)
typ, pos = detect_magic(data)
png = cut_png_to_iend(data)
score = 0
if typ == "png" and pos >= 0:
score += 1000
if png is not None:
score += 5000 # 能完整切到 IEND 给最高分
trials.append((score, typ, pos, revfreq, invert, msb_first, revbyte, data, png))

trials.sort(key=lambda x: x[0], reverse=True)
best = trials[0]
score, typ, pos, revfreq, invert, msb_first, revbyte, data, png = best

print("\n[+] Best mapping:")
print(" reverse_freq_order =", revfreq)
print(" invert_bits =", invert)
print(" msb_first =", msb_first)
print(" reverse_each_byte =", revbyte)
print(" detected =", typ, "pos =", pos, "score =", score)
print(" first16 =", data[:16].hex().upper())

if png is None:
# 没切出完整 PNG,也把原始字节流落盘方便你手工分析
bin_out = os.path.splitext(out_png)[0] + ".bin"
with open(bin_out, "wb") as f:
f.write(data)
print("[-] 没能切到完整 PNG(IEND)。已输出字节流:", bin_out)
return

with open(out_png, "wb") as f:
f.write(png)
print("[+] 写出 PNG:", out_png, "size =", len(png), "bytes")

if __name__ == "__main__":
main()
  • 然后在线网站aztec识别
  • ai帮助下把github上源码搞成本地window的了(原来只有mac和linux的
  • 想要的可以联系我或者自己ai搞(可能也没人看到这里(笑,留个彩蛋谁看到这里我请喝一杯奶茶嘻嘻(保留到我下次更新这篇文章