记一处出题失误-Arnold变换算法
jerem1ah Lv4

记一处出题失误

https://github.com/BuptMerak/mrctf-2022-writeups/blob/main/offical/MISC.md

https://nano.ac/posts/dcf52abe/

https://nano.ac/posts/e8de5668/#Pixel

https://www.jianshu.com/p/39727dbaffd9

https://z2bns.github.io/2021/04/13/Arnold%E5%8F%98%E6%8D%A2/

最近在看Arnold变换算法,回顾了一下自己之前在TUTCTF2023出过的一道misc题,发现了一些错误,而且发现网上的算法大部分也都有一些问题。

猫脸变化算法这个题,我在多个比赛见到,分别是pwnhub-misc猫猫图、konano的博客记录的mrctf的题解、mrctf2022-official题解、ByteCTF2021 Final、最后就是今年的AliyunCTF2023也见到了此算法(因为出题人就是konano打ByteCTF2021 Final来的思路)。TUTCTF2023之所以出这个猫猫题,最直接的是当时在看pwnhub的猫猫图。之后AliyunCTF2023也出了这个算法,现在回顾看AliyunCTF2023的这个算法时,发现仓库已经不见了,还好自己当时git拉下来了,在看konano博客时,看到算法的优化,其中就是iterations是一个无效的参数,这时才意识到我出的题,似乎也没考虑这个问题。但是我出的题的思路脚本直接来源于pwnhub的一个题解,去看了一下,果然那个脚本也是没考虑iteration的问题。然后网上又搜了一下Arnold变换算法,发现其带有迭代的广义变换的代码似乎都忽略了这个问题。遂记录一下这个小失误,但是不影响解题(其实是有影响的,但是由于这个算法的脚本大家都是网上搜的,导致错误的代码解出错误的题,因为错误脚本迭代了一次,所以如果用正确迭代的脚本可能反而解不出来。但是题目有人解出来,可能大家都是网上搜的脚本,且没意识到迭代次数的问题)

贴一下aliyunctf的加密脚本:

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import random
import sys

import numpy as np
from PIL import Image


def arnold_cat_map(image, key=(1, 2, 1)):
"""
Implements Arnold's cat map transformation on an image.
"""
height, width, *_ = image.shape
offset_x, offset_y, iterations = key

new_image = np.zeros(image.shape, dtype=np.uint8)
for i in range(iterations):
for x in range(height):
for y in range(width):
_x, _y = x, y
_y = (_y + offset_x * _x) % width
_x = (_x + offset_y * _y) % height
new_image[_x, _y] = image[x, y]
return new_image

def arnold_cat_map_rev(image, key=(1, 2, 1)):
"""
Implements Arnold's cat map transformation on an image (reverse).
"""
height, width, *_ = image.shape
offset_x, offset_y, iterations = key

new_image = np.zeros(image.shape, dtype=np.uint8)
for i in range(iterations):
for x in range(height):
for y in range(width):
_x, _y = x, y
_x = (_x - offset_y * _y) % height
_y = (_y - offset_x * _x) % width
new_image[_x, _y] = image[x, y]
return new_image


def add_watermark(original_image_path, watermark_text_path, output_image_path):
"""
Adds a text watermark to an image using the Arnold's cat map transformation.
"""

# Open the original image
original_image = np.array(Image.open(original_image_path).convert("RGB"))
height, width, *_ = original_image.shape

# Open the watermark image
watermark_image = np.array(Image.open(watermark_text_path).convert("RGB"))
watermark_height, watermark_width, *_ = watermark_image.shape
watermark_top = (height - watermark_height) // 2
if watermark_top < 0:
print("The height of watermark_text is bigger than original_image")
sys.exit(1)
watermark_left = (width - watermark_width) // 2
if watermark_left < 0:
print("The width of watermark_text is larger than original_image")
sys.exit(1)

# Generator private key
arnold_dx = random.randint(width // 10, width // 10 * 9)
arnold_dy = random.randint(height // 10, height // 10 * 9)
arnold_rd = random.randint(min(height, width) // 10, min(height, width) // 10 * 9)
# private_key = (arnold_dx, arnold_dy, arnold_rd)
private_key = (20,20,5)
print(f'{private_key = }')

# Apply the Arnold's cat map transformation to the original image
transformed_image = arnold_cat_map(original_image, private_key)

# Add the watermark image to the transformed image
watermark_image[watermark_image > 0] = 1
transformed_image[watermark_top:watermark_top+watermark_height, watermark_left:watermark_left+watermark_width] ^= 1 - watermark_image

# Apply the Arnold's cat map transformation to the transformed image
output_image = arnold_cat_map_rev(transformed_image, private_key)

# Save the watermarked image
Image.fromarray(np.uint8(output_image)).save(output_image_path)

# Check if the command-line arguments are valid
# if len(sys.argv) != 4:
# print("Usage: encode.py original_image watermark_text output_image")
# sys.exit(1)
#
# original_image_path = sys.argv[1]
# watermark_text_path = sys.argv[2]
# output_image_path = sys.argv[3]

original_image_path = './img/black.png'
watermark_text_path = './img/cat1.png'
output_image_path = './img/cat1_flag.png'

# Add the watermark to the original image and save the resulting watermarked image
add_watermark(original_image_path, watermark_text_path, output_image_path)
 Comments