Fat client applications running on (usually) Windows are still extremely common in enterprises. When I look at internal penetration tests or red team engagements for any larger enterprise, it is almost 100% guaranteed that one will stumble upon such an application.
These fat client applications have also usually been originally written many, many years ago, when security was maybe not one of the primary requirements. Whenever one encounters such a fat client application, or if this is perhaps part of your penetration test, one of the primary goals is to analyze how the application communicates with the rest of the world (or, usually, other internal systems).
While modern applications that you might encounter will most of the time consume some web services (usually SOAP, but I can see modern RESTful interfaces being consumed more and more), “traditional” fat client applications will most of the time connect directly to a database (again, since we’re looking at Windows environment primarily here, this will be most of the time a Microsoft SQL Server database). Such setup will appear quite simple and is shown in the following figure:
The first step in identifying such an application will usually be to inspect its network traffic. In 99% of cases, this will be trivial to perform by using a tool such as Wireshark. This will allow not only to identify the target MS SQL Server, but also to inspect traffic on the wire. We will be looking for any traffic with destination TCP port set to 1433.
Again, due to the age of such applications, in almost every case I worked on, the data on the wire is most of the time sent in plain text, without any encryption. This is, obviously, very bad as we could easily perform a MitM attack (see more below), but the TDS protocol will, luckily, have one step encrypted: authentication.
SQL Server Authentication
Microsoft SQL server supports two authentication types: the builtin Windows authentication as well as SQL Server authentication. This second authentication mechanism is interesting to us, and is used by majority of fat client applications (at least those that I tested).
The workflow will look like this:
The fat client application will use a single (usually quite powerful) account to login to the MS SQL database server, using the SQL Server authentication protocol
Now the end user will be required to authenticate locally by the fat client application (this is usually a login screen displayed by the fat client application)
The fat client application will verify if the entered username/password pair is correct (again, by checking something in the database)
If everything goes well, the user has been authenticated and the fat client application will display the corresponding GUI
You can probably already see a critical step here – that single account used by the fat client application to login to the MS SQL database server.
This must be heavily guarded – I’ve seen examples of when these credentials were stored in a plain text configuration file or registry, but also cases when they were encrypted, and the encryption algorithm was heavily obfuscated (Borland – I’m looking at you).
Of course, for an attacker, getting these credentials is one of their primary goals since they will usually allow full access over the database, as well as potential lateral movement by exploiting the target systems further.
So how do we get the username and password, if they are encrypted in configuration? If we just monitor network traffic, they will still not be visible as modern SQL Server databases will encrypt the authentication exchange (see above), no matter if the rest of encryption is turned off. In other words, we can see SQL queries after authentication, but we will not be able to see the exchanged username and password, which means that we must dig deeper.
As the authentication part will be encrypted, we will want to somehow obtain this information in plain text (or whatever it is, as we will see later). There are couple of ways to do this, and here are my favorite methods.
Depending on the application, sometimes the easiest way will be to inject into the fat client application and monitor data before it’s being passed for encryption. There are several tools that you can use for this, that will require more or less experience:
Frida (https://frida.re/) is a very powerful dynamic instrumentation toolkit that will allow you to instrument almost anything in the target application. It’s very popular in mobile application penetration testing but we can use it here as well.
Echo Mirage – the original tool that will allow you to hook SSL/TLS libraries and inspect network traffic before it’s being encrypted (for outgoing traffic), and after it’s being decrypted (for incoming traffic). I still tend to use this tool quite a bit as it simply works, even on the latest Windows (despite being 20 years old).
Hallucinate (https://github.com/SySS-Research/hallucinate/), a tool originally based on Echo Mirage and Frida, that might be more stable.
Besides this, we might also run a MitM attack on the network; if there is no certificate pinning in the fat client application, our tool of choice will usually be mitmproxy (https://mitmproxy.org/), where I suggest that you check the mitmdump command line interface and the Wireguard mode.
No matter which of the tools above is used, our goal will be to capture username/password pair when the fat client application is authenticating with the target MS SQL database. And if succeeded in that, we might be a bit disappointed – even after defeating network encryption, the password is still not passed in plain-text and we might see something like this:
plaintextusername 0x00 A2A5B3A592A592A5D2A553A582A5E3A5 0x00
Defeating 20-year-old obfuscation
The highlighted bytes above probably contain password, but it’s indeed not in plaintext. That being said, it looks like this is not encryption but some obfuscation – notice how certain bytes (0xA5) appear quite often.
20 years ago David Litchfield, a great researcher (hands up if you’ve been on the Bugtraq mailing list back then) published a paper detailing how this obfuscation works. There was a small bug there that was corrected and it’s remarkable that the same algorithm is still used today (talk about backward compatibility). So what MS SQL Server will do with a password is the following:
Convert the password to the Unicode character set; this will result in “extending” an ASCII password with null bytes (0x00)
Swap the upper and lower nibble (4 bits) of every byte
XOR every byte with 0xA5
Not too difficult, right? With this in mind, we can easily take the obfuscated password we retrieved on the wire and decode it. I wrote a very simple Python script to do that, which is available at https://github.com/bojanisc/SQLAuthDecrypt, let’s try it:
Enter encrypted password: A2A5B3A592A592A5D2A553A582A5E3A5
Decrypted password: password
Nice! We got the plaintext password of the main account used by our fat client application. Now it’s time to try to perform some lateral movement, perhaps beginning with utilizing xp_cmdshell.
Finally, how do we prevent this? Well, one solution is easy – do not use SQL Server authentication but instead have users use their Windows credentials for authentication. This will open a can of worms with the application shown above as it would require the application to probably be re-engineered a lot – and I guess that this is one of the reasons why we still see these vulnerabilities, 20 years after they have been published.
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.