Sunday, July 10, 2011

HackThisSite - Realistic 6 Solution

It has been a while since I last posted. The only excuse I have is that it is "summer".

In any event, I decided to do a nice simple one to get back into things.

The "goal" behind hts 6 is to actually code the solution. As a penetration tester, you need to be able to write your own scripts to accomplish very specific tasks. You an find a lot of info on XECryption from here or here.  So I'm not going to go through the gory details about how to "crack" XECryption.

This is a good opportunity to pick a language that you do not know well in order to practice it.  I picked c# because I wanted to do more with LINQ.

In any event, here is my solution.  Pass in the full path to the file you wish to decrypt.  Pipe the output to a file.  Send the output (minus the first line saying it found the key) to ToxiCo_Watch.

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text.RegularExpressions;

namespace XECryptionDecrypter
{
    class Program
    {
        static void Main(string[] args)
        {
            var encryptedFile = ParseArguments(args);
            ProcessFile(encryptedFile);
        }

        private static void ProcessFile(FileInfo encryptedFile)
        {
            var encryptedContents = File.ReadAllText(encryptedFile.FullName);
            var chunks = GetChunks(encryptedContents);
            var key = DeterminePasswordKey(chunks);
            Console.WriteLine("Found key: " + key);

            foreach (var chunk in chunks)
            {
                PrintDecryptedChunk(chunk,key);
            }

        }

        private static int DeterminePasswordKey(List<ChunkedNumber> chunks)
        {
            var mostCommonChunkedValue = chunks.GroupBy(x => x.Total).OrderByDescending(x => x.Count()).First();
            var key = mostCommonChunkedValue.First().Total - 32;
            return key;
        }

        private static void PrintDecryptedChunk(ChunkedNumber number, int key)
        {
            Console.Write(char.ConvertFromUtf32(number.Total - key));
        }

        private static List<ChunkedNumber> GetChunks(string encryptedContents)
        {
            var encryptedContentsWithoutReturns = encryptedContents.Replace(Environment.NewLine, "");
            var chunkPattern = @"(\.\d+\.\d+\.\d+)";
            var chunkRegex = new Regex(chunkPattern);
            return (from match in chunkRegex.Split(encryptedContentsWithoutReturns) where !String.IsNullOrWhiteSpace(match) select new ChunkedNumber(match)).ToList();
        }


        private static FileInfo ParseArguments(string[] args)
        {
            if (args.Length < 1)
            {
                throw new ArgumentException("Please provide decrypted file path as argument 1");
            }

            var filePath = args[0];

            if (!String.IsNullOrWhiteSpace(filePath) && File.Exists(filePath))
            {
                return new FileInfo(filePath);
            }

            throw new ArgumentException(string.Format("File with path {0} not found",filePath));
        }
    }

    class ChunkedNumber
    {
        public int Number1 { get; private set; }
        public int Number2 { get; private set; }
        public int Number3 { get; private set; }
        public int Total { get; private set; }
        public string Raw { get; private set; }

        public ChunkedNumber(string raw)
        {
            var formattedString = raw.Replace(".", ",").Substring(1);
            var rawNumbers = formattedString.Split(',');
            Raw = raw;
            Number1 = int.Parse(rawNumbers[0]);
            Number2 = int.Parse(rawNumbers[1]);
            Number3 = int.Parse(rawNumbers[2]);
            Total = Number1 + Number2 + Number3;
        }
    }
}