Rating: 5.0

## Unvreakable Vase


Ah shoot, I dropped this data and now it's all squished and flat. Can you make any sense of this?


In this challenge, we're also given a text file prompt.txt:


zmxhz3tkb2vzx3roaxnfzxzlbl9jb3vudf9hc19jcnlwdg9vb30=


This looks like Base64, but where are all the upper-case letters? Base64 encoding flag{ gives us ZmxhZ3s=, from that we can deduce that the problem lies with all the upper-case letters being turned to lower case. As a result, decoding the ciphertext results in ÎlaÏ{dokóÇzèk.ßÏ.ån_co{îuÿas_crypv.oo}, mostly gibberish, but you can see fragments of the flag. At my first attempt at this, I simply went through all the letters and tested, slowly revealing the flag, but for the purposes of this writeup, I think it's beneficial to look at a more algorithmic solution. Here's a python script that solves for the flag, it's richly commented such that it's easy to follow:

python
import base64

#declare ciphertext (could do open("prompt.txt","r").read(), but just easier to paste the string)
ct = "zmxhz3tkb2vzx3roaxnfzxzlbl9jb3vudf9hc19jcnlwdg9vb30="
#decode base64
def dec(n):
return base64.b64decode(n)
#change the casing of a block
def tryCase(n,i):
#get i as 4-bit binary number
b =format(i, '#06b')[2:]
#declare a variable for each character in chunk
c1=n[0]
c2=n[1]
c3=n[2]
c4=n[3]
#set them to upper if their respective bit is 1
if b[0]=='1':
c1=c1.upper()
if b[1]=='1':
c2=c2.upper()
if b[2]=='1':
c3=c3.upper()
if b[3]=='1':
c4=c4.upper()
#return the result
return c1+c2+c3+c4
#check if the decoded b64 falls within valid flag-characters
def isValid(n):
try:
#try to decode, if n contains non-ASCII characters, will automatically return false
b=n.decode()
#interate through decoded n
for i in b:
#if decoded n is less than 32 i.e. where pritable characters start, return false
if ord(i)<32:
return False
#if n gets here, we can be sure it's a good character and we can return true
return True
except:
return False
#split the ciphertext into 4 character blocks (aka 3-character chunks in plaintext)
blocks = [ct[i:i+4] for i in range(0, len(ct), 4)]
#declares plaintext
pt=""
#iterates blocks
for i in blocks:
#iterates the 16 possible states a block can have (4 characters each either upper- or lower-case)
for j in range(16):
#define c as a test-case for the state of the block
c = dec(tryCase(i,j))
#check if c is valid
if isValid(c):
#if yes, append decoded chunk to plaintext and continue to the next block
pt+=c.decode()
break
#print the plaintext
print(pt)



Running this script returns the flag:

flag{does_this_even_count_as_cryptooo}

Original writeup (https://github.com/williamsolem/NahamCon-CTF-2020-Writeup).