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.
Topology and requirements
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.pcap - this is packet capture for EAPOL session between supplicant and network access device (NAD)
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)
eap-ssl.pcap - this is modified eap.pcap which chooses only SSL packets
ssl.pcap - this is result of my perl script dump.pl
dump.pl - my perl script extracting SSL streams from any packets and putting it into TCP session which is easy for wireshark to decrypt
perl_libs.tar.gz - bunch of publicly available perl libraries used (one of them patched by me)
EAP-PEAP - phase1 packet by packet
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.
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.
EAP-PEAP - phase2 packet by packet
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.
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:
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:
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.
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.
Dump.pl script details
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's universal, might be used to grab SSL from other protocols
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.
Disclaimer: I can not take any responsibility for that script. Please use it at your own risk.