Logging EAP-TLS certificate details

Roberto.Franceschetti at ocfl.net Roberto.Franceschetti at ocfl.net
Mon Mar 22 19:46:49 CET 2021


I thank you both for letting me know that it's not possible to obtain certificate information when logging the accounting information. I had been looking for a way for the past week and would still be looking for one if it wasn't for your reply.

However I believe my point of this being a big freeradius security issue is incorrectly overlooked.

Consider a scenario where freeradius is configured to authenticate against an LDAP/Active Directory.

* We detect IP 10.255.1.100 on our internal network currently attacking one of our Exchange servers.
* We see 10.255.1.100 as belonging to our WiFi DHCP pool.
* We thus go to the RADIUS radacct table to see the FramedIP address issued at the time of the attack.
* We see the UserName that was logged in as being "JohnS". We thus know exactly which LDAP account is compromised, are able to block the attack and quickly investigate how the account was compromised.

The key there is that access was granted with a username/password credential. The username in this case unequivocally identifies the account used to login WiFi, and that "identity" information was logged by freeradius.



Now consider a different scenario (ours...) were, in addition to LDAP/Active Directory, we also allow EAP-TLS authentication via certificates issues by our certificate authority (we have issued over 40,000 certificates).

* We detect IP 10.255.1.100 on our internal network currently attacking one of our Exchange servers.
* We see 10.255.1.100 as belonging to our WiFi DHCP pool.
* We thus go to the RADIUS radacct table to see the FramedIP address issued at the time of the attack.
* We see the UserName that was logged in as being "HaHaHaTryToCatchMeIfYouCan". We discover that the account "HaHaHaTryToCatchMeIfYouCan" does not exist in our LDAP/Active Directory. We then think the user probably authenticated with EAP-TLS and a certificate, but we're guessing since neither the radacct nor the radpostauth tables provide any clues as to the authentication used.
* We check the "CallingStationID" in radacct to see if the MAC address of the hacker appears elsewhere, but it's a fake MAC.

We are thus in a nightmare scenario where the hacker was able to obtain the private key for one of our 40,000 certificates to authenticate with our WiFi, but we have absolutely no idea which of these 40K certificates was compromised. We will need to revoke them all and that would be a disaster.


Saying "this is how radius works" does not apply here. There's nothing wrong with RADIUS. It's authenticating correctly. EAP-TLS allows the user to specify a random username as it's not taking part of the authentication process. There's nothing wrong with that either. WHY? Because they are authenticating with a certificate that we issued, and given any specific certificate's serial number, we know who it was issued to. If there's a problem with the specific certificate being compromised, we revoke it. Freeradius checks the CRL so it will not allow access to revoked certificates.

BUT WAIT. Freeradius is logging usernames for users who authenticating with a password, BUT it's NOT logging absolutely anything at for the certificate used by users who authenticate with a certificate. NOTHING.

The issue is thus that while freeradius is be default logging the critical "Username" when regular authentication is occurring, freeradius is completely oblivious when it comes to logging the equivalent of the username when dealing with EAP-TLS. Any properly written application will have adequate auditing for who is logging into it. Freeradius is instead allowing users to login via EAP-TLS with absolutely no auditing whats-over. Auditing means auditing the identity used to login. Auditing an EAP-TLS username that is not actually being used for login purposes is useless - Freeradius MUST log whatever method is used to authenticate a user, and with EAP-TLS that means logging the TLS-Client-Certificate information.


As you said there's nothing from with RADIUS protocol. But there everything wrong with the default installation of freeradius when it comes to auditing EAP-TLS authentications. This is a huge issue security hole as the logging of EAP-TLS certificate information that should be included in the default freeradius configuration, not left to admins to figure out that (1) they actually have an auditing problem of an application that's not logging who's authenticating, and (2) for them to figure out how to log it.


We were able to implement what was missing after much pain and Googling. For anyone who thinks this is an actual concern, this is how we addressed it.


1. Our NAS logs the MAC address of our wireless clients on authentication requests. So we modified the radpostauth table to include the "CallingStationID" (which has the MAC address of the client) and the client cert information. This allows us to had an audit trail of usernames, MAC and Client Cert for every Access-Request:

ALTER TABLE `radius`.`radpostauth` ADD COLUMN `CallingStationId ` VARCHAR(64) AFTER `nasipaddress`,
 ADD COLUMN `TLS_Client_Cert_Common_Name` VARCHAR(256) AFTER `CallingStationId`,
 ADD COLUMN `TLS_Client_Cert_Serial` VARCHAR(128) DEFAULT NULL AFTER `TLS_Client_Cert_Common_Name`,
 ADD COLUMN `TLS_Client_Cert_Issuer` VARCHAR(50)  DEFAULT NULL AFTER `TLS_Client_Cert_Serial`;


2. Modify the radacct table to add the client cert information in it so we can populate it afterwards:
ALTER TABLE `radius`.`radacct` ADD COLUMN `TLS_Client_Cert_Common_Name` VARCHAR(256) AFTER `xascendsessionsvrkey`,
 ADD COLUMN `TLS_Client_Cert_Serial` VARCHAR(128) DEFAULT NULL AFTER `TLS_Client_Cert_Common_Name`,
 ADD COLUMN `TLS_Client_Cert_Issuer` VARCHAR(50)  DEFAULT NULL AFTER `TLS_Client_Cert_Serial`;


3. Change the linelog module to log the certificate information on the Access-Request so it would be available in syslog as a backup:
Access-Request = "Packet-Type=\"%{Packet-Type}\" ...... ,Timestamp = %l,%{User-Name},%{Framed-IP-Address},TLS-Client-Cert-Common-Name = \"%{TLS-Client-Cert-Common-Name}\",TLS-Client-Serial=\"%{TLS-Client-Cert-Serial}\",TLS-Client-Cert-Issuer = \"%{TLS-Client-Cert-Issuer}\","


4. Change the postauth_query in the dialup.conf module to log the CallingStationid and the Client Cert data in the database on the Access-Request:
postauth_query = "INSERT INTO ${postauth_table} \
                          (username, message, nasipaddress, reply, authdate, CallingStationid, TLS_Client_Cert_Common_Name, TLS_Client_Cert_Serial, TLS_Client_Cert_Issuer) \
                          VALUES ( \
                          '%{User-Name}', \
                          '%{Module-Failure-Message}', \
                          '%{NAS-IP-Address}', \
                          '%{reply:Packet-Type}', '%S', '%{Calling-Station-Id}', \
                          '%{TLS-Client-Cert-Common-Name}', '%{TLS-Client-Cert-Serial}', '%{TLS-Client-Cert-Issuer}')"


5. Create and call every minute or so the following stored procedure which will update the certificate details for the records in the radacct table by matching logins via their MAC address (CallingStationId) in the radpostauth table (which does contain the certificate information previously retrieved/stored by the access-request).
CREATE PROCEDURE `radacct_add_cert_info`()
UPDATE radacct
INNER JOIN radpostauth
ON radacct.CallingStationId = radpostauth.CallingStationId
SET radacct.TLS_Client_Cert_Common_Name=radpostauth.TLS_Client_Cert_Common_Name,
    radacct.TLS_Client_Cert_Serial=radpostauth.TLS_Client_Cert_Serial,
    radacct.TLS_Client_Cert_Issuer=radpostauth.TLS_Client_Cert_Issuer
WHERE `authdate` > DATE_SUB(NOW(), INTERVAL '10' MINUTE) AND `AcctStartTime` > DATE_SUB(NOW(), INTERVAL '10' MINUTE)
AND (radpostauth.TLS_Client_Cert_Common_Name<>'' OR radpostauth.TLS_Client_Cert_Serial<>'' OR radpostauth.TLS_Client_Cert_Issuer<>'');;



The nightmare scenario above where EAP-TLS clients would be untraceable now becomes the following:

* We detect IP 10.255.1.100 on our internal network currently attacking one of our Exchange servers.
* We see 10.255.1.100 as belonging to our WiFi DHCP pool.
* We thus go to the RADIUS radacct table to see the FramedIP address issued at the time of the attack.
* We see the certificate's serial number and common name in the radacct table for that record
* We revoke the certificate, force a re-download of the CRL in the cron job, stop the attack, and can now focus on investigating how the user the certificate was issued to mishandled it.


Roberto



From: Alan DeKok
Subject: Re: Logging EAP-TLS certificate details
Date: March 19, 2021 at 8:04:04 AM EDT
To: FreeRadius users mailing list <freeradius-users at lists.freeradius.org<mailto:freeradius-users at lists.freeradius.org>>


On Mar 18, 2021, at 10:43 PM, Roberto.Franceschetti at ocfl.net<mailto:Roberto.Franceschetti at ocfl.net> wrote:
We see this "feature" of EAP-TLS that allows to specify a completely random username as a serious security risk, as there is no information being logged in the radacct table to indicate what certificate was used to authenticate a particular session.

 As Matthew says, that's how the protocols work.  It's not a security issue with FreeRADIUS.  It's an issue with your local configuration.

 TBH, it's RADIUS.  If it "just works", then great.  Otherwise, it's your responsibility to understand what's going on, and to work around issues with broken clients, broken NASes, etc.  This is simply the reality of RADIUS.

 FreeRADIUS gives you not only the information on exactly what's going on, it gives you the power to fix it.  So the only question here is "how do you work around the issues you're seeing".

 You can send the Class attribute back in the Access-Accept.  And the NAS *should* echo it back in Accounting-Request packets for the same session.

 You can create Class fairly easily in v3, and there are examples to do this.  In 2.2.9, it's a little harder, but not impossible.  Maybe:

update reply {
Class := "0x%{md5:%{NAS-Identifier}%{TLS-Client-Cert-Common-Name}%{TLS-Client-Cert-Serial}%{TLS-Client-Cert-Issuer}"
}

 You'll have to try some things to see what works.  The idea is to have Class be a 16-byte value, which is taken from an MD5 hash of a bunch of things specific to that particular session.  This hash MUST be unique.

 i.e. if two users log in at the same time, with the same certificate, then they MUST get different values for the Class attribute.  You'll have to (surprise) read the debug output to see wha's in the packets, and what makes those sessions unique.  Things like NAS-Port, etc.

 Once you find out which attributes make the request unique, then put them into the input for the MD5 hash.

 And also log the Class attribute, along with any information about the session (TLS cert information, Framed-IP-Address, NAS-IP-Address, NAS-Port, NAS-Identifier, etc.) before sending the Access-Accept.  Logging this information lets you cross-check the Class when the server receives an Accounting-Request packet which contains the Class.

Here is our scenario. Hundreds of IoT devices, each authenticating with certs, connecting/disconnecting multiple times per minute. All of them are logging in with the username "user". If one of those certificates is compromised and is used in a malicious way in a different device, while the radius accounting table will show us the IP address of the attacker, there will be absolutely no way to find out which of the hundreds of certificates we issued was abused, and we would thus not know which certificate was compromised and needs to be revoked.

 If you have the Class attribute in the Accounting-Request packets, you just look up that in a DB, find the TLS cert information, and revoke the cert.

 If you don't have Class, you can likely just look up NAS-IP, port, etc.  And that *should* generally be enough.  But not always.  Which is why Class exists.

 And whatever you do, you have to log things when sending the Access-Accept.

We were able to log the certificate information and link it to the client's IP during the Access-Request via syslog by modifying this in the linelog:
Access-Request = "Packet-Type=\"%{Packet-Type}\" ...... ,Timestamp = %l,%{User-Name},%{Framed-IP-Address},TLS-Client-Cert-Common-Name = \"%{TLS-Client-Cert-Common-Name}\",TLS-Client-Serial=\"%{TLS-Client-Cert-Serial}\",TLS-Client-Cert-Issuer = \"%{TLS-Client-Cert-Issuer}\","

 That's good, if the NAS sends Framed-IP-Address.  Except the whole point of RADIUS is that it happens *before* the system has network access.  So in general, the Access-Request will not contain a Framed-IP-Address.

 But if Framed-IP-Address exists in the Access-Request *and* Accounting-Request packets, then you can use it to associate the two packets, and then revoke the correct certificate.

The above will ultimately probably allow us identify the compromised certificate if we're able to capture/archive the syslog data (which we do...), but this is a workaround - the certificate information should really be available in the radacct table as that's what's used to examine user's activity (time remaining connected, bytes transferred, time of connection and so forth).

 No.  Absolutely not.  This is NOT how RADIUS works.

 Read the debug output.  See what's in the Accounting-Request packets.  Note that there's no certificate information.

Customizing the accounting queries in the dialup.conf however does not seem to work for adding the same TLS-Cert fields to the radacct table (we did of course modify the schema to add the extra TLS-Cert fields). The TLS-Cert fields are being filled with blank values in the radacct table. We're thinking it's probably because the various %{TLS-Client-Cert-nnnnn} are not available during the "Accounting-Request" process. Our modified query is below.

 Read the debug output to see what's in the Accounting-Request packets.  It really is that easy.

 There is no magic here.  If you want to know WHY something is in the radacct table, then read the debug output.  Just... PLEASE read the debug output.  Note that there's no certificate information in the Accounting-Request packet.  So... any idea why the certificate information isn't being logged into radacct?

Has anyone found a solution to log certificate information in the radius accounting table for users who authenticate via EAP-TLS?

 You don't.  It's impossible.

 What you DO is log the certificate information during authentication, AND log some information which identifies the session.  THEN when receiving an Accounting-Request packet, look up the session information in a database, in order to find the certificate information.

 You're running into the limitations of the RADIUS protocol.  These are NOT limitations in FreeRADIUS.  These are not security issues in FreeRADIUS.

 Every system using RADIUS has it's own set of bizarreness and breakages.  NASes which ignore the standards, supplicants which do weird things, etc.  Your responsibility is to figure out what's going on, and then to use FreeRADIUS and databases in order to glue together a solution.

 You simply cannot rely on the NAS to do anything intelligent.  The NAS gives you packets containing "something".  You have to work with that.  You can't make the NAS do anything else (except usually echo back Class).  So the ONLY solution here is to write FreeRADIUS policies which read/write a database, in order to get the results you want.

 Welcome to RADIUS.  It's a horrific nightmare of insanity.  But FreeRADIUS gives you back control, and lets you work around almost every issue you'll see.

 Alan DeKok.





-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html

PLEASE NOTE: Florida has a very broad public records law (F. S. 119).
All e-mails to and from County Officials are kept as a public record.
Your e-mail communications, including your e-mail address may be
disclosed to the public and media at any time.


More information about the Freeradius-Users mailing list