2026软件系统安全赛初赛MISC--steganography

前言

一个更好的方法与本文章方法不一样,都可以用来参考。

解题

下载附件得到一个无后缀文件

发现头部被修改。

如果想知道如何判断,可以参考:
CTF必知:以一次MISC题目完整分析png图片16进制分别代表什么(干货满满!)

python 复制代码
data = open("steganography_challenge","rb").read()
print("Header:",data[:35].hex())
idx = data.find(b"\x89PNG")
print("PNG at offset:",idx)

到35字节的地方有PNG的IDAT。

删除前面的字节后。

用zsteg功能扫描一下。

前面的因为跳过的报错不用管,只需要注意最后一条118行无效滤波字节 254。这个警告说明 PNG 滤波字节被修改了。

说明图片身高造假,就是要修改一下图片的高。

把高改成00 00 00 76(118)即可。

如果想知道如何判断,可以参考:
CTF必知:以一次MISC题目完整分析png图片16进制分别代表什么(干货满满!)

提取成功。

解压后每个压缩包都加密了。

但是其中6个和密码有关的只有4个字节。

CRC爆破。

可以用代码:

python 复制代码
import binascii, struct, itertools, string
 
# 从各 pass*.zip 头中读取 CRC32
crcs = {
    "pass1": 0xce70d424,
    "pass2": 0xf90c8a70,
    "pass3": 0xff3fe4bb,
    "pass4": 0x242a5387,
    "pass5": 0x9a27098e,
    "pass6": 0xd3f6df9f,
}
 
# 枚举所有 4 字节可打印 ASCII,匹配 CRC32
charset = "".join(chr(i) for i in range(32, 127))
crc_to_plain = {}
for combo in itertools.product(charset, repeat=4):
    candidate = "".join(combo).encode()
    c = binascii.crc32(candidate) & 0xffffffff
    if c in set(crcs.values()):
        crc_to_plain[c] = candidate.decode()

这4个是CRC32。如果想知道如何判断,可以参考:
CTF必知:以一次MISC题目完整分析png图片16进制分别代表什么(干货满满!)

脚本:

python 复制代码
#!/usr/bin/env python3
import binascii
import itertools
import string
from concurrent.futures import ThreadPoolExecutor

crc_dict = {
    'ce70d424': 'pass1',
    'f90c8a70': 'pass2',
    'ff3fe4bb': 'pass3',
    '242a5387': 'pass4',
    '9a27098e': 'pass5',
    'd3f6df9f': 'pass6'
}

targets = {int(k, 16): v for k, v in crc_dict.items()}
chars = "".join(chr(i) for i in range(32, 127))  # 修复 Bug
results = {}
lock = __import__('threading').Lock()

def check_batch(batch):
    """检查一批组合"""
    local_results = {}
    for p in batch:
        s = "".join(p)
        crc = binascii.crc32(s.encode()) & 0xffffffff
        if crc in targets:
            local_results[targets[crc]] = s
    return local_results

def main():
    print("开始 CRC32 碰撞爆破...")
    print(f"目标 CRC 数:{len(targets)}")
    print(f"字符集大小:{len(chars)}")
    print(f"总组合数:{len(chars)**4:,}")
    print()
    
    # 分批次处理
    all_combos = itertools.product(chars, repeat=4)
    batch_size = 100000
    batch = []
    completed = 0
    
    with ThreadPoolExecutor(max_workers=8) as executor:
        futures = []
        for combo in all_combos:
            batch.append(combo)
            completed += 1
            
            if len(batch) >= batch_size:
                futures.append(executor.submit(check_batch, batch.copy()))
                batch = []
            
            if completed % 1000000 == 0:
                print(f"进度:{completed:,}/{len(chars)**4:,}")
        
        # 处理剩余
        if batch:
            futures.append(executor.submit(check_batch, batch))
        
        # 收集结果
        for future in futures:
            for name, s in future.result().items():
                if name not in results:
                    results[name] = s
                    print(f"✓ {name} = {s}")
        
        # 检查是否完成
        if len(results) == 6:
            print("\n" + "="*50)
            pwd = "".join([results[f'pass{i}'] for i in range(1, 7)])
            print(f"🎉 密码:{pwd}")
            print("="*50)
            return pwd
    
    print(f"\n只找到 {len(results)}/6 个")
    return None

if __name__ == '__main__':
    main()

或者直接用ZipCracker。

最终得到:

python 复制代码
pass is c1!xxtLf%fXYPkaA

解压后得到:

存在零宽字符隐写。

python 复制代码
txt = open("flag.txt",encoding="utf-8").read()
ZWSP = "\u200b" 
ZWNJ = "\u200c"

bits = []
for char in txt:
    if char == ZWSP:
        bits.append("0")
    elif char == ZWNJ:
        bits.append("1")

flag = ""
for i in range(0,len(bits) - 7 ,8):
    flag += chr(int("".join(bits[i:i+8]),2))

print(flag) 

得到dart{bf4100d9-cc8d-48f6-a095-54cbfad189e1}。

相关推荐
其实防守也摸鱼19 分钟前
无线网络安全---WLAN相关安全工具--kali(理论附题目)
linux·安全·web安全·学习笔记·kali·命令模式·wlan
2401_8734794027 分钟前
应急响应:勒索软件攻击源IP分析,如何通过IP地址查询定位辅助溯源?
网络·tcp/ip·安全·网络安全·ip
a95114164229 分钟前
如何加固SQL集群防注入_实施网络层访问控制策略
jvm·数据库·python
2401_8359568135 分钟前
mysql处理大量更新场景_InnoDB MVCC与MyISAM对比
jvm·数据库·python
m0_7489203644 分钟前
Oracle默认端口被占用如何连接_修改端口号操作教程
jvm·数据库·python
qq_342295821 小时前
Redis怎样按照距离远近排序展示_通过GEORADIUS的ASC参数进行Geo排序
jvm·数据库·python
2201_761040591 小时前
C#比较两个二进制文件的差异 C#如何实现一个二进制diff工具
jvm·数据库·python
Polar__Star1 小时前
SQL中如何实现特定顺序的查询:CASE WHEN自定义排序
jvm·数据库·python
一只大袋鼠1 小时前
MyBatis 入门详细实战教程(一):从环境搭建到查询运行
java·开发语言·数据库·mysql·mybatis
u0109147601 小时前
mysql如何配置监听IP_mysql bind-address多地址设置
jvm·数据库·python