Challenge - Image DNA
Santa has thousands of Christmas balls in stock. They all look the same, but he can still tell them apart. Can you see the difference?
Image 1 | Image 2 |
---|---|
![]() |
![]() |
The first attempt so solving the challenge was to load the images into an editor and inspect them visually. We noticed they differ a lot when zoomed in. So much that it seemed unplausible any information was encoded in the differences. Nontheless we checked, but nothing was revealed by XORing, ORing, inspecting the LSBs etc.
Using binwalk and a hex-editor however, we gathered the following information about the images:
The information in the .zip was a bit puzzling at first, but after a while it occured to us that those gibberish extra bytes look like Nucleobases of DNA (the challenge name is “Image DNA”, duh). The “A” file was just a hint on how to solve it.
Searching for DNA string encodings really confirmed that we are on the right track. We stumbled upon this, especially the following piece code.
$dict = { '00' => 'A',
'11' => 'T',
'01' => 'C',
'10' => 'G' };
It’s a common CTF challenge it seems, and So lets write a code to translate those DNA sequnces to bits:
string DNA1 = "ATATATAAACCAGTTAATCAATATCTCTATATGCTTATATGTCTCGTCCGTCTACGCACCTAATATAACGTCCATGCGTCACCCCTAGACTAATTACCTCATTC";
string DNA2 = "CTGTCGCGAGCGGATACATTCAAACAATCCTGGGTACAAAGAATAAAACCTGGGCAATAATTCACCCAAACAAGGAAAGTAGCGAAAAAGTTCCAGAGGCCAAA";
// Typical DNA <-> binary table. But you can derive it.
// The embedded .zip suggested A=0b00, further I read A
// only matches to T, so T must be 0b11. With the typical
// order being A.C.G.T, chances are C=0b01 and G=0b10
var table = new Dictionary<char, string>() {
{'A', "00"},
{'C', "01"},
{'G', "10"},
{'T', "11"},
};
// Nucleobase to binary string lookup
string s1 = new string(DNA1.SelectMany(c => table[c]).ToArray());
string s2 = new string(DNA2.SelectMany(c => table[c]).ToArray());
Console.WriteLine(s1 + "\r\n");
Console.WriteLine(s2 + "\r\n");
The output:
0011001100110000000101001011110000110100001100110111011100110011100111110011001110110111011011010110110111000110010001011100001100110000011011010100111001101101000101010111001000011100001111000101110100111101
0111101101100110001001101000110001001111010000000100001101011110101011000100000010000011000000000101111010100100001100001111010001010100000001000010100000001011001001100000000000101111010100100010100101000000
Those, converted to ASCII, are just rubbish, but the challenge states “Can you see the difference?”. So we XOR’ed those two! Having this idea took a good hour and a half however. Anyways:
string xored = "";
for (int i = 0; i < s1.Length; ++i)
{
xored += (s1[i] != s2[i]) ? "1" : "0";
}
byte[] text = BinaryStringToBytes(xored); // ugly code not shown here
Console.WriteLine(Encoding.ASCII.GetString(text));
Tada, we were successful and finally got the flag:
HV20{s4m3s4m3bu7diff3r3nt}