28
Feb
2012

CODEGATE 2012 – Binary 100

We’re given a zipfile containing a Windows executable. An identification attempt (using CFF explorer) quickly reveals that it was packed using a simple executable compressor:

Signature: CExe v1.0a
Matches: 43

Proceed by checking out the resource directory, where you should find something resembling the original executable. Dump it using CFF Explorer and take a look at the header; the first few bytes (‘SZDD’) indicate the wrapped executable was compressed using a simple (DOS) compression format. Although it’s rather old, 7zip supports it just fine – extract it to obtain the original executable.

Open up the unpacked executable in CFF Explorer and it’s rather obvious that we’re dealing with a .NET executable here. ILSpy will happily decompile it for us, yielding the following interesting bits:

private static void Main(string[] args)
{
	RecognizerInfo recognizerInfo = (
		from r in SpeechRecognitionEngine.InstalledRecognizers()
		where r.get_Id() == "SR_MS_en-US_TELE_11.0"
		select r).FirstOrDefault<RecognizerInfo>();
	int num = 65;
	uint dwVolume = (uint)((num & 65535) | num << 16);
	Program.waveOutSetVolume(IntPtr.Zero, dwVolume);
	SpeechRecognitionEngine speechRecognitionEngine = new SpeechRecognitionEngine(recognizerInfo.get_Id());
	try
	{
		Stream manifestResourceStream = typeof(Program).Assembly.GetManifestResourceStream("ConsoleApplication1.computer.xml");
		Grammar grammar = new Grammar(manifestResourceStream);
		speechRecognitionEngine.LoadGrammar(grammar);
		speechRecognitionEngine.SetInputToDefaultAudioDevice();
		speechRecognitionEngine.add_SpeechRecognized(new EventHandler<SpeechRecognizedEventArgs>(Program.recognizer_SpeechRecognized));
		speechRecognitionEngine.RecognizeAsync(1);
		Console.WriteLine("Can u here me?");
		while (true)
		{
			SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer();
			speechSynthesizer.SetOutputToDefaultAudioDevice();
			speechSynthesizer.Speak("What is greater than god, more evil than the devil?");
			Thread.Sleep(60000);
		}
	}
	finally
	{
		if (speechRecognitionEngine != null)
		{
			speechRecognitionEngine.Dispose();
			goto IL_D9;
		}
		goto IL_D9;
		IL_D9:;
	}
}

private static void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
	if (e.get_Result().get_Text() == "Nothing" && Program.current == RecognitionState.None)
	{
		Program.current = RecognitionState.Question;
		SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer();
		speechSynthesizer.SetOutputToDefaultAudioDevice();
		speechSynthesizer.Speak("Are you sure?");
		Program.str_input = e.get_Result().get_Text();
		return;
	}
	if (Program.current == RecognitionState.Question)
	{
		Program.current = RecognitionState.None;
		if (e.get_Result().get_Text() == "Yes")
		{
			Program.str_cypher += "QA1f1/EqAOZktIz1RrwMPunDlqwww==";
			Program.DoHibernation();
		}
	}
}

private static string str_cypher = "BM3aZTvv5iQAhK95EFLuz4pta";

private static void DoHibernation()
{
	DateTime now = DateTime.Now;
	if (now.Hour == 8)
	{
		Program.str_input += "!";
		if (Program.str_input.Length == now.Hour)
		{
			WATCrypt wATCrypt = new WATCrypt(Program.str_input);
			Console.WriteLine(wATCrypt.Decrypt(Program.str_cypher));
			return;
		}
	}
	else
	{
		Console.WriteLine("This isn't the time yet.");
	}
}

public string Decrypt(string p_data)
{
	DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider();
	dESCryptoServiceProvider.Key = this.Skey;
	dESCryptoServiceProvider.IV = this.Skey;
	MemoryStream memoryStream = new MemoryStream();
	CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateDecryptor(), CryptoStreamMode.Write);
	byte[] array = Convert.FromBase64String(p_data);
	cryptoStream.Write(array, 0, array.Length);
	cryptoStream.FlushFinalBlock();
	return Encoding.UTF8.GetString(memoryStream.GetBuffer());
}

All we need is some simple static analysis – no need to actually run the thing:

  • The program uses SpeechRecognitionEngine and SpeechSynthesizer to ask us the question: What is greater than god, more evil than the devil?
  • In the recognizer_SpeechRecognized callback it first checks whether our reply is ‘Nothing‘ and next asks us whether we are sure.
  • Upon answering yes, an extra chunk of base64 ciphertext is added to an already initialized ciphertext, and decryption is performed by calling DoHibernation, which appends an exclamation mark to our initial reply (‘Nothing’) and uses it as a DES key to decrypt the ciphertext in CBC mode (IV is the key).

We have the key (‘Nothing!’) and ciphertext (‘BM3aZTvv5iQAhK95EFLuz4ptaQA1f1/EqAOZktIz1RrwMPunDlqwww==’), which we can decrypt using some C# copied from the disassembly – or just write a few lines of python:

>>> from Crypto.Cipher import DES
>>> key = 'Nothing!'
>>> c = 'BM3aZTvv5iQAhK95EFLuz4ptaQA1f1/EqAOZktIz1RrwMPunDlqwww=='.decode('base64')
>>> DES.new(key, DES.MODE_CBC, key).decrypt(c)
'Nuno! Congratulations on your wedding!\x02\x02'

PyCrypto doesn’t support (PKCS7) padding, so our result has two trailing padding bytes.

Flag: Nuno! Congratulations on your wedding!

Comments are closed.