smbserver.py 190 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174
  1. # Copyright (c) 2003-2016 CORE Security Technologies
  2. #
  3. # This software is provided under under a slightly modified version
  4. # of the Apache Software License. See the accompanying LICENSE file
  5. # for more information.
  6. #
  7. # Author: Alberto Solino (@agsolino)
  8. #
  9. # TODO:
  10. # [-] Functions should return NT error codes
  11. # [-] Handling errors in all situations, right now it's just raising exceptions.
  12. # [*] Standard authentication support
  13. # [ ] Organize the connectionData stuff
  14. # [*] Add capability to send a bad user ID if the user is not authenticated,
  15. # right now you can ask for any command without actually being authenticated
  16. # [ ] PATH TRAVERSALS EVERYWHERE.. BE WARNED!
  17. # [ ] Check the credentials.. now we're just letting everybody to log in.
  18. # [ ] Check error situation (now many places assume the right data is coming)
  19. # [ ] Implement IPC to the main process so the connectionData is on a single place
  20. # [ ] Hence.. implement locking
  21. # estamos en la B
  22. from __future__ import with_statement
  23. import calendar
  24. import socket
  25. import time
  26. import datetime
  27. import struct
  28. import ConfigParser
  29. import SocketServer
  30. import threading
  31. import logging
  32. import logging.config
  33. import ntpath
  34. import os
  35. import fnmatch
  36. import errno
  37. import sys
  38. import random
  39. import shutil
  40. from binascii import hexlify
  41. # For signing
  42. from impacket import smb, nmb, ntlm, uuid, LOG
  43. from impacket import smb3structs as smb2
  44. from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, ASN1_SUPPORTED_MECH
  45. from impacket.nt_errors import STATUS_NO_MORE_FILES, STATUS_NETWORK_NAME_DELETED, STATUS_INVALID_PARAMETER, \
  46. STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \
  47. STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \
  48. STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \
  49. STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS
  50. # These ones not defined in nt_errors
  51. STATUS_SMB_BAD_UID = 0x005B0002
  52. STATUS_SMB_BAD_TID = 0x00050002
  53. try:
  54. unicode # Python 2
  55. except NameError:
  56. unicode = str # Python 3
  57. # Utility functions
  58. # and general functions.
  59. # There are some common functions that can be accessed from more than one SMB
  60. # command (or either TRANSACTION). That's why I'm putting them here
  61. # TODO: Return NT ERROR Codes
  62. def outputToJohnFormat(challenge, username, domain, lmresponse, ntresponse):
  63. # We don't want to add a possible failure here, since this is an
  64. # extra bonus. We try, if it fails, returns nothing
  65. ret_value = ''
  66. try:
  67. if len(ntresponse) > 24:
  68. # Extended Security - NTLMv2
  69. 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'}
  70. else:
  71. # NTLMv1
  72. 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'}
  73. except:
  74. # Let's try w/o decoding Unicode
  75. try:
  76. if len(ntresponse) > 24:
  77. # Extended Security - NTLMv2
  78. ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
  79. else:
  80. # NTLMv1
  81. ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
  82. except Exception as e:
  83. LOG.error("outputToJohnFormat: %s" % e)
  84. pass
  85. return ret_value
  86. def writeJohnOutputToFile(hash_string, hash_version, file_name):
  87. fn_data = os.path.splitext(file_name)
  88. if hash_version == "ntlmv2":
  89. output_filename = fn_data[0] + "_ntlmv2" + fn_data[1]
  90. else:
  91. output_filename = fn_data[0] + "_ntlm" + fn_data[1]
  92. with open(output_filename,"a") as f:
  93. f.write(hash_string)
  94. f.write('\n')
  95. def decodeSMBString( flags, text ):
  96. if flags & smb.SMB.FLAGS2_UNICODE:
  97. return text.decode('utf-16le')
  98. else:
  99. return text
  100. def encodeSMBString( flags, text ):
  101. if flags & smb.SMB.FLAGS2_UNICODE:
  102. return (text).encode('utf-16le')
  103. else:
  104. return text
  105. def getFileTime(t):
  106. t *= 10000000
  107. t += 116444736000000000
  108. return t
  109. def getUnixTime(t):
  110. t -= 116444736000000000
  111. t /= 10000000
  112. return t
  113. def getSMBDate(t):
  114. # TODO: Fix this :P
  115. d = datetime.date.fromtimestamp(t)
  116. year = d.year - 1980
  117. ret = (year << 8) + (d.month << 4) + d.day
  118. return ret
  119. def getSMBTime(t):
  120. # TODO: Fix this :P
  121. d = datetime.datetime.fromtimestamp(t)
  122. return (d.hour << 8) + (d.minute << 4) + d.second
  123. def getShares(connId, smbServer):
  124. config = smbServer.getServerConfig()
  125. sections = config.sections()
  126. # Remove the global one
  127. del(sections[sections.index('global')])
  128. shares = {}
  129. for i in sections:
  130. shares[i] = dict(config.items(i))
  131. return shares
  132. def searchShare(connId, share, smbServer):
  133. config = smbServer.getServerConfig()
  134. if config.has_section(share):
  135. return dict(config.items(share))
  136. else:
  137. return None
  138. def openFile(path,fileName, accessMode, fileAttributes, openMode):
  139. fileName = os.path.normpath(fileName.replace('\\','/'))
  140. errorCode = 0
  141. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  142. # strip leading '/'
  143. fileName = fileName[1:]
  144. pathName = os.path.join(path,fileName)
  145. mode = 0
  146. # Check the Open Mode
  147. if openMode & 0x10:
  148. # If the file does not exist, create it.
  149. mode = os.O_CREAT
  150. else:
  151. # If file does not exist, return an error
  152. if os.path.exists(pathName) is not True:
  153. errorCode = STATUS_NO_SUCH_FILE
  154. return 0,mode, pathName, errorCode
  155. if os.path.isdir(pathName) and (fileAttributes & smb.ATTR_DIRECTORY) == 0:
  156. # Request to open a normal file and this is actually a directory
  157. errorCode = STATUS_FILE_IS_A_DIRECTORY
  158. return 0, mode, pathName, errorCode
  159. # Check the Access Mode
  160. if accessMode & 0x7 == 1:
  161. mode |= os.O_WRONLY
  162. elif accessMode & 0x7 == 2:
  163. mode |= os.O_RDWR
  164. else:
  165. mode = os.O_RDONLY
  166. try:
  167. if sys.platform == 'win32':
  168. mode |= os.O_BINARY
  169. fid = os.open(pathName, mode)
  170. except Exception as e:
  171. LOG.error("openFile: %s,%s" % (pathName, mode) ,e)
  172. fid = 0
  173. errorCode = STATUS_ACCESS_DENIED
  174. return fid, mode, pathName, errorCode
  175. def queryFsInformation(path, filename, level=0):
  176. if isinstance(filename,unicode):
  177. encoding = 'utf-16le'
  178. flags = smb.SMB.FLAGS2_UNICODE
  179. else:
  180. encoding = 'ascii'
  181. flags = 0
  182. fileName = os.path.normpath(filename.replace('\\','/'))
  183. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  184. # strip leading '/'
  185. fileName = fileName[1:]
  186. pathName = os.path.join(path,fileName)
  187. fileSize = os.path.getsize(pathName)
  188. (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
  189. if level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO:
  190. data = smb.SMBQueryFsAttributeInfo()
  191. data['FileSystemAttributes'] = smb.FILE_CASE_SENSITIVE_SEARCH | smb.FILE_CASE_PRESERVED_NAMES
  192. data['MaxFilenNameLengthInBytes'] = 255
  193. data['LengthOfFileSystemName'] = len('XTFS')*2
  194. data['FileSystemName'] = 'XTFS'.encode('utf-16le')
  195. return data.getData()
  196. elif level == smb.SMB_INFO_VOLUME:
  197. data = smb.SMBQueryFsInfoVolume( flags = flags )
  198. data['VolumeLabel'] = 'SHARE'.encode(encoding)
  199. return data.getData()
  200. elif level == smb.SMB_QUERY_FS_VOLUME_INFO or level == smb2.SMB2_FILESYSTEM_VOLUME_INFO:
  201. data = smb.SMBQueryFsVolumeInfo()
  202. data['VolumeLabel'] = ''
  203. data['VolumeCreationTime'] = getFileTime(ctime)
  204. return data.getData()
  205. elif level == smb.SMB_QUERY_FS_SIZE_INFO:
  206. data = smb.SMBQueryFsSizeInfo()
  207. return data.getData()
  208. elif level == smb.FILE_FS_FULL_SIZE_INFORMATION:
  209. data = smb.SMBFileFsFullSizeInformation()
  210. return data.getData()
  211. elif level == smb.FILE_FS_SIZE_INFORMATION:
  212. data = smb.FileFsSizeInformation()
  213. return data.getData()
  214. else:
  215. lastWriteTime = mtime
  216. attribs = 0
  217. if os.path.isdir(pathName):
  218. attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY
  219. if os.path.isfile(pathName):
  220. attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL
  221. fileAttributes = attribs
  222. return fileSize, lastWriteTime, fileAttributes
  223. def findFirst2(path, fileName, level, searchAttributes, isSMB2 = False):
  224. # TODO: Depending on the level, this could be done much simpler
  225. #print "FindFirs2 path:%s, filename:%s" % (path, fileName)
  226. fileName = os.path.normpath(fileName.replace('\\','/'))
  227. # Let's choose the right encoding depending on the request
  228. if isinstance(fileName,unicode):
  229. encoding = 'utf-16le'
  230. flags = smb.SMB.FLAGS2_UNICODE
  231. else:
  232. encoding = 'ascii'
  233. flags = 0
  234. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  235. # strip leading '/'
  236. fileName = fileName[1:]
  237. pathName = os.path.join(path,fileName)
  238. files = []
  239. if pathName.find('*') == -1 and pathName.find('?') == -1:
  240. # No search patterns
  241. pattern = ''
  242. else:
  243. pattern = os.path.basename(pathName)
  244. dirName = os.path.dirname(pathName)
  245. # Always add . and .. Not that important for Windows, but Samba whines if
  246. # not present (for * search only)
  247. if pattern == '*':
  248. files.append(os.path.join(dirName,'.'))
  249. files.append(os.path.join(dirName,'..'))
  250. if pattern != '':
  251. for file in os.listdir(dirName):
  252. if fnmatch.fnmatch(file.lower(),pattern.lower()):
  253. entry = os.path.join(dirName, file)
  254. if os.path.isdir(entry):
  255. if searchAttributes & smb.ATTR_DIRECTORY:
  256. files.append(entry)
  257. else:
  258. files.append(entry)
  259. else:
  260. if os.path.exists(pathName):
  261. files.append(pathName)
  262. searchResult = []
  263. searchCount = len(files)
  264. errorCode = STATUS_SUCCESS
  265. for i in files:
  266. if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
  267. item = smb.SMBFindFileBothDirectoryInfo( flags = flags )
  268. elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO or level == smb2.SMB2_FILE_DIRECTORY_INFO:
  269. item = smb.SMBFindFileDirectoryInfo( flags = flags )
  270. elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
  271. item = smb.SMBFindFileFullDirectoryInfo( flags = flags )
  272. elif level == smb.SMB_FIND_INFO_STANDARD:
  273. item = smb.SMBFindInfoStandard( flags = flags )
  274. elif level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO:
  275. item = smb.SMBFindFileIdFullDirectoryInfo( flags = flags )
  276. elif level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO:
  277. item = smb.SMBFindFileIdBothDirectoryInfo( flags = flags )
  278. elif level == smb.SMB_FIND_FILE_NAMES_INFO or level == smb2.SMB2_FILE_NAMES_INFO:
  279. item = smb.SMBFindFileNamesInfo( flags = flags )
  280. else:
  281. LOG.error("Wrong level %d!" % level)
  282. return searchResult, searchCount, STATUS_NOT_SUPPORTED
  283. (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(i)
  284. if os.path.isdir(i):
  285. item['ExtFileAttributes'] = smb.ATTR_DIRECTORY
  286. else:
  287. item['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
  288. item['FileName'] = os.path.basename(i).encode(encoding)
  289. 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:
  290. item['EaSize'] = 0
  291. item['EndOfFile'] = size
  292. item['AllocationSize'] = size
  293. item['CreationTime'] = getFileTime(ctime)
  294. item['LastAccessTime'] = getFileTime(atime)
  295. item['LastWriteTime'] = getFileTime(mtime)
  296. item['LastChangeTime'] = getFileTime(mtime)
  297. item['ShortName'] = '\x00'*24
  298. item['FileName'] = os.path.basename(i).encode(encoding)
  299. padLen = (8-(len(item) % 8)) % 8
  300. item['NextEntryOffset'] = len(item) + padLen
  301. elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO:
  302. item['EndOfFile'] = size
  303. item['AllocationSize'] = size
  304. item['CreationTime'] = getFileTime(ctime)
  305. item['LastAccessTime'] = getFileTime(atime)
  306. item['LastWriteTime'] = getFileTime(mtime)
  307. item['LastChangeTime'] = getFileTime(mtime)
  308. item['FileName'] = os.path.basename(i).encode(encoding)
  309. padLen = (8-(len(item) % 8)) % 8
  310. item['NextEntryOffset'] = len(item) + padLen
  311. 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:
  312. item['EaSize'] = 0
  313. item['EndOfFile'] = size
  314. item['AllocationSize'] = size
  315. item['CreationTime'] = getFileTime(ctime)
  316. item['LastAccessTime'] = getFileTime(atime)
  317. item['LastWriteTime'] = getFileTime(mtime)
  318. item['LastChangeTime'] = getFileTime(mtime)
  319. padLen = (8-(len(item) % 8)) % 8
  320. item['NextEntryOffset'] = len(item) + padLen
  321. elif level == smb.SMB_FIND_INFO_STANDARD:
  322. item['EaSize'] = size
  323. item['CreationDate'] = getSMBDate(ctime)
  324. item['CreationTime'] = getSMBTime(ctime)
  325. item['LastAccessDate'] = getSMBDate(atime)
  326. item['LastAccessTime'] = getSMBTime(atime)
  327. item['LastWriteDate'] = getSMBDate(mtime)
  328. item['LastWriteTime'] = getSMBTime(mtime)
  329. searchResult.append(item)
  330. # No more files
  331. if (level >= smb.SMB_FIND_FILE_DIRECTORY_INFO or isSMB2 == True) and searchCount > 0:
  332. searchResult[-1]['NextEntryOffset'] = 0
  333. return searchResult, searchCount, errorCode
  334. def queryFileInformation(path, filename, level):
  335. #print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
  336. return queryPathInformation(path,filename, level)
  337. def queryPathInformation(path, filename, level):
  338. # TODO: Depending on the level, this could be done much simpler
  339. #print "queryPathInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
  340. try:
  341. errorCode = 0
  342. fileName = os.path.normpath(filename.replace('\\','/'))
  343. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
  344. # strip leading '/'
  345. fileName = fileName[1:]
  346. pathName = os.path.join(path,fileName)
  347. if os.path.exists(pathName):
  348. (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
  349. if level == smb.SMB_QUERY_FILE_BASIC_INFO:
  350. infoRecord = smb.SMBQueryFileBasicInfo()
  351. infoRecord['CreationTime'] = getFileTime(ctime)
  352. infoRecord['LastAccessTime'] = getFileTime(atime)
  353. infoRecord['LastWriteTime'] = getFileTime(mtime)
  354. infoRecord['LastChangeTime'] = getFileTime(mtime)
  355. if os.path.isdir(pathName):
  356. infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
  357. else:
  358. infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
  359. elif level == smb.SMB_QUERY_FILE_STANDARD_INFO:
  360. infoRecord = smb.SMBQueryFileStandardInfo()
  361. infoRecord['AllocationSize'] = size
  362. infoRecord['EndOfFile'] = size
  363. if os.path.isdir(pathName):
  364. infoRecord['Directory'] = 1
  365. else:
  366. infoRecord['Directory'] = 0
  367. elif level == smb.SMB_QUERY_FILE_ALL_INFO or level == smb2.SMB2_FILE_ALL_INFO:
  368. infoRecord = smb.SMBQueryFileAllInfo()
  369. infoRecord['CreationTime'] = getFileTime(ctime)
  370. infoRecord['LastAccessTime'] = getFileTime(atime)
  371. infoRecord['LastWriteTime'] = getFileTime(mtime)
  372. infoRecord['LastChangeTime'] = getFileTime(mtime)
  373. if os.path.isdir(pathName):
  374. infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
  375. else:
  376. infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
  377. infoRecord['AllocationSize'] = size
  378. infoRecord['EndOfFile'] = size
  379. if os.path.isdir(pathName):
  380. infoRecord['Directory'] = 1
  381. else:
  382. infoRecord['Directory'] = 0
  383. infoRecord['FileName'] = filename.encode('utf-16le')
  384. elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO:
  385. infoRecord = smb.SMBFileNetworkOpenInfo()
  386. infoRecord['CreationTime'] = getFileTime(ctime)
  387. infoRecord['LastAccessTime'] = getFileTime(atime)
  388. infoRecord['LastWriteTime'] = getFileTime(mtime)
  389. infoRecord['ChangeTime'] = getFileTime(mtime)
  390. infoRecord['AllocationSize'] = size
  391. infoRecord['EndOfFile'] = size
  392. if os.path.isdir(pathName):
  393. infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY
  394. else:
  395. infoRecord['FileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
  396. elif level == smb.SMB_QUERY_FILE_EA_INFO or level == smb2.SMB2_FILE_EA_INFO:
  397. infoRecord = smb.SMBQueryFileEaInfo()
  398. elif level == smb2.SMB2_FILE_STREAM_INFO:
  399. infoRecord = smb.SMBFileStreamInformation()
  400. else:
  401. LOG.error('Unknown level for query path info! 0x%x' % level)
  402. # UNSUPPORTED
  403. return None, STATUS_NOT_SUPPORTED
  404. return infoRecord, errorCode
  405. else:
  406. # NOT FOUND
  407. return None, STATUS_OBJECT_NAME_NOT_FOUND
  408. except Exception as e:
  409. LOG.error('queryPathInfo: %s' % e)
  410. raise
  411. def queryDiskInformation(path):
  412. # TODO: Do something useful here :)
  413. # For now we just return fake values
  414. totalUnits = 65535
  415. freeUnits = 65535
  416. return totalUnits, freeUnits
  417. # Here we implement the NT transaction handlers
  418. class NTTRANSCommands:
  419. def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  420. pass
  421. # Here we implement the NT transaction handlers
  422. class TRANSCommands:
  423. @staticmethod
  424. def lanMan(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  425. # Minimal [MS-RAP] implementation, just to return the shares
  426. connData = smbServer.getConnectionData(connId)
  427. respSetup = ''
  428. respParameters = ''
  429. respData = ''
  430. errorCode = STATUS_SUCCESS
  431. if struct.unpack('<H',parameters[:2])[0] == 0:
  432. # NetShareEnum Request
  433. netShareEnum = smb.SMBNetShareEnum(parameters)
  434. if netShareEnum['InfoLevel'] == 1:
  435. shares = getShares(connId, smbServer)
  436. respParameters = smb.SMBNetShareEnumResponse()
  437. respParameters['EntriesReturned'] = len(shares)
  438. respParameters['EntriesAvailable'] = len(shares)
  439. tailData = ''
  440. for i in shares:
  441. # NetShareInfo1 len == 20
  442. entry = smb.NetShareInfo1()
  443. entry['NetworkName'] = i + '\x00'*(13-len(i))
  444. entry['Type'] = int(shares[i]['share type'])
  445. # (beto) If offset == 0 it crashes explorer.exe on windows 7
  446. entry['RemarkOffsetLow'] = 20 * len(shares) + len(tailData)
  447. respData += entry.getData()
  448. if 'comment' in shares[i]:
  449. tailData += shares[i]['comment'] + '\x00'
  450. else:
  451. tailData += '\x00'
  452. respData += tailData
  453. else:
  454. # We don't support other info levels
  455. errorCode = STATUS_NOT_SUPPORTED
  456. elif struct.unpack('<H',parameters[:2])[0] == 13:
  457. # NetrServerGetInfo Request
  458. respParameters = smb.SMBNetServerGetInfoResponse()
  459. netServerInfo = smb.SMBNetServerInfo1()
  460. netServerInfo['ServerName'] = smbServer.getServerName()
  461. respData = str(netServerInfo)
  462. respParameters['TotalBytesAvailable'] = len(respData)
  463. elif struct.unpack('<H',parameters[:2])[0] == 1:
  464. # NetrShareGetInfo Request
  465. request = smb.SMBNetShareGetInfo(parameters)
  466. respParameters = smb.SMBNetShareGetInfoResponse()
  467. shares = getShares(connId, smbServer)
  468. share = shares[request['ShareName'].upper()]
  469. shareInfo = smb.NetShareInfo1()
  470. shareInfo['NetworkName'] = request['ShareName'].upper() + '\x00'
  471. shareInfo['Type'] = int(share['share type'])
  472. respData = shareInfo.getData()
  473. if 'comment' in share:
  474. shareInfo['RemarkOffsetLow'] = len(respData)
  475. respData += share['comment'] + '\x00'
  476. respParameters['TotalBytesAvailable'] = len(respData)
  477. else:
  478. # We don't know how to handle anything else
  479. errorCode = STATUS_NOT_SUPPORTED
  480. smbServer.setConnectionData(connId, connData)
  481. return respSetup, respParameters, respData, errorCode
  482. @staticmethod
  483. def transactNamedPipe(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  484. connData = smbServer.getConnectionData(connId)
  485. respSetup = ''
  486. respParameters = ''
  487. respData = ''
  488. errorCode = STATUS_SUCCESS
  489. SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
  490. transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
  491. # Extract the FID
  492. fid = struct.unpack('<H', transParameters['Setup'][2:])[0]
  493. if fid in connData['OpenedFiles']:
  494. fileHandle = connData['OpenedFiles'][fid]['FileHandle']
  495. if fileHandle != PIPE_FILE_DESCRIPTOR:
  496. os.write(fileHandle,data)
  497. respData = os.read(fileHandle,data)
  498. else:
  499. sock = connData['OpenedFiles'][fid]['Socket']
  500. sock.send(data)
  501. respData = sock.recv(maxDataCount)
  502. else:
  503. errorCode = STATUS_INVALID_HANDLE
  504. smbServer.setConnectionData(connId, connData)
  505. return respSetup, respParameters, respData, errorCode
  506. # Here we implement the transaction2 handlers
  507. class TRANS2Commands:
  508. # All these commands return setup, parameters, data, errorCode
  509. @staticmethod
  510. def setPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  511. connData = smbServer.getConnectionData(connId)
  512. respSetup = ''
  513. respParameters = ''
  514. respData = ''
  515. errorCode = STATUS_SUCCESS
  516. setPathInfoParameters = smb.SMBSetPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
  517. if recvPacket['Tid'] in connData['ConnectedShares']:
  518. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  519. fileName = decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName'])
  520. fileName = os.path.normpath(fileName.replace('\\','/'))
  521. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
  522. # strip leading '/'
  523. fileName = fileName[1:]
  524. pathName = os.path.join(path,fileName)
  525. if os.path.exists(pathName):
  526. informationLevel = setPathInfoParameters['InformationLevel']
  527. if informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
  528. infoRecord = smb.SMBSetFileBasicInfo(data)
  529. # Creation time won't be set, the other ones we play with.
  530. atime = infoRecord['LastAccessTime']
  531. if atime == 0:
  532. atime = -1
  533. else:
  534. atime = getUnixTime(atime)
  535. mtime = infoRecord['LastWriteTime']
  536. if mtime == 0:
  537. mtime = -1
  538. else:
  539. mtime = getUnixTime(mtime)
  540. if mtime != -1 or atime != -1:
  541. os.utime(pathName,(atime,mtime))
  542. else:
  543. smbServer.log('Unknown level for set path info! 0x%x' % setPathInfoParameters['InformationLevel'], logging.ERROR)
  544. # UNSUPPORTED
  545. errorCode = STATUS_NOT_SUPPORTED
  546. else:
  547. errorCode = STATUS_OBJECT_NAME_NOT_FOUND
  548. if errorCode == STATUS_SUCCESS:
  549. respParameters = smb.SMBSetPathInformationResponse_Parameters()
  550. else:
  551. errorCode = STATUS_SMB_BAD_TID
  552. smbServer.setConnectionData(connId, connData)
  553. return respSetup, respParameters, respData, errorCode
  554. @staticmethod
  555. def setFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  556. connData = smbServer.getConnectionData(connId)
  557. respSetup = ''
  558. respParameters = ''
  559. respData = ''
  560. errorCode = STATUS_SUCCESS
  561. setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters)
  562. if recvPacket['Tid'] in connData['ConnectedShares']:
  563. if setFileInfoParameters['FID'] in connData['OpenedFiles']:
  564. fileName = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileName']
  565. informationLevel = setFileInfoParameters['InformationLevel']
  566. if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO:
  567. infoRecord = smb.SMBSetFileDispositionInfo(parameters)
  568. if infoRecord['DeletePending'] > 0:
  569. # Mark this file for removal after closed
  570. connData['OpenedFiles'][setFileInfoParameters['FID']]['DeleteOnClose'] = True
  571. respParameters = smb.SMBSetFileInformationResponse_Parameters()
  572. elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
  573. infoRecord = smb.SMBSetFileBasicInfo(data)
  574. # Creation time won't be set, the other ones we play with.
  575. atime = infoRecord['LastAccessTime']
  576. if atime == 0:
  577. atime = -1
  578. else:
  579. atime = getUnixTime(atime)
  580. mtime = infoRecord['LastWriteTime']
  581. if mtime == 0:
  582. mtime = -1
  583. else:
  584. mtime = getUnixTime(mtime)
  585. os.utime(fileName,(atime,mtime))
  586. elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO:
  587. fileHandle = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileHandle']
  588. infoRecord = smb.SMBSetFileEndOfFileInfo(data)
  589. if infoRecord['EndOfFile'] > 0:
  590. os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
  591. os.write(fileHandle, '\x00')
  592. else:
  593. smbServer.log('Unknown level for set file info! 0x%x' % setFileInfoParameters['InformationLevel'], logging.ERROR)
  594. # UNSUPPORTED
  595. errorCode = STATUS_NOT_SUPPORTED
  596. else:
  597. errorCode = STATUS_NO_SUCH_FILE
  598. if errorCode == STATUS_SUCCESS:
  599. respParameters = smb.SMBSetFileInformationResponse_Parameters()
  600. else:
  601. errorCode = STATUS_SMB_BAD_TID
  602. smbServer.setConnectionData(connId, connData)
  603. return respSetup, respParameters, respData, errorCode
  604. @staticmethod
  605. def queryFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  606. connData = smbServer.getConnectionData(connId)
  607. respSetup = ''
  608. respParameters = ''
  609. respData = ''
  610. queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters)
  611. if recvPacket['Tid'] in connData['ConnectedShares']:
  612. if queryFileInfoParameters['FID'] in connData['OpenedFiles']:
  613. fileName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName']
  614. infoRecord, errorCode = queryFileInformation('', fileName, queryFileInfoParameters['InformationLevel'])
  615. if infoRecord is not None:
  616. respParameters = smb.SMBQueryFileInformationResponse_Parameters()
  617. respData = infoRecord
  618. else:
  619. errorCode = STATUS_INVALID_HANDLE
  620. else:
  621. errorCode = STATUS_SMB_BAD_TID
  622. smbServer.setConnectionData(connId, connData)
  623. return respSetup, respParameters, respData, errorCode
  624. @staticmethod
  625. def queryPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  626. connData = smbServer.getConnectionData(connId)
  627. respSetup = ''
  628. respParameters = ''
  629. respData = ''
  630. errorCode = 0
  631. queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
  632. if recvPacket['Tid'] in connData['ConnectedShares']:
  633. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  634. try:
  635. infoRecord, errorCode = queryPathInformation(path, decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']), queryPathInfoParameters['InformationLevel'])
  636. except Exception as e:
  637. smbServer.log("queryPathInformation: %s" % e,logging.ERROR)
  638. if infoRecord is not None:
  639. respParameters = smb.SMBQueryPathInformationResponse_Parameters()
  640. respData = infoRecord
  641. else:
  642. errorCode = STATUS_SMB_BAD_TID
  643. smbServer.setConnectionData(connId, connData)
  644. return respSetup, respParameters, respData, errorCode
  645. @staticmethod
  646. def queryFsInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  647. connData = smbServer.getConnectionData(connId)
  648. errorCode = 0
  649. # Get the Tid associated
  650. if recvPacket['Tid'] in connData['ConnectedShares']:
  651. data = queryFsInformation(connData['ConnectedShares'][recvPacket['Tid']]['path'], '', struct.unpack('<H',parameters)[0])
  652. smbServer.setConnectionData(connId, connData)
  653. return '','', data, errorCode
  654. @staticmethod
  655. def findNext2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
  656. connData = smbServer.getConnectionData(connId)
  657. respSetup = ''
  658. respParameters = ''
  659. respData = ''
  660. errorCode = STATUS_SUCCESS
  661. findNext2Parameters = smb.SMBFindNext2_Parameters(flags = recvPacket['Flags2'], data = parameters)
  662. sid = findNext2Parameters['SID']
  663. if recvPacket['Tid'] in connData['ConnectedShares']:
  664. if sid in connData['SIDs']:
  665. searchResult = connData['SIDs'][sid]
  666. respParameters = smb.SMBFindNext2Response_Parameters()
  667. endOfSearch = 1
  668. searchCount = 1
  669. totalData = 0
  670. for i in enumerate(searchResult):
  671. data = i[1].getData()
  672. lenData = len(data)
  673. if (totalData+lenData) >= maxDataCount or (i[0]+1) >= findNext2Parameters['SearchCount']:
  674. # We gotta stop here and continue on a find_next2
  675. endOfSearch = 0
  676. connData['SIDs'][sid] = searchResult[i[0]:]
  677. respParameters['LastNameOffset'] = totalData
  678. break
  679. else:
  680. searchCount +=1
  681. respData += data
  682. totalData += lenData
  683. # Have we reached the end of the search or still stuff to send?
  684. if endOfSearch > 0:
  685. # Let's remove the SID from our ConnData
  686. del(connData['SIDs'][sid])
  687. respParameters['EndOfSearch'] = endOfSearch
  688. respParameters['SearchCount'] = searchCount
  689. else:
  690. errorCode = STATUS_INVALID_HANDLE
  691. else:
  692. errorCode = STATUS_SMB_BAD_TID
  693. smbServer.setConnectionData(connId, connData)
  694. return respSetup, respParameters, respData, errorCode
  695. @staticmethod
  696. def findFirst2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
  697. connData = smbServer.getConnectionData(connId)
  698. respSetup = ''
  699. respParameters = ''
  700. respData = ''
  701. findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters)
  702. if recvPacket['Tid'] in connData['ConnectedShares']:
  703. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  704. searchResult, searchCount, errorCode = findFirst2(path,
  705. decodeSMBString( recvPacket['Flags2'], findFirst2Parameters['FileName'] ),
  706. findFirst2Parameters['InformationLevel'],
  707. findFirst2Parameters['SearchAttributes'] )
  708. respParameters = smb.SMBFindFirst2Response_Parameters()
  709. endOfSearch = 1
  710. sid = 0x80 # default SID
  711. searchCount = 0
  712. totalData = 0
  713. for i in enumerate(searchResult):
  714. #i[1].dump()
  715. data = i[1].getData()
  716. lenData = len(data)
  717. if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']:
  718. # We gotta stop here and continue on a find_next2
  719. endOfSearch = 0
  720. # Simple way to generate a fid
  721. if len(connData['SIDs']) == 0:
  722. sid = 1
  723. else:
  724. sid = connData['SIDs'].keys()[-1] + 1
  725. # Store the remaining search results in the ConnData SID
  726. connData['SIDs'][sid] = searchResult[i[0]:]
  727. respParameters['LastNameOffset'] = totalData
  728. break
  729. else:
  730. searchCount +=1
  731. respData += data
  732. padLen = (8-(lenData % 8)) %8
  733. respData += '\xaa'*padLen
  734. totalData += lenData + padLen
  735. respParameters['SID'] = sid
  736. respParameters['EndOfSearch'] = endOfSearch
  737. respParameters['SearchCount'] = searchCount
  738. else:
  739. errorCode = STATUS_SMB_BAD_TID
  740. smbServer.setConnectionData(connId, connData)
  741. return respSetup, respParameters, respData, errorCode
  742. # Here we implement the commands handlers
  743. class SMBCommands:
  744. @staticmethod
  745. def smbTransaction(connId, smbServer, SMBCommand, recvPacket, transCommands):
  746. connData = smbServer.getConnectionData(connId)
  747. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  748. transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
  749. # Do the stuff
  750. if transParameters['ParameterCount'] != transParameters['TotalParameterCount']:
  751. # TODO: Handle partial parameters
  752. raise Exception("Unsupported partial parameters in TRANSACT2!")
  753. else:
  754. transData = smb.SMBTransaction_SData(flags = recvPacket['Flags2'])
  755. # Standard says servers shouldn't trust Parameters and Data comes
  756. # in order, so we have to parse the offsets, ugly
  757. paramCount = transParameters['ParameterCount']
  758. transData['Trans_ParametersLength'] = paramCount
  759. dataCount = transParameters['DataCount']
  760. transData['Trans_DataLength'] = dataCount
  761. transData.fromString(SMBCommand['Data'])
  762. if transParameters['ParameterOffset'] > 0:
  763. paramOffset = transParameters['ParameterOffset'] - 63 - transParameters['SetupLength']
  764. transData['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
  765. else:
  766. transData['Trans_Parameters'] = ''
  767. if transParameters['DataOffset'] > 0:
  768. dataOffset = transParameters['DataOffset'] - 63 - transParameters['SetupLength']
  769. transData['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
  770. else:
  771. transData['Trans_Data'] = ''
  772. # Call the handler for this TRANSACTION
  773. if transParameters['SetupCount'] == 0:
  774. # No subcommand, let's play with the Name
  775. command = decodeSMBString(recvPacket['Flags2'],transData['Name'])
  776. else:
  777. command = struct.unpack('<H', transParameters['Setup'][:2])[0]
  778. if command in transCommands:
  779. # Call the TRANS subcommand
  780. setup = ''
  781. parameters = ''
  782. data = ''
  783. try:
  784. setup, parameters, data, errorCode = transCommands[command](connId,
  785. smbServer,
  786. recvPacket,
  787. transData['Trans_Parameters'],
  788. transData['Trans_Data'],
  789. transParameters['MaxDataCount'])
  790. except Exception as e:
  791. #print 'Transaction: %s' % e,e
  792. smbServer.log('Transaction: (%r,%s)' % (command, e), logging.ERROR)
  793. errorCode = STATUS_ACCESS_DENIED
  794. #raise
  795. if setup == '' and parameters == '' and data == '':
  796. # Something wen't wrong
  797. respParameters = ''
  798. respData = ''
  799. else:
  800. # Build the answer
  801. data = str(data)
  802. remainingData = len(data)
  803. parameters = str(parameters)
  804. remainingParameters = len(parameters)
  805. commands = []
  806. dataDisplacement = 0
  807. while remainingData > 0 or remainingParameters > 0:
  808. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  809. respParameters = smb.SMBTransactionResponse_Parameters()
  810. respData = smb.SMBTransaction2Response_Data()
  811. respParameters['TotalParameterCount'] = len(parameters)
  812. respParameters['ParameterCount'] = len(parameters)
  813. respData['Trans_ParametersLength'] = len(parameters)
  814. respParameters['TotalDataCount'] = len(data)
  815. respParameters['DataDisplacement'] = dataDisplacement
  816. # TODO: Do the same for parameters
  817. if len(data) > transParameters['MaxDataCount']:
  818. # Answer doesn't fit in this packet
  819. LOG.debug("Lowering answer from %d to %d" % (len(data),transParameters['MaxDataCount']) )
  820. respParameters['DataCount'] = transParameters['MaxDataCount']
  821. else:
  822. respParameters['DataCount'] = len(data)
  823. respData['Trans_DataLength'] = respParameters['DataCount']
  824. respParameters['SetupCount'] = len(setup)
  825. respParameters['Setup'] = setup
  826. # TODO: Make sure we're calculating the pad right
  827. if len(parameters) > 0:
  828. #padLen = 4 - (55 + len(setup)) % 4
  829. padLen = (4 - (55 + len(setup)) % 4 ) % 4
  830. padBytes = '\xFF' * padLen
  831. respData['Pad1'] = padBytes
  832. respParameters['ParameterOffset'] = 55 + len(setup) + padLen
  833. else:
  834. padLen = 0
  835. respParameters['ParameterOffset'] = 0
  836. respData['Pad1'] = ''
  837. if len(data) > 0:
  838. #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
  839. pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
  840. respData['Pad2'] = '\xFF' * pad2Len
  841. respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
  842. else:
  843. respParameters['DataOffset'] = 0
  844. respData['Pad2'] = ''
  845. respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
  846. respData['Trans_Data'] = data[:respParameters['DataCount']]
  847. respSMBCommand['Parameters'] = respParameters
  848. respSMBCommand['Data'] = respData
  849. data = data[respParameters['DataCount']:]
  850. remainingData -= respParameters['DataCount']
  851. dataDisplacement += respParameters['DataCount'] + 1
  852. parameters = parameters[respParameters['ParameterCount']:]
  853. remainingParameters -= respParameters['ParameterCount']
  854. commands.append(respSMBCommand)
  855. smbServer.setConnectionData(connId, connData)
  856. return commands, None, errorCode
  857. else:
  858. smbServer.log("Unsupported Transact command %r" % command, logging.ERROR)
  859. respParameters = ''
  860. respData = ''
  861. errorCode = STATUS_NOT_IMPLEMENTED
  862. respSMBCommand['Parameters'] = respParameters
  863. respSMBCommand['Data'] = respData
  864. smbServer.setConnectionData(connId, connData)
  865. return [respSMBCommand], None, errorCode
  866. @staticmethod
  867. def smbNTTransact(connId, smbServer, SMBCommand, recvPacket, transCommands):
  868. connData = smbServer.getConnectionData(connId)
  869. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  870. NTTransParameters= smb.SMBNTTransaction_Parameters(SMBCommand['Parameters'])
  871. # Do the stuff
  872. if NTTransParameters['ParameterCount'] != NTTransParameters['TotalParameterCount']:
  873. # TODO: Handle partial parameters
  874. raise Exception("Unsupported partial parameters in NTTrans!")
  875. else:
  876. NTTransData = smb.SMBNTTransaction_Data()
  877. # Standard says servers shouldn't trust Parameters and Data comes
  878. # in order, so we have to parse the offsets, ugly
  879. paramCount = NTTransParameters['ParameterCount']
  880. NTTransData['NT_Trans_ParametersLength'] = paramCount
  881. dataCount = NTTransParameters['DataCount']
  882. NTTransData['NT_Trans_DataLength'] = dataCount
  883. if NTTransParameters['ParameterOffset'] > 0:
  884. paramOffset = NTTransParameters['ParameterOffset'] - 73 - NTTransParameters['SetupLength']
  885. NTTransData['NT_Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
  886. else:
  887. NTTransData['NT_Trans_Parameters'] = ''
  888. if NTTransParameters['DataOffset'] > 0:
  889. dataOffset = NTTransParameters['DataOffset'] - 73 - NTTransParameters['SetupLength']
  890. NTTransData['NT_Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
  891. else:
  892. NTTransData['NT_Trans_Data'] = ''
  893. # Call the handler for this TRANSACTION
  894. command = NTTransParameters['Function']
  895. if command in transCommands:
  896. # Call the NT TRANS subcommand
  897. setup = ''
  898. parameters = ''
  899. data = ''
  900. try:
  901. setup, parameters, data, errorCode = transCommands[command](connId,
  902. smbServer,
  903. recvPacket,
  904. NTTransData['NT_Trans_Parameters'],
  905. NTTransData['NT_Trans_Data'],
  906. NTTransParameters['MaxDataCount'])
  907. except Exception as e:
  908. smbServer.log('NTTransaction: (0x%x,%s)' % (command, e), logging.ERROR)
  909. errorCode = STATUS_ACCESS_DENIED
  910. #raise
  911. if setup == '' and parameters == '' and data == '':
  912. # Something wen't wrong
  913. respParameters = ''
  914. respData = ''
  915. if errorCode == STATUS_SUCCESS:
  916. errorCode = STATUS_ACCESS_DENIED
  917. else:
  918. # Build the answer
  919. data = str(data)
  920. remainingData = len(data)
  921. parameters = str(parameters)
  922. remainingParameters = len(parameters)
  923. commands = []
  924. dataDisplacement = 0
  925. while remainingData > 0 or remainingParameters > 0:
  926. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  927. respParameters = smb.SMBNTTransactionResponse_Parameters()
  928. respData = smb.SMBNTTransactionResponse_Data()
  929. respParameters['TotalParameterCount'] = len(parameters)
  930. respParameters['ParameterCount'] = len(parameters)
  931. respData['Trans_ParametersLength'] = len(parameters)
  932. respParameters['TotalDataCount'] = len(data)
  933. respParameters['DataDisplacement'] = dataDisplacement
  934. # TODO: Do the same for parameters
  935. if len(data) > NTTransParameters['MaxDataCount']:
  936. # Answer doesn't fit in this packet
  937. LOG.debug("Lowering answer from %d to %d" % (len(data),NTTransParameters['MaxDataCount']) )
  938. respParameters['DataCount'] = NTTransParameters['MaxDataCount']
  939. else:
  940. respParameters['DataCount'] = len(data)
  941. respData['NT_Trans_DataLength'] = respParameters['DataCount']
  942. respParameters['SetupCount'] = len(setup)
  943. respParameters['Setup'] = setup
  944. # TODO: Make sure we're calculating the pad right
  945. if len(parameters) > 0:
  946. #padLen = 4 - (71 + len(setup)) % 4
  947. padLen = (4 - (73 + len(setup)) % 4 ) % 4
  948. padBytes = '\xFF' * padLen
  949. respData['Pad1'] = padBytes
  950. respParameters['ParameterOffset'] = 73 + len(setup) + padLen
  951. else:
  952. padLen = 0
  953. respParameters['ParameterOffset'] = 0
  954. respData['Pad1'] = ''
  955. if len(data) > 0:
  956. #pad2Len = 4 - (71 + len(setup) + padLen + len(parameters)) % 4
  957. pad2Len = (4 - (73 + len(setup) + padLen + len(parameters)) % 4) % 4
  958. respData['Pad2'] = '\xFF' * pad2Len
  959. respParameters['DataOffset'] = 73 + len(setup) + padLen + len(parameters) + pad2Len
  960. else:
  961. respParameters['DataOffset'] = 0
  962. respData['Pad2'] = ''
  963. respData['NT_Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
  964. respData['NT_Trans_Data'] = data[:respParameters['DataCount']]
  965. respSMBCommand['Parameters'] = respParameters
  966. respSMBCommand['Data'] = respData
  967. data = data[respParameters['DataCount']:]
  968. remainingData -= respParameters['DataCount']
  969. dataDisplacement += respParameters['DataCount'] + 1
  970. parameters = parameters[respParameters['ParameterCount']:]
  971. remainingParameters -= respParameters['ParameterCount']
  972. commands.append(respSMBCommand)
  973. smbServer.setConnectionData(connId, connData)
  974. return commands, None, errorCode
  975. else:
  976. #smbServer.log("Unsupported NTTransact command 0x%x" % command, logging.ERROR)
  977. respParameters = ''
  978. respData = ''
  979. errorCode = STATUS_NOT_IMPLEMENTED
  980. respSMBCommand['Parameters'] = respParameters
  981. respSMBCommand['Data'] = respData
  982. smbServer.setConnectionData(connId, connData)
  983. return [respSMBCommand], None, errorCode
  984. @staticmethod
  985. def smbTransaction2(connId, smbServer, SMBCommand, recvPacket, transCommands):
  986. connData = smbServer.getConnectionData(connId)
  987. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  988. trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters'])
  989. # Do the stuff
  990. if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']:
  991. # TODO: Handle partial parameters
  992. #print "Unsupported partial parameters in TRANSACT2!"
  993. raise Exception("Unsupported partial parameters in TRANSACT2!")
  994. else:
  995. trans2Data = smb.SMBTransaction2_Data()
  996. # Standard says servers shouldn't trust Parameters and Data comes
  997. # in order, so we have to parse the offsets, ugly
  998. paramCount = trans2Parameters['ParameterCount']
  999. trans2Data['Trans_ParametersLength'] = paramCount
  1000. dataCount = trans2Parameters['DataCount']
  1001. trans2Data['Trans_DataLength'] = dataCount
  1002. if trans2Parameters['ParameterOffset'] > 0:
  1003. paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength']
  1004. trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
  1005. else:
  1006. trans2Data['Trans_Parameters'] = ''
  1007. if trans2Parameters['DataOffset'] > 0:
  1008. dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength']
  1009. trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
  1010. else:
  1011. trans2Data['Trans_Data'] = ''
  1012. # Call the handler for this TRANSACTION
  1013. command = struct.unpack('<H', trans2Parameters['Setup'])[0]
  1014. if command in transCommands:
  1015. # Call the TRANS2 subcommand
  1016. try:
  1017. setup, parameters, data, errorCode = transCommands[command](connId,
  1018. smbServer,
  1019. recvPacket,
  1020. trans2Data['Trans_Parameters'],
  1021. trans2Data['Trans_Data'],
  1022. trans2Parameters['MaxDataCount'])
  1023. except Exception as e:
  1024. smbServer.log('Transaction2: (0x%x,%s)' % (command, e), logging.ERROR)
  1025. #import traceback
  1026. #traceback.print_exc()
  1027. raise
  1028. if setup == '' and parameters == '' and data == '':
  1029. # Something wen't wrong
  1030. respParameters = ''
  1031. respData = ''
  1032. else:
  1033. # Build the answer
  1034. data = str(data)
  1035. remainingData = len(data)
  1036. parameters = str(parameters)
  1037. remainingParameters = len(parameters)
  1038. commands = []
  1039. dataDisplacement = 0
  1040. while remainingData > 0 or remainingParameters > 0:
  1041. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  1042. respParameters = smb.SMBTransaction2Response_Parameters()
  1043. respData = smb.SMBTransaction2Response_Data()
  1044. respParameters['TotalParameterCount'] = len(parameters)
  1045. respParameters['ParameterCount'] = len(parameters)
  1046. respData['Trans_ParametersLength'] = len(parameters)
  1047. respParameters['TotalDataCount'] = len(data)
  1048. respParameters['DataDisplacement'] = dataDisplacement
  1049. # TODO: Do the same for parameters
  1050. if len(data) > trans2Parameters['MaxDataCount']:
  1051. # Answer doesn't fit in this packet
  1052. LOG.debug("Lowering answer from %d to %d" % (len(data),trans2Parameters['MaxDataCount']) )
  1053. respParameters['DataCount'] = trans2Parameters['MaxDataCount']
  1054. else:
  1055. respParameters['DataCount'] = len(data)
  1056. respData['Trans_DataLength'] = respParameters['DataCount']
  1057. respParameters['SetupCount'] = len(setup)
  1058. respParameters['Setup'] = setup
  1059. # TODO: Make sure we're calculating the pad right
  1060. if len(parameters) > 0:
  1061. #padLen = 4 - (55 + len(setup)) % 4
  1062. padLen = (4 - (55 + len(setup)) % 4 ) % 4
  1063. padBytes = '\xFF' * padLen
  1064. respData['Pad1'] = padBytes
  1065. respParameters['ParameterOffset'] = 55 + len(setup) + padLen
  1066. else:
  1067. padLen = 0
  1068. respParameters['ParameterOffset'] = 0
  1069. respData['Pad1'] = ''
  1070. if len(data) > 0:
  1071. #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
  1072. pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
  1073. respData['Pad2'] = '\xFF' * pad2Len
  1074. respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
  1075. else:
  1076. respParameters['DataOffset'] = 0
  1077. respData['Pad2'] = ''
  1078. respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
  1079. respData['Trans_Data'] = data[:respParameters['DataCount']]
  1080. respSMBCommand['Parameters'] = respParameters
  1081. respSMBCommand['Data'] = respData
  1082. data = data[respParameters['DataCount']:]
  1083. remainingData -= respParameters['DataCount']
  1084. dataDisplacement += respParameters['DataCount'] + 1
  1085. parameters = parameters[respParameters['ParameterCount']:]
  1086. remainingParameters -= respParameters['ParameterCount']
  1087. commands.append(respSMBCommand)
  1088. smbServer.setConnectionData(connId, connData)
  1089. return commands, None, errorCode
  1090. else:
  1091. smbServer.log("Unsupported Transact/2 command 0x%x" % command, logging.ERROR)
  1092. respParameters = ''
  1093. respData = ''
  1094. errorCode = STATUS_NOT_IMPLEMENTED
  1095. respSMBCommand['Parameters'] = respParameters
  1096. respSMBCommand['Data'] = respData
  1097. smbServer.setConnectionData(connId, connData)
  1098. return [respSMBCommand], None, errorCode
  1099. @staticmethod
  1100. def smbComLockingAndX(connId, smbServer, SMBCommand, recvPacket):
  1101. connData = smbServer.getConnectionData(connId)
  1102. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOCKING_ANDX)
  1103. respParameters = ''
  1104. respData = ''
  1105. # I'm actually doing nothing.. just make MacOS happy ;)
  1106. errorCode = STATUS_SUCCESS
  1107. respSMBCommand['Parameters'] = respParameters
  1108. respSMBCommand['Data'] = respData
  1109. smbServer.setConnectionData(connId, connData)
  1110. return [respSMBCommand], None, errorCode
  1111. @staticmethod
  1112. def smbComClose(connId, smbServer, SMBCommand, recvPacket):
  1113. connData = smbServer.getConnectionData(connId)
  1114. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CLOSE)
  1115. respParameters = ''
  1116. respData = ''
  1117. comClose = smb.SMBClose_Parameters(SMBCommand['Parameters'])
  1118. if comClose['FID'] in connData['OpenedFiles']:
  1119. errorCode = STATUS_SUCCESS
  1120. fileHandle = connData['OpenedFiles'][comClose['FID']]['FileHandle']
  1121. try:
  1122. if fileHandle == PIPE_FILE_DESCRIPTOR:
  1123. connData['OpenedFiles'][comClose['FID']]['Socket'].close()
  1124. elif fileHandle != VOID_FILE_DESCRIPTOR:
  1125. os.close(fileHandle)
  1126. except Exception as e:
  1127. smbServer.log("comClose %s" % e, logging.ERROR)
  1128. errorCode = STATUS_ACCESS_DENIED
  1129. else:
  1130. # Check if the file was marked for removal
  1131. if connData['OpenedFiles'][comClose['FID']]['DeleteOnClose'] is True:
  1132. try:
  1133. os.remove(connData['OpenedFiles'][comClose['FID']]['FileName'])
  1134. except Exception as e:
  1135. smbServer.log("comClose %s" % e, logging.ERROR)
  1136. errorCode = STATUS_ACCESS_DENIED
  1137. del(connData['OpenedFiles'][comClose['FID']])
  1138. else:
  1139. errorCode = STATUS_INVALID_HANDLE
  1140. if errorCode > 0:
  1141. respParameters = ''
  1142. respData = ''
  1143. respSMBCommand['Parameters'] = respParameters
  1144. respSMBCommand['Data'] = respData
  1145. smbServer.setConnectionData(connId, connData)
  1146. return [respSMBCommand], None, errorCode
  1147. @staticmethod
  1148. def smbComWrite(connId, smbServer, SMBCommand, recvPacket):
  1149. connData = smbServer.getConnectionData(connId)
  1150. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE)
  1151. respParameters = smb.SMBWriteResponse_Parameters()
  1152. respData = ''
  1153. comWriteParameters = smb.SMBWrite_Parameters(SMBCommand['Parameters'])
  1154. comWriteData = smb.SMBWrite_Data(SMBCommand['Data'])
  1155. if comWriteParameters['Fid'] in connData['OpenedFiles']:
  1156. fileHandle = connData['OpenedFiles'][comWriteParameters['Fid']]['FileHandle']
  1157. errorCode = STATUS_SUCCESS
  1158. try:
  1159. if fileHandle != PIPE_FILE_DESCRIPTOR:
  1160. # TODO: Handle big size files
  1161. # If we're trying to write past the file end we just skip the write call (Vista does this)
  1162. if os.lseek(fileHandle, 0, 2) >= comWriteParameters['Offset']:
  1163. os.lseek(fileHandle,comWriteParameters['Offset'],0)
  1164. os.write(fileHandle,comWriteData['Data'])
  1165. else:
  1166. sock = connData['OpenedFiles'][comWriteParameters['Fid']]['Socket']
  1167. sock.send(comWriteData['Data'])
  1168. respParameters['Count'] = comWriteParameters['Count']
  1169. except Exception as e:
  1170. smbServer.log('smbComWrite: %s' % e, logging.ERROR)
  1171. errorCode = STATUS_ACCESS_DENIED
  1172. else:
  1173. errorCode = STATUS_INVALID_HANDLE
  1174. if errorCode > 0:
  1175. respParameters = ''
  1176. respData = ''
  1177. respSMBCommand['Parameters'] = respParameters
  1178. respSMBCommand['Data'] = respData
  1179. smbServer.setConnectionData(connId, connData)
  1180. return [respSMBCommand], None, errorCode
  1181. @staticmethod
  1182. def smbComFlush(connId, smbServer, SMBCommand,recvPacket ):
  1183. connData = smbServer.getConnectionData(connId)
  1184. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_FLUSH)
  1185. respParameters = ''
  1186. respData = ''
  1187. comFlush = smb.SMBFlush_Parameters(SMBCommand['Parameters'])
  1188. if comFlush['FID'] in connData['OpenedFiles']:
  1189. errorCode = STATUS_SUCCESS
  1190. fileHandle = connData['OpenedFiles'][comFlush['FID']]['FileHandle']
  1191. try:
  1192. os.fsync(fileHandle)
  1193. except Exception as e:
  1194. smbServer.log("comFlush %s" % e, logging.ERROR)
  1195. errorCode = STATUS_ACCESS_DENIED
  1196. else:
  1197. errorCode = STATUS_INVALID_HANDLE
  1198. if errorCode > 0:
  1199. respParameters = ''
  1200. respData = ''
  1201. respSMBCommand['Parameters'] = respParameters
  1202. respSMBCommand['Data'] = respData
  1203. smbServer.setConnectionData(connId, connData)
  1204. return [respSMBCommand], None, errorCode
  1205. @staticmethod
  1206. def smbComCreateDirectory(connId, smbServer, SMBCommand,recvPacket ):
  1207. connData = smbServer.getConnectionData(connId)
  1208. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY)
  1209. respParameters = ''
  1210. respData = ''
  1211. comCreateDirectoryData= smb.SMBCreateDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1212. # Get the Tid associated
  1213. if recvPacket['Tid'] in connData['ConnectedShares']:
  1214. errorCode = STATUS_SUCCESS
  1215. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1216. fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comCreateDirectoryData['DirectoryName']).replace('\\','/'))
  1217. if len(fileName) > 0:
  1218. if fileName[0] == '/' or fileName[0] == '\\':
  1219. # strip leading '/'
  1220. fileName = fileName[1:]
  1221. pathName = os.path.join(path,fileName)
  1222. if os.path.exists(pathName):
  1223. errorCode = STATUS_OBJECT_NAME_COLLISION
  1224. # TODO: More checks here in the future.. Specially when we support
  1225. # user access
  1226. else:
  1227. try:
  1228. os.mkdir(pathName)
  1229. except Exception as e:
  1230. smbServer.log("smbComCreateDirectory: %s" % e, logging.ERROR)
  1231. errorCode = STATUS_ACCESS_DENIED
  1232. else:
  1233. errorCode = STATUS_SMB_BAD_TID
  1234. if errorCode > 0:
  1235. respParameters = ''
  1236. respData = ''
  1237. respSMBCommand['Parameters'] = respParameters
  1238. respSMBCommand['Data'] = respData
  1239. smbServer.setConnectionData(connId, connData)
  1240. return [respSMBCommand], None, errorCode
  1241. @staticmethod
  1242. def smbComRename(connId, smbServer, SMBCommand, recvPacket ):
  1243. connData = smbServer.getConnectionData(connId)
  1244. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_RENAME)
  1245. respParameters = ''
  1246. respData = ''
  1247. comRenameData = smb.SMBRename_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1248. # Get the Tid associated
  1249. if recvPacket['Tid'] in connData['ConnectedShares']:
  1250. errorCode = STATUS_SUCCESS
  1251. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1252. oldFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['OldFileName']).replace('\\','/'))
  1253. newFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['NewFileName']).replace('\\','/'))
  1254. if len(oldFileName) > 0 and (oldFileName[0] == '/' or oldFileName[0] == '\\'):
  1255. # strip leading '/'
  1256. oldFileName = oldFileName[1:]
  1257. oldPathName = os.path.join(path,oldFileName)
  1258. if len(newFileName) > 0 and (newFileName[0] == '/' or newFileName[0] == '\\'):
  1259. # strip leading '/'
  1260. newFileName = newFileName[1:]
  1261. newPathName = os.path.join(path,newFileName)
  1262. if os.path.exists(oldPathName) is not True:
  1263. errorCode = STATUS_NO_SUCH_FILE
  1264. # TODO: More checks here in the future.. Specially when we support
  1265. # user access
  1266. else:
  1267. try:
  1268. os.rename(oldPathName,newPathName)
  1269. except OSError as e:
  1270. smbServer.log("smbComRename: %s" % e, logging.ERROR)
  1271. errorCode = STATUS_ACCESS_DENIED
  1272. else:
  1273. errorCode = STATUS_SMB_BAD_TID
  1274. if errorCode > 0:
  1275. respParameters = ''
  1276. respData = ''
  1277. respSMBCommand['Parameters'] = respParameters
  1278. respSMBCommand['Data'] = respData
  1279. smbServer.setConnectionData(connId, connData)
  1280. return [respSMBCommand], None, errorCode
  1281. @staticmethod
  1282. def smbComDelete(connId, smbServer, SMBCommand, recvPacket ):
  1283. connData = smbServer.getConnectionData(connId)
  1284. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE)
  1285. respParameters = ''
  1286. respData = ''
  1287. comDeleteData = smb.SMBDelete_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1288. # Get the Tid associated
  1289. if recvPacket['Tid'] in connData['ConnectedShares']:
  1290. errorCode = STATUS_SUCCESS
  1291. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1292. fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteData['FileName']).replace('\\','/'))
  1293. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  1294. # strip leading '/'
  1295. fileName = fileName[1:]
  1296. pathName = os.path.join(path,fileName)
  1297. if os.path.exists(pathName) is not True:
  1298. errorCode = STATUS_NO_SUCH_FILE
  1299. # TODO: More checks here in the future.. Specially when we support
  1300. # user access
  1301. else:
  1302. try:
  1303. os.remove(pathName)
  1304. except OSError as e:
  1305. smbServer.log("smbComDelete: %s" % e, logging.ERROR)
  1306. errorCode = STATUS_ACCESS_DENIED
  1307. else:
  1308. errorCode = STATUS_SMB_BAD_TID
  1309. if errorCode > 0:
  1310. respParameters = ''
  1311. respData = ''
  1312. respSMBCommand['Parameters'] = respParameters
  1313. respSMBCommand['Data'] = respData
  1314. smbServer.setConnectionData(connId, connData)
  1315. return [respSMBCommand], None, errorCode
  1316. @staticmethod
  1317. def smbComDeleteDirectory(connId, smbServer, SMBCommand, recvPacket ):
  1318. connData = smbServer.getConnectionData(connId)
  1319. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY)
  1320. respParameters = ''
  1321. respData = ''
  1322. comDeleteDirectoryData= smb.SMBDeleteDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1323. # Get the Tid associated
  1324. if recvPacket['Tid'] in connData['ConnectedShares']:
  1325. errorCode = STATUS_SUCCESS
  1326. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1327. fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteDirectoryData['DirectoryName']).replace('\\','/'))
  1328. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  1329. # strip leading '/'
  1330. fileName = fileName[1:]
  1331. pathName = os.path.join(path,fileName)
  1332. if os.path.exists(pathName) is not True:
  1333. errorCode = STATUS_NO_SUCH_FILE
  1334. # TODO: More checks here in the future.. Specially when we support
  1335. # user access
  1336. else:
  1337. try:
  1338. os.rmdir(pathName)
  1339. except OSError as e:
  1340. smbServer.log("smbComDeleteDirectory: %s" % e,logging.ERROR)
  1341. if e.errno == errno.ENOTEMPTY:
  1342. errorCode = STATUS_DIRECTORY_NOT_EMPTY
  1343. else:
  1344. errorCode = STATUS_ACCESS_DENIED
  1345. else:
  1346. errorCode = STATUS_SMB_BAD_TID
  1347. if errorCode > 0:
  1348. respParameters = ''
  1349. respData = ''
  1350. respSMBCommand['Parameters'] = respParameters
  1351. respSMBCommand['Data'] = respData
  1352. smbServer.setConnectionData(connId, connData)
  1353. return [respSMBCommand], None, errorCode
  1354. @staticmethod
  1355. def smbComWriteAndX(connId, smbServer, SMBCommand, recvPacket):
  1356. connData = smbServer.getConnectionData(connId)
  1357. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
  1358. respParameters = smb.SMBWriteAndXResponse_Parameters()
  1359. respData = ''
  1360. if SMBCommand['WordCount'] == 0x0C:
  1361. writeAndX = smb.SMBWriteAndX_Parameters_Short(SMBCommand['Parameters'])
  1362. writeAndXData = smb.SMBWriteAndX_Data_Short()
  1363. else:
  1364. writeAndX = smb.SMBWriteAndX_Parameters(SMBCommand['Parameters'])
  1365. writeAndXData = smb.SMBWriteAndX_Data()
  1366. writeAndXData['DataLength'] = writeAndX['DataLength']
  1367. writeAndXData['DataOffset'] = writeAndX['DataOffset']
  1368. writeAndXData.fromString(SMBCommand['Data'])
  1369. if writeAndX['Fid'] in connData['OpenedFiles']:
  1370. fileHandle = connData['OpenedFiles'][writeAndX['Fid']]['FileHandle']
  1371. errorCode = STATUS_SUCCESS
  1372. try:
  1373. if fileHandle != PIPE_FILE_DESCRIPTOR:
  1374. offset = writeAndX['Offset']
  1375. if 'HighOffset' in writeAndX.fields:
  1376. offset += (writeAndX['HighOffset'] << 32)
  1377. # If we're trying to write past the file end we just skip the write call (Vista does this)
  1378. if os.lseek(fileHandle, 0, 2) >= offset:
  1379. os.lseek(fileHandle,offset,0)
  1380. os.write(fileHandle,writeAndXData['Data'])
  1381. else:
  1382. sock = connData['OpenedFiles'][writeAndX['Fid']]['Socket']
  1383. sock.send(writeAndXData['Data'])
  1384. respParameters['Count'] = writeAndX['DataLength']
  1385. respParameters['Available']= 0xff
  1386. except Exception as e:
  1387. smbServer.log('smbComWriteAndx: %s' % e, logging.ERROR)
  1388. errorCode = STATUS_ACCESS_DENIED
  1389. else:
  1390. errorCode = STATUS_INVALID_HANDLE
  1391. if errorCode > 0:
  1392. respParameters = ''
  1393. respData = ''
  1394. respSMBCommand['Parameters'] = respParameters
  1395. respSMBCommand['Data'] = respData
  1396. smbServer.setConnectionData(connId, connData)
  1397. return [respSMBCommand], None, errorCode
  1398. @staticmethod
  1399. def smbComRead(connId, smbServer, SMBCommand, recvPacket):
  1400. connData = smbServer.getConnectionData(connId)
  1401. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ)
  1402. respParameters = smb.SMBReadResponse_Parameters()
  1403. respData = smb.SMBReadResponse_Data()
  1404. comReadParameters = smb.SMBRead_Parameters(SMBCommand['Parameters'])
  1405. if comReadParameters['Fid'] in connData['OpenedFiles']:
  1406. fileHandle = connData['OpenedFiles'][comReadParameters['Fid']]['FileHandle']
  1407. errorCode = STATUS_SUCCESS
  1408. try:
  1409. if fileHandle != PIPE_FILE_DESCRIPTOR:
  1410. # TODO: Handle big size files
  1411. os.lseek(fileHandle,comReadParameters['Offset'],0)
  1412. content = os.read(fileHandle,comReadParameters['Count'])
  1413. else:
  1414. sock = connData['OpenedFiles'][comReadParameters['Fid']]['Socket']
  1415. content = sock.recv(comReadParameters['Count'])
  1416. respParameters['Count'] = len(content)
  1417. respData['DataLength'] = len(content)
  1418. respData['Data'] = content
  1419. except Exception as e:
  1420. smbServer.log('smbComRead: %s ' % e, logging.ERROR)
  1421. errorCode = STATUS_ACCESS_DENIED
  1422. else:
  1423. errorCode = STATUS_INVALID_HANDLE
  1424. if errorCode > 0:
  1425. respParameters = ''
  1426. respData = ''
  1427. respSMBCommand['Parameters'] = respParameters
  1428. respSMBCommand['Data'] = respData
  1429. smbServer.setConnectionData(connId, connData)
  1430. return [respSMBCommand], None, errorCode
  1431. @staticmethod
  1432. def smbComReadAndX(connId, smbServer, SMBCommand, recvPacket):
  1433. connData = smbServer.getConnectionData(connId)
  1434. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ_ANDX)
  1435. respParameters = smb.SMBReadAndXResponse_Parameters()
  1436. respData = ''
  1437. if SMBCommand['WordCount'] == 0x0A:
  1438. readAndX = smb.SMBReadAndX_Parameters2(SMBCommand['Parameters'])
  1439. else:
  1440. readAndX = smb.SMBReadAndX_Parameters(SMBCommand['Parameters'])
  1441. if readAndX['Fid'] in connData['OpenedFiles']:
  1442. fileHandle = connData['OpenedFiles'][readAndX['Fid']]['FileHandle']
  1443. errorCode = 0
  1444. try:
  1445. if fileHandle != PIPE_FILE_DESCRIPTOR:
  1446. offset = readAndX['Offset']
  1447. if 'HighOffset' in readAndX.fields:
  1448. offset += (readAndX['HighOffset'] << 32)
  1449. os.lseek(fileHandle,offset,0)
  1450. content = os.read(fileHandle,readAndX['MaxCount'])
  1451. else:
  1452. sock = connData['OpenedFiles'][readAndX['Fid']]['Socket']
  1453. content = sock.recv(readAndX['MaxCount'])
  1454. respParameters['Remaining'] = 0xffff
  1455. respParameters['DataCount'] = len(content)
  1456. respParameters['DataOffset'] = 59
  1457. respParameters['DataCount_Hi'] = 0
  1458. respData = content
  1459. except Exception as e:
  1460. smbServer.log('smbComReadAndX: %s ' % e, logging.ERROR)
  1461. errorCode = STATUS_ACCESS_DENIED
  1462. else:
  1463. errorCode = STATUS_INVALID_HANDLE
  1464. if errorCode > 0:
  1465. respParameters = ''
  1466. respData = ''
  1467. respSMBCommand['Parameters'] = respParameters
  1468. respSMBCommand['Data'] = respData
  1469. smbServer.setConnectionData(connId, connData)
  1470. return [respSMBCommand], None, errorCode
  1471. @staticmethod
  1472. def smbQueryInformation(connId, smbServer, SMBCommand, recvPacket):
  1473. connData = smbServer.getConnectionData(connId)
  1474. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION)
  1475. respParameters = smb.SMBQueryInformationResponse_Parameters()
  1476. respData = ''
  1477. queryInformation= smb.SMBQueryInformation_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1478. # Get the Tid associated
  1479. if recvPacket['Tid'] in connData['ConnectedShares']:
  1480. fileSize, lastWriteTime, fileAttributes = queryFsInformation(
  1481. connData['ConnectedShares'][recvPacket['Tid']]['path'],
  1482. decodeSMBString(recvPacket['Flags2'],queryInformation['FileName']))
  1483. respParameters['FileSize'] = fileSize
  1484. respParameters['LastWriteTime'] = lastWriteTime
  1485. respParameters['FileAttributes'] = fileAttributes
  1486. errorCode = STATUS_SUCCESS
  1487. else:
  1488. # STATUS_SMB_BAD_TID
  1489. errorCode = STATUS_SMB_BAD_TID
  1490. respParameters = ''
  1491. respData = ''
  1492. respSMBCommand['Parameters'] = respParameters
  1493. respSMBCommand['Data'] = respData
  1494. smbServer.setConnectionData(connId, connData)
  1495. return [respSMBCommand], None, errorCode
  1496. @staticmethod
  1497. def smbQueryInformationDisk(connId, smbServer, SMBCommand, recvPacket):
  1498. connData = smbServer.getConnectionData(connId)
  1499. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION_DISK)
  1500. respParameters = smb.SMBQueryInformationDiskResponse_Parameters()
  1501. respData = ''
  1502. # Get the Tid associated
  1503. if recvPacket['Tid'] in connData['ConnectedShares']:
  1504. totalUnits, freeUnits = queryDiskInformation(
  1505. connData['ConnectedShares'][recvPacket['Tid']]['path'])
  1506. respParameters['TotalUnits'] = totalUnits
  1507. respParameters['BlocksPerUnit'] = 1
  1508. respParameters['BlockSize'] = 1
  1509. respParameters['FreeUnits'] = freeUnits
  1510. errorCode = STATUS_SUCCESS
  1511. else:
  1512. # STATUS_SMB_BAD_TID
  1513. respData = ''
  1514. respParameters = ''
  1515. errorCode = STATUS_SMB_BAD_TID
  1516. respSMBCommand['Parameters'] = respParameters
  1517. respSMBCommand['Data'] = respData
  1518. smbServer.setConnectionData(connId, connData)
  1519. return [respSMBCommand], None, errorCode
  1520. @staticmethod
  1521. def smbComEcho(connId, smbServer, SMBCommand, recvPacket):
  1522. connData = smbServer.getConnectionData(connId)
  1523. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
  1524. respParameters = smb.SMBEchoResponse_Parameters()
  1525. respData = smb.SMBEchoResponse_Data()
  1526. echoData = smb.SMBEcho_Data(SMBCommand['Data'])
  1527. respParameters['SequenceNumber'] = 1
  1528. respData['Data'] = echoData['Data']
  1529. respSMBCommand['Parameters'] = respParameters
  1530. respSMBCommand['Data'] = respData
  1531. errorCode = STATUS_SUCCESS
  1532. smbServer.setConnectionData(connId, connData)
  1533. return [respSMBCommand], None, errorCode
  1534. @staticmethod
  1535. def smbComTreeDisconnect(connId, smbServer, SMBCommand, recvPacket):
  1536. connData = smbServer.getConnectionData(connId)
  1537. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_DISCONNECT)
  1538. # Check if the Tid matches the Tid trying to disconnect
  1539. respParameters = ''
  1540. respData = ''
  1541. if recvPacket['Tid'] in connData['ConnectedShares']:
  1542. smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['Tid'],connData['ConnectedShares'][recvPacket['Tid']]['shareName']))
  1543. del(connData['ConnectedShares'][recvPacket['Tid']])
  1544. errorCode = STATUS_SUCCESS
  1545. else:
  1546. # STATUS_SMB_BAD_TID
  1547. errorCode = STATUS_SMB_BAD_TID
  1548. respSMBCommand['Parameters'] = respParameters
  1549. respSMBCommand['Data'] = respData
  1550. smbServer.setConnectionData(connId, connData)
  1551. return [respSMBCommand], None, errorCode
  1552. @staticmethod
  1553. def smbComLogOffAndX(connId, smbServer, SMBCommand, recvPacket):
  1554. connData = smbServer.getConnectionData(connId)
  1555. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOGOFF_ANDX)
  1556. # Check if the Uid matches the user trying to logoff
  1557. respParameters = ''
  1558. respData = ''
  1559. if recvPacket['Uid'] != connData['Uid']:
  1560. # STATUS_SMB_BAD_UID
  1561. errorCode = STATUS_SMB_BAD_UID
  1562. else:
  1563. errorCode = STATUS_SUCCESS
  1564. respSMBCommand['Parameters'] = respParameters
  1565. respSMBCommand['Data'] = respData
  1566. connData['Uid'] = 0
  1567. smbServer.setConnectionData(connId, connData)
  1568. return [respSMBCommand], None, errorCode
  1569. @staticmethod
  1570. def smbComQueryInformation2(connId, smbServer, SMBCommand, recvPacket):
  1571. connData = smbServer.getConnectionData(connId)
  1572. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION2)
  1573. respParameters = smb.SMBQueryInformation2Response_Parameters()
  1574. respData = ''
  1575. queryInformation2 = smb.SMBQueryInformation2_Parameters(SMBCommand['Parameters'])
  1576. errorCode = 0xFF
  1577. if queryInformation2['Fid'] in connData['OpenedFiles']:
  1578. errorCode = STATUS_SUCCESS
  1579. pathName = connData['OpenedFiles'][queryInformation2['Fid']]['FileName']
  1580. try:
  1581. (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
  1582. respParameters['CreateDate'] = getSMBDate(ctime)
  1583. respParameters['CreationTime'] = getSMBTime(ctime)
  1584. respParameters['LastAccessDate'] = getSMBDate(atime)
  1585. respParameters['LastAccessTime'] = getSMBTime(atime)
  1586. respParameters['LastWriteDate'] = getSMBDate(mtime)
  1587. respParameters['LastWriteTime'] = getSMBTime(mtime)
  1588. respParameters['FileDataSize'] = size
  1589. respParameters['FileAllocationSize'] = size
  1590. attribs = 0
  1591. if os.path.isdir(pathName):
  1592. attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
  1593. if os.path.isfile(pathName):
  1594. attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL
  1595. respParameters['FileAttributes'] = attribs
  1596. except Exception as e:
  1597. smbServer.log('smbComQueryInformation2 %s' % e,logging.ERROR)
  1598. errorCode = STATUS_ACCESS_DENIED
  1599. if errorCode > 0:
  1600. respParameters = ''
  1601. respData = ''
  1602. respSMBCommand['Parameters'] = respParameters
  1603. respSMBCommand['Data'] = respData
  1604. smbServer.setConnectionData(connId, connData)
  1605. return [respSMBCommand], None, errorCode
  1606. @staticmethod
  1607. def smbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket):
  1608. # TODO: Fully implement this
  1609. connData = smbServer.getConnectionData(connId)
  1610. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
  1611. respParameters = smb.SMBNtCreateAndXResponse_Parameters()
  1612. respData = ''
  1613. ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters'])
  1614. ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1615. #if ntCreateAndXParameters['CreateFlags'] & 0x10: # NT_CREATE_REQUEST_EXTENDED_RESPONSE
  1616. # respParameters = smb.SMBNtCreateAndXExtendedResponse_Parameters()
  1617. # respParameters['VolumeGUID'] = '\x00'
  1618. # Get the Tid associated
  1619. if recvPacket['Tid'] in connData['ConnectedShares']:
  1620. # If we have a rootFid, the path is relative to that fid
  1621. errorCode = STATUS_SUCCESS
  1622. if ntCreateAndXParameters['RootFid'] > 0:
  1623. path = connData['OpenedFiles'][ntCreateAndXParameters['RootFid']]['FileName']
  1624. LOG.debug("RootFid present %s!" % path)
  1625. else:
  1626. if 'path' in connData['ConnectedShares'][recvPacket['Tid']]:
  1627. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1628. else:
  1629. path = 'NONE'
  1630. errorCode = STATUS_ACCESS_DENIED
  1631. deleteOnClose = False
  1632. fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/'))
  1633. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  1634. # strip leading '/'
  1635. fileName = fileName[1:]
  1636. pathName = os.path.join(path,fileName)
  1637. createDisposition = ntCreateAndXParameters['Disposition']
  1638. mode = 0
  1639. if createDisposition == smb.FILE_SUPERSEDE:
  1640. mode |= os.O_TRUNC | os.O_CREAT
  1641. elif createDisposition & smb.FILE_OVERWRITE_IF == smb.FILE_OVERWRITE_IF:
  1642. mode |= os.O_TRUNC | os.O_CREAT
  1643. elif createDisposition & smb.FILE_OVERWRITE == smb.FILE_OVERWRITE:
  1644. if os.path.exists(pathName) is True:
  1645. mode |= os.O_TRUNC
  1646. else:
  1647. errorCode = STATUS_NO_SUCH_FILE
  1648. elif createDisposition & smb.FILE_OPEN_IF == smb.FILE_OPEN_IF:
  1649. if os.path.exists(pathName) is True:
  1650. mode |= os.O_TRUNC
  1651. else:
  1652. mode |= os.O_TRUNC | os.O_CREAT
  1653. elif createDisposition & smb.FILE_CREATE == smb.FILE_CREATE:
  1654. if os.path.exists(pathName) is True:
  1655. errorCode = STATUS_OBJECT_NAME_COLLISION
  1656. else:
  1657. mode |= os.O_CREAT
  1658. elif createDisposition & smb.FILE_OPEN == smb.FILE_OPEN:
  1659. if os.path.exists(pathName) is not True and (unicode(pathName) in smbServer.getRegisteredNamedPipes()) is not True:
  1660. errorCode = STATUS_NO_SUCH_FILE
  1661. if errorCode == STATUS_SUCCESS:
  1662. desiredAccess = ntCreateAndXParameters['AccessMask']
  1663. if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
  1664. mode |= os.O_RDONLY
  1665. if (desiredAccess & smb.FILE_WRITE_DATA) or (desiredAccess & smb.GENERIC_WRITE):
  1666. if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
  1667. mode |= os.O_RDWR #| os.O_APPEND
  1668. else:
  1669. mode |= os.O_WRONLY #| os.O_APPEND
  1670. if desiredAccess & smb.GENERIC_ALL:
  1671. mode |= os.O_RDWR #| os.O_APPEND
  1672. createOptions = ntCreateAndXParameters['CreateOptions']
  1673. if mode & os.O_CREAT == os.O_CREAT:
  1674. if createOptions & smb.FILE_DIRECTORY_FILE == smb.FILE_DIRECTORY_FILE:
  1675. try:
  1676. # Let's create the directory
  1677. os.mkdir(pathName)
  1678. mode = os.O_RDONLY
  1679. except Exception as e:
  1680. smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
  1681. errorCode = STATUS_ACCESS_DENIED
  1682. if createOptions & smb.FILE_NON_DIRECTORY_FILE == smb.FILE_NON_DIRECTORY_FILE:
  1683. # If the file being opened is a directory, the server MUST fail the request with
  1684. # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
  1685. # response.
  1686. if os.path.isdir(pathName) is True:
  1687. errorCode = STATUS_FILE_IS_A_DIRECTORY
  1688. if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE:
  1689. deleteOnClose = True
  1690. if errorCode == STATUS_SUCCESS:
  1691. try:
  1692. if os.path.isdir(pathName) and sys.platform == 'win32':
  1693. fid = VOID_FILE_DESCRIPTOR
  1694. else:
  1695. if sys.platform == 'win32':
  1696. mode |= os.O_BINARY
  1697. if unicode(pathName) in smbServer.getRegisteredNamedPipes():
  1698. fid = PIPE_FILE_DESCRIPTOR
  1699. sock = socket.socket()
  1700. sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
  1701. else:
  1702. fid = os.open(pathName, mode)
  1703. except Exception as e:
  1704. smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
  1705. #print e
  1706. fid = 0
  1707. errorCode = STATUS_ACCESS_DENIED
  1708. else:
  1709. errorCode = STATUS_SMB_BAD_TID
  1710. if errorCode == STATUS_SUCCESS:
  1711. # Simple way to generate a fid
  1712. if len(connData['OpenedFiles']) == 0:
  1713. fakefid = 1
  1714. else:
  1715. fakefid = connData['OpenedFiles'].keys()[-1] + 1
  1716. respParameters['Fid'] = fakefid
  1717. respParameters['CreateAction'] = createDisposition
  1718. if fid == PIPE_FILE_DESCRIPTOR:
  1719. respParameters['FileAttributes'] = 0x80
  1720. respParameters['IsDirectory'] = 0
  1721. respParameters['CreateTime'] = 0
  1722. respParameters['LastAccessTime'] = 0
  1723. respParameters['LastWriteTime'] = 0
  1724. respParameters['LastChangeTime'] = 0
  1725. respParameters['AllocationSize'] = 4096
  1726. respParameters['EndOfFile'] = 0
  1727. respParameters['FileType'] = 2
  1728. respParameters['IPCState'] = 0x5ff
  1729. else:
  1730. if os.path.isdir(pathName):
  1731. respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
  1732. respParameters['IsDirectory'] = 1
  1733. else:
  1734. respParameters['IsDirectory'] = 0
  1735. respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes']
  1736. # Let's get this file's information
  1737. respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
  1738. if errorCode == STATUS_SUCCESS:
  1739. respParameters['CreateTime'] = respInfo['CreationTime']
  1740. respParameters['LastAccessTime'] = respInfo['LastAccessTime']
  1741. respParameters['LastWriteTime'] = respInfo['LastWriteTime']
  1742. respParameters['LastChangeTime'] = respInfo['LastChangeTime']
  1743. respParameters['FileAttributes'] = respInfo['ExtFileAttributes']
  1744. respParameters['AllocationSize'] = respInfo['AllocationSize']
  1745. respParameters['EndOfFile'] = respInfo['EndOfFile']
  1746. else:
  1747. respParameters = ''
  1748. respData = ''
  1749. if errorCode == STATUS_SUCCESS:
  1750. # Let's store the fid for the connection
  1751. # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
  1752. connData['OpenedFiles'][fakefid] = {}
  1753. connData['OpenedFiles'][fakefid]['FileHandle'] = fid
  1754. connData['OpenedFiles'][fakefid]['FileName'] = pathName
  1755. connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
  1756. if fid == PIPE_FILE_DESCRIPTOR:
  1757. connData['OpenedFiles'][fakefid]['Socket'] = sock
  1758. else:
  1759. respParameters = ''
  1760. respData = ''
  1761. respSMBCommand['Parameters'] = respParameters
  1762. respSMBCommand['Data'] = respData
  1763. smbServer.setConnectionData(connId, connData)
  1764. return [respSMBCommand], None, errorCode
  1765. @staticmethod
  1766. def smbComOpenAndX(connId, smbServer, SMBCommand, recvPacket):
  1767. connData = smbServer.getConnectionData(connId)
  1768. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_OPEN_ANDX)
  1769. respParameters = smb.SMBOpenAndXResponse_Parameters()
  1770. respData = ''
  1771. openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters'])
  1772. openAndXData = smb.SMBOpenAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1773. # Get the Tid associated
  1774. if recvPacket['Tid'] in connData['ConnectedShares']:
  1775. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1776. openedFile, mode, pathName, errorCode = openFile(path,
  1777. decodeSMBString(recvPacket['Flags2'],openAndXData['FileName']),
  1778. openAndXParameters['DesiredAccess'],
  1779. openAndXParameters['FileAttributes'],
  1780. openAndXParameters['OpenMode'])
  1781. else:
  1782. errorCode = STATUS_SMB_BAD_TID
  1783. if errorCode == STATUS_SUCCESS:
  1784. # Simple way to generate a fid
  1785. fid = len(connData['OpenedFiles']) + 1
  1786. if len(connData['OpenedFiles']) == 0:
  1787. fid = 1
  1788. else:
  1789. fid = connData['OpenedFiles'].keys()[-1] + 1
  1790. respParameters['Fid'] = fid
  1791. if mode & os.O_CREAT:
  1792. # File did not exist and was created
  1793. respParameters['Action'] = 0x2
  1794. elif mode & os.O_RDONLY:
  1795. # File existed and was opened
  1796. respParameters['Action'] = 0x1
  1797. elif mode & os.O_APPEND:
  1798. # File existed and was opened
  1799. respParameters['Action'] = 0x1
  1800. else:
  1801. # File existed and was truncated
  1802. respParameters['Action'] = 0x3
  1803. # Let's store the fid for the connection
  1804. #smbServer.log('Opening file %s' % pathName)
  1805. connData['OpenedFiles'][fid] = {}
  1806. connData['OpenedFiles'][fid]['FileHandle'] = openedFile
  1807. connData['OpenedFiles'][fid]['FileName'] = pathName
  1808. connData['OpenedFiles'][fid]['DeleteOnClose'] = False
  1809. else:
  1810. respParameters = ''
  1811. respData = ''
  1812. respSMBCommand['Parameters'] = respParameters
  1813. respSMBCommand['Data'] = respData
  1814. smbServer.setConnectionData(connId, connData)
  1815. return [respSMBCommand], None, errorCode
  1816. @staticmethod
  1817. def smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket):
  1818. connData = smbServer.getConnectionData(connId)
  1819. resp = smb.NewSMBPacket()
  1820. resp['Flags1'] = smb.SMB.FLAGS1_REPLY
  1821. resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE
  1822. resp['Tid'] = recvPacket['Tid']
  1823. resp['Mid'] = recvPacket['Mid']
  1824. resp['Pid'] = connData['Pid']
  1825. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX)
  1826. respParameters = smb.SMBTreeConnectAndXResponse_Parameters()
  1827. respData = smb.SMBTreeConnectAndXResponse_Data()
  1828. treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters'])
  1829. if treeConnectAndXParameters['Flags'] & 0x8:
  1830. respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters()
  1831. treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] )
  1832. treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength']
  1833. treeConnectAndXData.fromString(SMBCommand['Data'])
  1834. errorCode = STATUS_SUCCESS
  1835. ## Process here the request, does the share exist?
  1836. UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path'])
  1837. # Is this a UNC?
  1838. if ntpath.ismount(UNCOrShare):
  1839. path = UNCOrShare.split('\\')[3]
  1840. else:
  1841. path = ntpath.basename(UNCOrShare)
  1842. share = searchShare(connId, path, smbServer)
  1843. if share is not None:
  1844. # Simple way to generate a Tid
  1845. if len(connData['ConnectedShares']) == 0:
  1846. tid = 1
  1847. else:
  1848. tid = connData['ConnectedShares'].keys()[-1] + 1
  1849. connData['ConnectedShares'][tid] = share
  1850. connData['ConnectedShares'][tid]['shareName'] = path
  1851. resp['Tid'] = tid
  1852. #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
  1853. else:
  1854. smbServer.log("TreeConnectAndX not found %s" % path, logging.ERROR)
  1855. errorCode = STATUS_OBJECT_PATH_NOT_FOUND
  1856. resp['ErrorCode'] = errorCode >> 16
  1857. resp['ErrorClass'] = errorCode & 0xff
  1858. ##
  1859. respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS
  1860. if path == 'IPC$':
  1861. respData['Service'] = 'IPC'
  1862. else:
  1863. respData['Service'] = path
  1864. respData['PadLen'] = 0
  1865. respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS' )
  1866. respSMBCommand['Parameters'] = respParameters
  1867. respSMBCommand['Data'] = respData
  1868. resp['Uid'] = connData['Uid']
  1869. resp.addCommand(respSMBCommand)
  1870. smbServer.setConnectionData(connId, connData)
  1871. return None, [resp], errorCode
  1872. @staticmethod
  1873. def smbComSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket):
  1874. connData = smbServer.getConnectionData(connId, checkStatus = False)
  1875. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
  1876. # From [MS-SMB]
  1877. # When extended security is being used (see section 3.2.4.2.4), the
  1878. # request MUST take the following form
  1879. # [..]
  1880. # WordCount (1 byte): The value of this field MUST be 0x0C.
  1881. if SMBCommand['WordCount'] == 12:
  1882. # Extended security. Here we deal with all SPNEGO stuff
  1883. respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters()
  1884. respData = smb.SMBSessionSetupAndX_Extended_Response_Data(flags = recvPacket['Flags2'])
  1885. sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters'])
  1886. sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data()
  1887. sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength']
  1888. sessionSetupData.fromString(SMBCommand['Data'])
  1889. connData['Capabilities'] = sessionSetupParameters['Capabilities']
  1890. rawNTLM = False
  1891. if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_AID:
  1892. # NEGOTIATE packet
  1893. blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob'])
  1894. token = blob['MechToken']
  1895. if len(blob['MechTypes'][0]) > 0:
  1896. # Is this GSSAPI NTLM or something else we don't support?
  1897. mechType = blob['MechTypes'][0]
  1898. if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
  1899. # Nope, do we know it?
  1900. if mechType in MechTypes:
  1901. mechStr = MechTypes[mechType]
  1902. else:
  1903. mechStr = hexlify(mechType)
  1904. smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
  1905. # We don't know the token, we answer back again saying
  1906. # we just support NTLM.
  1907. # ToDo: Build this into a SPNEGO_NegTokenResp()
  1908. respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
  1909. respParameters['SecurityBlobLength'] = len(respToken)
  1910. respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
  1911. respData['SecurityBlob'] = respToken
  1912. respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
  1913. respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
  1914. respSMBCommand['Parameters'] = respParameters
  1915. respSMBCommand['Data'] = respData
  1916. return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
  1917. elif struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_SUPPORTED_MECH:
  1918. # AUTH packet
  1919. blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob'])
  1920. token = blob['ResponseToken']
  1921. else:
  1922. # No GSSAPI stuff, raw NTLMSSP
  1923. rawNTLM = True
  1924. token = sessionSetupData['SecurityBlob']
  1925. # Here we only handle NTLMSSP, depending on what stage of the
  1926. # authentication we are, we act on it
  1927. messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
  1928. if messageType == 0x01:
  1929. # NEGOTIATE_MESSAGE
  1930. negotiateMessage = ntlm.NTLMAuthNegotiate()
  1931. negotiateMessage.fromString(token)
  1932. # Let's store it in the connection data
  1933. connData['NEGOTIATE_MESSAGE'] = negotiateMessage
  1934. # Let's build the answer flags
  1935. # TODO: Parse all the flags. With this we're leaving some clients out
  1936. ansFlags = 0
  1937. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
  1938. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
  1939. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
  1940. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
  1941. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
  1942. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
  1943. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
  1944. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
  1945. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
  1946. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
  1947. if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
  1948. ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
  1949. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
  1950. # Generate the AV_PAIRS
  1951. av_pairs = ntlm.AV_PAIRS()
  1952. # TODO: Put the proper data from SMBSERVER config
  1953. av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
  1954. av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
  1955. av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
  1956. challengeMessage = ntlm.NTLMAuthChallenge()
  1957. challengeMessage['flags'] = ansFlags
  1958. challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
  1959. challengeMessage['domain_max_len'] = challengeMessage['domain_len']
  1960. challengeMessage['domain_offset'] = 40 + 16
  1961. challengeMessage['challenge'] = smbServer.getSMBChallenge()
  1962. challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
  1963. challengeMessage['TargetInfoFields_len'] = len(av_pairs)
  1964. challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
  1965. challengeMessage['TargetInfoFields'] = av_pairs
  1966. challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
  1967. challengeMessage['Version'] = '\xff'*8
  1968. challengeMessage['VersionLen'] = 8
  1969. if rawNTLM is False:
  1970. respToken = SPNEGO_NegTokenResp()
  1971. # accept-incomplete. We want more data
  1972. respToken['NegResult'] = '\x01'
  1973. respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
  1974. respToken['ResponseToken'] = challengeMessage.getData()
  1975. else:
  1976. respToken = challengeMessage
  1977. # Setting the packet to STATUS_MORE_PROCESSING
  1978. errorCode = STATUS_MORE_PROCESSING_REQUIRED
  1979. # Let's set up an UID for this connection and store it
  1980. # in the connection's data
  1981. # Picking a fixed value
  1982. # TODO: Manage more UIDs for the same session
  1983. connData['Uid'] = 10
  1984. # Let's store it in the connection data
  1985. connData['CHALLENGE_MESSAGE'] = challengeMessage
  1986. elif messageType == 0x02:
  1987. # CHALLENGE_MESSAGE
  1988. raise Exception('Challenge Message raise, not implemented!')
  1989. elif messageType == 0x03:
  1990. # AUTHENTICATE_MESSAGE, here we deal with authentication
  1991. authenticateMessage = ntlm.NTLMAuthChallengeResponse()
  1992. authenticateMessage.fromString(token)
  1993. smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
  1994. # TODO: Check the credentials! Now granting permissions
  1995. respToken = SPNEGO_NegTokenResp()
  1996. # accept-completed
  1997. respToken['NegResult'] = '\x00'
  1998. # Status SUCCESS
  1999. errorCode = STATUS_SUCCESS
  2000. smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
  2001. # Let's store it in the connection data
  2002. connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
  2003. try:
  2004. jtr_dump_path = smbServer.getJTRdumpPath()
  2005. ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
  2006. smbServer.log(ntlm_hash_data['hash_string'])
  2007. if jtr_dump_path is not '':
  2008. writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
  2009. except:
  2010. smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
  2011. else:
  2012. raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
  2013. respParameters['SecurityBlobLength'] = len(respToken)
  2014. respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
  2015. respData['SecurityBlob'] = respToken.getData()
  2016. else:
  2017. # Process Standard Security
  2018. respParameters = smb.SMBSessionSetupAndXResponse_Parameters()
  2019. respData = smb.SMBSessionSetupAndXResponse_Data()
  2020. sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters'])
  2021. sessionSetupData = smb.SMBSessionSetupAndX_Data()
  2022. sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength']
  2023. sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength']
  2024. sessionSetupData.fromString(SMBCommand['Data'])
  2025. connData['Capabilities'] = sessionSetupParameters['Capabilities']
  2026. # Do the verification here, for just now we grant access
  2027. # TODO: Manage more UIDs for the same session
  2028. errorCode = STATUS_SUCCESS
  2029. connData['Uid'] = 10
  2030. respParameters['Action'] = 0
  2031. smbServer.log('User %s\\%s authenticated successfully (basic)' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account']))
  2032. try:
  2033. jtr_dump_path = smbServer.getJTRdumpPath()
  2034. ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd'] )
  2035. smbServer.log(ntlm_hash_data['hash_string'])
  2036. if jtr_dump_path is not '':
  2037. writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
  2038. except:
  2039. smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
  2040. respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
  2041. respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
  2042. respSMBCommand['Parameters'] = respParameters
  2043. respSMBCommand['Data'] = respData
  2044. # From now on, the client can ask for other commands
  2045. connData['Authenticated'] = True
  2046. # For now, just switching to nobody
  2047. #os.setregid(65534,65534)
  2048. #os.setreuid(65534,65534)
  2049. smbServer.setConnectionData(connId, connData)
  2050. return [respSMBCommand], None, errorCode
  2051. @staticmethod
  2052. def smbComNegotiate(connId, smbServer, SMBCommand, recvPacket ):
  2053. connData = smbServer.getConnectionData(connId, checkStatus = False)
  2054. connData['Pid'] = recvPacket['Pid']
  2055. SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
  2056. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)
  2057. resp = smb.NewSMBPacket()
  2058. resp['Flags1'] = smb.SMB.FLAGS1_REPLY
  2059. resp['Pid'] = connData['Pid']
  2060. resp['Tid'] = recvPacket['Tid']
  2061. resp['Mid'] = recvPacket['Mid']
  2062. # TODO: We support more dialects, and parse them accordingly
  2063. dialects = SMBCommand['Data'].split('\x02')
  2064. try:
  2065. index = dialects.index('NT LM 0.12\x00') - 1
  2066. # Let's fill the data for NTLM
  2067. if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY:
  2068. resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
  2069. #resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS
  2070. _dialects_data = smb.SMBExtended_Security_Data()
  2071. _dialects_data['ServerGUID'] = 'A'*16
  2072. blob = SPNEGO_NegTokenInit()
  2073. blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
  2074. _dialects_data['SecurityBlob'] = blob.getData()
  2075. _dialects_parameters = smb.SMBExtended_Security_Parameters()
  2076. _dialects_parameters['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS | smb.SMB.CAP_UNICODE
  2077. _dialects_parameters['ChallengeLength'] = 0
  2078. else:
  2079. resp['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
  2080. _dialects_parameters = smb.SMBNTLMDialect_Parameters()
  2081. _dialects_data= smb.SMBNTLMDialect_Data()
  2082. _dialects_data['Payload'] = ''
  2083. if 'EncryptionKey' in connData:
  2084. _dialects_data['Challenge'] = connData['EncryptionKey']
  2085. _dialects_parameters['ChallengeLength'] = len(str(_dialects_data))
  2086. else:
  2087. # TODO: Handle random challenges, now one that can be used with rainbow tables
  2088. _dialects_data['Challenge'] = '\x11\x22\x33\x44\x55\x66\x77\x88'
  2089. _dialects_parameters['ChallengeLength'] = 8
  2090. _dialects_parameters['Capabilities'] = smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS
  2091. # Let's see if we need to support RPC_REMOTE_APIS
  2092. config = smbServer.getServerConfig()
  2093. if config.has_option('global','rpc_apis'):
  2094. if config.getboolean('global', 'rpc_apis') is True:
  2095. _dialects_parameters['Capabilities'] |= smb.SMB.CAP_RPC_REMOTE_APIS
  2096. _dialects_parameters['DialectIndex'] = index
  2097. _dialects_parameters['SecurityMode'] = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER
  2098. _dialects_parameters['MaxMpxCount'] = 1
  2099. _dialects_parameters['MaxNumberVcs'] = 1
  2100. _dialects_parameters['MaxBufferSize'] = 64000
  2101. _dialects_parameters['MaxRawSize'] = 65536
  2102. _dialects_parameters['SessionKey'] = 0
  2103. _dialects_parameters['LowDateTime'] = 0
  2104. _dialects_parameters['HighDateTime'] = 0
  2105. _dialects_parameters['ServerTimeZone'] = 0
  2106. respSMBCommand['Data'] = _dialects_data
  2107. respSMBCommand['Parameters'] = _dialects_parameters
  2108. connData['_dialects_data'] = _dialects_data
  2109. connData['_dialects_parameters'] = _dialects_parameters
  2110. except Exception as e:
  2111. # No NTLM throw an error
  2112. smbServer.log('smbComNegotiate: %s' % e, logging.ERROR)
  2113. respSMBCommand['Data'] = struct.pack('<H',0xffff)
  2114. smbServer.setConnectionData(connId, connData)
  2115. resp.addCommand(respSMBCommand)
  2116. return None, [resp], STATUS_SUCCESS
  2117. @staticmethod
  2118. def default(connId, smbServer, SMBCommand, recvPacket):
  2119. # By default we return an SMB Packet with error not implemented
  2120. smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
  2121. packet = smb.NewSMBPacket()
  2122. packet['Flags1'] = smb.SMB.FLAGS1_REPLY
  2123. packet['Flags2'] = smb.SMB.FLAGS2_NT_STATUS
  2124. packet['Command'] = recvPacket['Command']
  2125. packet['Pid'] = recvPacket['Pid']
  2126. packet['Tid'] = recvPacket['Tid']
  2127. packet['Mid'] = recvPacket['Mid']
  2128. packet['Uid'] = recvPacket['Uid']
  2129. packet['Data'] = '\x00\x00\x00'
  2130. errorCode = STATUS_NOT_IMPLEMENTED
  2131. packet['ErrorCode'] = errorCode >> 16
  2132. packet['ErrorClass'] = errorCode & 0xff
  2133. return None, [packet], errorCode
  2134. class SMB2Commands:
  2135. @staticmethod
  2136. def smb2Negotiate(connId, smbServer, recvPacket, isSMB1 = False):
  2137. connData = smbServer.getConnectionData(connId, checkStatus = False)
  2138. respPacket = smb2.SMB2Packet()
  2139. respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
  2140. respPacket['Status'] = STATUS_SUCCESS
  2141. respPacket['CreditRequestResponse'] = 1
  2142. respPacket['Command'] = smb2.SMB2_NEGOTIATE
  2143. respPacket['SessionID'] = 0
  2144. if isSMB1 is False:
  2145. respPacket['MessageID'] = recvPacket['MessageID']
  2146. else:
  2147. respPacket['MessageID'] = 0
  2148. respPacket['TreeID'] = 0
  2149. respSMBCommand = smb2.SMB2Negotiate_Response()
  2150. respSMBCommand['SecurityMode'] = 1
  2151. if isSMB1 is True:
  2152. # Let's first parse the packet to see if the client supports SMB2
  2153. SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
  2154. dialects = SMBCommand['Data'].split('\x02')
  2155. if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects:
  2156. respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
  2157. else:
  2158. # Client does not support SMB2 fallbacking
  2159. raise Exception('SMB2 not supported, fallbacking')
  2160. else:
  2161. respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
  2162. respSMBCommand['ServerGuid'] = 'A'*16
  2163. respSMBCommand['Capabilities'] = 0
  2164. respSMBCommand['MaxTransactSize'] = 65536
  2165. respSMBCommand['MaxReadSize'] = 65536
  2166. respSMBCommand['MaxWriteSize'] = 65536
  2167. respSMBCommand['SystemTime'] = getFileTime(calendar.timegm(time.gmtime()))
  2168. respSMBCommand['ServerStartTime'] = getFileTime(calendar.timegm(time.gmtime()))
  2169. respSMBCommand['SecurityBufferOffset'] = 0x80
  2170. blob = SPNEGO_NegTokenInit()
  2171. blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
  2172. respSMBCommand['Buffer'] = blob.getData()
  2173. respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer'])
  2174. respPacket['Data'] = respSMBCommand
  2175. smbServer.setConnectionData(connId, connData)
  2176. return None, [respPacket], STATUS_SUCCESS
  2177. @staticmethod
  2178. def smb2SessionSetup(connId, smbServer, recvPacket):
  2179. connData = smbServer.getConnectionData(connId, checkStatus = False)
  2180. respSMBCommand = smb2.SMB2SessionSetup_Response()
  2181. sessionSetupData = smb2.SMB2SessionSetup(recvPacket['Data'])
  2182. connData['Capabilities'] = sessionSetupData['Capabilities']
  2183. securityBlob = sessionSetupData['Buffer']
  2184. rawNTLM = False
  2185. if struct.unpack('B',securityBlob[0])[0] == ASN1_AID:
  2186. # NEGOTIATE packet
  2187. blob = SPNEGO_NegTokenInit(securityBlob)
  2188. token = blob['MechToken']
  2189. if len(blob['MechTypes'][0]) > 0:
  2190. # Is this GSSAPI NTLM or something else we don't support?
  2191. mechType = blob['MechTypes'][0]
  2192. if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
  2193. # Nope, do we know it?
  2194. if mechType in MechTypes:
  2195. mechStr = MechTypes[mechType]
  2196. else:
  2197. mechStr = hexlify(mechType)
  2198. smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
  2199. # We don't know the token, we answer back again saying
  2200. # we just support NTLM.
  2201. # ToDo: Build this into a SPNEGO_NegTokenResp()
  2202. respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
  2203. respSMBCommand['SecurityBufferOffset'] = 0x48
  2204. respSMBCommand['SecurityBufferLength'] = len(respToken)
  2205. respSMBCommand['Buffer'] = respToken
  2206. return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
  2207. elif struct.unpack('B',securityBlob[0])[0] == ASN1_SUPPORTED_MECH:
  2208. # AUTH packet
  2209. blob = SPNEGO_NegTokenResp(securityBlob)
  2210. token = blob['ResponseToken']
  2211. else:
  2212. # No GSSAPI stuff, raw NTLMSSP
  2213. rawNTLM = True
  2214. token = securityBlob
  2215. # Here we only handle NTLMSSP, depending on what stage of the
  2216. # authentication we are, we act on it
  2217. messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
  2218. if messageType == 0x01:
  2219. # NEGOTIATE_MESSAGE
  2220. negotiateMessage = ntlm.NTLMAuthNegotiate()
  2221. negotiateMessage.fromString(token)
  2222. # Let's store it in the connection data
  2223. connData['NEGOTIATE_MESSAGE'] = negotiateMessage
  2224. # Let's build the answer flags
  2225. # TODO: Parse all the flags. With this we're leaving some clients out
  2226. ansFlags = 0
  2227. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
  2228. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
  2229. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
  2230. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
  2231. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
  2232. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
  2233. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
  2234. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
  2235. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
  2236. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
  2237. if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
  2238. ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
  2239. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
  2240. # Generate the AV_PAIRS
  2241. av_pairs = ntlm.AV_PAIRS()
  2242. # TODO: Put the proper data from SMBSERVER config
  2243. av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
  2244. av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
  2245. av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
  2246. challengeMessage = ntlm.NTLMAuthChallenge()
  2247. challengeMessage['flags'] = ansFlags
  2248. challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
  2249. challengeMessage['domain_max_len'] = challengeMessage['domain_len']
  2250. challengeMessage['domain_offset'] = 40 + 16
  2251. challengeMessage['challenge'] = smbServer.getSMBChallenge()
  2252. challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
  2253. challengeMessage['TargetInfoFields_len'] = len(av_pairs)
  2254. challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
  2255. challengeMessage['TargetInfoFields'] = av_pairs
  2256. challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
  2257. challengeMessage['Version'] = '\xff'*8
  2258. challengeMessage['VersionLen'] = 8
  2259. if rawNTLM is False:
  2260. respToken = SPNEGO_NegTokenResp()
  2261. # accept-incomplete. We want more data
  2262. respToken['NegResult'] = '\x01'
  2263. respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
  2264. respToken['ResponseToken'] = challengeMessage.getData()
  2265. else:
  2266. respToken = challengeMessage
  2267. # Setting the packet to STATUS_MORE_PROCESSING
  2268. errorCode = STATUS_MORE_PROCESSING_REQUIRED
  2269. # Let's set up an UID for this connection and store it
  2270. # in the connection's data
  2271. # Picking a fixed value
  2272. # TODO: Manage more UIDs for the same session
  2273. connData['Uid'] = random.randint(1,0xffffffff)
  2274. # Let's store it in the connection data
  2275. connData['CHALLENGE_MESSAGE'] = challengeMessage
  2276. elif messageType == 0x02:
  2277. # CHALLENGE_MESSAGE
  2278. raise Exception('Challenge Message raise, not implemented!')
  2279. elif messageType == 0x03:
  2280. # AUTHENTICATE_MESSAGE, here we deal with authentication
  2281. authenticateMessage = ntlm.NTLMAuthChallengeResponse()
  2282. authenticateMessage.fromString(token)
  2283. smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
  2284. # TODO: Check the credentials! Now granting permissions
  2285. respToken = SPNEGO_NegTokenResp()
  2286. # accept-completed
  2287. respToken['NegResult'] = '\x00'
  2288. # Status SUCCESS
  2289. errorCode = STATUS_SUCCESS
  2290. smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
  2291. # Let's store it in the connection data
  2292. connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
  2293. try:
  2294. jtr_dump_path = smbServer.getJTRdumpPath()
  2295. ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
  2296. smbServer.log(ntlm_hash_data['hash_string'])
  2297. if jtr_dump_path is not '':
  2298. writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
  2299. except:
  2300. smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
  2301. respSMBCommand['SessionFlags'] = 1
  2302. else:
  2303. raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
  2304. respSMBCommand['SecurityBufferOffset'] = 0x48
  2305. respSMBCommand['SecurityBufferLength'] = len(respToken)
  2306. respSMBCommand['Buffer'] = respToken.getData()
  2307. # From now on, the client can ask for other commands
  2308. connData['Authenticated'] = True
  2309. # For now, just switching to nobody
  2310. #os.setregid(65534,65534)
  2311. #os.setreuid(65534,65534)
  2312. smbServer.setConnectionData(connId, connData)
  2313. return [respSMBCommand], None, errorCode
  2314. @staticmethod
  2315. def smb2TreeConnect(connId, smbServer, recvPacket):
  2316. connData = smbServer.getConnectionData(connId)
  2317. respPacket = smb2.SMB2Packet()
  2318. respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
  2319. respPacket['Status'] = STATUS_SUCCESS
  2320. respPacket['CreditRequestResponse'] = 1
  2321. respPacket['Command'] = recvPacket['Command']
  2322. respPacket['SessionID'] = connData['Uid']
  2323. respPacket['Reserved'] = recvPacket['Reserved']
  2324. respPacket['MessageID'] = recvPacket['MessageID']
  2325. respPacket['TreeID'] = recvPacket['TreeID']
  2326. respSMBCommand = smb2.SMB2TreeConnect_Response()
  2327. treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data'])
  2328. errorCode = STATUS_SUCCESS
  2329. ## Process here the request, does the share exist?
  2330. path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']]
  2331. UNCOrShare = path.decode('utf-16le')
  2332. # Is this a UNC?
  2333. if ntpath.ismount(UNCOrShare):
  2334. path = UNCOrShare.split('\\')[3]
  2335. else:
  2336. path = ntpath.basename(UNCOrShare)
  2337. share = searchShare(connId, path.upper(), smbServer)
  2338. if share is not None:
  2339. # Simple way to generate a Tid
  2340. if len(connData['ConnectedShares']) == 0:
  2341. tid = 1
  2342. else:
  2343. tid = connData['ConnectedShares'].keys()[-1] + 1
  2344. connData['ConnectedShares'][tid] = share
  2345. connData['ConnectedShares'][tid]['shareName'] = path
  2346. respPacket['TreeID'] = tid
  2347. smbServer.log("Connecting Share(%d:%s)" % (tid,path))
  2348. else:
  2349. smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR)
  2350. errorCode = STATUS_OBJECT_PATH_NOT_FOUND
  2351. respPacket['Status'] = errorCode
  2352. ##
  2353. if path == 'IPC$':
  2354. respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE
  2355. respSMBCommand['ShareFlags'] = 0x30
  2356. else:
  2357. respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK
  2358. respSMBCommand['ShareFlags'] = 0x0
  2359. respSMBCommand['Capabilities'] = 0
  2360. respSMBCommand['MaximalAccess'] = 0x000f01ff
  2361. respPacket['Data'] = respSMBCommand
  2362. smbServer.setConnectionData(connId, connData)
  2363. return None, [respPacket], errorCode
  2364. @staticmethod
  2365. def smb2Create(connId, smbServer, recvPacket):
  2366. connData = smbServer.getConnectionData(connId)
  2367. respSMBCommand = smb2.SMB2Create_Response()
  2368. ntCreateRequest = smb2.SMB2Create(recvPacket['Data'])
  2369. respSMBCommand['Buffer'] = '\x00'
  2370. # Get the Tid associated
  2371. if recvPacket['TreeID'] in connData['ConnectedShares']:
  2372. # If we have a rootFid, the path is relative to that fid
  2373. errorCode = STATUS_SUCCESS
  2374. if 'path' in connData['ConnectedShares'][recvPacket['TreeID']]:
  2375. path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
  2376. else:
  2377. path = 'NONE'
  2378. errorCode = STATUS_ACCESS_DENIED
  2379. deleteOnClose = False
  2380. fileName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/'))
  2381. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  2382. # strip leading '/'
  2383. fileName = fileName[1:]
  2384. pathName = os.path.join(path,fileName)
  2385. createDisposition = ntCreateRequest['CreateDisposition']
  2386. mode = 0
  2387. if createDisposition == smb2.FILE_SUPERSEDE:
  2388. mode |= os.O_TRUNC | os.O_CREAT
  2389. elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF:
  2390. mode |= os.O_TRUNC | os.O_CREAT
  2391. elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE:
  2392. if os.path.exists(pathName) is True:
  2393. mode |= os.O_TRUNC
  2394. else:
  2395. errorCode = STATUS_NO_SUCH_FILE
  2396. elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF:
  2397. if os.path.exists(pathName) is True:
  2398. mode |= os.O_TRUNC
  2399. else:
  2400. mode |= os.O_TRUNC | os.O_CREAT
  2401. elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE:
  2402. if os.path.exists(pathName) is True:
  2403. errorCode = STATUS_OBJECT_NAME_COLLISION
  2404. else:
  2405. mode |= os.O_CREAT
  2406. elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN:
  2407. if os.path.exists(pathName) is not True and (unicode(pathName) in smbServer.getRegisteredNamedPipes()) is not True:
  2408. errorCode = STATUS_NO_SUCH_FILE
  2409. if errorCode == STATUS_SUCCESS:
  2410. desiredAccess = ntCreateRequest['DesiredAccess']
  2411. if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
  2412. mode |= os.O_RDONLY
  2413. if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE):
  2414. if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
  2415. mode |= os.O_RDWR #| os.O_APPEND
  2416. else:
  2417. mode |= os.O_WRONLY #| os.O_APPEND
  2418. if desiredAccess & smb2.GENERIC_ALL:
  2419. mode |= os.O_RDWR #| os.O_APPEND
  2420. createOptions = ntCreateRequest['CreateOptions']
  2421. if mode & os.O_CREAT == os.O_CREAT:
  2422. if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE:
  2423. try:
  2424. # Let's create the directory
  2425. os.mkdir(pathName)
  2426. mode = os.O_RDONLY
  2427. except Exception as e:
  2428. smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
  2429. errorCode = STATUS_ACCESS_DENIED
  2430. if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE:
  2431. # If the file being opened is a directory, the server MUST fail the request with
  2432. # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
  2433. # response.
  2434. if os.path.isdir(pathName) is True:
  2435. errorCode = STATUS_FILE_IS_A_DIRECTORY
  2436. if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE:
  2437. deleteOnClose = True
  2438. if errorCode == STATUS_SUCCESS:
  2439. try:
  2440. if os.path.isdir(pathName) and sys.platform == 'win32':
  2441. fid = VOID_FILE_DESCRIPTOR
  2442. else:
  2443. if sys.platform == 'win32':
  2444. mode |= os.O_BINARY
  2445. if unicode(pathName) in smbServer.getRegisteredNamedPipes():
  2446. fid = PIPE_FILE_DESCRIPTOR
  2447. sock = socket.socket()
  2448. sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
  2449. else:
  2450. fid = os.open(pathName, mode)
  2451. except Exception as e:
  2452. smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
  2453. #print e
  2454. fid = 0
  2455. errorCode = STATUS_ACCESS_DENIED
  2456. else:
  2457. errorCode = STATUS_SMB_BAD_TID
  2458. if errorCode == STATUS_SUCCESS:
  2459. # Simple way to generate a fid
  2460. fakefid = uuid.generate()
  2461. respSMBCommand['FileID'] = fakefid
  2462. respSMBCommand['CreateAction'] = createDisposition
  2463. if fid == PIPE_FILE_DESCRIPTOR:
  2464. respSMBCommand['CreationTime'] = 0
  2465. respSMBCommand['LastAccessTime'] = 0
  2466. respSMBCommand['LastWriteTime'] = 0
  2467. respSMBCommand['ChangeTime'] = 0
  2468. respSMBCommand['AllocationSize'] = 4096
  2469. respSMBCommand['EndOfFile'] = 0
  2470. respSMBCommand['FileAttributes'] = 0x80
  2471. else:
  2472. if os.path.isdir(pathName):
  2473. respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
  2474. else:
  2475. respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes']
  2476. # Let's get this file's information
  2477. respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
  2478. if errorCode == STATUS_SUCCESS:
  2479. respSMBCommand['CreationTime'] = respInfo['CreationTime']
  2480. respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime']
  2481. respSMBCommand['LastWriteTime'] = respInfo['LastWriteTime']
  2482. respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime']
  2483. respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes']
  2484. respSMBCommand['AllocationSize'] = respInfo['AllocationSize']
  2485. respSMBCommand['EndOfFile'] = respInfo['EndOfFile']
  2486. if errorCode == STATUS_SUCCESS:
  2487. # Let's store the fid for the connection
  2488. # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
  2489. connData['OpenedFiles'][fakefid] = {}
  2490. connData['OpenedFiles'][fakefid]['FileHandle'] = fid
  2491. connData['OpenedFiles'][fakefid]['FileName'] = pathName
  2492. connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
  2493. connData['OpenedFiles'][fakefid]['Open'] = {}
  2494. connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0
  2495. connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = ''
  2496. if fid == PIPE_FILE_DESCRIPTOR:
  2497. connData['OpenedFiles'][fakefid]['Socket'] = sock
  2498. else:
  2499. respSMBCommand = smb2.SMB2Error()
  2500. if errorCode == STATUS_SUCCESS:
  2501. connData['LastRequest']['SMB2_CREATE'] = respSMBCommand
  2502. smbServer.setConnectionData(connId, connData)
  2503. return [respSMBCommand], None, errorCode
  2504. @staticmethod
  2505. def smb2Close(connId, smbServer, recvPacket):
  2506. connData = smbServer.getConnectionData(connId)
  2507. respSMBCommand = smb2.SMB2Close_Response()
  2508. closeRequest = smb2.SMB2Close(recvPacket['Data'])
  2509. if str(closeRequest['FileID']) == '\xff'*16:
  2510. # Let's take the data from the lastRequest
  2511. if 'SMB2_CREATE' in connData['LastRequest']:
  2512. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2513. else:
  2514. fileID = str(closeRequest['FileID'])
  2515. else:
  2516. fileID = str(closeRequest['FileID'])
  2517. if fileID in connData['OpenedFiles']:
  2518. errorCode = STATUS_SUCCESS
  2519. fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
  2520. pathName = connData['OpenedFiles'][fileID]['FileName']
  2521. infoRecord = None
  2522. try:
  2523. if fileHandle == PIPE_FILE_DESCRIPTOR:
  2524. connData['OpenedFiles'][fileID]['Socket'].close()
  2525. elif fileHandle != VOID_FILE_DESCRIPTOR:
  2526. os.close(fileHandle)
  2527. infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), smb2.SMB2_FILE_NETWORK_OPEN_INFO)
  2528. except Exception as e:
  2529. smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
  2530. errorCode = STATUS_INVALID_HANDLE
  2531. else:
  2532. # Check if the file was marked for removal
  2533. if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True:
  2534. try:
  2535. if os.path.isdir(pathName):
  2536. shutil.rmtree(connData['OpenedFiles'][fileID]['FileName'])
  2537. else:
  2538. os.remove(connData['OpenedFiles'][fileID]['FileName'])
  2539. except Exception as e:
  2540. smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
  2541. errorCode = STATUS_ACCESS_DENIED
  2542. # Now fill out the response
  2543. if infoRecord is not None:
  2544. respSMBCommand['CreationTime'] = infoRecord['CreationTime']
  2545. respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime']
  2546. respSMBCommand['LastWriteTime'] = infoRecord['LastWriteTime']
  2547. respSMBCommand['ChangeTime'] = infoRecord['ChangeTime']
  2548. respSMBCommand['AllocationSize'] = infoRecord['AllocationSize']
  2549. respSMBCommand['EndofFile'] = infoRecord['EndOfFile']
  2550. respSMBCommand['FileAttributes'] = infoRecord['FileAttributes']
  2551. if errorCode == STATUS_SUCCESS:
  2552. del(connData['OpenedFiles'][fileID])
  2553. else:
  2554. errorCode = STATUS_INVALID_HANDLE
  2555. smbServer.setConnectionData(connId, connData)
  2556. return [respSMBCommand], None, errorCode
  2557. @staticmethod
  2558. def smb2QueryInfo(connId, smbServer, recvPacket):
  2559. connData = smbServer.getConnectionData(connId)
  2560. respSMBCommand = smb2.SMB2QueryInfo_Response()
  2561. queryInfo = smb2.SMB2QueryInfo(recvPacket['Data'])
  2562. errorCode = STATUS_SUCCESS
  2563. respSMBCommand['OutputBufferOffset'] = 0x48
  2564. respSMBCommand['Buffer'] = '\x00'
  2565. if str(queryInfo['FileID']) == '\xff'*16:
  2566. # Let's take the data from the lastRequest
  2567. if 'SMB2_CREATE' in connData['LastRequest']:
  2568. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2569. else:
  2570. fileID = str(queryInfo['FileID'])
  2571. else:
  2572. fileID = str(queryInfo['FileID'])
  2573. if recvPacket['TreeID'] in connData['ConnectedShares']:
  2574. if fileID in connData['OpenedFiles']:
  2575. fileName = connData['OpenedFiles'][fileID]['FileName']
  2576. if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
  2577. if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO:
  2578. # No need to call queryFileInformation, we have the data here
  2579. infoRecord = smb2.FileInternalInformation()
  2580. infoRecord['IndexNumber'] = fileID
  2581. else:
  2582. infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
  2583. elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
  2584. infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
  2585. elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
  2586. # Failing for now, until we support it
  2587. infoRecord = None
  2588. errorCode = STATUS_ACCESS_DENIED
  2589. else:
  2590. smbServer.log("queryInfo not supported (%x)" % queryInfo['InfoType'], logging.ERROR)
  2591. if infoRecord is not None:
  2592. respSMBCommand['OutputBufferLength'] = len(infoRecord)
  2593. respSMBCommand['Buffer'] = infoRecord
  2594. else:
  2595. errorCode = STATUS_INVALID_HANDLE
  2596. else:
  2597. errorCode = STATUS_SMB_BAD_TID
  2598. smbServer.setConnectionData(connId, connData)
  2599. return [respSMBCommand], None, errorCode
  2600. @staticmethod
  2601. def smb2SetInfo(connId, smbServer, recvPacket):
  2602. connData = smbServer.getConnectionData(connId)
  2603. respSMBCommand = smb2.SMB2SetInfo_Response()
  2604. setInfo = smb2.SMB2SetInfo(recvPacket['Data'])
  2605. errorCode = STATUS_SUCCESS
  2606. if str(setInfo['FileID']) == '\xff'*16:
  2607. # Let's take the data from the lastRequest
  2608. if 'SMB2_CREATE' in connData['LastRequest']:
  2609. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2610. else:
  2611. fileID = str(setInfo['FileID'])
  2612. else:
  2613. fileID = str(setInfo['FileID'])
  2614. if recvPacket['TreeID'] in connData['ConnectedShares']:
  2615. path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
  2616. if fileID in connData['OpenedFiles']:
  2617. pathName = connData['OpenedFiles'][fileID]['FileName']
  2618. if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
  2619. # The file information is being set
  2620. informationLevel = setInfo['FileInfoClass']
  2621. if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO:
  2622. infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer'])
  2623. if infoRecord['DeletePending'] > 0:
  2624. # Mark this file for removal after closed
  2625. connData['OpenedFiles'][fileID]['DeleteOnClose'] = True
  2626. elif informationLevel == smb2.SMB2_FILE_BASIC_INFO:
  2627. infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer'])
  2628. # Creation time won't be set, the other ones we play with.
  2629. atime = infoRecord['LastWriteTime']
  2630. if atime == 0:
  2631. atime = -1
  2632. else:
  2633. atime = getUnixTime(atime)
  2634. mtime = infoRecord['ChangeTime']
  2635. if mtime == 0:
  2636. mtime = -1
  2637. else:
  2638. mtime = getUnixTime(mtime)
  2639. if atime > 0 and mtime > 0:
  2640. os.utime(pathName,(atime,mtime))
  2641. elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO:
  2642. fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
  2643. infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer'])
  2644. if infoRecord['EndOfFile'] > 0:
  2645. os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
  2646. os.write(fileHandle, '\x00')
  2647. elif informationLevel == smb2.SMB2_FILE_RENAME_INFO:
  2648. renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer'])
  2649. newPathName = os.path.join(path,renameInfo['FileName'].decode('utf-16le').replace('\\', '/'))
  2650. if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName):
  2651. return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION
  2652. try:
  2653. os.rename(pathName,newPathName)
  2654. connData['OpenedFiles'][fileID]['FileName'] = newPathName
  2655. except Exception as e:
  2656. smbServer.log("smb2SetInfo: %s" % e, logging.ERROR)
  2657. errorCode = STATUS_ACCESS_DENIED
  2658. else:
  2659. smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR)
  2660. # UNSUPPORTED
  2661. errorCode = STATUS_NOT_SUPPORTED
  2662. #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
  2663. # # The underlying object store information is being set.
  2664. # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
  2665. #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
  2666. # # The security information is being set.
  2667. # # Failing for now, until we support it
  2668. # infoRecord = None
  2669. # errorCode = STATUS_ACCESS_DENIED
  2670. #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA:
  2671. # # The underlying object store quota information is being set.
  2672. # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
  2673. else:
  2674. smbServer.log("setInfo not supported (%x)" % setInfo['InfoType'], logging.ERROR)
  2675. else:
  2676. errorCode = STATUS_INVALID_HANDLE
  2677. else:
  2678. errorCode = STATUS_SMB_BAD_TID
  2679. smbServer.setConnectionData(connId, connData)
  2680. return [respSMBCommand], None, errorCode
  2681. @staticmethod
  2682. def smb2Write(connId, smbServer, recvPacket):
  2683. connData = smbServer.getConnectionData(connId)
  2684. respSMBCommand = smb2.SMB2Write_Response()
  2685. writeRequest = smb2.SMB2Write(recvPacket['Data'])
  2686. respSMBCommand['Buffer'] = '\x00'
  2687. if str(writeRequest['FileID']) == '\xff'*16:
  2688. # Let's take the data from the lastRequest
  2689. if 'SMB2_CREATE' in connData['LastRequest']:
  2690. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2691. else:
  2692. fileID = str(writeRequest['FileID'])
  2693. else:
  2694. fileID = str(writeRequest['FileID'])
  2695. if fileID in connData['OpenedFiles']:
  2696. fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
  2697. errorCode = STATUS_SUCCESS
  2698. try:
  2699. if fileHandle != PIPE_FILE_DESCRIPTOR:
  2700. offset = writeRequest['Offset']
  2701. # If we're trying to write past the file end we just skip the write call (Vista does this)
  2702. if os.lseek(fileHandle, 0, 2) >= offset:
  2703. os.lseek(fileHandle,offset,0)
  2704. os.write(fileHandle,writeRequest['Buffer'])
  2705. else:
  2706. sock = connData['OpenedFiles'][fileID]['Socket']
  2707. sock.send(writeRequest['Buffer'])
  2708. respSMBCommand['Count'] = writeRequest['Length']
  2709. respSMBCommand['Remaining']= 0xff
  2710. except Exception as e:
  2711. smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR)
  2712. errorCode = STATUS_ACCESS_DENIED
  2713. else:
  2714. errorCode = STATUS_INVALID_HANDLE
  2715. smbServer.setConnectionData(connId, connData)
  2716. return [respSMBCommand], None, errorCode
  2717. @staticmethod
  2718. def smb2Read(connId, smbServer, recvPacket):
  2719. connData = smbServer.getConnectionData(connId)
  2720. respSMBCommand = smb2.SMB2Read_Response()
  2721. readRequest = smb2.SMB2Read(recvPacket['Data'])
  2722. respSMBCommand['Buffer'] = '\x00'
  2723. if str(readRequest['FileID']) == '\xff'*16:
  2724. # Let's take the data from the lastRequest
  2725. if 'SMB2_CREATE' in connData['LastRequest']:
  2726. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2727. else:
  2728. fileID = str(readRequest['FileID'])
  2729. else:
  2730. fileID = str(readRequest['FileID'])
  2731. if fileID in connData['OpenedFiles']:
  2732. fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
  2733. errorCode = 0
  2734. try:
  2735. if fileHandle != PIPE_FILE_DESCRIPTOR:
  2736. offset = readRequest['Offset']
  2737. os.lseek(fileHandle,offset,0)
  2738. content = os.read(fileHandle,readRequest['Length'])
  2739. else:
  2740. sock = connData['OpenedFiles'][fileID]['Socket']
  2741. content = sock.recv(readRequest['Length'])
  2742. respSMBCommand['DataOffset'] = 0x50
  2743. respSMBCommand['DataLength'] = len(content)
  2744. respSMBCommand['DataRemaining']= 0
  2745. respSMBCommand['Buffer'] = content
  2746. except Exception as e:
  2747. smbServer.log('SMB2_READ: %s ' % e, logging.ERROR)
  2748. errorCode = STATUS_ACCESS_DENIED
  2749. else:
  2750. errorCode = STATUS_INVALID_HANDLE
  2751. smbServer.setConnectionData(connId, connData)
  2752. return [respSMBCommand], None, errorCode
  2753. @staticmethod
  2754. def smb2Flush(connId, smbServer, recvPacket):
  2755. connData = smbServer.getConnectionData(connId)
  2756. respSMBCommand = smb2.SMB2Flush_Response()
  2757. flushRequest = smb2.SMB2Flush(recvPacket['Data'])
  2758. if str(flushRequest['FileID']) in connData['OpenedFiles']:
  2759. fileHandle = connData['OpenedFiles'][str(flushRequest['FileID'])]['FileHandle']
  2760. errorCode = STATUS_SUCCESS
  2761. try:
  2762. os.fsync(fileHandle)
  2763. except Exception as e:
  2764. smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR)
  2765. errorCode = STATUS_ACCESS_DENIED
  2766. else:
  2767. errorCode = STATUS_INVALID_HANDLE
  2768. smbServer.setConnectionData(connId, connData)
  2769. return [respSMBCommand], None, errorCode
  2770. @staticmethod
  2771. def smb2QueryDirectory(connId, smbServer, recvPacket):
  2772. connData = smbServer.getConnectionData(connId)
  2773. respSMBCommand = smb2.SMB2QueryDirectory_Response()
  2774. queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data'])
  2775. respSMBCommand['Buffer'] = '\x00'
  2776. # The server MUST locate the tree connection, as specified in section 3.3.5.2.11.
  2777. if (recvPacket['TreeID'] in connData['ConnectedShares']) is False:
  2778. return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED
  2779. # Next, the server MUST locate the open for the directory to be queried
  2780. # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED
  2781. if str(queryDirectoryRequest['FileID']) == '\xff'*16:
  2782. # Let's take the data from the lastRequest
  2783. if 'SMB2_CREATE' in connData['LastRequest']:
  2784. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2785. else:
  2786. fileID = str(queryDirectoryRequest['FileID'])
  2787. else:
  2788. fileID = str(queryDirectoryRequest['FileID'])
  2789. if (fileID in connData['OpenedFiles']) is False:
  2790. return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED
  2791. # If the open is not an open to a directory, the request MUST be failed
  2792. # with STATUS_INVALID_PARAMETER.
  2793. if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False:
  2794. return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER
  2795. # If any other information class is specified in the FileInformationClass
  2796. # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the
  2797. # operation with STATUS_INVALID_INFO_CLASS.
  2798. if queryDirectoryRequest['FileInformationClass'] not in (
  2799. smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, smb2.FILEID_FULL_DIRECTORY_INFORMATION,
  2800. smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, smb2.FILENAMES_INFORMATION):
  2801. return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS
  2802. # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY
  2803. # Request, the server SHOULD<326> set Open.EnumerationLocation to 0
  2804. # and Open.EnumerationSearchPattern to an empty string.
  2805. if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN:
  2806. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
  2807. connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = ''
  2808. # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2
  2809. # QUERY_DIRECTORY Request, the server MUST set
  2810. # Open.EnumerationLocation to 0.
  2811. if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS:
  2812. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
  2813. # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern
  2814. # is an empty string, then Open.EnumerationSearchPattern MUST be set
  2815. # to the search pattern specified in the SMB2 QUERY_DIRECTORY by
  2816. # FileNameOffset and FileNameLength. If FileNameLength is 0, the server
  2817. # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries.
  2818. pattern = queryDirectoryRequest['Buffer'].decode('utf-16le')
  2819. if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \
  2820. connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '':
  2821. if pattern == '':
  2822. pattern = '*'
  2823. connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
  2824. # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero,
  2825. # the server MUST set Open.EnumerationSearchPattern to the search pattern
  2826. # specified in the request by FileNameOffset and FileNameLength.
  2827. if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \
  2828. queryDirectoryRequest['FileNameLength'] > 0:
  2829. connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
  2830. pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']),pattern)
  2831. searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName),
  2832. os.path.basename(pathName),
  2833. queryDirectoryRequest['FileInformationClass'],
  2834. smb.ATTR_DIRECTORY, isSMB2 = True )
  2835. if errorCode != STATUS_SUCCESS:
  2836. return [smb2.SMB2Error()], None, errorCode
  2837. if searchCount > 2 and pattern == '*':
  2838. # strip . and ..
  2839. searchCount -= 2
  2840. searchResult = searchResult[2:]
  2841. if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0:
  2842. return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE
  2843. if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0:
  2844. return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES
  2845. totalData = 0
  2846. respData = ''
  2847. for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount):
  2848. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1
  2849. if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
  2850. # If single entry is requested we must clear the NextEntryOffset
  2851. searchResult[nItem]['NextEntryOffset'] = 0
  2852. data = searchResult[nItem].getData()
  2853. lenData = len(data)
  2854. padLen = (8-(lenData % 8)) %8
  2855. if (totalData+lenData) >= queryDirectoryRequest['OutputBufferLength']:
  2856. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1
  2857. break
  2858. else:
  2859. respData += data + '\x00'*padLen
  2860. totalData += lenData + padLen
  2861. if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
  2862. break
  2863. if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount:
  2864. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1
  2865. respSMBCommand['OutputBufferOffset'] = 0x48
  2866. respSMBCommand['OutputBufferLength'] = totalData
  2867. respSMBCommand['Buffer'] = respData
  2868. smbServer.setConnectionData(connId, connData)
  2869. return [respSMBCommand], None, errorCode
  2870. @staticmethod
  2871. def smb2ChangeNotify(connId, smbServer, recvPacket):
  2872. return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
  2873. @staticmethod
  2874. def smb2Echo(connId, smbServer, recvPacket):
  2875. respSMBCommand = smb2.SMB2Echo_Response()
  2876. return [respSMBCommand], None, STATUS_SUCCESS
  2877. @staticmethod
  2878. def smb2TreeDisconnect(connId, smbServer, recvPacket):
  2879. connData = smbServer.getConnectionData(connId)
  2880. respSMBCommand = smb2.SMB2TreeDisconnect_Response()
  2881. if recvPacket['TreeID'] in connData['ConnectedShares']:
  2882. smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['TreeID'],connData['ConnectedShares'][recvPacket['TreeID']]['shareName']))
  2883. del(connData['ConnectedShares'][recvPacket['TreeID']])
  2884. errorCode = STATUS_SUCCESS
  2885. else:
  2886. # STATUS_SMB_BAD_TID
  2887. errorCode = STATUS_SMB_BAD_TID
  2888. smbServer.setConnectionData(connId, connData)
  2889. return [respSMBCommand], None, errorCode
  2890. @staticmethod
  2891. def smb2Logoff(connId, smbServer, recvPacket):
  2892. connData = smbServer.getConnectionData(connId)
  2893. respSMBCommand = smb2.SMB2Logoff_Response()
  2894. if recvPacket['SessionID'] != connData['Uid']:
  2895. # STATUS_SMB_BAD_UID
  2896. errorCode = STATUS_SMB_BAD_UID
  2897. else:
  2898. errorCode = STATUS_SUCCESS
  2899. connData['Uid'] = 0
  2900. smbServer.setConnectionData(connId, connData)
  2901. return [respSMBCommand], None, errorCode
  2902. @staticmethod
  2903. def smb2Ioctl(connId, smbServer, recvPacket):
  2904. connData = smbServer.getConnectionData(connId)
  2905. respSMBCommand = smb2.SMB2Ioctl_Response()
  2906. ioctlRequest = smb2.SMB2Ioctl(recvPacket['Data'])
  2907. ioctls = smbServer.getIoctls()
  2908. if ioctlRequest['CtlCode'] in ioctls:
  2909. outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest)
  2910. if errorCode == STATUS_SUCCESS:
  2911. respSMBCommand['CtlCode'] = ioctlRequest['CtlCode']
  2912. respSMBCommand['FileID'] = ioctlRequest['FileID']
  2913. respSMBCommand['InputOffset'] = 0
  2914. respSMBCommand['InputCount'] = 0
  2915. respSMBCommand['OutputOffset'] = 0x70
  2916. respSMBCommand['OutputCount'] = len(outputData)
  2917. respSMBCommand['Flags'] = 0
  2918. respSMBCommand['Buffer'] = outputData
  2919. else:
  2920. respSMBCommand = outputData
  2921. else:
  2922. smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'],logging.DEBUG)
  2923. errorCode = STATUS_INVALID_DEVICE_REQUEST
  2924. respSMBCommand = smb2.SMB2Error()
  2925. smbServer.setConnectionData(connId, connData)
  2926. return [respSMBCommand], None, errorCode
  2927. @staticmethod
  2928. def smb2Lock(connId, smbServer, recvPacket):
  2929. connData = smbServer.getConnectionData(connId)
  2930. respSMBCommand = smb2.SMB2Lock_Response()
  2931. # I'm actually doing nothing.. just make MacOS happy ;)
  2932. errorCode = STATUS_SUCCESS
  2933. smbServer.setConnectionData(connId, connData)
  2934. return [respSMBCommand], None, errorCode
  2935. @staticmethod
  2936. def smb2Cancel(connId, smbServer, recvPacket):
  2937. # I'm actually doing nothing
  2938. return [smb2.SMB2Error()], None, STATUS_CANCELLED
  2939. @staticmethod
  2940. def default(connId, smbServer, recvPacket):
  2941. # By default we return an SMB Packet with error not implemented
  2942. smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
  2943. return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
  2944. class Ioctls:
  2945. @staticmethod
  2946. def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest):
  2947. return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED
  2948. @staticmethod
  2949. def fsctlPipeTransceive(connId, smbServer, ioctlRequest):
  2950. connData = smbServer.getConnectionData(connId)
  2951. ioctlResponse = ''
  2952. if str(ioctlRequest['FileID']) in connData['OpenedFiles']:
  2953. fileHandle = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['FileHandle']
  2954. errorCode = STATUS_SUCCESS
  2955. try:
  2956. if fileHandle != PIPE_FILE_DESCRIPTOR:
  2957. errorCode = STATUS_INVALID_DEVICE_REQUEST
  2958. else:
  2959. sock = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['Socket']
  2960. sock.sendall(ioctlRequest['Buffer'])
  2961. ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse'])
  2962. except Exception as e:
  2963. smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR)
  2964. errorCode = STATUS_ACCESS_DENIED
  2965. else:
  2966. errorCode = STATUS_INVALID_DEVICE_REQUEST
  2967. smbServer.setConnectionData(connId, connData)
  2968. return ioctlResponse, errorCode
  2969. @staticmethod
  2970. def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest):
  2971. connData = smbServer.getConnectionData(connId)
  2972. errorCode = STATUS_SUCCESS
  2973. validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer'])
  2974. validateNegotiateInfo['Capabilities'] = 0
  2975. validateNegotiateInfo['Guid'] = 'A'*16
  2976. validateNegotiateInfo['SecurityMode'] = 1
  2977. validateNegotiateInfo['Dialects'] = (smb2.SMB2_DIALECT_002,)
  2978. smbServer.setConnectionData(connId, connData)
  2979. return validateNegotiateInfo.getData(), errorCode
  2980. class SMBSERVERHandler(SocketServer.BaseRequestHandler):
  2981. def __init__(self, request, client_address, server, select_poll = False):
  2982. self.__SMB = server
  2983. self.__ip, self.__port = client_address
  2984. self.__request = request
  2985. self.__connId = threading.currentThread().getName()
  2986. self.__timeOut = 60*5
  2987. self.__select_poll = select_poll
  2988. #self.__connId = os.getpid()
  2989. SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)
  2990. def handle(self):
  2991. self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port))
  2992. self.__SMB.addConnection(self.__connId, self.__ip, self.__port)
  2993. while True:
  2994. try:
  2995. # Firt of all let's get the NETBIOS packet
  2996. session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(),'HOST', self.__ip, sess_port = self.__port, sock = self.__request, select_poll = self.__select_poll)
  2997. try:
  2998. p = session.recv_packet(self.__timeOut)
  2999. except nmb.NetBIOSTimeout:
  3000. raise
  3001. except nmb.NetBIOSError:
  3002. break
  3003. if p.get_type() == nmb.NETBIOS_SESSION_REQUEST:
  3004. # Someone is requesting a session, we're gonna accept them all :)
  3005. _, rn, my = p.get_trailer().split(' ')
  3006. remote_name = nmb.decode_name('\x20'+rn)
  3007. myname = nmb.decode_name('\x20'+my)
  3008. self.__SMB.log("NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1]))
  3009. r = nmb.NetBIOSSessionPacket()
  3010. r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE)
  3011. r.set_trailer(p.get_trailer())
  3012. self.__request.send(r.rawData())
  3013. else:
  3014. resp = self.__SMB.processRequest(self.__connId, p.get_trailer())
  3015. # Send all the packets recevied. Except for big transactions this should be
  3016. # a single packet
  3017. for i in resp:
  3018. session.send_packet(str(i))
  3019. except Exception as e:
  3020. self.__SMB.log("Handle: %s" % e)
  3021. #import traceback
  3022. #traceback.print_exc()
  3023. break
  3024. def finish(self):
  3025. # Thread/process is dying, we should tell the main SMB thread to remove all this thread data
  3026. self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port))
  3027. self.__SMB.removeConnection(self.__connId)
  3028. return SocketServer.BaseRequestHandler.finish(self)
  3029. class SMBSERVER(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
  3030. #class SMBSERVER(SocketServer.ForkingMixIn, SocketServer.TCPServer):
  3031. def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser = None):
  3032. SocketServer.TCPServer.allow_reuse_address = True
  3033. SocketServer.TCPServer.__init__(self, server_address, handler_class)
  3034. # Server name and OS to be presented whenever is necessary
  3035. self.__serverName = ''
  3036. self.__serverOS = ''
  3037. self.__serverDomain = ''
  3038. self.__challenge = ''
  3039. self.__log = None
  3040. # Our ConfigParser data
  3041. self.__serverConfig = config_parser
  3042. # Our credentials to be used during the server's lifetime
  3043. self.__credentials = {}
  3044. # Our log file
  3045. self.__logFile = ''
  3046. # Registered Named Pipes, format is PipeName,Socket
  3047. self.__registeredNamedPipes = {}
  3048. # JTR dump path
  3049. self.__jtr_dump_path = ''
  3050. # SMB2 Support flag = default not active
  3051. self.__SMB2Support = False
  3052. # Our list of commands we will answer, by default the NOT IMPLEMENTED one
  3053. self.__smbCommandsHandler = SMBCommands()
  3054. self.__smbTrans2Handler = TRANS2Commands()
  3055. self.__smbTransHandler = TRANSCommands()
  3056. self.__smbNTTransHandler = NTTRANSCommands()
  3057. self.__smb2CommandsHandler = SMB2Commands()
  3058. self.__IoctlHandler = Ioctls()
  3059. self.__smbNTTransCommands = {
  3060. # NT IOCTL, can't find doc for this
  3061. 0xff :self.__smbNTTransHandler.default
  3062. }
  3063. self.__smbTransCommands = {
  3064. '\\PIPE\\LANMAN' :self.__smbTransHandler.lanMan,
  3065. smb.SMB.TRANS_TRANSACT_NMPIPE :self.__smbTransHandler.transactNamedPipe,
  3066. }
  3067. self.__smbTrans2Commands = {
  3068. smb.SMB.TRANS2_FIND_FIRST2 :self.__smbTrans2Handler.findFirst2,
  3069. smb.SMB.TRANS2_FIND_NEXT2 :self.__smbTrans2Handler.findNext2,
  3070. smb.SMB.TRANS2_QUERY_FS_INFORMATION :self.__smbTrans2Handler.queryFsInformation,
  3071. smb.SMB.TRANS2_QUERY_PATH_INFORMATION :self.__smbTrans2Handler.queryPathInformation,
  3072. smb.SMB.TRANS2_QUERY_FILE_INFORMATION :self.__smbTrans2Handler.queryFileInformation,
  3073. smb.SMB.TRANS2_SET_FILE_INFORMATION :self.__smbTrans2Handler.setFileInformation,
  3074. smb.SMB.TRANS2_SET_PATH_INFORMATION :self.__smbTrans2Handler.setPathInformation
  3075. }
  3076. self.__smbCommands = {
  3077. #smb.SMB.SMB_COM_FLUSH: self.__smbCommandsHandler.smbComFlush,
  3078. smb.SMB.SMB_COM_CREATE_DIRECTORY: self.__smbCommandsHandler.smbComCreateDirectory,
  3079. smb.SMB.SMB_COM_DELETE_DIRECTORY: self.__smbCommandsHandler.smbComDeleteDirectory,
  3080. smb.SMB.SMB_COM_RENAME: self.__smbCommandsHandler.smbComRename,
  3081. smb.SMB.SMB_COM_DELETE: self.__smbCommandsHandler.smbComDelete,
  3082. smb.SMB.SMB_COM_NEGOTIATE: self.__smbCommandsHandler.smbComNegotiate,
  3083. smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX,
  3084. smb.SMB.SMB_COM_LOGOFF_ANDX: self.__smbCommandsHandler.smbComLogOffAndX,
  3085. smb.SMB.SMB_COM_TREE_CONNECT_ANDX: self.__smbCommandsHandler.smbComTreeConnectAndX,
  3086. smb.SMB.SMB_COM_TREE_DISCONNECT: self.__smbCommandsHandler.smbComTreeDisconnect,
  3087. smb.SMB.SMB_COM_ECHO: self.__smbCommandsHandler.smbComEcho,
  3088. smb.SMB.SMB_COM_QUERY_INFORMATION: self.__smbCommandsHandler.smbQueryInformation,
  3089. smb.SMB.SMB_COM_TRANSACTION2: self.__smbCommandsHandler.smbTransaction2,
  3090. smb.SMB.SMB_COM_TRANSACTION: self.__smbCommandsHandler.smbTransaction,
  3091. # Not needed for now
  3092. smb.SMB.SMB_COM_NT_TRANSACT: self.__smbCommandsHandler.smbNTTransact,
  3093. smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk,
  3094. smb.SMB.SMB_COM_OPEN_ANDX: self.__smbCommandsHandler.smbComOpenAndX,
  3095. smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2,
  3096. smb.SMB.SMB_COM_READ_ANDX: self.__smbCommandsHandler.smbComReadAndX,
  3097. smb.SMB.SMB_COM_READ: self.__smbCommandsHandler.smbComRead,
  3098. smb.SMB.SMB_COM_WRITE_ANDX: self.__smbCommandsHandler.smbComWriteAndX,
  3099. smb.SMB.SMB_COM_WRITE: self.__smbCommandsHandler.smbComWrite,
  3100. smb.SMB.SMB_COM_CLOSE: self.__smbCommandsHandler.smbComClose,
  3101. smb.SMB.SMB_COM_LOCKING_ANDX: self.__smbCommandsHandler.smbComLockingAndX,
  3102. smb.SMB.SMB_COM_NT_CREATE_ANDX: self.__smbCommandsHandler.smbComNtCreateAndX,
  3103. 0xFF: self.__smbCommandsHandler.default
  3104. }
  3105. self.__smb2Ioctls = {
  3106. smb2.FSCTL_DFS_GET_REFERRALS: self.__IoctlHandler.fsctlDfsGetReferrals,
  3107. # smb2.FSCTL_PIPE_PEEK: self.__IoctlHandler.fsctlPipePeek,
  3108. # smb2.FSCTL_PIPE_WAIT: self.__IoctlHandler.fsctlPipeWait,
  3109. smb2.FSCTL_PIPE_TRANSCEIVE: self.__IoctlHandler.fsctlPipeTransceive,
  3110. # smb2.FSCTL_SRV_COPYCHUNK: self.__IoctlHandler.fsctlSrvCopyChunk,
  3111. # smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS: self.__IoctlHandler.fsctlSrvEnumerateSnapshots,
  3112. # smb2.FSCTL_SRV_REQUEST_RESUME_KEY: self.__IoctlHandler.fsctlSrvRequestResumeKey,
  3113. # smb2.FSCTL_SRV_READ_HASH: self.__IoctlHandler.fsctlSrvReadHash,
  3114. # smb2.FSCTL_SRV_COPYCHUNK_WRITE: self.__IoctlHandler.fsctlSrvCopyChunkWrite,
  3115. # smb2.FSCTL_LMR_REQUEST_RESILIENCY: self.__IoctlHandler.fsctlLmrRequestResiliency,
  3116. # smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo,
  3117. # smb2.FSCTL_SET_REPARSE_POINT: self.__IoctlHandler.fsctlSetReparsePoint,
  3118. # smb2.FSCTL_DFS_GET_REFERRALS_EX: self.__IoctlHandler.fsctlDfsGetReferralsEx,
  3119. # smb2.FSCTL_FILE_LEVEL_TRIM: self.__IoctlHandler.fsctlFileLevelTrim,
  3120. smb2.FSCTL_VALIDATE_NEGOTIATE_INFO: self.__IoctlHandler.fsctlValidateNegotiateInfo,
  3121. }
  3122. self.__smb2Commands = {
  3123. smb2.SMB2_NEGOTIATE: self.__smb2CommandsHandler.smb2Negotiate,
  3124. smb2.SMB2_SESSION_SETUP: self.__smb2CommandsHandler.smb2SessionSetup,
  3125. smb2.SMB2_LOGOFF: self.__smb2CommandsHandler.smb2Logoff,
  3126. smb2.SMB2_TREE_CONNECT: self.__smb2CommandsHandler.smb2TreeConnect,
  3127. smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect,
  3128. smb2.SMB2_CREATE: self.__smb2CommandsHandler.smb2Create,
  3129. smb2.SMB2_CLOSE: self.__smb2CommandsHandler.smb2Close,
  3130. smb2.SMB2_FLUSH: self.__smb2CommandsHandler.smb2Flush,
  3131. smb2.SMB2_READ: self.__smb2CommandsHandler.smb2Read,
  3132. smb2.SMB2_WRITE: self.__smb2CommandsHandler.smb2Write,
  3133. smb2.SMB2_LOCK: self.__smb2CommandsHandler.smb2Lock,
  3134. smb2.SMB2_IOCTL: self.__smb2CommandsHandler.smb2Ioctl,
  3135. smb2.SMB2_CANCEL: self.__smb2CommandsHandler.smb2Cancel,
  3136. smb2.SMB2_ECHO: self.__smb2CommandsHandler.smb2Echo,
  3137. smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory,
  3138. smb2.SMB2_CHANGE_NOTIFY: self.__smb2CommandsHandler.smb2ChangeNotify,
  3139. smb2.SMB2_QUERY_INFO: self.__smb2CommandsHandler.smb2QueryInfo,
  3140. smb2.SMB2_SET_INFO: self.__smb2CommandsHandler.smb2SetInfo,
  3141. # smb2.SMB2_OPLOCK_BREAK: self.__smb2CommandsHandler.smb2SessionSetup,
  3142. 0xFF: self.__smb2CommandsHandler.default
  3143. }
  3144. # List of active connections
  3145. self.__activeConnections = {}
  3146. def getIoctls(self):
  3147. return self.__smb2Ioctls
  3148. def getCredentials(self):
  3149. return self.__credentials
  3150. def removeConnection(self, name):
  3151. try:
  3152. del(self.__activeConnections[name])
  3153. except:
  3154. pass
  3155. self.log("Remaining connections %s" % self.__activeConnections.keys())
  3156. def addConnection(self, name, ip, port):
  3157. self.__activeConnections[name] = {}
  3158. # Let's init with some know stuff we will need to have
  3159. # TODO: Document what's in there
  3160. #print "Current Connections", self.__activeConnections.keys()
  3161. self.__activeConnections[name]['PacketNum'] = 0
  3162. self.__activeConnections[name]['ClientIP'] = ip
  3163. self.__activeConnections[name]['ClientPort'] = port
  3164. self.__activeConnections[name]['Uid'] = 0
  3165. self.__activeConnections[name]['ConnectedShares'] = {}
  3166. self.__activeConnections[name]['OpenedFiles'] = {}
  3167. # SID results for findfirst2
  3168. self.__activeConnections[name]['SIDs'] = {}
  3169. self.__activeConnections[name]['LastRequest'] = {}
  3170. def getActiveConnections(self):
  3171. return self.__activeConnections
  3172. def setConnectionData(self, connId, data):
  3173. self.__activeConnections[connId] = data
  3174. #print "setConnectionData"
  3175. #print self.__activeConnections
  3176. def getConnectionData(self, connId, checkStatus = True):
  3177. conn = self.__activeConnections[connId]
  3178. if checkStatus is True:
  3179. if ('Authenticated' in conn) is not True:
  3180. # Can't keep going further
  3181. raise Exception("User not Authenticated!")
  3182. return conn
  3183. def getRegisteredNamedPipes(self):
  3184. return self.__registeredNamedPipes
  3185. def registerNamedPipe(self, pipeName, address):
  3186. self.__registeredNamedPipes[unicode(pipeName)] = address
  3187. return True
  3188. def unregisterNamedPipe(self, pipeName):
  3189. if pipeName in self.__registeredNamedPipes:
  3190. del(self.__registeredNamedPipes[unicode(pipeName)])
  3191. return True
  3192. return False
  3193. def unregisterTransaction(self, transCommand):
  3194. if transCommand in self.__smbTransCommands:
  3195. del(self.__smbTransCommands[transCommand])
  3196. def hookTransaction(self, transCommand, callback):
  3197. # If you call this function, callback will replace
  3198. # the current Transaction sub command.
  3199. # (don't get confused with the Transaction smbCommand)
  3200. # If the transaction sub command doesn't not exist, it is added
  3201. # If the transaction sub command exists, it returns the original function # replaced
  3202. #
  3203. # callback MUST be declared as:
  3204. # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0)
  3205. #
  3206. # WHERE:
  3207. #
  3208. # connId : the connection Id, used to grab/update information about
  3209. # the current connection
  3210. # smbServer : the SMBServer instance available for you to ask
  3211. # configuration data
  3212. # recvPacket : the full SMBPacket that triggered this command
  3213. # parameters : the transaction parameters
  3214. # data : the transaction data
  3215. # maxDataCount: the max amount of data that can be transfered agreed
  3216. # with the client
  3217. #
  3218. # and MUST return:
  3219. # respSetup, respParameters, respData, errorCode
  3220. #
  3221. # WHERE:
  3222. #
  3223. # respSetup: the setup response of the transaction
  3224. # respParameters: the parameters response of the transaction
  3225. # respData: the data reponse of the transaction
  3226. # errorCode: the NT error code
  3227. if transCommand in self.__smbTransCommands:
  3228. originalCommand = self.__smbTransCommands[transCommand]
  3229. else:
  3230. originalCommand = None
  3231. self.__smbTransCommands[transCommand] = callback
  3232. return originalCommand
  3233. def unregisterTransaction2(self, transCommand):
  3234. if transCommand in self.__smbTrans2Commands:
  3235. del(self.__smbTrans2Commands[transCommand])
  3236. def hookTransaction2(self, transCommand, callback):
  3237. # Here we should add to __smbTrans2Commands
  3238. # Same description as Transaction
  3239. if transCommand in self.__smbTrans2Commands:
  3240. originalCommand = self.__smbTrans2Commands[transCommand]
  3241. else:
  3242. originalCommand = None
  3243. self.__smbTrans2Commands[transCommand] = callback
  3244. return originalCommand
  3245. def unregisterNTTransaction(self, transCommand):
  3246. if transCommand in self.__smbNTTransCommands:
  3247. del(self.__smbNTTransCommands[transCommand])
  3248. def hookNTTransaction(self, transCommand, callback):
  3249. # Here we should add to __smbNTTransCommands
  3250. # Same description as Transaction
  3251. if transCommand in self.__smbNTTransCommands:
  3252. originalCommand = self.__smbNTTransCommands[transCommand]
  3253. else:
  3254. originalCommand = None
  3255. self.__smbNTTransCommands[transCommand] = callback
  3256. return originalCommand
  3257. def unregisterSmbCommand(self, smbCommand):
  3258. if smbCommand in self.__smbCommands:
  3259. del(self.__smbCommands[smbCommand])
  3260. def hookSmbCommand(self, smbCommand, callback):
  3261. # Here we should add to self.__smbCommands
  3262. # If you call this function, callback will replace
  3263. # the current smbCommand.
  3264. # If smbCommand doesn't not exist, it is added
  3265. # If SMB command exists, it returns the original function replaced
  3266. #
  3267. # callback MUST be declared as:
  3268. # callback(connId, smbServer, SMBCommand, recvPacket)
  3269. #
  3270. # WHERE:
  3271. #
  3272. # connId : the connection Id, used to grab/update information about
  3273. # the current connection
  3274. # smbServer : the SMBServer instance available for you to ask
  3275. # configuration data
  3276. # SMBCommand: the SMBCommand itself, with its data and parameters.
  3277. # Check smb.py:SMBCommand() for a reference
  3278. # recvPacket: the full SMBPacket that triggered this command
  3279. #
  3280. # and MUST return:
  3281. # <list of respSMBCommands>, <list of packets>, errorCode
  3282. # <list of packets> has higher preference over commands, in case you
  3283. # want to change the whole packet
  3284. # errorCode: the NT error code
  3285. #
  3286. # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT
  3287. # the callback function is slightly different:
  3288. #
  3289. # callback(connId, smbServer, SMBCommand, recvPacket, transCommands)
  3290. #
  3291. # WHERE:
  3292. #
  3293. # transCommands: a list of transaction subcommands already registered
  3294. #
  3295. if smbCommand in self.__smbCommands:
  3296. originalCommand = self.__smbCommands[smbCommand]
  3297. else:
  3298. originalCommand = None
  3299. self.__smbCommands[smbCommand] = callback
  3300. return originalCommand
  3301. def unregisterSmb2Command(self, smb2Command):
  3302. if smb2Command in self.__smb2Commands:
  3303. del(self.__smb2Commands[smb2Command])
  3304. def hookSmb2Command(self, smb2Command, callback):
  3305. if smb2Command in self.__smb2Commands:
  3306. originalCommand = self.__smb2Commands[smb2Command]
  3307. else:
  3308. originalCommand = None
  3309. self.__smb2Commands[smb2Command] = callback
  3310. return originalCommand
  3311. def log(self, msg, level=logging.INFO):
  3312. self.__log.log(level,msg)
  3313. def getServerName(self):
  3314. return self.__serverName
  3315. def getServerOS(self):
  3316. return self.__serverOS
  3317. def getServerDomain(self):
  3318. return self.__serverDomain
  3319. def getSMBChallenge(self):
  3320. return self.__challenge
  3321. def getServerConfig(self):
  3322. return self.__serverConfig
  3323. def setServerConfig(self, config):
  3324. self.__serverConfig = config
  3325. def getJTRdumpPath(self):
  3326. return self.__jtr_dump_path
  3327. def verify_request(self, request, client_address):
  3328. # TODO: Control here the max amount of processes we want to launch
  3329. # returning False, closes the connection
  3330. return True
  3331. def processRequest(self, connId, data):
  3332. # TODO: Process batched commands.
  3333. isSMB2 = False
  3334. SMBCommand = None
  3335. try:
  3336. packet = smb.NewSMBPacket(data = data)
  3337. SMBCommand = smb.SMBCommand(packet['Data'][0])
  3338. except:
  3339. # Maybe a SMB2 packet?
  3340. packet = smb2.SMB2Packet(data = data)
  3341. isSMB2 = True
  3342. # We might have compound requests
  3343. compoundedPacketsResponse = []
  3344. compoundedPackets = []
  3345. try:
  3346. # Search out list of implemented commands
  3347. # We provide them with:
  3348. # connId : representing the data for this specific connection
  3349. # self : the SMBSERVER if they want to ask data to it
  3350. # SMBCommand : the SMBCommand they are expecting to process
  3351. # packet : the received packet itself, in case they need more data than the actual command
  3352. # Only for Transactions
  3353. # transCommand: a list of transaction subcommands
  3354. # We expect to get:
  3355. # respCommands: a list of answers for the commands processed
  3356. # respPacket : if the commands chose to directly craft packet/s, we use this and not the previous
  3357. # this MUST be a list
  3358. # errorCode : self explanatory
  3359. if isSMB2 is False:
  3360. if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2:
  3361. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3362. connId,
  3363. self,
  3364. SMBCommand,
  3365. packet,
  3366. self.__smbTrans2Commands)
  3367. elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT:
  3368. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3369. connId,
  3370. self,
  3371. SMBCommand,
  3372. packet,
  3373. self.__smbNTTransCommands)
  3374. elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION:
  3375. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3376. connId,
  3377. self,
  3378. SMBCommand,
  3379. packet,
  3380. self.__smbTransCommands)
  3381. else:
  3382. if packet['Command'] in self.__smbCommands:
  3383. if self.__SMB2Support is True:
  3384. if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE:
  3385. try:
  3386. respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE](connId, self, packet, True)
  3387. isSMB2 = True
  3388. except Exception as e:
  3389. self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR)
  3390. # If something went wrong, let's fallback to SMB1
  3391. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3392. connId,
  3393. self,
  3394. SMBCommand,
  3395. packet)
  3396. #self.__SMB2Support = False
  3397. pass
  3398. else:
  3399. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3400. connId,
  3401. self,
  3402. SMBCommand,
  3403. packet)
  3404. else:
  3405. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3406. connId,
  3407. self,
  3408. SMBCommand,
  3409. packet)
  3410. else:
  3411. respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, packet)
  3412. compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
  3413. compoundedPackets.append(packet)
  3414. else:
  3415. done = False
  3416. while not done:
  3417. if packet['Command'] in self.__smb2Commands:
  3418. if self.__SMB2Support is True:
  3419. respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']](
  3420. connId,
  3421. self,
  3422. packet)
  3423. else:
  3424. respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
  3425. else:
  3426. respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
  3427. # Let's store the result for this compounded packet
  3428. compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
  3429. compoundedPackets.append(packet)
  3430. if packet['NextCommand'] != 0:
  3431. data = data[packet['NextCommand']:]
  3432. packet = smb2.SMB2Packet(data = data)
  3433. else:
  3434. done = True
  3435. except Exception as e:
  3436. #import traceback
  3437. #traceback.print_exc()
  3438. # Something wen't wrong, defaulting to Bad user ID
  3439. self.log('processRequest (0x%x,%s)' % (packet['Command'],e), logging.ERROR)
  3440. raise
  3441. # We prepare the response packet to commands don't need to bother about that.
  3442. connData = self.getConnectionData(connId, False)
  3443. # Force reconnection loop.. This is just a test.. client will send me back credentials :)
  3444. #connData['PacketNum'] += 1
  3445. #if connData['PacketNum'] == 15:
  3446. # connData['PacketNum'] = 0
  3447. # # Something wen't wrong, defaulting to Bad user ID
  3448. # self.log('Sending BAD USER ID!', logging.ERROR)
  3449. # #raise
  3450. # packet['Flags1'] |= smb.SMB.FLAGS1_REPLY
  3451. # packet['Flags2'] = 0
  3452. # errorCode = STATUS_SMB_BAD_UID
  3453. # packet['ErrorCode'] = errorCode >> 16
  3454. # packet['ErrorClass'] = errorCode & 0xff
  3455. # return [packet]
  3456. self.setConnectionData(connId, connData)
  3457. packetsToSend = []
  3458. for packetNum in range(len(compoundedPacketsResponse)):
  3459. respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum]
  3460. packet = compoundedPackets[packetNum]
  3461. if respPackets is None:
  3462. for respCommand in respCommands:
  3463. if isSMB2 is False:
  3464. respPacket = smb.NewSMBPacket()
  3465. respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY
  3466. # TODO this should come from a per session configuration
  3467. respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | packet['Flags2'] & smb.SMB.FLAGS2_UNICODE
  3468. #respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES
  3469. #respPacket['Flags1'] = 0x98
  3470. #respPacket['Flags2'] = 0xc807
  3471. respPacket['Tid'] = packet['Tid']
  3472. respPacket['Mid'] = packet['Mid']
  3473. respPacket['Pid'] = packet['Pid']
  3474. respPacket['Uid'] = connData['Uid']
  3475. respPacket['ErrorCode'] = errorCode >> 16
  3476. respPacket['_reserved'] = errorCode >> 8 & 0xff
  3477. respPacket['ErrorClass'] = errorCode & 0xff
  3478. respPacket.addCommand(respCommand)
  3479. packetsToSend.append(respPacket)
  3480. else:
  3481. respPacket = smb2.SMB2Packet()
  3482. respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
  3483. if packetNum > 0:
  3484. respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS
  3485. respPacket['Status'] = errorCode
  3486. respPacket['CreditRequestResponse'] = packet['CreditRequestResponse']
  3487. respPacket['Command'] = packet['Command']
  3488. respPacket['CreditCharge'] = packet['CreditCharge']
  3489. #respPacket['CreditCharge'] = 0
  3490. respPacket['Reserved'] = packet['Reserved']
  3491. respPacket['SessionID'] = connData['Uid']
  3492. respPacket['MessageID'] = packet['MessageID']
  3493. respPacket['TreeID'] = packet['TreeID']
  3494. respPacket['Data'] = str(respCommand)
  3495. packetsToSend.append(respPacket)
  3496. else:
  3497. # The SMBCommand took care of building the packet
  3498. packetsToSend = respPackets
  3499. if isSMB2 is True:
  3500. # Let's build a compound answer
  3501. finalData = ''
  3502. i = 0
  3503. for i in range(len(packetsToSend)-1):
  3504. packet = packetsToSend[i]
  3505. # Align to 8-bytes
  3506. padLen = (8 - (len(packet) % 8) ) % 8
  3507. packet['NextCommand'] = len(packet) + padLen
  3508. finalData += str(packet) + padLen*'\x00'
  3509. # Last one
  3510. finalData += str(packetsToSend[len(packetsToSend)-1])
  3511. packetsToSend = [finalData]
  3512. # We clear the compound requests
  3513. connData['LastRequest'] = {}
  3514. return packetsToSend
  3515. def processConfigFile(self, configFile = None):
  3516. # TODO: Do a real config parser
  3517. if self.__serverConfig is None:
  3518. if configFile is None:
  3519. configFile = 'smb.conf'
  3520. self.__serverConfig = ConfigParser.ConfigParser()
  3521. self.__serverConfig.read(configFile)
  3522. self.__serverName = self.__serverConfig.get('global','server_name')
  3523. self.__serverOS = self.__serverConfig.get('global','server_os')
  3524. self.__serverDomain = self.__serverConfig.get('global','server_domain')
  3525. self.__logFile = self.__serverConfig.get('global','log_file')
  3526. if self.__serverConfig.has_option('global', 'challenge'):
  3527. self.__challenge = self.__serverConfig.get('global', 'challenge')
  3528. else:
  3529. self.__challenge = 'A'*8
  3530. if self.__serverConfig.has_option("global", "jtr_dump_path"):
  3531. self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path")
  3532. if self.__serverConfig.has_option("global", "SMB2Support"):
  3533. self.__SMB2Support = self.__serverConfig.getboolean("global","SMB2Support")
  3534. else:
  3535. self.__SMB2Support = False
  3536. if self.__logFile != 'None':
  3537. logging.basicConfig(filename = self.__logFile,
  3538. level = logging.DEBUG,
  3539. format="%(asctime)s: %(levelname)s: %(message)s",
  3540. datefmt = '%m/%d/%Y %I:%M:%S %p')
  3541. self.__log = LOG
  3542. # Process the credentials
  3543. credentials_fname = self.__serverConfig.get('global','credentials_file')
  3544. if credentials_fname is not "":
  3545. cred = open(credentials_fname)
  3546. line = cred.readline()
  3547. while line:
  3548. name, domain, lmhash, nthash = line.split(':')
  3549. self.__credentials[name] = (domain, lmhash, nthash.strip('\r\n'))
  3550. line = cred.readline()
  3551. cred.close()
  3552. self.log('Config file parsed')
  3553. # For windows platforms, opening a directory is not an option, so we set a void FD
  3554. VOID_FILE_DESCRIPTOR = -1
  3555. PIPE_FILE_DESCRIPTOR = -2