The Kerberos mechanism supports several DTrace probes for decoding various protocol messages. For a list, see Appendix A, DTrace Probes for Kerberos. DTrace probes have a distinct advantage over other protocol inspectors, because DTrace enables a privileged user to easily look at unencrypted Kerberos and application data.
The following examples indicate what can be viewed with Kerberos DTrace probes.
Example 8-1 Using DTrace to Track Kerberos MessagesThe following script uses DTrace probes to display details about Kerberos messages that are sent and received by the system. Note that the fields that are displayed are based the structures that are assigned to the krb_message-recv and krb_message-send probes. For more information, see Definitions of Kerberos DTrace Probes.
kerberos$target:::krb_message-recv { printf("<- krb message recved: %s\n", args[0]->krb_message_type); printf("<- krb message remote addr: %s\n", args[1]->kconn_remote); printf("<- krb message ports: local %d remote %d\n", args[1]->kconn_localport, args[1]->kconn_remoteport); printf("<- krb message protocol: %s transport: %s\n", args[1]->kconn_protocol, args[1]->kconn_type); } kerberos$target:::krb_message-send { printf("-> krb message sent: %s\n", args[0]->krb_message_type); printf("-> krb message remote addr: %s\n", args[1]->kconn_remote); printf("-> krb message ports: local %d remote %d\n", args[1]->kconn_localport, args[1]->kconn_remoteport); printf("-> krb message protocol: %s transport: %s\n", args[1]->kconn_protocol, args[1]->kconn_type); printf("\n"); } kerberos$target:::krb_error-read { printf("<- krb error code: %s\n", args[1]->kerror_error_code); printf("<- krb error client: %s server: %s\n", args[1]->kerror_client, args[1]->kerror_server); printf("<- krb error e-text: %s\n", args[1]->kerror_e_text); printf("\n"); }
The preceding script can be called from the command line or with the krb5kdc daemon. The following is an example of calling the script, which is named krb-dtrace.d, from the command line. The command causes Kerberos to send and receive messages. Note that LD_NOLAZYLOAD=1 is needed to force the loading of the Kerberos mech_krb5.so library that contains the Kerberos DTrace probes.
# LD_NOLAZYLOAD=1 dtrace -s ./krb\-dtrace.d -c kinit dtrace: script './krb-dtrace' matched 4 probes kinit: Client '[email protected]' not found in Kerberos database while g etting initial credentials dtrace: pid 3750 has exited CPU ID FUNCTION:NAME 2 74782 k5_trace_message_send:krb_message-send -> krb message sent: KR B_AS_REQ(10) -> krb message remote addr: 10.229.168.163 -> krb message ports: local 62029 remote 88 -> krb message protocol: ipv4 transport: udp 2 74781 k5_trace_message_recv:krb_message-recv <- krb message recved: KRB_ERROR(30) <- krb message remote addr: 10.229.168.163 <- krb message ports: local 62029 remote 88 <- krb message protocol: ipv4 transport: udp 2 74776 krb5_rd_error:krb_error-read <- krb error code: KDC_ERR_C_ PRINCIPAL_UNKNOWN(6) <- krb error client: [email protected] server: krbtgt/DEV.ORACLE.COM@DEV .ORACLE.COM <- krb error e-text: CLIENT_NOT_FOUND
To use the script with the krb5kdc daemon, the svc:/network/security/krb5kdc:default service must be enabled and online. Note that the following command does not use LD_NOLAZYLOAD=1 because the mech_krb5.so library loads the krb5kdc daemon.
# dtrace -s ./krb\-dtrace.d -p $(pgrep -x krb5kdc)Example 8-2 Using DTrace to View Kerberos Pre-Authentication Types
The following example shows what pre-authentication is chosen by the client. The first step is to create a DTrace script, like the following:
cat krbtrace.d kerberos$target:::krb_message-recv { printf("<- krb message recved: %s\n", args[0]->krb_message_type); printf("<- krb message remote addr: %s\n", args[1]->kconn_remote); printf("<- krb message ports: local %d remote %d\n", args[1]->kconn_localport, args[1]->kconn_remoteport); printf("<- krb message protocol: %s transport: %s\n", args[1]->kconn_protocol, args[1]->kconn_type); } kerberos$target:::krb_message-send { printf("-> krb message sent: %s\n", args[0]->krb_message_type); printf("-> krb message remote addr: %s\n", args[1]->kconn_remote); printf("-> krb message ports: local %d remote %d\n", args[1]->kconn_localport, args[1]->kconn_remoteport); printf("-> krb message protocol: %s transport: %s\n", args[1]->kconn_protocol, args[1]->kconn_type); printf("\n"); } kerberos$target:::krb_kdc_req-make { printf("-> krb kdc_req make msg type: %s\n", args[0]->krb_message_type); printf("-> krb kdc_req make pre-auths: %s\n", args[1]->kdcreq_padata_types); printf("-> krb kdc_req make auth data: %s\n", args[1]->kdcreq_authorization_data); printf("-> krb kdc_req make client: %s server: %s\n", args[1]->kdcreq_client, args[1]->kdcreq_server ); } kerberos$target:::krb_kdc_req-read { /* printf("<- krb kdc_req msg type: %s\n", args[0]->krb_message_type); */ printf("<- krb kdc_req client: %s server: %s\n", args[1]->kdcreq_client, args[1]->kdcreq_server ); printf("\n"); } kerberos$target:::krb_kdc_rep-read { /* printf("<- krb kdc_rep msg type: %s\n", args[0]->krb_message_type); */ printf("<- krb kdc_rep client: %s server: %s\n", args[1]->kdcrep_client, args[1]->kdcrep_enc_server ); printf("\n"); } kerberos$target:::krb_ap_req-make { printf("-> krb ap_req make server: %s client: %s\n", args[2]->kticket_server, args[2]->kticket_enc_client ); } kerberos$target:::krb_error-read { printf("<- krb error code: %s\n", args[1]->kerror_error_code); printf("<- krb error client: %s server: %s\n", args[1]->kerror_client, args[1]->kerror_server); printf("<- krb error e-text: %s\n", args[1]->kerror_e_text); printf("\n"); }
Next, execute the krbtrace.d script as a privileged user on the Kerberos system by typing the following command:
# LD_BIND_NOW=1 dtrace -qs krbtrace.d -c "kinit -k" . . -> krb kdc_req make pre-auths: FX_COOKIE(133) ENC_TIMESTAMP(2) REQ_ENC_PA_REP(149)
The pre-authentication types are displayed in the output. For more information about the various pre-authentication types see RFC 4120.
Example 8-3 Using DTrace to Dump a Kerberos Error Message# dtrace -n 'krb_error-make { printf("\n{"); printf("\n\tctime = %Y", (uint64_t)(args[1]->kerror_ctime * 1000000000)); printf("\n\tcusec = %d", args[1]->kerror_cusec); printf("\n\tstime = %Y", (uint64_t)(args[1]->kerror_stime * 1000000000)); printf("\n\tsusec = %d", args[1]->kerror_susec); printf("\n\terror_code = %s", args[1]->kerror_error_code); printf("\n\tclient = %s", args[1]->kerror_client); printf("\n\tserver = %s", args[1]->kerror_server); printf("\n\te_text = %s", args[1]->kerror_e_text); printf("\n\te_data = %s", ""); printf("\n}"); }' dtrace: description 'krb_error-make ' matched 1 probe CPU ID FUNCTION:NAME 0 78307 krb5_mk_error:krb_error-make { ctime = 2012 May 10 12:10:20 cusec = 0 stime = 2012 May 10 12:10:20 susec = 319090 error_code = KDC_ERR_C_PRINCIPAL_UNKNOWN(6) client = [email protected] server = krbtgt/[email protected] e_text = CLIENT_NOT_FOUND e_data = }Example 8-4 Using DTrace to View the Service Ticket for an SSH Server
# LD_PRELOAD_32=/usr/lib/gss/mech_krb5.so.1 dtrace -q -n ' kerberos$target:::krb_kdc_req-make { printf("kdcreq_server: %s",args[1]->kdcreq_server); }' -c "ssh [email protected]" -o dtrace.out Last login: Wed Sep 10 10:10:20 2014 Oracle Solaris 11 X86 July 2014 $ ^D # cat dtrace.out kdcreq_server: host/[email protected]Example 8-5 Using DTrace to View the Address and Port of an Unavailable KDC When Requesting an Initial TGT
# LD_BIND_NOW=1 dtrace -q -n ' kerberos$target:::krb_message-send { printf("%s:%d\n",args[1]->kconn_remote, args[1]->kconn_remoteport) }' -c "kinit local4" 10.10.10.14:88 10.10.10.14:750 10.10.10.14:88 10.10.10.14:750 10.10.10.14:88 10.10.10.14:750 kinit(v5): Cannot contact any KDC for realm 'EXAMPLE.COM' while getting initial credentialsExample 8-6 Using DTrace to View Requests From Kerberos Principals
# LD_BIND_NOW=1 dtrace -qs /opt/kdebug/mykdtrace.d \ -c 'kadmin -p kdc/admin -w test123 -q listprincs' Authenticating as principal kdc/admin with password. krb kdc_req msg type: KRB_AS_REQ(10) krb kdc_req make client: kdc/[email protected] server: kadmin/[email protected] krb message sent: KRB_AS_REQ(10) krb message recved: KRB_ERROR(30) Err code: KDC_ERR_PREAUTH_REQUIRED(25) Err msg client: kdc/[email protected] server: kadmin/[email protected] Err e-text: NEEDED_PREAUTH krb kdc_req msg type: KRB_AS_REQ(10) krb kdc_req make client: kdc/[email protected] server: kadmin/[email protected] krb message sent: KRB_AS_REQ(10) krb message recved: KRB_AS_REP(11) kadmin: Database error! Required KADM5 principal missing while initializing kadmin interface krb kdc_req msg type: KRB_AS_REQ(10) krb kdc_req make client: kdc/[email protected] server: kadmin/[email protected] krb message sent: KRB_AS_REQ(10) krb message recved: KRB_ERROR(30) Err code: KDC_ERR_S_PRINCIPAL_UNKNOWN(7) Err msg client: kdc/[email protected] server: kadmin/[email protected] Err e-text: SERVER_NOT_FOUND krb kdc_req msg type: KRB_AS_REQ(10) krb kdc_req make client: kdc/[email protected] server: kadmin/[email protected]
The following script was used to produce the preceding output.
kerberos$target:::krb_message-recv { printf("krb message recved: %s\n", args[0]->krb_message_type); } kerberos$target:::krb_message-send { printf("krb message sent: %s\n", args[0]->krb_message_type); } kerberos$target:::krb_kdc_req-make { printf("krb kdc_req msg type: %s\n", args[0]->krb_message_type); printf("krb kdc_req make client: %s server: %s\n", args[1]->kdcreq_client, args[1]->kdcreq_server ); } kerberos$target:::krb_ap_req-make { printf("krb ap_req make server: %s client: %s\n", args[2]->kticket_server, args[2]->kticket_enc_client ); } kerberos$target:::krb_error-read { printf("Err code: %s\n", args[1]->kerror_error_code); printf("Err msg client: %s server: %s\n", args[1]->kerror_client, args[1]->kerror_server); printf("Err e-text: %s\n", args[1]->kerror_e_text); }