LUO 一个兴趣使然的人与他兴趣使然的博客

支持 1 ~ 4 Byte の CRC32 爆破脚本

⚠️ 本文最后更新于2023年12月04日,已经过了289天没有更新,若内容或图片失效,请留言反馈

Powered by Python
Designed by CHAT-GPT-4.0-1106

背景

  • ISCTF-2023 [Misc-Ez_crc] 解题
  • 一般来说的 crc32 爆破加密 txt 文件只会让爆破几个(一般 < 10)
    但这道题给的压缩包有200+个加密txt文档
  • 因为文件较多如果使用流传较广的脚本进行爆破的话可能会出现输出的索引问题 例如:

    • 本该是

      1-
      2-
      3-
      ······
      1000-
    • 可能变成

      1-
      2-
      3-
      ······
      10-
      100-
  • 即爆破出的文本的位置和他本来应该在的位置不同
  • 所以拷打了 GPT-4.0 写了这个脚本 优势有

    • 正确排序的爆破输出
    • 可能一点的爆破速度
    • 可一键支持 1~4 Byte 的爆破

用途

  • 可用于 「1 ~ 4 Byte」 的 压缩包文件 crc32爆破 文件内 加密txt 文件的内容

注意事项

  • 4 Byte 的 txt 文本可能会出现一个 crc32 值对应多个 明文 的情况,爆破结果可能还需自己筛选
  • 1~3 Byte 爆出来是啥就是啥
  • 默认爆破文件名为 flagF.zip

示例

输入

Enter the number of bytes to brute force (1-4): 3 // X 代表爆破文件 Byte 数

输出

[+] 0.txt: 0xd2b184ff matched with "e5a4a7"
[+] 1.txt: 0xb462df74 matched with "e58699"
[+] 2.txt: 0x32973a9e matched with "e79a84"
[+] 3.txt: 0x80a37b94 matched with "e4b98c"
[+] 4.txt: 0x67ff2f5b matched with "e5a3b9"
[+] 5.txt: 0xd2b184ff matched with "e5a4a7"
[+] 6.txt: 0xb462df74 matched with "e58699"
······示范中省略 , 实际运行中会全部输出
[+] 202.txt: 0x32973a9e matched with "e79a84"
[+] 203.txt: 0x0b10371d matched with "e789b9"
[+] 204.txt: 0xe9c57755 matched with "e99bb6"
[+] 205.txt: 0xef809c83 matched with "e78e96"
Total running time: 2.81 seconds
e5a4a7 e58699 e79a84 e4b98c e5a3b9 e5a4a7 e58699 e79a84 e8b584 e5a4a7 e58699 e79a84 e59694 e5a4a7 e58699 e79a84 e697a5 e5a4a7 e58699 e79a84 e4bd9b e5a4a7 e58699 e79a84 e8b584 e5a4a7 e58699 e79a84 e4bd9b e5a4a7 e58699 e79a84 e5b7ab e59fba e5be97 e5a4a7 e58699 e79a84 e8aeb7 e5a4a7 e58699 e79a84 e8bf82 e5a3b9 e7a791 e5b7ab e5a4a7 e58699 e79a84 e789b9 e5a4a7 e58699 e79a84 e5b7ab e59da1 e697a5 e5be97 e5a3b9 e58b92 e789b9 e5a4a7 e58699 e79a84 e789b9 e5a4a7 e58699 e79a84 e5b88c e5a4a7 e58699 e79a84 e697a5 e5a4a7 e58699 e79a84 e8b584 e9b985 e7a791 e5a4a7 e58699 e79a84 e4bd9b e99986 e5a4a7 e58699 e79a84 e5b7ab e5a4a7 e58699 e79a84 e8bf82 e5a4a7 e58699 e79a84 e691b8 e5b7ab e5a4a7 e58699 e79a84 e691b8 e5a4a7 e58699 e79a84 e4bd9b e59da1 e6acba e5a4a7 e58699 e79a84 e5b7ab e691b8 e5b88c e5a4a7 e58699 e79a84 e691b8 e5a4a7 e58699 e79a84 e8bf82 e99bb6 e5a4a7 e58699 e79a84 e4b98c e99bb6 e5a4a7 e58699 e79a84 e789b9 e8aeb7 e59da1 e5a4a7 e58699 e79a84 e8aeb7 e5be97 e5a4a7 e58699 e79a84 e9b985 e78e96 e5a4a7 e58699 e79a84 e9b985 e5a4a7 e58699 e79a84 e4b98c e691b8 e5a3b9 e5a4a7 e58699 e79a84 e59da1 e5a4a7 e58699 e79a84 e8bf82 e5a4a7 e58699 e79a84 e9b985 e4bc8d e6809d e5a4a7 e58699 e79a84 e5b7ab e58b92 e5a4a7 e58699 e79a84 e697a5 e5a4a7 e58699 e79a84 e6809d e5958a e7a791 e5a3b9 e5a4a7 e58699 e79a84 e9b985 e5a4a7 e58699 e79a84 e8b584 e5a4a7 e58699 e79a84 e593a5 e5969d e691b8 e5a4a7 e58699 e79a84 e4b98c e5a4a7 e58699 e79a84 e789b9 e99bb6 e78e96

代码

import zipfile
import binascii
from concurrent.futures import ThreadPoolExecutor
import time


def extract_crc_from_zip(zip_path):
    with zipfile.ZipFile(zip_path) as file_handler:
        name_list = file_handler.namelist()
        crc_info = {name: file_handler.getinfo(name).CRC for name in name_list}
        sorted_crc_info = dict(sorted(crc_info.items(), key=lambda item: int(item[0].split('.')[0])))
        return sorted_crc_info


def search_range(start, end, target_crc32_set, matches, bytes_length):
    for i in range(start, end):
        # 根据指定的字节数生成字节序列
        bytes_str = i.to_bytes(bytes_length, byteorder='big')
        crc32 = binascii.crc32(bytes_str) & 0xffffffff
        if crc32 in target_crc32_set:
            # 将整数转换为指定长度的十六进制字符串
            matches[crc32].append(bytes_str.hex().zfill(bytes_length * 2))


def find_crc_matches(crc_info, bytes_length):
    target_crc32_set = set(crc_info.values())
    matches = {target_crc: [] for target_crc in target_crc32_set}

    with ThreadPoolExecutor(max_workers=4) as executor:
        range_size = (1 << (8 * bytes_length)) // 4
        futures = [
            executor.submit(search_range, i * range_size, (i + 1) * range_size, target_crc32_set, matches, bytes_length)
            for i in range(4)
        ]
        for future in futures:
            future.result()

    return matches


def main(zip_path, bytes_length):
    start_time = time.time()  # Start timing

    crc_info = extract_crc_from_zip(zip_path)
    matches = find_crc_matches(crc_info, bytes_length)

    match_strings = []
    for filename, crc in crc_info.items():
        crc_hex = f'0x{crc:08x}'
        match_string = ', '.join(matches[crc])
        print(f'[+] {filename}: {crc_hex} matched with "{match_string}"')
        match_strings.append(match_string)

    end_time = time.time()  # End timing
    total_time = end_time - start_time  # Calculate total running time
    print(f"Total running time: {total_time:.2f} seconds")  # Print total running time

    return match_strings


if __name__ == "__main__":
    bytes_length = int(input("Enter the number of bytes to brute force (1-4): "))
    assert 1 <= bytes_length <= 4, "Bytes length must be between 1 and 4"
    match_strings = main('./flagF.zip', bytes_length)
    output_str = ' '.join(match_strings)
    print(output_str)