NSSCTF-2023-gift_in_qrcode(revenge)

题目来源

NSSCTF-2023-misc-gift_in_qrcode(revenge)

考点

getrandbits(8) python伪随机数 爆破脚本的编写

题目内容

main.py

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
import qrcode
from PIL import Image
from random import randrange, getrandbits, seed
import os
import base64

flag = os.getenv("FLAG")
if flag == None:
flag = "flag{test}"

secret_seed = randrange(1, 1000)
seed(secret_seed)
reveal = []
for i in range(20):
reveal.append(str(getrandbits(8)))
target = getrandbits(8)
reveal = ",".join(reveal)

img_qrcode = qrcode.make(reveal)
img_qrcode = img_qrcode.crop((35, 35, img_qrcode.size[0] - 35, img_qrcode.size[1] - 35))

offset, delta, rate = 50, 3, 5
img_qrcode = img_qrcode.resize(
(int(img_qrcode.size[0] / rate), int(img_qrcode.size[1] / rate)), Image.LANCZOS
)
img_out = Image.new("RGB", img_qrcode.size)
for y in range(img_qrcode.size[1]):
for x in range(img_qrcode.size[0]):
pixel_qrcode = img_qrcode.getpixel((x, y))
if pixel_qrcode == 255:
img_out.putpixel(
(x, y),
(
randrange(offset, offset + delta),
randrange(offset, offset + delta),
randrange(offset, offset + delta),
),
)
else:
img_out.putpixel(
(x, y),
(
randrange(offset - delta, offset),
randrange(offset - delta, offset),
randrange(offset - delta, offset),
),
)

img_out.save("qrcode.png")
with open("qrcode.png", "rb") as f:
data = f.read()
print("This my gift:")
print(base64.b64encode(data).decode(), "\\n")

ans = input("What's your answer:")
if ans == str(target):
print(flag)
else:
print("No no no!")

nc连上去,会给一长串的base64数据,然后要求输入answer。

分析

  • 首先是生成reveal的地方,还有target[也就是我们最后要求的answer] secret_seed = randrange(1, 1000) seed(secret_seed) reveal = [] for i in range(20): reveal.append(str(getrandbits(8))) target = getrandbits(8) reveal = ",".join(reveal)
  • 先用getrandbits(8)生成了20个数字,放到reveal里面了,然后又生成了target,所以我们的思路就是利用伪随机数的原理,通过那20个数去爆破第21位
  • 而题目后面的内容就是把这20个数据的信息生成一个二维码再把信息的base64编码输出给我们,所以还需要一个脚本把这个二维码还原出来。

解答

首先是二维码的还原

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# auther:youzhi
# time:2023/8/27
import base64
from PIL import Image

base64_encoded_data = """
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
"""

# 解码base64数据
decoded_data = base64.b64decode(base64_encoded_data)

# 将解码后的数据写入PNG文件
with open("restored_qrcode.png", "wb") as f:
f.write(decoded_data)

# 打开恢复后的QR码图像
restored_qrcode = Image.open("restored_qrcode.png")
restored_qrcode.show()

生成的二维码直接扫描就得到数据,接下来就是考虑编写脚本爆破。

思路就是:把已知的20个数值传上去,然后用循环开始执行随机生成seed和getrandbits(8),当找到匹配的结果之后就继续下一位,直到20个数值全部匹配成功,就说明找到了那个序列,就直接再执行一次输出第21位的值。

脚本

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
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# auther:youzhi
# time:2023/8/28
from random import seed, getrandbits

# 已知的 20 个数值
known_values = [78,122,161,126,38,94,156,23,65,190,167,204,205,160,124,45,170,60,107,148]

# 待爆破的目标值
target = None

# 尝试不同的种子和随机数生成,直到找到匹配的结果
for secret_seed in range(1, 1000):
seed(secret_seed) # 设置种子
for _ in range(20):
generated_value = getrandbits(8)
if generated_value != known_values[_]:
break
else:
# 找到合适的种子和随机数生成方式
target = getrandbits(8)
break

# 输出结果
if target is not None:
print("Found target:", target)
else:
print("Target not found")