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
```

![](https://raw.githubusercontent.com/shawnduong/ctf-writeups/master/2019-BCA/images/snapshot-1.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

def �eroVecto(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

def �eroVecto(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).