There are many things that can be automated in security testing, with the goal of freeing up time to perform manual analysis of interesting areas (or for pub lunches or playing pool etc.) Fuzzing is a great example of this - you leave the fuzzer crunching away while you review the source code or disassembly.
But fuzzing is just part of the work that needs to be done. If I have some downtime between consultancy gigs and I decide to do some bug hunting, I have to first choose a product that I think will have some interesting components, then I have to install it, then I have to do a quick informal analysis of its attack surface, then I have to attack it. I have been thinking for a while about how we can automate these other areas:
- Target selection. This really depends on what sort of technologies you are interested in testing, e.g. if I've created a new file format fuzzer, I'll want to test it out on some client side apps. Similarly, if I'm looking researching RPC, I'd favour server side apps. We can therefore choose a target by ranking various technologies and performing some pre-installation analysis of the product - does it install a system service? Does it install a driver? Does it register a protocol handler? And so on (there are many, many more we could use).
- Installation. This is normally easy to script - we can fire up a clean VM and silently install our target app into it. Depending on the app, we might have to configure some settings manually, and we probably want to be running standard tools such as Filemon/Regmon/Procmon so we know exactly what is installed.
- Testing. If we knew in advance or at least at runtime, what technologies the application installed we could set up specific fuzzers, e.g. if we know it registers handlers for certain filetypes we might automate retrieving some sample files from our zoo of interesting test cases, or if its an unknown filetype to us, from Google.
Further thinking on the above lead me to consider what types of vulnerability can we easily spot without even installing the product - i.e. just from an analysis of the install files. I say "easily" spot, since you could argue that we could just perform static analysis of the application binaries to find bugs with no need for any dynamic analysis! I am interested in looking for specific issues or classes of issue that can be spotted from simple analysis of the install files. I will leave the discussion of installation time issues (such as this) for another day.
Installers for enterprise level software typically use Windows Installer or InstallShield. Much of the discussion that follows is focused on MSIs, the file format of the Windows Installer. An MSI file is essentially a database inside a structured storage document. The database holds information about what needs to be done - which keys need to be put in the registry, which files need to be unpacked and where, which drivers need to be installed and so on. The MSI API provided within the platform SDK has functions for creating, opening, querying and updating databases. The query language is SQL. Perhaps the easiest way of investigating an MSI is with Orca (if you view an MSI with a structured storage viewer such as SSView, the stream names will appear corrupt, although you will no doubt recognise some of the content of the streams themselves as CAB files - more on this later).
Orca a command line and GUI-based tool for viewing and modifying MSI table data. It is included with the Windows SDK Components for Windows Installer Developers but can be found elsewhere if you don't feel like downloading 300mb to get it :)
Orca, examining the File table
Let's take a quick look at one of the interesting tables. The rest of them are documented here.
- LockPermissions - The LockPermissions table deals with ACLs. MSDN states "it can be used to secure individual portions of an application in a locked-down environment. It can be used with the installation of files, registry keys, and created folders." However note that it can be used to set any required ACLs on a resources - i.e. it can be used to set a weak ACL on a shared resource, and used incorrectly, can introduce vulnerabilities.
Now lets look at a real world example. In August 2007 Dominic Beecher, a colleague of mine at NGS, released a privilege escalation advisory in the Cisco VPN client. Versions prior to 5.0.01.0600 set an ACE that allowed interactive users to modify files in the installation directory, easily detectable from cacls.exe or accesschk.exe: AccessChk v2.0 - Check account access of files, registry keys or servicesCopyright (C) 2006 Mark Russinovich Sysinternals -http://www.sysinternals.com/
C\Program Files>accesschk -d -s -w "NT AUTHORITY\INTERACTIVE" .
RW C:\Program Files\Cisco Systems\VPN Client\
RW C:\Program Files\Cisco Systems\VPN Client\accessible\
RW C:\Program Files\Cisco Systems\VPN Client\Help\
RW C:\Program Files\Cisco Systems\VPN Client\include\
RW C:\Program Files\Cisco Systems\VPN Client\Languages\
RW C:\Program Files\Cisco Systems\VPN Client\Resources\
RW C:\Program Files\Cisco Systems\VPN Client\search\
RW C:\Program Files\Cisco Systems\VPN Client\Setup\
RW C:\Program Files\Cisco Systems\VPN Client\shared\
AccessChk v2.0 - Check account access of files, registry keys or servicesCopyright (C) 2006 Mark Russinovich Sysinternals -http://www.sysinternals.com/
Based on our discussion of the LockPermissions table above, you might expect to see a entry in this table for the installation directory, but if you open up a vulnerable version of the client MSI (e.g. vpnclient-win-msi-4.8.02.0010-k9.exe) in Orca, you won't find one. How does the installer set this ACE? Before we solve this, lets consider the InstallShield way of doing things.
InstallShield stores installation data in script files which have the extension INS prior to version 6, and INX post v6. There are many tools to decompile these files; the two most widespread seem to be isDcc and Sid. I was browsing some sample InstallShield code here and noticed two samples for setting ACLs. The first builds an ACL then calls the standard Win32 API, SetNamedSecurityInfo. This is a lot of work compared to the second solution, which simply calls cacls.exe to do the heavy lifting. With this in mind, lets see how the InstallShield version of a vulnerable Cisco VPN client does things (vpnclient-win-is-4.8.02.0010-k9.exe):
@0000D71F:0006 local_string2 = local_string1;
@0000D729:0021 LongPathToQuote(local_string2, 1);
@0000D737:0007 local_string2 = (local_string2 + " /t /e /g \"NT AUTHORITY\\INTERACTIVE\":C");
@0000D76A:0021 function_264("cacls.exe", local_string2, -1);
If you trace this fragment back a little in the decompiled script you'll find it assigns the installation directory to a global string and calls a function that executes this code.
So back to the MSI, now we have a big clue. Could it be that this particular MSI also calls cacls.exe? Searching in Orca for cacls.exe proves this is the case. The CustomAction table contains the entry:
CsCaExe_SetVpnClientFolderACL 3170 SystemFolder cacls.exe "[INSTALLDIR]." /t /e /g "NT AUTHORITY\INTERACTIVE":C
et voilà. The MSI API is very simple to use, so its easy to knock up a tool that scans for interesting LockPermissions entries and scans CustomAction for any exes that are launched, paying particular attention to cacls.exe entries.
There are several other vulnerabilities we can potentially detect prior to installation:
- Service password if hardcoded. Interestingly, the ServiceInstall table has a password column, from MSDN:
"This string is the password to the account name specified in the StartName column. Note that the user must have permissions to log on as a service. The service has no password if StartName is null or an empty string. The Startname of LocalSystem is null, and therefore the password in this instance is null, so most services leave this column blank."
- Outdated, vulnerable versions of common libraries such as Zlib, OpenSSL, LibCurl and so on.
A note on extracting files from MSIs - if all you want to do is check the file version, it may not be necessary to extract it - check the Version field of the File table first. If you do need to extract the file, there are many tools out there that can do this. The basic premise is to look up the target file's Sequence in the File table then cross-reference this with LastSequence column in the Media table to get the CAB file name. If the CAB file name starts with '#' then this indicates it's stored as a stream inside the MSI (remember its a structured storage document). The last thing to add is that if you go looking for a stream name corresponding to the CAB name, you'll be out of luck. The stream name is an encoded version of the CAB name. My advice for anyone intending roll their own file extraction code is to take a look at the Wine MSI implementation first, this will hopefully save you some time.
Of course, once you get into performing static analysis of the application binaries themselves there are many more issues you can alert on reasonably easily such as service binaries with RPC interfaces without security callbacks, drivers with calls to IoCreateDeviceSecure with permissive SDDL strings and so on. These could form the basis of a nifty attack surface analysis tool... which I have done some initial work on. If anyone is interested in taking this further, or has additional vulnerabilities we can spot pre-installation, get in touch.