The aim of the article is to show how EAP-PEAP is used for 802.1x networks. I will also show how to troubleshoot it at the packet level. For the inner method we will use Mschapv2 - which is most common inner method for EAP-PEAP. We will look at phase1 negotiation for EAP-PEAP which is used to establish secure SSL tunnel. That secure tunnel is used to protect phase2 which uses Mschapv2 for peer authentication. I will present a method to decrypt that SSL tunnel and to decode Mschapv2 session.
Some basic knowledge about EAP and SSL is required.
Supplicant (Windows XP SP3) connected via 802.1x to cisco 2960 (NAD – network access device) which uses ACS 5.3 as radius server for authentication (AS – authentication server).
I will base on practical examples and files attached to this post. I will refer to following files:
eap-radius.pcap - the same capture but between network access device and authentication server (AS). This contains EAP encapsulated into Radius. That is just for reference, we will not analyze it (EAP content is the same as eap.pcap)
This part is really simple, there is already a lot of documents on the Internet. So I will not cover this part in details.
Let's focus on eap.pcap.
Authenticator sending EAP Request Identity.
Right now popup appears on Supplicant and user provides username (cisco) and password (cisco). Supplicant is responding with EAP Response with Identity “cisco”. This packet is received on NAD, EAP is decapsulated from EAPOL, encapsulated into Radius and sent to AS. All further communication uses the same transport mechanism. EAP session is built between supplicant and AS.
AS sending EAP Request with Type “EAP-PEAP”
Supplicant sending EAP Response with Type “EAP-PEAP” - which means that method is accepted by supplicant. In the same packet we already SSL payload (Client Hello)
AS responds with SSL Server Hello with it's certificate attached. EAP framework does not support fragmentation, each EAP method need to implement that on it's own. EAP-PEAP supports fragmentation (it's not specified for EAP-PEAP but for EAP-TLS certificate can be up to 16MB in size - RFC5216).
Let's look at packet 5:
We have EAP-Length=1012 (packet 5 length). Then More Fragments = 1. And EAP-TLS-Length=1210 – which is total size of all fragments.
At this stage AS already agrees on SSL cipher suit and send random session id.
Supplicant already has all the information (server certificate, random session id) to generate and encrypt session key using AS public key.
AS acknowledges that and finished SSL session establishment.
SSL tunnel is complete.
Supplicant send empty EAP Reponse with Type “EAP-PEAP” (this is not SSL encrypted packet). This is in accordance to http://tools.ietf.org/html/draft-kamath-pppext-peapv0-00 (Appendix A Examples) to acknowledge SSL tunnel establishment and end of phase1.
If you look for the rest packets in eap.pcap – they are encrypted by SSL. That is used to protect phase2 which is used for Mschapv2 peer authentication.
Except the last packet 18. This is EAP Response with Code 3 (Success). It can be read by NAD to verify that supplicant has been authenticated successfully. But NAD can and usually does read that information from Radius header (Access-Accept Code) along with other Radius authorization attributes.
Can we decrypt that SSL packets easily ? Of course for that we need server private key. It's not always so easy. If you troubleshoot production network it's sometimes easier and more secure to generate and install self signed certificate on AAA server and use that one - just for this process.
It also depends on cipher suits. If DH (Diffie-Hellman) cipher suit is being used we can not, because DH is used to establish secure key in unsecure medium. We would need to get dynamically generated secret values (a,b) from supplicant and AS to decrypt such a session. Of course it's possible but quite difficult to perform.
But if RSA based cipher suit is used – it's much easier. All we need is a private key of server (AS).
Fortunately most AAA servers use RSA ciphers. Let's check default configuration for ACS:
Packet4: Ciphers proposed by client
Packet5: Cipher chosen by server:
So the client propose all types of ciphers but server accept TLS_RSA_WITH_3DES_EDE_CBC_SHA.
We can decrypt it easily then.
Wireshark has the option to decrypt SSL traffic:
But unfortunately it works only for SSL encapsulated in TCP session. It uses TCP/IP headers to track communication (server->client, client->server). And we have SSL encapsulated in EAP in EAPOL. Not even IP layer.
So i wrote perl script (dump.pl) which search for SSL session encapsulated in other protocols. Then it creates dummy TCP session with that SSL payload. Tracking of session is based on L2 (ethernet address)
The output of the script is ssl.pcap file which can be decrypted by wireshark.
More info/details about script at the end of this document.
After we have ssl.pcap it's time to configure wireshark:
# cat ~/.wireshark/preferences | grep ssl
server.pem is base64 encoded unprotected server key, example:
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
Remember to compile wireshark with gnutls and gcrypt support. Gcrypt was not default on my gentoo box and it did not work (read debugs to verify).
Right now – when opening ssl.pcap in wireshark we have SSL payload decrypted.
The bad news is that wireshark does not understand Mschapv2 nor EAP encapsulated Mschapv2.
We need to decode it manually.
At this stage we will continue packet reading. Previously we have finished on packet9 which was not SSL encrypted (we will not see that packet in ssl.pcap). No we will read ssl.pcap file.
This is first SSL payload. It's identity request send from AS:
Supplicant respond with response with identity “cisco”.
This is first surprise. Why we do not see full EAP packet here ?
This is intended for packet 9 and 10. Full EAP packet would need to have type field with specific value (for example Mschapv2 as you will see it later). But at this stage we do not know that. After AS gets client identity it can choose which inner method to use based on that identity - and propose that in packet 11.
Does cisco ACS use that ? No, it can read Radius-IETF User-Name attribute from first Access-Request - then based on that username put that session into specific service. That is controlled in Access Policies / Service Selection Rules, example:
In specific service (POD11_RADIUS) we might have enabled for example just EAP-GTC as inner method for EAP-PEAP - then in packet11 that will be offer send to supplicant:
In our case AS sends Mschapv2 challenge (default setting) . Indeed we can see here the first field is Type as described above. But then we have Identifier, Length, Opcode – as described in: http://tools.ietf.org/html/draft-kamath-pppext-eap-mschapv2-02 (EAP MS-CHAP-v2 Packet Format).
After fixed length value-size we have 16bytes of challenge.
Last we have identity of authentication server (AS) which is “acs” in our scenario.
That type of frame is not consistent with most EAP-PEAP drafts (different order of fields, no code filed). Why ?
The response is found in http://tools.ietf.org/html/draft-kamath-pppext-peapv0-00
The [PEAP] specification requires that EAP packets be tunneled within a TLS channel
in their entirety. However, the Windows XP SP1 implementation of PEAP does not
include an EAP header on packets sent within the TLS channel, except for EAP
Extension packets (Type 33), where the complete header is sent. As a result, for
EAP Types other than 33, the Code, Identifier, and Length fields are not sent,
but rather EAP packets sent within the PEAP tunnel begin with the Type field.
That is also not entirely true, also we are using Windows XP SP3 not SP1. But from now on the first field will be always Type.
If supplicant have a correct password it can create correct response. This packet is pretty similar, but with Opcode=2 (response) and 49 bytes of challenge response which consists of:
16 octets: Peer-Challenge
8 octets: Reserved, must be zero
24 octets: NT-Response
1 octet : Flags
Last part of this packet is Name which represents name of peer's user account name (“cisco”).
AS performs similar computation to count correct response. If it matches with received one it sends Success Request Packet (Opcode=3). Payload of that packet (42 Bytes) is message authenticator. This is used by supplicant for verification.
If supplicant verify message authenticator it sends empty Success Response Packet (Opcode=3). In general this is enough. We are already authenticated.
This is moment when EAP-extension is being used. AS sends Extension Request Packet with Type = 33 (EAP extensions). It has only one mandatory AVP which is ACK result.
(more details in http://tools.ietf.org/html/draft-kamath-pppext-peapv0-00).
Supplicant respond with with the same packet but opcode = 2 (response).
The last 2 packets is the additional step to acknowledge the successful result of authentication.
I wound not expect to see this step for linux/opensource supplicants.
We have several peer identities being sent, all of them can differ:
We also have authentication server identity being send in packet 11 as challenge-request (“acs”)
We also have User-Name AVP in all Access-Requests for Radius which tunnel EAP frames to AS.
This creates some potential misinterpreting and bugs in software.
Moreover we might have multiple identities being send in one EAP session.
According to http://tools.ietf.org/html/draft-josefsson-pppext-eap-tls-eap-06 5.7 (Identify verification):
As a result, PEAP implementations SHOULD NOT attempt to compare the Identities
claimed with Parts 1 and 2 of the PEAP conversation. Similarly, if multiple Identities
are claimed within PEAP Part 2, these SHOULD NOT be compared.
We can see that EAP-PEAP with EAP tunneled Mschapv2 implementation in Microsoft is not clear. It's not event 100% compatible with drafts. Also please notice that drafts are pretty old and are ralated to WindowsXP SP1. Moreover behavior differs between operating system version.
It performs binary search for beginning of SSL session inside other protocols. It might be not always accurate because I did not follow RFC to write it. But it works with all examples I tested.
It uses heavily Net::Frame::Layer libraries. One of them did not worked correctly (newest version) so I added my changes (Frame::Layer:IPv4). Attached working libs to this document.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.