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

422 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_Event_Timestamp(_RadiusAttrIntValue): 

439 """RFC 2869""" 

440 val = 55 

441 

442 

443class RadiusAttr_Egress_VLANID(_RadiusAttrIntValue): 

444 """RFC 4675""" 

445 val = 56 

446 

447 

448class RadiusAttr_Port_Limit(_RadiusAttrIntValue): 

449 """RFC 2865""" 

450 val = 62 

451 

452 

453class RadiusAttr_ARAP_Security(_RadiusAttrIntValue): 

454 """RFC 2869""" 

455 val = 73 

456 

457 

458class RadiusAttr_Password_Retry(_RadiusAttrIntValue): 

459 """RFC 2869""" 

460 val = 75 

461 

462 

463class RadiusAttr_Tunnel_Preference(_RadiusAttrIntValue): 

464 """RFC 2868""" 

465 val = 83 

466 

467 

468class RadiusAttr_Acct_Interim_Interval(_RadiusAttrIntValue): 

469 """RFC 2869""" 

470 val = 85 

471 

472 

473class RadiusAttr_Acct_Tunnel_Packets_Lost(_RadiusAttrIntValue): 

474 """RFC 2867""" 

475 val = 86 

476 

477 

478class RadiusAttr_Management_Privilege_Level(_RadiusAttrIntValue): 

479 """RFC 5607""" 

480 val = 136 

481 

482 

483class RadiusAttr_Mobility_Domain_Id(_RadiusAttrIntValue): 

484 """RFC 7268""" 

485 val = 177 

486 

487 

488class RadiusAttr_Preauth_Timeout(_RadiusAttrIntValue): 

489 """RFC 7268""" 

490 val = 178 

491 

492 

493class RadiusAttr_WLAN_Venue_Info(_RadiusAttrIntValue): 

494 """RFC 7268""" 

495 val = 182 

496 

497 

498class RadiusAttr_WLAN_Reason_Code(_RadiusAttrIntValue): 

499 """RFC 7268""" 

500 val = 185 

501 

502 

503class RadiusAttr_WLAN_Pairwise_Cipher(_RadiusAttrIntValue): 

504 """RFC 7268""" 

505 val = 186 

506 

507 

508class RadiusAttr_WLAN_Group_Cipher(_RadiusAttrIntValue): 

509 """RFC 7268""" 

510 val = 187 

511 

512 

513class RadiusAttr_WLAN_AKM_Suite(_RadiusAttrIntValue): 

514 """RFC 7268""" 

515 val = 188 

516 

517 

518class RadiusAttr_WLAN_Group_Mgmt_Cipher(_RadiusAttrIntValue): 

519 """RFC 7268""" 

520 val = 189 

521 

522 

523class RadiusAttr_WLAN_RF_Band(_RadiusAttrIntValue): 

524 """RFC 7268""" 

525 val = 190 

526 

527 

528# 

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

530# 

531 

532class _RadiusAttrHexStringVal(_SpecificRadiusAttr): 

533 """ 

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

535 as a hex string. 

536 """ 

537 

538 __slots__ = ["val"] 

539 

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

541 super(_RadiusAttrHexStringVal, self).__init__( 

542 _pkt, 

543 post_transform, 

544 _internal, 

545 _underlayer, 

546 **fields 

547 ) 

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

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

550 if len(name_parts) < 2: 

551 raise Scapy_Exception( 

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

553 ) 

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

555 

556 fields_desc = [ 

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

558 FieldLenField( 

559 "len", 

560 None, 

561 "value", 

562 "B", 

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

564 ), 

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

566 ] 

567 

568 

569class RadiusAttr_User_Password(_RadiusAttrHexStringVal): 

570 """RFC 2865""" 

571 val = 2 

572 

573 def decrypt(self, radius_packet, secret): 

574 """ 

575 Return the decrypted value of the User-Password field 

576 RFC2865 sect 5.2 

577 """ 

578 password = b"" 

579 

580 encrypted = self.value 

581 ci = radius_packet.authenticator 

582 while encrypted: 

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

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

585 password += strxor(ci, bi) 

586 

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

588 

589 @staticmethod 

590 def encrypt(radius_packet, password, secret): 

591 """ 

592 Create a User-Password attribute from a secret 

593 RFC2865 sect 5.2 

594 """ 

595 password = bytes_encode(password) 

596 

597 # Pad to 16 octets boundary 

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

599 

600 encrypted = b"" 

601 ci = radius_packet.authenticator 

602 while password: 

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

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

605 password = password[16:] 

606 

607 return RadiusAttr_User_Password(value=encrypted) 

608 

609 

610class RadiusAttr_State(_RadiusAttrHexStringVal): 

611 """RFC 2865""" 

612 val = 24 

613 

614 

615def prepare_packed_data(radius_packet, RequestAuth): 

616 """ 

617 Pack RADIUS data prior computing the authentication MAC 

618 """ 

619 s = bytes(radius_packet) 

620 Code_Id_Length = s[:4] 

621 Attributes = s[4 + 16:] 

622 return Code_Id_Length + RequestAuth + Attributes 

623 

624 

625class RadiusAttr_Message_Authenticator(_RadiusAttrHexStringVal): 

626 """RFC 2869""" 

627 val = 80 

628 

629 fields_desc = [ 

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

631 FieldLenField( 

632 "len", 

633 18, 

634 "value", 

635 "B", 

636 ), 

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

638 ] 

639 

640 @staticmethod 

641 def compute_message_authenticator(radius_packet, packed_req_authenticator, 

642 shared_secret): 

643 """ 

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

645 (RFC 2869 - Page 33) 

646 """ 

647 

648 # Make sure the current auth is empty 

649 attr = radius_packet[RadiusAttr_Message_Authenticator] 

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

651 

652 data = prepare_packed_data(radius_packet, packed_req_authenticator) 

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

654 

655 return radius_hmac.digest() 

656 

657# 

658# RADIUS attributes which values are IPv4 prefixes 

659# 

660 

661 

662class _RadiusAttrIPv4AddrVal(_SpecificRadiusAttr): 

663 """ 

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

665 """ 

666 

667 __slots__ = ["val"] 

668 

669 fields_desc = [ 

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

671 ByteField("len", 6), 

672 IPField("value", "0.0.0.0") 

673 ] 

674 

675 

676class RadiusAttr_NAS_IP_Address(_RadiusAttrIPv4AddrVal): 

677 """RFC 2865""" 

678 val = 4 

679 

680 

681class RadiusAttr_Framed_IP_Address(_RadiusAttrIPv4AddrVal): 

682 """RFC 2865""" 

683 val = 8 

684 

685 

686class RadiusAttr_Framed_IP_Netmask(_RadiusAttrIPv4AddrVal): 

687 """RFC 2865""" 

688 val = 9 

689 

690 

691class RadiusAttr_Login_IP_Host(_RadiusAttrIPv4AddrVal): 

692 """RFC 2865""" 

693 val = 14 

694 

695 

696class RadiusAttr_Framed_IPX_Network(_RadiusAttrIPv4AddrVal): 

697 """RFC 2865""" 

698 val = 23 

699 

700 

701class RadiusAttr_PMIP6_Home_LMA_IPv4_Address(_RadiusAttrIPv4AddrVal): 

702 """RFC 6572""" 

703 val = 149 

704 

705 

706class RadiusAttr_PMIP6_Visited_LMA_IPv4_Address(_RadiusAttrIPv4AddrVal): 

707 """RFC 6572""" 

708 val = 150 

709 

710 

711class RadiusAttr_PMIP6_Home_DHCP4_Server_Address(_RadiusAttrIPv4AddrVal): 

712 """RFC 6572""" 

713 val = 157 

714 

715 

716class RadiusAttr_PMIP6_Visited_DHCP4_Server_Address(_RadiusAttrIPv4AddrVal): 

717 """RFC 6572""" 

718 val = 158 

719 

720 

721class RadiusAttr_PMIP6_Home_IPv4_Gateway(_RadiusAttrIPv4AddrVal): 

722 """RFC 6572""" 

723 val = 161 

724 

725 

726class RadiusAttr_PMIP6_Visited_IPv4_Gateway(_RadiusAttrIPv4AddrVal): 

727 """RFC 6572""" 

728 val = 162 

729 

730 

731# See IANA registry "RADIUS Types" 

732_radius_attrs_values = { 

733 # Service-Type 

734 6: 

735 { 

736 1: "Login", 

737 2: "Framed", 

738 3: "Callback Login", 

739 4: "Callback Framed", 

740 5: "Outbound", 

741 6: "Administrative", 

742 7: "NAS Prompt", 

743 8: "Authenticate Only", 

744 9: "Callback NAS Prompt", 

745 10: "Call Check", 

746 11: "Callback Administrative", 

747 12: "Voice", 

748 13: "Fax", 

749 14: "Modem Relay", 

750 15: "IAPP-Register", 

751 16: "IAPP-AP-Check", 

752 17: "Authorize Only", 

753 18: "Framed-Management", 

754 19: "Additional-Authorization" 

755 }, 

756 

757 # Framed-Protocol 

758 7: 

759 { 

760 1: "PPP", 

761 2: "SLIP", 

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

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

764 5: "Xylogics proprietary IPX/SLIP", 

765 6: "X.75 Synchronous", 

766 7: "GPRS PDP Context" 

767 }, 

768 

769 # Framed-Routing 

770 10: 

771 { 

772 0: "None", 

773 1: "Send routing packets", 

774 2: "Listen for routing packets", 

775 3: "Send and Listen" 

776 }, 

777 

778 # Framed-Compression 

779 13: 

780 { 

781 0: "None", 

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

783 2: "IPX header compression", 

784 3: "Stac-LZS compression" 

785 }, 

786 

787 # Login-Service 

788 15: 

789 { 

790 0: "Telnet", 

791 1: "Rlogin", 

792 2: "TCP Clear", 

793 3: "PortMaster (proprietary)", 

794 4: "LAT", 

795 5: "X25-PAD", 

796 6: "X25-T3POS", 

797 7: "Unassigned", 

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

799 }, 

800 

801 # Termination-Action 

802 29: 

803 { 

804 0: "Default", 

805 1: "RADIUS-Request" 

806 }, 

807 

808 # Acct-Status-Type 

809 40: 

810 { 

811 1: "Start", 

812 2: "Stop", 

813 3: "Interim-Update", 

814 4: "Unassigned", 

815 5: "Unassigned", 

816 6: "Unassigned", 

817 7: "Accounting-On", 

818 8: "Accounting-Off", 

819 9: "Tunnel-Start", 

820 10: "Tunnel-Stop", 

821 11: "Tunnel-Reject", 

822 12: "Tunnel-Link-Start", 

823 13: "Tunnel-Link-Stop", 

824 14: "Tunnel-Link-Reject", 

825 15: "Failed" 

826 }, 

827 

828 # Acct-Authentic 

829 45: 

830 { 

831 1: "RADIUS", 

832 2: "Local", 

833 3: "Remote", 

834 4: "Diameter" 

835 }, 

836 

837 # Acct-Terminate-Cause 

838 49: 

839 { 

840 1: "User Request", 

841 2: "Lost Carrier", 

842 3: "Lost Service", 

843 4: "Idle Timeout", 

844 5: "Session Timeout", 

845 6: "Admin Reset", 

846 7: "Admin Reboot", 

847 8: "Port Error", 

848 9: "NAS Error", 

849 10: "NAS Request", 

850 11: "NAS Reboot", 

851 12: "Port Unneeded", 

852 13: "Port Preempted", 

853 14: "Port Suspended", 

854 15: "Service Unavailable", 

855 16: "Callback", 

856 17: "User Error", 

857 18: "Host Request", 

858 19: "Supplicant Restart", 

859 20: "Reauthentication Failure", 

860 21: "Port Reinitialized", 

861 22: "Port Administratively Disabled", 

862 23: "Lost Power", 

863 }, 

864 

865 # NAS-Port-Type 

866 61: 

867 { 

868 0: "Async", 

869 1: "Sync", 

870 2: "ISDN Sync", 

871 3: "ISDN Async V.120", 

872 4: "ISDN Async V.110", 

873 5: "Virtual", 

874 6: "PIAFS", 

875 7: "HDLC Clear Channel", 

876 8: "X.25", 

877 9: "X.75", 

878 10: "G.3 Fax", 

879 11: "SDSL - Symmetric DSL", 

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

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

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

883 15: "Ethernet", 

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

885 17: "Cable", 

886 18: "Wireles - Other", 

887 19: "Wireless - IEEE 802.11", 

888 20: "Token-Ring", 

889 21: "FDDI", 

890 22: "Wireless - CDMA2000", 

891 23: "Wireless - UMTS", 

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

893 25: "IAPP", 

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

895 27: "Wireless - IEEE 802.16", 

896 28: "Wireless - IEEE 802.20", 

897 29: "Wireless - IEEE 802.22", 

898 30: "PPPoA - PPP over ATM", 

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

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

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

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

903 35: "xPON - Passive Optical Network", 

904 36: "Wireless - XGP", 

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

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

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

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

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

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

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

912 }, 

913 

914 # Tunnel-Type 

915 64: 

916 { 

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

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

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

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

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

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

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

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

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

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

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

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

929 13: "Virtual LANs (VLAN)" 

930 }, 

931 

932 # Tunnel-Medium-Type 

933 65: 

934 { 

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

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

937 3: "NSAP", 

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

939 5: "BBN 1822", 

940 6: "802", 

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

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

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

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

945 11: "IPX", 

946 12: "Appletalk", 

947 13: "Decnet IV", 

948 14: "Banyan Vine", 

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

950 }, 

951 

952 # ARAP-Zone-Access 

953 72: 

954 { 

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

956 2: "Use zone filter inclusively", 

957 3: "Not used", 

958 4: "Use zone filter exclusively" 

959 }, 

960 

961 # Prompt 

962 76: 

963 { 

964 0: "No Echo", 

965 1: "Echo" 

966 }, 

967 

968 # Error-Cause Attribute 

969 101: 

970 { 

971 201: "Residual Session Context Removed", 

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

973 401: "Unsupported Attribute", 

974 402: "Missing Attribute", 

975 403: "NAS Identification Mismatch", 

976 404: "Invalid Request", 

977 405: "Unsupported Service", 

978 406: "Unsupported Extension", 

979 407: "Invalid Attribute Value", 

980 501: "Administratively Prohibited", 

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

982 503: "Session Context Not Found", 

983 504: "Session Context Not Removable", 

984 505: "Other Proxy Processing Error", 

985 506: "Resources Unavailable", 

986 507: "Request Initiated", 

987 508: "Multiple Session Selection Unsupported", 

988 509: "Location-Info-Required", 

989 601: "Response Too Big" 

990 }, 

991 

992 # Operator Namespace Identifier - Attribute 126 

993 126: 

994 { 

995 0x30: "TADIG", 

996 0x31: "REALM", 

997 0x32: "E212", 

998 0x33: "ICC", 

999 0xFF: "Reserved" 

1000 }, 

1001 

1002 # Basic-Location-Policy-Rules 

1003 129: 

1004 { 

1005 0: "Retransmission allowed", 

1006 }, 

1007 

1008 # Location-Capable 

1009 131: 

1010 { 

1011 1: "CIVIC_LOCATION", 

1012 2: "GEO_LOCATION", 

1013 4: "USERS_LOCATION", 

1014 8: "NAS_LOCATION" 

1015 }, 

1016 

1017 # Framed-Management-Protocol 

1018 133: 

1019 { 

1020 1: "SNMP", 

1021 2: "Web-based", 

1022 3: "NETCONF", 

1023 4: "FTP", 

1024 5: "TFTP", 

1025 6: "SFTP", 

1026 7: "RCP", 

1027 8: "SCP" 

1028 }, 

1029 

1030 # Management-Transport-Protection 

1031 134: 

1032 { 

1033 1: "No-Protection", 

1034 2: "Integrity-Protection", 

1035 3: "Integrity-Confidentiality-Protection", 

1036 }, 

1037} 

1038 

1039 

1040class _RadiusAttrIntEnumVal(_SpecificRadiusAttr): 

1041 """ 

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

1043 """ 

1044 

1045 __slots__ = ["val"] 

1046 

1047 fields_desc = [ 

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

1049 ByteField("len", 6), 

1050 MultiEnumField( 

1051 "value", 

1052 0, 

1053 _radius_attrs_values, 

1054 depends_on=lambda p: p.type, 

1055 fmt="I" 

1056 ) 

1057 ] 

1058 

1059 

1060class RadiusAttr_Service_Type(_RadiusAttrIntEnumVal): 

1061 """RFC 2865""" 

1062 val = 6 

1063 

1064 

1065class RadiusAttr_Framed_Protocol(_RadiusAttrIntEnumVal): 

1066 """RFC 2865""" 

1067 val = 7 

1068 

1069 

1070class RadiusAttr_Acct_Status_Type(_RadiusAttrIntEnumVal): 

1071 """RFC 2866""" 

1072 val = 40 

1073 

1074 

1075class RadiusAttr_Acct_Authentic(_RadiusAttrIntEnumVal): 

1076 """RFC 2866""" 

1077 val = 45 

1078 

1079 

1080class RadiusAttr_Acct_Terminate_Cause(_RadiusAttrIntEnumVal): 

1081 """RFC 2866""" 

1082 val = 49 

1083 

1084 

1085class RadiusAttr_NAS_Port_Type(_RadiusAttrIntEnumVal): 

1086 """RFC 2865""" 

1087 val = 61 

1088 

1089# 

1090# RADIUS attributes that are complex structures 

1091# 

1092 

1093 

1094class _EAPPacketField(PacketLenField): 

1095 """ 

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

1097 """ 

1098 

1099 def m2i(self, pkt, m): 

1100 ret = None 

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

1102 if eap_packet_len < 254: 

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

1104 # packet from the data. 

1105 ret = EAP(m) 

1106 else: 

1107 ret = conf.raw_layer(m) 

1108 return ret 

1109 

1110 

1111class RadiusAttr_EAP_Message(RadiusAttribute): 

1112 """ 

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

1114 """ 

1115 name = "EAP-Message" 

1116 match_subclass = True 

1117 fields_desc = [ 

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

1119 FieldLenField( 

1120 "len", 

1121 None, 

1122 "value", 

1123 "B", 

1124 adjust=lambda pkt, x: x + 2 

1125 ), 

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

1127 ] 

1128 

1129 def post_dissect(self, s): 

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

1131 return s 

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

1133 # Defragment 

1134 x = s 

1135 buf = self.value.load 

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

1137 # Let's carefully avoid the infinite loop 

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

1139 if not length: 

1140 return s 

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

1142 if length < 254: 

1143 self.value = EAP(buf) 

1144 return x 

1145 return s 

1146 

1147 

1148_radius_vendor_types = { 

1149 # Microsoft (RFC 2548) 

1150 311: { 

1151 1: "MS-CHAP-Response", 

1152 2: "MS-CHAP-Error", 

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

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

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

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

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

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

1159 9: "MS-RAS-Vendor", 

1160 10: "MS-CHAP-Domain", 

1161 11: "MS-CHAP-Challenge", 

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

1163 13: "MS-BAP-Usage", 

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

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

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

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

1168 18: "MS-RAS-Version", 

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

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

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

1172 22: "MS-Filter", 

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

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

1175 25: "MS-CHAP2-Response", 

1176 26: "MS-CHAP2-Success", 

1177 27: "MS-CHAP2-CPW", 

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

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

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

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

1182 33: "MS-ARAP-Challenge", 

1183 } 

1184} 

1185 

1186 

1187class _RadiusAttrVendorValue(Packet): 

1188 """ 

1189 Used to register a 'value' vendor-specific 

1190 """ 

1191 registered_vendor_value = collections.defaultdict(dict) 

1192 VENDOR_ID = 0 

1193 VENDOR_TYPE = 0 

1194 

1195 @classmethod 

1196 def register_variant(cls): 

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

1198 

1199 

1200def _radius_vendor_cls(pkt): 

1201 """ 

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

1203 """ 

1204 if pkt.vendor_id not in _RadiusAttrVendorValue.registered_vendor_value: 

1205 return None 

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

1207 pkt.vendor_type, 

1208 None, 

1209 ) 

1210 

1211 

1212class _RadiusVendorValueField(PacketLenField): 

1213 def m2i(self, pkt, s): 

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

1215 

1216 

1217class RadiusAttr_Vendor_Specific(RadiusAttribute): 

1218 """ 

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

1220 """ 

1221 

1222 name = "Vendor-Specific" 

1223 match_subclass = True 

1224 fields_desc = [ 

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

1226 FieldLenField( 

1227 "len", 

1228 None, 

1229 "value", 

1230 "B", 

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

1232 ), 

1233 IntEnumField("vendor_id", 0, { 

1234 311: "Microsoft", 

1235 }), 

1236 MultiEnumField( 

1237 "vendor_type", 

1238 0, 

1239 _radius_vendor_types, 

1240 depends_on=lambda p: p.vendor_id, 

1241 fmt="B" 

1242 ), 

1243 FieldLenField( 

1244 "vendor_len", 

1245 None, 

1246 "value", 

1247 "B", 

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

1249 ), 

1250 MultipleTypeField( 

1251 [ 

1252 ( 

1253 _RadiusVendorValueField("value", None, None, 

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

1255 lambda pkt: _radius_vendor_cls(pkt) is not None 

1256 ) 

1257 ], 

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

1259 ) 

1260 ] 

1261 

1262 

1263# See IANA RADIUS Packet Type Codes registry 

1264_packet_codes = { 

1265 1: "Access-Request", 

1266 2: "Access-Accept", 

1267 3: "Access-Reject", 

1268 4: "Accounting-Request", 

1269 5: "Accounting-Response", 

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

1271 7: "Password-Request", 

1272 8: "Password-Ack", 

1273 9: "Password-Reject", 

1274 10: "Accounting-Message", 

1275 11: "Access-Challenge", 

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

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

1278 21: "Resource-Free-Request", 

1279 22: "Resource-Free-Response", 

1280 23: "Resource-Query-Request", 

1281 24: "Resource-Query-Response", 

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

1283 26: "NAS-Reboot-Request", 

1284 27: "NAS-Reboot-Response", 

1285 28: "Reserved", 

1286 29: "Next-Passcode", 

1287 30: "New-Pin", 

1288 31: "Terminate-Session", 

1289 32: "Password-Expired", 

1290 33: "Event-Request", 

1291 34: "Event-Response", 

1292 40: "Disconnect-Request", 

1293 41: "Disconnect-ACK", 

1294 42: "Disconnect-NAK", 

1295 43: "CoA-Request", 

1296 44: "CoA-ACK", 

1297 45: "CoA-NAK", 

1298 50: "IP-Address-Allocate", 

1299 51: "IP-Address-Release", 

1300 52: "Protocol-Error", 

1301 250: "Experimental Use", 

1302 251: "Experimental Use", 

1303 252: "Experimental Use", 

1304 253: "Experimental Use", 

1305 254: "Reserved", 

1306 255: "Reserved" 

1307} 

1308 

1309 

1310class Radius(Packet): 

1311 """ 

1312 Implements a RADIUS packet (RFC 2865). 

1313 """ 

1314 

1315 name = "RADIUS" 

1316 fields_desc = [ 

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

1318 ByteField("id", 0), 

1319 FieldLenField( 

1320 "len", 

1321 None, 

1322 "attributes", 

1323 "H", 

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

1325 ), 

1326 XStrFixedLenField("authenticator", "", 16), 

1327 PacketListField( 

1328 "attributes", 

1329 [], 

1330 RadiusAttribute, 

1331 length_from=lambda pkt: pkt.len - 20 

1332 ) 

1333 ] 

1334 

1335 def compute_authenticator(self, packed_request_auth, shared_secret): 

1336 """ 

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

1338 """ 

1339 

1340 data = prepare_packed_data(self, packed_request_auth) 

1341 radius_mac = hashlib.md5(data + shared_secret) 

1342 return radius_mac.digest() 

1343 

1344 def post_build(self, p, pay): 

1345 p += pay 

1346 length = self.len 

1347 if length is None: 

1348 length = len(p) 

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

1350 return p 

1351 

1352 def mysummary(self): 

1353 extra = "" 

1354 if self.code == 1: 

1355 # Access-Request 

1356 attrs = { 

1357 ( 

1358 (x.vendor_id, x.vendor_type) 

1359 if RadiusAttr_Vendor_Specific in x else 

1360 x.type 

1361 ): x 

1362 for x in self.attributes 

1363 if isinstance(x, RadiusAttribute) 

1364 } 

1365 # Log additional attributes 

1366 if 1 in attrs: 

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

1368 # Try to detect the logon algo 

1369 if 2 in attrs: 

1370 extra += "PAP" 

1371 elif 3 in attrs: 

1372 extra += "CHAP" 

1373 elif 79 in attrs: 

1374 extra += "EAP" 

1375 elif (311, 1) in attrs: 

1376 extra += "MS-CHAP" 

1377 elif (311, 25) in attrs: 

1378 extra += "MS-CHAP2" 

1379 if extra: 

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

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

1382 

1383 

1384bind_bottom_up(UDP, Radius, sport=1812) 

1385bind_bottom_up(UDP, Radius, dport=1812) 

1386bind_bottom_up(UDP, Radius, sport=1813) 

1387bind_bottom_up(UDP, Radius, dport=1813) 

1388bind_bottom_up(UDP, Radius, sport=3799) 

1389bind_bottom_up(UDP, Radius, dport=3799) 

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

1391 

1392 

1393# MS-CHAP2 

1394 

1395# RFC 2548 sect 2.3.2 

1396 

1397class MS_CHAP2_Response(_RadiusAttrVendorValue): 

1398 VENDOR_ID = 311 

1399 VENDOR_TYPE = 25 

1400 fields_desc = [ 

1401 ByteField("Ident", 0), 

1402 ByteField("Flags", 0), 

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

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

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

1406 ] 

1407 

1408 

1409# RFC 2548 sect 2.3.3 

1410 

1411class MS_CHAP2_Success(_RadiusAttrVendorValue): 

1412 VENDOR_ID = 311 

1413 VENDOR_TYPE = 26 

1414 fields_desc = [ 

1415 ByteField("Ident", 0), 

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

1417 ] 

1418 

1419 

1420# RFC 2548 sect 2.1.5 

1421 

1422class MS_CHAP_Error(_RadiusAttrVendorValue): 

1423 VENDOR_ID = 311 

1424 VENDOR_TYPE = 2 

1425 fields_desc = [ 

1426 ByteField("Ident", 0), 

1427 StrField("String", b""), 

1428 ] 

1429 

1430 

1431# RFC 2548 sect 2.1.4 

1432 

1433class MS_CHAP_Domain(_RadiusAttrVendorValue): 

1434 VENDOR_ID = 311 

1435 VENDOR_TYPE = 10 

1436 fields_desc = [ 

1437 ByteField("Ident", 0), 

1438 StrField("String", b""), 

1439 ] 

1440 

1441 

1442def MS_CHAP2_GenerateNTResponse(AuthenticatorChallenge, PeerChallenge, 

1443 UserName, HashNT): 

1444 """ 

1445 RFC2759 sect 8.1 

1446 """ 

1447 Challenge = MS_CHAP2_ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName) 

1448 PasswordHash = HashNT 

1449 return MS_CHAP2_ChallengeResponse(Challenge, PasswordHash) 

1450 

1451 

1452def MS_CHAP2_ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName): 

1453 """ 

1454 rfc 2759 sect 8.2 

1455 """ 

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

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

1458 

1459 

1460def MS_CHAP2_ChallengeResponse(Challenge, PasswordHash): 

1461 """ 

1462 rfc 2759 sect 8.5 

1463 """ 

1464 ZPasswordHash = int.from_bytes( 

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

1466 "big", 

1467 ) 

1468 

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

1470 ZPasswordHashParity = b"" 

1471 for _ in range(24): 

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

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

1474 

1475 return ( 

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

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

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

1479 ) 

1480 

1481 

1482def MS_CHAP2_GenerateAuthenticatorResponse(HashNT, 

1483 NTResponse, 

1484 PeerChallenge, 

1485 AuthenticatorChallenge, 

1486 UserName): 

1487 """ 

1488 rfc 2759 sect 8.7 

1489 """ 

1490 Magic1 = bytes(bytearray([ 

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

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

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

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

1495 ])) 

1496 Magic2 = bytes(bytearray([ 

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

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

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

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

1501 0x6E 

1502 ])) 

1503 PasswordHash = HashNT 

1504 PasswordHashHash = Hash_MD4().digest(PasswordHash) 

1505 

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

1507 

1508 Challenge = MS_CHAP2_ChallengeHash( 

1509 PeerChallenge, 

1510 AuthenticatorChallenge, 

1511 UserName, 

1512 ) 

1513 

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

1515 

1516 

1517# Answering machine 

1518 

1519class RadiusAuthType(enum.Enum): 

1520 MS_CHAP_V2 = enum.auto() 

1521 EAP = enum.auto() 

1522 

1523 

1524@crypto_validator 

1525class Radius_am(AnsweringMachine): 

1526 function_name = "radiusd" 

1527 filter = "udp and port 1812" 

1528 send_function = staticmethod(send) 

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

1530 

1531 def parse_options(self, 

1532 secret, 

1533 IDENTITIES=None, 

1534 IDENTITIES_MSCHAPv2=None, 

1535 servicetype=None, 

1536 mschapdomain=None, 

1537 extra_attributes=[]): 

1538 """ 

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

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

1541 

1542 Demo:: 

1543 

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

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

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

1547 

1548 :param secret: the server's secret 

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

1550 :param IDENTITIES_MSCHAPv2: the MsCHAPv2 identities in format 

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

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

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

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

1555 :param extra_attributes: a list of extra Radius attributes 

1556 """ 

1557 self.secret = bytes_encode(secret) 

1558 self.servicetype = servicetype 

1559 self.mschapdomain = mschapdomain 

1560 self.extra_attributes = extra_attributes 

1561 if not IDENTITIES: 

1562 IDENTITIES = {} 

1563 if IDENTITIES_MSCHAPv2 is None and IDENTITIES: 

1564 IDENTITIES_MSCHAPv2 = { 

1565 user: MD4le(pwd) 

1566 for user, pwd in IDENTITIES.items() 

1567 } 

1568 self.IDENTITIES = { 

1569 user: bytes_encode(pwd) 

1570 for user, pwd in IDENTITIES.items() 

1571 } 

1572 self.IDENTITIES_MSCHAPv2 = IDENTITIES_MSCHAPv2 

1573 

1574 def is_request(self, req): 

1575 # Only match Access-Request 

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

1577 

1578 def print_reply(self, req, reply): 

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

1580 reply[IP].dst, 

1581 req[Radius].summary(), 

1582 ( 

1583 conf.color_theme.fail 

1584 if reply.code != 2 else 

1585 conf.color_theme.success 

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

1587 )) 

1588 

1589 def make_reply(self, req): 

1590 resp = req 

1591 

1592 # Basic response 

1593 resp = ( 

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

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

1596 ) 

1597 

1598 # Sort attributes for quick access 

1599 attrs = { 

1600 ( 

1601 (x.vendor_id, x.vendor_type) 

1602 if RadiusAttr_Vendor_Specific in x else 

1603 x.type 

1604 ): x 

1605 for x in req.attributes 

1606 } 

1607 

1608 # Build Radius response 

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

1610 

1611 # Process various authentication methods 

1612 try: 

1613 if 2 in attrs: 

1614 # PAP 

1615 if not self.IDENTITIES: 

1616 raise Scapy_Exception( 

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

1618 ) 

1619 

1620 UserName = attrs[1].value 

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

1622 UserPassword = attrs[2].decrypt( 

1623 req, 

1624 self.secret, 

1625 ) 

1626 

1627 if KnownPassword is None: 

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

1629 rad.code = 3 

1630 elif UserPassword != KnownPassword: 

1631 log_runtime.warning( 

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

1633 ) 

1634 rad.code = 3 

1635 elif 79 in attrs: 

1636 # EAP-Message is used 

1637 raise Scapy_Exception( 

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

1639 ) 

1640 elif (311, 25) in attrs: 

1641 # MS-CHAP2 

1642 if not self.IDENTITIES_MSCHAPv2: 

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

1644 

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

1646 try: 

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

1648 except KeyError: 

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

1650 

1651 UserName = attrs[1].value 

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

1653 

1654 # 1. Check the client-provided NTResponse 

1655 if HashNT is None: 

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

1657 rad.code = 3 

1658 elif MS_CHAP2_GenerateNTResponse( 

1659 AuthenticatorChallenge, 

1660 response.PeerChallenge, 

1661 UserName, 

1662 HashNT) != response.Response: 

1663 log_runtime.warning( 

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

1665 ) 

1666 rad.code = 3 

1667 

1668 # Did the auth failed? 

1669 if rad.code == 3: 

1670 rad.attributes.append( 

1671 RadiusAttr_Vendor_Specific( 

1672 vendor_id="Microsoft", 

1673 vendor_type=2, 

1674 value=MS_CHAP_Error( 

1675 Ident=response.Ident, 

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

1677 ), 

1678 ) 

1679 ) 

1680 else: 

1681 # 2. Build the response 'success' response 

1682 auth_string = MS_CHAP2_GenerateAuthenticatorResponse( 

1683 HashNT, 

1684 response.Response, 

1685 response.PeerChallenge, 

1686 AuthenticatorChallenge, 

1687 UserName, 

1688 ) 

1689 rad.attributes.append( 

1690 RadiusAttr_Vendor_Specific( 

1691 vendor_id=311, 

1692 vendor_type="MS-CHAP2-Success", 

1693 value=MS_CHAP2_Success( 

1694 Ident=response.Ident, 

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

1696 ) 

1697 ) 

1698 ) 

1699 if self.mschapdomain is not None: 

1700 rad.attributes.append( 

1701 RadiusAttr_Vendor_Specific( 

1702 vendor_id=311, 

1703 vendor_type="MS-CHAP-Domain", 

1704 value=MS_CHAP_Domain( 

1705 Ident=response.Ident, 

1706 String=self.mschapdomain, 

1707 ) 

1708 ) 

1709 ) 

1710 else: 

1711 raise Scapy_Exception( 

1712 "Authentication method not provided or unsupported !" 

1713 ) 

1714 except Scapy_Exception as ex: 

1715 # display a warning 

1716 log_runtime.warning(str(ex)) 

1717 

1718 # Add additional records if it's an accept 

1719 if rad.code == 2: 

1720 if self.servicetype is not None: 

1721 rad.attributes.append( 

1722 RadiusAttr_Service_Type(value=self.servicetype) 

1723 ) 

1724 

1725 rad.attributes.extend(self.extra_attributes) 

1726 

1727 # Add and compute message authenticator 

1728 mauth = RadiusAttr_Message_Authenticator() 

1729 rad.attributes.insert(0, mauth) 

1730 mauth.value = mauth.compute_message_authenticator( 

1731 rad, 

1732 req.authenticator, 

1733 self.secret, 

1734 ) 

1735 

1736 # Add global authenticator 

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

1738 

1739 # Final packet 

1740 return resp / rad