{"id":202,"date":"2012-08-03T20:05:09","date_gmt":"2012-08-03T20:05:09","guid":{"rendered":"http:\/\/www.gironsec.com\/blog\/?p=202"},"modified":"2012-08-21T17:50:21","modified_gmt":"2012-08-21T17:50:21","slug":"cracking-smartermail-hashes","status":"publish","type":"post","link":"https:\/\/www.gironsec.com\/blog\/2012\/08\/cracking-smartermail-hashes\/","title":{"rendered":"Cracking SmarterMail hashes"},"content":{"rendered":"<p>This week I encountered a password hash I hadnt seen in a while. Base64 with a twist. SmarterTools.com has a mail server called SmarterMail written in all .net. It stores its passwords in xml files in what looks to be base64, but not quite.<\/p>\n<p><a href=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/1277327753072.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-207\" title=\"1277327753072\" src=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/1277327753072.jpg\" alt=\"\" width=\"447\" height=\"380\" srcset=\"https:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/1277327753072.jpg 447w, https:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/1277327753072-300x255.jpg 300w\" sizes=\"(max-width: 447px) 100vw, 447px\" \/><\/a><\/p>\n<p>Unlike most companies, I assume SmarterTools doesn&#8217;t know how to encrypt or obfuscate its binaries, instead, they store all of their code in a managed assembly DLL and call it with an exe. That said, reversing it was rather simple since I only needed a decent decompiler and grep to find its hashing algorithm. And here it is:<\/p>\n<pre><code class=\"C#\">\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.IO;\nusing System.Security.Cryptography;\nnamespace TicketCounter\n{\npublic class CryptographyHelper\n{\nprotected internal byte[] salt = new byte[4]\n{\n(byte) 155,\n(byte) 26,\n(byte) 93,\n(byte) 86\n};\nprotected SymmetricAlgorithm Coder;\nprotected byte[] Key;\nprotected byte[] IV;\nprotected int Method;\nprotected CryptographyHelper()\n{\n}\npublic CryptographyHelper(int methodIn)\n{\nthis.Method = methodIn;\nif (this.Method == 0)\nthis.Coder = (SymmetricAlgorithm) DES.Create();\nelse\nthis.Coder = (SymmetricAlgorithm) RC2.Create();\n}\npublic void SetKey(string key)\n{\nint cb = this.Method != 0 ? 5 : 8;\nPasswordDeriveBytes passwordDeriveBytes = new PasswordDeriveBytes(key, this.salt);\nthis.Key = passwordDeriveBytes.GetBytes(cb);\nthis.IV = passwordDeriveBytes.GetBytes(cb);\n}\npublic void SetKey(ref Random rnd)\n{\nint length = this.Method != 0 ? 5 : 8;\nthis.Key = new byte[length];\nthis.IV = new byte[length];\nrnd.NextBytes(this.Key);\nrnd.NextBytes(this.IV);\n}\npublic void SetKey(byte[] keyIn, byte[] ivIn)\n{\nint length = this.Method != 0 ? 5 : 8;\nthis.Key = new byte[length];\nthis.IV = new byte[length];\nArray.Copy((Array) keyIn, 0, (Array) this.Key, 0, length);\nArray.Copy((Array) ivIn, 0, (Array) this.IV, 0, length);\n}\npublic string EncodeToBase64(string val)\n{\nif (val.Length == 0)\nreturn val;\nelse\nreturn Convert.ToBase64String(this.Encode(Encoding.UTF8.GetBytes(val)));\n}\npublic string DecodeFromBase64(string val)\n{\nif (val.Length == 0)\nreturn val;\nelse\nreturn Encoding.UTF8.GetString(this.Decode(Convert.FromBase64String(val)));\n}\npublic static string EncodeToBase64(int method, int key, string val)\n{\nif (val.Length == 0)\nreturn val;\nCryptographyHelper cryptographyHelper = new CryptographyHelper(method);\nRandom rnd = new Random(key);\ncryptographyHelper.SetKey(ref rnd);\nreturn cryptographyHelper.EncodeToBase64(val);\n}\npublic static string DecodeFromBase64(int method, int key, string val)\n{\nif (val.Length == 0)\nreturn val;\nCryptographyHelper cryptographyHelper = new CryptographyHelper(method);\nRandom rnd = new Random(key);\ncryptographyHelper.SetKey(ref rnd);\nreturn cryptographyHelper.DecodeFromBase64(val);\n}\npublic static string EncodeToBase64(int method, string key, string val)\n{\nif (val.Length == 0)\nreturn val;\nCryptographyHelper cryptographyHelper = new CryptographyHelper(method);\ncryptographyHelper.SetKey(key);\nreturn cryptographyHelper.EncodeToBase64(val);\n}\npublic static string DecodeFromBase64(int method, string key, string val)\n{\nif (val.Length == 0)\nreturn val;\nCryptographyHelper cryptographyHelper = new CryptographyHelper(method);\ncryptographyHelper.SetKey(key);\nreturn cryptographyHelper.DecodeFromBase64(val);\n}\npublic byte[] Encode(byte[] buf)\n{\nreturn this.PassThrough(buf, this.Coder.CreateEncryptor(this.Key, this.IV));\n}\npublic byte[] Decode(byte[] buf)\n{\nreturn this.PassThrough(buf, this.Coder.CreateDecryptor(this.Key, this.IV));\n}\nprotected byte[] PassThrough(byte[] buf, ICryptoTransform transformation)\n{\nMemoryStream memoryStream = new MemoryStream();\nCryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, transformation, CryptoStreamMode.Write);\ncryptoStream.Write(buf, 0, buf.Length);\ncryptoStream.FlushFinalBlock();\nmemoryStream.Seek(0L, SeekOrigin.Begin);\nbyte[] buffer = new byte[memoryStream.Length];\nmemoryStream.Read(buffer, 0, (int) memoryStream.Length);\ncryptoStream.Close();\nmemoryStream.Close();\nreturn buffer;\n}\n}\n}\n<\/code><\/pre>\n<p>See the key?\u00a0 No you don&#8217;t because the key was elsewhere in the app &#8211; specifically in the config area that deals with description:<\/p>\n<pre><code class=\"C#\">\n\/\/namespace SmarterMail.Config\npublic class SystemAdminLogin\n{\npublic static string PasswordKey = 03a8ur98qhfa9h; \/\/  assume quotes\npublic string ID { get; set; }\npublic string Username { get; set; }\npublic List&amp;lt;IpAccess&amp;gt; IpAccessRestrictions { get; private set; }\npublic bool IsPrimaryAdmin { get; set; }\npublic bool EnableIpAccessRestriction { get; set; }\npublic DateTime DateCreated { get; set; }\npublic string Description { get; set; }\npublic string Password\n{\nget\n{\nreturn CryptographyHelper.\nDecodeFromBase64(0,SystemAdminLogin.PasswordKey, this.get_EncryptedPassword());\n}\nset\n{\nthis.set_EncryptedPassword(CryptographyHelper.EncodeToBase64(0,SystemAdminLogin.PasswordKey, value));\n}\n}static SystemAdminLogin()\n{\n}public SystemAdminLogin()\n{\nthis.IpAccessRestrictions = new List&amp;lt;IpAccess&amp;gt;();\nthis.DateCreated = DateTime.Now;\nthis.ID = string.Empty;\n}public void ToXml(XmlWriter writer)\n{\nwriter.WriteStartElement(&amp;#8220;SystemAdmin&amp;#8221;);\nwriter.WriteElementString(&amp;#8220;ID&amp;#8221;, this.ID);\nwriter.WriteElementString(&amp;#8220;Username&amp;#8221;, this.Username);\n\/\/ ISSUE: reference to a compiler-generated method\nwriter.WriteElementString(&amp;#8220;Password&amp;#8221;, this.get_EncryptedPassword());\nwriter.WriteElementString(&amp;#8220;EnableIpAccessRestriction&amp;#8221;,\nthis.EnableIpAccessRestriction.ToString());\nwriter.WriteElementString(&amp;#8220;DateCreated&amp;#8221;,\nthis.DateCreated.ToString((IFormatProvider)\nCultureInfo.InvariantCulture));\nwriter.WriteElementString(&amp;#8220;Description&amp;#8221;, this.Description);\nif (this.IpAccessRestrictions.Count &amp;gt; 0)\n{\nwriter.WriteStartElement(&amp;#8220;IpAccess&amp;#8221;);\nforeach (IpAccess ipAccess in this.IpAccessRestrictions)\n{\nwriter.WriteStartElement(&amp;#8220;Allowed&amp;#8221;);\nwriter.WriteElementString(&amp;#8220;Description&amp;#8221;, ipAccess.Description);\nwriter.WriteElementString(&amp;#8220;StartIp&amp;#8221;, ipAccess.StartIP);\nif (System_ExtensionMethods7BCA73B06BAB478aA3AC6AC60979BA25.HasValue(ipAccess.EndIP))\nwriter.WriteElementString(&amp;#8220;EndIp&amp;#8221;, ipAccess.EndIP);\nwriter.WriteElementString(&amp;#8220;Type&amp;#8221;, ((int) ipAccess.Type).ToString());\nwriter.WriteEndElement();\n}\nwriter.WriteEndElement();\n}\nwriter.WriteEndElement();\n}\npublic void FromXml(XmlReader reader)\n{\nstring str = string.Empty;\nlabel_27:\nwhile (reader.Read())\n{\nint num = (int) reader.MoveToContent();\nif (reader.NodeType == XmlNodeType.EndElement &amp;amp;&amp;amp;\nreader.Name.ToLowerInvariant() == &amp;#8220;systemadmin&amp;#8221;)\nbreak;\nif (reader.NodeType == XmlNodeType.Element &amp;amp;&amp;amp;\nreader.Name.ToLowerInvariant() == &amp;#8220;ipaccess&amp;#8221;)\n{\nIpAccess ipAccess = new IpAccess();\nbool flag = false;\nwhile (true)\n{\ndo\n{\nif (reader.Read() &amp;amp;&amp;amp; (reader.NodeType !=\nXmlNodeType.EndElement || !(reader.Name.ToLowerInvariant() ==\n&amp;#8220;ipaccess&amp;#8221;)))\n{\nif (reader.NodeType == XmlNodeType.EndElement &amp;amp;&amp;amp;\nreader.Name.ToLowerInvariant() == &amp;#8220;allowed&amp;#8221; &amp;amp;&amp;amp; flag)\n{\nthis.IpAccessRestrictions.Add(ipAccess);\nflag = false;\nipAccess = new IpAccess();\n}\nif (reader.NodeType == XmlNodeType.Element)\ngoto label_8;\n}\nelse\ngoto label_27;\n}\nwhile (reader.NodeType != XmlNodeType.Text);\ngoto label_10;\nlabel_8:\nstr = reader.Name.ToLowerInvariant();\ncontinue;\nlabel_10:\nswitch (str)\n{\ncase &amp;#8220;description&amp;#8221;:\nflag = true;\nipAccess.Description = reader.Value;\ncontinue;\ncase &amp;#8220;startip&amp;#8221;:\nflag = true;\nipAccess.StartIP = reader.Value;\ncontinue;\ncase &amp;#8220;endip&amp;#8221;:\nflag = true;\nipAccess.EndIP = reader.Value;\ncontinue;\ncase &amp;#8220;type&amp;#8221;:\nflag = true;\nipAccess.Type = (IPType) int.Parse(reader.Value);\ncontinue;\ndefault:\ncontinue;\n}\n}\n}\nelse if (reader.NodeType == XmlNodeType.Element)\nstr = reader.Name.ToLowerInvariant();\nelse if (reader.NodeType == XmlNodeType.Text)\n{\nswitch (str)\n{\ncase &amp;#8220;id&amp;#8221;:\nthis.ID = reader.Value;\ncontinue;\ncase &amp;#8220;enableipaccessrestriction&amp;#8221;:\nthis.EnableIpAccessRestriction = bool.Parse(reader.Value);\ncontinue;\ncase &amp;#8220;username&amp;#8221;:\nthis.Username = reader.Value;\ncontinue;\ncase &amp;#8220;password&amp;#8221;:\n\/\/ ISSUE: reference to a compiler-generated method\nthis.set_EncryptedPassword(reader.Value);\ncontinue;\ncase &amp;#8220;datecreated&amp;#8221;:\nthis.DateCreated = DateTime.Parse(reader.Value,\n(IFormatProvider) CultureInfo.InvariantCulture);\ncontinue;\ncase &amp;#8220;description&amp;#8221;:\nthis.Description = reader.Value;\ncontinue;\ndefault:\ncontinue;\n}\n}\n}\n}\n}\n<\/code><\/pre><\/wbr><\/wbr><\/wbr><\/wbr><\/wbr><\/p>\n<p><\/wbr><\/wbr><\/wbr><\/div>\n<p>That&#8217;s what we&#8217;re going to use to decrypt the binary.<\/p>\n<p>I borrowed their code to make my own little decrypter app kind of like how a cracker makes a keygen &#8211; same principle really, except in this case, they include a function for decrypting so I don&#8217;t need much:<\/p>\n<pre><code class=\"C#\">\nusing System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Drawing;\nusing System.Text;\nusing System.Windows.Forms;\nnamespace TicketCounter\n{\npublic partial class Form1 : Form\n{\npublic Form1()\n{\nInitializeComponent();\n}\npublic static string PasswordKey = &amp;#8220;03a8ur98qhfa9h&amp;#8221;;\nprivate void btnDecode_Click(object sender, EventArgs e)\n{\nstring enc = this.tbEnc.Text;\nthis.tbDec.Text = DecodeFromBase64(0, PasswordKey, enc);\n}\npublic static string DecodeFromBase64(int method, string key, string val)\n{\nif (val.Length == 0)\nreturn val;\nCryptographyHelper cryptographyHelper = new CryptographyHelper(method);\ncryptographyHelper.SetKey(key);\nreturn cryptographyHelper.DecodeFromBase64(val);\n}\n}\n}\n<\/code><\/pre>\n<p>Create the object and use it. Keep it simple. The project includes the class I ripped in the project.<\/p>\n<p>And there you have it. Next time you take control of a Smarter Mail server, you can now decrypt the passwords with ease.<\/p>\n<p><a href=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/smartermail_decryter.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-204\" title=\"smartermail_decryter\" src=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/smartermail_decryter.png\" alt=\"\" width=\"300\" height=\"300\" srcset=\"https:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/smartermail_decryter.png 300w, https:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/smartermail_decryter-150x150.png 150w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>For those of you who are lazy, you can download the project <a href=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/TicketCounter.7z\">here.<\/a> <\/p>\n<p>Happy hacking \ud83d\ude42<\/p>\n<p><a href=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/1249693573698.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-205\" title=\"1249693573698\" src=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/1249693573698.jpg\" alt=\"\" width=\"380\" height=\"247\" srcset=\"https:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/1249693573698.jpg 380w, https:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2012\/08\/1249693573698-300x195.jpg 300w\" sizes=\"(max-width: 380px) 100vw, 380px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This week I encountered a password hash I hadnt seen in a while. Base64 with a twist. SmarterTools.com has a mail server called SmarterMail written in all .net. It stores its passwords in xml files in what looks to be base64, but not quite. Unlike most companies, I assume SmarterTools doesn&#8217;t know how to encrypt [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[4,5,6,7],"tags":[24],"_links":{"self":[{"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/posts\/202"}],"collection":[{"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/comments?post=202"}],"version-history":[{"count":13,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/posts\/202\/revisions"}],"predecessor-version":[{"id":220,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/posts\/202\/revisions\/220"}],"wp:attachment":[{"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/media?parent=202"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/categories?post=202"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/tags?post=202"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}