Friday 30 July 2010

Cyber Security Challenge

To all those interested, here is a copy of my email with my solution.

To whom it may concern,

Decoded this from the last challenge!

"
Congratulations  youve found and completed the REAL challenge. Your win
code is  cyb3r=s3cur1ty*ch@ll3nge+26-07-2010.

Please email this code to our team at
media@cybersecuritychallenge.org.uk. If youre the first person to do so,
and can prove you meet the eligibility criteria (British citizen
currently resident in the UK) we will be in touch to advise how to claim
your prize. Well done and good luck in the Cyber Security Challenge
competitions taking place throughout the rest of the year
"

Figured I would go through the process:

Task one
========

Copied the data into a file.
Created the following perl script:

#!/usr/bin/perl
use MIME::Base64;

while(<STDIN>){
    print decode_base64($_);
}

I then piped the data through the script into another file
$ cat data | ./base64.pl > output

At a hunch, checked if it was an image.
$ evince output

Voila!

Task two
========

Noticed the squiggles, zoomed in a lot and noticed it covered 2 pixel
strips, so converted the image to a bitmap, then created a very hacky C
file to grab the data (after checking the wiki page for the file format).
It is quite hacky, but combined with an online binary to ascii
converter, worked well.
The C file was as follows:

#include <stdlib.h>
#include <stdio.h>

void * imgdata;
int datao(int x, int y);

int main(int argc, char *argv[]){

  FILE * fp;
  int w, h, o, off, i;
  int r, g, b, re;

  //Read binary data
  fp = fopen("output.bmp", "rb");

  fseek(fp, 0x0a, SEEK_SET);
  o = getc(fp);
  printf("1\n", o);

  //First
  off = o + 1052 * 173;
  fseek(fp, off, SEEK_SET);
  for(i = 0; i < 350; i++){
    r = getc(fp);
    g = getc(fp);
    b = getc(fp);
    if (r+g+b > 600)
      re = 1;
    else
      re = 0;

    if((i+1)%8)
      printf("%d", re);
    else
      printf("%d", re);
  }
  printf("\n2\n", o);

  //section section
  for(i = 3; i <= 172; i++){
    off = o + (1052 * i) + 1047;
    fseek(fp, off, SEEK_SET);
    r = getc(fp);
    g = getc(fp);
    b = getc(fp);
    if (r+g+b > 600)
      re = 0;
    else
      re = 1;

    if((i+1)%8)
      printf("%d", re);
    else
      printf("%d", re);
  }

  printf("\n3\n", o);

  //third section
  off = o;
  for(i = 349; i >= 0 ; i--){
    fseek(fp, off + (i*3), SEEK_SET);
    r = getc(fp);
    g = getc(fp);
    b = getc(fp);
    if (r+g+b > 600)
      re = 0;
    else
      re = 1;

    if((i+1)%8)
      printf("%d", re);
    else
      printf("%d", re);
  }
  printf("\n4\n", o);

  //forth section
  for(i = 172; i >= 3; i--){
    off = o + (1052 * i) + 3 ;
    fseek(fp, off, SEEK_SET);
    r = getc(fp);
    g = getc(fp);
    b = getc(fp);
    if (r+g+b > 600)
      re = 0;
    else
      re = 1;

    if((i+1)%8)
      printf("%d", re);
    else
      printf("%d", re);
  }

  return 0;
}

//offst from data start
int datao(int x, int y){

  int width = 350;
  int height = 175;

  int offset = (y * width * 3) + x*3;
  return offset;
}

- From this I got the following text:
Cyrnfr sbyybj guvf yvax:
uggcf://plorefrphevglpunyyratr.bet.hx/834wgc.ugzy
uggcf://plorefrphevglpunyyratr.bet.hx/834wgc.ugzy

Which after running through the following perl script:

#!/usr/bin/perl

use MIME::Base64;

while(<stdin>){
  $_ =~ tr/a-zA-Z/n-za-mN-ZA-M/;
  print $_;
}


Which led me to ...

Task three
==========

This one was tricky. I looked for ascii values on the data, reversed,
big endian, little endian, looked for 7bit data compacted into 8, 7bit
and parity (odd/even) and then only looking at bits which passed the test.

Early on I noticed there were no '3's in the data, but didn't see the
shocking clue.

Then I tried some basic frequency analysis, but as there were 56 unique
entries it was probably a polyalphabetic cypher if it was. Tried the
kasiski technique, ended up with random numbers, but tried none the
less. I was convinced that the page name was a key, or something simple,
like "cypher". Alas, it was not true. Whilst looking at the binary for
the 500th time looking for patterns of shifts which you could be
employing, but finally I saw the solution. Turns out I was doing the
rookie mistake of starting out complex.

Following is the ruby file used to decode the data:

class Cypherc


    attr_accessor :bytearray, :rawdata


    def initialize


        rawdata =

"68edcdec4e2c8eae8d2c8e2dedcd6e04d2042fedae52ceac04ccedaecd8c042ccd8c046cedad0e8dac8eac8c048e0dac044aa82889046c0d2c8d8daccdecacc5042bedae4e04ee2dcd046ced8cac042d6e04046c2f4c664ea76e666cae4e268e2f456c0d088d8d66cdecac6546c6a506e6a546062606c504a141a1410a8dac2c6eac04acad2c2d8d048e0d2d6e046ced8cac048eed04edae4e048eac2cad042c8e04adac8c2d2c086c2f4cac4e6eac6cae4e2d8e2f6c0d2c8d8daccdecacc5ed4eecc5ae6dc50429cc042fedae524eac048e0dac04cc2d4e6e8e040eac4e6eedcd048eed048ced046eed85042ccd8c046c2ccd040e4eedceac042fedae04adacac8e048e0dac04ac8d2dec2d4c2d8d2d8e2f046c4e2d8eac4e2d2c0405484e2d8e2d6e0d046c2d8e2d4faccd046cae4e4eaccd8e8d2f044eac6e2d8caccd8e042dcd048e0dac04aa692504eeac04ee2d8d8d044cac042dcd048eedae6c0d048eed042c8cce2d6eac040dedee048eed046c8d2c2dad042fedae4e040e4e2d4facc504eaac8d8d048cedcdac042ccd8c04eceded8c048dae6c6d042dcd048e0dac04682f4cac4e046aac6cae4e2d8e2f04680d2c8d8daccdecac046cedad0eac8e2d8e2dedcd6e048e2c6d2dcdec040e8d2c6cac048e0d4eedaeec0dedae8e048e0dac044eac6e8e04edcc048e0dac0

42fac2c4ec5"


        @rawdata = rawdata


        bytearray = []


        (0 ... rawdata.size/2).each do |i|

            bytearray &lt;&lt; "0x#{rawdata.slice!(0,2)}"

        end


        @bytearray = bytearray

   

    end


    def differencekeysize(length)

        diff = []

        initial = @bytearray[0]

        (1...@bytearray.size).each do |i|

            if (i%length &lt; 1)

                d = Integer(@bytearray[i]) - Integer(initial)

                initial = @bytearray[i]

                diff &lt;&lt; d

            end

        end

        return diff

    end


    def asciicharacters

        ac = {}

        (0...@bytearray.size).each do |i|

            if(Integer(bytearray[i]) &lt; 128)

                puts "#{i} : #{@bytearray[i]}"

                ac[i] = @bytearray[i]

            end

        end

        return ac

    end


    def paritycheck(byte, type = 1)

        #number of 1s

        binary = Integer(byte)

        tocheck = binary &amp; 0x7f

        par = binary &gt;&gt; 7

        ones = 0

        (0..7).each { |i|

            ones += tocheck &amp; 0x01

            tocheck = tocheck &gt;&gt; 1

        }

        ok = false

        if(type == 1)

            if par == 1 and ones.odd?

                ok = true

            elsif par == 0 and ones.even?

                ok = true

            end

        elsif(type == 2)

            if par == 1 and ones.even?

                ok = true

            elsif par == 0 and ones.odd?

                ok = true

            end

        end


        return ok

    end


    def bitvalue(byte)

        return byte &amp; 0x7f

    end


    def diffscan(index)

        diffs = []

        tocheck = @bytearray[index]

        (index+1 ... @bytearray.size).each{|b|

            diffs &lt;&lt; Integer(@bytearray[b]) - Integer(tocheck)

        }

        return diffs

    end


    def ngrams(n)

        bins = {}


        (0...@bytearray.size - n).each { |i|

            key = @bytearray.slice(i, n).to_s

            if bins[key].nil?

                bins[key] = 1

            else

                bins[key] += 1

            end

        }


        return bins

       

    end


    def bincheck

        bins = {}

        ks = 10


        (0 ... rawdata.size/ks).each {|i|

            bins[i] = rawdata.slice(ks*i, ks)

            t = []

            (0 ... bins[i].size/2).each do |j|

                t &lt;&lt; "0x#{bins[i].slice(j*2,2)}"

            end

            bins[i] = t

        }


        comp = []

        bins.each{ |k,v| comp &lt;&lt; bins[k][0] }

    end


    def shiftbits(byte)

        binary = Integer(byte)

        bottom = binary &gt;&gt; 5

        top = (binary &amp; 0x1f) &lt;&lt; 3

        return bottom ^ top

    end


    def decode

        @bytearray.each { |b|

            print "#{shiftbits(b).chr}"

        }

    end



end


c = Cypherc.new

c.decode

Those are my workings, 3 hours on the steg stuff probably, and much too
long on the last challenge.

Looking forward to more challenges :-)

Carl Ellis
http://www.jimhi.com

No comments: