Лаборатория TJCTF 2016 - Interesting Telegrams [misc 100]

delimitry
, 1 июня 2016

We intercepted this message from the Fully Centralized Public Services' Department of Interesting Telegrams. We have reason to believe that the message contains secret information, but our top Morse decoders can't seem to get it.

We have an OGG audio file audio_6b3284d534df270e90e7a9c26dd02fd839377d5e8b6233b2f1b061e4415c7b0e.ogg.

This task was created by Fox Wilson, and as the game has shown - his tasks are really complex and tricky.

After checking the metadata we've got the next information:
ALBUM=TJCTF 2016
ARTIST=TJCTF
GENRE=Flags
TITLE=This Is Not The Flag

Then I've listened to the file and understood that it is some kind of phone dial tone frequencies.
In scientific terms, this is called Dual Tone Multi-Frequency or DTMF.
Also I've checked the spectrogram of the file using Audacity and Sonic Visualiser.



As you can notice tones are grouped - by three tones in the group.
I've tried some software to decode DTMF from the given audio file to numbers, and luckily I've got the next first values:

1 (0,0s)
3 (0,0s)
7 (0,1s)

0 (0,1s)
8 (0,2s)
0 (0,2s)

0 (0,3s)
7 (0,3s)
8 (0,4s)

0 (0,6s)
7 (0,6s)
1 (0,7s)

what could be written as 137, 080, 078, 071. After converting these ASCII numbers to chars I've got: '\x89PNG'.
It's PNG file's header :) Good.

But after converting all decoded numbers into chars, I got several errors. I think because of noise in the file, DTMF decoder decoded some of numbers with error.
So I've decided to use plan B and save spectrogram from Sonic Visualiser into the file and scan it using Python script. 



Here is my script:

from PIL import Image
from collections import Counter


def check_pixel(pix, x, y):
    col = pix[x, y]
    delta = 40
    color = (245, 220, 0)
    return abs(col[0] - color[0]) < delta and abs(col[1] - color[1]) < delta and abs(col[2] - color[2]) < delta


def check(pix, x, y):
    return check_pixel(pix, x, y) or check_pixel(pix, x, y + 2) or check_pixel(pix, x + 2, y + 2) or check_pixel(pix, x + 2, y - 2)


im = Image.open('111.png')
w, h = im.size
pix = im.load()

values = []
num = ''
out = ''

for x in xrange(w - 3):
    # skip a scale
    if x < 42: 
        continue

    value = ''
    if check(pix, x, 136) and check(pix, x, 199):
        value = '1'
    elif check(pix, x, 106) and check(pix, x, 199):
        value = '3'
    elif check(pix, x, 136) and check(pix, x, 179):
        value = '7'
    elif check(pix, x, 121) and check(pix, x, 167):
        value = '0'
    elif check(pix, x, 121) and check(pix, x, 179):
        value = '8'
    elif check(pix, x, 121) and check(pix, x, 199):
        value = '2'
    elif check(pix, x, 106) and check(pix, x, 187):
        value = '6'
    elif check(pix, x, 121) and check(pix, x, 187):
        value = '5'
    elif check(pix, x, 136) and check(pix, x, 187):
        value = '4'
    elif check(pix, x, 106) and check(pix, x, 179):
        value = '9'
    else:
        value = ''

    values.append(value)
    if values.count('') > 3:
        most = Counter(filter(None, values)).most_common()
        if most:
            num += most[0][0]
            if len(num) == 3:
                print num, x
                out += chr(int(num))
                num = ''
        values = []
            
with open('tele_flag.png', 'wb') as f:
    f.write(out)



So after finish my script I've got the next numbers:
137 080 078 071 013 010 026 010 000 000 000 013 073 072 068 082 000 000 000 100 000 000 000 100 008 002 000 000 000 255 128 002 003 000 000 001 101 073 068 065 084 120 156 237 219 049 110 195 064 012 069 065 090 240 185 115 117 167 016 178 112 017 128 122 253 012 092 164 038 184 095 020 087 121 205 252 092 051 215 204 053 175 191 063 252 254 255 189 231 122 013 207 188 231 154 153 207 204 204 168 218 226 046 150 050 061 242 158 075 091 061 037 179 002 157 021 200 172 224 046 214 204 124 148 108 117 050 075 165 118 167 179 216 221 001 255 114 012 159 184 143 161 074 061 162 179 002 067 105 112 058 139 221 247 214 129 133 128 015 206 235 142 122 237 100 086 032 179 002 175 059 193 153 179 052 215 078 103 005 103 083 202 206 156 021 088 043 007 050 043 248 206 044 253 181 048 058 004 231 117 071 091 237 124 024 018 008 248 192 156 021 152 179 002 183 059 129 125 086 224 042 044 240 021 077 096 007 031 200 172 064 102 005 167 179 148 108 103 040 013 116 086 224 105 024 124 047 255 148 108 113 134 082 149 218 249 015 139 224 236 179 216 025 029 002 199 048 112 012 003 023 022 129 161 052 176 117 008 004 124 032 179 002 079 195 192 080 026 200 172 064 103 005 070 135 192 211 048 144 089 129 099 024 184 221 009 100 086 224 127 119 002 115 086 032 224 003 153 021 216 148 006 190 131 015 028 195 192 211 048 240 110 024 232 172 064 192 007 058 043 048 103 005 070 135 192 187 097 160 179 002 115 086 224 250 062 240 052 012 100 086 224 118 039 144 089 129 099 024 008 248 064 102 005 050 043 176 162 009 028 195 192 183 014 129 021 077 224 024 006 142 097 240 011 065 110 064 181 091 206 102 028 000 000 000 000 073 069 078 068 174 066 096

Or the next image: 



But where is the flag?
After hours of staring at this image and filtering it in GIMP, I've decided to check R, G, B channels.
And luckily found that first pixels from the left - have some deviations in blue channel.

Using the next Python script I've finally got the flag:

from PIL import Image

img = Image.open('tele_flag.png')
p = img.load()
w, h = img.size
out = ''
for y in range(h):
    for x in range(0,1):
        out += chr(p[x, y][2])
for y in range(h):
    for x in range(1,2):
        out += chr(p[x, y][2])
for y in range(h):
    for x in range(2,3):
        out += chr(p[x, y][2])

bits = ''
for c in out:
    bits += '1' if ord(c) & 1 else '0'
print bits
out = ''
for i in xrange(0, len(bits), 8):
    out += chr(int(bits[i:i+8],2))
print out

The flag is:
tjctf{m3ss4ge_s3cur1ty_1$_h@rd}

Авторизуйтесь, что бы оставить комментарий