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-DTYP] Interface mini implementation 

11# 

12from __future__ import division 

13from __future__ import print_function 

14from struct import pack 

15from six import binary_type 

16 

17from impacket.dcerpc.v5.ndr import NDRULONG, NDRUHYPER, NDRSHORT, NDRLONG, NDRPOINTER, NDRUniConformantArray, \ 

18 NDRUniFixedArray, NDR, NDRHYPER, NDRSMALL, NDRPOINTERNULL, NDRSTRUCT, \ 

19 NDRUSMALL, NDRBOOLEAN, NDRUSHORT, NDRFLOAT, NDRDOUBLEFLOAT, NULL 

20 

21DWORD = NDRULONG 

22BOOL = NDRULONG 

23UCHAR = NDRUSMALL 

24SHORT = NDRSHORT 

25NULL = NULL 

26 

27class LPDWORD(NDRPOINTER): 

28 referent = ( 

29 ('Data', DWORD), 

30 ) 

31 

32class PSHORT(NDRPOINTER): 

33 referent = ( 

34 ('Data', SHORT), 

35 ) 

36 

37class PBOOL(NDRPOINTER): 

38 referent = ( 

39 ('Data', BOOL), 

40 ) 

41 

42class LPBYTE(NDRPOINTER): 

43 referent = ( 

44 ('Data', NDRUniConformantArray), 

45 ) 

46PBYTE = LPBYTE 

47 

48# 2.2.4 BOOLEAN 

49BOOLEAN = NDRBOOLEAN 

50 

51# 2.2.6 BYTE 

52BYTE = NDRUSMALL 

53 

54# 2.2.7 CHAR 

55CHAR = NDRSMALL 

56class PCHAR(NDRPOINTER): 

57 referent = ( 

58 ('Data', CHAR), 

59 ) 

60 

61class WIDESTR(NDRUniFixedArray): 

62 def getDataLen(self, data, offset=0): 

63 return data.find(b'\x00\x00\x00', offset)+3-offset 

64 

65 def __setitem__(self, key, value): 

66 if key == 'Data': 66 ↛ 75line 66 didn't jump to line 75, because the condition on line 66 was never false

67 try: 

68 self.fields[key] = value.encode('utf-16le') 

69 except UnicodeDecodeError: 

70 import sys 

71 self.fields[key] = value.decode(sys.getfilesystemencoding()).encode('utf-16le') 

72 

73 self.data = None # force recompute 

74 else: 

75 return NDR.__setitem__(self, key, value) 

76 

77 def __getitem__(self, key): 

78 if key == 'Data': 78 ↛ 81line 78 didn't jump to line 81, because the condition on line 78 was never false

79 return self.fields[key].decode('utf-16le') 

80 else: 

81 return NDR.__getitem__(self,key) 

82 

83class STR(NDRSTRUCT): 

84 commonHdr = ( 

85 ('MaximumCount', '<L=len(Data)'), 

86 ('Offset','<L=0'), 

87 ('ActualCount','<L=len(Data)'), 

88 ) 

89 commonHdr64 = ( 

90 ('MaximumCount', '<Q=len(Data)'), 

91 ('Offset','<Q=0'), 

92 ('ActualCount','<Q=len(Data)'), 

93 ) 

94 structure = ( 

95 ('Data',':'), 

96 ) 

97 

98 def dump(self, msg = None, indent = 0): 

99 if msg is None: 

100 msg = self.__class__.__name__ 

101 if msg != '': 

102 print("%s" % msg, end=' ') 

103 # Here just print the data 

104 print(" %r" % (self['Data']), end=' ') 

105 

106 def __setitem__(self, key, value): 

107 if key == 'Data': 107 ↛ 121line 107 didn't jump to line 121, because the condition on line 107 was never false

108 try: 

109 if not isinstance(value, binary_type): 109 ↛ 113line 109 didn't jump to line 113, because the condition on line 109 was never false

110 self.fields[key] = value.encode('utf-8') 

111 else: 

112 # if it is a binary type (str in Python 2, bytes in Python 3), then we assume it is a raw buffer 

113 self.fields[key] = value 

114 except UnicodeDecodeError: 

115 import sys 

116 self.fields[key] = value.decode(sys.getfilesystemencoding()).encode('utf-8') 

117 self.fields['MaximumCount'] = None 

118 self.fields['ActualCount'] = None 

119 self.data = None # force recompute 

120 else: 

121 return NDR.__setitem__(self, key, value) 

122 

123 def __getitem__(self, key): 

124 if key == 'Data': 

125 try: 

126 return self.fields[key].decode('utf-8') 

127 except UnicodeDecodeError: 

128 # if we could't decode it, we assume it is a raw buffer 

129 return self.fields[key] 

130 else: 

131 return NDR.__getitem__(self,key) 

132 

133 def getDataLen(self, data, offset=0): 

134 return self["ActualCount"] 

135 

136class LPSTR(NDRPOINTER): 

137 referent = ( 

138 ('Data', STR), 

139 ) 

140 

141class WSTR(NDRSTRUCT): 

142 commonHdr = ( 

143 ('MaximumCount', '<L=len(Data)//2'), 

144 ('Offset','<L=0'), 

145 ('ActualCount','<L=len(Data)//2'), 

146 ) 

147 commonHdr64 = ( 

148 ('MaximumCount', '<Q=len(Data)//2'), 

149 ('Offset','<Q=0'), 

150 ('ActualCount','<Q=len(Data)//2'), 

151 ) 

152 structure = ( 

153 ('Data',':'), 

154 ) 

155 

156 def dump(self, msg = None, indent = 0): 

157 if msg is None: 157 ↛ 158line 157 didn't jump to line 158, because the condition on line 157 was never true

158 msg = self.__class__.__name__ 

159 if msg != '': 

160 print("%s" % msg, end=' ') 

161 # Here just print the data 

162 print(" %r" % (self['Data']), end=' ') 

163 

164 def getDataLen(self, data, offset=0): 

165 return self["ActualCount"]*2 

166 

167 def __setitem__(self, key, value): 

168 if key == 'Data': 168 ↛ 178line 168 didn't jump to line 178, because the condition on line 168 was never false

169 try: 

170 self.fields[key] = value.encode('utf-16le') 

171 except UnicodeDecodeError: 

172 import sys 

173 self.fields[key] = value.decode(sys.getfilesystemencoding()).encode('utf-16le') 

174 self.fields['MaximumCount'] = None 

175 self.fields['ActualCount'] = None 

176 self.data = None # force recompute 

177 else: 

178 return NDR.__setitem__(self, key, value) 

179 

180 def __getitem__(self, key): 

181 if key == 'Data': 

182 return self.fields[key].decode('utf-16le') 

183 else: 

184 return NDR.__getitem__(self,key) 

185 

186class LPWSTR(NDRPOINTER): 

187 referent = ( 

188 ('Data', WSTR), 

189 ) 

190 

191# 2.2.5 BSTR 

192BSTR = LPWSTR 

193 

194# 2.2.8 DOUBLE 

195DOUBLE = NDRDOUBLEFLOAT 

196class PDOUBLE(NDRPOINTER): 

197 referent = ( 

198 ('Data', DOUBLE), 

199 ) 

200 

201# 2.2.15 FLOAT 

202FLOAT = NDRFLOAT 

203class PFLOAT(NDRPOINTER): 

204 referent = ( 

205 ('Data', FLOAT), 

206 ) 

207 

208# 2.2.18 HRESULT 

209HRESULT = NDRLONG 

210class PHRESULT(NDRPOINTER): 

211 referent = ( 

212 ('Data', HRESULT), 

213 ) 

214 

215# 2.2.19 INT 

216INT = NDRLONG 

217class PINT(NDRPOINTER): 

218 referent = ( 

219 ('Data', INT), 

220 ) 

221 

222# 2.2.26 LMSTR 

223LMSTR = LPWSTR 

224 

225# 2.2.27 LONG 

226LONG = NDRLONG 

227class LPLONG(NDRPOINTER): 

228 referent = ( 

229 ('Data', LONG), 

230 ) 

231 

232PLONG = LPLONG 

233 

234# 2.2.28 LONGLONG 

235LONGLONG = NDRHYPER 

236 

237class PLONGLONG(NDRPOINTER): 

238 referent = ( 

239 ('Data', LONGLONG), 

240 ) 

241 

242# 2.2.31 LONG64 

243LONG64 = NDRUHYPER 

244class PLONG64(NDRPOINTER): 

245 referent = ( 

246 ('Data', LONG64), 

247 ) 

248 

249# 2.2.32 LPCSTR 

250LPCSTR = LPSTR 

251 

252# 2.2.36 NET_API_STATUS 

253NET_API_STATUS = DWORD 

254 

255# 2.2.52 ULONG_PTR 

256ULONG_PTR = NDRULONG 

257# 2.2.10 DWORD_PTR 

258DWORD_PTR = ULONG_PTR 

259 

260# 2.3.2 GUID and UUID 

261class GUID(NDRSTRUCT): 

262 structure = ( 

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

264 ) 

265 

266 def getAlignment(self): 

267 return 4 

268 

269class PGUID(NDRPOINTER): 

270 referent = ( 

271 ('Data', GUID), 

272 ) 

273 

274UUID = GUID 

275PUUID = PGUID 

276 

277# 2.2.37 NTSTATUS 

278NTSTATUS = DWORD 

279 

280# 2.2.45 UINT 

281UINT = NDRULONG 

282class PUINT(NDRPOINTER): 

283 referent = ( 

284 ('Data', UINT), 

285 ) 

286 

287# 2.2.50 ULONG 

288ULONG = NDRULONG 

289class PULONG(NDRPOINTER): 

290 referent = ( 

291 ('Data', ULONG), 

292 ) 

293 

294LPULONG = PULONG 

295 

296# 2.2.54 ULONGLONG 

297ULONGLONG = NDRUHYPER 

298class PULONGLONG(NDRPOINTER): 

299 referent = ( 

300 ('Data', ULONGLONG), 

301 ) 

302 

303# 2.2.57 USHORT 

304USHORT = NDRUSHORT 

305class PUSHORT(NDRPOINTER): 

306 referent = ( 

307 ('Data', USHORT), 

308 ) 

309 

310# 2.2.59 WCHAR 

311WCHAR = WSTR 

312PWCHAR = LPWSTR 

313 

314# 2.2.61 WORD 

315WORD = NDRUSHORT 

316class PWORD(NDRPOINTER): 

317 referent = ( 

318 ('Data', WORD), 

319 ) 

320LPWORD = PWORD 

321 

322# 2.3.1 FILETIME 

323class FILETIME(NDRSTRUCT): 

324 structure = ( 

325 ('dwLowDateTime', DWORD), 

326 ('dwHighDateTime', LONG), 

327 ) 

328 

329class PFILETIME(NDRPOINTER): 

330 referent = ( 

331 ('Data', FILETIME), 

332 ) 

333 

334# 2.3.3 LARGE_INTEGER 

335LARGE_INTEGER = NDRHYPER 

336class PLARGE_INTEGER(NDRPOINTER): 

337 referent = ( 

338 ('Data', LARGE_INTEGER), 

339 ) 

340 

341# 2.3.5 LUID 

342class LUID(NDRSTRUCT): 

343 structure = ( 

344 ('LowPart', DWORD), 

345 ('HighPart', LONG), 

346 ) 

347 

348# 2.3.8 RPC_UNICODE_STRING 

349class RPC_UNICODE_STRING(NDRSTRUCT): 

350 # Here we're doing some tricks to make this data type 

351 # easier to use. It's exactly the same as defined. I changed the 

352 # Buffer name for Data, so users can write directly to the datatype 

353 # instead of writing to datatype['Buffer']. 

354 # The drawback is you cannot directly access the Length and  

355 # MaximumLength fields.  

356 # If you really need it, you will need to do it this way: 

357 # class TT(NDRCALL): 

358 # structure = ( 

359 # ('str1', RPC_UNICODE_STRING), 

360 # ) 

361 #  

362 # nn = TT() 

363 # nn.fields['str1'].fields['MaximumLength'] = 30 

364 structure = ( 

365 ('Length','<H=0'), 

366 ('MaximumLength','<H=0'), 

367 ('Data',LPWSTR), 

368 ) 

369 

370 def __setitem__(self, key, value): 

371 if key == 'Data' and isinstance(value, NDR) is False: 

372 try: 

373 value.encode('utf-16le') 

374 except UnicodeDecodeError: 

375 import sys 

376 value = value.decode(sys.getfilesystemencoding()) 

377 self['Length'] = len(value)*2 

378 self['MaximumLength'] = len(value)*2 

379 return NDRSTRUCT.__setitem__(self, key, value) 

380 

381 def dump(self, msg = None, indent = 0): 

382 if msg is None: 382 ↛ 383line 382 didn't jump to line 383, because the condition on line 382 was never true

383 msg = self.__class__.__name__ 

384 if msg != '': 

385 print("%s" % msg, end=' ') 

386 

387 if isinstance(self.fields['Data'] , NDRPOINTERNULL): 387 ↛ 388line 387 didn't jump to line 388, because the condition on line 387 was never true

388 print(" NULL", end=' ') 

389 elif self.fields['Data']['ReferentID'] == 0: 

390 print(" NULL", end=' ') 

391 else: 

392 return self.fields['Data'].dump('',indent) 

393 

394class PRPC_UNICODE_STRING(NDRPOINTER): 

395 referent = ( 

396 ('Data', RPC_UNICODE_STRING ), 

397 ) 

398 

399# 2.3.9 OBJECT_TYPE_LIST 

400ACCESS_MASK = DWORD 

401class OBJECT_TYPE_LIST(NDRSTRUCT): 

402 structure = ( 

403 ('Level', WORD), 

404 ('Remaining',ACCESS_MASK), 

405 ('ObjectType',PGUID), 

406 ) 

407 

408class POBJECT_TYPE_LIST(NDRPOINTER): 

409 referent = ( 

410 ('Data', OBJECT_TYPE_LIST ), 

411 ) 

412 

413# 2.3.13 SYSTEMTIME 

414class SYSTEMTIME(NDRSTRUCT): 

415 structure = ( 

416 ('wYear', WORD), 

417 ('wMonth', WORD), 

418 ('wDayOfWeek', WORD), 

419 ('wDay', WORD), 

420 ('wHour', WORD), 

421 ('wMinute', WORD), 

422 ('wSecond', WORD), 

423 ('wMilliseconds', WORD), 

424 ) 

425 

426class PSYSTEMTIME(NDRPOINTER): 

427 referent = ( 

428 ('Data', SYSTEMTIME ), 

429 ) 

430 

431# 2.3.15 ULARGE_INTEGER 

432class ULARGE_INTEGER(NDRSTRUCT): 

433 structure = ( 

434 ('QuadPart', LONG64), 

435 ) 

436 

437class PULARGE_INTEGER(NDRPOINTER): 

438 referent = ( 

439 ('Data', ULARGE_INTEGER), 

440 ) 

441 

442# 2.4.2.3 RPC_SID 

443class DWORD_ARRAY(NDRUniConformantArray): 

444 item = '<L' 

445 

446class RPC_SID_IDENTIFIER_AUTHORITY(NDRUniFixedArray): 

447 align = 1 

448 align64 = 1 

449 def getDataLen(self, data, offset=0): 

450 return 6 

451 

452class RPC_SID(NDRSTRUCT): 

453 structure = ( 

454 ('Revision',NDRSMALL), 

455 ('SubAuthorityCount',NDRSMALL), 

456 ('IdentifierAuthority',RPC_SID_IDENTIFIER_AUTHORITY), 

457 ('SubAuthority',DWORD_ARRAY), 

458 ) 

459 def getData(self, soFar = 0): 

460 self['SubAuthorityCount'] = len(self['SubAuthority']) 

461 return NDRSTRUCT.getData(self, soFar) 

462 

463 def fromCanonical(self, canonical): 

464 items = canonical.split('-') 

465 self['Revision'] = int(items[1]) 

466 self['IdentifierAuthority'] = b'\x00\x00\x00\x00\x00' + pack('B',int(items[2])) 

467 self['SubAuthorityCount'] = len(items) - 3 

468 for i in range(self['SubAuthorityCount']): 

469 self['SubAuthority'].append(int(items[i+3])) 

470 

471 def formatCanonical(self): 

472 ans = 'S-%d-%d' % (self['Revision'], ord(self['IdentifierAuthority'][5:6])) 

473 for i in range(self['SubAuthorityCount']): 

474 ans += '-%d' % self['SubAuthority'][i] 

475 return ans 

476 

477class PRPC_SID(NDRPOINTER): 

478 referent = ( 

479 ('Data', RPC_SID), 

480 ) 

481 

482PSID = PRPC_SID 

483 

484# 2.4.3 ACCESS_MASK 

485GENERIC_READ = 0x80000000 

486GENERIC_WRITE = 0x40000000 

487GENERIC_EXECUTE = 0x20000000 

488GENERIC_ALL = 0x10000000 

489MAXIMUM_ALLOWED = 0x02000000 

490ACCESS_SYSTEM_SECURITY = 0x01000000 

491SYNCHRONIZE = 0x00100000 

492WRITE_OWNER = 0x00080000 

493WRITE_DACL = 0x00040000 

494READ_CONTROL = 0x00020000 

495DELETE = 0x00010000 

496 

497# 2.4.5.1 ACL--RPC Representation 

498class ACL(NDRSTRUCT): 

499 structure = ( 

500 ('AclRevision',NDRSMALL), 

501 ('Sbz1',NDRSMALL), 

502 ('AclSize',NDRSHORT), 

503 ('AceCount',NDRSHORT), 

504 ('Sbz2',NDRSHORT), 

505 ) 

506 

507class PACL(NDRPOINTER): 

508 referent = ( 

509 ('Data', ACL), 

510 ) 

511 

512# 2.4.6.1 SECURITY_DESCRIPTOR--RPC Representation 

513class SECURITY_DESCRIPTOR(NDRSTRUCT): 

514 structure = ( 

515 ('Revision',UCHAR), 

516 ('Sbz1',UCHAR), 

517 ('Control',USHORT), 

518 ('Owner',PSID), 

519 ('Group',PSID), 

520 ('Sacl',PACL), 

521 ('Dacl',PACL), 

522 ) 

523 

524# 2.4.7 SECURITY_INFORMATION 

525OWNER_SECURITY_INFORMATION = 0x00000001 

526GROUP_SECURITY_INFORMATION = 0x00000002 

527DACL_SECURITY_INFORMATION = 0x00000004 

528SACL_SECURITY_INFORMATION = 0x00000008 

529LABEL_SECURITY_INFORMATION = 0x00000010 

530UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000 

531UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000 

532PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000 

533PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000 

534ATTRIBUTE_SECURITY_INFORMATION = 0x00000020 

535SCOPE_SECURITY_INFORMATION = 0x00000040 

536BACKUP_SECURITY_INFORMATION = 0x00010000 

537 

538SECURITY_INFORMATION = DWORD 

539class PSECURITY_INFORMATION(NDRPOINTER): 

540 referent = ( 

541 ('Data', SECURITY_INFORMATION), 

542 )