pyHarvest SMB

This module crawls a given SMB server and provides the following options (parameter dependent):

  • list all fileshares available
  • start crawling from given directory
  • lists contents (file name, size, date, etc)
  • recursive or limited to current directory
  • downloads contents using filters on:
    • size limit (TBD)
    • file name (TBD)
    • directory name (TBD)
    • hierarchy level/limit max depth (TBD)

I am not a programmer in any ways, so the scripts below are pretty ugly, but it serves the purpose they meant to do for me. Please feel free to use or modify them as needed. Any feedback also appreciated (info@ domain of this website). 

GitHub resource containing source code:

https://github.com/bl305/pyHarvest

Program code:

#!/usr/bin/env python
# coding=utf-8
 
####
#TODO
#skipdirs
#sizelimit
#permissions
####
 
from smb.SMBConnection import SMBConnection
import time
import os
import errno
import socket
#from datetime import datetime
#import re
#from StringIO import StringIO
 
def convert_to_unicode(string):
 
    if not isinstance(string, unicode):
        string = unicode(string, "utf-8")
    return string
 
 
#######PARAMETERS
#	SMBusername='user1'
#	SMBusername=convert_to_unicode(SMBusername)
#	#in main
#	#SMBpassword='Asdf1234'
#	#SMBpassword = raw_input('password:')
#	#SMBpassword=convert_to_unicode(SMBpassword)
#	#SMBremotesystem = 'FileServer'
#	SMBremotesystem = 'REMOTESERVER'
#	SMBremotesystem=convert_to_unicode(SMBremotesystem)
#	SMBremoteip = '127.0.0.1'
#	SMBremoteip=convert_to_unicode(SMBremoteip)
#	#SMBlocalsystem='LOCALHOSTNAME'
#	SMBlocalsystem = socket.gethostname()
#	SMBlocalsystem=convert_to_unicode(SMBlocalsystem)
#	#SMBdomain='WORKGROUP'
#	SMBmydomain=convert_to_unicode(SMBdomain)
#	SMBfileshare='TestShare'
#	SMBfileshare=convert_to_unicode(SMBfileshare)
#	SMBoutdir="./DataGathered/SMB/"
#	SMBoutdir=convert_to_unicode(SMBoutdir)
#	SMBtop="/"
#	SMBtop=convert_to_unicode(SMBtop)
#	SMBtop=os.path.normpath(SMBtop).replace('//','/')
#	#if you want to find all shares and use them set this to 1, else the myfileshare will be used
#	SMBgetshares=0
#
#	#create empty directories?
#	SMBcreateemptydirs=0
#
#	#download files?
#	SMBdownloadfiles=1
#
#	#set verbosity
#	#-1 - no messages
#	#0 - tuple of results
#	#1 - summary information
#	#2 - basic information, positive info
#	#3 - detailed information, positive, negative
#	#4 - go crazy about it...
#	SMBverbosity=1
 
def smb_connect(username,password,localsystem,remotesystem,remoteIP,domain,averbosity=0):
	try:
		if averbosity>=1:
			print '[+] Analyzing system: ', remotesystem
		# parameterize an smb connection with a system
		conn = SMBConnection(username,
			password,
			localsystem,
			remotesystem,
			domain,
			use_ntlm_v2=True,
#this kills it			sign_options=SMBConnection.SIGN_WHEN_SUPPORTED,
			is_direct_tcp=True)
 
		# establish the actual connection
		connected = conn.connect(remoteIP,445)
 
		if connected:
			if averbosity>=2:
				print "[+] Connected"
		else:
			if averbosity>=3:
				print "[-] Connection failed"
				exit(1)
		return conn
	except Exception, e:
		if averbosity>=3:
			print('[-] Can not access the system')
		if averbosity>=4:
			print('[-] Can not access the system'),e
		#exit(2)
 
#this doesn't work for some reason...
def smb_list_shares(conn,aremotesystem,averbosity=0):
	if averbosity>=2:
		print '[+] Shares on: ', aremotesystem
	try:
		Response = conn.listShares(timeout=30)  # obtain a list of shares
 
		#for i in range(len(Response)):  # iterate through the list of shares
		#	print Response[i].name
		return tuple(Response)
	except Exception, e:
		if averbosity>=3:
			print('[-] Can not list shares')
		if averbosity>=4:
			print('[-] Can not list shares'),e
 
def smb_list_subfolders(conn,aremotesystem,ashare,apath,averbosity=0):
	if averbosity>=2:
		print "[+] Listing subfolders in share:\"%s\" folder: \"%s\""%(ashare,apath)
	try:
		Response = conn.listPath(ashare,apath,timeout=30)
 
		for i in range(len(Response)):
			filename=Response[i].filename
			fileisdir=Response[i].isDirectory
			filetype=""
			filecreatetime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(Response[i].create_time))
			fileattributes=Response[i].file_attributes
			fileallocsize=Response[i].alloc_size
			filesize=Response[i].file_size
			isreadonly=Response[i].isReadOnly
			lastaccesstime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(Response[i].last_access_time))
			filelastattrchangetime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(Response[i].last_attr_change_time))
			filelastwritetime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(Response[i].last_write_time))
			if filename == ".":
				pass
			elif filename == "..":
				pass
			else:
				newpath=os.path.join(apath,filename)
				newpath=os.path.normpath(newpath).replace('//','/')
				if averbosity>=4:
					print newpath
				if fileisdir:
					#print "DIR: ",filename
					filetype="d"
					for i in smb_list_subfolders(conn,aremotesystem,ashare,newpath):
						yield i
				else:
					filetype="f"
					#print "FIL: ",filename
					pass
				newfile=(ashare,apath,filename,filetype,filesize,filecreatetime,fileattributes,fileallocsize,isreadonly,lastaccesstime,filelastattrchangetime,filelastwritetime)
				yield newfile
	except Exception,e:
		if averbosity>=3:
			print '[-] Can not access the resource %s%s'% (ashare,apath)
		if averbosity>=4:
			print '[-] Can not access the resource %s%s%s'% (ashare,apath,e)
		pass
 
def smb_get_file(conn, remotesystem,filename,aoutdir,averbosity=0):
	apath = os.path.join(aoutdir,remotesystem)
	abspath=apath+filename
	abspath = os.path.normpath(abspath).replace('//','/')
	xpath, xfilename = os.path.split(filename)
	localdir=apath+xpath
	mycounter1=0
	mycounter2=0
	try:
		if not os.path.exists(localdir):
			os.makedirs(localdir)
			mycounter1+=1
			#print "[+] Creating directory %s" % apath
	except OSError as exception:
		if exception.errno != errno.EEXIST:
			raise
		else:
			#print "[-] Directory already exist %s" % apath
			pass
	try:
		try:
			if averbosity>=2:
				print "[+] Creating local file:",abspath
			temp_fh = open(abspath, 'wb')
		except:
			if averbosity>=3:
				"[-] Could not create local file",abspath
 
		try:
			if averbosity>=3:
				print "[+] Pulling %s"%(abspath)
			file_attributes, filesize = conn.retrieveFile(remotesystem, filename, temp_fh, timeout=30)
			mycounter2+=1
		except:
			if averbosity>=3:
				"[-] Could not retrieve file %s %s",(remotesystem, filename)
 
		temp_fh.close()
		if averbosity>=1:
			print "[+] Got file %s"%abspath
	except Exception,e:
		if averbosity>=3:
			print "[-] Could not create file: %s"%abspath
		if averbosity>=4:
			print "[-] Could not create file: %s %s"%(abspath,e)
	return mycounter1,mycounter2
 
def smb_prepare_dir(remotesystem,abspath):
	mycounter1=0
	try:
		if not os.path.exists(abspath):
			os.makedirs(abspath)
			mycounter1+=1
			#print "[+] Creating directory %s" % path
	except OSError as exception:
		if exception.errno != errno.EEXIST:
			raise
		else:
			#print "[-] Directory already exist %s" % path
			pass
	return mycounter1
 
def smb_main(ausername,apassword,alocalsystem,aremotesystem,aremoteip,adomain,afileshare,atop,aoutdir,adownloadfiles=1,acreateemptydirs=0,agetshares=0,averbosity=0):
 
	if averbosity>=1:
		#print summary:
		print "Server             :",aremotesystem
		print "File Share         :",afileshare
		print "Skipped directories: TBD"
		print "Skipped files      : TBD"
		print "Maximum depth      : TBD"
		print "Max filesize       : TBD"
 
 
	myconn=smb_connect(ausername,apassword,alocalsystem,aremotesystem,aremoteip,adomain)
	#this will be populated based on the agetshares parameter
	shares=()
	if agetshares == 1:
		allshares = smb_list_shares(myconn,aremotesystem)
		for i1 in range(len(allshares)):
			shares+=(allshares[i1].name),
			if averbosity>=4:
				print "[+] Shares in server:",allshares[i1].name
	else:
		if averbosity>=4:
			print "[+] Shares in server:",fileshare
		shares=(afileshare),
 
	allitems=()
	fcount=0
	dcount=0
	dnum1=0
	fnum2=0
	dnum2=0
 
	for a1 in range(len(shares)):
		if averbosity>=4:
			print shares[a1]
 
		for i in smb_list_subfolders(myconn,aremotesystem,shares[a1],atop):
			item=os.path.join(aoutdir+"/"+i[0]+"/"+i[1],i[2])
			item=os.path.normpath(item).replace('//','/')
			fileitem=os.path.join(i[1],i[2]).replace('//','/')
			if i[3] == "d":
				dcount+=1
				if acreateemptydirs==1:
					dnum1+=smb_prepare_dir(aremotesystem,item)
				if averbosity>=4:
					print "DIR: %s"%item
			elif i[3] == "f":
				fcount+=1
				if averbosity>=4:
					print "FIL: %s %s"%(i[0],fileitem)
				if adownloadfiles==1:
					dnumTMP,fnumTMP=smb_get_file(myconn, i[0],fileitem,aoutdir)
					dnum2+=dnumTMP
					fnum2+=fnumTMP
				if averbosity>=4:
					print "(%s) %s%s%s (%s) (%s) (%s) (%s) (%s) (%s) (%s) (%s)"%(i[3],i[0],i[1],i[2],i[4],i[5],i[6],i[7],i[8],i[9],i[10],i[11])
			allitems+=(i[0],i[1],i[2],i[3],i[4],i[5],i[6],i[7],i[8],i[9],i[10],i[11],'','','','',aoutdir),
			pass
	if averbosity==0:
		print allitems
 
	if averbosity>=1:
		print "Found %d directories and %d files"%(dcount,fcount)
		print "Created %d directories using directory downloader (absolute path)"%(dnum1)    
		print "Created %d directories (absolute path) and %d files (if existed, overwritten)"%(dnum2,fnum2)
 
	myconn.close()
	return allitems