Nytro Posted December 28, 2014 Report Posted December 28, 2014 Decrypt stored passwords from Firefox, Chrome and Internet Explorer with C# and .NET Mladen Stanisic, 28 Dec 2014 CPOL How to retrieve passwords stored in Firefox, Chrome and Internet Explorer programmatically in C# Introduction Modern internet browsers offer user to save user name/password while logging to sites. Some third party applications can be used to extract this information. These applications are written in C++, and the source code I ran into while searching for answer on how it's done is mostly in C++. Although I searched thoroughly for the answer on how to do this in C#, I didn't find complete solution for all the three. This article explains how to do this programmaticaly in C# with .NET 2.0 and for all three most popular browsers: Firefox, Chrome and IE. Background The way passwords are stored in browsers is thoroughly explained by Jordan Wright's excellent article in his blog on Raider Security which can be found here. His article also provide many usefull links for further insights. Especially useful are articles on password security SecurityXploaded site. For the purpose of this article it is enough to say that Google Chrome stores passwords in a file Login Data in %LOCALAPPDATA%\Google\Chrome\User Data\Default\ folder which is basically an SQLite database; Firefox stores login data in %APPDATA%\Mozilla\Firefox\Profiles\{profile name}\ folder in logins.json file, and older versions used to store data in signons.sqlite file, which is SQLite database and is not used anymore. Internet Explorer store its autocomplete passwords in Registry, in HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage2 key.Articol complet: Decrypt stored passwords from Firefox, Chrome and Internet Explorer with C# and .NET - CodeProject Quote
gavneco1 Posted May 25, 2015 Report Posted May 25, 2015 Article was removed from codeproject, anybody have backup ? Quote
gigiRoman Posted March 3, 2020 Report Posted March 3, 2020 (edited) Tare: https://web.archive.org/web/20150109073357/http://www.codeproject.com/Articles/857320/Decrypt-Stored-Passwords-from-Firefox-Chrome-and-I Si pt posteritate: DEC JAN JUN 09 2014 2015 2016 15 captures 31 Dec 2014 - 26 Jul 2017 About this capture 11,138,654 members (69,146 online) Sign in home articles Chapters and Sections> Search Latest Articles Latest Tips/Tricks Top Articles Beginner Articles Technical Blogs Posting/Update Guidelines Article Help Forum Article Competition Submit an article or tip Post your Blog quick answers Ask a Question about this article Ask a Question View Unanswered Questions View All Questions... C# questions ASP.NET questions VB.NET questions SQL questions Javascript questions discussions All Message Boards... Application Lifecycle> Running a Business Sales / Marketing Collaboration / Beta Testing Work & Training Issues Design and Architecture ASP.NET JavaScript C / C++ / MFC> ATL / WTL / STL Managed C++/CLI Adobe Technologies C# Free Tools Objective-C Ruby On Rails Database Hardware & Devices> System Admin Hosting and Servers Java .NET Framework Android Mobile Sharepoint Silverlight / WPF Visual Basic Web Development Site Bugs / Suggestions features Competitions News The Insider Newsletter The Daily Build Newsletter Newsletter archive Surveys Product Showcase Research Library CodeProject Stuff community Who's Who Most Valuable Professionals The Lounge The Insider News The Weird & The Wonderful The Soapbox Press Releases Non-English Language> General Indian Topics General Chinese Topics help What is 'CodeProject'? General FAQ Ask a Question Bugs and Suggestions Article Help Forum Site Map Advertise with us Employment Opportunities About Us Articles » Platforms, Frameworks & Libraries » .NET Framework » How To Article Alternatives Comments (20) Tagged as .NET2.0 WinXP Vista C# Windows .NET Dev Intermediate Win7 C#3.5 security Win8 SQLlite VS2013 WinAPI , + Related Articles Introducing Textmode in ASP.NET 4.5 Disable IE/Firefox remember password ? A Fully Featured Windows HTTP Wrapper in C++ A Basic MVC Application and UI Testing through Selenium Web Driver Export Chrome bookmarks to IE Favorites with JsonCpp Go to top Decrypt Stored Passwords from Firefox, Chrome and Internet Explorer with C# and .NET Mladen Stanisic, 27 Dec 2014 CPOL 4.98 (33 votes) Rate this: vote 1vote 2vote 3vote 4vote 5 How to retrieve passwords stored in Firefox, Chrome and Internet Explorer programmatically in C# Download source - 603.8 KB Introduction Modern internet browsers offer user to save user name/password while logging to sites. Some third party applications can be used to extract this information. These applications are written in C++, and the source code I ran into while searching for an answer on how it's done is mostly in C++. Although I searched thoroughly for the answer on how to do this in C#, I didn't find a complete solution for all the three. This article explains how to do this programmaticaly in C# with .NET 2.0 and for all three most popular browsers: Firefox, Chrome and Internet Explorer. Background The way passwords are stored in browsers is thoroughly explained by Jordan Wright in his excellent article on RaiderSecurity blog which can be found here. His article also provides many useful links for further insights. Especially useful are articles on password security SecurityXploaded site. For the purpose of this article, it is enough to say that Google Chrome stores passwords in a file Login Data in %LOCALAPPDATA%\Google\Chrome\User Data\Default\ folder which is basically an SQLite database; Firefox stores login data in %APPDATA%\Mozilla\Firefox\Profiles\{profile name}\ folder in JSON logins.json file, and older versions used to store data in signons.sqlite file, which is SQLite database and is not used anymore. Internet Explorer stores its autocomplete passwords in Registry, in HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage2 key. Using the Code Single user login consists of the following information: site/url visited, user name and password. This information is retrieved from browser database (registry in the case of Internet Explorer) by static LoginReader class. Encrypted information about user name and password are decrypted by methods in large CryptoAPI class, and finally stored in LoginInfo class, where they can be accessed though properties UserName, Password, and Url. Collapse | Copy Code public class LoginInfo { public string Url { get; set } public string Password { get; set; } public string UserName { get; set; } public string Browser { get; set; } } To retrieve login information for the specified browser, we call static methods in LoginReader class. LoginReader class has three static methods (for each of the supported browsers); each of them will return a collection of LoginInfo objects which can be added to ListView, or displayed in console (like in this demo project, it offers some handy overloads of ToString() method for simplicity). Demo project comes with precompiled Decryptor.dll. To use classes in your project, you can add reference to this DLL, and include Newtonsoft.Json.dll and sqlite_x86.dll which are located in \bin folder of the demo to your project. Then, to retrieve login data, you would write: Collapse | Copy Code using PassDecrypt; ... List<LoginInfo> logins = new List<LoginInfo>(); logins.AddRange(LoginReader.GetLoginsFirefox()); logins.AddRange(LoginReader.GetLoginsChrome()); logins.AddRange(LoginReader.GetLoginsIE()); The rest is just iterating through a list and displaying the contents of each LoginInfo object: Collapse | Copy Code foreach (LoginInfo login in logins) { Console.WriteLine(login); // or access individual properties like this: // //Console.WriteLine("Browser: \"{0}\":: URL: {1}, UserName: {2}, Password: {3}.", // login.Browser, login.Url, login.UserName, login.Password); } Helper Classes For the demo project, I used a number of helper classes to retrieve entries from SQLite databases, Explorer history and JSON database of Firefox. For reading SQLite databases, I used heavily modified SQLWrapper class which I found here. The class still holds the name SQLiteWrapper, but now includes support for sequential reading by DataReader class, reading of BLOB objects, and support for 64-bit sqlite.dll. Basically, this is a native wrapper around sqlite.dll which can be downloaded here. I modified this simple wrapper for the code in the demo project to be 100 % compatible with the code you would write for the ADO.NET SQLite wrapper. So you may also reference System.Data.SQLite and use it instead if you prefer so. But this wrapper is light-weight and can be compiled for AnyCPU or x64 target without concern about which dlls to include in project and distribute to end users. All that needs to be included in the project are two sqlite.dlls, one compiled for 32 bit platform which has to be renamed to sqlite_x86.dll and the other compiled for 64 bit platform which has to be renamed to sqlite_x64.dll both are available for download from SQLite download page. Demo project is compiled for x86 platform, otherwise calling decryption functions would not be possible through delegates obtained by GetProcAddress() (64-bit code is not compatible with 32-bit libraries Firefox uses) so sqlite_x64.dll is not included in the demo. For reading JSON database stored in logins.json, I used Newtonsoft.Json wrapper for .NET. It is available as NuGet package. To read json into C# object, I have written FFLogins class. Finally, for reading Internet Explorer history, I used slightly modified version of The Tiny Wrapper Class for URL History Interface in C#. Decrypting the Passwords Google Chrome This one is the most simple to acquire. Because Google Chrome store passwords as BLOB objects encrypted in the context of current user using the Win32 API CryptProtectData() function without additional entropy, it can be easily decrypted using CryptUnprotectData(). Both functions have a handy .NET wrapper in static ProtectData class of System.Security.Cryptography namespace. When the password blob object is retrieved from database as byte[] the rest is just a call to ProtectData.Unprotect() and converting resulting decrypted byte[] to string: Collapse | Copy Code using System.Security.Cryptography; public static string Decrypt(byte[] blob) { byte[] decryptedBytes = ProtectedData.Unprotect(blob, null, DataProtectionScope.CurrentUser); return Encoding.UTF8.GetString(decryptedBytes); } Mozilla Firefox For this, I used a solution readily available in C# which I found here, but I have updated it to work with the most recent version of Firefox and repacked into FFDecryptor class. This is wrapper around functions which Firefox use to store and retrieve passwords, and which are exported from nss3.dll. There are no wrappers for these in .NET so interop with P/Invoke has to be utilised. Functions have the following signatures: Collapse | Copy Code long NSS_Init(string configdir); int PK11SDR_Decrypt(ref TSECItem data, ref TSECItem result, int cx); long PK11_GetInternalKeySlot(); long PK11_Authenticate(long slot, bool loadCerts, long wincx); int NSSBase64_DecodeBuffer(IntPtr arenaOpt, IntPtr outItemOpt, StringBuilder inStr, int inLen); and structure TSECItem referenced in PK11SDR_Decrypt has the following declaration: Collapse | Copy Code private struct TSECItem { public int SECItemType; public int SECItemData; public int SECItemLen; } To aquire these functions, we load nss3.dll (which has the following dependencies: msvcr100.dll, msvcp100.dll, mozglue.dll) by using LoadLibrary from Win32 API (kernel32.dll), and initialize decrypter by calling NSS_Init. All of this is done in Init() function of FFDecryptor class. Folder which contains the database, %APPDATA% profile folder, is passed as a parameter. Collapse | Copy Code public static void Init(string configDir) { string mozillaPath = Environment.GetEnvironmentVariable("ProgramFiles(x86)") + @"\Mozilla Firefox\"; if (!Directory.Exists(mozillaPath)) mozillaPath = Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles) + @"\Mozilla Firefox\"; if (!Directory.Exists(mozillaPath)) throw new ArgumentException ("Mozilla Firefox install folder cannot be found."); LoadLibrary(mozillaPath + "msvcr100.dll"); LoadLibrary(mozillaPath + "msvcp100.dll"); LoadLibrary(mozillaPath + "mozglue.dll"); _nss3DllPtr = LoadLibrary(mozillaPath + "nss3.dll"); IntPtr pProc = GetProcAddress(_nss3DllPtr, "NSS_Init"); NSS_InitPtr NSS_Init = (NSS_InitPtr)Marshal.GetDelegateForFunctionPointer(pProc, typeof(NSS_InitPtr)); NSS_Init(configDir); long keySlot = PK11_GetInternalKeySlot(); PK11_Authenticate(keySlot, true, 0); } User name and password are stored as an encrypted string. To decrypt it, the following function from static FFDecryptor class is used: Collapse | Copy Code public static string Decrypt(string cypherText) { StringBuilder sb = new StringBuilder(cypherText); int hi2 = NSSBase64_DecodeBuffer(IntPtr.Zero, IntPtr.Zero, sb, sb.Length); TSECItem tSecDec = new TSECItem(); TSECItem item = (TSECItem)Marshal.PtrToStructure(new IntPtr(hi2), typeof(TSECItem)); if (PK11SDR_Decrypt(ref item, ref tSecDec, 0) == 0) { if (tSecDec.SECItemLen != 0) { byte[] bvRet = new byte[tSecDec.SECItemLen]; Marshal.Copy(new IntPtr(tSecDec.SECItemData), bvRet, 0, tSecDec.SECItemLen); return Encoding.ASCII.GetString(bvRet); } } return null; } Internet Explorer The most difficult to obtain are passwords from Internet Explorer, and not just because of the lack of decent interop routines. User name and password in Internet Explorer are stored in a single string. This string is packed into a byte array along with a couple of headers which contain information about size and offsets of each "secret" (username or password is consider a "secret" in a context of Internet Explorer depcryption). This byte array is then encrypted by using a CryptProtectData() with URL string (including trailing'\0' character!) as an additional entrophy parameter. It is then stored in registry as a value under the name which is constructed from the same URL used for encryption. This URL is hashed with SHA1 encryption to 21 byte array, and converted to string of 42 hexadecimal digits. As mentioned above, the value is stored in HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage2 key. To retrieve user name and password, first we iterate through all items in history, converting URL to hash and comparing it with the value name in registry key. If the match is found, than we decrypt the value (byte array) by using URL as additional entropy in function call CryptUnprotectData(). This is easy since the wrapper is available through ProtectData.Unprotect() method. The hard part is extracting information from resulting byte[]. Layout of structures used to store information is given in this article, but the provided source code is written in C++ and heavily uses pointer arithmetics to reconstruct structures from data buffer. Since using of unsafe code in C# is discouraged, I have used System.Buffer class (System.IO.MemoryStream can also be used successfully, but with Buffer the same effect can be accomplished with less lines of code) and a very handy byte[] to struct converter I have found here. The code is given below: Collapse | Copy Code static T ByteArrayToStructure<T>(byte[] bytes) where T : struct { GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); handle.Free(); return stuff; } To convert URL from history to SHA1 hash, I had to write an interop for the existing code in C++ taken from SecurityXploaded site. Here is the function in C#: Collapse | Copy Code static string GetURLHashString(string wstrURL) { IntPtr hProv = IntPtr.Zero; IntPtr hHash = IntPtr.Zero; CryptAcquireContext (out hProv, String.Empty, string.Empty, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); if (!CryptCreateHash(hProv, ALG_ID.CALG_SHA1, IntPtr.Zero, 0, ref hHash)) throw new Win32Exception(Marshal.GetLastWin32Error()); byte[] bytesToCrypt = Encoding.Unicode.GetBytes(wstrURL); StringBuilder urlHash = new StringBuilder(42); if (CryptHashData(hHash, bytesToCrypt, (wstrURL.Length + 1) * 2, 0)) { // retrieve 20 bytes of hash value uint dwHashLen = 20; byte[] buffer = new byte[dwHashLen]; //Get the hash value now... if (!CryptGetHashParam(hHash, HashParameters.HP_HASHVAL, buffer, ref dwHashLen, 0)) throw new Win32Exception(Marshal.GetLastWin32Error()); //Convert the 20 byte hash value to hexadecimal string format... byte tail = 0; // used to calculate value for the last 2 bytes urlHash.Length = 0; for (int i = 0; i < dwHashLen; ++i) { byte c = buffer[i]; tail += c; urlHash.AppendFormat("{0:X2}", c); } urlHash.AppendFormat("{0:X2}", tail); CryptDestroyHash(hHash); } CryptReleaseContext(hProv, 0); return urlHash.ToString(); } And finally, the function to retrieve user name and password from Internet Explorer goes as follows: Collapse | Copy Code public static bool DecryptIePassword(string url, List<string[]> dataList) { //Get the hash for the passed URL string urlHash = GetURLHashString(url); //Check if this hash matches with stored hash in registry if (!DoesURLMatchWithHash(urlHash)) return false; //Now retrieve the encrypted credentials for this registry hash entry.... RegistryKey key = Registry.CurrentUser.OpenSubKey(KeyStr); if (key == null) return false; //Retrieve encrypted data for this website hash... //First get the value... byte[] cypherBytes = (byte[])key.GetValue(urlHash); key.Close(); // to use URL as optional entropy we must include trailing null character byte[] optionalEntropy = new byte[2 * (url.Length + 1)]; Buffer.BlockCopy(url.ToCharArray(), 0, optionalEntropy, 0, url.Length * 2); //Now decrypt the Autocomplete credentials.... byte[] decryptedBytes = ProtectedData.Unprotect(cypherBytes, optionalEntropy, DataProtectionScope.CurrentUser); var ieAutoHeader = ByteArrayToStructure<IEAutoComplteSecretHeader>(decryptedBytes); //check if the data contains enough length.... if (decryptedBytes.Length >= (ieAutoHeader.dwSize + ieAutoHeader.dwSecretInfoSize + ieAutoHeader.dwSecretSize)) { //Get the total number of secret entries (username & password) for the site... // user name and passwords are accounted as separate secrets, but will be threated in pairs here. uint dwTotalSecrets = ieAutoHeader.IESecretHeader.dwTotalSecrets / 2; int sizeOfSecretEntry = Marshal.SizeOf(typeof(SecretEntry)); byte[] secretsBuffer = new byte[ieAutoHeader.dwSecretSize]; int offset = (int) (ieAutoHeader.dwSize + ieAutoHeader.dwSecretInfoSize); Buffer.BlockCopy(decryptedBytes, offset, secretsBuffer, 0, secretsBuffer.Length); if (dataList == null) dataList = new List<string[]>(); else dataList.Clear(); offset = Marshal.SizeOf(ieAutoHeader); // Each time process 2 secret entries for username & password for (int i = 0; i < dwTotalSecrets; i++) { byte[] secEntryBuffer = new byte[sizeOfSecretEntry]; Buffer.BlockCopy(decryptedBytes, offset, secEntryBuffer, 0, secEntryBuffer.Length); SecretEntry secEntry = ByteArrayToStructure<SecretEntry>(secEntryBuffer); string[] dataTriplet = new string[3]; // store data such as url, username & password for each secret byte[] secret1 = new byte[secEntry.dwLength * 2]; Buffer.BlockCopy(secretsBuffer, (int)secEntry.dwOffset, secret1, 0, secret1.Length); dataTriplet[0] = Encoding.Unicode.GetString(secret1); // read another secret entry offset += sizeOfSecretEntry; Buffer.BlockCopy(decryptedBytes, offset, secEntryBuffer, 0, secEntryBuffer.Length); secEntry = ByteArrayToStructure<SecretEntry>(secEntryBuffer); byte[] secret2 = new byte[secEntry.dwLength * 2]; //Get the next secret's offset i.e password Buffer.BlockCopy(secretsBuffer, (int) secEntry.dwOffset, secret2, 0, secret2.Length); dataTriplet[1] = Encoding.Unicode.GetString(secret2); dataTriplet[2] = urlHash; //move to next entry dataList.Add(dataTriplet); offset += sizeOfSecretEntry; // advanced offset pointer to next secret } } return true; } //End of function Points of Interest Retrieval of passwords for Firefox and Internet Explorer requires use of P/Invoke. The code in the demo project for this article demontrates how to use delegates to call functions from run-time loaded dlls obtained with LoadLibrary() and GetProcAddress() API functions. It further demonstrates how to use System.Buffer and Marshal classes to perform interop between managed and native structures, and how to construct structures from byte arrays without use of unsafe code and pointer arithmetics. It also gives an insight to a bit of cryptography by demonstrating how to use data decryption function in System.Security.Cryptography.ProtectData class. History 27.12.2014: Initial post 07.01.2015: Updated code to fix bugs in DecryptIePassword() License This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL) Share EMAIL About the Author Mladen Stanisic Software Developer Serbia I was a hobbyist programmer writing in C++ for seven years. Starting from summer 2014 I am professional C# developer working on desktop applications using Windows Forms. Comments and Discussions First Prev Next IE Problem - "Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2" does not exist Graeme_Grant 10hrs 10mins ago Re: IE Problem - "Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2" does not exist Mladen Stanisic 8hrs 40mins ago My vote of 5 raja mohan 7-Jan-15 3:50 IE Error Burhan Eyimaya 6-Jan-15 4:56 Re: IE Error [modified] Mladen Stanisic 7-Jan-15 12:03 Re: IE Error Burhan Eyimaya 7-Jan-15 20:29 My vote of 5 Oshtri Deka 30-Dec-14 6:52 Chrome DB angelbroz85 29-Dec-14 14:26 Re: Chrome DB Mladen Stanisic 30-Dec-14 6:49 Re: Chrome DB angelbroz85 30-Dec-14 6:57 Is there a source code download for this article? Martin Hart Turner 29-Dec-14 2:58 Re: Is there a source code download for this article? [modified] Mladen Stanisic 29-Dec-14 9:51 Re: Is there a source code download for this article? Martin Hart Turner 29-Dec-14 21:40 My vote of 5 PapyRef 29-Dec-14 2:17 My vote of 5 Humayun Kabir Mamun 29-Dec-14 1:44 Slight Error [modified] ledtech3 28-Dec-14 14:09 Re: Slight Error [modified] Mladen Stanisic 29-Dec-14 10:15 Re: Slight Error ledtech3 29-Dec-14 12:45 My vote of 5 m-mousavi 27-Dec-14 23:59 My vote of 5 Joe Gakenheimer 27-Dec-14 20:26 Last Visit: 31-Dec-99 19:00 Last Update: 8-Jan-15 16:33 Refresh 1 General News Suggestion Question Bug Answer Joke Rant Admin Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages. Info First Posted 27 Dec 2014 Views 9,737 Downloads 230 Bookmarked 44 times Research Why Your Developers Need More Training How to Evaluate Component Vendors Permalink | Advertise | Privacy | Terms of Use | Mobile Web02 | 2.8.141223.1 | Last Updated 28 Dec 2014 Article Copyright 2014 by Mladen Stanisic Everything else Copyright © CodeProject, 1999-2015 Layout: fixed | fluid Edited March 3, 2020 by gigiRoman Quote