1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168 |
- # Copyright (c) 2003-2016 CORE Security Technologies
- #
- # This software is provided under under a slightly modified version
- # of the Apache Software License. See the accompanying LICENSE file
- # for more information.
- #
- # Author: Alberto Solino (@agsolino)
- #
- # TODO:
- # [-] Functions should return NT error codes
- # [-] Handling errors in all situations, right now it's just raising exceptions.
- # [*] Standard authentication support
- # [ ] Organize the connectionData stuff
- # [*] Add capability to send a bad user ID if the user is not authenticated,
- # right now you can ask for any command without actually being authenticated
- # [ ] PATH TRAVERSALS EVERYWHERE.. BE WARNED!
- # [ ] Check the credentials.. now we're just letting everybody to log in.
- # [ ] Check error situation (now many places assume the right data is coming)
- # [ ] Implement IPC to the main process so the connectionData is on a single place
- # [ ] Hence.. implement locking
- # estamos en la B
- from __future__ import with_statement
- import calendar
- import socket
- import time
- import datetime
- import struct
- import ConfigParser
- import SocketServer
- import threading
- import logging
- import logging.config
- import ntpath
- import os
- import fnmatch
- import errno
- import sys
- import random
- import shutil
- from binascii import hexlify
- # For signing
- from impacket import smb, nmb, ntlm, uuid, LOG
- from impacket import smb3structs as smb2
- from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, ASN1_SUPPORTED_MECH
- from impacket.nt_errors import STATUS_NO_MORE_FILES, STATUS_NETWORK_NAME_DELETED, STATUS_INVALID_PARAMETER, \
- STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \
- STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \
- STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \
- STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS
- # These ones not defined in nt_errors
- STATUS_SMB_BAD_UID = 0x005B0002
- STATUS_SMB_BAD_TID = 0x00050002
- # Utility functions
- # and general functions.
- # There are some common functions that can be accessed from more than one SMB
- # command (or either TRANSACTION). That's why I'm putting them here
- # TODO: Return NT ERROR Codes
- def outputToJohnFormat(challenge, username, domain, lmresponse, ntresponse):
- # We don't want to add a possible failure here, since this is an
- # extra bonus. We try, if it fails, returns nothing
- ret_value = ''
- try:
- if len(ntresponse) > 24:
- # Extended Security - NTLMv2
- ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
- else:
- # NTLMv1
- ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
- except:
- # Let's try w/o decoding Unicode
- try:
- if len(ntresponse) > 24:
- # Extended Security - NTLMv2
- ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
- else:
- # NTLMv1
- ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
- except Exception, e:
- LOG.error("outputToJohnFormat: %s" % e)
- pass
- return ret_value
- def writeJohnOutputToFile(hash_string, hash_version, file_name):
- fn_data = os.path.splitext(file_name)
- if hash_version == "ntlmv2":
- output_filename = fn_data[0] + "_ntlmv2" + fn_data[1]
- else:
- output_filename = fn_data[0] + "_ntlm" + fn_data[1]
- with open(output_filename,"a") as f:
- f.write(hash_string)
- f.write('\n')
- def decodeSMBString( flags, text ):
- if flags & smb.SMB.FLAGS2_UNICODE:
- return text.decode('utf-16le')
- else:
- return text
- def encodeSMBString( flags, text ):
- if flags & smb.SMB.FLAGS2_UNICODE:
- return (text).encode('utf-16le')
- else:
- return text
- def getFileTime(t):
- t *= 10000000
- t += 116444736000000000
- return t
- def getUnixTime(t):
- t -= 116444736000000000
- t /= 10000000
- return t
- def getSMBDate(t):
- # TODO: Fix this :P
- d = datetime.date.fromtimestamp(t)
- year = d.year - 1980
- ret = (year << 8) + (d.month << 4) + d.day
- return ret
- def getSMBTime(t):
- # TODO: Fix this :P
- d = datetime.datetime.fromtimestamp(t)
- return (d.hour << 8) + (d.minute << 4) + d.second
- def getShares(connId, smbServer):
- config = smbServer.getServerConfig()
- sections = config.sections()
- # Remove the global one
- del(sections[sections.index('global')])
- shares = {}
- for i in sections:
- shares[i] = dict(config.items(i))
- return shares
- def searchShare(connId, share, smbServer):
- config = smbServer.getServerConfig()
- if config.has_section(share):
- return dict(config.items(share))
- else:
- return None
- def openFile(path,fileName, accessMode, fileAttributes, openMode):
- fileName = os.path.normpath(fileName.replace('\\','/'))
- errorCode = 0
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- mode = 0
- # Check the Open Mode
- if openMode & 0x10:
- # If the file does not exist, create it.
- mode = os.O_CREAT
- else:
- # If file does not exist, return an error
- if os.path.exists(pathName) is not True:
- errorCode = STATUS_NO_SUCH_FILE
- return 0,mode, pathName, errorCode
- if os.path.isdir(pathName) and (fileAttributes & smb.ATTR_DIRECTORY) == 0:
- # Request to open a normal file and this is actually a directory
- errorCode = STATUS_FILE_IS_A_DIRECTORY
- return 0, mode, pathName, errorCode
- # Check the Access Mode
- if accessMode & 0x7 == 1:
- mode |= os.O_WRONLY
- elif accessMode & 0x7 == 2:
- mode |= os.O_RDWR
- else:
- mode = os.O_RDONLY
- try:
- if sys.platform == 'win32':
- mode |= os.O_BINARY
- fid = os.open(pathName, mode)
- except Exception, e:
- LOG.error("openFile: %s,%s" % (pathName, mode) ,e)
- fid = 0
- errorCode = STATUS_ACCESS_DENIED
- return fid, mode, pathName, errorCode
- def queryFsInformation(path, filename, level=0):
- if isinstance(filename,unicode):
- encoding = 'utf-16le'
- flags = smb.SMB.FLAGS2_UNICODE
- else:
- encoding = 'ascii'
- flags = 0
- fileName = os.path.normpath(filename.replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- fileSize = os.path.getsize(pathName)
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
- if level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO:
- data = smb.SMBQueryFsAttributeInfo()
- data['FileSystemAttributes'] = smb.FILE_CASE_SENSITIVE_SEARCH | smb.FILE_CASE_PRESERVED_NAMES
- data['MaxFilenNameLengthInBytes'] = 255
- data['LengthOfFileSystemName'] = len('XTFS')*2
- data['FileSystemName'] = 'XTFS'.encode('utf-16le')
- return data.getData()
- elif level == smb.SMB_INFO_VOLUME:
- data = smb.SMBQueryFsInfoVolume( flags = flags )
- data['VolumeLabel'] = 'SHARE'.encode(encoding)
- return data.getData()
- elif level == smb.SMB_QUERY_FS_VOLUME_INFO or level == smb2.SMB2_FILESYSTEM_VOLUME_INFO:
- data = smb.SMBQueryFsVolumeInfo()
- data['VolumeLabel'] = ''
- data['VolumeCreationTime'] = getFileTime(ctime)
- return data.getData()
- elif level == smb.SMB_QUERY_FS_SIZE_INFO:
- data = smb.SMBQueryFsSizeInfo()
- return data.getData()
- elif level == smb.FILE_FS_FULL_SIZE_INFORMATION:
- data = smb.SMBFileFsFullSizeInformation()
- return data.getData()
- elif level == smb.FILE_FS_SIZE_INFORMATION:
- data = smb.FileFsSizeInformation()
- return data.getData()
- else:
- lastWriteTime = mtime
- attribs = 0
- if os.path.isdir(pathName):
- attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY
- if os.path.isfile(pathName):
- attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL
- fileAttributes = attribs
- return fileSize, lastWriteTime, fileAttributes
- def findFirst2(path, fileName, level, searchAttributes, isSMB2 = False):
- # TODO: Depending on the level, this could be done much simpler
- #print "FindFirs2 path:%s, filename:%s" % (path, fileName)
- fileName = os.path.normpath(fileName.replace('\\','/'))
- # Let's choose the right encoding depending on the request
- if isinstance(fileName,unicode):
- encoding = 'utf-16le'
- flags = smb.SMB.FLAGS2_UNICODE
- else:
- encoding = 'ascii'
- flags = 0
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- files = []
- if pathName.find('*') == -1 and pathName.find('?') == -1:
- # No search patterns
- pattern = ''
- else:
- pattern = os.path.basename(pathName)
- dirName = os.path.dirname(pathName)
- # Always add . and .. Not that important for Windows, but Samba whines if
- # not present (for * search only)
- if pattern == '*':
- files.append(os.path.join(dirName,'.'))
- files.append(os.path.join(dirName,'..'))
- if pattern != '':
- for file in os.listdir(dirName):
- if fnmatch.fnmatch(file.lower(),pattern.lower()):
- entry = os.path.join(dirName, file)
- if os.path.isdir(entry):
- if searchAttributes & smb.ATTR_DIRECTORY:
- files.append(entry)
- else:
- files.append(entry)
- else:
- if os.path.exists(pathName):
- files.append(pathName)
- searchResult = []
- searchCount = len(files)
- errorCode = STATUS_SUCCESS
- for i in files:
- if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
- item = smb.SMBFindFileBothDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO or level == smb2.SMB2_FILE_DIRECTORY_INFO:
- item = smb.SMBFindFileDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
- item = smb.SMBFindFileFullDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_INFO_STANDARD:
- item = smb.SMBFindInfoStandard( flags = flags )
- elif level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO:
- item = smb.SMBFindFileIdFullDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO:
- item = smb.SMBFindFileIdBothDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_FILE_NAMES_INFO or level == smb2.SMB2_FILE_NAMES_INFO:
- item = smb.SMBFindFileNamesInfo( flags = flags )
- else:
- LOG.error("Wrong level %d!" % level)
- return searchResult, searchCount, STATUS_NOT_SUPPORTED
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(i)
- if os.path.isdir(i):
- item['ExtFileAttributes'] = smb.ATTR_DIRECTORY
- else:
- item['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
- item['FileName'] = os.path.basename(i).encode(encoding)
- if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
- item['EaSize'] = 0
- item['EndOfFile'] = size
- item['AllocationSize'] = size
- item['CreationTime'] = getFileTime(ctime)
- item['LastAccessTime'] = getFileTime(atime)
- item['LastWriteTime'] = getFileTime(mtime)
- item['LastChangeTime'] = getFileTime(mtime)
- item['ShortName'] = '\x00'*24
- item['FileName'] = os.path.basename(i).encode(encoding)
- padLen = (8-(len(item) % 8)) % 8
- item['NextEntryOffset'] = len(item) + padLen
- elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO:
- item['EndOfFile'] = size
- item['AllocationSize'] = size
- item['CreationTime'] = getFileTime(ctime)
- item['LastAccessTime'] = getFileTime(atime)
- item['LastWriteTime'] = getFileTime(mtime)
- item['LastChangeTime'] = getFileTime(mtime)
- item['FileName'] = os.path.basename(i).encode(encoding)
- padLen = (8-(len(item) % 8)) % 8
- item['NextEntryOffset'] = len(item) + padLen
- elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
- item['EaSize'] = 0
- item['EndOfFile'] = size
- item['AllocationSize'] = size
- item['CreationTime'] = getFileTime(ctime)
- item['LastAccessTime'] = getFileTime(atime)
- item['LastWriteTime'] = getFileTime(mtime)
- item['LastChangeTime'] = getFileTime(mtime)
- padLen = (8-(len(item) % 8)) % 8
- item['NextEntryOffset'] = len(item) + padLen
- elif level == smb.SMB_FIND_INFO_STANDARD:
- item['EaSize'] = size
- item['CreationDate'] = getSMBDate(ctime)
- item['CreationTime'] = getSMBTime(ctime)
- item['LastAccessDate'] = getSMBDate(atime)
- item['LastAccessTime'] = getSMBTime(atime)
- item['LastWriteDate'] = getSMBDate(mtime)
- item['LastWriteTime'] = getSMBTime(mtime)
- searchResult.append(item)
- # No more files
- if (level >= smb.SMB_FIND_FILE_DIRECTORY_INFO or isSMB2 == True) and searchCount > 0:
- searchResult[-1]['NextEntryOffset'] = 0
- return searchResult, searchCount, errorCode
- def queryFileInformation(path, filename, level):
- #print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
- return queryPathInformation(path,filename, level)
- def queryPathInformation(path, filename, level):
- # TODO: Depending on the level, this could be done much simpler
- #print "queryPathInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
- try:
- errorCode = 0
- fileName = os.path.normpath(filename.replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName):
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
- if level == smb.SMB_QUERY_FILE_BASIC_INFO:
- infoRecord = smb.SMBQueryFileBasicInfo()
- infoRecord['CreationTime'] = getFileTime(ctime)
- infoRecord['LastAccessTime'] = getFileTime(atime)
- infoRecord['LastWriteTime'] = getFileTime(mtime)
- infoRecord['LastChangeTime'] = getFileTime(mtime)
- if os.path.isdir(pathName):
- infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
- else:
- infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
- elif level == smb.SMB_QUERY_FILE_STANDARD_INFO:
- infoRecord = smb.SMBQueryFileStandardInfo()
- infoRecord['AllocationSize'] = size
- infoRecord['EndOfFile'] = size
- if os.path.isdir(pathName):
- infoRecord['Directory'] = 1
- else:
- infoRecord['Directory'] = 0
- elif level == smb.SMB_QUERY_FILE_ALL_INFO or level == smb2.SMB2_FILE_ALL_INFO:
- infoRecord = smb.SMBQueryFileAllInfo()
- infoRecord['CreationTime'] = getFileTime(ctime)
- infoRecord['LastAccessTime'] = getFileTime(atime)
- infoRecord['LastWriteTime'] = getFileTime(mtime)
- infoRecord['LastChangeTime'] = getFileTime(mtime)
- if os.path.isdir(pathName):
- infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
- else:
- infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
- infoRecord['AllocationSize'] = size
- infoRecord['EndOfFile'] = size
- if os.path.isdir(pathName):
- infoRecord['Directory'] = 1
- else:
- infoRecord['Directory'] = 0
- infoRecord['FileName'] = filename.encode('utf-16le')
- elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO:
- infoRecord = smb.SMBFileNetworkOpenInfo()
- infoRecord['CreationTime'] = getFileTime(ctime)
- infoRecord['LastAccessTime'] = getFileTime(atime)
- infoRecord['LastWriteTime'] = getFileTime(mtime)
- infoRecord['ChangeTime'] = getFileTime(mtime)
- infoRecord['AllocationSize'] = size
- infoRecord['EndOfFile'] = size
- if os.path.isdir(pathName):
- infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY
- else:
- infoRecord['FileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
- elif level == smb.SMB_QUERY_FILE_EA_INFO or level == smb2.SMB2_FILE_EA_INFO:
- infoRecord = smb.SMBQueryFileEaInfo()
- elif level == smb2.SMB2_FILE_STREAM_INFO:
- infoRecord = smb.SMBFileStreamInformation()
- else:
- LOG.error('Unknown level for query path info! 0x%x' % level)
- # UNSUPPORTED
- return None, STATUS_NOT_SUPPORTED
- return infoRecord, errorCode
- else:
- # NOT FOUND
- return None, STATUS_OBJECT_NAME_NOT_FOUND
- except Exception, e:
- LOG.error('queryPathInfo: %s' % e)
- raise
- def queryDiskInformation(path):
- # TODO: Do something useful here :)
- # For now we just return fake values
- totalUnits = 65535
- freeUnits = 65535
- return totalUnits, freeUnits
- # Here we implement the NT transaction handlers
- class NTTRANSCommands:
- def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- pass
- # Here we implement the NT transaction handlers
- class TRANSCommands:
- @staticmethod
- def lanMan(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- # Minimal [MS-RAP] implementation, just to return the shares
- connData = smbServer.getConnectionData(connId)
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- if struct.unpack('<H',parameters[:2])[0] == 0:
- # NetShareEnum Request
- netShareEnum = smb.SMBNetShareEnum(parameters)
- if netShareEnum['InfoLevel'] == 1:
- shares = getShares(connId, smbServer)
- respParameters = smb.SMBNetShareEnumResponse()
- respParameters['EntriesReturned'] = len(shares)
- respParameters['EntriesAvailable'] = len(shares)
- tailData = ''
- for i in shares:
- # NetShareInfo1 len == 20
- entry = smb.NetShareInfo1()
- entry['NetworkName'] = i + '\x00'*(13-len(i))
- entry['Type'] = int(shares[i]['share type'])
- # (beto) If offset == 0 it crashes explorer.exe on windows 7
- entry['RemarkOffsetLow'] = 20 * len(shares) + len(tailData)
- respData += entry.getData()
- if shares[i].has_key('comment'):
- tailData += shares[i]['comment'] + '\x00'
- else:
- tailData += '\x00'
- respData += tailData
- else:
- # We don't support other info levels
- errorCode = STATUS_NOT_SUPPORTED
- elif struct.unpack('<H',parameters[:2])[0] == 13:
- # NetrServerGetInfo Request
- respParameters = smb.SMBNetServerGetInfoResponse()
- netServerInfo = smb.SMBNetServerInfo1()
- netServerInfo['ServerName'] = smbServer.getServerName()
- respData = str(netServerInfo)
- respParameters['TotalBytesAvailable'] = len(respData)
- elif struct.unpack('<H',parameters[:2])[0] == 1:
- # NetrShareGetInfo Request
- request = smb.SMBNetShareGetInfo(parameters)
- respParameters = smb.SMBNetShareGetInfoResponse()
- shares = getShares(connId, smbServer)
- share = shares[request['ShareName'].upper()]
- shareInfo = smb.NetShareInfo1()
- shareInfo['NetworkName'] = request['ShareName'].upper() + '\x00'
- shareInfo['Type'] = int(share['share type'])
- respData = shareInfo.getData()
- if share.has_key('comment'):
- shareInfo['RemarkOffsetLow'] = len(respData)
- respData += share['comment'] + '\x00'
- respParameters['TotalBytesAvailable'] = len(respData)
- else:
- # We don't know how to handle anything else
- errorCode = STATUS_NOT_SUPPORTED
- smbServer.setConnectionData(connId, connData)
- return respSetup, respParameters, respData, errorCode
- @staticmethod
- def transactNamedPipe(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
- transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
- # Extract the FID
- fid = struct.unpack('<H', transParameters['Setup'][2:])[0]
- if connData['OpenedFiles'].has_key(fid):
- fileHandle = connData['OpenedFiles'][fid]['FileHandle']
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- os.write(fileHandle,data)
- respData = os.read(fileHandle,data)
- else:
- sock = connData['OpenedFiles'][fid]['Socket']
- sock.send(data)
- respData = sock.recv(maxDataCount)
- else:
- errorCode = STATUS_INVALID_HANDLE
- smbServer.setConnectionData(connId, connData)
- return respSetup, respParameters, respData, errorCode
- # Here we implement the transaction2 handlers
- class TRANS2Commands:
- # All these commands return setup, parameters, data, errorCode
- @staticmethod
- def setPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- setPathInfoParameters = smb.SMBSetPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- fileName = decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName'])
- fileName = os.path.normpath(fileName.replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName):
- informationLevel = setPathInfoParameters['InformationLevel']
- if informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
- infoRecord = smb.SMBSetFileBasicInfo(data)
- # Creation time won't be set, the other ones we play with.
- atime = infoRecord['LastAccessTime']
- if atime == 0:
- atime = -1
- else:
- atime = getUnixTime(atime)
- mtime = infoRecord['LastWriteTime']
- if mtime == 0:
- mtime = -1
- else:
- mtime = getUnixTime(mtime)
- if mtime != -1 or atime != -1:
- os.utime(pathName,(atime,mtime))
- else:
- smbServer.log('Unknown level for set path info! 0x%x' % setPathInfoParameters['InformationLevel'], logging.ERROR)
- # UNSUPPORTED
- errorCode = STATUS_NOT_SUPPORTED
- else:
- errorCode = STATUS_OBJECT_NAME_NOT_FOUND
- if errorCode == STATUS_SUCCESS:
- respParameters = smb.SMBSetPathInformationResponse_Parameters()
- else:
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return respSetup, respParameters, respData, errorCode
- @staticmethod
- def setFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters)
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- if connData['OpenedFiles'].has_key(setFileInfoParameters['FID']):
- fileName = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileName']
- informationLevel = setFileInfoParameters['InformationLevel']
- if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO:
- infoRecord = smb.SMBSetFileDispositionInfo(parameters)
- if infoRecord['DeletePending'] > 0:
- # Mark this file for removal after closed
- connData['OpenedFiles'][setFileInfoParameters['FID']]['DeleteOnClose'] = True
- respParameters = smb.SMBSetFileInformationResponse_Parameters()
- elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
- infoRecord = smb.SMBSetFileBasicInfo(data)
- # Creation time won't be set, the other ones we play with.
- atime = infoRecord['LastAccessTime']
- if atime == 0:
- atime = -1
- else:
- atime = getUnixTime(atime)
- mtime = infoRecord['LastWriteTime']
- if mtime == 0:
- mtime = -1
- else:
- mtime = getUnixTime(mtime)
- os.utime(fileName,(atime,mtime))
- elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO:
- fileHandle = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileHandle']
- infoRecord = smb.SMBSetFileEndOfFileInfo(data)
- if infoRecord['EndOfFile'] > 0:
- os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
- os.write(fileHandle, '\x00')
- else:
- smbServer.log('Unknown level for set file info! 0x%x' % setFileInfoParameters['InformationLevel'], logging.ERROR)
- # UNSUPPORTED
- errorCode = STATUS_NOT_SUPPORTED
- else:
- errorCode = STATUS_NO_SUCH_FILE
- if errorCode == STATUS_SUCCESS:
- respParameters = smb.SMBSetFileInformationResponse_Parameters()
- else:
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return respSetup, respParameters, respData, errorCode
- @staticmethod
- def queryFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
- respSetup = ''
- respParameters = ''
- respData = ''
- queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters)
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- if connData['OpenedFiles'].has_key(queryFileInfoParameters['FID']):
- fileName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName']
- infoRecord, errorCode = queryFileInformation('', fileName, queryFileInfoParameters['InformationLevel'])
- if infoRecord is not None:
- respParameters = smb.SMBQueryFileInformationResponse_Parameters()
- respData = infoRecord
- else:
- errorCode = STATUS_INVALID_HANDLE
- else:
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return respSetup, respParameters, respData, errorCode
- @staticmethod
- def queryPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = 0
- queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- try:
- infoRecord, errorCode = queryPathInformation(path, decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']), queryPathInfoParameters['InformationLevel'])
- except Exception, e:
- smbServer.log("queryPathInformation: %s" % e,logging.ERROR)
- if infoRecord is not None:
- respParameters = smb.SMBQueryPathInformationResponse_Parameters()
- respData = infoRecord
- else:
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return respSetup, respParameters, respData, errorCode
- @staticmethod
- def queryFsInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
- errorCode = 0
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- data = queryFsInformation(connData['ConnectedShares'][recvPacket['Tid']]['path'], '', struct.unpack('<H',parameters)[0])
- smbServer.setConnectionData(connId, connData)
- return '','', data, errorCode
- @staticmethod
- def findNext2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
- connData = smbServer.getConnectionData(connId)
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- findNext2Parameters = smb.SMBFindNext2_Parameters(flags = recvPacket['Flags2'], data = parameters)
- sid = findNext2Parameters['SID']
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- if connData['SIDs'].has_key(sid):
- searchResult = connData['SIDs'][sid]
- respParameters = smb.SMBFindNext2Response_Parameters()
- endOfSearch = 1
- searchCount = 1
- totalData = 0
- for i in enumerate(searchResult):
- data = i[1].getData()
- lenData = len(data)
- if (totalData+lenData) >= maxDataCount or (i[0]+1) >= findNext2Parameters['SearchCount']:
- # We gotta stop here and continue on a find_next2
- endOfSearch = 0
- connData['SIDs'][sid] = searchResult[i[0]:]
- respParameters['LastNameOffset'] = totalData
- break
- else:
- searchCount +=1
- respData += data
- totalData += lenData
- # Have we reached the end of the search or still stuff to send?
- if endOfSearch > 0:
- # Let's remove the SID from our ConnData
- del(connData['SIDs'][sid])
- respParameters['EndOfSearch'] = endOfSearch
- respParameters['SearchCount'] = searchCount
- else:
- errorCode = STATUS_INVALID_HANDLE
- else:
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return respSetup, respParameters, respData, errorCode
- @staticmethod
- def findFirst2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
- connData = smbServer.getConnectionData(connId)
- respSetup = ''
- respParameters = ''
- respData = ''
- findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters)
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- searchResult, searchCount, errorCode = findFirst2(path,
- decodeSMBString( recvPacket['Flags2'], findFirst2Parameters['FileName'] ),
- findFirst2Parameters['InformationLevel'],
- findFirst2Parameters['SearchAttributes'] )
- respParameters = smb.SMBFindFirst2Response_Parameters()
- endOfSearch = 1
- sid = 0x80 # default SID
- searchCount = 0
- totalData = 0
- for i in enumerate(searchResult):
- #i[1].dump()
- data = i[1].getData()
- lenData = len(data)
- if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']:
- # We gotta stop here and continue on a find_next2
- endOfSearch = 0
- # Simple way to generate a fid
- if len(connData['SIDs']) == 0:
- sid = 1
- else:
- sid = connData['SIDs'].keys()[-1] + 1
- # Store the remaining search results in the ConnData SID
- connData['SIDs'][sid] = searchResult[i[0]:]
- respParameters['LastNameOffset'] = totalData
- break
- else:
- searchCount +=1
- respData += data
- padLen = (8-(lenData % 8)) %8
- respData += '\xaa'*padLen
- totalData += lenData + padLen
- respParameters['SID'] = sid
- respParameters['EndOfSearch'] = endOfSearch
- respParameters['SearchCount'] = searchCount
- else:
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return respSetup, respParameters, respData, errorCode
- # Here we implement the commands handlers
- class SMBCommands:
- @staticmethod
- def smbTransaction(connId, smbServer, SMBCommand, recvPacket, transCommands):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
- # Do the stuff
- if transParameters['ParameterCount'] != transParameters['TotalParameterCount']:
- # TODO: Handle partial parameters
- raise Exception("Unsupported partial parameters in TRANSACT2!")
- else:
- transData = smb.SMBTransaction_SData(flags = recvPacket['Flags2'])
- # Standard says servers shouldn't trust Parameters and Data comes
- # in order, so we have to parse the offsets, ugly
- paramCount = transParameters['ParameterCount']
- transData['Trans_ParametersLength'] = paramCount
- dataCount = transParameters['DataCount']
- transData['Trans_DataLength'] = dataCount
- transData.fromString(SMBCommand['Data'])
- if transParameters['ParameterOffset'] > 0:
- paramOffset = transParameters['ParameterOffset'] - 63 - transParameters['SetupLength']
- transData['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
- else:
- transData['Trans_Parameters'] = ''
- if transParameters['DataOffset'] > 0:
- dataOffset = transParameters['DataOffset'] - 63 - transParameters['SetupLength']
- transData['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
- else:
- transData['Trans_Data'] = ''
- # Call the handler for this TRANSACTION
- if transParameters['SetupCount'] == 0:
- # No subcommand, let's play with the Name
- command = decodeSMBString(recvPacket['Flags2'],transData['Name'])
- else:
- command = struct.unpack('<H', transParameters['Setup'][:2])[0]
- if transCommands.has_key(command):
- # Call the TRANS subcommand
- setup = ''
- parameters = ''
- data = ''
- try:
- setup, parameters, data, errorCode = transCommands[command](connId,
- smbServer,
- recvPacket,
- transData['Trans_Parameters'],
- transData['Trans_Data'],
- transParameters['MaxDataCount'])
- except Exception, e:
- #print 'Transaction: %s' % e,e
- smbServer.log('Transaction: (%r,%s)' % (command, e), logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- #raise
- if setup == '' and parameters == '' and data == '':
- # Something wen't wrong
- respParameters = ''
- respData = ''
- else:
- # Build the answer
- data = str(data)
- remainingData = len(data)
- parameters = str(parameters)
- remainingParameters = len(parameters)
- commands = []
- dataDisplacement = 0
- while remainingData > 0 or remainingParameters > 0:
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- respParameters = smb.SMBTransactionResponse_Parameters()
- respData = smb.SMBTransaction2Response_Data()
- respParameters['TotalParameterCount'] = len(parameters)
- respParameters['ParameterCount'] = len(parameters)
- respData['Trans_ParametersLength'] = len(parameters)
- respParameters['TotalDataCount'] = len(data)
- respParameters['DataDisplacement'] = dataDisplacement
- # TODO: Do the same for parameters
- if len(data) > transParameters['MaxDataCount']:
- # Answer doesn't fit in this packet
- LOG.debug("Lowering answer from %d to %d" % (len(data),transParameters['MaxDataCount']) )
- respParameters['DataCount'] = transParameters['MaxDataCount']
- else:
- respParameters['DataCount'] = len(data)
- respData['Trans_DataLength'] = respParameters['DataCount']
- respParameters['SetupCount'] = len(setup)
- respParameters['Setup'] = setup
- # TODO: Make sure we're calculating the pad right
- if len(parameters) > 0:
- #padLen = 4 - (55 + len(setup)) % 4
- padLen = (4 - (55 + len(setup)) % 4 ) % 4
- padBytes = '\xFF' * padLen
- respData['Pad1'] = padBytes
- respParameters['ParameterOffset'] = 55 + len(setup) + padLen
- else:
- padLen = 0
- respParameters['ParameterOffset'] = 0
- respData['Pad1'] = ''
- if len(data) > 0:
- #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
- pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
- respData['Pad2'] = '\xFF' * pad2Len
- respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
- else:
- respParameters['DataOffset'] = 0
- respData['Pad2'] = ''
- respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
- respData['Trans_Data'] = data[:respParameters['DataCount']]
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- data = data[respParameters['DataCount']:]
- remainingData -= respParameters['DataCount']
- dataDisplacement += respParameters['DataCount'] + 1
- parameters = parameters[respParameters['ParameterCount']:]
- remainingParameters -= respParameters['ParameterCount']
- commands.append(respSMBCommand)
- smbServer.setConnectionData(connId, connData)
- return commands, None, errorCode
- else:
- smbServer.log("Unsupported Transact command %r" % command, logging.ERROR)
- respParameters = ''
- respData = ''
- errorCode = STATUS_NOT_IMPLEMENTED
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbNTTransact(connId, smbServer, SMBCommand, recvPacket, transCommands):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- NTTransParameters= smb.SMBNTTransaction_Parameters(SMBCommand['Parameters'])
- # Do the stuff
- if NTTransParameters['ParameterCount'] != NTTransParameters['TotalParameterCount']:
- # TODO: Handle partial parameters
- raise Exception("Unsupported partial parameters in NTTrans!")
- else:
- NTTransData = smb.SMBNTTransaction_Data()
- # Standard says servers shouldn't trust Parameters and Data comes
- # in order, so we have to parse the offsets, ugly
- paramCount = NTTransParameters['ParameterCount']
- NTTransData['NT_Trans_ParametersLength'] = paramCount
- dataCount = NTTransParameters['DataCount']
- NTTransData['NT_Trans_DataLength'] = dataCount
- if NTTransParameters['ParameterOffset'] > 0:
- paramOffset = NTTransParameters['ParameterOffset'] - 73 - NTTransParameters['SetupLength']
- NTTransData['NT_Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
- else:
- NTTransData['NT_Trans_Parameters'] = ''
- if NTTransParameters['DataOffset'] > 0:
- dataOffset = NTTransParameters['DataOffset'] - 73 - NTTransParameters['SetupLength']
- NTTransData['NT_Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
- else:
- NTTransData['NT_Trans_Data'] = ''
- # Call the handler for this TRANSACTION
- command = NTTransParameters['Function']
- if transCommands.has_key(command):
- # Call the NT TRANS subcommand
- setup = ''
- parameters = ''
- data = ''
- try:
- setup, parameters, data, errorCode = transCommands[command](connId,
- smbServer,
- recvPacket,
- NTTransData['NT_Trans_Parameters'],
- NTTransData['NT_Trans_Data'],
- NTTransParameters['MaxDataCount'])
- except Exception, e:
- smbServer.log('NTTransaction: (0x%x,%s)' % (command, e), logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- #raise
- if setup == '' and parameters == '' and data == '':
- # Something wen't wrong
- respParameters = ''
- respData = ''
- if errorCode == STATUS_SUCCESS:
- errorCode = STATUS_ACCESS_DENIED
- else:
- # Build the answer
- data = str(data)
- remainingData = len(data)
- parameters = str(parameters)
- remainingParameters = len(parameters)
- commands = []
- dataDisplacement = 0
- while remainingData > 0 or remainingParameters > 0:
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- respParameters = smb.SMBNTTransactionResponse_Parameters()
- respData = smb.SMBNTTransactionResponse_Data()
- respParameters['TotalParameterCount'] = len(parameters)
- respParameters['ParameterCount'] = len(parameters)
- respData['Trans_ParametersLength'] = len(parameters)
- respParameters['TotalDataCount'] = len(data)
- respParameters['DataDisplacement'] = dataDisplacement
- # TODO: Do the same for parameters
- if len(data) > NTTransParameters['MaxDataCount']:
- # Answer doesn't fit in this packet
- LOG.debug("Lowering answer from %d to %d" % (len(data),NTTransParameters['MaxDataCount']) )
- respParameters['DataCount'] = NTTransParameters['MaxDataCount']
- else:
- respParameters['DataCount'] = len(data)
- respData['NT_Trans_DataLength'] = respParameters['DataCount']
- respParameters['SetupCount'] = len(setup)
- respParameters['Setup'] = setup
- # TODO: Make sure we're calculating the pad right
- if len(parameters) > 0:
- #padLen = 4 - (71 + len(setup)) % 4
- padLen = (4 - (73 + len(setup)) % 4 ) % 4
- padBytes = '\xFF' * padLen
- respData['Pad1'] = padBytes
- respParameters['ParameterOffset'] = 73 + len(setup) + padLen
- else:
- padLen = 0
- respParameters['ParameterOffset'] = 0
- respData['Pad1'] = ''
- if len(data) > 0:
- #pad2Len = 4 - (71 + len(setup) + padLen + len(parameters)) % 4
- pad2Len = (4 - (73 + len(setup) + padLen + len(parameters)) % 4) % 4
- respData['Pad2'] = '\xFF' * pad2Len
- respParameters['DataOffset'] = 73 + len(setup) + padLen + len(parameters) + pad2Len
- else:
- respParameters['DataOffset'] = 0
- respData['Pad2'] = ''
- respData['NT_Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
- respData['NT_Trans_Data'] = data[:respParameters['DataCount']]
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- data = data[respParameters['DataCount']:]
- remainingData -= respParameters['DataCount']
- dataDisplacement += respParameters['DataCount'] + 1
- parameters = parameters[respParameters['ParameterCount']:]
- remainingParameters -= respParameters['ParameterCount']
- commands.append(respSMBCommand)
- smbServer.setConnectionData(connId, connData)
- return commands, None, errorCode
- else:
- #smbServer.log("Unsupported NTTransact command 0x%x" % command, logging.ERROR)
- respParameters = ''
- respData = ''
- errorCode = STATUS_NOT_IMPLEMENTED
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbTransaction2(connId, smbServer, SMBCommand, recvPacket, transCommands):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters'])
- # Do the stuff
- if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']:
- # TODO: Handle partial parameters
- #print "Unsupported partial parameters in TRANSACT2!"
- raise Exception("Unsupported partial parameters in TRANSACT2!")
- else:
- trans2Data = smb.SMBTransaction2_Data()
- # Standard says servers shouldn't trust Parameters and Data comes
- # in order, so we have to parse the offsets, ugly
- paramCount = trans2Parameters['ParameterCount']
- trans2Data['Trans_ParametersLength'] = paramCount
- dataCount = trans2Parameters['DataCount']
- trans2Data['Trans_DataLength'] = dataCount
- if trans2Parameters['ParameterOffset'] > 0:
- paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength']
- trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
- else:
- trans2Data['Trans_Parameters'] = ''
- if trans2Parameters['DataOffset'] > 0:
- dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength']
- trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
- else:
- trans2Data['Trans_Data'] = ''
- # Call the handler for this TRANSACTION
- command = struct.unpack('<H', trans2Parameters['Setup'])[0]
- if transCommands.has_key(command):
- # Call the TRANS2 subcommand
- try:
- setup, parameters, data, errorCode = transCommands[command](connId,
- smbServer,
- recvPacket,
- trans2Data['Trans_Parameters'],
- trans2Data['Trans_Data'],
- trans2Parameters['MaxDataCount'])
- except Exception, e:
- smbServer.log('Transaction2: (0x%x,%s)' % (command, e), logging.ERROR)
- #import traceback
- #traceback.print_exc()
- raise
- if setup == '' and parameters == '' and data == '':
- # Something wen't wrong
- respParameters = ''
- respData = ''
- else:
- # Build the answer
- data = str(data)
- remainingData = len(data)
- parameters = str(parameters)
- remainingParameters = len(parameters)
- commands = []
- dataDisplacement = 0
- while remainingData > 0 or remainingParameters > 0:
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- respParameters = smb.SMBTransaction2Response_Parameters()
- respData = smb.SMBTransaction2Response_Data()
- respParameters['TotalParameterCount'] = len(parameters)
- respParameters['ParameterCount'] = len(parameters)
- respData['Trans_ParametersLength'] = len(parameters)
- respParameters['TotalDataCount'] = len(data)
- respParameters['DataDisplacement'] = dataDisplacement
- # TODO: Do the same for parameters
- if len(data) > trans2Parameters['MaxDataCount']:
- # Answer doesn't fit in this packet
- LOG.debug("Lowering answer from %d to %d" % (len(data),trans2Parameters['MaxDataCount']) )
- respParameters['DataCount'] = trans2Parameters['MaxDataCount']
- else:
- respParameters['DataCount'] = len(data)
- respData['Trans_DataLength'] = respParameters['DataCount']
- respParameters['SetupCount'] = len(setup)
- respParameters['Setup'] = setup
- # TODO: Make sure we're calculating the pad right
- if len(parameters) > 0:
- #padLen = 4 - (55 + len(setup)) % 4
- padLen = (4 - (55 + len(setup)) % 4 ) % 4
- padBytes = '\xFF' * padLen
- respData['Pad1'] = padBytes
- respParameters['ParameterOffset'] = 55 + len(setup) + padLen
- else:
- padLen = 0
- respParameters['ParameterOffset'] = 0
- respData['Pad1'] = ''
- if len(data) > 0:
- #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
- pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
- respData['Pad2'] = '\xFF' * pad2Len
- respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
- else:
- respParameters['DataOffset'] = 0
- respData['Pad2'] = ''
- respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
- respData['Trans_Data'] = data[:respParameters['DataCount']]
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- data = data[respParameters['DataCount']:]
- remainingData -= respParameters['DataCount']
- dataDisplacement += respParameters['DataCount'] + 1
- parameters = parameters[respParameters['ParameterCount']:]
- remainingParameters -= respParameters['ParameterCount']
- commands.append(respSMBCommand)
- smbServer.setConnectionData(connId, connData)
- return commands, None, errorCode
- else:
- smbServer.log("Unsupported Transact/2 command 0x%x" % command, logging.ERROR)
- respParameters = ''
- respData = ''
- errorCode = STATUS_NOT_IMPLEMENTED
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComLockingAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOCKING_ANDX)
- respParameters = ''
- respData = ''
- # I'm actually doing nothing.. just make MacOS happy ;)
- errorCode = STATUS_SUCCESS
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComClose(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CLOSE)
- respParameters = ''
- respData = ''
- comClose = smb.SMBClose_Parameters(SMBCommand['Parameters'])
- if connData['OpenedFiles'].has_key(comClose['FID']):
- errorCode = STATUS_SUCCESS
- fileHandle = connData['OpenedFiles'][comClose['FID']]['FileHandle']
- try:
- if fileHandle == PIPE_FILE_DESCRIPTOR:
- connData['OpenedFiles'][comClose['FID']]['Socket'].close()
- elif fileHandle != VOID_FILE_DESCRIPTOR:
- os.close(fileHandle)
- except Exception, e:
- smbServer.log("comClose %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- # Check if the file was marked for removal
- if connData['OpenedFiles'][comClose['FID']]['DeleteOnClose'] is True:
- try:
- os.remove(connData['OpenedFiles'][comClose['FID']]['FileName'])
- except Exception, e:
- smbServer.log("comClose %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- del(connData['OpenedFiles'][comClose['FID']])
- else:
- errorCode = STATUS_INVALID_HANDLE
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComWrite(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE)
- respParameters = smb.SMBWriteResponse_Parameters()
- respData = ''
- comWriteParameters = smb.SMBWrite_Parameters(SMBCommand['Parameters'])
- comWriteData = smb.SMBWrite_Data(SMBCommand['Data'])
- if connData['OpenedFiles'].has_key(comWriteParameters['Fid']):
- fileHandle = connData['OpenedFiles'][comWriteParameters['Fid']]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- # TODO: Handle big size files
- # If we're trying to write past the file end we just skip the write call (Vista does this)
- if os.lseek(fileHandle, 0, 2) >= comWriteParameters['Offset']:
- os.lseek(fileHandle,comWriteParameters['Offset'],0)
- os.write(fileHandle,comWriteData['Data'])
- else:
- sock = connData['OpenedFiles'][comWriteParameters['Fid']]['Socket']
- sock.send(comWriteData['Data'])
- respParameters['Count'] = comWriteParameters['Count']
- except Exception, e:
- smbServer.log('smbComWrite: %s' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComFlush(connId, smbServer, SMBCommand,recvPacket ):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_FLUSH)
- respParameters = ''
- respData = ''
- comFlush = smb.SMBFlush_Parameters(SMBCommand['Parameters'])
- if connData['OpenedFiles'].has_key(comFlush['FID']):
- errorCode = STATUS_SUCCESS
- fileHandle = connData['OpenedFiles'][comFlush['FID']]['FileHandle']
- try:
- os.fsync(fileHandle)
- except Exception, e:
- smbServer.log("comFlush %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComCreateDirectory(connId, smbServer, SMBCommand,recvPacket ):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY)
- respParameters = ''
- respData = ''
- comCreateDirectoryData= smb.SMBCreateDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- errorCode = STATUS_SUCCESS
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comCreateDirectoryData['DirectoryName']).replace('\\','/'))
- if len(fileName) > 0:
- if fileName[0] == '/' or fileName[0] == '\\':
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName):
- errorCode = STATUS_OBJECT_NAME_COLLISION
- # TODO: More checks here in the future.. Specially when we support
- # user access
- else:
- try:
- os.mkdir(pathName)
- except Exception, e:
- smbServer.log("smbComCreateDirectory: %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComRename(connId, smbServer, SMBCommand, recvPacket ):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_RENAME)
- respParameters = ''
- respData = ''
- comRenameData = smb.SMBRename_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- errorCode = STATUS_SUCCESS
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- oldFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['OldFileName']).replace('\\','/'))
- newFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['NewFileName']).replace('\\','/'))
- if len(oldFileName) > 0 and (oldFileName[0] == '/' or oldFileName[0] == '\\'):
- # strip leading '/'
- oldFileName = oldFileName[1:]
- oldPathName = os.path.join(path,oldFileName)
- if len(newFileName) > 0 and (newFileName[0] == '/' or newFileName[0] == '\\'):
- # strip leading '/'
- newFileName = newFileName[1:]
- newPathName = os.path.join(path,newFileName)
- if os.path.exists(oldPathName) is not True:
- errorCode = STATUS_NO_SUCH_FILE
- # TODO: More checks here in the future.. Specially when we support
- # user access
- else:
- try:
- os.rename(oldPathName,newPathName)
- except OSError, e:
- smbServer.log("smbComRename: %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComDelete(connId, smbServer, SMBCommand, recvPacket ):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE)
- respParameters = ''
- respData = ''
- comDeleteData = smb.SMBDelete_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- errorCode = STATUS_SUCCESS
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteData['FileName']).replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName) is not True:
- errorCode = STATUS_NO_SUCH_FILE
- # TODO: More checks here in the future.. Specially when we support
- # user access
- else:
- try:
- os.remove(pathName)
- except OSError, e:
- smbServer.log("smbComDelete: %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComDeleteDirectory(connId, smbServer, SMBCommand, recvPacket ):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY)
- respParameters = ''
- respData = ''
- comDeleteDirectoryData= smb.SMBDeleteDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- errorCode = STATUS_SUCCESS
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteDirectoryData['DirectoryName']).replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName) is not True:
- errorCode = STATUS_NO_SUCH_FILE
- # TODO: More checks here in the future.. Specially when we support
- # user access
- else:
- try:
- os.rmdir(pathName)
- except OSError, e:
- smbServer.log("smbComDeleteDirectory: %s" % e,logging.ERROR)
- if e.errno == errno.ENOTEMPTY:
- errorCode = STATUS_DIRECTORY_NOT_EMPTY
- else:
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComWriteAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
- respParameters = smb.SMBWriteAndXResponse_Parameters()
- respData = ''
- if SMBCommand['WordCount'] == 0x0C:
- writeAndX = smb.SMBWriteAndX_Parameters_Short(SMBCommand['Parameters'])
- writeAndXData = smb.SMBWriteAndX_Data_Short()
- else:
- writeAndX = smb.SMBWriteAndX_Parameters(SMBCommand['Parameters'])
- writeAndXData = smb.SMBWriteAndX_Data()
- writeAndXData['DataLength'] = writeAndX['DataLength']
- writeAndXData['DataOffset'] = writeAndX['DataOffset']
- writeAndXData.fromString(SMBCommand['Data'])
- if connData['OpenedFiles'].has_key(writeAndX['Fid']):
- fileHandle = connData['OpenedFiles'][writeAndX['Fid']]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- offset = writeAndX['Offset']
- if writeAndX.fields.has_key('HighOffset'):
- offset += (writeAndX['HighOffset'] << 32)
- # If we're trying to write past the file end we just skip the write call (Vista does this)
- if os.lseek(fileHandle, 0, 2) >= offset:
- os.lseek(fileHandle,offset,0)
- os.write(fileHandle,writeAndXData['Data'])
- else:
- sock = connData['OpenedFiles'][writeAndX['Fid']]['Socket']
- sock.send(writeAndXData['Data'])
- respParameters['Count'] = writeAndX['DataLength']
- respParameters['Available']= 0xff
- except Exception, e:
- smbServer.log('smbComWriteAndx: %s' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComRead(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ)
- respParameters = smb.SMBReadResponse_Parameters()
- respData = smb.SMBReadResponse_Data()
- comReadParameters = smb.SMBRead_Parameters(SMBCommand['Parameters'])
- if connData['OpenedFiles'].has_key(comReadParameters['Fid']):
- fileHandle = connData['OpenedFiles'][comReadParameters['Fid']]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- # TODO: Handle big size files
- os.lseek(fileHandle,comReadParameters['Offset'],0)
- content = os.read(fileHandle,comReadParameters['Count'])
- else:
- sock = connData['OpenedFiles'][comReadParameters['Fid']]['Socket']
- content = sock.recv(comReadParameters['Count'])
- respParameters['Count'] = len(content)
- respData['DataLength'] = len(content)
- respData['Data'] = content
- except Exception, e:
- smbServer.log('smbComRead: %s ' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComReadAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ_ANDX)
- respParameters = smb.SMBReadAndXResponse_Parameters()
- respData = ''
- if SMBCommand['WordCount'] == 0x0A:
- readAndX = smb.SMBReadAndX_Parameters2(SMBCommand['Parameters'])
- else:
- readAndX = smb.SMBReadAndX_Parameters(SMBCommand['Parameters'])
- if connData['OpenedFiles'].has_key(readAndX['Fid']):
- fileHandle = connData['OpenedFiles'][readAndX['Fid']]['FileHandle']
- errorCode = 0
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- offset = readAndX['Offset']
- if readAndX.fields.has_key('HighOffset'):
- offset += (readAndX['HighOffset'] << 32)
- os.lseek(fileHandle,offset,0)
- content = os.read(fileHandle,readAndX['MaxCount'])
- else:
- sock = connData['OpenedFiles'][readAndX['Fid']]['Socket']
- content = sock.recv(readAndX['MaxCount'])
- respParameters['Remaining'] = 0xffff
- respParameters['DataCount'] = len(content)
- respParameters['DataOffset'] = 59
- respParameters['DataCount_Hi'] = 0
- respData = content
- except Exception, e:
- smbServer.log('smbComReadAndX: %s ' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbQueryInformation(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION)
- respParameters = smb.SMBQueryInformationResponse_Parameters()
- respData = ''
- queryInformation= smb.SMBQueryInformation_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- fileSize, lastWriteTime, fileAttributes = queryFsInformation(
- connData['ConnectedShares'][recvPacket['Tid']]['path'],
- decodeSMBString(recvPacket['Flags2'],queryInformation['FileName']))
- respParameters['FileSize'] = fileSize
- respParameters['LastWriteTime'] = lastWriteTime
- respParameters['FileAttributes'] = fileAttributes
- errorCode = STATUS_SUCCESS
- else:
- # STATUS_SMB_BAD_TID
- errorCode = STATUS_SMB_BAD_TID
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbQueryInformationDisk(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION_DISK)
- respParameters = smb.SMBQueryInformationDiskResponse_Parameters()
- respData = ''
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- totalUnits, freeUnits = queryDiskInformation(
- connData['ConnectedShares'][recvPacket['Tid']]['path'])
- respParameters['TotalUnits'] = totalUnits
- respParameters['BlocksPerUnit'] = 1
- respParameters['BlockSize'] = 1
- respParameters['FreeUnits'] = freeUnits
- errorCode = STATUS_SUCCESS
- else:
- # STATUS_SMB_BAD_TID
- respData = ''
- respParameters = ''
- errorCode = STATUS_SMB_BAD_TID
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComEcho(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
- respParameters = smb.SMBEchoResponse_Parameters()
- respData = smb.SMBEchoResponse_Data()
- echoData = smb.SMBEcho_Data(SMBCommand['Data'])
- respParameters['SequenceNumber'] = 1
- respData['Data'] = echoData['Data']
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- errorCode = STATUS_SUCCESS
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComTreeDisconnect(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_DISCONNECT)
- # Check if the Tid matches the Tid trying to disconnect
- respParameters = ''
- respData = ''
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['Tid'],connData['ConnectedShares'][recvPacket['Tid']]['shareName']))
- del(connData['ConnectedShares'][recvPacket['Tid']])
- errorCode = STATUS_SUCCESS
- else:
- # STATUS_SMB_BAD_TID
- errorCode = STATUS_SMB_BAD_TID
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComLogOffAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOGOFF_ANDX)
- # Check if the Uid matches the user trying to logoff
- respParameters = ''
- respData = ''
- if recvPacket['Uid'] != connData['Uid']:
- # STATUS_SMB_BAD_UID
- errorCode = STATUS_SMB_BAD_UID
- else:
- errorCode = STATUS_SUCCESS
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- connData['Uid'] = 0
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComQueryInformation2(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION2)
- respParameters = smb.SMBQueryInformation2Response_Parameters()
- respData = ''
- queryInformation2 = smb.SMBQueryInformation2_Parameters(SMBCommand['Parameters'])
- errorCode = 0xFF
- if connData['OpenedFiles'].has_key(queryInformation2['Fid']):
- errorCode = STATUS_SUCCESS
- pathName = connData['OpenedFiles'][queryInformation2['Fid']]['FileName']
- try:
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
- respParameters['CreateDate'] = getSMBDate(ctime)
- respParameters['CreationTime'] = getSMBTime(ctime)
- respParameters['LastAccessDate'] = getSMBDate(atime)
- respParameters['LastAccessTime'] = getSMBTime(atime)
- respParameters['LastWriteDate'] = getSMBDate(mtime)
- respParameters['LastWriteTime'] = getSMBTime(mtime)
- respParameters['FileDataSize'] = size
- respParameters['FileAllocationSize'] = size
- attribs = 0
- if os.path.isdir(pathName):
- attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
- if os.path.isfile(pathName):
- attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL
- respParameters['FileAttributes'] = attribs
- except Exception, e:
- smbServer.log('smbComQueryInformation2 %s' % e,logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- if errorCode > 0:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket):
- # TODO: Fully implement this
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
- respParameters = smb.SMBNtCreateAndXResponse_Parameters()
- respData = ''
- ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters'])
- ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
- #if ntCreateAndXParameters['CreateFlags'] & 0x10: # NT_CREATE_REQUEST_EXTENDED_RESPONSE
- # respParameters = smb.SMBNtCreateAndXExtendedResponse_Parameters()
- # respParameters['VolumeGUID'] = '\x00'
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- # If we have a rootFid, the path is relative to that fid
- errorCode = STATUS_SUCCESS
- if ntCreateAndXParameters['RootFid'] > 0:
- path = connData['OpenedFiles'][ntCreateAndXParameters['RootFid']]['FileName']
- LOG.debug("RootFid present %s!" % path)
- else:
- if connData['ConnectedShares'][recvPacket['Tid']].has_key('path'):
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- else:
- path = 'NONE'
- errorCode = STATUS_ACCESS_DENIED
- deleteOnClose = False
- fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- createDisposition = ntCreateAndXParameters['Disposition']
- mode = 0
- if createDisposition == smb.FILE_SUPERSEDE:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb.FILE_OVERWRITE_IF == smb.FILE_OVERWRITE_IF:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb.FILE_OVERWRITE == smb.FILE_OVERWRITE:
- if os.path.exists(pathName) is True:
- mode |= os.O_TRUNC
- else:
- errorCode = STATUS_NO_SUCH_FILE
- elif createDisposition & smb.FILE_OPEN_IF == smb.FILE_OPEN_IF:
- if os.path.exists(pathName) is True:
- mode |= os.O_TRUNC
- else:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb.FILE_CREATE == smb.FILE_CREATE:
- if os.path.exists(pathName) is True:
- errorCode = STATUS_OBJECT_NAME_COLLISION
- else:
- mode |= os.O_CREAT
- elif createDisposition & smb.FILE_OPEN == smb.FILE_OPEN:
- if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
- errorCode = STATUS_NO_SUCH_FILE
- if errorCode == STATUS_SUCCESS:
- desiredAccess = ntCreateAndXParameters['AccessMask']
- if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
- mode |= os.O_RDONLY
- if (desiredAccess & smb.FILE_WRITE_DATA) or (desiredAccess & smb.GENERIC_WRITE):
- if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
- mode |= os.O_RDWR #| os.O_APPEND
- else:
- mode |= os.O_WRONLY #| os.O_APPEND
- if desiredAccess & smb.GENERIC_ALL:
- mode |= os.O_RDWR #| os.O_APPEND
- createOptions = ntCreateAndXParameters['CreateOptions']
- if mode & os.O_CREAT == os.O_CREAT:
- if createOptions & smb.FILE_DIRECTORY_FILE == smb.FILE_DIRECTORY_FILE:
- try:
- # Let's create the directory
- os.mkdir(pathName)
- mode = os.O_RDONLY
- except Exception, e:
- smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- if createOptions & smb.FILE_NON_DIRECTORY_FILE == smb.FILE_NON_DIRECTORY_FILE:
- # If the file being opened is a directory, the server MUST fail the request with
- # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
- # response.
- if os.path.isdir(pathName) is True:
- errorCode = STATUS_FILE_IS_A_DIRECTORY
- if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE:
- deleteOnClose = True
- if errorCode == STATUS_SUCCESS:
- try:
- if os.path.isdir(pathName) and sys.platform == 'win32':
- fid = VOID_FILE_DESCRIPTOR
- else:
- if sys.platform == 'win32':
- mode |= os.O_BINARY
- if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
- fid = PIPE_FILE_DESCRIPTOR
- sock = socket.socket()
- sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
- else:
- fid = os.open(pathName, mode)
- except Exception, e:
- smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
- #print e
- fid = 0
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
- if errorCode == STATUS_SUCCESS:
- # Simple way to generate a fid
- if len(connData['OpenedFiles']) == 0:
- fakefid = 1
- else:
- fakefid = connData['OpenedFiles'].keys()[-1] + 1
- respParameters['Fid'] = fakefid
- respParameters['CreateAction'] = createDisposition
- if fid == PIPE_FILE_DESCRIPTOR:
- respParameters['FileAttributes'] = 0x80
- respParameters['IsDirectory'] = 0
- respParameters['CreateTime'] = 0
- respParameters['LastAccessTime'] = 0
- respParameters['LastWriteTime'] = 0
- respParameters['LastChangeTime'] = 0
- respParameters['AllocationSize'] = 4096
- respParameters['EndOfFile'] = 0
- respParameters['FileType'] = 2
- respParameters['IPCState'] = 0x5ff
- else:
- if os.path.isdir(pathName):
- respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
- respParameters['IsDirectory'] = 1
- else:
- respParameters['IsDirectory'] = 0
- respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes']
- # Let's get this file's information
- respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
- if errorCode == STATUS_SUCCESS:
- respParameters['CreateTime'] = respInfo['CreationTime']
- respParameters['LastAccessTime'] = respInfo['LastAccessTime']
- respParameters['LastWriteTime'] = respInfo['LastWriteTime']
- respParameters['LastChangeTime'] = respInfo['LastChangeTime']
- respParameters['FileAttributes'] = respInfo['ExtFileAttributes']
- respParameters['AllocationSize'] = respInfo['AllocationSize']
- respParameters['EndOfFile'] = respInfo['EndOfFile']
- else:
- respParameters = ''
- respData = ''
- if errorCode == STATUS_SUCCESS:
- # Let's store the fid for the connection
- # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
- connData['OpenedFiles'][fakefid] = {}
- connData['OpenedFiles'][fakefid]['FileHandle'] = fid
- connData['OpenedFiles'][fakefid]['FileName'] = pathName
- connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
- if fid == PIPE_FILE_DESCRIPTOR:
- connData['OpenedFiles'][fakefid]['Socket'] = sock
- else:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComOpenAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_OPEN_ANDX)
- respParameters = smb.SMBOpenAndXResponse_Parameters()
- respData = ''
- openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters'])
- openAndXData = smb.SMBOpenAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['Tid']):
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- openedFile, mode, pathName, errorCode = openFile(path,
- decodeSMBString(recvPacket['Flags2'],openAndXData['FileName']),
- openAndXParameters['DesiredAccess'],
- openAndXParameters['FileAttributes'],
- openAndXParameters['OpenMode'])
- else:
- errorCode = STATUS_SMB_BAD_TID
- if errorCode == STATUS_SUCCESS:
- # Simple way to generate a fid
- fid = len(connData['OpenedFiles']) + 1
- if len(connData['OpenedFiles']) == 0:
- fid = 1
- else:
- fid = connData['OpenedFiles'].keys()[-1] + 1
- respParameters['Fid'] = fid
- if mode & os.O_CREAT:
- # File did not exist and was created
- respParameters['Action'] = 0x2
- elif mode & os.O_RDONLY:
- # File existed and was opened
- respParameters['Action'] = 0x1
- elif mode & os.O_APPEND:
- # File existed and was opened
- respParameters['Action'] = 0x1
- else:
- # File existed and was truncated
- respParameters['Action'] = 0x3
- # Let's store the fid for the connection
- #smbServer.log('Opening file %s' % pathName)
- connData['OpenedFiles'][fid] = {}
- connData['OpenedFiles'][fid]['FileHandle'] = openedFile
- connData['OpenedFiles'][fid]['FileName'] = pathName
- connData['OpenedFiles'][fid]['DeleteOnClose'] = False
- else:
- respParameters = ''
- respData = ''
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
- resp = smb.NewSMBPacket()
- resp['Flags1'] = smb.SMB.FLAGS1_REPLY
- resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE
- resp['Tid'] = recvPacket['Tid']
- resp['Mid'] = recvPacket['Mid']
- resp['Pid'] = connData['Pid']
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX)
- respParameters = smb.SMBTreeConnectAndXResponse_Parameters()
- respData = smb.SMBTreeConnectAndXResponse_Data()
- treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters'])
- if treeConnectAndXParameters['Flags'] & 0x8:
- respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters()
- treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] )
- treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength']
- treeConnectAndXData.fromString(SMBCommand['Data'])
- errorCode = STATUS_SUCCESS
- ## Process here the request, does the share exist?
- UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path'])
- # Is this a UNC?
- if ntpath.ismount(UNCOrShare):
- path = UNCOrShare.split('\\')[3]
- else:
- path = ntpath.basename(UNCOrShare)
- share = searchShare(connId, path, smbServer)
- if share is not None:
- # Simple way to generate a Tid
- if len(connData['ConnectedShares']) == 0:
- tid = 1
- else:
- tid = connData['ConnectedShares'].keys()[-1] + 1
- connData['ConnectedShares'][tid] = share
- connData['ConnectedShares'][tid]['shareName'] = path
- resp['Tid'] = tid
- #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
- else:
- smbServer.log("TreeConnectAndX not found %s" % path, logging.ERROR)
- errorCode = STATUS_OBJECT_PATH_NOT_FOUND
- resp['ErrorCode'] = errorCode >> 16
- resp['ErrorClass'] = errorCode & 0xff
- ##
- respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS
- if path == 'IPC$':
- respData['Service'] = 'IPC'
- else:
- respData['Service'] = path
- respData['PadLen'] = 0
- respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS' )
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- resp['Uid'] = connData['Uid']
- resp.addCommand(respSMBCommand)
- smbServer.setConnectionData(connId, connData)
- return None, [resp], errorCode
- @staticmethod
- def smbComSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId, checkStatus = False)
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
- # From [MS-SMB]
- # When extended security is being used (see section 3.2.4.2.4), the
- # request MUST take the following form
- # [..]
- # WordCount (1 byte): The value of this field MUST be 0x0C.
- if SMBCommand['WordCount'] == 12:
- # Extended security. Here we deal with all SPNEGO stuff
- respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters()
- respData = smb.SMBSessionSetupAndX_Extended_Response_Data(flags = recvPacket['Flags2'])
- sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters'])
- sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data()
- sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength']
- sessionSetupData.fromString(SMBCommand['Data'])
- connData['Capabilities'] = sessionSetupParameters['Capabilities']
- rawNTLM = False
- if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_AID:
- # NEGOTIATE packet
- blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob'])
- token = blob['MechToken']
- if len(blob['MechTypes'][0]) > 0:
- # Is this GSSAPI NTLM or something else we don't support?
- mechType = blob['MechTypes'][0]
- if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
- # Nope, do we know it?
- if MechTypes.has_key(mechType):
- mechStr = MechTypes[mechType]
- else:
- mechStr = hexlify(mechType)
- smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
- # We don't know the token, we answer back again saying
- # we just support NTLM.
- # ToDo: Build this into a SPNEGO_NegTokenResp()
- respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
- respParameters['SecurityBlobLength'] = len(respToken)
- respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
- respData['SecurityBlob'] = respToken
- respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
- respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
- elif struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_SUPPORTED_MECH:
- # AUTH packet
- blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob'])
- token = blob['ResponseToken']
- else:
- # No GSSAPI stuff, raw NTLMSSP
- rawNTLM = True
- token = sessionSetupData['SecurityBlob']
- # Here we only handle NTLMSSP, depending on what stage of the
- # authentication we are, we act on it
- messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
- if messageType == 0x01:
- # NEGOTIATE_MESSAGE
- negotiateMessage = ntlm.NTLMAuthNegotiate()
- negotiateMessage.fromString(token)
- # Let's store it in the connection data
- connData['NEGOTIATE_MESSAGE'] = negotiateMessage
- # Let's build the answer flags
- # TODO: Parse all the flags. With this we're leaving some clients out
- ansFlags = 0
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
- if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
- ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
- # Generate the AV_PAIRS
- av_pairs = ntlm.AV_PAIRS()
- # TODO: Put the proper data from SMBSERVER config
- av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
- av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
- av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
- challengeMessage = ntlm.NTLMAuthChallenge()
- challengeMessage['flags'] = ansFlags
- challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
- challengeMessage['domain_max_len'] = challengeMessage['domain_len']
- challengeMessage['domain_offset'] = 40 + 16
- challengeMessage['challenge'] = smbServer.getSMBChallenge()
- challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
- challengeMessage['TargetInfoFields_len'] = len(av_pairs)
- challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
- challengeMessage['TargetInfoFields'] = av_pairs
- challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
- challengeMessage['Version'] = '\xff'*8
- challengeMessage['VersionLen'] = 8
- if rawNTLM is False:
- respToken = SPNEGO_NegTokenResp()
- # accept-incomplete. We want more data
- respToken['NegResult'] = '\x01'
- respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
- respToken['ResponseToken'] = challengeMessage.getData()
- else:
- respToken = challengeMessage
- # Setting the packet to STATUS_MORE_PROCESSING
- errorCode = STATUS_MORE_PROCESSING_REQUIRED
- # Let's set up an UID for this connection and store it
- # in the connection's data
- # Picking a fixed value
- # TODO: Manage more UIDs for the same session
- connData['Uid'] = 10
- # Let's store it in the connection data
- connData['CHALLENGE_MESSAGE'] = challengeMessage
- elif messageType == 0x02:
- # CHALLENGE_MESSAGE
- raise Exception('Challenge Message raise, not implemented!')
- elif messageType == 0x03:
- # AUTHENTICATE_MESSAGE, here we deal with authentication
- authenticateMessage = ntlm.NTLMAuthChallengeResponse()
- authenticateMessage.fromString(token)
- smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
- # TODO: Check the credentials! Now granting permissions
- respToken = SPNEGO_NegTokenResp()
- # accept-completed
- respToken['NegResult'] = '\x00'
- # Status SUCCESS
- errorCode = STATUS_SUCCESS
- smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
- # Let's store it in the connection data
- connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
- try:
- jtr_dump_path = smbServer.getJTRdumpPath()
- ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
- smbServer.log(ntlm_hash_data['hash_string'])
- if jtr_dump_path is not '':
- writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
- except:
- smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
- else:
- raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
- respParameters['SecurityBlobLength'] = len(respToken)
- respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
- respData['SecurityBlob'] = respToken.getData()
- else:
- # Process Standard Security
- respParameters = smb.SMBSessionSetupAndXResponse_Parameters()
- respData = smb.SMBSessionSetupAndXResponse_Data()
- sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters'])
- sessionSetupData = smb.SMBSessionSetupAndX_Data()
- sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength']
- sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength']
- sessionSetupData.fromString(SMBCommand['Data'])
- connData['Capabilities'] = sessionSetupParameters['Capabilities']
- # Do the verification here, for just now we grant access
- # TODO: Manage more UIDs for the same session
- errorCode = STATUS_SUCCESS
- connData['Uid'] = 10
- respParameters['Action'] = 0
- smbServer.log('User %s\\%s authenticated successfully (basic)' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account']))
- try:
- jtr_dump_path = smbServer.getJTRdumpPath()
- ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd'] )
- smbServer.log(ntlm_hash_data['hash_string'])
- if jtr_dump_path is not '':
- writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
- except:
- smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
- respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
- respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- # From now on, the client can ask for other commands
- connData['Authenticated'] = True
- # For now, just switching to nobody
- #os.setregid(65534,65534)
- #os.setreuid(65534,65534)
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smbComNegotiate(connId, smbServer, SMBCommand, recvPacket ):
- connData = smbServer.getConnectionData(connId, checkStatus = False)
- connData['Pid'] = recvPacket['Pid']
- SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)
- resp = smb.NewSMBPacket()
- resp['Flags1'] = smb.SMB.FLAGS1_REPLY
- resp['Pid'] = connData['Pid']
- resp['Tid'] = recvPacket['Tid']
- resp['Mid'] = recvPacket['Mid']
- # TODO: We support more dialects, and parse them accordingly
- dialects = SMBCommand['Data'].split('\x02')
- try:
- index = dialects.index('NT LM 0.12\x00') - 1
- # Let's fill the data for NTLM
- if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY:
- resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
- #resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS
- _dialects_data = smb.SMBExtended_Security_Data()
- _dialects_data['ServerGUID'] = 'A'*16
- blob = SPNEGO_NegTokenInit()
- blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
- _dialects_data['SecurityBlob'] = blob.getData()
- _dialects_parameters = smb.SMBExtended_Security_Parameters()
- _dialects_parameters['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS | smb.SMB.CAP_UNICODE
- _dialects_parameters['ChallengeLength'] = 0
- else:
- resp['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
- _dialects_parameters = smb.SMBNTLMDialect_Parameters()
- _dialects_data= smb.SMBNTLMDialect_Data()
- _dialects_data['Payload'] = ''
- if connData.has_key('EncryptionKey'):
- _dialects_data['Challenge'] = connData['EncryptionKey']
- _dialects_parameters['ChallengeLength'] = len(str(_dialects_data))
- else:
- # TODO: Handle random challenges, now one that can be used with rainbow tables
- _dialects_data['Challenge'] = '\x11\x22\x33\x44\x55\x66\x77\x88'
- _dialects_parameters['ChallengeLength'] = 8
- _dialects_parameters['Capabilities'] = smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS
- # Let's see if we need to support RPC_REMOTE_APIS
- config = smbServer.getServerConfig()
- if config.has_option('global','rpc_apis'):
- if config.getboolean('global', 'rpc_apis') is True:
- _dialects_parameters['Capabilities'] |= smb.SMB.CAP_RPC_REMOTE_APIS
- _dialects_parameters['DialectIndex'] = index
- _dialects_parameters['SecurityMode'] = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER
- _dialects_parameters['MaxMpxCount'] = 1
- _dialects_parameters['MaxNumberVcs'] = 1
- _dialects_parameters['MaxBufferSize'] = 64000
- _dialects_parameters['MaxRawSize'] = 65536
- _dialects_parameters['SessionKey'] = 0
- _dialects_parameters['LowDateTime'] = 0
- _dialects_parameters['HighDateTime'] = 0
- _dialects_parameters['ServerTimeZone'] = 0
- respSMBCommand['Data'] = _dialects_data
- respSMBCommand['Parameters'] = _dialects_parameters
- connData['_dialects_data'] = _dialects_data
- connData['_dialects_parameters'] = _dialects_parameters
- except Exception, e:
- # No NTLM throw an error
- smbServer.log('smbComNegotiate: %s' % e, logging.ERROR)
- respSMBCommand['Data'] = struct.pack('<H',0xffff)
- smbServer.setConnectionData(connId, connData)
- resp.addCommand(respSMBCommand)
- return None, [resp], STATUS_SUCCESS
- @staticmethod
- def default(connId, smbServer, SMBCommand, recvPacket):
- # By default we return an SMB Packet with error not implemented
- smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
- packet = smb.NewSMBPacket()
- packet['Flags1'] = smb.SMB.FLAGS1_REPLY
- packet['Flags2'] = smb.SMB.FLAGS2_NT_STATUS
- packet['Command'] = recvPacket['Command']
- packet['Pid'] = recvPacket['Pid']
- packet['Tid'] = recvPacket['Tid']
- packet['Mid'] = recvPacket['Mid']
- packet['Uid'] = recvPacket['Uid']
- packet['Data'] = '\x00\x00\x00'
- errorCode = STATUS_NOT_IMPLEMENTED
- packet['ErrorCode'] = errorCode >> 16
- packet['ErrorClass'] = errorCode & 0xff
- return None, [packet], errorCode
- class SMB2Commands:
- @staticmethod
- def smb2Negotiate(connId, smbServer, recvPacket, isSMB1 = False):
- connData = smbServer.getConnectionData(connId, checkStatus = False)
- respPacket = smb2.SMB2Packet()
- respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
- respPacket['Status'] = STATUS_SUCCESS
- respPacket['CreditRequestResponse'] = 1
- respPacket['Command'] = smb2.SMB2_NEGOTIATE
- respPacket['SessionID'] = 0
- if isSMB1 is False:
- respPacket['MessageID'] = recvPacket['MessageID']
- else:
- respPacket['MessageID'] = 0
- respPacket['TreeID'] = 0
- respSMBCommand = smb2.SMB2Negotiate_Response()
- respSMBCommand['SecurityMode'] = 1
- if isSMB1 is True:
- # Let's first parse the packet to see if the client supports SMB2
- SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
- dialects = SMBCommand['Data'].split('\x02')
- if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects:
- respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
- else:
- # Client does not support SMB2 fallbacking
- raise Exception('SMB2 not supported, fallbacking')
- else:
- respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
- respSMBCommand['ServerGuid'] = 'A'*16
- respSMBCommand['Capabilities'] = 0
- respSMBCommand['MaxTransactSize'] = 65536
- respSMBCommand['MaxReadSize'] = 65536
- respSMBCommand['MaxWriteSize'] = 65536
- respSMBCommand['SystemTime'] = getFileTime(calendar.timegm(time.gmtime()))
- respSMBCommand['ServerStartTime'] = getFileTime(calendar.timegm(time.gmtime()))
- respSMBCommand['SecurityBufferOffset'] = 0x80
- blob = SPNEGO_NegTokenInit()
- blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
- respSMBCommand['Buffer'] = blob.getData()
- respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer'])
- respPacket['Data'] = respSMBCommand
- smbServer.setConnectionData(connId, connData)
- return None, [respPacket], STATUS_SUCCESS
- @staticmethod
- def smb2SessionSetup(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId, checkStatus = False)
- respSMBCommand = smb2.SMB2SessionSetup_Response()
- sessionSetupData = smb2.SMB2SessionSetup(recvPacket['Data'])
- connData['Capabilities'] = sessionSetupData['Capabilities']
- securityBlob = sessionSetupData['Buffer']
- rawNTLM = False
- if struct.unpack('B',securityBlob[0])[0] == ASN1_AID:
- # NEGOTIATE packet
- blob = SPNEGO_NegTokenInit(securityBlob)
- token = blob['MechToken']
- if len(blob['MechTypes'][0]) > 0:
- # Is this GSSAPI NTLM or something else we don't support?
- mechType = blob['MechTypes'][0]
- if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
- # Nope, do we know it?
- if MechTypes.has_key(mechType):
- mechStr = MechTypes[mechType]
- else:
- mechStr = hexlify(mechType)
- smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
- # We don't know the token, we answer back again saying
- # we just support NTLM.
- # ToDo: Build this into a SPNEGO_NegTokenResp()
- respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
- respSMBCommand['SecurityBufferOffset'] = 0x48
- respSMBCommand['SecurityBufferLength'] = len(respToken)
- respSMBCommand['Buffer'] = respToken
- return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
- elif struct.unpack('B',securityBlob[0])[0] == ASN1_SUPPORTED_MECH:
- # AUTH packet
- blob = SPNEGO_NegTokenResp(securityBlob)
- token = blob['ResponseToken']
- else:
- # No GSSAPI stuff, raw NTLMSSP
- rawNTLM = True
- token = securityBlob
- # Here we only handle NTLMSSP, depending on what stage of the
- # authentication we are, we act on it
- messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
- if messageType == 0x01:
- # NEGOTIATE_MESSAGE
- negotiateMessage = ntlm.NTLMAuthNegotiate()
- negotiateMessage.fromString(token)
- # Let's store it in the connection data
- connData['NEGOTIATE_MESSAGE'] = negotiateMessage
- # Let's build the answer flags
- # TODO: Parse all the flags. With this we're leaving some clients out
- ansFlags = 0
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
- if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
- ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
- # Generate the AV_PAIRS
- av_pairs = ntlm.AV_PAIRS()
- # TODO: Put the proper data from SMBSERVER config
- av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
- av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
- av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
- challengeMessage = ntlm.NTLMAuthChallenge()
- challengeMessage['flags'] = ansFlags
- challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
- challengeMessage['domain_max_len'] = challengeMessage['domain_len']
- challengeMessage['domain_offset'] = 40 + 16
- challengeMessage['challenge'] = smbServer.getSMBChallenge()
- challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
- challengeMessage['TargetInfoFields_len'] = len(av_pairs)
- challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
- challengeMessage['TargetInfoFields'] = av_pairs
- challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
- challengeMessage['Version'] = '\xff'*8
- challengeMessage['VersionLen'] = 8
- if rawNTLM is False:
- respToken = SPNEGO_NegTokenResp()
- # accept-incomplete. We want more data
- respToken['NegResult'] = '\x01'
- respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
- respToken['ResponseToken'] = challengeMessage.getData()
- else:
- respToken = challengeMessage
- # Setting the packet to STATUS_MORE_PROCESSING
- errorCode = STATUS_MORE_PROCESSING_REQUIRED
- # Let's set up an UID for this connection and store it
- # in the connection's data
- # Picking a fixed value
- # TODO: Manage more UIDs for the same session
- connData['Uid'] = random.randint(1,0xffffffff)
- # Let's store it in the connection data
- connData['CHALLENGE_MESSAGE'] = challengeMessage
- elif messageType == 0x02:
- # CHALLENGE_MESSAGE
- raise Exception('Challenge Message raise, not implemented!')
- elif messageType == 0x03:
- # AUTHENTICATE_MESSAGE, here we deal with authentication
- authenticateMessage = ntlm.NTLMAuthChallengeResponse()
- authenticateMessage.fromString(token)
- smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
- # TODO: Check the credentials! Now granting permissions
- respToken = SPNEGO_NegTokenResp()
- # accept-completed
- respToken['NegResult'] = '\x00'
- # Status SUCCESS
- errorCode = STATUS_SUCCESS
- smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
- # Let's store it in the connection data
- connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
- try:
- jtr_dump_path = smbServer.getJTRdumpPath()
- ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
- smbServer.log(ntlm_hash_data['hash_string'])
- if jtr_dump_path is not '':
- writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
- except:
- smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
- respSMBCommand['SessionFlags'] = 1
- else:
- raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
- respSMBCommand['SecurityBufferOffset'] = 0x48
- respSMBCommand['SecurityBufferLength'] = len(respToken)
- respSMBCommand['Buffer'] = respToken.getData()
- # From now on, the client can ask for other commands
- connData['Authenticated'] = True
- # For now, just switching to nobody
- #os.setregid(65534,65534)
- #os.setreuid(65534,65534)
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2TreeConnect(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respPacket = smb2.SMB2Packet()
- respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
- respPacket['Status'] = STATUS_SUCCESS
- respPacket['CreditRequestResponse'] = 1
- respPacket['Command'] = recvPacket['Command']
- respPacket['SessionID'] = connData['Uid']
- respPacket['Reserved'] = recvPacket['Reserved']
- respPacket['MessageID'] = recvPacket['MessageID']
- respPacket['TreeID'] = recvPacket['TreeID']
- respSMBCommand = smb2.SMB2TreeConnect_Response()
- treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data'])
- errorCode = STATUS_SUCCESS
- ## Process here the request, does the share exist?
- path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']]
- UNCOrShare = path.decode('utf-16le')
- # Is this a UNC?
- if ntpath.ismount(UNCOrShare):
- path = UNCOrShare.split('\\')[3]
- else:
- path = ntpath.basename(UNCOrShare)
- share = searchShare(connId, path.upper(), smbServer)
- if share is not None:
- # Simple way to generate a Tid
- if len(connData['ConnectedShares']) == 0:
- tid = 1
- else:
- tid = connData['ConnectedShares'].keys()[-1] + 1
- connData['ConnectedShares'][tid] = share
- connData['ConnectedShares'][tid]['shareName'] = path
- respPacket['TreeID'] = tid
- smbServer.log("Connecting Share(%d:%s)" % (tid,path))
- else:
- smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR)
- errorCode = STATUS_OBJECT_PATH_NOT_FOUND
- respPacket['Status'] = errorCode
- ##
- if path == 'IPC$':
- respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE
- respSMBCommand['ShareFlags'] = 0x30
- else:
- respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK
- respSMBCommand['ShareFlags'] = 0x0
- respSMBCommand['Capabilities'] = 0
- respSMBCommand['MaximalAccess'] = 0x000f01ff
- respPacket['Data'] = respSMBCommand
- smbServer.setConnectionData(connId, connData)
- return None, [respPacket], errorCode
- @staticmethod
- def smb2Create(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2Create_Response()
- ntCreateRequest = smb2.SMB2Create(recvPacket['Data'])
- respSMBCommand['Buffer'] = '\x00'
- # Get the Tid associated
- if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
- # If we have a rootFid, the path is relative to that fid
- errorCode = STATUS_SUCCESS
- if connData['ConnectedShares'][recvPacket['TreeID']].has_key('path'):
- path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
- else:
- path = 'NONE'
- errorCode = STATUS_ACCESS_DENIED
- deleteOnClose = False
- fileName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- createDisposition = ntCreateRequest['CreateDisposition']
- mode = 0
- if createDisposition == smb2.FILE_SUPERSEDE:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE:
- if os.path.exists(pathName) is True:
- mode |= os.O_TRUNC
- else:
- errorCode = STATUS_NO_SUCH_FILE
- elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF:
- if os.path.exists(pathName) is True:
- mode |= os.O_TRUNC
- else:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE:
- if os.path.exists(pathName) is True:
- errorCode = STATUS_OBJECT_NAME_COLLISION
- else:
- mode |= os.O_CREAT
- elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN:
- if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
- errorCode = STATUS_NO_SUCH_FILE
- if errorCode == STATUS_SUCCESS:
- desiredAccess = ntCreateRequest['DesiredAccess']
- if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
- mode |= os.O_RDONLY
- if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE):
- if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
- mode |= os.O_RDWR #| os.O_APPEND
- else:
- mode |= os.O_WRONLY #| os.O_APPEND
- if desiredAccess & smb2.GENERIC_ALL:
- mode |= os.O_RDWR #| os.O_APPEND
- createOptions = ntCreateRequest['CreateOptions']
- if mode & os.O_CREAT == os.O_CREAT:
- if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE:
- try:
- # Let's create the directory
- os.mkdir(pathName)
- mode = os.O_RDONLY
- except Exception, e:
- smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE:
- # If the file being opened is a directory, the server MUST fail the request with
- # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
- # response.
- if os.path.isdir(pathName) is True:
- errorCode = STATUS_FILE_IS_A_DIRECTORY
- if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE:
- deleteOnClose = True
- if errorCode == STATUS_SUCCESS:
- try:
- if os.path.isdir(pathName) and sys.platform == 'win32':
- fid = VOID_FILE_DESCRIPTOR
- else:
- if sys.platform == 'win32':
- mode |= os.O_BINARY
- if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
- fid = PIPE_FILE_DESCRIPTOR
- sock = socket.socket()
- sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
- else:
- fid = os.open(pathName, mode)
- except Exception, e:
- smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
- #print e
- fid = 0
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
- if errorCode == STATUS_SUCCESS:
- # Simple way to generate a fid
- fakefid = uuid.generate()
- respSMBCommand['FileID'] = fakefid
- respSMBCommand['CreateAction'] = createDisposition
- if fid == PIPE_FILE_DESCRIPTOR:
- respSMBCommand['CreationTime'] = 0
- respSMBCommand['LastAccessTime'] = 0
- respSMBCommand['LastWriteTime'] = 0
- respSMBCommand['ChangeTime'] = 0
- respSMBCommand['AllocationSize'] = 4096
- respSMBCommand['EndOfFile'] = 0
- respSMBCommand['FileAttributes'] = 0x80
- else:
- if os.path.isdir(pathName):
- respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
- else:
- respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes']
- # Let's get this file's information
- respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
- if errorCode == STATUS_SUCCESS:
- respSMBCommand['CreationTime'] = respInfo['CreationTime']
- respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime']
- respSMBCommand['LastWriteTime'] = respInfo['LastWriteTime']
- respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime']
- respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes']
- respSMBCommand['AllocationSize'] = respInfo['AllocationSize']
- respSMBCommand['EndOfFile'] = respInfo['EndOfFile']
- if errorCode == STATUS_SUCCESS:
- # Let's store the fid for the connection
- # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
- connData['OpenedFiles'][fakefid] = {}
- connData['OpenedFiles'][fakefid]['FileHandle'] = fid
- connData['OpenedFiles'][fakefid]['FileName'] = pathName
- connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
- connData['OpenedFiles'][fakefid]['Open'] = {}
- connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0
- connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = ''
- if fid == PIPE_FILE_DESCRIPTOR:
- connData['OpenedFiles'][fakefid]['Socket'] = sock
- else:
- respSMBCommand = smb2.SMB2Error()
- if errorCode == STATUS_SUCCESS:
- connData['LastRequest']['SMB2_CREATE'] = respSMBCommand
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2Close(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2Close_Response()
- closeRequest = smb2.SMB2Close(recvPacket['Data'])
- if str(closeRequest['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if connData['LastRequest'].has_key('SMB2_CREATE'):
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(closeRequest['FileID'])
- else:
- fileID = str(closeRequest['FileID'])
- if connData['OpenedFiles'].has_key(fileID):
- errorCode = STATUS_SUCCESS
- fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
- pathName = connData['OpenedFiles'][fileID]['FileName']
- infoRecord = None
- try:
- if fileHandle == PIPE_FILE_DESCRIPTOR:
- connData['OpenedFiles'][fileID]['Socket'].close()
- elif fileHandle != VOID_FILE_DESCRIPTOR:
- os.close(fileHandle)
- infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), smb2.SMB2_FILE_NETWORK_OPEN_INFO)
- except Exception, e:
- smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
- errorCode = STATUS_INVALID_HANDLE
- else:
- # Check if the file was marked for removal
- if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True:
- try:
- if os.path.isdir(pathName):
- shutil.rmtree(connData['OpenedFiles'][fileID]['FileName'])
- else:
- os.remove(connData['OpenedFiles'][fileID]['FileName'])
- except Exception, e:
- smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- # Now fill out the response
- if infoRecord is not None:
- respSMBCommand['CreationTime'] = infoRecord['CreationTime']
- respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime']
- respSMBCommand['LastWriteTime'] = infoRecord['LastWriteTime']
- respSMBCommand['ChangeTime'] = infoRecord['ChangeTime']
- respSMBCommand['AllocationSize'] = infoRecord['AllocationSize']
- respSMBCommand['EndofFile'] = infoRecord['EndOfFile']
- respSMBCommand['FileAttributes'] = infoRecord['FileAttributes']
- if errorCode == STATUS_SUCCESS:
- del(connData['OpenedFiles'][fileID])
- else:
- errorCode = STATUS_INVALID_HANDLE
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2QueryInfo(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2QueryInfo_Response()
- queryInfo = smb2.SMB2QueryInfo(recvPacket['Data'])
- errorCode = STATUS_SUCCESS
- respSMBCommand['OutputBufferOffset'] = 0x48
- respSMBCommand['Buffer'] = '\x00'
- if str(queryInfo['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if connData['LastRequest'].has_key('SMB2_CREATE'):
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(queryInfo['FileID'])
- else:
- fileID = str(queryInfo['FileID'])
- if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
- if connData['OpenedFiles'].has_key(fileID):
- fileName = connData['OpenedFiles'][fileID]['FileName']
- if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
- if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO:
- # No need to call queryFileInformation, we have the data here
- infoRecord = smb2.FileInternalInformation()
- infoRecord['IndexNumber'] = fileID
- else:
- infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
- elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
- infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
- elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
- # Failing for now, until we support it
- infoRecord = None
- errorCode = STATUS_ACCESS_DENIED
- else:
- smbServer.log("queryInfo not supported (%x)" % queryInfo['InfoType'], logging.ERROR)
- if infoRecord is not None:
- respSMBCommand['OutputBufferLength'] = len(infoRecord)
- respSMBCommand['Buffer'] = infoRecord
- else:
- errorCode = STATUS_INVALID_HANDLE
- else:
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2SetInfo(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2SetInfo_Response()
- setInfo = smb2.SMB2SetInfo(recvPacket['Data'])
- errorCode = STATUS_SUCCESS
- if str(setInfo['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if connData['LastRequest'].has_key('SMB2_CREATE'):
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(setInfo['FileID'])
- else:
- fileID = str(setInfo['FileID'])
- if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
- path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
- if connData['OpenedFiles'].has_key(fileID):
- pathName = connData['OpenedFiles'][fileID]['FileName']
- if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
- # The file information is being set
- informationLevel = setInfo['FileInfoClass']
- if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO:
- infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer'])
- if infoRecord['DeletePending'] > 0:
- # Mark this file for removal after closed
- connData['OpenedFiles'][fileID]['DeleteOnClose'] = True
- elif informationLevel == smb2.SMB2_FILE_BASIC_INFO:
- infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer'])
- # Creation time won't be set, the other ones we play with.
- atime = infoRecord['LastWriteTime']
- if atime == 0:
- atime = -1
- else:
- atime = getUnixTime(atime)
- mtime = infoRecord['ChangeTime']
- if mtime == 0:
- mtime = -1
- else:
- mtime = getUnixTime(mtime)
- if atime > 0 and mtime > 0:
- os.utime(pathName,(atime,mtime))
- elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO:
- fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
- infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer'])
- if infoRecord['EndOfFile'] > 0:
- os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
- os.write(fileHandle, '\x00')
- elif informationLevel == smb2.SMB2_FILE_RENAME_INFO:
- renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer'])
- newPathName = os.path.join(path,renameInfo['FileName'].decode('utf-16le').replace('\\', '/'))
- if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName):
- return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION
- try:
- os.rename(pathName,newPathName)
- connData['OpenedFiles'][fileID]['FileName'] = newPathName
- except Exception, e:
- smbServer.log("smb2SetInfo: %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR)
- # UNSUPPORTED
- errorCode = STATUS_NOT_SUPPORTED
- #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
- # # The underlying object store information is being set.
- # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
- #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
- # # The security information is being set.
- # # Failing for now, until we support it
- # infoRecord = None
- # errorCode = STATUS_ACCESS_DENIED
- #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA:
- # # The underlying object store quota information is being set.
- # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
- else:
- smbServer.log("setInfo not supported (%x)" % setInfo['InfoType'], logging.ERROR)
- else:
- errorCode = STATUS_INVALID_HANDLE
- else:
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2Write(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2Write_Response()
- writeRequest = smb2.SMB2Write(recvPacket['Data'])
- respSMBCommand['Buffer'] = '\x00'
- if str(writeRequest['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if connData['LastRequest'].has_key('SMB2_CREATE'):
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(writeRequest['FileID'])
- else:
- fileID = str(writeRequest['FileID'])
- if connData['OpenedFiles'].has_key(fileID):
- fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- offset = writeRequest['Offset']
- # If we're trying to write past the file end we just skip the write call (Vista does this)
- if os.lseek(fileHandle, 0, 2) >= offset:
- os.lseek(fileHandle,offset,0)
- os.write(fileHandle,writeRequest['Buffer'])
- else:
- sock = connData['OpenedFiles'][fileID]['Socket']
- sock.send(writeRequest['Buffer'])
- respSMBCommand['Count'] = writeRequest['Length']
- respSMBCommand['Remaining']= 0xff
- except Exception, e:
- smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2Read(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2Read_Response()
- readRequest = smb2.SMB2Read(recvPacket['Data'])
- respSMBCommand['Buffer'] = '\x00'
- if str(readRequest['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if connData['LastRequest'].has_key('SMB2_CREATE'):
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(readRequest['FileID'])
- else:
- fileID = str(readRequest['FileID'])
- if connData['OpenedFiles'].has_key(fileID):
- fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
- errorCode = 0
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- offset = readRequest['Offset']
- os.lseek(fileHandle,offset,0)
- content = os.read(fileHandle,readRequest['Length'])
- else:
- sock = connData['OpenedFiles'][fileID]['Socket']
- content = sock.recv(readRequest['Length'])
- respSMBCommand['DataOffset'] = 0x50
- respSMBCommand['DataLength'] = len(content)
- respSMBCommand['DataRemaining']= 0
- respSMBCommand['Buffer'] = content
- except Exception, e:
- smbServer.log('SMB2_READ: %s ' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2Flush(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2Flush_Response()
- flushRequest = smb2.SMB2Flush(recvPacket['Data'])
- if connData['OpenedFiles'].has_key(str(flushRequest['FileID'])):
- fileHandle = connData['OpenedFiles'][str(flushRequest['FileID'])]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- os.fsync(fileHandle)
- except Exception, e:
- smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2QueryDirectory(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2QueryDirectory_Response()
- queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data'])
- respSMBCommand['Buffer'] = '\x00'
- # The server MUST locate the tree connection, as specified in section 3.3.5.2.11.
- if connData['ConnectedShares'].has_key(recvPacket['TreeID']) is False:
- return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED
- # Next, the server MUST locate the open for the directory to be queried
- # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED
- if str(queryDirectoryRequest['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if connData['LastRequest'].has_key('SMB2_CREATE'):
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(queryDirectoryRequest['FileID'])
- else:
- fileID = str(queryDirectoryRequest['FileID'])
- if connData['OpenedFiles'].has_key(fileID) is False:
- return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED
- # If the open is not an open to a directory, the request MUST be failed
- # with STATUS_INVALID_PARAMETER.
- if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False:
- return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER
- # If any other information class is specified in the FileInformationClass
- # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the
- # operation with STATUS_INVALID_INFO_CLASS.
- if queryDirectoryRequest['FileInformationClass'] not in (
- smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, smb2.FILEID_FULL_DIRECTORY_INFORMATION,
- smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, smb2.FILENAMES_INFORMATION):
- return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS
- # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY
- # Request, the server SHOULD<326> set Open.EnumerationLocation to 0
- # and Open.EnumerationSearchPattern to an empty string.
- if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN:
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
- connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = ''
- # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2
- # QUERY_DIRECTORY Request, the server MUST set
- # Open.EnumerationLocation to 0.
- if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS:
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
- # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern
- # is an empty string, then Open.EnumerationSearchPattern MUST be set
- # to the search pattern specified in the SMB2 QUERY_DIRECTORY by
- # FileNameOffset and FileNameLength. If FileNameLength is 0, the server
- # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries.
- pattern = queryDirectoryRequest['Buffer'].decode('utf-16le')
- if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \
- connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '':
- if pattern == '':
- pattern = '*'
- connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
- # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero,
- # the server MUST set Open.EnumerationSearchPattern to the search pattern
- # specified in the request by FileNameOffset and FileNameLength.
- if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \
- queryDirectoryRequest['FileNameLength'] > 0:
- connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
- pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']),pattern)
- searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName),
- os.path.basename(pathName),
- queryDirectoryRequest['FileInformationClass'],
- smb.ATTR_DIRECTORY, isSMB2 = True )
- if errorCode != STATUS_SUCCESS:
- return [smb2.SMB2Error()], None, errorCode
- if searchCount > 2 and pattern == '*':
- # strip . and ..
- searchCount -= 2
- searchResult = searchResult[2:]
- if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0:
- return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE
- if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0:
- return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES
- totalData = 0
- respData = ''
- for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount):
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1
- if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
- # If single entry is requested we must clear the NextEntryOffset
- searchResult[nItem]['NextEntryOffset'] = 0
- data = searchResult[nItem].getData()
- lenData = len(data)
- padLen = (8-(lenData % 8)) %8
- if (totalData+lenData) >= queryDirectoryRequest['OutputBufferLength']:
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1
- break
- else:
- respData += data + '\x00'*padLen
- totalData += lenData + padLen
- if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
- break
- if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount:
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1
- respSMBCommand['OutputBufferOffset'] = 0x48
- respSMBCommand['OutputBufferLength'] = totalData
- respSMBCommand['Buffer'] = respData
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2ChangeNotify(connId, smbServer, recvPacket):
- return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
- @staticmethod
- def smb2Echo(connId, smbServer, recvPacket):
- respSMBCommand = smb2.SMB2Echo_Response()
- return [respSMBCommand], None, STATUS_SUCCESS
- @staticmethod
- def smb2TreeDisconnect(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2TreeDisconnect_Response()
- if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
- smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['TreeID'],connData['ConnectedShares'][recvPacket['TreeID']]['shareName']))
- del(connData['ConnectedShares'][recvPacket['TreeID']])
- errorCode = STATUS_SUCCESS
- else:
- # STATUS_SMB_BAD_TID
- errorCode = STATUS_SMB_BAD_TID
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2Logoff(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2Logoff_Response()
- if recvPacket['SessionID'] != connData['Uid']:
- # STATUS_SMB_BAD_UID
- errorCode = STATUS_SMB_BAD_UID
- else:
- errorCode = STATUS_SUCCESS
- connData['Uid'] = 0
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2Ioctl(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2Ioctl_Response()
- ioctlRequest = smb2.SMB2Ioctl(recvPacket['Data'])
- ioctls = smbServer.getIoctls()
- if ioctls.has_key(ioctlRequest['CtlCode']):
- outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest)
- if errorCode == STATUS_SUCCESS:
- respSMBCommand['CtlCode'] = ioctlRequest['CtlCode']
- respSMBCommand['FileID'] = ioctlRequest['FileID']
- respSMBCommand['InputOffset'] = 0
- respSMBCommand['InputCount'] = 0
- respSMBCommand['OutputOffset'] = 0x70
- respSMBCommand['OutputCount'] = len(outputData)
- respSMBCommand['Flags'] = 0
- respSMBCommand['Buffer'] = outputData
- else:
- respSMBCommand = outputData
- else:
- smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'],logging.DEBUG)
- errorCode = STATUS_INVALID_DEVICE_REQUEST
- respSMBCommand = smb2.SMB2Error()
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2Lock(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2Lock_Response()
- # I'm actually doing nothing.. just make MacOS happy ;)
- errorCode = STATUS_SUCCESS
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
- @staticmethod
- def smb2Cancel(connId, smbServer, recvPacket):
- # I'm actually doing nothing
- return [smb2.SMB2Error()], None, STATUS_CANCELLED
- @staticmethod
- def default(connId, smbServer, recvPacket):
- # By default we return an SMB Packet with error not implemented
- smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
- return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
- class Ioctls:
- @staticmethod
- def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest):
- return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED
- @staticmethod
- def fsctlPipeTransceive(connId, smbServer, ioctlRequest):
- connData = smbServer.getConnectionData(connId)
- ioctlResponse = ''
- if connData['OpenedFiles'].has_key(str(ioctlRequest['FileID'])):
- fileHandle = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- errorCode = STATUS_INVALID_DEVICE_REQUEST
- else:
- sock = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['Socket']
- sock.sendall(ioctlRequest['Buffer'])
- ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse'])
- except Exception, e:
- smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_DEVICE_REQUEST
- smbServer.setConnectionData(connId, connData)
- return ioctlResponse, errorCode
- @staticmethod
- def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest):
- connData = smbServer.getConnectionData(connId)
- errorCode = STATUS_SUCCESS
- validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer'])
- validateNegotiateInfo['Capabilities'] = 0
- validateNegotiateInfo['Guid'] = 'A'*16
- validateNegotiateInfo['SecurityMode'] = 1
- validateNegotiateInfo['Dialects'] = (smb2.SMB2_DIALECT_002,)
- smbServer.setConnectionData(connId, connData)
- return validateNegotiateInfo.getData(), errorCode
- class SMBSERVERHandler(SocketServer.BaseRequestHandler):
- def __init__(self, request, client_address, server, select_poll = False):
- self.__SMB = server
- self.__ip, self.__port = client_address
- self.__request = request
- self.__connId = threading.currentThread().getName()
- self.__timeOut = 60*5
- self.__select_poll = select_poll
- #self.__connId = os.getpid()
- SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)
- def handle(self):
- self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port))
- self.__SMB.addConnection(self.__connId, self.__ip, self.__port)
- while True:
- try:
- # Firt of all let's get the NETBIOS packet
- session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(),'HOST', self.__ip, sess_port = self.__port, sock = self.__request, select_poll = self.__select_poll)
- try:
- p = session.recv_packet(self.__timeOut)
- except nmb.NetBIOSTimeout:
- raise
- except nmb.NetBIOSError:
- break
- if p.get_type() == nmb.NETBIOS_SESSION_REQUEST:
- # Someone is requesting a session, we're gonna accept them all :)
- _, rn, my = p.get_trailer().split(' ')
- remote_name = nmb.decode_name('\x20'+rn)
- myname = nmb.decode_name('\x20'+my)
- self.__SMB.log("NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1]))
- r = nmb.NetBIOSSessionPacket()
- r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE)
- r.set_trailer(p.get_trailer())
- self.__request.send(r.rawData())
- else:
- resp = self.__SMB.processRequest(self.__connId, p.get_trailer())
- # Send all the packets recevied. Except for big transactions this should be
- # a single packet
- for i in resp:
- session.send_packet(str(i))
- except Exception, e:
- self.__SMB.log("Handle: %s" % e)
- #import traceback
- #traceback.print_exc()
- break
- def finish(self):
- # Thread/process is dying, we should tell the main SMB thread to remove all this thread data
- self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port))
- self.__SMB.removeConnection(self.__connId)
- return SocketServer.BaseRequestHandler.finish(self)
- class SMBSERVER(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
- #class SMBSERVER(SocketServer.ForkingMixIn, SocketServer.TCPServer):
- def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser = None):
- SocketServer.TCPServer.allow_reuse_address = True
- SocketServer.TCPServer.__init__(self, server_address, handler_class)
- # Server name and OS to be presented whenever is necessary
- self.__serverName = ''
- self.__serverOS = ''
- self.__serverDomain = ''
- self.__challenge = ''
- self.__log = None
- # Our ConfigParser data
- self.__serverConfig = config_parser
- # Our credentials to be used during the server's lifetime
- self.__credentials = {}
- # Our log file
- self.__logFile = ''
- # Registered Named Pipes, format is PipeName,Socket
- self.__registeredNamedPipes = {}
- # JTR dump path
- self.__jtr_dump_path = ''
- # SMB2 Support flag = default not active
- self.__SMB2Support = False
- # Our list of commands we will answer, by default the NOT IMPLEMENTED one
- self.__smbCommandsHandler = SMBCommands()
- self.__smbTrans2Handler = TRANS2Commands()
- self.__smbTransHandler = TRANSCommands()
- self.__smbNTTransHandler = NTTRANSCommands()
- self.__smb2CommandsHandler = SMB2Commands()
- self.__IoctlHandler = Ioctls()
- self.__smbNTTransCommands = {
- # NT IOCTL, can't find doc for this
- 0xff :self.__smbNTTransHandler.default
- }
- self.__smbTransCommands = {
- '\\PIPE\\LANMAN' :self.__smbTransHandler.lanMan,
- smb.SMB.TRANS_TRANSACT_NMPIPE :self.__smbTransHandler.transactNamedPipe,
- }
- self.__smbTrans2Commands = {
- smb.SMB.TRANS2_FIND_FIRST2 :self.__smbTrans2Handler.findFirst2,
- smb.SMB.TRANS2_FIND_NEXT2 :self.__smbTrans2Handler.findNext2,
- smb.SMB.TRANS2_QUERY_FS_INFORMATION :self.__smbTrans2Handler.queryFsInformation,
- smb.SMB.TRANS2_QUERY_PATH_INFORMATION :self.__smbTrans2Handler.queryPathInformation,
- smb.SMB.TRANS2_QUERY_FILE_INFORMATION :self.__smbTrans2Handler.queryFileInformation,
- smb.SMB.TRANS2_SET_FILE_INFORMATION :self.__smbTrans2Handler.setFileInformation,
- smb.SMB.TRANS2_SET_PATH_INFORMATION :self.__smbTrans2Handler.setPathInformation
- }
- self.__smbCommands = {
- #smb.SMB.SMB_COM_FLUSH: self.__smbCommandsHandler.smbComFlush,
- smb.SMB.SMB_COM_CREATE_DIRECTORY: self.__smbCommandsHandler.smbComCreateDirectory,
- smb.SMB.SMB_COM_DELETE_DIRECTORY: self.__smbCommandsHandler.smbComDeleteDirectory,
- smb.SMB.SMB_COM_RENAME: self.__smbCommandsHandler.smbComRename,
- smb.SMB.SMB_COM_DELETE: self.__smbCommandsHandler.smbComDelete,
- smb.SMB.SMB_COM_NEGOTIATE: self.__smbCommandsHandler.smbComNegotiate,
- smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX,
- smb.SMB.SMB_COM_LOGOFF_ANDX: self.__smbCommandsHandler.smbComLogOffAndX,
- smb.SMB.SMB_COM_TREE_CONNECT_ANDX: self.__smbCommandsHandler.smbComTreeConnectAndX,
- smb.SMB.SMB_COM_TREE_DISCONNECT: self.__smbCommandsHandler.smbComTreeDisconnect,
- smb.SMB.SMB_COM_ECHO: self.__smbCommandsHandler.smbComEcho,
- smb.SMB.SMB_COM_QUERY_INFORMATION: self.__smbCommandsHandler.smbQueryInformation,
- smb.SMB.SMB_COM_TRANSACTION2: self.__smbCommandsHandler.smbTransaction2,
- smb.SMB.SMB_COM_TRANSACTION: self.__smbCommandsHandler.smbTransaction,
- # Not needed for now
- smb.SMB.SMB_COM_NT_TRANSACT: self.__smbCommandsHandler.smbNTTransact,
- smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk,
- smb.SMB.SMB_COM_OPEN_ANDX: self.__smbCommandsHandler.smbComOpenAndX,
- smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2,
- smb.SMB.SMB_COM_READ_ANDX: self.__smbCommandsHandler.smbComReadAndX,
- smb.SMB.SMB_COM_READ: self.__smbCommandsHandler.smbComRead,
- smb.SMB.SMB_COM_WRITE_ANDX: self.__smbCommandsHandler.smbComWriteAndX,
- smb.SMB.SMB_COM_WRITE: self.__smbCommandsHandler.smbComWrite,
- smb.SMB.SMB_COM_CLOSE: self.__smbCommandsHandler.smbComClose,
- smb.SMB.SMB_COM_LOCKING_ANDX: self.__smbCommandsHandler.smbComLockingAndX,
- smb.SMB.SMB_COM_NT_CREATE_ANDX: self.__smbCommandsHandler.smbComNtCreateAndX,
- 0xFF: self.__smbCommandsHandler.default
- }
- self.__smb2Ioctls = {
- smb2.FSCTL_DFS_GET_REFERRALS: self.__IoctlHandler.fsctlDfsGetReferrals,
- # smb2.FSCTL_PIPE_PEEK: self.__IoctlHandler.fsctlPipePeek,
- # smb2.FSCTL_PIPE_WAIT: self.__IoctlHandler.fsctlPipeWait,
- smb2.FSCTL_PIPE_TRANSCEIVE: self.__IoctlHandler.fsctlPipeTransceive,
- # smb2.FSCTL_SRV_COPYCHUNK: self.__IoctlHandler.fsctlSrvCopyChunk,
- # smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS: self.__IoctlHandler.fsctlSrvEnumerateSnapshots,
- # smb2.FSCTL_SRV_REQUEST_RESUME_KEY: self.__IoctlHandler.fsctlSrvRequestResumeKey,
- # smb2.FSCTL_SRV_READ_HASH: self.__IoctlHandler.fsctlSrvReadHash,
- # smb2.FSCTL_SRV_COPYCHUNK_WRITE: self.__IoctlHandler.fsctlSrvCopyChunkWrite,
- # smb2.FSCTL_LMR_REQUEST_RESILIENCY: self.__IoctlHandler.fsctlLmrRequestResiliency,
- # smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo,
- # smb2.FSCTL_SET_REPARSE_POINT: self.__IoctlHandler.fsctlSetReparsePoint,
- # smb2.FSCTL_DFS_GET_REFERRALS_EX: self.__IoctlHandler.fsctlDfsGetReferralsEx,
- # smb2.FSCTL_FILE_LEVEL_TRIM: self.__IoctlHandler.fsctlFileLevelTrim,
- smb2.FSCTL_VALIDATE_NEGOTIATE_INFO: self.__IoctlHandler.fsctlValidateNegotiateInfo,
- }
- self.__smb2Commands = {
- smb2.SMB2_NEGOTIATE: self.__smb2CommandsHandler.smb2Negotiate,
- smb2.SMB2_SESSION_SETUP: self.__smb2CommandsHandler.smb2SessionSetup,
- smb2.SMB2_LOGOFF: self.__smb2CommandsHandler.smb2Logoff,
- smb2.SMB2_TREE_CONNECT: self.__smb2CommandsHandler.smb2TreeConnect,
- smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect,
- smb2.SMB2_CREATE: self.__smb2CommandsHandler.smb2Create,
- smb2.SMB2_CLOSE: self.__smb2CommandsHandler.smb2Close,
- smb2.SMB2_FLUSH: self.__smb2CommandsHandler.smb2Flush,
- smb2.SMB2_READ: self.__smb2CommandsHandler.smb2Read,
- smb2.SMB2_WRITE: self.__smb2CommandsHandler.smb2Write,
- smb2.SMB2_LOCK: self.__smb2CommandsHandler.smb2Lock,
- smb2.SMB2_IOCTL: self.__smb2CommandsHandler.smb2Ioctl,
- smb2.SMB2_CANCEL: self.__smb2CommandsHandler.smb2Cancel,
- smb2.SMB2_ECHO: self.__smb2CommandsHandler.smb2Echo,
- smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory,
- smb2.SMB2_CHANGE_NOTIFY: self.__smb2CommandsHandler.smb2ChangeNotify,
- smb2.SMB2_QUERY_INFO: self.__smb2CommandsHandler.smb2QueryInfo,
- smb2.SMB2_SET_INFO: self.__smb2CommandsHandler.smb2SetInfo,
- # smb2.SMB2_OPLOCK_BREAK: self.__smb2CommandsHandler.smb2SessionSetup,
- 0xFF: self.__smb2CommandsHandler.default
- }
- # List of active connections
- self.__activeConnections = {}
- def getIoctls(self):
- return self.__smb2Ioctls
- def getCredentials(self):
- return self.__credentials
- def removeConnection(self, name):
- try:
- del(self.__activeConnections[name])
- except:
- pass
- self.log("Remaining connections %s" % self.__activeConnections.keys())
- def addConnection(self, name, ip, port):
- self.__activeConnections[name] = {}
- # Let's init with some know stuff we will need to have
- # TODO: Document what's in there
- #print "Current Connections", self.__activeConnections.keys()
- self.__activeConnections[name]['PacketNum'] = 0
- self.__activeConnections[name]['ClientIP'] = ip
- self.__activeConnections[name]['ClientPort'] = port
- self.__activeConnections[name]['Uid'] = 0
- self.__activeConnections[name]['ConnectedShares'] = {}
- self.__activeConnections[name]['OpenedFiles'] = {}
- # SID results for findfirst2
- self.__activeConnections[name]['SIDs'] = {}
- self.__activeConnections[name]['LastRequest'] = {}
- def getActiveConnections(self):
- return self.__activeConnections
- def setConnectionData(self, connId, data):
- self.__activeConnections[connId] = data
- #print "setConnectionData"
- #print self.__activeConnections
- def getConnectionData(self, connId, checkStatus = True):
- conn = self.__activeConnections[connId]
- if checkStatus is True:
- if conn.has_key('Authenticated') is not True:
- # Can't keep going further
- raise Exception("User not Authenticated!")
- return conn
- def getRegisteredNamedPipes(self):
- return self.__registeredNamedPipes
- def registerNamedPipe(self, pipeName, address):
- self.__registeredNamedPipes[unicode(pipeName)] = address
- return True
- def unregisterNamedPipe(self, pipeName):
- if self.__registeredNamedPipes.has_key(pipeName):
- del(self.__registeredNamedPipes[unicode(pipeName)])
- return True
- return False
- def unregisterTransaction(self, transCommand):
- if self.__smbTransCommands.has_key(transCommand):
- del(self.__smbTransCommands[transCommand])
- def hookTransaction(self, transCommand, callback):
- # If you call this function, callback will replace
- # the current Transaction sub command.
- # (don't get confused with the Transaction smbCommand)
- # If the transaction sub command doesn't not exist, it is added
- # If the transaction sub command exists, it returns the original function # replaced
- #
- # callback MUST be declared as:
- # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0)
- #
- # WHERE:
- #
- # connId : the connection Id, used to grab/update information about
- # the current connection
- # smbServer : the SMBServer instance available for you to ask
- # configuration data
- # recvPacket : the full SMBPacket that triggered this command
- # parameters : the transaction parameters
- # data : the transaction data
- # maxDataCount: the max amount of data that can be transfered agreed
- # with the client
- #
- # and MUST return:
- # respSetup, respParameters, respData, errorCode
- #
- # WHERE:
- #
- # respSetup: the setup response of the transaction
- # respParameters: the parameters response of the transaction
- # respData: the data reponse of the transaction
- # errorCode: the NT error code
- if self.__smbTransCommands.has_key(transCommand):
- originalCommand = self.__smbTransCommands[transCommand]
- else:
- originalCommand = None
- self.__smbTransCommands[transCommand] = callback
- return originalCommand
- def unregisterTransaction2(self, transCommand):
- if self.__smbTrans2Commands.has_key(transCommand):
- del(self.__smbTrans2Commands[transCommand])
- def hookTransaction2(self, transCommand, callback):
- # Here we should add to __smbTrans2Commands
- # Same description as Transaction
- if self.__smbTrans2Commands.has_key(transCommand):
- originalCommand = self.__smbTrans2Commands[transCommand]
- else:
- originalCommand = None
- self.__smbTrans2Commands[transCommand] = callback
- return originalCommand
- def unregisterNTTransaction(self, transCommand):
- if self.__smbNTTransCommands.has_key(transCommand):
- del(self.__smbNTTransCommands[transCommand])
- def hookNTTransaction(self, transCommand, callback):
- # Here we should add to __smbNTTransCommands
- # Same description as Transaction
- if self.__smbNTTransCommands.has_key(transCommand):
- originalCommand = self.__smbNTTransCommands[transCommand]
- else:
- originalCommand = None
- self.__smbNTTransCommands[transCommand] = callback
- return originalCommand
- def unregisterSmbCommand(self, smbCommand):
- if self.__smbCommands.has_key(smbCommand):
- del(self.__smbCommands[smbCommand])
- def hookSmbCommand(self, smbCommand, callback):
- # Here we should add to self.__smbCommands
- # If you call this function, callback will replace
- # the current smbCommand.
- # If smbCommand doesn't not exist, it is added
- # If SMB command exists, it returns the original function replaced
- #
- # callback MUST be declared as:
- # callback(connId, smbServer, SMBCommand, recvPacket)
- #
- # WHERE:
- #
- # connId : the connection Id, used to grab/update information about
- # the current connection
- # smbServer : the SMBServer instance available for you to ask
- # configuration data
- # SMBCommand: the SMBCommand itself, with its data and parameters.
- # Check smb.py:SMBCommand() for a reference
- # recvPacket: the full SMBPacket that triggered this command
- #
- # and MUST return:
- # <list of respSMBCommands>, <list of packets>, errorCode
- # <list of packets> has higher preference over commands, in case you
- # want to change the whole packet
- # errorCode: the NT error code
- #
- # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT
- # the callback function is slightly different:
- #
- # callback(connId, smbServer, SMBCommand, recvPacket, transCommands)
- #
- # WHERE:
- #
- # transCommands: a list of transaction subcommands already registered
- #
- if self.__smbCommands.has_key(smbCommand):
- originalCommand = self.__smbCommands[smbCommand]
- else:
- originalCommand = None
- self.__smbCommands[smbCommand] = callback
- return originalCommand
- def unregisterSmb2Command(self, smb2Command):
- if self.__smb2Commands.has_key(smb2Command):
- del(self.__smb2Commands[smb2Command])
- def hookSmb2Command(self, smb2Command, callback):
- if self.__smb2Commands.has_key(smb2Command):
- originalCommand = self.__smb2Commands[smb2Command]
- else:
- originalCommand = None
- self.__smb2Commands[smb2Command] = callback
- return originalCommand
- def log(self, msg, level=logging.INFO):
- self.__log.log(level,msg)
- def getServerName(self):
- return self.__serverName
- def getServerOS(self):
- return self.__serverOS
- def getServerDomain(self):
- return self.__serverDomain
- def getSMBChallenge(self):
- return self.__challenge
- def getServerConfig(self):
- return self.__serverConfig
- def setServerConfig(self, config):
- self.__serverConfig = config
- def getJTRdumpPath(self):
- return self.__jtr_dump_path
- def verify_request(self, request, client_address):
- # TODO: Control here the max amount of processes we want to launch
- # returning False, closes the connection
- return True
- def processRequest(self, connId, data):
- # TODO: Process batched commands.
- isSMB2 = False
- SMBCommand = None
- try:
- packet = smb.NewSMBPacket(data = data)
- SMBCommand = smb.SMBCommand(packet['Data'][0])
- except:
- # Maybe a SMB2 packet?
- packet = smb2.SMB2Packet(data = data)
- isSMB2 = True
- # We might have compound requests
- compoundedPacketsResponse = []
- compoundedPackets = []
- try:
- # Search out list of implemented commands
- # We provide them with:
- # connId : representing the data for this specific connection
- # self : the SMBSERVER if they want to ask data to it
- # SMBCommand : the SMBCommand they are expecting to process
- # packet : the received packet itself, in case they need more data than the actual command
- # Only for Transactions
- # transCommand: a list of transaction subcommands
- # We expect to get:
- # respCommands: a list of answers for the commands processed
- # respPacket : if the commands chose to directly craft packet/s, we use this and not the previous
- # this MUST be a list
- # errorCode : self explanatory
- if isSMB2 is False:
- if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet,
- self.__smbTrans2Commands)
- elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet,
- self.__smbNTTransCommands)
- elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet,
- self.__smbTransCommands)
- else:
- if self.__smbCommands.has_key(packet['Command']):
- if self.__SMB2Support is True:
- if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE:
- try:
- respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE](connId, self, packet, True)
- isSMB2 = True
- except Exception, e:
- self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR)
- # If something went wrong, let's fallback to SMB1
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet)
- #self.__SMB2Support = False
- pass
- else:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet)
- else:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet)
- else:
- respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, packet)
- compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
- compoundedPackets.append(packet)
- else:
- done = False
- while not done:
- if self.__smb2Commands.has_key(packet['Command']):
- if self.__SMB2Support is True:
- respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']](
- connId,
- self,
- packet)
- else:
- respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
- else:
- respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
- # Let's store the result for this compounded packet
- compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
- compoundedPackets.append(packet)
- if packet['NextCommand'] != 0:
- data = data[packet['NextCommand']:]
- packet = smb2.SMB2Packet(data = data)
- else:
- done = True
- except Exception, e:
- #import traceback
- #traceback.print_exc()
- # Something wen't wrong, defaulting to Bad user ID
- self.log('processRequest (0x%x,%s)' % (packet['Command'],e), logging.ERROR)
- raise
- # We prepare the response packet to commands don't need to bother about that.
- connData = self.getConnectionData(connId, False)
- # Force reconnection loop.. This is just a test.. client will send me back credentials :)
- #connData['PacketNum'] += 1
- #if connData['PacketNum'] == 15:
- # connData['PacketNum'] = 0
- # # Something wen't wrong, defaulting to Bad user ID
- # self.log('Sending BAD USER ID!', logging.ERROR)
- # #raise
- # packet['Flags1'] |= smb.SMB.FLAGS1_REPLY
- # packet['Flags2'] = 0
- # errorCode = STATUS_SMB_BAD_UID
- # packet['ErrorCode'] = errorCode >> 16
- # packet['ErrorClass'] = errorCode & 0xff
- # return [packet]
- self.setConnectionData(connId, connData)
- packetsToSend = []
- for packetNum in range(len(compoundedPacketsResponse)):
- respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum]
- packet = compoundedPackets[packetNum]
- if respPackets is None:
- for respCommand in respCommands:
- if isSMB2 is False:
- respPacket = smb.NewSMBPacket()
- respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY
- # TODO this should come from a per session configuration
- respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | packet['Flags2'] & smb.SMB.FLAGS2_UNICODE
- #respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES
- #respPacket['Flags1'] = 0x98
- #respPacket['Flags2'] = 0xc807
- respPacket['Tid'] = packet['Tid']
- respPacket['Mid'] = packet['Mid']
- respPacket['Pid'] = packet['Pid']
- respPacket['Uid'] = connData['Uid']
- respPacket['ErrorCode'] = errorCode >> 16
- respPacket['_reserved'] = errorCode >> 8 & 0xff
- respPacket['ErrorClass'] = errorCode & 0xff
- respPacket.addCommand(respCommand)
- packetsToSend.append(respPacket)
- else:
- respPacket = smb2.SMB2Packet()
- respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
- if packetNum > 0:
- respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS
- respPacket['Status'] = errorCode
- respPacket['CreditRequestResponse'] = packet['CreditRequestResponse']
- respPacket['Command'] = packet['Command']
- respPacket['CreditCharge'] = packet['CreditCharge']
- #respPacket['CreditCharge'] = 0
- respPacket['Reserved'] = packet['Reserved']
- respPacket['SessionID'] = connData['Uid']
- respPacket['MessageID'] = packet['MessageID']
- respPacket['TreeID'] = packet['TreeID']
- respPacket['Data'] = str(respCommand)
- packetsToSend.append(respPacket)
- else:
- # The SMBCommand took care of building the packet
- packetsToSend = respPackets
- if isSMB2 is True:
- # Let's build a compound answer
- finalData = ''
- i = 0
- for i in range(len(packetsToSend)-1):
- packet = packetsToSend[i]
- # Align to 8-bytes
- padLen = (8 - (len(packet) % 8) ) % 8
- packet['NextCommand'] = len(packet) + padLen
- finalData += str(packet) + padLen*'\x00'
- # Last one
- finalData += str(packetsToSend[len(packetsToSend)-1])
- packetsToSend = [finalData]
- # We clear the compound requests
- connData['LastRequest'] = {}
- return packetsToSend
- def processConfigFile(self, configFile = None):
- # TODO: Do a real config parser
- if self.__serverConfig is None:
- if configFile is None:
- configFile = 'smb.conf'
- self.__serverConfig = ConfigParser.ConfigParser()
- self.__serverConfig.read(configFile)
- self.__serverName = self.__serverConfig.get('global','server_name')
- self.__serverOS = self.__serverConfig.get('global','server_os')
- self.__serverDomain = self.__serverConfig.get('global','server_domain')
- self.__logFile = self.__serverConfig.get('global','log_file')
- if self.__serverConfig.has_option('global', 'challenge'):
- self.__challenge = self.__serverConfig.get('global', 'challenge')
- else:
- self.__challenge = 'A'*8
- if self.__serverConfig.has_option("global", "jtr_dump_path"):
- self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path")
- if self.__serverConfig.has_option("global", "SMB2Support"):
- self.__SMB2Support = self.__serverConfig.getboolean("global","SMB2Support")
- else:
- self.__SMB2Support = False
- if self.__logFile != 'None':
- logging.basicConfig(filename = self.__logFile,
- level = logging.DEBUG,
- format="%(asctime)s: %(levelname)s: %(message)s",
- datefmt = '%m/%d/%Y %I:%M:%S %p')
- self.__log = LOG
- # Process the credentials
- credentials_fname = self.__serverConfig.get('global','credentials_file')
- if credentials_fname is not "":
- cred = open(credentials_fname)
- line = cred.readline()
- while line:
- name, domain, lmhash, nthash = line.split(':')
- self.__credentials[name] = (domain, lmhash, nthash.strip('\r\n'))
- line = cred.readline()
- cred.close()
- self.log('Config file parsed')
- # For windows platforms, opening a directory is not an option, so we set a void FD
- VOID_FILE_DESCRIPTOR = -1
- PIPE_FILE_DESCRIPTOR = -2
|