To analyse the cna12 MySQL attacks, I had to install MySQL Express Server as the attacks were prematurely exiting when connecting to Dionaea. Extracting the binary files from the libpcap files was annoying, so I decided to change Dionaea so that it would automatically extract the binary files used in the cna12 attacks.
It was annoying just sitting here knowing that these binary files were actually being downloaded, but not being recognised, logged, and stored. Downloading and logging the binaries would make it easier to see how the cna12 attack binaries were differing from each other and over time.
There is only one file that needs modifying, and that is ./modules/python/scripts/mysql/mysql.py from Dionaea‘s top-level source directory. So this is a unified diff in Python, watch me for the changes, and try to keep up ok? It’s a shame it wasn’t written in C as that would have fit the original quote better.
It is mostly new code, but I did have to change the check for a SET query as the check was case-sensitive and the attack was using set.
I added an import to import the Python tempfile module, to create a temporary file. This temporary file stores the captured binary file before sending it to Dionaea‘s download handlers, and then hangs around to fill up your file system. If the temporary files don’t fill your file system up quickly enough for your liking, you can get the mysql.py module to log the MySQL queries, like I was doing originally (see line 38 of the patch). Needless to say I commented those logging commands out, and the version that I used to create the patch doesn’t use them.
Firstly, I added an autocommit variable and initialised it to 1 in the __init__() function. This is because the attacks were modifying the autocommit setting, and part of the MySQL response packets contain the value of the autocommit setting. I found that the attack failed to continue if I didn’t return the value that it was expecting, and hence I needed to use a variable to keep track of it.
Starting at line 39, we check to see if the MySQL query, after being converted to all upper case characters, starts with the SET command. If it does, we explicitly check to see if it is SET AUTOCOMMIT=0. This was one of the commands that the attack was issuing, which the original Dionaea code wasn’t handling. If it is, then set the autocommit variable accordingly, as we’ll need to reflect this in our MySQL response packets.
If it isn’t the SET AUTOCOMMIT=0 command, lines 48 – 58 convert the query to all lower case characters, strip whitespace (some of the attacks spread the hex encoded data over a few lines), convert the query to a Python string, and then search the query looking for the string 0x4d5a which is a hex encoded (0x) version of the PE file signature (MZ) at the start of a PE file.
If the 0x4d5a string is found, the block of code between lines 61 – 72 uses a while loop to search, after skipping over the initial 0x, for the next non-valid hex character. In these attacks, this will more than likely be a ‘)’ character closing the MySQL concat() function call. The hex characters between the 0x marker and the next non-valid hex character are saved in the variable hexstr and, after creating a temporary file in Dionaea‘s downloads directory, are decoded using the fromhex() method of the built-in Python bytes object and written to the temporary file.
Lines 76 – 80 took some figuring out, as I was having problems finding any documentation about Dionaea‘s incidents. This block of code creates a Dionaea download complete incident, sets its path to the file name of the temporary file, its url to the string hex:// followed by the remote host’s IP address, the con property to the current MySQL connection object, and then calls the incident‘s report() method.
Creating a Dionaea incident means that the decoded file and associated information gets passed to the configured incident handlers. In my case, this causes Dionaea to submit the binary file to my repository, and to log the information to the SURFids database.
Line 82 causes Dionaea to return a successful MySQL status to the MySQL client/attacker.
The block of code between lines 89 – 107 simply handles the SELECT VERSION() command. I implemented this after some trial-and-error experimentation. I kept checking to see how Dionaea‘s response differed from that of a real MySQL server, and worked on it until Dionaea‘s response was good enough to convince the attacks to continue.
Lines 108 – 139 get interesting. This block of code implements a command that the attack was running. These lines look for the SELECT XPDL3() command.which the attack was using to call an exported function in the DLL file that it had just sent in a hex encoded string (which we decoded and saved above).
This block of code looks for the string ‘http: or ‘https:, extracts the URL from between the quotes, and creates a Dionaea download offer incident. A download offer incident causes Dionaea to download the file from the given URL before passing it to the incident handlers.
So there you have it. These Dionaea changes allow you to use Dionaea to capture the different files downloaded using the cna12.dll file that the attacks use. You can then extract connection and download information about MySQL attacks that contain a hex encoded PE file by issuing the following query against Dionaea‘s logsql.sqlite database.
select connections.*,downloads.download_url,downloads.download_md5_hash from downloads, (select connection from downloads where download_url like 'hex://%') as c join connections on connections.connection = downloads.connection and connections.local_port = 3306 where downloads.connection = c.connection;
That query will return connection and download information about any MySQL connection which contained at least one download URL starting with hex:// which, given that the only Dionaea code which uses such URLs is the code that my Dionaea patch added, will match any MySQL connections issuing a MySQL command containing the string 0x4d5a — that is, a hex encoded Windows PE file.