-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgen_chals.py
145 lines (119 loc) · 4.18 KB
/
gen_chals.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
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import os
import json
import pathlib
import hashlib
import errno
import shutil
import subprocess
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
# pwgen
SECRET="koof9nuamaiquaeNee0l"
def small_hash(name):
checksum=0
for byte in name:
# get last bit of checksum
b=checksum & 0b11111111
# addition on 8bits
b+=ord(byte)
b&= 0b11111111
#clear last bits of checksum
checksum = checksum & 0b11111111111111111111111100000000
# checksum last 8 bits = b
checksum = checksum | b
# rol checksum
checksum=rol(checksum, 3, 32)
return checksum.to_bytes(4, byteorder='big')
def copy_dir(src, dest):
try:
shutil.copytree(src, dest)
except OSError as e:
# If the error was caused because the source wasn't a directory
if e.errno == errno.ENOTDIR:
shutil.copy(src, dest)
else:
print('Directory not copied. Error: %s' % e)
def avoid_borders(salts):
for i in range(0, len(salts)):
if(salts[i]==0):
salts[i]+=2
elif(salts[i]==31):
salts[i]-=2
# check if a list has a duplicate element el
def is_dup(l, el):
count=0
for i in range(0, len(l)):
if(l[i]==el):
count+=1
if(count>1):
return True
return False
def add_salt(salts, b):
salts.append(b)
avoid_borders(salts)
# duplicate
for i in range(0, len(salts)):
if(is_dup(salts, salts[i])):
avoid_borders(salts)
salts[i]=(salts[i]+1)%32
i=0
return salts
if os.path.exists("chals_out/") and os.path.isdir("chals_out/"):
shutil.rmtree("chals_out/")
team_count=0
team_names=[]
chals=[]
for i in next(os.walk('chals'))[1]:
chals.append(i)
with open("teams.json", "r") as read_file:
data = json.load(read_file)
team_count=data['count']
for i in range(0, team_count):
team_names.append(data['results'][i]['name'])
# flag creation is a bit complex: in theory we do a sha2 for each challenge
# name, but also calculate through a custom hash team name + chal name that we
# add inside this flag at random bytes for each chal
for i in chals:
regex_done=False
# we calculate the location of the identifying bytes
salt_chal=small_hash(i+SECRET)
salts=[]
for z in range(0, 4):
salts=add_salt(salts, salt_chal[z]%32)
for y in team_names:
copy_dir("chals/" + i, "chals_out/" + i + "/" + y)
uni_hash=small_hash(i+y+SECRET)
# make it a bit harder to guess the format of the sha2
chal_name=i+SECRET
hash_final=bytearray(bytes.fromhex(hashlib.sha256(chal_name.encode()).hexdigest()))
# we replace by the identifying bytes
hash_final[salts[0]]=uni_hash[0]
hash_final[salts[1]]=uni_hash[1]
hash_final[salts[2]]=uni_hash[2]
hash_final[salts[3]]=uni_hash[3]
hash_final_str=hash_final.hex()
flag = "GY{" + hash_final_str + "}"
with open("chals_out/" + i + "/" + y + "/flag.txt", "w") as fdflag:
fdflag.write(flag)
# generate the challenge
subprocess.call(["python3", "setup.py"], cwd="chals_out/" + i + "/" + y)
if(regex_done==False):
regex = list(flag)
# we want a global regex for all challengers, so we replace
# identifying bytes in the regex. The anti cheat script is going to
# be ran after the ctf anyways
regex[((salts[0]*2)+3)]="."
regex[((salts[0]*2)+3)+1]="."
regex[((salts[1]*2)+3)]="."
regex[((salts[1]*2)+3)+1]="."
regex[((salts[2]*2)+3)]="."
regex[((salts[2]*2)+3)+1]="."
regex[((salts[3]*2)+3)]="."
regex[((salts[3]*2)+3)+1]="."
with open("chals_out/" + i + "/regex.txt", "w") as fdregex:
fdregex.write(''.join(regex))
regex_done=True