Skip to content

Instantly share code, notes, and snippets.

@telecastr
Last active April 24, 2021 17:40
Show Gist options
  • Save telecastr/c074d7f22c93e1f8bbdf6b4d7dded747 to your computer and use it in GitHub Desktop.
Save telecastr/c074d7f22c93e1f8bbdf6b4d7dded747 to your computer and use it in GitHub Desktop.
HTB - Cyberapocalypse 2021 - Off The Grid (HW) - Rough Writeup

Off the grid

  • Given is a data-stream to an SH1306-OLED display

  • SH1306 is slightly different to well known SSD1306, differences in Protocol

  • Basic explanation of SSD1306 display: lastminuteengineers.com

  • SSD1306 datasheet: adafruit.com

  • SH1306 seems to only support page addressing mode. This can also be seen on the data stream itself - 128 Bytes are transmitted in one go = 128 Lines*8 Rows at 1 bit 'color-depth' (black/white)

  • Correct Settings for Saleae Logic can be determined from the capture itself or the shematic given by HTB: screens

  • After exporting the Saleae Logic analyser result as .csv, the protocol can be reversed/display can be emulated and the pixel-stream can be saved to an image file

  • Exploit (input: .csv data, output: .bmp files):

    import csv
    from PIL import Image
    import numpy
    
    
    with open('data.csv', 'r') as file:
        reader = csv.reader(file)
        data = list(zip(*reader))[1][1:]
        # Filter null values
        filtered = list(filter(None, data))
        # Skip display initialisation
        filtered = filtered[25:]
    
        # Split at page init 0xB0 0x02 0x10
        raw_images = [s.split() for s in ' '.join(filtered).split('0xB0 0x02 0x10') if s]
    
        images = {}
        # Split every 128bytes (=one colum) and skip three bytes column init
        # Overall: Six images, each with eight pages
        for i in range(0,5):
            images[i] = [raw_images[0][x:x+128] for x in range(0, len(raw_images[i]),131)]
    
        # Convert hex value (string) to padded binary string for each of the eight rows in each image
        #  '0x00' -> ['0','0','0','0','0','0'.'0','0'], '0xFF' -> '['1','1','1','1','1','1','1','1'] 
        for i in range(0,8):
            for n in range(0,5):
                images[n][i] = [list(bin(int(row, 0))[2:].zfill(8)) for row in images[n][i]]
    
        for i in range(0,5):   
            # Python foo: Left-rotate list
            rotated = [list(zip(*row))[::-1] for row in images[i]]
            # Python foo: Flatten array = Combine rows to one picture
            flat_list = [item for sublist in rotated for item in sublist]
            arr = numpy.array(flat_list)
            # arr.asInt() will cause problem with PIL!
            arr = numpy.uint8(arr)
    
            # Scale binary to greyscale, create image
            img = Image.fromarray(arr * 255, mode='L')
            img.save('image{}.bmp'.format(i))        
  • Exploit-Output:

    screens

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment