A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 1 | #### Authentication parameters |
Chetan Gaonker | 35cb16f | 2016-03-02 03:05:28 -0800 | [diff] [blame] | 2 | from scapy.all import * |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 3 | from socket import * |
| 4 | from struct import * |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 5 | import sys |
| 6 | from nose.tools import assert_equal, assert_not_equal, assert_raises, assert_true |
| 7 | |
| 8 | USER = "raduser" |
| 9 | PASS = "radpass" |
| 10 | WRONG_USER = "XXXX" |
| 11 | WRONG_PASS = "XXXX" |
| 12 | NO_USER = "" |
| 13 | NO_PASS = "" |
| 14 | DEV = "tap0" |
| 15 | ETHERTYPE_PAE = 0x888e |
| 16 | PAE_GROUP_ADDR = "\xff\xff\xff\xff\xff\xff" |
| 17 | EAPOL_VERSION = 1 |
| 18 | EAPOL_EAPPACKET = 0 |
| 19 | EAPOL_START = 1 |
| 20 | EAPOL_LOGOFF = 2 |
| 21 | EAPOL_KEY = 3 |
| 22 | EAPOL_ASF = 4 |
| 23 | EAP_REQUEST = 1 |
| 24 | EAP_RESPONSE = 2 |
| 25 | EAP_SUCCESS = 3 |
| 26 | EAP_FAILURE = 4 |
| 27 | EAP_TYPE_ID = 1 |
| 28 | EAP_TYPE_MD5 = 4 |
| 29 | EAP_TYPE_MSCHAP = 26 |
| 30 | EAP_TYPE_TLS = 13 |
| 31 | cCertMsg = '\x0b\x00\x00\x03\x00\x00\x00' |
| 32 | TLS_LENGTH_INCLUDED = 0x80 |
| 33 | |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 34 | class EapolPacket(object): |
| 35 | |
| 36 | def __init__(self, intf = 'veth0'): |
| 37 | self.intf = intf |
| 38 | self.s = None |
| 39 | self.max_payload_size = 1600 |
| 40 | |
| 41 | def setup(self): |
| 42 | self.s = socket(AF_PACKET, SOCK_RAW, htons(ETHERTYPE_PAE)) |
| 43 | self.s.bind((self.intf, ETHERTYPE_PAE)) |
| 44 | self.mymac = self.s.getsockname()[4] |
Chetan Gaonker | 35cb16f | 2016-03-02 03:05:28 -0800 | [diff] [blame] | 45 | self.llheader = Ether(dst = PAE_GROUP_ADDR, src = self.mymac, type = ETHERTYPE_PAE) |
Chetan Gaonker | 5b36630 | 2016-03-21 16:18:21 -0700 | [diff] [blame] | 46 | self.recv_sock = L2Socket(iface = self.intf, type = ETHERTYPE_PAE) |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 47 | |
| 48 | def cleanup(self): |
| 49 | if self.s is not None: |
| 50 | self.s.close() |
| 51 | self.s = None |
| 52 | |
| 53 | def eapol(self, req_type, payload=""): |
Chetan Gaonker | 35cb16f | 2016-03-02 03:05:28 -0800 | [diff] [blame] | 54 | return EAPOL(version = EAPOL_VERSION, type = req_type)/payload |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 55 | |
| 56 | def eap(self, code, pkt_id, req_type=0, data=""): |
Chetan Gaonker | 35cb16f | 2016-03-02 03:05:28 -0800 | [diff] [blame] | 57 | return EAP(code = code, id = pkt_id, type = req_type)/data |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 58 | |
| 59 | def eapTLS(self, code, pkt_id, flags = TLS_LENGTH_INCLUDED, data=""): |
| 60 | req_type = EAP_TYPE_TLS |
| 61 | if code in [EAP_SUCCESS, EAP_FAILURE]: |
| 62 | return pack("!BBH", code, pkt_id, 4) |
| 63 | else: |
| 64 | if flags & TLS_LENGTH_INCLUDED: |
| 65 | flags_dlen = pack("!BL", flags, len(data)) |
| 66 | return pack("!BBHB", code, pkt_id, 5+len(flags_dlen)+len(data), req_type) + flags_dlen + data |
| 67 | flags_str = pack("!B", flags) |
| 68 | return pack("!BBHB", code, pkt_id, 5+len(flags_str)+len(data), req_type) + flags_str + data |
| 69 | |
| 70 | def eapol_send(self, eapol_type, eap_payload): |
Chetan Gaonker | 35cb16f | 2016-03-02 03:05:28 -0800 | [diff] [blame] | 71 | return sendp(self.llheader/self.eapol(eapol_type, eap_payload), iface=self.intf) |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 72 | |
| 73 | def eapol_recv(self): |
| 74 | p = self.s.recv(self.max_payload_size)[14:] |
| 75 | vers,pkt_type,eapollen = unpack("!BBH",p[:4]) |
| 76 | print "Version %d, type %d, len %d" %(vers, pkt_type, eapollen) |
| 77 | assert_equal(pkt_type, EAPOL_EAPPACKET) |
| 78 | return p[4:] |
| 79 | |
Chetan Gaonker | 5b36630 | 2016-03-21 16:18:21 -0700 | [diff] [blame] | 80 | def eapol_scapy_recv(self, cb = None, lfilter = None, count = 1): |
| 81 | def eapol_default_cb(pkt): pass |
| 82 | if cb is None: |
| 83 | cb = eapol_default_cb |
| 84 | sniff(prn = cb, lfilter = lfilter, count = count, opened_socket = self.recv_sock) |
| 85 | |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 86 | def eapol_start(self): |
| 87 | eap_payload = self.eap(EAPOL_START, 2) |
| 88 | return self.eapol_send(EAPOL_START, eap_payload) |
| 89 | |
| 90 | def eapol_id_req(self, pkt_id = 0, user = USER): |
| 91 | eap_payload = self.eap(EAP_RESPONSE, pkt_id, EAP_TYPE_ID, user) |
| 92 | return self.eapol_send(EAPOL_EAPPACKET, eap_payload) |
| 93 | |
Chetan Gaonker | 4a25e2b | 2016-03-04 14:45:15 -0800 | [diff] [blame] | 94 | def eap_md5_challenge_recv(self,rad_pwd): |
| 95 | PASS = rad_pwd |
| 96 | print 'Inside EAP MD5 Challenge Exchange' |
| 97 | p = self.s.recv(self.max_payload_size)[14:] |
| 98 | vers,pkt_type,eapollen = unpack("!BBH",p[:4]) |
| 99 | print "EAPOL Version %d, type %d, len %d" %(vers, pkt_type, eapollen) |
| 100 | code, pkt_id, eaplen = unpack("!BBH", p[4:8]) |
| 101 | print "EAP Code %d, id %d, len %d" %(code, pkt_id, eaplen) |
| 102 | assert_equal(code, EAP_REQUEST) |
| 103 | reqtype = unpack("!B", p[8:9])[0] |
| 104 | reqdata = p[9:4+eaplen] |
| 105 | print 'Request type is %d' %(reqtype) |
| 106 | assert_equal(reqtype, EAP_TYPE_MD5) |
| 107 | challenge=pack("!B",pkt_id)+PASS+reqdata[1:] |
| 108 | print "Generating md5 challenge for %s" % challenge |
| 109 | return (challenge,pkt_id) |
| 110 | |
| 111 | def eap_Status(self): |
| 112 | print 'Inside EAP Status' |
| 113 | p = self.s.recv(self.max_payload_size)[14:] |
| 114 | code, id, eaplen = unpack("!BBH", p[4:8]) |
| 115 | return code |
| 116 | |