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 << "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 < 1)
d = Integer(@bytearray[i]) - Integer(initial)
initial = @bytearray[i]
diff << d
end
end
return diff
end
def asciicharacters
ac = {}
(0...@bytearray.size).each do |i|
if(Integer(bytearray[i]) < 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 & 0x7f
par = binary >> 7
ones = 0
(0..7).each { |i|
ones += tocheck & 0x01
tocheck = tocheck >> 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 & 0x7f
end
def diffscan(index)
diffs = []
tocheck = @bytearray[index]
(index+1 ... @bytearray.size).each{|b|
diffs << 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 << "0x#{bins[i].slice(j*2,2)}"
end
bins[i] = t
}
comp = []
bins.each{ |k,v| comp << bins[k][0] }
end
def shiftbits(byte)
binary = Integer(byte)
bottom = binary >> 5
top = (binary & 0x1f) << 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