Лаборатория TJCTF 2016 - µ'sic [forensics 200]

, 6 июня 2016

µ's Music Start!

I was solving this task for 3-4 days after TJCTF and yesterday finally solved it.

We are given a link to µ'sic.zip file.

Archive is protected with a password. I've brutted the pasword to the archive.
Password is "LL". Inside the archive a Welcome.txt file with the next message is stored:

Welcome to µ'sic!

The purpose of this challenge is to elucidate the applications of forensics and steganography techniques and the manner in which they may be solved. Our intent is that you will learn and develop a multitude of skills as you progress through this challenge.

For each "layer" of this challenge, we have included one of our favorite songs from Love Live! (now you know what LL stands for), along with the cover image that came with the CD for each song. Each layer involves a password protected zip file, and the password can be found hidden in the cover image.

If nothing else, please enjoy the µ'sic!


So we have several nested archives with songs, posters and some other files. 
Each level's cover image contains a hidden password to the next level's zip archive.

Level 0

Password is hidden as a plain text in the cover image:

Level 1

We have two cover images. We can find diff bytes using Python script:

with open('1.jpg', 'rb') as f:
    data1 = f.read()
with open('2.jpg', 'rb') as f:
    data2 = f.read()

out = ''
for i in xrange(len(data1)):
    if data1[i] != data2[i]:
        out += data1[i]
print out

And get a next data:
Which is base64 encoded next level's password:

Level 3

Inside this level's achive we have a PDF file.
Using the next script I've extracted and decompressed all stream data blocks from PDF.

import zlib

with open('1.pdf', 'rb') as f:
    data = f.read()

while True:
    start = data.find('\x0Astream\x0A')
    if start < 0:
    data = data[start + 8:]
    end = data.find('\x0Aendstream')
        decompressor = zlib.decompressobj()
        dec_data = decompressor.decompress(data[:end]) 
        with open('out.png', 'wb') as f:

Is is password written with Wingdings font.


Level 4

In this level's archive we have two PNG images. Using the next script I've extracted diff image with a password:

import operator
from PIL import Image

def diff(col1, col2):
    return map(abs, map(lambda x: operator.sub(*x), zip(col1, col2)))

img1 = Image.open('1.png')
pixels1 = img1.load()

img2 = Image.open('2.png')
pixels2 = img2.load()

w, h = img1.size

img3 = Image.new('RGB', (w, h))
pixels3 = img3.load()

for y in xrange(h):
    for x in xrange(w):
        v = tuple(diff(pixels1[x, y], pixels2[x, y]))
        if v == (1, 1, 1):
            pixels3[x, y] = (255, 255, 255)
            pixels3[x, y] = v



Level 5

We have a jpg file. I've noticed that inside of this file, zip achive is hidden. With the next script - I've extracted it.

with open('Cutie Panther.jpg', 'rb') as f:
    data = f.read()

pos = data.find('PK')

with open('out.zip', 'wb') as f:

Inside extracted archive - Cutie Panther.png image with QR codes... Lots of them...
Image size is 13500 x 13500 pixels. 900 QR codes.
So I've cutted the image into subimages with QR codes. And then decoded each of them.

import glob
import os
import re
import subprocess
import zipfile
from PIL import Image

def cut_qr_codes(img_path, out_dir, qr_left, qr_top, qr_w, qr_h, qr_step_x, qr_step_y):
    """ Cut off subimages from image """
    if not os.path.exists(out_dir):
    img = Image.open(img_path)
    img_w, img_h = img.size
    index = 0
    for j in xrange(qr_top, img_h - qr_top - qr_step_y, qr_h + qr_step_y):
        for i in xrange(qr_left, img_w - qr_left - qr_step_x, qr_w + qr_step_x):
            print i, j, index
            img.crop((i, j, i + qr_w, j + qr_h)).save(os.path.join(out_dir, '%003d.png' % index))
            index += 1

def decode_qr(path):
    """ Decode QR using zbar """
    res = subprocess.check_output('zbarimg %s -q' % path, shell=True)
    return re.findall('QR\-Code:(.*)\r', res)

def unzip_specific_file(zip_file, name, password):
    """ Unzip file from zip archive """
        zip_file.extract(name, pwd=password)
        return True
    return False

def main():
    # cut image into subimages with QR codes
    out_dir = './qr_codes/'
    cut_qr_codes('Cutie Panther.png', out_dir, 40, 40, 371, 371, 79, 79)

    # decode QR codes
    passwords = []
    for fn in glob.glob(os.path.join(out_dir, '*.png')):
        data = decode_qr(fn)

    # find the password
    filename = 'zip5.zip'
    zip_file = zipfile.ZipFile(filename)
    # get image's name in archive
    name = ''
    for name in zip_file.namelist():
        if name.endswith('.jpg'):
            print name

    for password in passwords:
        if unzip_specific_file(zip_file, name, password):
            print 'password is:', password

if __name__ == '__main__':

After running this script, I've found appropriate password.


Level 6

import itertools
from collections import Counter
from PIL import Image

img = Image.open('Octal.png')
w, h = img.size
pixels = img.load()

colors_data = []
for y in xrange(0, h, 20):
    for x in xrange(0, w, 20):
        col = pixels[x, y]

alphabet = set(colors_data)
alphabet_len = len(alphabet)

out_file = open('out.dat', 'wb')

colors = map(str, xrange(8))
for items in itertools.product(colors, repeat=alphabet_len):
    # get only possible variants without repetition
    if len(set(items)) == alphabet_len:
        alpha_to_item = dict(zip(alphabet, items))
        # get image as an octal number
        oct_number = ''.join(alpha_to_item.get(x) for x in colors_data)
        dec_number = int(oct_number, 8)
        # write all possible results
        if len(hex(dec_number)[2:-1]) % 2 != 0:
            out_file.write(('0' + hex(dec_number)[2:-1]).decode('hex') + '\n')


After running the script I've checked the file with huge number of possible results. And one of them was:

So a first part of this message is a password:

Level 7

On this level - a password was simply hidden in JPG file as plain text.

Level 8

In this level we have a PNG file. 
I've noticed a hint in PNG file after IEND block: r^g&b

And using the next script I've got a password to the next level:

from PIL import Image

img = Image.open('1.png')
w, h = img.size
pixels = img.load()
bits = ''

img_out = Image.new('RGB', (w, h))
img_out_pixels = img_out.load()

for j in xrange(h):
    for i in xrange(w):
        col = pixels[i, j]
        r, g, b = col
        bits += '1' if (r^g&b) & 0b1 else '0'
        img_out_pixels[i, j] = (255, 255, 255) if ((r ^ g & b) & 0b1) else (0, 0, 0)

bits = '0' + bits  # !!!!
out = ''
for i in xrange(0, len(bits), 8):
    out += chr(int(bits[i:i + 8], 2))
print `out`


Level 9

The last archive contained Flag.png file with part of QR code. Only a part :(

I've decoded QR code by hands :)
Here is the structure of QR code, I've filled each data blocks with color:

It is QR code version 4 (33x33). As you can see the mask (x % 3) is used here.
First block = 4 or byte encoding (8 bits per character).
Second block is a encoded message length = 58.
Next four blocks in the first column are t, j, c, t.
In such way all 58 bytes of data was extracted.

Flag is:

It was a really difficult task by Annabel Faylan. Thank you!
Inception! We need to go deeper! :)

2 комментария:

  1. Justnix
       #   10:32, 24 мая 2017
    Zithromax Cost Cialis Free Offer Novolog Ltd Antibiotic Keflex And The Liver Buy Cheap Kamagra Pills Cialis Pas Cher Espagne Finax Generic Propecia Hair Loss Cialis Online Buy Levitra Orodispersibile Prezzo In Farmacia Viagra Uk 150mg Buy Cialis Zithromax For Strep Throat Nolvadex Dosage For Epistane ?Tadalafil Viacom Orlistat Diet Pill Genuine Viagra Cheap Low Price Cialis Levitra Viagra O Cialis Baclofene Amm Get Cheap Cialis Online Buy Accutane In Usa Fast Viagra Delivery Mail Order Zoloft isotretinoin order internet no physician approval Taking Anaprox With Amoxicillin Low Cost Cialis Online Amoxicillin 875mg Tablet Silagra 100 Uk For Sale Propranolol Online Cheap Keflex Is Not Very Strong Baclofene Mal De Tete Buy Kamagra Jelly Online Achat Kamagra Oral Jelly Cephalexin Dosage Puppy Cheapest Levitra Tadalafil Generique Viagra En Vente Where To Buy Zoloft Levitra Prix Au Maroc Keflex Manufacturing Cialis Online No Propecia Infertilidad Cialis Kaufen In Hamburg Cialis Online Usa Generic Finasteride Skin Cialis 20 Mg Utilizzo Buy Kamagra Doryx Website Discount On Line Buying Provera Online Viagra Online Stores Where To Get Levitra Can You Take Benadryl With Amoxicillin Ordina Zoloft Online Cialis Kaufen Internet Viagra Foto Pillola Purchase Viagra Buy Amlodipine Without Prescription Cialis Quanto Costa In Farmacia How Much Is Kamagra Cephalexin Information Generic Free Shipping Clobetasol 0.05% Psoriasis Kamagra En Ligne World Pharmacy Store Achat Cialis Us Ordering Cialis Online Lioresal En Ligne 10mg Online Cialis India Purchase Cheap Xenical Amoxil Informations Peut On Acheter Cialis Sans Ordonnance En Pharmacie Where To Order Kamagra Kamagra Fast London Am Luat Propecia Order Zoloft Tablets Order Acticin Permethrinum Scabies Quick Shipping Australia Cheapeast Buy Cipro Online Uk Tadalafil 20mg Viagra 200mg Online Price Canada Viagra Einnahme Cialis Where To Order Cialis Amoxicillin Dosage For Strep Propecia Help Baldness Sildenafil Generic Amoxicillin Dosing Schedule Flex Keflex 250mg Kamagra Jelly Online Priligy Mise A Jour
  2. KelDuhCrory
       #   06:30, 20 июня 2017
    Does Priligy Work Forum Purchase Cytotec Usa Trazodone Generic Brand Sildenafil Citrate For Sell viagra Viagra In The Netherlands Penicillin Without Going To Doctor Best Levitra Acheter Du Kamagra Pour Femme Propecia Catez Generic Kamagra Cheap How Long Does Cephalexin Last Ceftin Cheap Cialis 20mg Purchase Tadalafil Online Viagra Kaufen Aus Deutschland Viagra Price Generic Super Viagra

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