today I'm gonna write a very quick analysis about an Happy Ransomware variant spotted in the wild on Jan 24 2019.
https://www.hybrid-analysis.com/sample/9da7d298691613a398e26ac3c4c4e4e9c93069d2162fa6639901dd7c62774ef5?environmentId=100
https://www.virustotal.com/en/file/9da7d298691613a398e26ac3c4c4e4e9c93069d2162fa6639901dd7c62774ef5/analysis/
sample hash details:
MD5 64f11aee7f21ec74a3f8f518e45c6d55
SHA1 1d06a6c7032c4ec4005a46ffe7c29135f26d3e15
SHA256 9da7d298691613a398e26ac3c4c4e4e9c93069d2162fa6639901dd7c62774ef5
This was a very easy ransomware, like many I've seen in the past it actually send an email with a PC screenshot, this.i (wich is the encrypted files counter) and some other stuffs... Actually the ransomware sends some of such informations also trough the UserAgent to a specific url but we dont care about that, we're focused to know how to get back our files.
In this ransomware a static analysis is enough to have an idea on how the sample works.
From the picture above, the circle number 1 is actually a search of all ("*") the files + all sub Directories of the following ones: ProgramFiles, PROGRAMFILES(X86), systemroot, appdata, tmp , Desktop and MyDocuments folder.
As you can see on the circle number 2or each file found, the encryption key string is composed by (this.i + 1) + "GbVjXehg"
The encryption function is called (2bis circle) and then the circle number 3 actually means this.i +=1;
This means that we have different key for each file encrypted in a keyspace which is contained into 1 up to the number of files encrypted. If we suppose to have 1000 encrypted files (wich we can enumerate by a search of "*.happy")
Minium key string is from "1"+"GbVjXehg" to "1000" +"GbVjXehg"
Each key is actually hashed (sha256Cng.Computehash(byte[] in) in the encrypt function), but this does not change the size of the keyspace because we have just one hash match for each key string.
Source code (its just a proof of concept), here:
using System; using System.Security.Cryptography; using System.Text; using System.IO; namespace proofofcode { class Program { public static void Main(string[] args) { var buffer = File.ReadAllBytes(@"c:\enc.happy"); int maxfiles= 1000; //We suppose to have just 1000 encrypted files. int i=0; MemoryStream mss = new MemoryStream(); for(;i<=maxfiles;i++){ if(Decrypt(i,buffer,out mss)==1) break; } File.WriteAllBytes(@"C:\Users\PC\dec.bin",mss.ToArray()); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } public static int Decrypt(int i, byte[] buffer, out MemoryStream msi) { int ret=1; try{ RijndaelManaged myRijndael = new RijndaelManaged(); myRijndael.Mode = CipherMode.ECB; SHA256Cng asd = new SHA256Cng(); var rijndael = new RijndaelManaged { // "135GbVjXehg" Key = asd.ComputeHash(Encoding.ASCII.GetBytes(i+"GbVjXehg")), Mode = CipherMode.ECB }; var transform = rijndael.CreateDecryptor(); string decrypted; using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, transform, CryptoStreamMode.Write)) { cs.Write(buffer, 0, buffer.Length); cs.FlushFinalBlock(); cs.Close(); // Console.Write("good key"); // File.WriteAllBytes(@"c:\dec.bin",ms.ToArray()); } msi=ms; ms.Close(); } }catch(Exception e){Console.WriteLine("error key"+i); Console.WriteLine("IOException source: {0}", e.Message); msi=null; ret=0; } return ret; } }}
Obviously the code can be optimized by for example, starting from rewriting my whole code LOL :)) plus, as we know each key is used once for one file, so to speedup the process excluding the used key helps a lot.
You can extend the use searching all the .happy files and automate the decryption for each file found.
Cheers,
RE Solver
Nessun commento:
Posta un commento