Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/layers/radius.py: 69%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

420 statements  

1# SPDX-License-Identifier: GPL-2.0-only 

2# This file is part of Scapy 

3# See https://scapy.net/ for more information 

4# Acknowledgment: Vincent Mauge <vmauge.nospam@nospam.gmail.com> 

5 

6""" 

7RADIUS (Remote Authentication Dial In User Service) 

8 

9To disable Radius-EAP defragmentation (True by default), you can use:: 

10 

11 conf.contribs.setdefault("radius", {}).setdefault("auto-defrag", False) 

12""" 

13 

14import collections 

15import enum 

16import hashlib 

17import hmac 

18import struct 

19 

20from scapy.ansmachine import AnsweringMachine 

21from scapy.compat import bytes_encode 

22from scapy.config import conf, crypto_validator 

23from scapy.error import log_runtime, Scapy_Exception 

24from scapy.packet import ( 

25 Packet, 

26 Padding, 

27 bind_layers, 

28 bind_bottom_up, 

29) 

30from scapy.fields import ( 

31 ByteEnumField, 

32 ByteField, 

33 FieldLenField, 

34 IPField, 

35 IntEnumField, 

36 IntField, 

37 MultiEnumField, 

38 MultipleTypeField, 

39 PacketLenField, 

40 PacketListField, 

41 StrField, 

42 StrFixedLenField, 

43 StrLenField, 

44 XStrFixedLenField, 

45 XStrLenField, 

46) 

47from scapy.sendrecv import send 

48from scapy.utils import strxor 

49 

50from scapy.layers.eap import EAP 

51from scapy.layers.inet import UDP, IP 

52from scapy.layers.ntlm import MD4le 

53 

54if conf.crypto_valid: 

55 from scapy.layers.tls.crypto.cipher_block import Cipher_DES_ECB 

56 from scapy.layers.tls.crypto.hash import ( 

57 Hash_MD4, 

58 Hash_MD5, 

59 Hash_SHA, 

60 ) 

61else: 

62 Cipher_DES_ECB = None 

63 Hash_MD4 = Hash_MD5 = Hash_SHA = None 

64 

65 

66# https://www.iana.org/assignments/radius-types/radius-types.xhtml 

67_radius_attribute_types = { 

68 1: "User-Name", 

69 2: "User-Password", 

70 3: "CHAP-Password", 

71 4: "NAS-IP-Address", 

72 5: "NAS-Port", 

73 6: "Service-Type", 

74 7: "Framed-Protocol", 

75 8: "Framed-IP-Address", 

76 9: "Framed-IP-Netmask", 

77 10: "Framed-Routing", 

78 11: "Filter-Id", 

79 12: "Framed-MTU", 

80 13: "Framed-Compression", 

81 14: "Login-IP-Host", 

82 15: "Login-Service", 

83 16: "Login-TCP-Port", 

84 17: "Unassigned", 

85 18: "Reply-Message", 

86 19: "Callback-Number", 

87 20: "Callback-Id", 

88 21: "Unassigned", 

89 22: "Framed-Route", 

90 23: "Framed-IPX-Network", 

91 24: "State", 

92 25: "Class", 

93 26: "Vendor-Specific", 

94 27: "Session-Timeout", 

95 28: "Idle-Timeout", 

96 29: "Termination-Action", 

97 30: "Called-Station-Id", 

98 31: "Calling-Station-Id", 

99 32: "NAS-Identifier", 

100 33: "Proxy-State", 

101 34: "Login-LAT-Service", 

102 35: "Login-LAT-Node", 

103 36: "Login-LAT-Group", 

104 37: "Framed-AppleTalk-Link", 

105 38: "Framed-AppleTalk-Network", 

106 39: "Framed-AppleTalk-Zone", 

107 40: "Acct-Status-Type", 

108 41: "Acct-Delay-Time", 

109 42: "Acct-Input-Octets", 

110 43: "Acct-Output-Octets", 

111 44: "Acct-Session-Id", 

112 45: "Acct-Authentic", 

113 46: "Acct-Session-Time", 

114 47: "Acct-Input-Packets", 

115 48: "Acct-Output-Packets", 

116 49: "Acct-Terminate-Cause", 

117 50: "Acct-Multi-Session-Id", 

118 51: "Acct-Link-Count", 

119 52: "Acct-Input-Gigawords", 

120 53: "Acct-Output-Gigawords", 

121 54: "Unassigned", 

122 55: "Event-Timestamp", 

123 56: "Egress-VLANID", 

124 57: "Ingress-Filters", 

125 58: "Egress-VLAN-Name", 

126 59: "User-Priority-Table", 

127 60: "CHAP-Challenge", 

128 61: "NAS-Port-Type", 

129 62: "Port-Limit", 

130 63: "Login-LAT-Port", 

131 64: "Tunnel-Type", 

132 65: "Tunnel-Medium-Type", 

133 66: "Tunnel-Client-Endpoint", 

134 67: "Tunnel-Server-Endpoint", 

135 68: "Acct-Tunnel-Connection", 

136 69: "Tunnel-Password", 

137 70: "ARAP-Password", 

138 71: "ARAP-Features", 

139 72: "ARAP-Zone-Access", 

140 73: "ARAP-Security", 

141 74: "ARAP-Security-Data", 

142 75: "Password-Retry", 

143 76: "Prompt", 

144 77: "Connect-Info", 

145 78: "Configuration-Token", 

146 79: "EAP-Message", 

147 80: "Message-Authenticator", 

148 81: "Tunnel-Private-Group-ID", 

149 82: "Tunnel-Assignment-ID", 

150 83: "Tunnel-Preference", 

151 84: "ARAP-Challenge-Response", 

152 85: "Acct-Interim-Interval", 

153 86: "Acct-Tunnel-Packets-Lost", 

154 87: "NAS-Port-Id", 

155 88: "Framed-Pool", 

156 89: "CUI", 

157 90: "Tunnel-Client-Auth-ID", 

158 91: "Tunnel-Server-Auth-ID", 

159 92: "NAS-Filter-Rule", 

160 93: "Unassigned", 

161 94: "Originating-Line-Info", 

162 95: "NAS-IPv6-Address", 

163 96: "Framed-Interface-Id", 

164 97: "Framed-IPv6-Prefix", 

165 98: "Login-IPv6-Host", 

166 99: "Framed-IPv6-Route", 

167 100: "Framed-IPv6-Pool", 

168 101: "Error-Cause", 

169 102: "EAP-Key-Name", 

170 103: "Digest-Response", 

171 104: "Digest-Realm", 

172 105: "Digest-Nonce", 

173 106: "Digest-Response-Auth", 

174 107: "Digest-Nextnonce", 

175 108: "Digest-Method", 

176 109: "Digest-URI", 

177 110: "Digest-Qop", 

178 111: "Digest-Algorithm", 

179 112: "Digest-Entity-Body-Hash", 

180 113: "Digest-CNonce", 

181 114: "Digest-Nonce-Count", 

182 115: "Digest-Username", 

183 116: "Digest-Opaque", 

184 117: "Digest-Auth-Param", 

185 118: "Digest-AKA-Auts", 

186 119: "Digest-Domain", 

187 120: "Digest-Stale", 

188 121: "Digest-HA1", 

189 122: "SIP-AOR", 

190 123: "Delegated-IPv6-Prefix", 

191 124: "MIP6-Feature-Vector", 

192 125: "MIP6-Home-Link-Prefix", 

193 126: "Operator-Name", 

194 127: "Location-Information", 

195 128: "Location-Data", 

196 129: "Basic-Location-Policy-Rules", 

197 130: "Extended-Location-Policy-Rules", 

198 131: "Location-Capable", 

199 132: "Requested-Location-Info", 

200 133: "Framed-Management-Protocol", 

201 134: "Management-Transport-Protection", 

202 135: "Management-Policy-Id", 

203 136: "Management-Privilege-Level", 

204 137: "PKM-SS-Cert", 

205 138: "PKM-CA-Cert", 

206 139: "PKM-Config-Settings", 

207 140: "PKM-Cryptosuite-List", 

208 141: "PKM-SAID", 

209 142: "PKM-SA-Descriptor", 

210 143: "PKM-Auth-Key", 

211 144: "DS-Lite-Tunnel-Name", 

212 145: "Mobile-Node-Identifier", 

213 146: "Service-Selection", 

214 147: "PMIP6-Home-LMA-IPv6-Address", 

215 148: "PMIP6-Visited-LMA-IPv6-Address", 

216 149: "PMIP6-Home-LMA-IPv4-Address", 

217 150: "PMIP6-Visited-LMA-IPv4-Address", 

218 151: "PMIP6-Home-HN-Prefix", 

219 152: "PMIP6-Visited-HN-Prefix", 

220 153: "PMIP6-Home-Interface-ID", 

221 154: "PMIP6-Visited-Interface-ID", 

222 155: "PMIP6-Home-IPv4-HoA", 

223 156: "PMIP6-Visited-IPv4-HoA", 

224 157: "PMIP6-Home-DHCP4-Server-Address", 

225 158: "PMIP6-Visited-DHCP4-Server-Address", 

226 159: "PMIP6-Home-DHCP6-Server-Address", 

227 160: "PMIP6-Visited-DHCP6-Server-Address", 

228 161: "PMIP6-Home-IPv4-Gateway", 

229 162: "PMIP6-Visited-IPv4-Gateway", 

230 163: "EAP-Lower-Layer", 

231 164: "GSS-Acceptor-Service-Name", 

232 165: "GSS-Acceptor-Host-Name", 

233 166: "GSS-Acceptor-Service-Specifics", 

234 167: "GSS-Acceptor-Realm-Name", 

235 168: "Framed-IPv6-Address", 

236 169: "DNS-Server-IPv6-Address", 

237 170: "Route-IPv6-Information", 

238 171: "Delegated-IPv6-Prefix-Pool", 

239 172: "Stateful-IPv6-Address-Pool", 

240 173: "IPv6-6rd-Configuration", 

241 174: "Allowed-Called-Station-Id", 

242 175: "EAP-Peer-Id", 

243 176: "EAP-Server-Id", 

244 177: "Mobility-Domain-Id", 

245 178: "Preauth-Timeout", 

246 179: "Network-Id-Name", 

247 180: "EAPoL-Announcement", 

248 181: "WLAN-HESSID", 

249 182: "WLAN-Venue-Info", 

250 183: "WLAN-Venue-Language", 

251 184: "WLAN-Venue-Name", 

252 185: "WLAN-Reason-Code", 

253 186: "WLAN-Pairwise-Cipher", 

254 187: "WLAN-Group-Cipher", 

255 188: "WLAN-AKM-Suite", 

256 189: "WLAN-Group-Mgmt-Cipher", 

257 190: "WLAN-RF-Band", 

258 191: "Unassigned", 

259} 

260 

261 

262class RadiusAttribute(Packet): 

263 """ 

264 Implements a RADIUS attribute (RFC 2865). Every specific RADIUS attribute 

265 class should inherit from this one. 

266 """ 

267 

268 name = "Radius Attribute" 

269 fields_desc = [ 

270 ByteEnumField("type", 1, _radius_attribute_types), 

271 FieldLenField("len", None, "value", "B", 

272 adjust=lambda pkt, x: len(pkt.value) + 2), 

273 StrLenField("value", "", length_from=lambda pkt: pkt.len - 2) 

274 ] 

275 

276 registered_attributes = {} 

277 

278 @classmethod 

279 def register_variant(cls): 

280 """ 

281 Registers the RADIUS attributes defined in this module. 

282 """ 

283 

284 if hasattr(cls, "val"): 

285 cls.registered_attributes[cls.val] = cls 

286 else: 

287 cls.registered_attributes[cls.type.default] = cls 

288 

289 @classmethod 

290 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

291 """ 

292 Returns the right RadiusAttribute class for the given data. 

293 """ 

294 

295 if _pkt: 

296 attr_type = _pkt[0] 

297 return cls.registered_attributes.get(attr_type, cls) 

298 return cls 

299 

300 def post_build(self, p, pay): 

301 length = self.len 

302 if length is None: 

303 length = len(p) 

304 p = p[:1] + struct.pack("!B", length) + p[2:] 

305 return p 

306 

307 def guess_payload_class(self, _): 

308 return Padding 

309 

310 

311class _SpecificRadiusAttr(RadiusAttribute): 

312 """ 

313 Class from which every "specific" RADIUS attribute defined in this module 

314 inherits. 

315 """ 

316 

317 __slots__ = ["val"] 

318 match_subclass = True 

319 

320 def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields): # noqa: E501 

321 super(_SpecificRadiusAttr, self).__init__( 

322 _pkt, 

323 post_transform, 

324 _internal, 

325 _underlayer, 

326 **fields 

327 ) 

328 self.fields["type"] = self.val 

329 name_parts = self.__class__.__name__.split('RadiusAttr_') 

330 if len(name_parts) < 2: 

331 raise Scapy_Exception( 

332 "Invalid class name: {}".format(self.__class__.__name__) 

333 ) 

334 self.name = name_parts[1].replace('_', '-') 

335 

336 

337# 

338# RADIUS attributes which values are 4 bytes integers 

339# 

340 

341class _RadiusAttrIntValue(_SpecificRadiusAttr): 

342 """ 

343 Implements a RADIUS attribute which value field is 4 bytes long integer. 

344 """ 

345 

346 fields_desc = [ 

347 ByteEnumField("type", 5, _radius_attribute_types), 

348 ByteField("len", 6), 

349 IntField("value", 0) 

350 ] 

351 

352 

353class RadiusAttr_User_Name(_SpecificRadiusAttr): 

354 """RFC 2865""" 

355 val = 1 

356 

357 

358class RadiusAttr_NAS_Port(_RadiusAttrIntValue): 

359 """RFC 2865""" 

360 val = 5 

361 

362 

363class RadiusAttr_Framed_MTU(_RadiusAttrIntValue): 

364 """RFC 2865""" 

365 val = 12 

366 

367 

368class RadiusAttr_Login_TCP_Port(_RadiusAttrIntValue): 

369 """RFC 2865""" 

370 val = 16 

371 

372 

373class RadiusAttr_Session_Timeout(_RadiusAttrIntValue): 

374 """RFC 2865""" 

375 val = 27 

376 

377 

378class RadiusAttr_Idle_Timeout(_RadiusAttrIntValue): 

379 """RFC 2865""" 

380 val = 28 

381 

382 

383class RadiusAttr_Framed_AppleTalk_Link(_RadiusAttrIntValue): 

384 """RFC 2865""" 

385 val = 37 

386 

387 

388class RadiusAttr_Framed_AppleTalk_Network(_RadiusAttrIntValue): 

389 """RFC 2865""" 

390 val = 38 

391 

392 

393class RadiusAttr_Acct_Delay_Time(_RadiusAttrIntValue): 

394 """RFC 2866""" 

395 val = 41 

396 

397 

398class RadiusAttr_Acct_Input_Octets(_RadiusAttrIntValue): 

399 """RFC 2866""" 

400 val = 42 

401 

402 

403class RadiusAttr_Acct_Output_Octets(_RadiusAttrIntValue): 

404 """RFC 2866""" 

405 val = 43 

406 

407 

408class RadiusAttr_Acct_Session_Time(_RadiusAttrIntValue): 

409 """RFC 2866""" 

410 val = 46 

411 

412 

413class RadiusAttr_Acct_Input_Packets(_RadiusAttrIntValue): 

414 """RFC 2866""" 

415 val = 47 

416 

417 

418class RadiusAttr_Acct_Output_Packets(_RadiusAttrIntValue): 

419 """RFC 2866""" 

420 val = 48 

421 

422 

423class RadiusAttr_Acct_Link_Count(_RadiusAttrIntValue): 

424 """RFC 2866""" 

425 val = 51 

426 

427 

428class RadiusAttr_Acct_Input_Gigawords(_RadiusAttrIntValue): 

429 """RFC 2869""" 

430 val = 52 

431 

432 

433class RadiusAttr_Acct_Output_Gigawords(_RadiusAttrIntValue): 

434 """RFC 2869""" 

435 val = 53 

436 

437 

438class RadiusAttr_Egress_VLANID(_RadiusAttrIntValue): 

439 """RFC 4675""" 

440 val = 56 

441 

442 

443class RadiusAttr_Port_Limit(_RadiusAttrIntValue): 

444 """RFC 2865""" 

445 val = 62 

446 

447 

448class RadiusAttr_ARAP_Security(_RadiusAttrIntValue): 

449 """RFC 2869""" 

450 val = 73 

451 

452 

453class RadiusAttr_Password_Retry(_RadiusAttrIntValue): 

454 """RFC 2869""" 

455 val = 75 

456 

457 

458class RadiusAttr_Tunnel_Preference(_RadiusAttrIntValue): 

459 """RFC 2868""" 

460 val = 83 

461 

462 

463class RadiusAttr_Acct_Interim_Interval(_RadiusAttrIntValue): 

464 """RFC 2869""" 

465 val = 85 

466 

467 

468class RadiusAttr_Acct_Tunnel_Packets_Lost(_RadiusAttrIntValue): 

469 """RFC 2867""" 

470 val = 86 

471 

472 

473class RadiusAttr_Management_Privilege_Level(_RadiusAttrIntValue): 

474 """RFC 5607""" 

475 val = 136 

476 

477 

478class RadiusAttr_Mobility_Domain_Id(_RadiusAttrIntValue): 

479 """RFC 7268""" 

480 val = 177 

481 

482 

483class RadiusAttr_Preauth_Timeout(_RadiusAttrIntValue): 

484 """RFC 7268""" 

485 val = 178 

486 

487 

488class RadiusAttr_WLAN_Venue_Info(_RadiusAttrIntValue): 

489 """RFC 7268""" 

490 val = 182 

491 

492 

493class RadiusAttr_WLAN_Reason_Code(_RadiusAttrIntValue): 

494 """RFC 7268""" 

495 val = 185 

496 

497 

498class RadiusAttr_WLAN_Pairwise_Cipher(_RadiusAttrIntValue): 

499 """RFC 7268""" 

500 val = 186 

501 

502 

503class RadiusAttr_WLAN_Group_Cipher(_RadiusAttrIntValue): 

504 """RFC 7268""" 

505 val = 187 

506 

507 

508class RadiusAttr_WLAN_AKM_Suite(_RadiusAttrIntValue): 

509 """RFC 7268""" 

510 val = 188 

511 

512 

513class RadiusAttr_WLAN_Group_Mgmt_Cipher(_RadiusAttrIntValue): 

514 """RFC 7268""" 

515 val = 189 

516 

517 

518class RadiusAttr_WLAN_RF_Band(_RadiusAttrIntValue): 

519 """RFC 7268""" 

520 val = 190 

521 

522 

523# 

524# RADIUS attributes which values are string (displayed as hex) 

525# 

526 

527class _RadiusAttrHexStringVal(_SpecificRadiusAttr): 

528 """ 

529 Implements a RADIUS attribute which value field is a string that will be 

530 as a hex string. 

531 """ 

532 

533 __slots__ = ["val"] 

534 

535 def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields): # noqa: E501 

536 super(_RadiusAttrHexStringVal, self).__init__( 

537 _pkt, 

538 post_transform, 

539 _internal, 

540 _underlayer, 

541 **fields 

542 ) 

543 self.fields["type"] = self.val 

544 name_parts = self.__class__.__name__.split('RadiusAttr_') 

545 if len(name_parts) < 2: 

546 raise Scapy_Exception( 

547 "Invalid class name: {}".format(self.__class__.__name__) 

548 ) 

549 self.name = name_parts[1].replace('_', '-') 

550 

551 fields_desc = [ 

552 ByteEnumField("type", 24, _radius_attribute_types), 

553 FieldLenField( 

554 "len", 

555 None, 

556 "value", 

557 "B", 

558 adjust=lambda p, x: len(p.value) + 2 

559 ), 

560 XStrLenField("value", "", length_from=lambda p: p.len - 2 if p.len else 0) # noqa: E501 

561 ] 

562 

563 

564class RadiusAttr_User_Password(_RadiusAttrHexStringVal): 

565 """RFC 2865""" 

566 val = 2 

567 

568 def decrypt(self, radius_packet, secret): 

569 """ 

570 Return the decrypted value of the User-Password field 

571 RFC2865 sect 5.2 

572 """ 

573 password = b"" 

574 

575 encrypted = self.value 

576 ci = radius_packet.authenticator 

577 while encrypted: 

578 bi = Hash_MD5().digest(secret + ci) 

579 ci, encrypted = encrypted[:16], encrypted[16:] 

580 password += strxor(ci, bi) 

581 

582 return password.rstrip(b"\x00") 

583 

584 @staticmethod 

585 def encrypt(radius_packet, password, secret): 

586 """ 

587 Create a User-Password attribute from a secret 

588 RFC2865 sect 5.2 

589 """ 

590 password = bytes_encode(password) 

591 

592 # Pad to 16 octets boundary 

593 password += (-len(password) % 16) * b"\x00" 

594 

595 encrypted = b"" 

596 ci = radius_packet.authenticator 

597 while password: 

598 bi = Hash_MD5().digest(secret + ci) 

599 ci = strxor(password[:16], bi) 

600 password = password[16:] 

601 

602 return RadiusAttr_User_Password(value=encrypted) 

603 

604 

605class RadiusAttr_State(_RadiusAttrHexStringVal): 

606 """RFC 2865""" 

607 val = 24 

608 

609 

610def prepare_packed_data(radius_packet, RequestAuth): 

611 """ 

612 Pack RADIUS data prior computing the authentication MAC 

613 """ 

614 s = bytes(radius_packet) 

615 Code_Id_Length = s[:4] 

616 Attributes = s[4 + 16:] 

617 return Code_Id_Length + RequestAuth + Attributes 

618 

619 

620class RadiusAttr_Message_Authenticator(_RadiusAttrHexStringVal): 

621 """RFC 2869""" 

622 val = 80 

623 

624 fields_desc = [ 

625 ByteEnumField("type", 24, _radius_attribute_types), 

626 FieldLenField( 

627 "len", 

628 18, 

629 "value", 

630 "B", 

631 ), 

632 XStrFixedLenField("value", "\x00" * 16, length=16) 

633 ] 

634 

635 @staticmethod 

636 def compute_message_authenticator(radius_packet, packed_req_authenticator, 

637 shared_secret): 

638 """ 

639 Computes the "Message-Authenticator" of a given RADIUS packet. 

640 (RFC 2869 - Page 33) 

641 """ 

642 

643 # Make sure the current auth is empty 

644 attr = radius_packet[RadiusAttr_Message_Authenticator] 

645 attr.value = b"\x00" * (attr.len - 2) 

646 

647 data = prepare_packed_data(radius_packet, packed_req_authenticator) 

648 radius_hmac = hmac.new(shared_secret, data, hashlib.md5) 

649 

650 return radius_hmac.digest() 

651 

652# 

653# RADIUS attributes which values are IPv4 prefixes 

654# 

655 

656 

657class _RadiusAttrIPv4AddrVal(_SpecificRadiusAttr): 

658 """ 

659 Implements a RADIUS attribute which value field is an IPv4 address. 

660 """ 

661 

662 __slots__ = ["val"] 

663 

664 fields_desc = [ 

665 ByteEnumField("type", 4, _radius_attribute_types), 

666 ByteField("len", 6), 

667 IPField("value", "0.0.0.0") 

668 ] 

669 

670 

671class RadiusAttr_NAS_IP_Address(_RadiusAttrIPv4AddrVal): 

672 """RFC 2865""" 

673 val = 4 

674 

675 

676class RadiusAttr_Framed_IP_Address(_RadiusAttrIPv4AddrVal): 

677 """RFC 2865""" 

678 val = 8 

679 

680 

681class RadiusAttr_Framed_IP_Netmask(_RadiusAttrIPv4AddrVal): 

682 """RFC 2865""" 

683 val = 9 

684 

685 

686class RadiusAttr_Login_IP_Host(_RadiusAttrIPv4AddrVal): 

687 """RFC 2865""" 

688 val = 14 

689 

690 

691class RadiusAttr_Framed_IPX_Network(_RadiusAttrIPv4AddrVal): 

692 """RFC 2865""" 

693 val = 23 

694 

695 

696class RadiusAttr_PMIP6_Home_LMA_IPv4_Address(_RadiusAttrIPv4AddrVal): 

697 """RFC 6572""" 

698 val = 149 

699 

700 

701class RadiusAttr_PMIP6_Visited_LMA_IPv4_Address(_RadiusAttrIPv4AddrVal): 

702 """RFC 6572""" 

703 val = 150 

704 

705 

706class RadiusAttr_PMIP6_Home_DHCP4_Server_Address(_RadiusAttrIPv4AddrVal): 

707 """RFC 6572""" 

708 val = 157 

709 

710 

711class RadiusAttr_PMIP6_Visited_DHCP4_Server_Address(_RadiusAttrIPv4AddrVal): 

712 """RFC 6572""" 

713 val = 158 

714 

715 

716class RadiusAttr_PMIP6_Home_IPv4_Gateway(_RadiusAttrIPv4AddrVal): 

717 """RFC 6572""" 

718 val = 161 

719 

720 

721class RadiusAttr_PMIP6_Visited_IPv4_Gateway(_RadiusAttrIPv4AddrVal): 

722 """RFC 6572""" 

723 val = 162 

724 

725 

726# See IANA registry "RADIUS Types" 

727_radius_attrs_values = { 

728 # Service-Type 

729 6: 

730 { 

731 1: "Login", 

732 2: "Framed", 

733 3: "Callback Login", 

734 4: "Callback Framed", 

735 5: "Outbound", 

736 6: "Administrative", 

737 7: "NAS Prompt", 

738 8: "Authenticate Only", 

739 9: "Callback NAS Prompt", 

740 10: "Call Check", 

741 11: "Callback Administrative", 

742 12: "Voice", 

743 13: "Fax", 

744 14: "Modem Relay", 

745 15: "IAPP-Register", 

746 16: "IAPP-AP-Check", 

747 17: "Authorize Only", 

748 18: "Framed-Management", 

749 19: "Additional-Authorization" 

750 }, 

751 

752 # Framed-Protocol 

753 7: 

754 { 

755 1: "PPP", 

756 2: "SLIP", 

757 3: "AppleTalk Remote Access Protocol (ARAP)", 

758 4: "Gandalf proprietary SingleLink/MultiLink protocol", 

759 5: "Xylogics proprietary IPX/SLIP", 

760 6: "X.75 Synchronous", 

761 7: "GPRS PDP Context" 

762 }, 

763 

764 # Framed-Routing 

765 10: 

766 { 

767 0: "None", 

768 1: "Send routing packets", 

769 2: "Listen for routing packets", 

770 3: "Send and Listen" 

771 }, 

772 

773 # Framed-Compression 

774 13: 

775 { 

776 0: "None", 

777 1: "VJ TCP/IP header compression", 

778 2: "IPX header compression", 

779 3: "Stac-LZS compression" 

780 }, 

781 

782 # Login-Service 

783 15: 

784 { 

785 0: "Telnet", 

786 1: "Rlogin", 

787 2: "TCP Clear", 

788 3: "PortMaster (proprietary)", 

789 4: "LAT", 

790 5: "X25-PAD", 

791 6: "X25-T3POS", 

792 7: "Unassigned", 

793 8: "TCP Clear Quiet (suppresses any NAS-generated connect string)" 

794 }, 

795 

796 # Termination-Action 

797 29: 

798 { 

799 0: "Default", 

800 1: "RADIUS-Request" 

801 }, 

802 

803 # Acct-Status-Type 

804 40: 

805 { 

806 1: "Start", 

807 2: "Stop", 

808 3: "Interim-Update", 

809 4: "Unassigned", 

810 5: "Unassigned", 

811 6: "Unassigned", 

812 7: "Accounting-On", 

813 8: "Accounting-Off", 

814 9: "Tunnel-Start", 

815 10: "Tunnel-Stop", 

816 11: "Tunnel-Reject", 

817 12: "Tunnel-Link-Start", 

818 13: "Tunnel-Link-Stop", 

819 14: "Tunnel-Link-Reject", 

820 15: "Failed" 

821 }, 

822 

823 # Acct-Authentic 

824 45: 

825 { 

826 1: "RADIUS", 

827 2: "Local", 

828 3: "Remote", 

829 4: "Diameter" 

830 }, 

831 

832 # Acct-Terminate-Cause 

833 49: 

834 { 

835 1: "User Request", 

836 2: "Lost Carrier", 

837 3: "Lost Service", 

838 4: "Idle Timeout", 

839 5: "Session Timeout", 

840 6: "Admin Reset", 

841 7: "Admin Reboot", 

842 8: "Port Error", 

843 9: "NAS Error", 

844 10: "NAS Request", 

845 11: "NAS Reboot", 

846 12: "Port Unneeded", 

847 13: "Port Preempted", 

848 14: "Port Suspended", 

849 15: "Service Unavailable", 

850 16: "Callback", 

851 17: "User Error", 

852 18: "Host Request", 

853 19: "Supplicant Restart", 

854 20: "Reauthentication Failure", 

855 21: "Port Reinitialized", 

856 22: "Port Administratively Disabled", 

857 23: "Lost Power", 

858 }, 

859 

860 # NAS-Port-Type 

861 61: 

862 { 

863 0: "Async", 

864 1: "Sync", 

865 2: "ISDN Sync", 

866 3: "ISDN Async V.120", 

867 4: "ISDN Async V.110", 

868 5: "Virtual", 

869 6: "PIAFS", 

870 7: "HDLC Clear Channel", 

871 8: "X.25", 

872 9: "X.75", 

873 10: "G.3 Fax", 

874 11: "SDSL - Symmetric DSL", 

875 12: "ADSL-CAP - Asymmetric DSL, Carrierless Amplitude Phase Modulation", # noqa: E501 

876 13: "ADSL-DMT - Asymmetric DSL, Discrete Multi-Tone", 

877 14: "IDSL - ISDN Digital Subscriber Line", 

878 15: "Ethernet", 

879 16: "xDSL - Digital Subscriber Line of unknown type", 

880 17: "Cable", 

881 18: "Wireles - Other", 

882 19: "Wireless - IEEE 802.11", 

883 20: "Token-Ring", 

884 21: "FDDI", 

885 22: "Wireless - CDMA2000", 

886 23: "Wireless - UMTS", 

887 24: "Wireless - 1X-EV", 

888 25: "IAPP", 

889 26: "FTTP - Fiber to the Premises", 

890 27: "Wireless - IEEE 802.16", 

891 28: "Wireless - IEEE 802.20", 

892 29: "Wireless - IEEE 802.22", 

893 30: "PPPoA - PPP over ATM", 

894 31: "PPPoEoA - PPP over Ethernet over ATM", 

895 32: "PPPoEoE - PPP over Ethernet over Ethernet", 

896 33: "PPPoEoVLAN - PPP over Ethernet over VLAN", 

897 34: "PPPoEoQinQ - PPP over Ethernet over IEEE 802.1QinQ", 

898 35: "xPON - Passive Optical Network", 

899 36: "Wireless - XGP", 

900 37: "WiMAX Pre-Release 8 IWK Function", 

901 38: "WIMAX-WIFI-IWK: WiMAX WIFI Interworking", 

902 39: "WIMAX-SFF: Signaling Forwarding Function for LTE/3GPP2", 

903 40: "WIMAX-HA-LMA: WiMAX HA and or LMA function", 

904 41: "WIMAX-DHCP: WIMAX DHCP service", 

905 42: "WIMAX-LBS: WiMAX location based service", 

906 43: "WIMAX-WVS: WiMAX voice service" 

907 }, 

908 

909 # Tunnel-Type 

910 64: 

911 { 

912 1: "Point-to-Point Tunneling Protocol (PPTP)", 

913 2: "Layer Two Forwarding (L2F)", 

914 3: "Layer Two Tunneling Protocol (L2TP)", 

915 4: "Ascend Tunnel Management Protocol (ATMP)", 

916 5: "Virtual Tunneling Protocol (VTP)", 

917 6: "IP Authentication Header in the Tunnel-mode (AH)", 

918 7: "IP-in-IP Encapsulation (IP-IP)", 

919 8: "Minimal IP-in-IP Encapsulation (MIN-IP-IP)", 

920 9: "IP Encapsulating Security Payload in the Tunnel-mode (ESP)", 

921 10: "Generic Route Encapsulation (GRE)", 

922 11: "Bay Dial Virtual Services (DVS)", 

923 12: "IP-in-IP Tunneling", 

924 13: "Virtual LANs (VLAN)" 

925 }, 

926 

927 # Tunnel-Medium-Type 

928 65: 

929 { 

930 1: "IPv4 (IP version 4)", 

931 2: "IPv6 (IP version 6)", 

932 3: "NSAP", 

933 4: "HDLC (8-bit multidrop)", 

934 5: "BBN 1822", 

935 6: "802", 

936 7: "E.163 (POTS)", 

937 8: "E.164 (SMDS, Frame Relay, ATM)", 

938 9: "F.69 (Telex)", 

939 10: "X.121 (X.25, Frame Relay)", 

940 11: "IPX", 

941 12: "Appletalk", 

942 13: "Decnet IV", 

943 14: "Banyan Vine", 

944 15: "E.164 with NSAP format subaddress" 

945 }, 

946 

947 # ARAP-Zone-Access 

948 72: 

949 { 

950 1: "Only allow access to default zone", 

951 2: "Use zone filter inclusively", 

952 3: "Not used", 

953 4: "Use zone filter exclusively" 

954 }, 

955 

956 # Prompt 

957 76: 

958 { 

959 0: "No Echo", 

960 1: "Echo" 

961 }, 

962 

963 # Error-Cause Attribute 

964 101: 

965 { 

966 201: "Residual Session Context Removed", 

967 202: "Invalid EAP Packet (Ignored)", 

968 401: "Unsupported Attribute", 

969 402: "Missing Attribute", 

970 403: "NAS Identification Mismatch", 

971 404: "Invalid Request", 

972 405: "Unsupported Service", 

973 406: "Unsupported Extension", 

974 407: "Invalid Attribute Value", 

975 501: "Administratively Prohibited", 

976 502: "Request Not Routable (Proxy)", 

977 503: "Session Context Not Found", 

978 504: "Session Context Not Removable", 

979 505: "Other Proxy Processing Error", 

980 506: "Resources Unavailable", 

981 507: "Request Initiated", 

982 508: "Multiple Session Selection Unsupported", 

983 509: "Location-Info-Required", 

984 601: "Response Too Big" 

985 }, 

986 

987 # Operator Namespace Identifier - Attribute 126 

988 126: 

989 { 

990 0x30: "TADIG", 

991 0x31: "REALM", 

992 0x32: "E212", 

993 0x33: "ICC", 

994 0xFF: "Reserved" 

995 }, 

996 

997 # Basic-Location-Policy-Rules 

998 129: 

999 { 

1000 0: "Retransmission allowed", 

1001 }, 

1002 

1003 # Location-Capable 

1004 131: 

1005 { 

1006 1: "CIVIC_LOCATION", 

1007 2: "GEO_LOCATION", 

1008 4: "USERS_LOCATION", 

1009 8: "NAS_LOCATION" 

1010 }, 

1011 

1012 # Framed-Management-Protocol 

1013 133: 

1014 { 

1015 1: "SNMP", 

1016 2: "Web-based", 

1017 3: "NETCONF", 

1018 4: "FTP", 

1019 5: "TFTP", 

1020 6: "SFTP", 

1021 7: "RCP", 

1022 8: "SCP" 

1023 }, 

1024 

1025 # Management-Transport-Protection 

1026 134: 

1027 { 

1028 1: "No-Protection", 

1029 2: "Integrity-Protection", 

1030 3: "Integrity-Confidentiality-Protection", 

1031 }, 

1032} 

1033 

1034 

1035class _RadiusAttrIntEnumVal(_SpecificRadiusAttr): 

1036 """ 

1037 Implements a RADIUS attribute which value field is 4 bytes long integer. 

1038 """ 

1039 

1040 __slots__ = ["val"] 

1041 

1042 fields_desc = [ 

1043 ByteEnumField("type", 6, _radius_attribute_types), 

1044 ByteField("len", 6), 

1045 MultiEnumField( 

1046 "value", 

1047 0, 

1048 _radius_attrs_values, 

1049 depends_on=lambda p: p.type, 

1050 fmt="I" 

1051 ) 

1052 ] 

1053 

1054 

1055class RadiusAttr_Service_Type(_RadiusAttrIntEnumVal): 

1056 """RFC 2865""" 

1057 val = 6 

1058 

1059 

1060class RadiusAttr_Framed_Protocol(_RadiusAttrIntEnumVal): 

1061 """RFC 2865""" 

1062 val = 7 

1063 

1064 

1065class RadiusAttr_Acct_Status_Type(_RadiusAttrIntEnumVal): 

1066 """RFC 2866""" 

1067 val = 40 

1068 

1069 

1070class RadiusAttr_Acct_Authentic(_RadiusAttrIntEnumVal): 

1071 """RFC 2866""" 

1072 val = 45 

1073 

1074 

1075class RadiusAttr_Acct_Terminate_Cause(_RadiusAttrIntEnumVal): 

1076 """RFC 2866""" 

1077 val = 49 

1078 

1079 

1080class RadiusAttr_NAS_Port_Type(_RadiusAttrIntEnumVal): 

1081 """RFC 2865""" 

1082 val = 61 

1083 

1084# 

1085# RADIUS attributes that are complex structures 

1086# 

1087 

1088 

1089class _EAPPacketField(PacketLenField): 

1090 """ 

1091 Handles EAP-Message attribute value (the actual EAP packet). 

1092 """ 

1093 

1094 def m2i(self, pkt, m): 

1095 ret = None 

1096 eap_packet_len = struct.unpack("!H", m[2:4])[0] 

1097 if eap_packet_len < 254: 

1098 # If the EAP packet has not been fragmented, build a Scapy EAP 

1099 # packet from the data. 

1100 ret = EAP(m) 

1101 else: 

1102 ret = conf.raw_layer(m) 

1103 return ret 

1104 

1105 

1106class RadiusAttr_EAP_Message(RadiusAttribute): 

1107 """ 

1108 Implements the "EAP-Message" attribute (RFC 3579). 

1109 """ 

1110 name = "EAP-Message" 

1111 match_subclass = True 

1112 fields_desc = [ 

1113 ByteEnumField("type", 79, _radius_attribute_types), 

1114 FieldLenField( 

1115 "len", 

1116 None, 

1117 "value", 

1118 "B", 

1119 adjust=lambda pkt, x: x + 2 

1120 ), 

1121 _EAPPacketField("value", "", EAP, length_from=lambda p: p.len - 2) 

1122 ] 

1123 

1124 def post_dissect(self, s): 

1125 if not conf.contribs.get("radius", {}).get("auto-defrag", True): 

1126 return s 

1127 if isinstance(self.value, conf.raw_layer): 

1128 # Defragment 

1129 x = s 

1130 buf = self.value.load 

1131 while x and struct.unpack("!B", x[:1])[0] == 79: 

1132 # Let's carefully avoid the infinite loop 

1133 length = struct.unpack("!B", x[1:2])[0] 

1134 if not length: 

1135 return s 

1136 buf, x = buf + x[2:length], x[length:] 

1137 if length < 254: 

1138 self.value = EAP(buf) 

1139 return x 

1140 return s 

1141 

1142 

1143_radius_vendor_types = { 

1144 # Microsoft (RFC 2548) 

1145 311: { 

1146 1: "MS-CHAP-Response", 

1147 2: "MS-CHAP-Error", 

1148 3: "MS-CHAP-CPW-1", 

1149 4: "MS-CHAP-CPW-2", 

1150 5: "MS-CHAP-LM-Enc-PW", 

1151 6: "MS-CHAP-NT-Enc-PW", 

1152 7: "MS-MPPE-Encryption-Policy", 

1153 8: "MS-MPPE-Encryption-Type", 

1154 9: "MS-RAS-Vendor", 

1155 10: "MS-CHAP-Domain", 

1156 11: "MS-CHAP-Challenge", 

1157 12: "MS-CHAP-MPPE-Keys", 

1158 13: "MS-BAP-Usage", 

1159 14: "MS-Link-Utilization-Threshold", 

1160 15: "MS-Link-Drop-Time-Limit", 

1161 16: "MS-MPPE-Send-Key", 

1162 17: "MS-MPPE-Recv-Key", 

1163 18: "MS-RAS-Version", 

1164 19: "MS-Old-ARAP-Password", 

1165 20: "MS-New-ARAP-Password", 

1166 21: "MS-ARAP-PW-Change-Reason", 

1167 22: "MS-Filter", 

1168 23: "MS-Acct-Auth-Type", 

1169 24: "MS-Acct-EAP-Type", 

1170 25: "MS-CHAP2-Response", 

1171 26: "MS-CHAP2-Success", 

1172 27: "MS-CHAP2-CPW", 

1173 28: "MS-Primary-DNS-Server", 

1174 29: "MS-Secondary-DNS-Server", 

1175 30: "MS-Primary-NBNS-Server", 

1176 31: "MS-Secondary-NBNS-Server", 

1177 33: "MS-ARAP-Challenge", 

1178 } 

1179} 

1180 

1181 

1182class _RadiusAttrVendorValue(Packet): 

1183 """ 

1184 Used to register a 'value' vendor-specific 

1185 """ 

1186 registered_vendor_value = collections.defaultdict(dict) 

1187 VENDOR_ID = 0 

1188 VENDOR_TYPE = 0 

1189 

1190 @classmethod 

1191 def register_variant(cls): 

1192 cls.registered_vendor_value[cls.VENDOR_ID][cls.VENDOR_TYPE] = cls 

1193 

1194 

1195def _radius_vendor_cls(pkt): 

1196 """ 

1197 Return the class that makes for a 'value' in the vendor attribute, or None. 

1198 """ 

1199 if pkt.vendor_id not in _RadiusAttrVendorValue.registered_vendor_value: 

1200 return None 

1201 return _RadiusAttrVendorValue.registered_vendor_value[pkt.vendor_id].get( 

1202 pkt.vendor_type, 

1203 None, 

1204 ) 

1205 

1206 

1207class _RadiusVendorValueField(PacketLenField): 

1208 def m2i(self, pkt, s): 

1209 return _radius_vendor_cls(pkt)(s, _parent=pkt) 

1210 

1211 

1212class RadiusAttr_Vendor_Specific(RadiusAttribute): 

1213 """ 

1214 Implements the "Vendor-Specific" attribute, as described in RFC 2865. 

1215 """ 

1216 

1217 name = "Vendor-Specific" 

1218 match_subclass = True 

1219 fields_desc = [ 

1220 ByteEnumField("type", 26, _radius_attribute_types), 

1221 FieldLenField( 

1222 "len", 

1223 None, 

1224 "value", 

1225 "B", 

1226 adjust=lambda pkt, x: len(pkt.value) + 8 

1227 ), 

1228 IntEnumField("vendor_id", 0, { 

1229 311: "Microsoft", 

1230 }), 

1231 MultiEnumField( 

1232 "vendor_type", 

1233 0, 

1234 _radius_vendor_types, 

1235 depends_on=lambda p: p.vendor_id, 

1236 fmt="B" 

1237 ), 

1238 FieldLenField( 

1239 "vendor_len", 

1240 None, 

1241 "value", 

1242 "B", 

1243 adjust=lambda p, x: len(p.value) + 2 

1244 ), 

1245 MultipleTypeField( 

1246 [ 

1247 ( 

1248 _RadiusVendorValueField("value", None, None, 

1249 length_from=lambda p: p.vendor_len - 2), 

1250 lambda pkt: _radius_vendor_cls(pkt) is not None 

1251 ) 

1252 ], 

1253 StrLenField("value", "", length_from=lambda p: p.vendor_len - 2), 

1254 ) 

1255 ] 

1256 

1257 

1258# See IANA RADIUS Packet Type Codes registry 

1259_packet_codes = { 

1260 1: "Access-Request", 

1261 2: "Access-Accept", 

1262 3: "Access-Reject", 

1263 4: "Accounting-Request", 

1264 5: "Accounting-Response", 

1265 6: "Accounting-Status (now Interim Accounting)", 

1266 7: "Password-Request", 

1267 8: "Password-Ack", 

1268 9: "Password-Reject", 

1269 10: "Accounting-Message", 

1270 11: "Access-Challenge", 

1271 12: "Status-Server (experimental)", 

1272 13: "Status-Client (experimental)", 

1273 21: "Resource-Free-Request", 

1274 22: "Resource-Free-Response", 

1275 23: "Resource-Query-Request", 

1276 24: "Resource-Query-Response", 

1277 25: "Alternate-Resource-Reclaim-Request", 

1278 26: "NAS-Reboot-Request", 

1279 27: "NAS-Reboot-Response", 

1280 28: "Reserved", 

1281 29: "Next-Passcode", 

1282 30: "New-Pin", 

1283 31: "Terminate-Session", 

1284 32: "Password-Expired", 

1285 33: "Event-Request", 

1286 34: "Event-Response", 

1287 40: "Disconnect-Request", 

1288 41: "Disconnect-ACK", 

1289 42: "Disconnect-NAK", 

1290 43: "CoA-Request", 

1291 44: "CoA-ACK", 

1292 45: "CoA-NAK", 

1293 50: "IP-Address-Allocate", 

1294 51: "IP-Address-Release", 

1295 52: "Protocol-Error", 

1296 250: "Experimental Use", 

1297 251: "Experimental Use", 

1298 252: "Experimental Use", 

1299 253: "Experimental Use", 

1300 254: "Reserved", 

1301 255: "Reserved" 

1302} 

1303 

1304 

1305class Radius(Packet): 

1306 """ 

1307 Implements a RADIUS packet (RFC 2865). 

1308 """ 

1309 

1310 name = "RADIUS" 

1311 fields_desc = [ 

1312 ByteEnumField("code", 1, _packet_codes), 

1313 ByteField("id", 0), 

1314 FieldLenField( 

1315 "len", 

1316 None, 

1317 "attributes", 

1318 "H", 

1319 adjust=lambda pkt, x: len(pkt.attributes) + 20 

1320 ), 

1321 XStrFixedLenField("authenticator", "", 16), 

1322 PacketListField( 

1323 "attributes", 

1324 [], 

1325 RadiusAttribute, 

1326 length_from=lambda pkt: pkt.len - 20 

1327 ) 

1328 ] 

1329 

1330 def compute_authenticator(self, packed_request_auth, shared_secret): 

1331 """ 

1332 Computes the authenticator field (RFC 2865 - Section 3) 

1333 """ 

1334 

1335 data = prepare_packed_data(self, packed_request_auth) 

1336 radius_mac = hashlib.md5(data + shared_secret) 

1337 return radius_mac.digest() 

1338 

1339 def post_build(self, p, pay): 

1340 p += pay 

1341 length = self.len 

1342 if length is None: 

1343 length = len(p) 

1344 p = p[:2] + struct.pack("!H", length) + p[4:] 

1345 return p 

1346 

1347 def mysummary(self): 

1348 extra = "" 

1349 if self.code == 1: 

1350 # Access-Request 

1351 attrs = { 

1352 ( 

1353 (x.vendor_id, x.vendor_type) 

1354 if RadiusAttr_Vendor_Specific in x else 

1355 x.type 

1356 ): x 

1357 for x in self.attributes 

1358 if isinstance(x, RadiusAttribute) 

1359 } 

1360 # Log additional attributes 

1361 if 1 in attrs: 

1362 extra += "User:'%s' " % attrs[1].value.decode(errors="ignore") 

1363 # Try to detect the logon algo 

1364 if 2 in attrs: 

1365 extra += "PAP" 

1366 elif 3 in attrs: 

1367 extra += "CHAP" 

1368 elif 79 in attrs: 

1369 extra += "EAP" 

1370 elif (311, 1) in attrs: 

1371 extra += "MS-CHAP" 

1372 elif (311, 25) in attrs: 

1373 extra += "MS-CHAP2" 

1374 if extra: 

1375 extra = " (%s)" % extra.strip() 

1376 return self.sprintf("RADIUS %code%") + extra 

1377 

1378 

1379bind_bottom_up(UDP, Radius, sport=1812) 

1380bind_bottom_up(UDP, Radius, dport=1812) 

1381bind_bottom_up(UDP, Radius, sport=1813) 

1382bind_bottom_up(UDP, Radius, dport=1813) 

1383bind_bottom_up(UDP, Radius, sport=3799) 

1384bind_bottom_up(UDP, Radius, dport=3799) 

1385bind_layers(UDP, Radius, sport=1812, dport=1812) 

1386 

1387 

1388# MS-CHAP2 

1389 

1390# RFC 2548 sect 2.3.2 

1391 

1392class MS_CHAP2_Response(_RadiusAttrVendorValue): 

1393 VENDOR_ID = 311 

1394 VENDOR_TYPE = 25 

1395 fields_desc = [ 

1396 ByteField("Ident", 0), 

1397 ByteField("Flags", 0), 

1398 XStrFixedLenField("PeerChallenge", b"", length=16), 

1399 XStrFixedLenField("Reserved", b"", length=8), 

1400 XStrFixedLenField("Response", b"", length=24), 

1401 ] 

1402 

1403 

1404# RFC 2548 sect 2.3.3 

1405 

1406class MS_CHAP2_Success(_RadiusAttrVendorValue): 

1407 VENDOR_ID = 311 

1408 VENDOR_TYPE = 26 

1409 fields_desc = [ 

1410 ByteField("Ident", 0), 

1411 StrFixedLenField("String", b"", length=42), 

1412 ] 

1413 

1414 

1415# RFC 2548 sect 2.1.5 

1416 

1417class MS_CHAP_Error(_RadiusAttrVendorValue): 

1418 VENDOR_ID = 311 

1419 VENDOR_TYPE = 2 

1420 fields_desc = [ 

1421 ByteField("Ident", 0), 

1422 StrField("String", b""), 

1423 ] 

1424 

1425 

1426# RFC 2548 sect 2.1.4 

1427 

1428class MS_CHAP_Domain(_RadiusAttrVendorValue): 

1429 VENDOR_ID = 311 

1430 VENDOR_TYPE = 10 

1431 fields_desc = [ 

1432 ByteField("Ident", 0), 

1433 StrField("String", b""), 

1434 ] 

1435 

1436 

1437def MS_CHAP2_GenerateNTResponse(AuthenticatorChallenge, PeerChallenge, 

1438 UserName, HashNT): 

1439 """ 

1440 RFC2759 sect 8.1 

1441 """ 

1442 Challenge = MS_CHAP2_ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName) 

1443 PasswordHash = HashNT 

1444 return MS_CHAP2_ChallengeResponse(Challenge, PasswordHash) 

1445 

1446 

1447def MS_CHAP2_ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName): 

1448 """ 

1449 rfc 2759 sect 8.2 

1450 """ 

1451 UserName = UserName.split(b"\\")[-1] # Strip domain if present 

1452 return Hash_SHA().digest(PeerChallenge + AuthenticatorChallenge + UserName)[:8] 

1453 

1454 

1455def MS_CHAP2_ChallengeResponse(Challenge, PasswordHash): 

1456 """ 

1457 rfc 2759 sect 8.5 

1458 """ 

1459 ZPasswordHash = int.from_bytes( 

1460 PasswordHash + b"\x00" * (-len(PasswordHash) % 21), 

1461 "big", 

1462 ) 

1463 

1464 # Add !FAKE! DES parity bits because cryptography requires them (then drops them) 

1465 ZPasswordHashParity = b"" 

1466 for _ in range(24): 

1467 val, ZPasswordHash = (ZPasswordHash & 0x7F), (ZPasswordHash >> 7) 

1468 ZPasswordHashParity = struct.pack("B", val << 1) + ZPasswordHashParity 

1469 

1470 return ( 

1471 Cipher_DES_ECB(ZPasswordHashParity[0:8]).encrypt(Challenge) + 

1472 Cipher_DES_ECB(ZPasswordHashParity[8:16]).encrypt(Challenge) + 

1473 Cipher_DES_ECB(ZPasswordHashParity[16:24]).encrypt(Challenge) 

1474 ) 

1475 

1476 

1477def MS_CHAP2_GenerateAuthenticatorResponse(HashNT, 

1478 NTResponse, 

1479 PeerChallenge, 

1480 AuthenticatorChallenge, 

1481 UserName): 

1482 """ 

1483 rfc 2759 sect 8.7 

1484 """ 

1485 Magic1 = bytes(bytearray([ 

1486 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 

1487 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 

1488 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 

1489 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 

1490 ])) 

1491 Magic2 = bytes(bytearray([ 

1492 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 

1493 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 

1494 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 

1495 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 

1496 0x6E 

1497 ])) 

1498 PasswordHash = HashNT 

1499 PasswordHashHash = Hash_MD4().digest(PasswordHash) 

1500 

1501 Digest = Hash_SHA().digest(PasswordHashHash + NTResponse + Magic1) 

1502 

1503 Challenge = MS_CHAP2_ChallengeHash( 

1504 PeerChallenge, 

1505 AuthenticatorChallenge, 

1506 UserName, 

1507 ) 

1508 

1509 return Hash_SHA().digest(Digest + Challenge + Magic2) 

1510 

1511 

1512# Answering machine 

1513 

1514class RadiusAuthType(enum.Enum): 

1515 MS_CHAP_V2 = enum.auto() 

1516 EAP = enum.auto() 

1517 

1518 

1519@crypto_validator 

1520class Radius_am(AnsweringMachine): 

1521 function_name = "radiusd" 

1522 filter = "udp and port 1812" 

1523 send_function = staticmethod(send) 

1524 send_options_list = ["inter", "verbose"] 

1525 

1526 def parse_options(self, 

1527 secret, 

1528 IDENTITIES=None, 

1529 IDENTITIES_MSCHAPv2=None, 

1530 servicetype=None, 

1531 mschapdomain=None, 

1532 extra_attributes=[]): 

1533 """ 

1534 This provides a tiny RADIUS daemon that answers Access-Request messages. 

1535 This can be used while setting up a Cisco switch for instance. 

1536 

1537 Demo:: 

1538 

1539 >>> radiusd(secret="SECRET", iface="lo", IDENTITIES={"user": "password"}) 

1540 $ echo "Message-Authenticator=0x00,User-Name=user,\\ 

1541 User-Password=password" | radclient -P udp 127.0.0.1 auth -F SECRET 

1542 

1543 :param secret: the server's secret 

1544 :param IDENTITIES: the identities in format {"username": b"password"} 

1545 :param IDENTITIES_MSCHAPv2: the MsCHAPv2 identities in format 

1546 {"username": b"HashNT"}. The HashNT can be obtained 

1547 using MD4le(). If IDENTITIES is provided, this will be calculated. 

1548 :param servicetype: the Service-Type to answer. 

1549 :param mschapdomain: the MS-CHAP-DOMAIN to answer if MS-CHAP* is used. 

1550 :param extra_attributes: a list of extra Radius attributes 

1551 """ 

1552 self.secret = bytes_encode(secret) 

1553 self.servicetype = servicetype 

1554 self.mschapdomain = mschapdomain 

1555 self.extra_attributes = extra_attributes 

1556 if not IDENTITIES: 

1557 IDENTITIES = {} 

1558 if IDENTITIES_MSCHAPv2 is None and IDENTITIES: 

1559 IDENTITIES_MSCHAPv2 = { 

1560 user: MD4le(pwd) 

1561 for user, pwd in IDENTITIES.items() 

1562 } 

1563 self.IDENTITIES = { 

1564 user: bytes_encode(pwd) 

1565 for user, pwd in IDENTITIES.items() 

1566 } 

1567 self.IDENTITIES_MSCHAPv2 = IDENTITIES_MSCHAPv2 

1568 

1569 def is_request(self, req): 

1570 # Only match Access-Request 

1571 return Radius in req and req[Radius].code == 1 

1572 

1573 def print_reply(self, req, reply): 

1574 print("%s / %s -> %s" % ( 

1575 reply[IP].dst, 

1576 req[Radius].summary(), 

1577 ( 

1578 conf.color_theme.fail 

1579 if reply.code != 2 else 

1580 conf.color_theme.success 

1581 )(reply.sprintf("%Radius.code%")), 

1582 )) 

1583 

1584 def make_reply(self, req): 

1585 resp = req 

1586 

1587 # Basic response 

1588 resp = ( 

1589 IP(src=req[IP].dst, dst=req[IP].src) / 

1590 UDP(sport=req[UDP].dport, dport=req[UDP].sport) 

1591 ) 

1592 

1593 # Sort attributes for quick access 

1594 attrs = { 

1595 ( 

1596 (x.vendor_id, x.vendor_type) 

1597 if RadiusAttr_Vendor_Specific in x else 

1598 x.type 

1599 ): x 

1600 for x in req.attributes 

1601 } 

1602 

1603 # Build Radius response 

1604 rad = Radius(code=2, id=req[Radius].id) 

1605 

1606 # Process various authentication methods 

1607 try: 

1608 if 2 in attrs: 

1609 # PAP 

1610 if not self.IDENTITIES: 

1611 raise Scapy_Exception( 

1612 "Missing IDENTITIES for User-Password auth ! Assuming OK." 

1613 ) 

1614 

1615 UserName = attrs[1].value 

1616 KnownPassword = self.IDENTITIES.get(UserName.decode(), None) 

1617 UserPassword = attrs[2].decrypt( 

1618 req, 

1619 self.secret, 

1620 ) 

1621 

1622 if KnownPassword is None: 

1623 log_runtime.warning("Couldn't find user '%s'" % UserName.decode()) 

1624 rad.code = 3 

1625 elif UserPassword != KnownPassword: 

1626 log_runtime.warning( 

1627 "Bad password for user '%s'" % UserName.decode() 

1628 ) 

1629 rad.code = 3 

1630 elif 79 in attrs: 

1631 # EAP-Message is used 

1632 raise Scapy_Exception( 

1633 "EAP as a Radius auth method is not implemented !" 

1634 ) 

1635 elif (311, 25) in attrs: 

1636 # MS-CHAP2 

1637 if not self.IDENTITIES_MSCHAPv2: 

1638 raise Scapy_Exception("Missing IDENTITIES_MSCHAPv2 for MsChapV2 !") 

1639 

1640 response = attrs[(311, 25)].value 

1641 try: 

1642 AuthenticatorChallenge = attrs[(311, 11)].value # CHAP-Challenge 

1643 except KeyError: 

1644 raise Scapy_Exception("Missing CHAP-Challenge !") 

1645 

1646 UserName = attrs[1].value 

1647 HashNT = self.IDENTITIES_MSCHAPv2.get(UserName.decode(), None) 

1648 

1649 # 1. Check the client-provided NTResponse 

1650 if HashNT is None: 

1651 log_runtime.warning("Couldn't find user '%s'" % UserName.decode()) 

1652 rad.code = 3 

1653 elif MS_CHAP2_GenerateNTResponse( 

1654 AuthenticatorChallenge, 

1655 response.PeerChallenge, 

1656 UserName, 

1657 HashNT) != response.Response: 

1658 log_runtime.warning( 

1659 "Bad MS-CHAP2-NTResponse for user '%s' !" % UserName.decode() 

1660 ) 

1661 rad.code = 3 

1662 

1663 # Did the auth failed? 

1664 if rad.code == 3: 

1665 rad.attributes.append( 

1666 RadiusAttr_Vendor_Specific( 

1667 vendor_id="Microsoft", 

1668 vendor_type=2, 

1669 value=MS_CHAP_Error( 

1670 Ident=response.Ident, 

1671 String="E=691 R=0 V=3", 

1672 ), 

1673 ) 

1674 ) 

1675 else: 

1676 # 2. Build the response 'success' response 

1677 auth_string = MS_CHAP2_GenerateAuthenticatorResponse( 

1678 HashNT, 

1679 response.Response, 

1680 response.PeerChallenge, 

1681 AuthenticatorChallenge, 

1682 UserName, 

1683 ) 

1684 rad.attributes.append( 

1685 RadiusAttr_Vendor_Specific( 

1686 vendor_id=311, 

1687 vendor_type="MS-CHAP2-Success", 

1688 value=MS_CHAP2_Success( 

1689 Ident=response.Ident, 

1690 String="S=%s" % auth_string.hex().upper() 

1691 ) 

1692 ) 

1693 ) 

1694 if self.mschapdomain is not None: 

1695 rad.attributes.append( 

1696 RadiusAttr_Vendor_Specific( 

1697 vendor_id=311, 

1698 vendor_type="MS-CHAP-Domain", 

1699 value=MS_CHAP_Domain( 

1700 Ident=response.Ident, 

1701 String=self.mschapdomain, 

1702 ) 

1703 ) 

1704 ) 

1705 else: 

1706 raise Scapy_Exception( 

1707 "Authentication method not provided or unsupported !" 

1708 ) 

1709 except Scapy_Exception as ex: 

1710 # display a warning 

1711 log_runtime.warning(str(ex)) 

1712 

1713 # Add additional records if it's an accept 

1714 if rad.code == 2: 

1715 if self.servicetype is not None: 

1716 rad.attributes.append( 

1717 RadiusAttr_Service_Type(value=self.servicetype) 

1718 ) 

1719 

1720 rad.attributes.extend(self.extra_attributes) 

1721 

1722 # Add and compute message authenticator 

1723 mauth = RadiusAttr_Message_Authenticator() 

1724 rad.attributes.insert(0, mauth) 

1725 mauth.value = mauth.compute_message_authenticator( 

1726 rad, 

1727 req.authenticator, 

1728 self.secret, 

1729 ) 

1730 

1731 # Add global authenticator 

1732 rad.authenticator = rad.compute_authenticator(req.authenticator, self.secret) 

1733 

1734 # Final packet 

1735 return resp / rad