Tags: misc 

Rating: 5.0

## 3DSCTF - A HUNDRED BASES OF GREY - MISC

When we enter the page, we are greeted with a beautiful soundtrack (which unfortunately doesn't hold any useful information for retrieving the flag) and a couple of gifs. From the website we can extract flag1-6, 1st, 2nd, 3rd, 4th gifs.

From the names we can expect that flag1-6 are the gifs that somehow decoded can give us the flag. All frames of gifs are one-colored, so let's look at their RGB values:

```python
from PIL import ImageSequence, Image

colors = []
for i in range(6):
im = Image.open('flag' + str(i + 1) + '.gif')
colors.append([])

try:
while True:
new_frame = im.convert('RGB')
colors[i].append(new_frame.getdata()[0])
im.seek(im.tell()+1)
except EOFError:
pass

from pprint import pprint
pprint(colors)
```

After running, we get this output:

```
[[(3, 3, 3),
(5, 5, 5),
(5, 5, 5),
(3, 3, 3),
(3, 3, 3),
(5, 5, 5),
...
(3, 3, 3),
(5, 5, 5)],
[(3, 3, 3),
(18, 18, 18),
(18, 18, 18),
(3, 3, 3),
(18, 18, 18),
(10, 10, 10),
...
(13, 13, 13),
(5, 5, 5)],

...
[(189, 189, 189),
(217, 217, 217),
(199, 199, 199),
(189, 189, 189),
(15, 15, 15),
...
(217, 217, 217),
(194, 194, 194)]]
```

It seems like all colors have the same R, G and B values - maybe it will be a good idea to convert every frame to a number and inspect these sequences? Worth a try:

```python
for i in range(6):
colors[i] = [x for (x, j, k) in colors[i]]
print('flag' + str(i + 1) + '.gif:', colors[i])
```

After conversion we get these sequences:
```
flag1.gif: [3, 5, 5, 3, 3, 5, 3, 5, 3, 3, 5, 5, 3, 3, 5, 3, 3, 3, 5, 5, 3, 5, 5, 5, 3, 5, 5, 3, 3, 5, 3, 5, 3, 5, 5, 3, 3, 3, 3, 5, 3, 3, 5, 5, 3, 5, 3, 5, 3, 3, 5, 5, 3, 5, 3, 3, 3, 3, 5, 5, 3, 5, 5, 5, 3, 3, 5, 5, 3, 3, 3, 3, 3, 5, 5, 3, 3, 5, 3, 3, 3, 3, 5, 5, 3, 3, 3, 5]
flag2.gif: [3, 18, 18, 3, 18, 10, 3, 18, 15, 5, 13, 13, 3, 20, 3, 5, 13, 18, 3, 18, 18, 5, 13, 15, 3, 18, 3, 5, 13, 18, 5, 13, 5]
flag3.gif: [10, 20, 18, 10, 18, 15, 18, 8, 18, 15, 18, 8, 10, 18, 10, 13, 18, 15, 18, 15, 10, 13]
flag4.gif: [33, 43, 74, 59, 33, 66, 46, 59, 18, 23, 64, 10, 8, 38, 26, 66, 20, 3, 84, 84, 84, 84, 84, 84]
flag5.gif: [64, 133, 26, 89, 64, 59, 23, 143, 36, 51, 36, 94, 36, 140, 13, 166]
flag6.gif: [189, 217, 199, 189, 15, 140, 120, 31, 13, 145, 166, 135, 33, 115, 181, 168, 217, 194]
```

Hmmm... first sequence has only two different values, maybe it holds some information in binary? Let's try to decode flag1 sequence to binary by mapping 3 to '0' and 5 to '1':

```python
guessed_mapping = {3: '0', 5: '1'}
print("".join([guessed_mapping[i] for i in colors[0]]))
```

We get `0110010100110010001101110110010101100001001101010011010000110111001100000110010000110001`, which after translation to ASCII is `e27ea5470d1`.

That's a good sign! We got something printable, it even looks like something in hex. But what now? We guessed values that can be mapped to numbers in flag1 sequence - with other gifs it's a little bit more complicated. That's where 1st, 2nd, 3rd and 4th gifs come in handy. Let's look at RGB values on them (spoiler - they also have R = G = B):

```python
strips = []
gifs = ['1st.gif', '2nd.gif', '3rd.gif', '4th.gif']

for i, name in enumerate(gifs):
im = Image.open(name)
strips.append([])

for j in range(0, 500, 20):
frame = im.convert('RGB')
strips[i].append(frame.getdata()[j])

strips[i] = [x for (x, j, k) in strips[i]]
print(name + ':', strips[i])
```

Our script will print:

```
1st.gif: [3, 5, 8, 10, 13, 15, 18, 20, 23, 26, 28, 31, 33, 36, 38, 41, 43, 46, 48, 51, 54, 56, 59, 61, 64]
2nd.gif: [66, 69, 71, 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 105, 107, 110, 112, 115, 117, 120, 122, 125, 127]
3rd.gif: [130, 133, 135, 138, 140, 143, 145, 148, 150, 153, 156, 158, 161, 163, 166, 168, 171, 173, 176, 179, 181, 184, 186, 189, 191]
4th.gif: [194, 196, 199, 201, 204, 207, 209, 212, 214, 217, 219, 222, 224, 227, 229, 232, 235, 237, 240, 242, 245, 247, 250, 252, 255]
```

It looks like pallette - all numbers from flag1-6 gifs can be found here. Looks like 2nd sequence is continuation of 1st, 3rd of 2nd and 4th of 3rd, so it might be a good idea to merge these into one pallette list. Also - we got something interesting from flag1.gif by mapping 3 to 0 and 5 to 1. Natural thought that could come is to map all numbers to their corresponding indices in our pallete:

```python
pallette = sum(strips, [])
colors = [map(pallette.index, i) for i in colors]

for i in range(6):
print('flag' + str(i + 1) + '.gif:', colors[i])
```

We get:

```
flag1.gif: [0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1]
flag2.gif: [0, 6, 6, 0, 6, 3, 0, 6, 5, 1, 4, 4, 0, 7, 0, 1, 4, 6, 0, 6, 6, 1, 4, 5, 0, 6, 0, 1, 4, 6, 1, 4, 1]
flag3.gif: [3, 7, 6, 3, 6, 5, 6, 2, 6, 5, 6, 2, 3, 6, 3, 4, 6, 5, 6, 5, 3, 4]
flag4.gif: [12, 16, 28, 22, 12, 25, 17, 22, 6, 8, 24, 3, 2, 14, 9, 25, 7, 0, 32, 32, 32, 32, 32, 32]
flag5.gif: [24, 51, 9, 34, 24, 22, 8, 55, 13, 19, 13, 36, 13, 54, 4, 64]
flag6.gif: [73, 84, 77, 73, 5, 54, 46, 11, 4, 56, 64, 52, 12, 44, 70, 65, 84, 75]
```

Unfortunately, mapping every number to binary (0 -> '0', 1 -> '1', 2 -> '10' and so on), merging into one string and translating to ASCII doesn't give any interesting results for flag2-6 gifs. So let's try a different approach...

So far we've used `GRAY` and `HUNDRED` from task name, what about `BASES`? Let's do some converting!

Highest number on the second list is 7, so that may suggest octal. Indeed, after joining numbers on a list we get `066063065144070146066145060146141` which converted to ASCII gives us `635d8f6e0fa`.

However, if we use the same approach to the next list, we do not get anything that makes sense. So let's try next "sensible" base - decimal. `3763656265623634656534` maps to `7cebeb64ee4`.

Next list has many `32` at the end, which suggests Base32 with `32` as a padding. `MQ4WMZRWGIYDCOJZHA======` maps to `d9ff6201998`.

Penultimate list is encoded in Base64 (the same idea - last value is `64`). `YzJiYWI3NTNkN2E=` maps to `c2bab753d7a`.

Last, but not least - the last list is encoded in Ascii85, Adobe version (highest number is 84). `<~@<5skB4u$qCi+%~>` maps to `asdfghjklmn`.

So, after concatenating all of those together and adding necessary `3DS{` and `}` we obtain `3DS{e27ea5470d1635d8f6e0fa7cebeb64ee4d9ff6201998c2bab753d7aasdfghjklmn}` which is the correct flag.

Whole script (with decoding included) can be found [here](https://gist.github.com/michsiw96/14b1e60ae2e93137ec4cde61e99c7309).

Original writeup (https://hackmd.io/s/rJuijPSzG).