TJCTF
Pretty easy ctf good for beginners like me!
Name
Category
1
bacon-bits
❯ ls
enc.py out.txtwith open('flag.txt') as f: flag = f.read().strip()
with open('text.txt') as t: text = t.read().strip()
baconian = {
'a': '00000', 'b': '00001',
'c': '00010', 'd': '00011',
'e': '00100', 'f': '00101',
'g': '00110', 'h': '00111',
'i': '01000', 'j': '01000',
'k': '01001', 'l': '01010',
'm': '01011', 'n': '01100',
'o': '01101', 'p': '01110',
'q': '01111', 'r': '10000',
's': '10001', 't': '10010',
'u': '10011', 'v': '10011',
'w': '10100', 'x': '10101',
'y': '10110', 'z': '10111'}
text = [*text]
ciphertext = ""
for i,l in enumerate(flag):
if not l.isalpha(): continue
change = baconian[l]
ciphertext += "".join([ts for ix, lt in enumerate(text[i*5:(i+1)*5]) if int(change[ix]) and (ts:=lt.upper()) or (ts:=lt.lower())]) #python lazy boolean evaluation + walrus operator
with open('out.txt', 'w') as e:
e.write(''.join([chr(ord(i)-13) for i in ciphertext]))baconian = {
'a': '00000', 'b': '00001',
'c': '00010', 'd': '00011',
'e': '00100', 'f': '00101',
'g': '00110', 'h': '00111',
'i': '01000', 'j': '01000',
'k': '01001', 'l': '01010',
'm': '01011', 'n': '01100',
'o': '01101', 'p': '01110',
'q': '01111', 'r': '10000',
's': '10001', 't': '10010',
'u': '10011', 'v': '10011',
'w': '10100', 'x': '10101',
'y': '10110', 'z': '10111'
}
reverse_baconian = {}
for key, value in baconian.items():
if value not in reverse_baconian:
reverse_baconian[value] = key
with open('out.txt', 'r') as f:
out_txt_full = f.read().strip()
truncated_len = (len(out_txt_full) // 5) * 5
out_txt_content = out_txt_full[:truncated_len]
intermediate_ciphertext = "".join([chr(ord(c) + 13) for c in out_txt_content])
binary_flag_string = ""
for char_val in intermediate_ciphertext:
if 'a' <= char_val <= 'z':
binary_flag_string += '0'
elif 'A' <= char_val <= 'Z':
binary_flag_string += '1'
else:
binary_flag_string += '?'
recovered_chars = []
for i in range(0, len(binary_flag_string), 5):
chunk = binary_flag_string[i:i+5]
if len(chunk) == 5:
recovered_chars.append(reverse_baconian.get(chunk, f"[?{chunk}?]"))
else:
recovered_chars.append(f"[SHORT:{chunk}]")
recovered_content = "".join(recovered_chars)
print("tjctf{" + recovered_content[5:] + "}")❯ python3 solve.py
tjctf{oinkooinkoooinkooooink}2
alchemist-recipe
❯ ls
encrypted.txt chall.pyimport hashlib
SNEEZE_FORK = "AurumPotabileEtChymicumSecretum"
WUMBLE_BAG = 8
def glorbulate_sprockets_for_bamboozle(blorbo):
zing = {}
yarp = hashlib.sha256(blorbo.encode()).digest()
zing['flibber'] = list(yarp[:WUMBLE_BAG])
zing['twizzle'] = list(yarp[WUMBLE_BAG:WUMBLE_BAG+16])
glimbo = list(yarp[WUMBLE_BAG+16:])
snorb = list(range(256))
sploop = 0
for _ in range(256):
for z in glimbo:
wob = (sploop + z) % 256
snorb[sploop], snorb[wob] = snorb[wob], snorb[sploop]
sploop = (sploop + 1) % 256
zing['drizzle'] = snorb
return zing
def scrungle_crank(dingus, sprockets):
if len(dingus) != WUMBLE_BAG:
raise ValueError(f"Must be {WUMBLE_BAG} wumps for crankshaft.")
zonked = bytes([sprockets['drizzle'][x] for x in dingus])
quix = sprockets['twizzle']
splatted = bytes([zonked[i] ^ quix[i % len(quix)] for i in range(WUMBLE_BAG)])
wiggle = sprockets['flibber']
waggly = sorted([(wiggle[i], i) for i in range(WUMBLE_BAG)])
zort = [oof for _, oof in waggly]
plunk = [0] * WUMBLE_BAG
for y in range(WUMBLE_BAG):
x = zort[y]
plunk[y] = splatted[x]
return bytes(plunk)
def snizzle_bytegum(bubbles, jellybean):
fuzz = WUMBLE_BAG - (len(bubbles) % WUMBLE_BAG)
if fuzz == 0:
fuzz = WUMBLE_BAG
bubbles += bytes([fuzz] * fuzz)
glomp = b""
for b in range(0, len(bubbles), WUMBLE_BAG):
splinter = bubbles[b:b+WUMBLE_BAG]
zap = scrungle_crank(splinter, jellybean)
glomp += zap
return glomp
def main():
try:
with open("flag.txt", "rb") as f:
flag_content = f.read().strip()
except FileNotFoundError:
print("Error: flag.txt not found. Create it with the flag content.")
return
if not flag_content:
print("Error: flag.txt is empty.")
return
print(f"Original Recipe (for generation only): {flag_content.decode(errors='ignore')}")
jellybean = glorbulate_sprockets_for_bamboozle(SNEEZE_FORK)
encrypted_recipe = snizzle_bytegum(flag_content, jellybean)
with open("encrypted.txt", "w") as f_out:
f_out.write(encrypted_recipe.hex())
print(f"\nEncrypted recipe written to encrypted.txt:")
print(encrypted_recipe.hex())
if __name__ == "__main__":
main()import hashlib
SNEEZE_FORK = "AurumPotabileEtChymicumSecretum"
WUMBLE_BAG = 8
def glorbulate_sprockets_for_bamboozle(blorbo):
zing = {}
yarp = hashlib.sha256(blorbo.encode()).digest()
zing['flibber'] = list(yarp[:WUMBLE_BAG])
zing['twizzle'] = list(yarp[WUMBLE_BAG:WUMBLE_BAG+16])
glimbo = list(yarp[WUMBLE_BAG+16:])
snorb = list(range(256))
sploop = 0
for _ in range(256):
for z in glimbo:
wob = (sploop + z) % 256
snorb[sploop], snorb[wob] = snorb[wob], snorb[sploop]
sploop = (sploop + 1) % 256
zing['drizzle'] = snorb
return zing
def prepare_decryption_sprockets(sprockets):
inv_drizzle = [0] * 256
for i, val in enumerate(sprockets['drizzle']):
inv_drizzle[val] = i
sprockets['inv_drizzle'] = inv_drizzle
wiggle = sprockets['flibber']
waggly = sorted([(wiggle[i], i) for i in range(WUMBLE_BAG)])
zort = [oof for _, oof in waggly]
sprockets['zort'] = zort
return sprockets
def unscrungle_crank(plunk_block, sprockets):
zort = sprockets['zort']
splatted_recovered_list = [0] * WUMBLE_BAG
for y in range(WUMBLE_BAG):
splatted_recovered_list[zort[y]] = plunk_block[y]
splatted_recovered = bytes(splatted_recovered_list)
quix = sprockets['twizzle']
zonked_recovered_list = [splatted_recovered[i] ^ quix[i % len(quix)] for i in range(WUMBLE_BAG)]
zonked_recovered = bytes(zonked_recovered_list)
inv_drizzle = sprockets['inv_drizzle']
dingus_recovered_list = [inv_drizzle[x] for x in zonked_recovered]
dingus_recovered = bytes(dingus_recovered_list)
return dingus_recovered
def unsnizzle_bytegum(encrypted_glomp, jellybean):
decrypted_padded_bytes = b""
for b_idx in range(0, len(encrypted_glomp), WUMBLE_BAG):
cipher_block = encrypted_glomp[b_idx : b_idx + WUMBLE_BAG]
plain_block = unscrungle_crank(cipher_block, jellybean)
decrypted_padded_bytes += plain_block
pad_val = decrypted_padded_bytes[-1]
return decrypted_padded_bytes[:-pad_val]
def main_decrypt():
with open("encrypted.txt", "r") as f_in:
hex_encrypted_recipe = f_in.read().strip()
encrypted_recipe_bytes = bytes.fromhex(hex_encrypted_recipe)
print(f"Encrypted recipe (hex): {hex_encrypted_recipe}")
jellybean = glorbulate_sprockets_for_bamboozle(SNEEZE_FORK)
jellybean_for_decryption = prepare_decryption_sprockets(jellybean)
decrypted_flag_content = unsnizzle_bytegum(encrypted_recipe_bytes, jellybean_for_decryption)
print(f"\nDecrypted content (bytes): {decrypted_flag_content}")
print(f"Decrypted content (utf-8): {decrypted_flag_content.decode(errors='replace')}")
if __name__ == "__main__":
main_decrypt()❯ python3 solve.py
Encrypted recipe (hex): b80854d7b5920901192ea91ccd9f588686d69684ec70583abe46f6747e940c027bdeaa848ecb316e11d9a99c7e87b09e
Decrypted content (bytes): b'tjctf{thank_you_for_making_me_normal_again_yay}'
Decrypted content (utf-8): tjctf{thank_you_for_making_me_normal_again_yay}Last updated