Rating: 4.5

## [Original/Source Writeup](https://bigpick.github.io/TodayILearned/articles/2020-10/b01lersbootcamp#totem)

We’re also given a template to get started, but I didn’t bother using that, since I’m not a total n00b.

Connecting to the endpoint, we get a game that gives us the encryption method, and the ciphertext, and asks us for the original plaintext:


nc chal.ctf.b01lers.com 2008
Method: rot13
Ciphertext: jbeyq
Input: world
Method: Base64
Ciphertext: c3Vycm91bmQ=
Input: c3Vycm91bmQ=
Hm that doesn't seem quite right we must be awake.


After playing around manually to try to find all possible encryptions, I found the following to be possible:

1. [ROT13](https://rot13.com/)
2. [base64](https://www.base64decode.org/)
3. [atbash](https://en.wikipedia.org/wiki/Atbash)
4. [Baconian](https://en.wikipedia.org/wiki/Bacon%27s_cipher)

From the template, we can expect there to be 1000 total rounds. With this knowledge, we can code something up in Python that just repeatedly receives and then solves the challenge (creds for the baconian/atbash cipher in comments):

python
#!/usr/bin/env python3.8
from pwn import *
import sys
from base64 import b64decode

atbash_cipher = {'A': 'Z', 'a': 'z', 'B': 'Y', 'b': 'y', 'C': 'X', 'c': 'x', 'D': 'W', 'd': 'w', 'E': 'V', 'e': 'v', 'F': 'U', 'f': 'u', 'G': 'T', 'g': 't', 'H': 'S', 'h': 's', 'I': 'R', 'i': 'r', 'J': 'Q', 'j': 'q', 'K': 'P', 'k': 'p', 'L': 'O', 'l': 'o', 'M': 'N', 'm': 'n', 'N': 'M', 'n': 'm', 'O': 'L', 'o': 'l', 'P': 'K', 'p': 'k', 'Q': 'J', 'q': 'j', 'R': 'I', 'r': 'i', 'S': 'H', 's': 'h', 'T': 'G', 't': 'g', 'U': 'F', 'u': 'f', 'V': 'E', 'v': 'e', 'W': 'D', 'w': 'd', 'X': 'C', 'x': 'c', 'Y': 'B', 'y': 'b', 'Z': 'A', 'z': 'a', ' ': ' ', '.': '.', ',': ',', '?': '?', '!': '!', '\'': '\'', '\"': '\"', ':': ':', ';': ';', '$$': '$$', '\)': '\)', '$': '\[', '$': '\]', '\-': '\-', '1': '1', '2': '2', '3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9', '0': '0'}

def rot_alpha(n):
from string import ascii_lowercase as lc, ascii_uppercase as uc
lookup = str.maketrans(lc + uc, lc[n:] + lc[:n] + uc[n:] + uc[:n])
return lambda s: s.translate(lookup)

# https://stackoverflow.com/a/45717802/13158274
# -- Jérôme
class AtBash:

def __init__(self):
self.alphabets = ' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()_+|:"<>-=[];,.?/' self.alphabets = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_{|}'

def encode(self, plaintext):
cipher = ""
for i in plaintext:
index = self.alphabets.index(i)
cipher += self.alphabets[abs(len(self.alphabets) - index - 1) % len(self.alphabets)]
return cipher

def decode(self, ciphertext):
return self.encode(ciphertext)

# https://www.geeksforgeeks.org/baconian-cipher/
def decrypt_bacon(message):
lookup = {'A':'aaaaa', 'B':'aaaab', 'C':'aaaba', 'D':'aaabb', 'E':'aabaa',
'F':'aabab', 'G':'aabba', 'H':'aabbb', 'I':'abaaa', 'J':'abaab',
'K':'ababa', 'L':'ababb', 'M':'abbaa', 'N':'abbab', 'O':'abbba',
'P':'abbbb', 'Q':'baaaa', 'R':'baaab', 'S':'baaba', 'T':'baabb',
'U':'babaa', 'V':'babab', 'W':'babba', 'X':'babbb', 'Y':'bbaaa', 'Z':'bbaab'}

decipher = ''
i = 0

# emulating a do-while loop
while True :
# condition to run decryption till
# the last set of ciphertext
if(i < len(message)-4):
# extracting a set of ciphertext
# from the message
substr = message[i:i + 5]
# checking for space as the first
# character of the substring
if(substr[0] != ' '):
'''
This statement gets us the key(plaintext) using the values(ciphertext)
Just the reverse of what we were doing in encrypt function
'''
decipher += list(lookup.keys())[list(lookup.values()).index(substr)]
i += 5 # to get the next set of ciphertext

else:
decipher += ' '
i += 1 # index next to the space
else:
break # emulating a do-while loop

return decipher

def main():
r = remote('chal.ctf.b01lers.com', 2008)
i = 0
while 1 < 2:
print("=== ", i)
method = r.recvline().decode().strip().split()[-1]
ct = r.recvline().decode().strip().split()[-1]
plaintext = ""
if method == "atbash":
for char in ct:
plaintext += atbash_cipher[char]
r.sendafter('Input: ', plaintext+'\n')
elif method == "rot13":
r.sendafter('Input: ', rot_alpha(13)(ct)+'\n')
elif method == "Base64":
r.sendafter('Input: ', b64decode(ct).decode()+'\n')
elif method == "bacon":
r.sendafter('Input: ', decrypt_bacon(ct.lower()).lower()+'\n')
i += 1
if i == 1000:
print(r.stream())
sys.exit(0)

if __name__ == '__main__':
main()


Which after running, gives us the flag:


...
=== 993
=== 994
=== 995
=== 996
=== 997
=== 998
=== 999
We must be dreaming, here's your flag: ctf{4n_313g4nt_s01ut10n_f0r_tr4cking_r341ity}
b"We must be dreaming, here's your flag: ctf{4n_313g4nt_s01ut10n_f0r_tr4cking_r341ity}\n"


Flag is ctf{4n_313g4nt_s01ut10n_f0r_tr4cking_r341ity}.