And I would have gotten away with it too, if it weren’t for you meddling kids and your CRC32!

MISJA 012

Zaraz to się chyba stanie tradycją, że w czwartek po streamie CLT podsyła zadanie 🙂 – tym razem nie byle jakie, alla crypto – choć mówi, że takich nie lubi….

I co my tu mamy?

Zaszyfrowany….

i co teraz? Wstępna analiza 7z, wczytanie w c# do obiektu klasy zipFile i dowiedzieliśmy się, że mamy w środku 24 pliki, 23 po 4B i ostatni 1B spakowane, tak, że do każdego dodane jest 12B zapewne jakiegoś paddingu. CRC też wyglądało ciekawie… rodziło myśli… 🙂

No ale… jak się do tego zabrać… to już chyba będzie tradycja, że „fajne” klasy w .NET tracą swoją fajność, gdy przechodzimy do szczegółów – tak też było tym razem, klasą ZipFile nie sposób odczytać crc z kodu – choć jest to udostępnione w debuggerze jako private field.

Biblioteka – spróbowałem dwóch – jedna pokazywała inne CRC niż w rzeczywistości… (.net pokazywał ok…), druga nie chciała się kompilować, trzecia – zipstorer była OK 🙂

Któraś z bibliotek pokazała, że zip nie jest zaszyfrowany jakoś silną metodą np AES’em, a jest to „weak encryption” – patrząc w Internet jest trochę informacji jak to złamać – np. w tym dokumencie

Pokazałem to CLT… a on mi mówi, że to chyba zbyt gruba metoda, pliki są małe, znamy CRC – może trzeba to „po chamsku” przeliczyć… i się zabrał… i skończył.

A mój kod nadal nie chciał wspólpracować….

CRC32 – również nie obsługiwane przez .net – przecież są lepsze funkcje hashujące, mimo że banki nadal używają MD5 😀 to .net nie wspiera liczenia CRC. W Internecie jest trochę implementacji – część liczy CRC dając inne wartości (jest różnica i niektóre implementacje .net nie spełniają standardu IEEE – niby 🙂

W końcu znalazłem właściwy kod, w zasadzie prosta klasa, ale spełniła swe zadanie: klik

Poskładałem wszystko ze sobą i wyszło to co poniżej 🙂

Kodzik (trochę ubolewam, że nie jest do końca elegancki, ale parcie na flagę jest silniejsze… a później gdy działa to szybko to czy przeróbki mają sens?):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Compression;
using NullFX.Security;
 
namespace MISJA_012
{
    class zips
    {
        public string name { get; set; }
        public uint crc { get; set; }
        public long size { get; set; }
        public string data { get; set; }
 
        public new string ToString()
        {
            return string.Format(
                           "{0}\t{1}\t{2}\t{3}"
                           , name
                           , crc
                           , size
                           , data
                          );
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            var fn = @"75b9d9bd1667bea881504206a0c5248964413653_secrets.zip";
            var files = new List();
            using (var en = ZipStorer.Open(fn, FileAccess.Read))
            {
                files = en.ReadCentralDir().Select(
                    x => new zips()
                    {
                        name = x.FilenameInZip,
                        crc = x.Crc32,
                        size = x.FileSize
                    }
                    ).ToList();
            }
 
            var lengths = files
                .Where(x => x.size > 0)
                .Select(x => x.size)
                .Distinct().ToList();
            DateTime tt = DateTime.Now;
            foreach (var length in lengths)
            {
                Brute(files, (int)length);
            }
            Console.WriteLine(string.Format(
                "Time: {0}s"
                , (DateTime.Now - tt).TotalSeconds
                ));
 
            foreach (var f in files)
                Console.WriteLine(f.ToString());
            Console.WriteLine();
            foreach (var f in files)
                Console.Write(f.data);
            Console.ReadLine();
        }
 
        static void Brute(
            List files
            , int levels)
        {
            int min = 32;
            int max = 128;
            byte[] buffer = new byte[levels];
            Crc32 crc = new Crc32();
 
            if (levels == 4)
                for (int i = min; i < max; i++)
                    for (int j = min; j < max; j++)
                        for (int k = min; k < max; k++)
                            for (int l = min; l < max; l++)
                            {
                                buffer[0] = (byte)i;
                                buffer[1] = (byte)j;
                                buffer[2] = (byte)k;
                                buffer[3] = (byte)l;
                                computeCRC(files, buffer, crc);
                            }
            else if (levels == 1)
                for (int i = min; i < max; i++)
                {
                    buffer[0] = (byte)i;
                    computeCRC(files, buffer, crc);
                }
        }
        static void computeCRC(
            List files
            , byte[] buffer
            , Crc32 crc
            )
        {
 
            var hash = crc.ComputeChecksum(buffer);
            var fs = files.FindAll(
                x => x.crc == hash);
            if (fs != null)
            {
                var s = System.Text.Encoding.UTF8.GetString(buffer);
                foreach (var f in fs)
                {
                    f.data = s;
                    Console.WriteLine(f.ToString());
                }
            }
        }
    }
}

Czas liczenia – o zgrozo!!!! 22 sekundy 😀

Ale fun! 🙂

2 Komentarze

Komentowanie jest wyłączone.