2026黄河流域CTF(Misc全)"

admin 2026-10-22 01:45:39 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

for r in range(rounds):
    for c in range(3):
        for i in range(n):
            target = (i * i + (2 * r + 3) * i + 7 * (c + 1)) % n
            swap(i, target)

逆过程的时候我们只需要将轮数、像素下标反向执行即可

for r in range(rounds - 1, -1, -1):
    for c in range(3):
        for i in range(n - 1, -1, -1):
            target = (i * i + (2 * r + 3) * i + 7 * (c + 1)) % n
            swap(i, target)

写得脚本

#!/usr/bin/env python3
from PIL import Image
import numpy as np
import sys

def undo_one_round(flat: np.ndarray, round_index: int, channel_index: int) -> None:
    n = flat.size
    a = 2 * round_index + 3
    b = 7 * (channel_index + 1)
    # inverse of: for i in range(n): swap(i, target(i))
    for i in range(n - 1, -1, -1):
        j = (i * i + a * i + b) % n
        flat[i], flat[j] = flat[j], flat[i]

def decrypt(input_png: str, output_png: str, rounds: int) -> None:
    arr = np.array(Image.open(input_png).convert('RGB'))
    h, w, _ = arr.shape
    out = np.empty_like(arr)
    for c in range(3):
        flat = arr[:, :, c].reshape(-1).copy()
        for r in range(rounds - 1, -1, -1):
            undo_one_round(flat, r, c)
        out[:, :, c] = flat.reshape(h, w)
    Image.fromarray(out, 'RGB').save(output_png)

if __name__ == '__main__':
    if len(sys.argv) != 4:
        print(f'Usage: {sys.argv[0]} <encrypted.png> <output.png> <rounds>')
        sys.exit(1)
    decrypt(sys.argv[1], sys.argv[2], int(sys.argv[3]))

成功解得下图

#!/usr/bin/env python3
from pathlib import Path
from zipfile import ZipFile
from PIL import Image
import numpy as np

flag = np.array(Image.open('flag.png').convert('RGB'))
scb = np.array(Image.open('SCB.png').convert('RGB'))
n = flag.shape[0]
assert flag.shape == (n, n, 3)
assert scb.shape[0] * scb.shape[1] >= n * n

def spiral_indices(n: int):
    top, left = 0, 0
    bottom, right = n - 1, n - 1
    out = []
    while top <= bottom and left <= right:
        for x in range(left, right + 1):
            out.append((top, x))
        for y in range(top + 1, bottom + 1):
            out.append((y, right))
        if top < bottom:
            for x in range(right - 1, left - 1, -1):
                out.append((bottom, x))
        if left < right:
            for y in range(bottom - 1, top, -1):
                out.append((y, left))
        top += 1
        bottom -= 1
        left += 1
        right -= 1
    return out

path = [(y, n - 1 - x) for y, x in spiral_indices(n)][::-1]
coin = np.empty_like(flag)
coin.reshape(-1, 3)[:] = flag[[y for y, x in path], [x for y, x in path]]
Image.fromarray(coin).save('SCB_coin.png')

white = np.all(scb == 255, axis=2)
assert int(white.sum()) == n * n
res = np.full_like(scb, 255)
res[~white] = [0, 0, 0]
res[white] = coin.reshape(-1, 3)
Image.fromarray(res).save('revealed.png')

r, g, b = res[:, :, 0].astype(int), res[:, :, 1].astype(int), res[:, :, 2].astype(int)
green = (g - r > 20) & (g - b > 20) & (g < 250)
mask = np.full_like(res, 255)
mask[green] = [0, 0, 0]
Image.fromarray(mask).save('revealed_green_mask.png')

print(f'wrote: {\"SCB_coin.png\"}')
print(f'wrote: {\"revealed.png\"}')
print(f'wrote: {\"revealed_green_mask.png\"}')

成功还原出硬币

from PIL import Image
import numpy as np

img = np.array(Image.open(\"1.png\").convert(\"RGBA\"))

# 取蓝色通道 LSB
bits = (img[:, :, 2] & 1).ravel()

out = bytearray()
for i in range(0, len(bits) // 8 * 8, 8):
    v = 0
    for b in bits[i:i + 8]:
        v = (v << 1) | int(b)
    out.append(v)

data = bytes(out)

# 前 4 字节为后续十进制字符串长度
ln_bits = int.from_bytes(data[:4], \"big\")
digits = data[4:4 + ln_bits // 8].decode()

print(digits[:100])
print(len(digits))