Post

BuckeyCTF - square cipher

1
2
3
4
5
6
(lambda x=int(input('> '),16):
(all((int(bin(y).translate(str.maketrans('1b','fx')),0)&x).bit_count()==15 for y in
[511,261632,1838599,14708792,117670336,133955584,68585259008,35115652612096,246772580483072,1974180643864576,15793445150916608,17979214137393152,9205357638345293824,4713143110832790437888,4731607904558235517441,9463215809116471034882,18926431618232942069764,33121255085135066300416,37852863236465884139528,75705726472931768279056,151411452945863536558112,264970040681080530403328,302822905891727073116224,605645811783454146232448,1211291623566908292464896,2119760325448644243226624,2413129272746388704198656])
and x&2135465562637171390290201561322170738230609084732268110734985633502584038857972308065155558608880
==1271371190459412480076309932821732439054921890752535035282222258816851982409101952239053178406432 
or print('incorrect'))and print(__import__('os').environ.get('FLAG','bctf{fake_flag}')))()

程序会对数据的输入进行两类对比:

  • 首先将列表中的每一个数字转换成 0b 格式后,变成十六进制,1 -> f, 0 -> 0 , 最后和每一个数字 and 后的1数量有15个
  • 和一个大整数 and 后得到另一个

首先估计位数:

1
2
3
4
5
6
7
8
9
10
11
12
13
# max bit_count
bit_count = 0

for y in [511,261632,1838599,14708792,117670336,133955584,68585259008,35115652612096,246772580483072,1974180643864576,15793445150916608,17979214137393152,9205357638345293824,4713143110832790437888,4731607904558235517441,9463215809116471034882,18926431618232942069764,33121255085135066300416,37852863236465884139528,75705726472931768279056,151411452945863536558112,264970040681080530403328,302822905891727073116224,605645811783454146232448,1211291623566908292464896,2119760325448644243226624,2413129272746388704198656]:
    bin_str = str(bin(int(bin(y).translate(str.maketrans('1b','fx')),0) ))[2:]
    bit_count = max([len(bin_str), bit_count])
    print(bit_count)

for y in [2135465562637171390290201561322170738230609084732268110734985633502584038857972308065155558608880,
          1271371190459412480076309932821732439054921890752535035282222258816851982409101952239053178406432 ]:
    bin_str = str(bin(y))[2:]
    bit_count = max([len(bin_str), bit_count])
    print(bit_count)

有324位,然后尝试用z3求解。自动生成z3代码:

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
import math

bit_count = 324     # each bit: 0/1, create a variable


group = []
bit_a = str(bin(2135465562637171390290201561322170738230609084732268110734985633502584038857972308065155558608880))[2:][::-1]
bit_b = str(bin(1271371190459412480076309932821732439054921890752535035282222258816851982409101952239053178406432))[2:][::-1]
for y in [511,261632,1838599,14708792,117670336,133955584,68585259008,35115652612096,246772580483072,1974180643864576,15793445150916608,17979214137393152,9205357638345293824,4713143110832790437888,4731607904558235517441,9463215809116471034882,18926431618232942069764,33121255085135066300416,37852863236465884139528,75705726472931768279056,151411452945863536558112,264970040681080530403328,302822905891727073116224,605645811783454146232448,1211291623566908292464896,2119760325448644243226624,2413129272746388704198656]:
    bin_str = str(bin(int(bin(y).translate(str.maketrans('1b','fx')),0) ))[2:]
    group.append(bin_str[::-1])

# create constraint code

code = """
from z3 import *\n
s = Solver()\n

"""

# define variable
for i in range(324):
    code+=f'x{i} = Int(\'x{i}\')\n'

for i in range(324):
    code += f's.add(x{i} <= 1)\n'
    code += f's.add(x{i} >= 0)\n'


# create constraint for part1
for bin_str in group:
    
    equation = ''
    for i in range(len(bin_str)):
        if bin_str[i] == '1':
            equation += f'x{i}+'
    equation = equation[:-1] + ' == 15'
    
    code+= f's.add({equation})\n'
            
# create constraint for part2
for i in range(len(bit_a)):
    if bit_a[i] == '1':
        code+= f's.add(x{i} == {bit_b[i]})\n'

code += f"""
model = 0
if s.check() == sat:\n
    model = s.model()
else:
    exit(-1)\n
"""

            
code += 'bin_str = \'\'\n'
for i in range(324):
    code += f'bin_str += str(model[x{i}].as_long())\n'

code += """
bin_str = bin_str[::-1]
print(hex(int(bin_str, 2)))
"""

print(code)

运行后获得auto.py, 再运行即可

1
2
3
4
5
6
(venv13) woc@myarch:buckeyCTF/square-cipher $ python code_gen.py > auto.py
(venv13) woc@myarch:buckeyCTF/square-cipher $ python auto.py
0x986227f143f97038053257287030750a23b61047f988f6106146504e61f0878b9426e05e30e8062b
(venv13) woc@myarch:buckeyCTF/square-cipher $ ncat --ssl square-cipher.challs.pwnoh.io 1337
> 986227f143f97038053257287030750a23b61047f988f6106146504e61f0878b9426e05e30e8062b
bctf{5um_0f_f1r57_n_0dd_numb3r5_c1ph3r_025165aa}

z3中的BitVec会实现自然溢出,刚开始使用1bit类型的时候,相加等于15的约束一直无法满足。后来换成int再加上[0, 1]约束才通过

This post is licensed under CC BY 4.0 by the author.