Insomni'Hack CTF Teaser 2022 - DrJeb [Misc]

We participated as r3vengers (Ripp3rs + Scavenger Security), and scored 34th out of almost 500 teams, with 6/15 challenges solved.

Description:

Dr. Jeb was able to analyze the virus in depth. He believes in the power of open source so his disassembler is publicly available here.
It's time to check his research with practice.

This challenge was completed by 271/500 teams.

Unintended solution

We are given the following source code:

import numpy as np
from PIL import Image
import sys
# Very important
from doctorsecret.const import SECRET

def Dissasemble(img_path):

    img = Image.open(img_path, 'r')
    data = np.array(list(img.getdata()))
    data = data[::SECRET,:]
    tot_pixels = data.shape[0]

    tmp_bits = ""
    for p in range(tot_pixels):
        tmp_bits += (bin(data[p][2])[-1])
    tmp_bits = [tmp_bits[i:i+8] for i in range(0, len(tmp_bits), 8)]

    message = ""
    for i in range(len(tmp_bits)):
        newchar = chr(int(tmp_bits[i], 2))
        message += newchar
    return message


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Example: python3 VirusDissasembler.py <image_path>")
    else:
        print(Dissasemble(sys.argv[1]))

Where we notice the "Very important" comment just before the from doctorsecret.const import SECRET, basically this code is trying to import a SECRET value from the file named const.py inside the doctorsecret folder, however we don't have those files.

And an image file to test the tool:

We don't know what value is SECRET holding, so I tried to bruteforce the key adding a REGEX looking up for a flag matching the format INS{, as the SECRET value is being use to select an index of the numpy array, it must be an integer:

So I came up with the following python script based on the original code to bruteforce the value:

import numpy as np                                                                                                                                                                            
from PIL import Image                                                                                                                                                                         
import sys                                                                                                                                                                                    
# Very important                                                                                                                                                                              
# from doctorsecret.const import SECRET                                                                                                                                                       
                                                                                                                                                                                              
def Dissasemble(img_path, SECRET):                                                                                                                                                            
    img = Image.open(img_path, 'r')                                                                                                                                                           
    data = np.array(list(img.getdata()))                                                                                                                                                      
    data = data[::SECRET,:]                    
    tot_pixels = data.shape[0]
                                                    
    tmp_bits = ""                        
    for p in range(tot_pixels):                                                                          
        tmp_bits += (bin(data[p][2])[-1])      
    tmp_bits = [tmp_bits[i:i+8] for i in range(0, len(tmp_bits), 8)]                           
                                                    
    message = ""                          
    for i in range(len(tmp_bits)):
        newchar = chr(int(tmp_bits[i], 2))
        message += newchar                     
    return message
                                                    
def generator():        
        seed = 1                                                                                         
        pattern = "INS{"                                                                                 
        while pattern not in Dissasemble(sys.argv[1], seed):                                   
                # print(f"[-] Attempt: {seed}") # Debug only                                     
                seed += 1     

        success(pattern, seed)
                                                                                                         
def success(pattern, seed):                                                                              
        print(f"[+] Pattern \"{pattern}\" found in seed {seed}:")                              
        print(f"[+] SECRET value might be: {seed}")                                                                                    
        print(Dissasemble(sys.argv[1], seed))       
                                                    
if __name__ == "__main__":                                                                               
    if len(sys.argv) != 2:                          
        print("Example: python3 VirusDissasembler.py <image_path>")                                                                    
    else:                                                                                                
        generator()

Flag: INS{W3LCOME_2o22_1NS0_B3_Car3fuL}

Intended solution:

When I solved the challenge, I didn't notice that in the same Github profile the challenge's code was uploaded to, there was another repo named secret1234, with a doctorsecret/const.py library holding the value 133 for the SECRET variable.

At this point there are two ways of solving this challenge, the first one being copying the doctorsecret/const.py file inside our challenge's repo, and the second one hardcoding the SECRET variable value in the code, I'm showing you the second method:

import numpy as np
from PIL import Image
import sys
# Very important
# from doctorsecret.const import SECRET

def Dissasemble(img_path):
    SECRET = 133
    img = Image.open(img_path, 'r')
    data = np.array(list(img.getdata()))
    data = data[::SECRET,:]
    tot_pixels = data.shape[0]

    tmp_bits = ""
    for p in range(tot_pixels):
        tmp_bits += (bin(data[p][2])[-1])
    tmp_bits = [tmp_bits[i:i+8] for i in range(0, len(tmp_bits), 8)]

    message = ""
    for i in range(len(tmp_bits)):
        newchar = chr(int(tmp_bits[i], 2))
        message += newchar
    return message


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Example: python3 VirusDissasembler.py <image_path>")
    else:
        print(Dissasemble(sys.argv[1]))

Flag: INS{W3LCOME_2o22_1NS0_B3_Car3fuL}