Securing Business Apps - Rise of the White Collar Crackers

Securing Business Apps
Rise of the White Collar Crackers

Author: David Zimmer

  1. Introduction
  2. Bypassing the login
  3. Hacking the User Interface - Privledge Escalation
  4. Conclusion
  5. About the Author

Downloads
  • Example Binaries and Source - Visual Basic 6 sample business app used for demonstration in paper. Also includes a Patch Manager program so that you can see the effects of the various hacks as the paper progresses.

  • Securing_business_apps.chm - Compiled HTML help archive containg of all of the files used in this paper as a single download.


About the Author -

David Zimmer is an independent developer, consultant, and researcher based in New York.

When not buried in R&D, he has been known to pop his head up from time to time to release new white papers, and documentation of the various things he has turned up through out his research.

Current Research and topics of interest include: Web Application security, data forensics/restoration, malware and system analysis, software security, and Windows development.

David’s business, Venture Digital Mfg, first started life as a small manufacturing company creating a specialty machined product. Eventually CNC programming and CAD design lead David into the realm of computer programming where he discovered his fascination with computer security and software development.

Future skills he is looking forward to include custom electronics and embedded software development. This next piece of the puzzle will bring together all of his manufacturing, fabrication, mechanical engineering, and software development experience.

David is currently available for various consulting roles including:
  • Developer and Auditor Training
  • Custom Software Development
  • Security Auditing & Review
  • Project and Technology Consulting

Back to Index


White Collar Cracking - Conclusion

Section 4 - Conclusion

There are many many factors that go into creating a secure application.

From the obvious, like database security, right down to the actual coding implementation and security models it is based upon.

Attacks can come in many various shapes and sizes, this paper just mentions some. A motivated skilled attacker can pull of some pretty creative and amazing things.

The core problem with most of this sample, (and many apps found throughout industry) is that it used an application level security mechanism to control the actions of the users. This means that code running on the client machine is responsible for making the decisions to allow or deny an action.

Unless your computing environment is tightly controlled to not allow any unauthorized programs, or you take specific anti-cracking measures in your application you could be quite susceptible to these types of attacks.

When in doubt, have your applications audited by skilled personnel.

This paper is brought to you by Sleuth. Sleuth is a Web application auditing toolbox that allows to you efficiently poke, prod, push, and wrench your way into any corner of your web applications, using quick, efficient, visual tools.

Visit us on the web at http://sandsprite.com/Sleuth/ to learn more!


White Collar Cracking - Hacking the UI - Privledge Escalation

Section 3 - Hacking the UI & Privilege Escalation

  • Enabling Disabled Menu Items
  • Enabling Disabled Form Elements
  • Showing Invisible Form Elements
  • Revealing Hidden Features by Resizing Forms
So were in!

Now we can look around some. If we used the null char injection technique then we have access as the first user in the database, in this case the low data entry level.

If we used the binary patching technique, then are stuck with whatever the default level access is...again mere data entry level.

Another situation just as likely is that the user is actually a legitimate user to the system, who wants to get in and cause some problems.

Now our focus turns to privilege escalation.

Looking around, we see that we do not have access to the accounting and administration functions. Data Entry personal can only take orders and look up customer balance information.

The top menus that hold Administrator and Account links are disabled, and there are no disabled options on any of the forms we have access to that look to interesting. So where do we go from here?

Lets say our first interest is in getting to those administration functions that are shown as disabled on the top menu there. Can we enable those menu items ourselves or otherwise execute the functions they would call?

Would I have mentioned it otherwise? :)

Enabling Disabled Menu Items

First, lets start with the windows API. The API (Application Programming Interface) is a set of standard functions that developers use to call routines that the operating system exposes. These standard services include things like writing files, messaging services and yes...even menu creation/manipulation functions.

For API chaos and hacking I have thrown together a little program called winHack. (also available in the zip download at the beginning of this article)

The fourth button over from the left is the menu analyzer, and will break down a forms menus by handle, id and index and allow you to play around with API calls to them. Here is a picture of the form below with the settings entered to enable the Product Administration Menu item.

Hitting DoIt will call the EnableMenuItem API and magically turn on the menu item so we can select it.

Sounds pretty easy huh?

Well it comes with a catch. While it does indeed enable the menu item, for Visual Basic apps at least, this is not enough for VB to fire up the event handler for the menu item :(

Why do I mention it? Because it will probably work in just about any other programming language. I dug a little more into it, and the menu does send the exact same messages to the main window handler as for an enabled menu item, so the menu is working as it should, however it appears as if VB is not listening for that message to hook to the proper event handler when it believes the menu item is disabled. Go figure.

Anyway...we want those menu items. Our first stab hit some bad luck, time for take 2.

If you look at the over all layout of a VB compiled app you notice some things right off the bat. VB has its forms names, objects, and their properties all stored within it in a series of object tables. If we can learn to read and identify these objects then maybe we can manipulate their properties so they will be enabled by default.

Scanning down through the exe we come to some strings that look like the menu captions we see in the application. We also note that preceding each caption in the app is a mnu* string. This is a common notation by VB developers to name their menu objects.

In the image above, we have compared two sequential enabled menu items we found in the main app. Below that, we have two sequential disabled menus.

By comparing the two we are able to draw some similarities and try to define some common fields. Highlighted in red are the string length prefixes and null terminators. Yellow are the object and caption strings for each object. The objects themselves seem to be delimited by the FF 02 markers left in white.

This leaves us with just a couple fields we need to look into. The 13 03 looks curious but since it is found in both we know it does not have anything to do with the menus disabled/enabled state. Upon some further research we find that 13 is the object type identifier signifying a menu item [1] . Ok that makes sense. Looking some more we are also able to find documentation that the 03 is a property specifier, in this case for the caption property (for which the caption immediately follows).

The differences between the two, is the presence of the trailing 05 00. Looking at the documentation...we are able to see that 05 is an optional attribute specifier for the enabled option. 00 is the value of its state (false). Hummm..Can we change its default state from disabled to enabled?

Lets change that 00 to FF.

Starting up the app again, guess what...the menu item is now enabled by default and fully functional. It appears the author did not perform any further checks on the administration forms. His assumption was that only administrators could make it to this form and thus there was no need to performs further checks.

Want to try this one for yourself? Fire up the Patch Manager and enable the menu item checkbox and start up the app again. Pretty slick. Ok, so this is handy to know, but it only works because the author relied on its default state being disabled and had not set it latter in code.

Had the author left it enabled by default and then disabled it based on user credentials then you would then again have to dive back into the debugger to manipulate that logic. Can you find where the menus are manipulated based on the login user group?

Hint: The most logical place to put this code is in the form_load event when the main form loads. We know right where this is because we had to jump to the code that loads it back when we were patching the login. Also, we know where the group data was being access to load up a probably global usergroup identifier. If you could find the address of this variable, you could also just manually load it with something and let the rest go its merry way.

So here we are with full access to all of the menu items and thier functionality. That wasnt really that hard was it?

With access to the user administration functions, we can now see the administrator login information and login as him.

Enabling Disabled Form Elements

Looking around with the administrator account we notice that some of the forms we had access to as a data entry person, now have more features available to us. Lets compare one such form, the Customer Balance form.

As our default user, we were able to see the account information and account balance, however the "Update Record" button was disabled. Had we logged in as someone from accounting, the update record button would be available to us, however not even that is everything.

As we can see from the administrator user screen shot, administrators also have the option to remove customer records from the database.

Lets go back to assuming we were just a legitimate data entry user. The button is disabled. how can we get access to that functionality?

Lets fire up winHack again and see what else we can do with these windows API tricks. If we could enable menu items...Maybe we can enable command buttons as well.

So we fire up winHack and drag the cross hairs over the Customer Balance form. We can now see some information on the form such as its window handle, its parent etc. What we are interested in here is see what child windows it has. To Windows® every control you see is actually a separate window. Every button, every textbox is actually its own object that the operating system keeps track of.

This time..lets use the 3rd button over which has the tooltip "Enumerate Children"

There is our Update Record button handle as well as that of the hidden "Delete Customer" button. First, lets try to enable that Update Record button and see if we cant change our customers billing information.

Select the Update Record entry in the list then right click. If you could see the main winHack window while you did this..you noticed that the window handle was just changed to that of the selected child window.

Why not just use the cross hairs on the button directly? Unfortunately disabled child windows do not seem to give up their handles to the crosshairs method I employ. Anyway we have its handle now, so how do we enable it?

If you have played with the winHack interface much, you may have noticed the tool tip on the first and second buttons at the top. "Enable Window" and "Disable Window" Yup now that you have the window you want in your crosshairs hit the first buttons and watch it enable.

Lets see if it works, change some data up in the address textboxes and hit update record. If you listen, you can probably hear your hardrive churn as stuff happens. If not, reload the form and see if the new data is there. Sure enough it is.

Showing Invisible Form Elements

So what is left to do on this form? From our child enumeration list, we saw a reference to a button named "Add New Customer" I wonder what that’s all about. Do the right click thing to load it as the current hwnd and lets explore another winhack dialog.

The sendmessage form shown below is a wrapper for some common window messaging and visibility functions.

In the top frame labeled ShowWindow lets choose SW_SHOW from the drop down and hit the show button. Hey look, there it is.

Ok, there was one last button left on the Customer Balance form, the delete user button that was only visible for administrators. Can I gain access to that?

Right now the winHack hwnd is aimed at the freshly visible button. For our next manipulation we want it aimed back at the parent form. Sure we could just drag the cross hairs over the main form again, but I dunno, how about something new.

Click on the hwnd textbox in the parent details section of the winHack form and drag it up to the top textbox. The current hwnd is now focused on the parent.

Revealing Hidden Features by Resizing Forms

Now we know there is another button there...but we don’t know where it is. If you were to just try to make it visible, it wouldn’t help...the button must be outside the visible viewing area of the form.

The creator must be dynamically modifying the form size to hide/show options available to certain user groups. Ok, So we need to resize the form somehow. Can this be done?

Sure, go back to the sendmessage dialog and look at the bottom most pane with the MoveWindow button. Fill out the settings as you see in the picture below and hit the button.

Note: The customer balance form was meant to be non-resizable but I forgot to set that option when I compiled the app. At this point it is to late to recompile because it would change all of my offsets in my screenshots. So just pretend you cannot resize the window through normal means.


White Collar Cracking - Business Apps Bypass Login

Introduction

As more and more systems and processes turn to electronic storage and database driven tracking systems we find our selves in love with the new efficient, concise data access that brings with it.

Most of today’s businesses will be using custom developed Business Apps in some way to help them manage their clients, orders, accounts etc. Indeed there is an entire segment of the consulting market geared towards providing clients with custom data access front ends.

These consulting firms are generally filled with developers who are good multitaskers. Switching from client jobs on a dime and having to learn and manage a host of programmatic tasks from web design to windows desktop development.

Visual Basic is one of the most widely used RAD (Rapid Application Development) languages in the world, and the frequent weapon on choice for business app developers because of its extremely fast development times and ease of use. For this reason, this paper will focus on VB created business apps. While some of the techniques outline will be VB specific, many will also hold true for applications developed in other languages.

The term "software cracking" is often associated by default with pirated desktop user software. For those not familiar with the term, cracking refers to the act of analyzing a compiled program (no source code available) and manipulating the raw processor commands that make it up to gain extended (or infinite trial versions) or obtaining the use of privileged features. For the focus of this paper, we are going to take this into corporate America and see how these same techniques can be used to gain unauthorized access to privileged software functions in Business Applications.

In conventional software cracking, the typical reward, is gaining the use of some piece of software for general use. Manipulating these raw commands and redefining the logic of compiled programs takes alot of patience, time and skill. In the end there is no real financial gain to fund or justify the effort.

Today we live in the information age, most stored electronically in some form or another. Companies are very protective of their proprietary data. This confidential data is a closely guarded asset, and could be of real financial worth to competitors. Whether we like it or not, our information systems are at risk and we have to analyze and understand each level they can be attacked at.

In this paper, we are going to explore possible attacks against common logic found in a typical business application. In the course of the paper we will outline ways to bypass logins, enabled administrator only functionality and wreak general havoc through cracking techniques.

These techniques are usually highly effective with business applications, because their creators typically have little to no understanding of how their compiled code can be manipulated. If you have sensitive data systems with data intake and reporting applications that run on users desktops, take notice that your propiritary data could be exposed.

To help this paper cross from the realm of conversation to that of practical example, I have created a sample business app in Visual Basic 6 where you can examine, test, and see the results of these attacks directly for yourself.

This application is a order intake, tracking, and billing application modeled around common logic and programming techniques. There are 3 user levels.

1) Data Intake - only has access to adding and viewing orders 2) Accounting - access to add & view orders + handle accounts paid and credit 3) Administrator - full access + ability to grant logins and change passwords.

All of these functions are available within the same application. Privileges are managed through a handful of common techniques such as disabled menu items, disabled buttons, hidden form elements etc.

When you first login to the system, your credentials are verified and your group privileges are established that will be used throughout the rest of the application.


White Collar Cracking - Business Apps Bypass Login

Section 2 - Bypassing the login

  • Database security
  • Query Manipulation - Null Byte String Truncation
  • Debugging and Byte Patching

Database Security

When an attacker first comes to the application, they will need to gain primary access. Lets assume a condition where the attacker is in after hours or does not have a valid login of his own. The first level of security comes with how much it takes just to gain access to the rest of the application.

There are many login and authentication schemes available. Our sample application uses a simple portable small business scheme based around data stored in an access database.

In order to provide a portable demonstration for these and other techniques, I was forced to use an Access database. As we will see shortly, that is a poor choice for sensitive data.

If the computer we are working on has Access installed, we could actually just open up the database and see what all the user names and passwords were.

In our example the Access database does not have a password required to open it, however even if it had, it would provide little to no real security for the database.

There are many programs on the market, and even open source code available on the internet to crack Accesses weak authentication scheme. Even if the attacker was unable to open the database, they could open it in a hex editor and search for table and field names which appear unencrypted.

The above concerns all have the precondition of physical access to the database and are commonly understood security factors. In this next section we are going to begin to look at what can be done with only physical access to the application.

The login mechanism of our sample app first connects to the database and then compares our login values to the usernames and passwords found in a users table.

If the username/password combination is found it loads the usergroup into a global variable and loads the main form. If a correct username and password is not given then it will alert them of an invalid login and again prompt for valid credentials.

The next level of attack we are going to look at comes through the use of cracking techniques. That is binary analysis and manipulation of the compiled executable.

Query Manipulation - Null Byte String Truncation

Since our authentication model stores the users in the database, our Visual Basic code must first open a connection to verify the login information. In this classic example, our developers have chosen to implement application layer security controls rather than information layer security controls.

Because all application security is handled with code running on our local machine, and because we have physical access to the executable, we have the power to explore the application as it runs and manipulate the code as it executes.

The first bypass we are going to discuss is actually very simple. As we step through the application code in our debugger we can make out the SQL statement used to query the database with the username and password we supplied. In Visual Basic it looks like this:

    "Select * from tblUsers where " & _
       "username='" & txtUserName & "' And " & _
       "password='" & txtPassword & "'"
Another thing we can see in the debugger is where these strings are loaded from. All of the strings we see in the app are plainly readable in the executable in the form of unicode strings compiled in as data in the executable file. The first fragment to be loaded for this sql statement is "Select * from tblUsers where " which is located at offset 5C74.

We can see from the SQL syntax that if either the password or username does not match no records will be returned. The developer will then test this condition. If no records are found in the recordset, then its an invalid login. Since username/ password pairs have to be unique, only one record could be returned for a successful login thus identifying the user.

But here’s the catch...we know how the sql query string is built up and from where. The thing that limits the result of the query is that where clause that gets appended onto it with our values from the textboxes.

If we say...replace the space just before "where" with a null character what will happen then?

In C and many other programming languages the end of a string is denoted by the presence of the first null character found. Visual Basic does not have this limitation because it uses an OLE type to hold its strings, so VB can contain embedded nulls with out a problem.

It happily uses the modified string, appends on the username and password just as it was designed to do then hands the query off to the database engine to return the recordset.

The catch is, the database engines are not written in VB, they locate the length of the strings passed to them by the occurrence of the null terminator, which in our case, now truncates our sql query to be "Select * from tblUsers" which will always return a result set.

You can try this for yourself by starting up PatchManager.exe and selecting the first Sql Null char truncation sample and hitting Patch & startup button. After the binary is patched, it will execute for you and you will be able to login with any username and password you want.

This may sound like alot of work...but really this much can be accomplished in under 5 minutes by a skilled hand.

Lets say I knew a users login and I wanted to login as them but did not know thier password. This could also be readily accomplished by changing the space before "And" to a null in effect limiting the results to just checking for a valid username.

If we knew there was an account named admin, we could now login with his privledge level without having his password. Try the second Sql truncation demo from the patch manager with user "admin" and see for yourself.

Debugging and Byte Patching

The next manipulation is more of a classic example of cracking and actual command modifications. Above, we didn’t really change the logic of the program flow, just exploited some knowledge of how languages handle string manipulation.

After the standard Sql query is made, the recordset either contains a record, or it doesn’t. If not, then its an invalid login. In the end...this comes down to one processor command. Valid? go on, Invalid? Stop and warn

Because of the unique string used for the message box warning, it is actually extremely simple to locate this processor command. Running the executable through a debugger you you can find the go-nogo command very easily by just scrolling up from the API call for the messagebox.

The debug window shown above lists the raw assembler commands that make up the executable. For vb developers, this view of their application is worlds away from they see and write. The top line highlighted you see the conditional jump that will bypass the failed login message if there were no records returned from the query.

What if this conditional jump was turned into an unconditional one thus making any login, good or bad goto the login verified code instead?

Such a manipulation is trivial and can be made right in the debugger.

If you tried it out, you will find that the program now crashes unexpectedly on us with some recordset related error. Ok, so this isn’t quite as easy as it could be. Apparently because it takes a filled recordset to bypass the failed login message, some results from that recordset are also being used to load variables to determine user privilege level or something.

For some application code, just simply switching the kind of jump that is taken will lead to immediate results. Such would be the result in a simpler case where there was just a test like

if userGroup <> Administrator then
    Msgbox "You do not have permission to perform this action"
    exit sub
else
    'do some privileged stuff
end if
As for our login example...Is this a stumbling block? yes, Does it put us out of the game? No. With some time and experimentation we could look through the disassembly and try to make sense of what was going on. In our case, to bypass the login using this technique, we have to not only modify the type of jump that is executed, we also have to modify the address it takes us to.

We know it does some recordset manipulations that are messing us up but don’t really know what its trying to do. A logical assumption would be that its trying to get some information for our user level to use through out the rest of the program.

Going back to our debugger, we stop execution to right after our patched jump occurs. With out really having to know to much of what is going we can look at what calls to the VB runtime and what strings are being used.

We see the string "group" being loaded. If we find its string offset and change its name, and let it run then we get a new error about not being to find that field in the recordset. So we know the error has to do with recordset manipulation trying to access the group the logged in user is from.

If we scroll down a ways in the debug window we see this

You dont really have to understand assembler to see what is going on, Look at the names of the highlighted VB runtime calls. We can see that some object is being accessed, then freed, then finally at the bottom a new object is being created with a couple arguments (the two pushs before the call to _vbaNew)

We cant know for sure, but its a good shot in the dark to try to just jump directly to where the grey highlighted line where it is preparing for the _vbaNew function call. At this point in the code the recordset looks like it has been disposed of, and something new is happening. What we are hoping is hat we aren’t jumping over any critical initialization code, and that a default value for whatever usergroup variable there is valid.

Going back to the place where we patched our jump, we now change the address it jumps to to be our new location of 40AD6A. Running the program again and hey were in.

If you would like to try this patch for yourself fire up the PatchManager program and select the first option and hit patch it. You will now be able to login with any username and password combination with the default level privledges.

Because of the extra guess work and fishing we had to do to dodge the subsequent recordset query, we got kind of lucky. Had the post jump code been much more complex bypassing the login with this method could have become a very very arduous task. As is, figuring out where to make it jump to bypass the recordset took me on the order of an hour or so with trying to play with a couple different techniques to get through it. (what I really wanted to do was to insert my own error handler into the function mais c'est la vie oui?)