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

8# Cisco Discovery Protocol packet codecs. 

9# 

10# Author: 

11# Martin Candurra 

12# martincad at corest.com 

13 

14from struct import unpack 

15import socket 

16 

17from impacket.ImpactPacket import Header, array_tobytes 

18from impacket import LOG 

19 

20IP_ADDRESS_LENGTH = 4 

21 

22class CDPTypes: 

23 

24 DeviceID_Type = 1 

25 Address_Type = 2 

26 PortID_Type = 3 

27 Capabilities_Type = 4 

28 SoftVersion_Type = 5 

29 Platform_Type = 6 

30 IPPrefix_Type = 7 

31 ProtocolHello_Type = 8 

32 MTU_Type = 17 

33 SystemName_Type = 20 

34 SystemObjectId_Type = 21 

35 SnmpLocation = 23 

36 

37class CDP(Header): 

38 

39 Type = 0x2000 

40 OUI = 0x00000c 

41 

42 def __init__(self, aBuffer = None): 

43 Header.__init__(self, 8) 

44 if aBuffer: 

45 self.load_header(aBuffer) 

46 self._elements = self._getElements(aBuffer) 

47 

48 def _getElements(self, aBuffer): 

49 # Remove version (1 byte), TTL (1 byte), and checksum (2 bytes) 

50 buff = aBuffer[4:] 

51 l = [] 

52 while buff: 

53 elem = CDPElementFactory.create(buff) 

54 l.append( elem ) 

55 buff = buff[ elem.get_length() : ] 

56 return l 

57 

58 def get_header_size(self): 

59 return 8 

60 

61 def get_version(self): 

62 return self.get_byte(0) 

63 

64 def get_ttl(self): 

65 return self.get_byte(1) 

66 

67 def get_checksum(self): 

68 return self.get_word(2) 

69 

70 def get_type(self): 

71 return self.get_word(4) 

72 

73 def get_lenght(self): 

74 return self.get_word(6) 

75 

76 def getElements(self): 

77 return self._elements 

78 

79 

80 def __str__(self): 

81 tmp_str = 'CDP Details:\n' 

82 for element in self._elements: 

83 tmp_str += "** Type:" + str(element.get_type()) + " " + str(element) + "\n" 

84 return tmp_str 

85 

86 

87def get_byte(buffer, offset): 

88 return unpack("!B", buffer[offset:offset+1])[0] 

89 

90def get_word(buffer, offset): 

91 return unpack("!h", buffer[offset:offset+2])[0] 

92 

93def get_long(buffer, offset): 

94 return unpack("!I", buffer[offset:offset+4])[0] 

95 

96def get_bytes(buffer, offset, bytes): 

97 return buffer[offset:offset + bytes] 

98 

99def mac_to_string(mac_bytes): 

100 bytes = unpack('!BBBBBB', mac_bytes) 

101 s = '' 

102 for byte in bytes: 

103 s += '%02x:' % byte 

104 return s[0:-1] 

105 

106 

107 

108class CDPElement(Header): 

109 

110 def __init__(self, aBuffer = None): 

111 Header.__init__(self, 8) 

112 if aBuffer: 

113 self._length = CDPElement.Get_length(aBuffer) 

114 self.load_header( aBuffer[:self._length] ) 

115 

116 @classmethod 

117 def Get_length(cls, aBuffer): 

118 return unpack('!h', aBuffer[2:4])[0] 

119 

120 def get_header_size(self): 

121 self._length 

122 

123 def get_length(self): 

124 return self.get_word(2) 

125 

126 def get_data(self): 

127 return array_tobytes(self.get_bytes())[4:self.get_length()] 

128 

129 def get_ip_address(self, offset = 0, ip = None): 

130 if not ip: 

131 ip = array_tobytes(self.get_bytes())[offset : offset + IP_ADDRESS_LENGTH] 

132 return socket.inet_ntoa( ip ) 

133 

134class CDPDevice(CDPElement): 

135 Type = 1 

136 

137 def get_type(self): 

138 return CDPDevice.Type 

139 

140 def get_device_id(self): 

141 return CDPElement.get_data(self) 

142 

143 def __str__(self): 

144 return "Device:" + self.get_device_id() 

145 

146class Address(CDPElement): 

147 Type = 2 

148 

149 def __init__(self, aBuffer = None): 

150 CDPElement.__init__(self, aBuffer) 

151 if aBuffer: 

152 data = array_tobytes(self.get_bytes())[8:] 

153 self._generateAddressDetails(data) 

154 

155 def _generateAddressDetails(self, buff): 

156 self.address_details = [] 

157 while buff: 

158 address = AddressDetails.create(buff) 

159 self.address_details.append( address ) 

160 buff = buff[address.get_total_length():] 

161 

162 def get_type(self): 

163 return Address.Type 

164 

165 def get_number(self): 

166 return self.get_long(4) 

167 

168 def get_address_details(self): 

169 return self.address_details 

170 

171 def __str__(self): 

172 tmp_str = "Addresses:" 

173 for address_detail in self.address_details: 

174 tmp_str += "\n" + str(address_detail) 

175 return tmp_str 

176 

177class AddressDetails(): 

178 

179 PROTOCOL_IP = 0xcc 

180 

181 @classmethod 

182 def create(cls, buff): 

183 a = AddressDetails(buff) 

184 return a 

185 

186 

187 def __init__(self, aBuffer = None): 

188 if aBuffer: 

189 addr_length = unpack("!h", aBuffer[3:5])[0] 

190 self.total_length = addr_length + 5 

191 self.buffer = aBuffer[:self.total_length] 

192 

193 def get_total_length(self): 

194 return self.total_length 

195 

196 def get_protocol_type(self): 

197 return self.buffer[0:1] 

198 

199 def get_protocol_length(self): 

200 return get_byte( self.buffer, 1) 

201 

202 def get_protocol(self): 

203 return get_byte( self.buffer, 2) 

204 

205 def get_address_length(self): 

206 return get_word( self.buffer, 3) 

207 

208 def get_address(self): 

209 address = get_bytes( self.buffer, 5, self.get_address_length() ) 

210 if self.get_protocol()==AddressDetails.PROTOCOL_IP: 

211 return socket.inet_ntoa(address) 

212 else: 

213 LOG.error("Address not IP") 

214 return address 

215 

216 def is_protocol_IP(self): 

217 return self.get_protocol()==AddressDetails.PROTOCOL_IP 

218 

219 def __str__(self): 

220 return "Protocol Type:%r Protocol:%r Address Length:%r Address:%s" % (self.get_protocol_type(), self.get_protocol(), self.get_address_length(), self.get_address()) 

221 

222class Port(CDPElement): 

223 Type = 3 

224 

225 def get_type(self): 

226 return Port.Type 

227 

228 def get_port(self): 

229 return CDPElement.get_data(self) 

230 

231 def __str__(self): 

232 return "Port:" + self.get_port() 

233 

234 

235class Capabilities(CDPElement): 

236 Type = 4 

237 

238 def __init__(self, aBuffer = None): 

239 CDPElement.__init__(self, aBuffer) 

240 self._capabilities_processed = False 

241 

242 self._router = False 

243 self._transparent_bridge = False 

244 self._source_route_bridge = False 

245 self._switch = False 

246 self._host = False 

247 self._igmp_capable = False 

248 self._repeater = False 

249 self._init_capabilities() 

250 

251 def get_type(self): 

252 return Capabilities.Type 

253 

254 def get_capabilities(self): 

255 return CDPElement.get_data(self) 

256 

257 def _init_capabilities(self): 

258 if self._capabilities_processed: 

259 return 

260 

261 capabilities = unpack("!L", self.get_capabilities())[0] 

262 self._router = (capabilities & 0x1) > 0 

263 self._transparent_bridge = (capabilities & 0x02) > 0 

264 self._source_route_bridge = (capabilities & 0x04) > 0 

265 self._switch = (capabilities & 0x08) > 0 

266 self._host = (capabilities & 0x10) > 0 

267 self._igmp_capable = (capabilities & 0x20) > 0 

268 self._repeater = (capabilities & 0x40) > 0 

269 

270 def is_router(self): 

271 return self._router 

272 

273 def is_transparent_bridge(self): 

274 return self._transparent_bridge 

275 

276 def is_source_route_bridge(self): 

277 return self._source_route_bridge 

278 

279 def is_switch(self): 

280 return self._switch 

281 

282 def is_host(self): 

283 return self.is_host 

284 

285 def is_igmp_capable(self): 

286 return self._igmp_capable 

287 

288 def is_repeater(self): 

289 return self._repeater 

290 

291 

292 def __str__(self): 

293 return "Capabilities:" + self.get_capabilities() 

294 

295 

296class SoftVersion(CDPElement): 

297 Type = 5 

298 

299 def get_type(self): 

300 return SoftVersion.Type 

301 

302 def get_version(self): 

303 return CDPElement.get_data(self) 

304 

305 def __str__(self): 

306 return "Version:" + self.get_version() 

307 

308 

309class Platform(CDPElement): 

310 Type = 6 

311 

312 def get_type(self): 

313 return Platform.Type 

314 

315 def get_platform(self): 

316 return CDPElement.get_data(self) 

317 

318 def __str__(self): 

319 return "Platform:%r" % self.get_platform() 

320 

321 

322class IpPrefix(CDPElement): 

323 Type = 7 

324 

325 def get_type(self): 

326 return IpPrefix .Type 

327 

328 def get_ip_prefix(self): 

329 return CDPElement.get_ip_address(self, 4) 

330 

331 def get_bits(self): 

332 return self.get_byte(8) 

333 

334 def __str__(self): 

335 return "IP Prefix/Gateway: %r/%d" % (self.get_ip_prefix(), self.get_bits()) 

336 

337class ProtocolHello(CDPElement): 

338 Type = 8 

339 

340 def get_type(self): 

341 return ProtocolHello.Type 

342 

343 def get_master_ip(self): 

344 return self.get_ip_address(9) 

345 

346 def get_version(self): 

347 return self.get_byte(17) 

348 

349 def get_sub_version(self): 

350 return self.get_byte(18) 

351 

352 def get_status(self): 

353 return self.get_byte(19) 

354 

355 def get_cluster_command_mac(self): 

356 return array_tobytes(self.get_bytes())[20:20+6] 

357 

358 def get_switch_mac(self): 

359 return array_tobytes(self.get_bytes())[28:28+6] 

360 

361 def get_management_vlan(self): 

362 return self.get_word(36) 

363 

364 def __str__(self): 

365 return "\n\n\nProcolHello: Master IP:%s version:%r subversion:%r status:%r Switch's Mac:%r Management VLAN:%r" \ 

366 % (self.get_master_ip(), self.get_version(), self.get_sub_version(), self.get_status(), mac_to_string(self.get_switch_mac()), self.get_management_vlan()) 

367 

368class VTPManagementDomain(CDPElement): 

369 Type = 9 

370 

371 def get_type(self): 

372 return VTPManagementDomain.Type 

373 

374 def get_domain(self): 

375 return CDPElement.get_data(self) 

376 

377 

378class Duplex(CDPElement): 

379 Type = 0xb 

380 

381 def get_type(self): 

382 return Duplex.Type 

383 

384 def get_duplex(self): 

385 return CDPElement.get_data(self) 

386 

387 def is_full_duplex(self): 

388 return self.get_duplex()==0x1 

389 

390class VLAN(CDPElement): 

391 Type = 0xa 

392 

393 def get_type(self): 

394 return VLAN.Type 

395 

396 def get_vlan_number(self): 

397 return CDPElement.get_data(self) 

398 

399 

400 

401class TrustBitmap(CDPElement): 

402 Type = 0x12 

403 

404 def get_type(self): 

405 return TrustBitmap.Type 

406 

407 def get_trust_bitmap(self): 

408 return self.get_data() 

409 

410 def __str__(self): 

411 return "TrustBitmap Trust Bitmap:%r" % self.get_trust_bitmap() 

412 

413class UntrustedPortCoS(CDPElement): 

414 Type = 0x13 

415 

416 def get_type(self): 

417 return UntrustedPortCoS.Type 

418 

419 def get_port_CoS(self): 

420 return self.get_data() 

421 

422 def __str__(self): 

423 return "UntrustedPortCoS port CoS %r" % self.get_port_CoS() 

424 

425class ManagementAddresses(Address): 

426 Type = 0x16 

427 

428 def get_type(self): 

429 return ManagementAddresses.Type 

430 

431class MTU(CDPElement): 

432 Type = 0x11 

433 

434 def get_type(self): 

435 return MTU.Type 

436 

437class SystemName(CDPElement): 

438 Type = 0x14 

439 

440 def get_type(self): 

441 return SystemName.Type 

442 

443class SystemObjectId(CDPElement): 

444 Type = 0x15 

445 

446 def get_type(self): 

447 return SystemObjectId.Type 

448 

449class SnmpLocation(CDPElement): 

450 Type = 0x17 

451 

452 def get_type(self): 

453 return SnmpLocation.Type 

454 

455 

456class DummyCdpElement(CDPElement): 

457 Type = 0x99 

458 

459 def get_type(self): 

460 return DummyCdpElement.Type 

461 

462class CDPElementFactory(): 

463 

464 elementTypeMap = { 

465 CDPDevice.Type : CDPDevice, 

466 Port.Type : Port, 

467 Capabilities.Type : Capabilities, 

468 Address.Type : Address, 

469 SoftVersion.Type : SoftVersion, 

470 Platform.Type : Platform, 

471 IpPrefix.Type : IpPrefix, 

472 ProtocolHello.Type : ProtocolHello, 

473 VTPManagementDomain.Type : VTPManagementDomain, 

474 VLAN.Type : VLAN, 

475 Duplex.Type : Duplex, 

476 TrustBitmap.Type : TrustBitmap, 

477 UntrustedPortCoS.Type : UntrustedPortCoS, 

478 ManagementAddresses.Type : ManagementAddresses, 

479 MTU.Type : MTU, 

480 SystemName.Type : SystemName, 

481 SystemObjectId.Type : SystemObjectId, 

482 SnmpLocation.Type : SnmpLocation 

483 } 

484 

485 @classmethod 

486 def create(cls, aBuffer): 

487# print "CDPElementFactory.create aBuffer:", repr(aBuffer) 

488# print "CDPElementFactory.create sub_type:", repr(aBuffer[0:2]) 

489 _type = unpack("!h", aBuffer[0:2])[0] 

490# print "CDPElementFactory.create _type:", _type 

491 try: 

492 class_type = cls.elementTypeMap[_type] 

493 except KeyError: 

494 class_type = DummyCdpElement 

495 #raise Exception("CDP Element type %s not implemented" % _type) 

496 return class_type( aBuffer )