Saturday, 14 January 2012

Hacking MS Access for fun and profit

Once you realise that hacking isn't a black art - that's it's simply about knowing your subject matter - it becomes frighteningly easy but no less fun.

I spent a great many years of my early career making amazing things with MS Access databases and VBA.  I've lost most of these skills nowadays, but I remember a lot about how things are constructed internally and how I used to go about securing things.

And it turns our that this knowledge is pretty useful in figuring out how to un-secure things.

There's a database that I needed access to.  One table, actually.  A table that I needed to keep my team running, that I'd had access to for 3 years previous and that I'd only had access removed because a new contractor came in and decided that he wanted to build himself an empire.  And an ego.

Not to be a complete killjoy, he provides everyone with locked down versions of his new database front end that they can use to access the tables he's created for us.  To summarise, he's removed some essential functionality and added nothing.  Thanks for that.

I decided that I would have a sniff around.

Firstly, he'd disabled the shift-key bypass restriction.  This is obvious database security for MS Access.  It's also trivially easy to disable.  Most tutorials give you the code to do it within a database to which you have VBA capabilities.  This is the code, taken from here:


Sub EnableShiftKey()
    Dim db As DAO.Database
    Dim prp As DAO.Property
    Set db = CurrentDb
    db.Properties.Delete "AllowBypassKey"
    Set prp = db.CreateProperty("AllowBypassKey", dbBoolean, True, True)
    db.Properties.Append prp
    db.Properties.Refresh
    Set prp = Nothing
    Set db = Nothing
End Sub


A simple modification (that I haven't seen anywhere else so far) allows you to run this from a database that you own and have access to on a database that you don't.  Here's the modified code:


Sub EnableShiftKey()
    Dim db As DAO.Database
    Dim prp As DAO.Property
    Set db = OpenDatabase ("\\PATH\TO\TARGET\DATABASE.MDB")
    db.Properties.Delete "AllowBypassKey"
    Set prp = db.CreateProperty("AllowBypassKey", dbBoolean, True, True)
    db.Properties.Append prp
    db.Properties.Refresh
    Set prp = Nothing
    Set db = Nothing
End Sub


Simply, we're providing a database path to the OpenDatabase command which returns a remote database as the database object, rather than using CurrentDb, which refers to itself.

So, with the shift-key bypass restriction removed, I could open the database properly and take a look around.

There were some linked tables - including the one I wanted access to, but only 1 local table containing version information.

I decided that since I'd unlocked the database now, I would try to link a table to it.  This was dumb because you can't to a linked table - the only info I could see in the link was the version table.  Try again.

I looked at the link table manager and traced the backend tables to the new location that it had been moved to.  After navigating to this database I tried to open it and access the table that way.  Password protected, obviously.

Since Access 97, passwords on database are no longer trivial to remove, and since we're playing with Access 2007, we have a non-starter.

Back to the front end that I do have access to.

I look in the table that I'm interested in and realise that I can see the information within it.  It's pointing to the backend that I don't have access to, but I can see the data.  The password for the back end must be stored somewhere in this front end that I have...

The Linked Table Manager doesn't tell me anything I don't know - I was hoping for some kind of password option.

I turn on visibility of the System tables and have a look in there.  The table MSysObjects contains a list of all the local and linked objects that the database can see.  Most of the information shown is useless, system level information that doesn't help.  But then I see the path for the backend database at the beginning of a connection string.  I expand the field and find that this actually contains the whole database connection string...including the password for the backend database.