Passchecker Writeup
from vsCTF
We were given passchecker2000.py
def validate(password: str) -> bool:
if len(password) != 49:
return False
key = ['vs'.join(str(randint(7, 9)) for _ in range(ord(i))) + 'vs' for i in password[::-2]]
gate = [118, 140, 231, 176, 205, 480, 308, 872, 702, 820, 1034, 1176, 1339, 1232, 1605, 1792, 782, 810, 1197, 880,
924, 1694, 2185, 2208, 2775]
if [randint(a, b[0]) for a, b in enumerate(zip(gate, key), 1) if len(b[1]) != 3 * (b[0] + 7 * a) // a]:
return False
hammer = {str(a): password[a] + password[a + len(password) // 2] for a in range(1, len(password) // 2, 2)}
block = b'c3MxLnRkMy57XzUuaE83LjVfOS5faDExLkxfMTMuR0gxNS5fTDE3LjNfMTkuMzEyMS5pMzIz'
if b64encode(b'.'.join([((b + a).encode()) for a, b in hammer.items()])) != block:
return False
return True
if __name__ == "__main__":
passwd = input('Please validate your ID using your password\n> ')
if validate(passwd):
print('Access Granted: You now have gained access to the View Source Flag Vault!')
else:
print('Access Denied :(')
the main function takes in a password and determines if it is valid. We want to get a valid password since that would be the flag. The validate function has three conditions that we must pass in order to get the flag.
1st one is a simple length check: ```if len(password) != 49: return False
I commented this out so I could examine the workings of the rest of the challenge
the second obstacle for the password is a permutation that takes the string provided, goes from back to front, skipping every other letter, and converting to some kind of cipher.
```key = ['vs'.join(str(randint(7, 9)) for _ in range(ord(i))) + 'vs' for i in password[::-2]]```
Every other letter from back to front has its `ord` or ascii number evaluated and used to create a list of string, where each string in the list contains the sequence of `[7,8,9]vs`, `n` times where n equals the `ord` number of the letter being evaluated.
A string like `a!!` would turn into an array of lenght two, the first element containing ord('!') = 33 sequences of `[7,8,9]vs` ... ie `7vs8vs7vs9vs7vs8vs...8vs', the second will have ord('a')= 97 sequences of the pattern.
The flag information is given in a form of numbers:
```gate = [118, 140, 231, 176, 205, 480, 308, 872, 702, 820, 1034, 1176, 1339, 1232, 1605, 1792, 782, 810, 1197, 880,
924, 1694, 2185, 2208, 2775]
if [randint(a, b[0]) for a, b in enumerate(zip(gate, key), 1) if len(b[1]) != 3 * (b[0] + 7 * a) // a]:
return False```
this gooky equation which basically says for each element in the gate, add 7 * current index (starting at 1 not 0) and divide the sum by the current index then convert the product to a character (int to chr)
Copying the gate list to a separate python file, we can then compute the flag with this: equation
```a = ""
counter = 1
for g in gate:
character = chr(int((g + 7*counter)//counter))
counter +=1
a+=character
print(a) #v_c_f_T_3_3_F_4_5_w_r___n_i_e_Y_U_t_3_W_0_3_T_M_}
This lets us know every other character in the flag. To get the other half of the flag we must go through this challenge:
```hammer = {str(a): password[a] + password[a + len(password) // 2] for a in range(1, len(password) // 2, 2)} block = b’c3MxLnRkMy57XzUuaE83LjVfOS5faDExLkxfMTMuR0gxNS5fTDE3LjNfMTkuMzEyMS5pMzIz’ if b64encode(b’.’.join([((b + a).encode()) for a, b in hammer.items()])) != block: return False
this basically takes a block of bytes and encodes indexes and values of the remaining letters. To decode the block we do
```rush = [a.decode() for a in b64decode(b'c3MxLnRkMy57XzUuaE83LjVfOS5faDExLkxfMTMuR0gxNS5fTDE3LjNfMTkuMzEyMS5pMzIz').split(b'.')]
print(rush) # ['ss1', 'td3', '{_5', 'hO7', '5_9', '_h11', 'L_13', 'GH15', '_L17', '3_19', '3121', 'i323']```
each string has 3 pieces of information encoded like so:
`1st character: character 1`
`2nd character: character 2`
`3rd character onwards: position of the 1st character `
One thing we also seee from the code is that the 2nd character position is always 24 + position of the 1st character1
so we can decrypt this with:
```for a in rush:
print(a)
index = int(a[2:])
index2 = int(a[2:])+24
value1 = a[0]
value2 = a[1]
print(index, index2, value1, value2)
current_flag[index] = value1
current_flag[index2] = value2
print(current_flag) # vsctf{Th353_FL4G5_w3r3_inside_YOU_th3_WH0L3_T1M3}
we don’t have to rerun the program with the encrypted version of the flag since we know what the decyrpted version is.