NSS刷题记录 [BCACTF 2024]Static

NSS刷题记录 [BCACTF 2024]Static

n久没更新过了复建一下

传新MP4隐写方式。

题目描述给了一串MD5值。给了一个mp4附件。

1
exiftool static.mp4

找一下详细信息。发现encoder字段是一个网址,

image-20260508175621508

其中提供了一个包含StaticMaker的文档

1
2
3
4
5
6
7
8
9
10
11
The StaticMaker ™ utility converts any binary file into a video, suitable for use in … some application somewhere, probably.
The default configuration is width=256, height=256.

The program works by:
1. Compressing the data
2. Padding to a size that is a multiple of (6*width*height) bits
3. Splitting the data into “subframes” of size (2*width*height) bits
4. Writes data to video frames, which each triplet of three consecutive subframes are written to the red, green, and blue channels of one frame, respectively
Data written in row-major order
2 bits per pixel per channel
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

这是一个把二进制文件转换成视频的工具。转换思路是:把文件里的二进制数据(0 和 1)编码进视频每一帧的 RGB 像素里。

视频默认帧率是256*256(width*heifht)

步骤

  1. 压缩数据
  2. 把数据补齐到总长度是6*width*heifht
  3. 把数据拆成多个子帧,每个子帧大小2×width×height
  4. 按照red、green、blue的顺序从左到右从上到下依次写入视频帧。
  5. 每个像素颜色通道只存2bit数据

我们要把每一帧提取出来,然后按照顺序还原数据。

提取帧

1
ffmpeg -i static.mp4 frame_%04d.png

从每一帧中提取bit还原数据

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import hashlib
from PIL import Image
import numpy as np

def decode_frames(frame_prefix, frame_count, width=256, height=256):
channels = ['R', 'G', 'B']
bit_position = 4 # Bit position(4or6) chosen based on successful MD5 checksum match, were taken bitpositions [2,4,6,8]

data_bits = []
for frame_idx in range(1, frame_count + 1):
frame_path = f"{frame_prefix}{frame_idx:04d}.png"
frame = Image.open(frame_path)
frame = frame.convert("RGB")
pixels = np.array(frame)

# Extract the specified bits from each color channel
r_channel = (pixels[:, :, 0] & (0b11 << bit_position)) >> bit_position
g_channel = (pixels[:, :, 1] & (0b11 << bit_position)) >> bit_position
b_channel = (pixels[:, :, 2] & (0b11 << bit_position)) >> bit_position

# Flatten the channels and convert to bit strings
for bits in r_channel.flatten():
data_bits.append(format(bits, '02b'))
for bits in g_channel.flatten():
data_bits.append(format(bits, '02b'))
for bits in b_channel.flatten():
data_bits.append(format(bits, '02b'))
return ''.join(data_bits)

def check_padding(data_bits, width, height):
size = 6 * width * height
print("The size is", size)
actual_size = len(data_bits)
print('The actual size is ', actual_size)
if actual_size % size == 0:
print("Multiple of size")
# No padding to remove
return data_bits # size was already in multiple so need for removing the padding.

# Calculate the number of excess bits to remove
padding_size = actual_size % size

# Remove the excess bits
data_bits = data_bits[:-padding_size]
return data_bits

def bits_to_bytes(data_bits):
byte_arr = bytearray()
for i in range(0, len(data_bits), 8):
byte = data_bits[i:i+8]
byte_arr.append(int(byte, 2))
return bytes(byte_arr)

def calculate_md5(data):
md5 = hashlib.md5(data).hexdigest()
return md5

# Parameters
frame_prefix = 'frame_'
frame_count = 72 # Total number of frames
width = 256
height = 256

# Decode frames
data_bits = decode_frames(frame_prefix, frame_count, width, height)

# Checking padding
data_bits = check_padding(data_bits, width, height)

# Convert bits to bytes
compressed_data = bits_to_bytes(data_bits)

output_path = 'extracted_data.bin'
with open(output_path, 'wb') as f:
f.write(compressed_data)
print("Extracted data saved.")

# Calculate and print MD5 checksum
calculated_md5 = calculate_md5(compressed_data)
print(f"MD5 checksum of extracted data after removing padding: {calculated_md5}")

还原得到的bin文件md5值和题目描述中的一致

image-20260508193711847

然后分析bin文件,使用binwalk发现有压缩数据

image-20260508193835651

可以直接在拓展文件里全局搜索bcactf{

1
strings * | grep bcactf**{**

image-20260508194002270