Showing results for 
Search instead for 
Did you mean: 

EAP-PEAP with Mschapv2: Decrypted and Decoded

Michal Garcarz
Cisco Employee



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
  • - 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.

SSL tunnel is complete.


Supplicant send empty EAP Reponse with Type “EAP-PEAP” (this is not SSL encrypted packet). This is in accordance to (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.

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.

We can decrypt it easily then. script

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 ( 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.

Wireshark configuration

After we have ssl.pcap it's time to configure wireshark:

# cat ~/.wireshark/preferences | grep ssl

ssl.desegment_ssl_records: TRUE

ssl.desegment_ssl_application_data: TRUE


ssl.debug_file: /tmp/debug-ssl.txt

server.pem is base64 encoded unprotected server key, example:






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.

Packet analysis

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: (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

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



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:

  • outer      identity being send in packet2 in EAPOL identity response (“cisco”)
  • inner      identity being send inside SSL tunnel in packet10 as identity response (“cisco”)
  • inner      identity being send inside SSL tunnel in packet12 as challange-response (“cisco”)

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 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. 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.


Recognize Your Peers
Content for Community-Ad