Blog section
CTF

picoCTF 2024 Cryptography

picoCTF 2024 Cryptography writeups covering encryption, decryption, and cryptanalysis challenges.

picoCTFCTFCryptography

picoCTF 2024 - Cryptography

challenge screenshot

Cryptography Challenges

Solved: 4/5 challenges


interencdec

Tags: `Cryptography` `base64` `browser_webshell_solvable` `caesar`

Description

Can you get the real meaning from this file.

//enc_flag
YidkM0JxZGtwQlRYdHFhR3g2YUhsZmF6TnFlVGwzWVROclh6YzRNalV3YUcxcWZRPT0nCg==

Solution Strategy

import base64

encoded_base64 = "YidkM0JxZGtwQlRYdHFhR3g2YUhsZmF6TnFlVGwzWVROclh6YzRNalV3YUcxcWZRPT0nCg=="

print("Encoded base64 string:", encoded_base64)

decoded_bytes = base64.b64decode(encoded_base64)
decoded_string = decoded_bytes.decode("utf-8")

print("Decoded base64 string:", decoded_string)

import re
base64_pattern = "'(.*?)'"
base64_match = re.search(base64_pattern, decoded_string)
if base64_match:
    base64_text = base64_match.group(1)
else:
    raise ValueError("No base64 string found within single quotes")

print("Extracted base64 string:", base64_text)

decoded_text_bytes = base64.b64decode(base64_text)
decoded_text = decoded_text_bytes.decode("utf-8")

print("Decoded base64 text before shift:", decoded_text)

def caesar_cipher(text, shift):
    result = ""
    for char in text:
        if char.isalpha():
            shifted = ord(char) + shift
            if char.islower():
                if shifted > ord("z"):
                    shifted -= 26
                elif shifted < ord("a"):
                    shifted += 26
            elif char.isupper():
                if shifted > ord("Z"):
                    shifted -= 26
                elif shifted < ord("A"):
                    shifted += 26
            result += chr(shifted)
        else:
            result += char
    return result

shifted_text = caesar_cipher(decoded_text, 19)

print("Decoded and shifted base64 text:", shifted_text)
  • The script decodes a base64-encoded string (encoded_base64) using the base64 module and prints the decoded string.
  • It then extracts a substring from the decoded string using a regular expression pattern to find a base64 string within single quotes.
  • After decoding this extracted base64 string, it applies a Caesar Cipher with a shift of 19 to the decoded text using a custom function (caesar_cipher).
  • Finally, it prints the resulting text after applying the Caesar Cipher.
  • The overall purpose seems to be to decode a base64-encoded string, extract another base64 string from it, decode it, and then apply a Caesar Cipher with a specific shift to it.

Flag

challenge screenshot


Custom encryption

Tags: `Cryptography` `ASCII_encoding` `browser_webshell_solvable` `XOR`

Description

Can you make sense of this code file and write the function that will decode the given encrypted file content. Find the encrypted file here flag_info and code file might be good to analyze and get the flag.

//custom_encryption.py
from random import randint
import sys

def generator(g, x, p):
    return pow(g, x) % p

def encrypt(plaintext, key):
    cipher = []
    for char in plaintext:
        cipher.append(((ord(char) * key*311)))
    return cipher

def is_prime(p):
    v = 0
    for i in range(2, p + 1):
        if p % i == 0:
            v = v + 1
    if v > 1:
        return False
    else:
        return True

def dynamic_xor_encrypt(plaintext, text_key):
    cipher_text = ""
    key_length = len(text_key)
    for i, char in enumerate(plaintext[::-1]):
        key_char = text_key[i % key_length]
        encrypted_char = chr(ord(char) ^ ord(key_char))
        cipher_text += encrypted_char
    return cipher_text

def test(plain_text, text_key):
    p = 97
    g = 31
    if not is_prime(p) and not is_prime(g):
        print("Enter prime numbers")
        return
    a = randint(p-10, p)
    b = randint(g-10, g)
    print(f"a = {a}")
    print(f"b = {b}")
    u = generator(g, a, p)
    v = generator(g, b, p)
    key = generator(v, a, p)
    b_key = generator(u, b, p)
    shared_key = None
    if key == b_key:
        shared_key = key
    else:
        print("Invalid key")
        return
    semi_cipher = dynamic_xor_encrypt(plain_text, text_key)
    cipher = encrypt(semi_cipher, shared_key)
    print(f'cipher is: {cipher}')

if __name__ == "__main__":
    message = sys.argv[1]
    test(message, "trudeau")
//enc_flag
a = 94
b = 21
cipher is: [131553, 993956, 964722, 1359381, 43851, 1169360, 950105, 321574, 1081658, 613914, 0, 1213211, 306957, 73085, 993956, 0, 321574, 1257062, 14617, 906254, 350808, 394659, 87702, 87702, 248489, 87702, 380042, 745467, 467744, 716233, 380042, 102319, 175404, 248489]

Solution Strategy

def decrypt(ciphertext, key):
    plaintext = ""
    for num in ciphertext:
        decrypted_num = num // (key * 311)
        plaintext += chr(decrypted_num)
    return plaintext

def dynamic_xor_decrypt(ciphertext, text_key):
    decrypted_text = ""
    key_length = len(text_key)
    for i, char in enumerate(ciphertext):
        key_char = text_key[i % key_length]
        decrypted_char = chr(ord(char) ^ ord(key_char))
        decrypted_text += decrypted_char
    return decrypted_text

def find_shared_key(p, g, a, b):
    u = pow(g, a, p)
    v = pow(g, b, p)
    shared_key = pow(v, a, p)
    b_key = pow(u, b, p)
    if shared_key == b_key:
        return shared_key
    else:
        return None

def main():
    p = 97
    g = 31
    a = 94
    b = 21
    shared_key = find_shared_key(p, g, a, b)
    if shared_key is None:
        print("Invalid key")
        return
    
    ciphertext = [131553, 993956, 964722, 1359381, 43851, 1169360, 950105, 321574, 1081658, 613914, 0, 1213211, 306957, 73085, 993956, 0, 321574, 1257062, 14617, 906254, 350808, 394659, 87702, 87702, 248489, 87702, 380042, 745467, 467744, 716233, 380042, 102319, 175404, 248489]
    decrypted_text = decrypt(ciphertext, shared_key)
    decrypted_text = dynamic_xor_decrypt(decrypted_text, "trudeau")
    decrypted_text = decrypted_text[::-1]
    print("Decrypted text:", decrypted_text)

if __name__ == "__main__":
    main()

  • The decrypt function takes a list of ciphertext numbers and a key as input, then decrypts the ciphertext by dividing each number by the product of the key and a constant (311), converting the decrypted numbers to characters, and appending them to form the plaintext.
  • The dynamic_xor_decrypt function performs a dynamic XOR decryption on a ciphertext using a text-based key. It XORs each character of the ciphertext with the corresponding character from the key, repeating the key cyclically if necessary, and builds the decrypted text.
  • The find_shared_key function calculates a shared key using Diffie-Hellman key exchange algorithm parameters (p, g) and private keys (a, b). It computes intermediate values u and v, then derives the shared key using modular exponentiation.
  • In the main function, it initializes parameters for Diffie-Hellman key exchange (p, g, a, b) and calculates the shared key using find_shared_key.
  • It then decrypts a ciphertext list using the shared key and the decrypt function, followed by a dynamic XOR decryption using the dynamic_xor_decrypt function with the key "trudeau".
  • Finally, it reverses the decrypted text and prints the result.

Flag

challenge screenshot


C3

Tags: `Cryptography` `browser_webshell_solvable`

Description

This is the Custom Cyclical Cipher! Download the ciphertext here. Download the encoder here. Enclose the flag in our wrapper for submission. If the flag was "example" you would submit "picoCTF{example}".

//convert.py
import sys
chars = ""
from fileinput import input
for line in input():
  chars += line

lookup1 = "\n \"#()*+/1:=[]abcdefghijklmnopqrstuvwxyz"
lookup2 = "ABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrst"

out = ""

prev = 0
for char in chars:
  cur = lookup1.index(char)
  out += lookup2[(cur - prev) % 40]
  prev = cur

sys.stdout.write(out)
//ciphertext
DLSeGAGDgBNJDQJDCFSFnRBIDjgHoDFCFtHDgJpiHtGDmMAQFnRBJKkBAsTMrsPSDDnEFCFtIbEDtDCIbFCFtHTJDKerFldbFObFCFtLBFkBAAAPFnRBJGEkerFlcPgKkImHnIlATJDKbTbFOkdNnsgbnJRMFnRBNAFkBAAAbrcbTKAkOgFpOgFpOpkBAAAAAAAiClFGIPFnRBaKliCgClFGtIBAAAAAAAOgGEkImHnIl

Solution Strategy

ciphertext = "DLSeGAGDgBNJDQJDCFSFnRBIDjgHoDFCFtHDgJpiHtGDmMAQFnRBJKkBAsTMrsPSDDnEFCFtIbEDtDCIbFCFtHTJDKerFldbFObFCFtLBFkBAAAPFnRBJGEkerFlcPgKkImHnIlATJDKbTbFOkdNnsgbnJRMFnRBNAFkBAAAbrcbTKAkOgFpOgFpOpkBAAAAAAAiClFGIPFnRBaKliCgClFGtIBAAAAAAAOgGEkImHnIl"

lookup1 = "\n \"#()*+/1:=[]abcdefghijklmnopqrstuvwxyz"
lookup2 = "ABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrst"

out = ""
prev = 0

for char in ciphertext:
    cur = lookup2.index(char) + prev
    cur_mod = cur % len(lookup1) 
    out += lookup1[cur_mod]
    prev = cur_mod  
print(out)
  • Initialization: The ciphertext is defined as a string of characters. Two lookup tables, lookup1 and lookup2, contain a mix of symbols, numbers, and letters. An empty string out is initialized to hold the decrypted output, and a variable prev is set to 0 to track the position from the previous iteration.
  • Decryption process:
    • The script iterates over each character in the ciphertext.
    • For each character, it finds the character's index in lookup2 and adds this index to prev (initially 0).
    • The sum is then modulo-divided by the length of lookup1 to ensure the resulting index is within the bounds of lookup1. This result is stored in cur_mod.
    • The character at the cur_mod index of lookup1 is appended to the out string, building the decrypted message character by character.
    • The prev variable is updated to cur_mod for use in the next iteration.
  • Output: After iterating through the entire ciphertext, the decrypted message is stored in out, which is then printed to the console.
#This is output from solve.py 
 
#asciiorder
#fortychars
#selfinput
#pythontwo

chars = ""
from fileinput import input
for line in input():
    chars += line
b = 1 / 1

for i in range(len(chars)):
    if i == b * b * b:
        print chars[i] #prints
        b += 1 / 1
python solve.py > decode.txt

Flag

# Change Python2 --> Python3
#asciiorder
#fortychars
#selfinput
#pythontwo

chars = ""
from fileinput import input
for line in input():
    chars += line
b = 1

for i in range(len(chars)):
    if i == b * b * b:
        print(chars[i])  # prints
        b += 1
python flag.py < decode.txt

picoCTF{adlibs}

picoCTF{adlibs}


rsa_oracle

Tags: `Cryptography` `browser_webshell_solvable`

Description

Can you abuse the oracle? An attacker was able to intercept communications between a bank and a fintech company. They managed to get the message (ciphertext) and the password that was used to encrypt the message. After some intensive reconnaissance they found out that the bank has an oracle that was used to encrypt the password and can be found here nc titan.picoctf.net 52816. Decrypt the password and use it to decrypt the message. The oracle can decrypt anything except the password.

//secret.enc
Salted__ÿò(†Ñè-év\rAjž6<Cž·µ ^&šÕËòƒ€±q•¯\ª/KžÓÃÎ:ÆÊL€õ3'‘~
//pwd.enc
1634668422544022562287275254811184478161245548888973650857381112077711852144181630709254123963471597994127621183174673720047559236204808750789430675058597

Solution Strategy

#!/usr/bin/env python
from pwn import *
import subprocess

IP = 'titan.picoctf.net'
PORT = 52816

def get_target():
    return remote(IP, PORT)

with open('pwd.enc', 'r') as f:
    pas = f.read()
ipas = int(pas, 10)

t = get_target()

t.sendlineafter(b'decrypt.', b'E')
t.sendlineafter(':', p8(2))
t.recvuntil(b'(m ^ e mod n)')
c_a = int(t.recvline().strip())

t.sendlineafter(b'decrypt.', b'D')
t.sendlineafter(b':', str(c_a * ipas).encode())

t.recvuntil(b'(c ^ d mod n): ')
oracle = int(t.recvline().strip(), 0x10)

password = bytes.fromhex(hex(oracle // 2)[2:].rstrip("L")).decode()
print(f"Decrypted Password: {password}")

t.close()

command = ["openssl", "enc", "-aes-256-cbc", "-d", "-in", "secret.enc", "-k", password]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()

if process.returncode == 0:
    print("Decrypted Content:\n", stdout.decode())
else:
    print("Decryption failed:", stderr.decode())
  • Import and Setup
    • The script begins by importing necessary libraries: pwntools for network communication and subprocess for executing external commands.
    • The target encryption service is defined with its IP (titan.picoctf.net) and port (52816), indicating the script is designed to interact with a specific remote service.
  • Reading Encrypted Password
    • An encrypted password is read from a file named pwd.enc. This file contains the password needed to decrypt another file, but in encrypted form. The script reads this encrypted password and converts it to an integer (ipas), preparing it for further operations.
  • Establishing Connection
    • Utilizing pwntools, the script establishes a network connection to the remote encryption service. This connection is used to send commands to and receive responses from the service, facilitating remote exploitation.
  • Exploiting Encryption
    • Encryption Request: The script first instructs the remote service to encrypt the number 2. This step is crucial because it uses the service's own encryption functionality against it. The response, c_a, is the encrypted form of 2 according to the service's encryption scheme.
    • Crafting Decryption Request: Next, the script sends a decryption request, but with a twist. Instead of asking to decrypt a straightforward message, it requests the decryption of the product of c_a (the encrypted 2) and ipas (the encrypted password, now as an integer). This crafted request exploits specific vulnerabilities in the encryption algorithm's implementation, leveraging mathematical properties of RSA encryption to manipulate the service into performing operations that ultimately aid in reversing the encryption.
  • Decrypting the Password
    • Processing the Decryption Response: The service responds with oracle, the result of the decryption request. The script processes this response to extract the original password. By dividing oracle by 2 and converting it back from hexadecimal, the script effectively reverses the encryption applied to the original password. This step cleverly uses the properties of RSA encryption, where specific manipulations of encrypted data can yield useful decrypted outcomes.
  • File Decryption
    • Decrypting secret.enc: With the decrypted password now available, the script proceeds to decrypt secret.enc using OpenSSL. This step is straightforward: it runs an OpenSSL command with the AES-256-CBC decryption option, using the decrypted password as the key. The success of this operation hinges on correctly extracting the password in the previous steps.
  • Output Handling
    • The script evaluates the success of the decryption operation by checking the return code of the OpenSSL command. A return code of 0 indicates success, prompting the script to print the decrypted contents of secret.enc. If the operation fails, an error message is displayed instead.

Flag

challenge screenshot