Tags: forensics 

Rating:

of-course-rachel (150)

Problem

Ugh, I had a really important file with the flag, but sadly it broke. My friend Rachel said that snapshots are good for backing up, and luckily I listened so here is my screenshot. Do you think you could help me put it back together?

(Attachments: files/snapshot.zip)

Solution

Let's first unzip the file to see what we're dealing with.

$ unzip snapshot.zip 
Archive:  snapshot.zip
   creating: snapshot/
  inflating: snapshot/part1.png      
  inflating: snapshot/part2.png      
  inflating: snapshot/part3.png      
  inflating: snapshot/part4.png      
  inflating: snapshot/part5.png

Looks like this is a bunch of literal screenshots of what seems to be a bunch of hex. That'd be a lot to have to type out by hand, so we can instead use an OCR tool such as GOCR to look at the image and turn it into a text file for us. We can also pipe it into xxd to perform a reverse operation to decode the hex.

$ gocr -i part1.png | xxd -r -p
imot binscii
impor rndom


cls Vector(object):
    """
        This clss reesent  eco of rbira i�e.
        Yo need to give he eco components. 

        Overview bout the methods:

        contuctor(componens : list) : init the vector
        set(component : lis) : chanae he eco components.
        __str__() : toString method
        componen(i : int): ges the i-th component (start by 0)
        __len__() : aes the si�e of he ecto (number of components)
        euclidLength() : ens the euliden lenath of he vector.
        opertor + : vector addition
        operto - : vecor sbrction
        operator * : sclar multipliction nd do prodct
        coy() : copie thi ecto and retrn it.
        chngeComponent(pos,vlue) : changes he ecified comonen.
        TODO: compre-opertor
    """

    def __init__(self, comonent=[]):
        """
            input: components or nothing
            imple contcto for init the vector
        """
        self.__component = lis(comonens)

    def e(self, components):
        """
            inu: ne components
            chngsthcomonG2ofthvct"�     elce the comonens with neer one.
        """
        if len(component) > 0:
            self.__comonent = list(componen)
        ele:
            raise Exception("plese give ny vecto")

    def __sr__(elf):
        """
            returns  string representaion of he eco
        """
        return "(" + ",".join(map(str, self.__comonent)) + ")"

    def componen(self, i):
        """
            input: inde (r t 0)
            opt: he i-thcomonntofthvct"�"""
        if tpe(i) is in and -len(self.__components) <= i < len(self.__componens):
            retn self.__comonents[i]
        else:
            rise Excepion("inde out of range")

    def __len__(self):
        """
            returns the size of the vector
        """
        reun len(self.__comonent)

    def eulidLength(self):
        """
            retrn he euliden length ofthvct�"""�smm=
$ gocr -i part2.png | xxd -r -p
 0
        for c in self.__components:
            summe += c**2
        retrn math.sqrt(summe)

    def __add__(self, oher):
        """
            in: othrvct�assms:F�rvector has he me size
            eurnsanwvct"thatrrsG2thsm.
        """
        i�e = len(self)
        if size == len(other):
            result = [self.__components[i] +
                      othe.component(i) fo i in rnge(size)]
            return Vecor(result)
        ele:
            ise Exception("must hve the sme size")

    def __ub__(elf, othe):
        """
            input: other vector
            sumes: othe veco h the same size
            returns  new vector tha repesen he diffeenz.
        """
        size = len(self)
        if ize == len(oher):
            reul = [self.__components[i] -
                      other.comonent(i) for i in nae(size)]
            return result
        else:  # error case
            raise Exceion("mus he the me size")

    def __mul__(self, other):
        """
            ml imlemen he sclar mltiplication 
            and the dot-product
        """
        if iintance(other, flot) or isinstnce(other, int):
            ns = [c*othe for c in self.�6��onnts�rtrna�       elif (isinnce(oher, Vector) nd (len(self) == len(other))):
            i�e = len(elf)
            summe = 0
            for i in range(size):
                summe += elf.__component[i] * ohe.componen(i)
            rern summe
        else:  # error cse
            rise Exceion("inlide oend")

    def copy(self):
        """
            coies thi vecor nd euns it.
        """
        return Vector(self.__comonent)

    def chngeComponent(self, pos, value):
        """
            inpu: n index (pos) nd  le
            changes the specified component (os) ih he
            'vle'
        """
        # precondition
        aer (-len(elf.__comonent) <= pos < len(self.__components))
        self.__comonent[po] = vle


fla = 820926016672424573282546345206805820898691
$ gocr -i part3.png | xxd -r -p
3215291392096695738686757700743744203737234698


deferoVecto(dimension):"""�rtrnsazro-vct"of si�e !dimenion'
    """
    # pecondition
    ssert(isinstance(dimnsion, in))
    etun Veco([0]*dimension)


df min():
    print(int_to�Fxt(flag))


def niBsisVeco(dimension, o):
    """
        returns a nit bsis vector with a On 
        at index 'pos' (indexina t 0)
    """
    # recondition
    assert(isinstanc(dimension, int) nd (iinstance(o, int)))
    ns = [0ҦF��nsion
    ans�����&trn Veco(ans)


def ap(cl, x, y):
    """
        input: a 'scalar' nd two ecos !! nd '!
        oupt:  ector
        computes th axpy opration
    """
    # econdition
    ser(isinstance(x, Vector) nd (isinstnc(y, Veco))
           nd (isinsnce(sclar, int) or isinstance(scalar, flot)))
    etrn (*cl + y)


def ndomVector(N, a, b):
    """
        input: size (N) of th vctor.
               random nge (a,b)
        otput: return a random vctor of size N, with 
                ndom integer comonent beten''nd'b'.�"""�random6d(None)
    ns = [ndom.ndint(, b) for i in rnge(N)]
    return fctor(ans)


def text_to_int(in):
    heed = binascii.hxlify(inp)
    rtrn int(hexed, 6)


def int_o_et(in):
    heed = hx(inp)
    rtrn byterray.fromhx(heed[2:]).decode()


cls Mati(object):
    """
    class: Mtrix
    This clas eresent a bitry matix.

    Oerieq bou he mehod:

           _�7G%��&trns a string rpresntation 
           oeror * : imlement h mtrix vector mltipliction
                        implemen he mrix-scalr mltipliction.
           changeComponen(,y,le) : changes the pecified component.
           componnt(x,y) : euns the pecified comonen.
           width() : returns th width of th mti
           heiaht() : retrn he height of the matrix
           operto + : imlement he mri-ddition.
           oprator - _ implemnts th mari-sbraction
    """

    def __ini__(elf, mrix, q, h):
        """

Looks like we've found the flag between parts 2 and 3. Not perfect, of course, no OCR is (yet), but this really narrows things down for us. Let's just get the last 2 rows of part 2 and first 2 rows of part 3 and manually fix them.

$ ( gocr -i part2.png | tail -n 2; gocr -i part3.png | head -n 2 ) > hex
$ cat hex 
5F5F636F 6D106F6E 656E7413 5B706F13 5D203D20 766l6C15 650A0A0A 666C6I61 203D2038 32303932
3l363031 3l363637 323l3432 34353733 32383235 34363334 35323036 38303538 32303839 38363931
33323135 323l3931 33393230 3l393636 393l3537 33383638 363S3735 37373S30 30373433 37343432
30333733 37323334 3639380A 0A0A6465 66201A65 726F5665 63746F12 2864696D 656E7369 6F6E293A

The most common problem is that the OCR is mistaking the number 1 for the letter l, 5 for S, and it's getting 7s and 1s mixed up. We can use our human discretion to fix these errors.

This is the fixed hex:

5F5F636F 6D706F6E 656E7473 5B706F73 5D203D20 76616C75 650A0A0A 666C6167 203D2038 32303932
31363031 31363637 32313432 34353733 32383235 34363334 35323036 38303538 32303839 38363937
33323135 32313931 33393230 31393636 39313537 33383638 36353735 37373530 30373433 37343432
30333733 37323334 3639380A 0A0A6465 66207A65 726F5665 63746F72 2864696D 656E7369 6F6E293A

When we decode it, we get the flag.

$ xxd -r -p hex 
__components[pos] = value


flag = 820921601166721424573282546345206805820898697321521913920196691573868657577500743744203737234698


def zeroVector(dimension):

However, we again need to decode the flag. There is a decoder function further in the program in part 3 from earlier.

$ gocr -i part3.png | xxd -r -p
3215291392096695738686757700743744203737234698


deferoVecto(dimension):"""�rtrnsazro-vct"of si�e !dimenion'
    """
    # pecondition
    ssert(isinstance(dimnsion, in))
    etun Veco([0]*dimension)


df min():
    print(int_to�Fxt(flag))


def niBsisVeco(dimension, o):
    """
        returns a nit bsis vector with a On 
        at index 'pos' (indexina t 0)
    """
    # recondition
    assert(isinstanc(dimension, int) nd (iinstance(o, int)))
    ns = [0ҦF��nsion
    ans�����&trn Veco(ans)


def ap(cl, x, y):
    """
        input: a 'scalar' nd two ecos !! nd '!
        oupt:  ector
        computes th axpy opration
    """
    # econdition
    ser(isinstance(x, Vector) nd (isinstnc(y, Veco))
           nd (isinsnce(sclar, int) or isinstance(scalar, flot)))
    etrn (*cl + y)


def ndomVector(N, a, b):
    """
        input: size (N) of th vctor.
               random nge (a,b)
        otput: return a random vctor of size N, with 
                ndom integer comonent beten''nd'b'.�"""�random6d(None)
    ns = [ndom.ndint(, b) for i in rnge(N)]
    return fctor(ans)


def text_to_int(in):
    heed = binascii.hxlify(inp)
    rtrn int(hexed, 6)


def int_o_et(in):
    heed = hx(inp)
    rtrn byterray.fromhx(heed[2:]).decode()


cls Mati(object):
    """
    class: Mtrix
    This clas eresent a bitry matix.

    Oerieq bou he mehod:

           _�7G%��&trns a string rpresntation 
           oeror * : imlement h mtrix vector mltipliction
                        implemen he mrix-scalr mltipliction.
           changeComponen(,y,le) : changes the pecified component.
           componnt(x,y) : euns the pecified comonen.
           width() : returns th width of th mti
           heiaht() : retrn he height of the matrix
           operto + : imlement he mri-ddition.
           oprator - _ implemnts th mari-sbraction
    """

    def __ini__(elf, mrix, q, h):
        """

The main() function calls on int_to_text().

def int_o_et(in):
    heed = hx(inp)
    rtrn byterray.fromhx(heed[2:]).decode()

Let's go ahead and input the flag into this code, again using our human discretion to correct mistakes.

$ python3
Python 3.7.3 (default, Mar 26 2019, 21:43:19) 
[GCC 8.2.1 20181127] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> seed = hex(820921601166721424573282546345206805820898697321521913920196691573868657577500743744203737234698)
>>> bytearray.fromhex(seed[2:]).decode()
'bcactf{0p71c4lly_r3c0gn1z3d_ch4r4c73rs}\n'
Original writeup (https://github.com/shawnduong/ctf-writeups/blob/master/2019-BCA/forensics/of-course-rachel.md).