Skip to main content

How Not to Obfuscate Passwords in Code

September 11, 2015

Software programs, from client-server to web to mobile, often need credentials to access a resource like a database or a web service. Storing these passwords is not an easy task, since there are so many potential threats. If one of those threats is an adversary able to disassemble your compiled code, well … all bets are probably off.

On a recent client engagement, I came across an application we had assessed a year prior.  This was a Java application contained within a .jar file, but the following principles hold the same for Android .apk files (which are just .jar files with special organization inside) or even .NET apps. From an attacker’s perspective, one of the best features of Java and .NET apps is the ability to reverse the high-level source code from them with tools like JD-GUI for Java and .NET Reflector for any language (C#, VB.NET, F#, Python) that is compiled down to .NET runtime. There are some decent tools out there for obfuscating code to make disassembly difficult (note: “difficult” not “impossible”), but in this particular case, the client did their obfuscation by hand.

In the assessment, we reported to the client that credentials were stored in plaintext as String objects in the compiled .jar file.  We verified the credentials were valid by logging in with them. The criticality of an issue like this really depends on what the credentials can access. It can range from “no big deal” to “fix this now!”

On the annual check-up a year later, the client’s developers left the connection details, including the User IDs as plaintext String objects in the Java code, but they removed the String password objects. Curious, I looked a little deeper and found a new helper object that was called when the passwords were needed. The following is a similar mock-up for illustration purposes:

public class PasswordObfuscator 
{    
    static String GetPassword(boolean bool)
    {
        StringBuffer sb = new StringBuffer();
        double[] dArray = { 72.125D, 36.9999999999D, 119.27000000000001D, 71.999999999D, 66.222D, 67.01D, 99.9999D, 121.0001D, 122.00000001D, 79.000023423D, 98.34119D, 33.0D, 48.0012312D, 101.00023D, 64.00004312999D, 45.000009999999D, 118.1D, 53.001D, 78.32323D, 95.5D };
        int i = 0;
        for (double d : dArray)
        {
            int val = (int)d;
            if (bool && (i % 2 == 0))
            {
                sb.append((char)val);
            }
            if (!bool && (i % 2 == 1))
            {
                sb.append((char)val);                
            }
            i++;
        }
        return sb.toString();
    }
}

I stared at this code for a couple moments trying to recall how Java handled overflow of all the bits on the right hand side of the decimal point when cast to integer. It was immediately apparent to me this code was alternating through the values in the array, casting every other integer value to its ASCII value. I began working the algorithm mentally for a second and then it hit me: Why am I doing this the hard way? 

At this point, I decided to pick on one of the recent graduates from our successful junior consultant program who was working this engagement with me. “Take a look at this for a second.” Being a recent computer science grad, I saw him start working the algorithm like I previously started, but (much to my enjoyment) he broke out a notepad and pencil to work it all out by hand. [Mental note: universities need to teach how to break code, not just build it.]

“That’s the hard way. Cheat!” 

He looked confused for a second as he saw me copy the entire helper object out of JD-GUI and paste it into a new “Hello World” Java project in Eclipse.  I modified the main() function as follows: 

public class Program {
    public static void main(String[] args) {
        System.out.println("Hello World.");
        System.out.println(PasswordObfuscator.GetPassword(true));
        System.out.println(PasswordObfuscator.GetPassword(false));
    }
}

Then he smiled.  He saw where this was going.  Click build, then click run > debug:

Out to the console came the super-secret passwords. What took the developer probably at least a couple hours to obfuscate by hand was unraveled in the few seconds it takes to copy, paste, build and run.

Moral of the story: don’t write your own security features—this includes code obfuscation.

Related Blogs

June 07, 2018

Quick Tips for Building an Effective AppSec Program – Part 3

This is the last post in my series on creating an effective AppSec program within your organization. In my last post, we discussed the importance of t...

See Details

May 10, 2018

Observations on Smoke Tests – Part 3

While attending one of our technology partner’s security training courses, the instructor presented on their product’s various features and capabiliti...

See Details

May 03, 2018

Getting Started with Postman for API Security Testing: Part 1

Postman is a useful tool used by many developers to document, test and interact with Application Programming Interfaces (APIs). With the ubiquity of A...

See Details

How Can We Help?

Let us know what you need, and we will have an Optiv professional contact you shortly.


Privacy Policy

Stay in the Know

For all the latest cybersecurity and Optiv news, subscribe to our blog and connect with us on Social.

Subscribe

Join our Email List

We take your privacy seriously and promise never to share your email with anyone.

Stay Connected

Find cyber security Events in your area.