misql.py: A Cuckoo Package for MySQL Commands
#######################################################################
# Cuckoo Sandbox (v0.4.2) package to monitor the MySQL server process #
# while connecting to it and issuing SQL commands from a given file #
# #
# misql.py v2012.12.09 #
# http://malwaremusings.com/scripts/misql-py/ #
#######################################################################
###
# imports
###
from lib.common.abstracts import Package
from lib.api.process import Process
from lib.common.exceptions import CuckooError
import os
import socket
try:
import mysql.connector
except Exception as e:
raise CuckooError("my.py failed to import mysql.connector: " + e.message)
###
# subclass of Cuckoo's Package class so that Cuckoo can call us
###
class Misql(Package):
"""MySQL analysis package."""
###
# configuration variables
###
mysqldpid = "C:\\Documents and Settings\\All Users\\Application Data\\MySQL\\MySQL Server 5.5\\data\\" + socket.gethostname() + ".pid"
mysqldexe = "C:\\Program Files\\MySQL\\MySQL Server 5.5\\bin\\mysqld.exe"
mysqldini = "C:\\Documents and Settings\\All Users\\Application Data\\MySQL\\MySQL Server 5.5\\my.ini"
mysqldbuser = "<mysqldbuser>"
mysqldbpass = "<mysqldbpassword>"
procmon = "C:\\processmonitor\\procmon.exe"
procmonfile = "C:\\cuckoo\\logs\\events"
misqllog = "C:\\cuckoo\\logs\\misql.log"
###
# class global variables
###
logfile = None
###
# doqry(): submit a MySQL query and print out the results
# The results must be read otherwise the server won't accept next query
###
def doqry(self,connection,query):
self.logfile.write("Q: %s" % query)
try:
result = connection.cmd_query(query)
if 'columns' in result:
done = False
while (not done):
(row,status) = connection.get_row()
if (row != None):
for col in range(0,len(row)):
self.logfile.write(row[col] + "\t")
self.logfile.write("\n")
done = (row == None)
except mysql.connector.errors.ProgrammingError as pe:
self.logfile.write("ProgrammingError: %s\n" % pe.msg)
except mysql.connector.errors.DatabaseError as de:
self.logfile.write("DatabaseError: %s\n" % de.msg)
except Exception as e:
self.logfile.write("Exception: %s\n" % e.message)
###
# start(): method called by Cuckoo to start the process(es) of interest
###
def start(self, path):
self.logfile = open(self.misqllog,"w")
#
# check for mysqld pid file
#
try:
pidfile = open(self.mysqldpid,"r")
pidstr = pidfile.read()
pid = int(pidstr)
self.logfile.write("MySQL server pid: %d\n" % pid)
except IOError as ioe:
# unable to determine PID of mysqld
self.logfile.write("Unable to determine MySQL server pid\n")
pid = 0
#
# if we didn't find a pid file, then start mysqld
#
if (pid == 0):
self.logfile.write("Starting MySQL server... ")
p = Process()
ok = p.execute(path = self.mysqldexe,args = "--defaults-file=\"" + self.mysqldini + "\"",suspended = False)
self.logfile.write("%s\n" % ok)
else:
p = Process(pid = pid)
#
# start process monitor
# use the 'start' command to run it in the background
#
os.system('start ' + self.procmon + ' /BackingFile ' + self.procmonfile + '.pml /AcceptEula /Minimized')
#
# inject the cuckoomon.dll so that Cuckoo can monitor it
# note that the Process.inject() method has to be modified
# so that it passes an absolute path to LoadLibrary() and
# not a relative path
#
self.logfile.write("Injecting DLL... ")
injectstat = p.inject()
self.logfile.write("%s\n" % injectstat)
#
# open the file of SQL commands
#
self.logfile.write("Opening SQL command file: %s... " % path)
sqlcmdfile = open(path,"r")
self.logfile.write("done\n")
#
# connect to MySQL server and send commands
#
self.logfile.write("Connecting to MySQL server... ")
try:
#
# establish a connection to the MySQL server on localhost
#
c = mysql.connector.connect(user = self.mysqldbuser,password = self.mysqldbpass)
#
# read one command per line and send it to the SQL server
#
self.logfile.write("done\nSending SQL commands:")
for line in sqlcmdfile:
self.doqry(c,line)
self.logfile.write("done\n")
#
# close the MySQL connection
#
c.close()
except Exception as e:
self.logfile.write("%s\n" % e.message)
#
# close SQL command file and our logfile
#
sqlcmdfile.close()
self.logfile.close()
#
# we're done
#
return p.pid
###
# check(): Method periodically called by Cuckoo, to see if it should stop the guest
###
def check(self):
return True
###
# finish(): Method called by Cuckoo to notify us that it is shutting down the guest
###
def finish(self):
os.system(self.procmon + ' /Terminate')
os.system('if exist ' + self.procmonfile + '.pml ' + self.procmon + ' /OpenLog ' + self.procmonfile + '.pml /SaveAs ' + self.procmonfile + '.csv')
return True