code hacking, zen coding

CSAW 2011 .NET1 Bin200 Write-up

In this challenge, we get an archive with an encrypted file and an executable that was used to encrypt it.

We have to decrypt this file to get the key.

The executable is a pure .NET assembly so we can use ILSpy: http://wiki.sharpdevelop.net/ILSpy.ashx

We get this quickly:

using System;
using System.IO;
namespace DumpPrepper
{
internal class Program
{
private static uint[] key = new uint[]
{
1929540644u,
2488374377u,
339237175u,
54625381u
};
private static void Main(string[] args)
{
if (args.Length < 1 || args.Length > 1)
{
Console.WriteLine("Usage: DumpPrepper.exe file");
return;
}
if (!File.Exists(args[0]))
{
Console.WriteLine("Could not find " + args[0]);
return;
}
byte[] plaintext = File.ReadAllBytes(args[0]);
byte[] bytes = Program.Encrypt(plaintext, Program.key);
string path = DateTime.UtcNow.ToString().Replace('/', '-').Replace(':', '-') + ".dmp";
File.WriteAllBytes(path, bytes);
}
private static byte[] Encrypt(byte[] plaintext, uint[] key)
{
byte b = (byte)(8 - plaintext.Length % 8);
byte[] array = new byte[plaintext.Length + (int)b];
Array.Copy(plaintext, array, plaintext.Length);
for (int i = plaintext.Length; i < array.Length; i++)
{
array[i] = b;
}
byte[] array2 = new byte[array.Length];
for (int j = 0; j < array.Length; j += 8)
{
uint[] v = new uint[]
{
BitConverter.ToUInt32(array, j),
BitConverter.ToUInt32(array, j + 4)
};
uint[] array3 = Program.ProcessBlock(64u, v, key);
Array.Copy(BitConverter.GetBytes(array3[0]), 0, array2, j, 4);
Array.Copy(BitConverter.GetBytes(array3[1]), 0, array2, j + 4, 4);
}
return array2;
}
private static uint[] ProcessBlock(uint num_rounds, uint[] v, uint[] key)
{
if (key.Length != 4)
{
throw new ArgumentException();
}
if (v.Length != 2)
{
throw new ArgumentException();
}
uint num = v[0];
uint num2 = v[1];
uint num3 = 0u;
uint num4 = 2654435769u;
for (uint num5 = 0u; num5 < num_rounds; num5 += 1u)
{
uint num6 = num2 << 4;
uint num7 = num2 >> 5;
uint num8 = (num6 ^ num7) + num2;
uint num9 = num3 + key[(int)((UIntPtr)(num3 & 3u))];
num += (num8 ^ num9);
num3 += num4;
uint num10 = num << 4;
uint num11 = num >> 5;
uint num12 = (num10 ^ num11) + num;
uint num13 = num3 + key[(int)((UIntPtr)(num3 >> 11 & 3u))];
num2 += (num12 ^ num13);
}
v[0] = num;
v[1] = num2;
return v;
}
}
}

We notice the Decrypt function is not part of the binary, we have to write it ourselve.

This could take a lot of time if you don’t first study a little bit the ProcessBlock function. Googling “2654435769” will bring up a very interesting article: http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm

Now, the implementation code on Wikipedia don’t exactly match the code in our binary, it’s missing the round stuff. That feature was introduced in TEA’s successor: http://en.wikipedia.org/wiki/XTEA

There the code matchs perfectly. We only have now to code the Decrypt function following the implementation example on Wikipedia.

This give something like:

using System;
using System.IO;
namespace DumpPrepper
{
internal class Program
{
private static uint[] key = new uint[]
{
1929540644u,
2488374377u,
339237175u,
54625381u
};
private static void Main(string[] args)
{
if (args.Length < 1 || args.Length > 1)
{
Console.WriteLine("Usage: DumpPrepper.exe file");
return;
}
if (!File.Exists(args[0]))
{
Console.WriteLine("Could not find " + args[0]);
return;
}
byte[] plaintext = File.ReadAllBytes(args[0]);
byte[] bytes = Program.Decrypt(plaintext, Program.key);
string path = DateTime.UtcNow.ToString().Replace('/', '-').Replace(':', '-') + ".dmp";
File.WriteAllBytes(path, bytes);
}
private static byte[] Decrypt(byte[] plaintext, uint[] key)
{
byte b = (byte)(8 - plaintext.Length % 8);
byte[] array = new byte[plaintext.Length + (int)b];
Array.Copy(plaintext, array, plaintext.Length);
for (int i = plaintext.Length; i < array.Length; i++)
{
array[i] = b;
}
byte[] array2 = new byte[array.Length];
for (int j = 0; j < array.Length; j += 8)
{
uint[] v = new uint[]
{
BitConverter.ToUInt32(array, j),
BitConverter.ToUInt32(array, j + 4)
};
uint[] array3 = Program.DecryptBlock(64u, v, key);
Array.Copy(BitConverter.GetBytes(array3[0]), 0, array2, j, 4);
Array.Copy(BitConverter.GetBytes(array3[1]), 0, array2, j + 4, 4);
}
return array2;
}
private static uint[] DecryptBlock(uint num_rounds, uint[] v, uint[] key)
{
if (key.Length != 4)
{
throw new ArgumentException();
}
if (v.Length != 2)
{
throw new ArgumentException();
}
uint v0 = v[0];
uint v1 = v[1];
uint delta = 2654435769u;
uint sum = delta*num_rounds;
for (uint i = 0u; i < num_rounds; i += 1u)
{
uint num10 = v0 << 4;
uint num11 = v0 >> 5;
uint num12 = (num10 ^ num11) + v0;
uint num13 = sum + key[(int)((UIntPtr)(sum >> 11 & 3u))];
v1 -= (num12 ^ num13);
sum -= delta;
uint num6 = v1 << 4;
uint num7 = v1 >> 5;
uint num8 = (num6 ^ num7) + v1;
uint num9 = sum + key[(int)((UIntPtr)(sum & 3u))];
v0 -= (num8 ^ num9);

}
v[0] = v0;
v[1] = v1;
return v;
}
}
}

We run it with our encrypted file as parameter and get a new decrypted file with the key:

key{  f79b5967afade81c142eab7e4b4c9a3b  }

Share