Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 

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# Description: 

10# [MS-SCMP]: Shadow Copy Management Protocol Interface implementation 

11# This was used as a way to test the DCOM runtime. Further  

12# testing is needed to verify it is working as expected 

13# 

14# Best way to learn how to use these calls is to grab the protocol standard 

15# so you understand what the call does, and then read the test case located 

16# at https://github.com/SecureAuthCorp/impacket/tree/master/tests/SMB_RPC 

17# 

18# Since DCOM is like an OO RPC, instead of helper functions you will see the  

19# classes described in the standards developed.  

20# There are test cases for them too.  

21# 

22from __future__ import division 

23from __future__ import print_function 

24from impacket.dcerpc.v5.ndr import NDRENUM, NDRSTRUCT, NDRUNION 

25from impacket.dcerpc.v5.dcomrt import PMInterfacePointer, INTERFACE, DCOMCALL, DCOMANSWER, IRemUnknown2 

26from impacket.dcerpc.v5.dtypes import LONG, LONGLONG, ULONG, WSTR 

27from impacket.dcerpc.v5.enum import Enum 

28from impacket.dcerpc.v5.rpcrt import DCERPCException 

29from impacket import hresult_errors 

30from impacket.uuid import string_to_bin 

31 

32class DCERPCSessionError(DCERPCException): 

33 def __init__(self, error_string=None, error_code=None, packet=None): 

34 DCERPCException.__init__(self, error_string, error_code, packet) 

35 

36 def __str__( self ): 

37 if self.error_code in hresult_errors.ERROR_MESSAGES: 

38 error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] 

39 error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] 

40 return 'SCMP SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) 

41 else: 

42 return 'SCMP SessionError: unknown error code: 0x%x' % self.error_code 

43 

44################################################################################ 

45# CONSTANTS 

46################################################################################ 

47# 1.9 Standards Assignments 

48CLSID_ShadowCopyProvider = string_to_bin('0b5a2c52-3eb9-470a-96e2-6c6d4570e40f') 

49IID_IVssSnapshotMgmt = string_to_bin('FA7DF749-66E7-4986-A27F-E2F04AE53772') 

50IID_IVssEnumObject = string_to_bin('AE1C7110-2F60-11d3-8A39-00C04F72D8E3') 

51IID_IVssDifferentialSoftwareSnapshotMgmt = string_to_bin('214A0F28-B737-4026-B847-4F9E37D79529') 

52IID_IVssEnumMgmtObject = string_to_bin('01954E6B-9254-4e6e-808C-C9E05D007696') 

53IID_ShadowCopyProvider = string_to_bin('B5946137-7B9F-4925-AF80-51ABD60B20D5') 

54 

55# 2.2.1.1 VSS_ID 

56class VSS_ID(NDRSTRUCT): 

57 structure = ( 

58 ('Data','16s=b""'), 

59 ) 

60 

61 def getAlignment(self): 

62 return 2 

63 

64#2.2.1.2 VSS_PWSZ 

65VSS_PWSZ = WSTR 

66 

67# 2.2.1.3 VSS_TIMESTAMP 

68VSS_TIMESTAMP = LONGLONG 

69 

70error_status_t = LONG 

71################################################################################ 

72# STRUCTURES 

73################################################################################ 

74# 2.2.2.1 VSS_OBJECT_TYPE Enumeration 

75class VSS_OBJECT_TYPE(NDRENUM): 

76 class enumItems(Enum): 

77 VSS_OBJECT_UNKNOWN = 0 

78 VSS_OBJECT_NONE = 1 

79 VSS_OBJECT_SNAPSHOT_SET = 2 

80 VSS_OBJECT_SNAPSHOT = 3 

81 VSS_OBJECT_PROVIDER = 4 

82 VSS_OBJECT_TYPE_COUNT = 5 

83 

84# 2.2.2.2 VSS_MGMT_OBJECT_TYPE Enumeration 

85class VSS_MGMT_OBJECT_TYPE(NDRENUM): 

86 class enumItems(Enum): 

87 VSS_MGMT_OBJECT_UNKNOWN = 0 

88 VSS_MGMT_OBJECT_VOLUME = 1 

89 VSS_MGMT_OBJECT_DIFF_VOLUME = 2 

90 VSS_MGMT_OBJECT_DIFF_AREA = 3 

91 

92# 2.2.2.3 VSS_VOLUME_SNAPSHOT_ATTRIBUTES Enumeration 

93class VSS_VOLUME_SNAPSHOT_ATTRIBUTES(NDRENUM): 

94 class enumItems(Enum): 

95 VSS_VOLSNAP_ATTR_PERSISTENT = 0x01 

96 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY = 0x02 

97 VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE = 0x04 

98 VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE = 0x08 

99 VSS_VOLSNAP_ATTR_NO_WRITERS = 0x10 

100 

101# 2.2.2.4 VSS_SNAPSHOT_STATE Enumeration 

102class VSS_SNAPSHOT_STATE(NDRENUM): 

103 class enumItems(Enum): 

104 VSS_SS_UNKNOWN = 0x01 

105 VSS_SS_CREATED = 0x0c 

106 

107# 2.2.2.5 VSS_PROVIDER_TYPE Enumeration 

108class VSS_PROVIDER_TYPE(NDRENUM): 

109 class enumItems(Enum): 

110 VSS_PROV_UNKNOWN = 0 

111 

112# 2.2.3.7 VSS_VOLUME_PROP Structure 

113class VSS_VOLUME_PROP(NDRSTRUCT): 

114 structure = ( 

115 ('m_pwszVolumeName', VSS_PWSZ), 

116 ('m_pwszVolumeDisplayName', VSS_PWSZ), 

117 ) 

118 

119# 2.2.3.5 VSS_MGMT_OBJECT_UNION Union 

120class VSS_MGMT_OBJECT_UNION(NDRUNION): 

121 commonHdr = ( 

122 ('tag', ULONG), 

123 ) 

124 union = { 

125 VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_VOLUME: ('Vol', VSS_VOLUME_PROP), 

126 #VSS_MGMT_OBJECT_DIFF_VOLUME: ('DiffVol', VSS_DIFF_VOLUME_PROP), 

127 #VSS_MGMT_OBJECT_DIFF_AREA: ('DiffArea', VSS_DIFF_AREA_PROP), 

128 } 

129 

130# 2.2.3.6 VSS_MGMT_OBJECT_PROP Structure 

131class VSS_MGMT_OBJECT_PROP(NDRSTRUCT): 

132 structure = ( 

133 ('Type', VSS_MGMT_OBJECT_TYPE), 

134 ('Obj', VSS_MGMT_OBJECT_UNION), 

135 ) 

136 

137################################################################################ 

138# RPC CALLS 

139################################################################################ 

140# 3.1.3 IVssEnumMgmtObject Details 

141 

142# 3.1.3.1 Next (Opnum 3) 

143class IVssEnumMgmtObject_Next(DCOMCALL): 

144 opnum = 3 

145 structure = ( 

146 ('celt', ULONG), 

147 ) 

148 

149class IVssEnumMgmtObject_NextResponse(DCOMANSWER): 

150 structure = ( 

151 ('rgelt', VSS_MGMT_OBJECT_PROP), 

152 ('pceltFetched', ULONG), 

153 ('ErrorCode', error_status_t), 

154 ) 

155 

156# 3.1.2.1 Next (Opnum 3) 

157class IVssEnumObject_Next(DCOMCALL): 

158 opnum = 3 

159 structure = ( 

160 ('celt', ULONG), 

161 ) 

162 

163class IVssEnumObject_NextResponse(DCOMANSWER): 

164 structure = ( 

165 ('rgelt', VSS_MGMT_OBJECT_PROP), 

166 ('pceltFetched', ULONG), 

167 ('ErrorCode', error_status_t), 

168 ) 

169 

170class GetProviderMgmtInterface(DCOMCALL): 

171 opnum = 3 

172 structure = ( 

173 ('ProviderId', VSS_ID), 

174 ('InterfaceId', VSS_ID), 

175 ) 

176 

177class GetProviderMgmtInterfaceResponse(DCOMANSWER): 

178 structure = ( 

179 ('ppItf', PMInterfacePointer), 

180 ('ErrorCode', error_status_t), 

181 ) 

182 

183class QueryVolumesSupportedForSnapshots(DCOMCALL): 

184 opnum = 4 

185 structure = ( 

186 ('ProviderId', VSS_ID), 

187 ('IContext', LONG), 

188 ) 

189 

190class QueryVolumesSupportedForSnapshotsResponse(DCOMANSWER): 

191 structure = ( 

192 ('ppEnum', PMInterfacePointer), 

193 ('ErrorCode', error_status_t), 

194 ) 

195 

196class QuerySnapshotsByVolume(DCOMCALL): 

197 opnum = 5 

198 structure = ( 

199 ('pwszVolumeName', VSS_PWSZ), 

200 ('ProviderId', VSS_ID), 

201 ) 

202 

203class QuerySnapshotsByVolumeResponse(DCOMANSWER): 

204 structure = ( 

205 ('ppEnum', PMInterfacePointer), 

206 ('ErrorCode', error_status_t), 

207 ) 

208 

209# 3.1.4.4.5 QueryDiffAreasForVolume (Opnum 6) 

210class QueryDiffAreasForVolume(DCOMCALL): 

211 opnum = 6 

212 structure = ( 

213 ('pwszVolumeName', VSS_PWSZ), 

214 ) 

215 

216class QueryDiffAreasForVolumeResponse(DCOMANSWER): 

217 structure = ( 

218 ('ppEnum', PMInterfacePointer), 

219 ('ErrorCode', error_status_t), 

220 ) 

221 

222# 3.1.4.4.6 QueryDiffAreasOnVolume (Opnum 7) 

223class QueryDiffAreasOnVolume(DCOMCALL): 

224 opnum = 7 

225 structure = ( 

226 ('pwszVolumeName', VSS_PWSZ), 

227 ) 

228 

229class QueryDiffAreasOnVolumeResponse(DCOMANSWER): 

230 structure = ( 

231 ('ppEnum', PMInterfacePointer), 

232 ('ErrorCode', error_status_t), 

233 ) 

234 

235 

236################################################################################ 

237# OPNUMs and their corresponding structures 

238################################################################################ 

239OPNUMS = { 

240} 

241 

242################################################################################ 

243# HELPER FUNCTIONS AND INTERFACES 

244################################################################################ 

245class IVssEnumMgmtObject(IRemUnknown2): 

246 def __init__(self, interface): 

247 IRemUnknown2.__init__(self, interface) 

248 self._iid = IID_IVssEnumMgmtObject 

249 

250 def Next(self, celt): 

251 request = IVssEnumMgmtObject_Next() 

252 request['ORPCthis'] = self.get_cinstance().get_ORPCthis() 

253 request['ORPCthis']['flags'] = 0 

254 request['celt'] = celt 

255 resp = self.request(request, self._iid, uuid = self.get_iPid()) 

256 return resp 

257 

258class IVssEnumObject(IRemUnknown2): 

259 def __init__(self, interface): 

260 IRemUnknown2.__init__(self, interface) 

261 self._iid = IID_IVssEnumObject 

262 

263 def Next(self, celt): 

264 request = IVssEnumObject_Next() 

265 request['ORPCthis'] = self.get_cinstance().get_ORPCthis() 

266 request['ORPCthis']['flags'] = 0 

267 request['celt'] = celt 

268 dce = self.connect() 

269 resp = dce.request(request, self._iid, uuid = self.get_iPid()) 

270 return resp 

271 

272class IVssSnapshotMgmt(IRemUnknown2): 

273 def __init__(self, interface): 

274 IRemUnknown2.__init__(self, interface) 

275 self._iid = IID_IVssSnapshotMgmt 

276 

277 def GetProviderMgmtInterface(self, providerId = IID_ShadowCopyProvider, interfaceId = IID_IVssDifferentialSoftwareSnapshotMgmt): 

278 req = GetProviderMgmtInterface() 

279 classInstance = self.get_cinstance() 

280 req['ORPCthis'] = classInstance.get_ORPCthis() 

281 req['ORPCthis']['flags'] = 0 

282 req['ProviderId'] = providerId 

283 req['InterfaceId'] = interfaceId 

284 resp = self.request(req, self._iid, uuid = self.get_iPid()) 

285 return IVssDifferentialSoftwareSnapshotMgmt(INTERFACE(classInstance, ''.join(resp['ppItf']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) 

286 

287 def QueryVolumesSupportedForSnapshots(self, providerId, iContext): 

288 req = QueryVolumesSupportedForSnapshots() 

289 classInstance = self.get_cinstance() 

290 req['ORPCthis'] = classInstance.get_ORPCthis() 

291 req['ORPCthis']['flags'] = 0 

292 req['ProviderId'] = providerId 

293 req['IContext'] = iContext 

294 resp = self.request(req, self._iid, uuid = self.get_iPid()) 

295 return IVssEnumMgmtObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(),target = self.get_target())) 

296 

297 def QuerySnapshotsByVolume(self, volumeName, providerId = IID_ShadowCopyProvider): 

298 req = QuerySnapshotsByVolume() 

299 classInstance = self.get_cinstance() 

300 req['ORPCthis'] = classInstance.get_ORPCthis() 

301 req['ORPCthis']['flags'] = 0 

302 req['pwszVolumeName'] = volumeName 

303 req['ProviderId'] = providerId 

304 try: 

305 resp = self.request(req, self._iid, uuid = self.get_iPid()) 

306 except DCERPCException as e: 

307 print(e) 

308 from impacket.winregistry import hexdump 

309 data = e.get_packet() 

310 hexdump(data) 

311 kk = QuerySnapshotsByVolumeResponse(data) 

312 kk.dump() 

313 #resp.dump() 

314 return IVssEnumObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) 

315 

316class IVssDifferentialSoftwareSnapshotMgmt(IRemUnknown2): 

317 def __init__(self, interface): 

318 IRemUnknown2.__init__(self, interface) 

319 self._iid = IID_IVssDifferentialSoftwareSnapshotMgmt 

320 

321 def QueryDiffAreasOnVolume(self, pwszVolumeName): 

322 req = QueryDiffAreasOnVolume() 

323 classInstance = self.get_cinstance() 

324 req['ORPCthis'] = classInstance.get_ORPCthis() 

325 req['ORPCthis']['flags'] = 0 

326 req['pwszVolumeName'] = pwszVolumeName 

327 resp = self.request(req, self._iid, uuid = self.get_iPid()) 

328 return IVssEnumMgmtObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) 

329 

330 def QueryDiffAreasForVolume(self, pwszVolumeName): 

331 req = QueryDiffAreasForVolume() 

332 classInstance = self.get_cinstance() 

333 req['ORPCthis'] = classInstance.get_ORPCthis() 

334 req['ORPCthis']['flags'] = 0 

335 req['pwszVolumeName'] = pwszVolumeName 

336 resp = self.request(req, self._iid, uuid = self.get_iPid()) 

337 return IVssEnumMgmtObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target()))