-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdetect_cheat.py
167 lines (141 loc) · 5.08 KB
/
detect_cheat.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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 avoid_borders(salts):
for i in range(0, len(salts)):
if(salts[i]==0):
salts[i]+=2
elif(salts[i]==32):
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
team_count=0
teams={}
team_names=[]
submissions=[]
chals=[]
chals_data={}
flags=[]
uni_bytes=[]
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):
teams[data['results'][i]['id']] = data['results'][i]['name']
team_names.append(data['results'][i]['name'])
with open("challenges.json", "r") as read_file:
data = json.load(read_file)
chal_count=data['count']
for i in range(0, chal_count):
chals_data[data['results'][i]['id']] = data['results'][i]['name']
with open("submissions.json", "r") as read_file:
data = json.load(read_file)
sub_count=data['count']
for i in range(0, sub_count):
submissions.append([data['results'][i]['provided'],
data['results'][i]['team_id'], data['results'][i]['challenge_id'],
data['results'][i]['type']])
# 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:
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()
uni_bytes.append([salts[0], uni_hash[0], salts[1], uni_hash[1],
salts[2], uni_hash[2], salts[3], uni_hash[3], y, i])
flag = "GY{" + hash_final_str + "}"
flags.append([y, flag])
for i in submissions:
found_flag=False
done_flag=False
# if flag is directly copied
for y in flags:
if(i[0]==y[1]):
found_flag=True
if(y[0]!=teams[i[1]]):
print(teams[i[1]] + " has cheated with " + y[0] + " on challenge "
+ chals_data[i[2]] + " with 100% probability!")
done_flag=True
if(done_flag):
continue
# if we only found the identifying bytes used at some point
i_hash=i[0].replace("GY{", "")
i_hash=i_hash.replace("}", "")
i_hash=bytes.fromhex(i_hash)
for y in uni_bytes:
if(i_hash[y[0]] == y[1] and i_hash[y[2]] == y[3] and i_hash[y[4]] ==
y[5] and i_hash[y[6]] == y[7] and teams[i[1]]!=y[8]):
print("identifying bytes from team " + y[8] + " in challenge " +
y[9] + " used by " +
teams[i[1]] + " on challenge " + chals_data[i[2]] +
"; this has a 0.0000000002% (1/256**4) chance of happening"
+ " approximately, a manual verification is needed")
done_flag=True
if(done_flag):
continue
# otherwise if the flag validated but we have no clue who they stole from
if(i[3]=="correct" and found_flag==False):
print(teams[i[1]] + " has somehow removed indentifying bytes on challenge "
+ chals_data[i[2]] + " and validated it, they most likely" +
" cheated but are somewhat smart!")