Frames & Stories Writeup

By
Gincy Mol A G
Published on
20 Sep 2020
6 min read
DOMECTF2020

Story

Sam is a photographer and the police have found out that he is trying to convey some sensitive information through his portfolio website. Help them find out what it is.

Solution

https://photographic.domectf.in/ is a website and with so many images in it.

There is a puzzle file which will be in the path https://photographic.domectf.in/puzzle/puzzle.txt and the hint is given in the robots.txt.

Puzzle.txt file contains:

        #!AES-CBC
        
        IV = ?
        KEY = boq33vPAIYbtj
        PLAINTEXT = ?
        CIPHER = c5........................f7160864f9bab6e3547d76d429712085ece154
        
        Flag : domectf{key + iv}

   

Since it is aes-cbc encryption and plaintext is missing in the file.

Zsteg tool gives the result for the image - 9.webp :

frames-and-stories1

It implies, the stego image is hiding the plaintext, the image is applied with LSB steganography and the plaintext is encrypted with morse code. It can be decoded and will get the message

        PLAINTEXT IS HERE : DDDBEAAEACDCCDDCDDEABDDCBCCDEAAEDBBBCDEABBAACDCDEABCCCEADADADBCB
    

Since the plaintext is encrypted and the cipher only contains 5 alphabets A to E, it’s a polybius cipher. But when decrypting it it wont give the correct message. So reverse the cipher

        BCBDADADAECCCBAEDCDCAABBAEDCBBBDEAAEDCCBCDDBAEDDCDDCCDCAEAAEBDDD
    

and decrypt it. Decryption can be done using the code:

        from pycipher import PolybiusSquare
        poly = PolybiusSquare(key='abcdefghiklmnopqrstuvwxyz', size=5, chars=None)
        msg = poly.decipher(message)
    

The msg will be the Plaintext , “HIDDENMESSAGESGIVESMORETOSOLVEIT”.

The puzzle will be complete only if the key and iv are discovered. Cipher 2 and some parts of the cipher 1 and key with missing 3 bytes (since aes key is 16 bytes) are given. We need to find the complete key and then the iv.

CIPHER = c5……………………f7160864f9bab6e3547d76d429712085ece154

Cipher 1 (16 bytes)= c5000000000000000000000000f71608 (unknown parts padded by zeros)

Cipher 2 (16 bytes) = 64f9bab6e3547d76d429712085ece154

Plain 1 (16 bytes) = “HIDDENMESSAGESGI”

Plain 2 (16 bytes) = “VESMORETOSOLVEIT”

Step 1: Find key

In aes decryption, after decrypting the n block the result will xor with n-1 block to produce the plaintext. We know the Cipher2, the Plaintext and parts of the Cipher1. Therefore we can brute force the key’s last three characters by decrypting the Cipher2 with all possible keys, xor it with the Cipher1 and check for which key the first letter and last three letters of the result match to the original Plaintext.

Step 2: Find cipher1

Now since the key is known, we can use the logic of aes decryption but use plain text as iv to recover Cipher 1, ie, decrypting Cipher 2 with the key found and xor the result with Plain 2.

Step 3: Find iv

To find iv use the same logic that we used for finding cipher 1, ie, decrypting cipher 1 with key and xor the result with plain 1.

We can recover it by;

        from Crypto.Cipher import AES
        from operator import xor
        import binascii
        
        KEY_given = "boq33vPAIYbtj"
        cipher1 = "c5000000000000000000000000f71608"
        cipher2 = "64f9bab6e3547d76d429712085ece154"
        plain1 = "HIDDENMESSAGESGI"
        plain2 = "VESMORETOSOLVEIT"
        
        def decrypt(c, k):
            aes = AES.new(k, AES.MODE_CBC, binascii.unhexlify(cipher1))
            return aes.decrypt(c)
        
        def find_key():
            for i in range(32, 126):
                for j in range(32, 126):
                    for k in range(32, 126):
                        key = KEY_given + chr(i) + chr(j) + chr(k)
                        dec_plain2 = decrypt(binascii.unhexlify(cipher2), key)
                        dplain2 = dec_plain2.decode('utf-8', 'ignore')
                        if str(dplain2).startswith(plain2[0]) and str(dplain2).endswith(plain2[-3:]):
                            return key
        
        def decrypt_cipher1(c,k):
            aes = AES.new(k,AES.MODE_CBC,plain2)
            return aes.decrypt(c)
        
        def decrypt_iv(c,k):
            aes = AES.new(k,AES.MODE_CBC,plain1)
            return aes.decrypt(c)
        
        # find the complete key
        Key = find_key()                                                                            
        # find the cipher1
        cipher1_final = binascii.hexlify(decrypt_cipher1(binascii.unhexlify(cipher2), Key)).decode()                           				             
        #find iv
        iv = decrypt_iv(binascii.unhexlify(cipher1_final), Key).decode()
    

ie,

domectf{boq33vPAIYbtj70e4d6kBFyHpSOeHdf8} is the flag

Automated human-like penetration testing for your web apps & APIs
Teams using Beagle Security are set up in minutes, embrace release-based CI/CD security testing and save up to 65% with timely remediation of vulnerabilities. Sign up for a free account to see what it can do for you.

Written by
Gincy Mol A G
Gincy Mol A G
AI Engineer
Experience the Beagle Security platform
Unlock one full penetration test and all Advanced plan features free for 10 days
Find surface-level website security issues in under a minute
Free website security assessment
Experience the power of automated penetration testing & contextual reporting.