Kerberos 机制支持多种 DTrace 探测器来解码各种协议消息。有关列表,请参见Appendix A, 用于 Kerberos 的 DTrace 探测器。相对于其他协议检查器,DTrace 探测器具有明显优势,因为 DTrace 可让特权用户轻松查看未加密的 Kerberos 数据和应用程序数据。
以下示例指明了可以使用 Kerberos DTrace 探测器查看的信息。
示例 8-1 使用 DTrace 跟踪 Kerberos 消息以下脚本使用 DTrace 探测器来显示有关系统收发的 Kerberos 消息的详细信息。请注意,所显示的字段基于分配给 krb_message-recv 和 krb_message-send 探测器的结构。有关更多信息,请参见Kerberos DTrace 探测器的定义。
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"); }
可以从命令行中调用前一个脚本,也可以通过 krb5kdc 守护进程调用。以下示例显示了如何从命令行中调用名为 krb-dtrace.d 的脚本。该命令将促使 Kerberos 收发消息。请注意,必须指定 LD_NOLAZYLOAD=1 来强制装入包含 Kerberos DTrace 探测器的 Kerberos mech_krb5.so 库。
# LD_NOLAZYLOAD=1 dtrace -s ./krb\-dtrace.d -c kinit dtrace: script './krb-dtrace' matched 4 probes kinit: Client 'root@DEV.ORACLE.COM' 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: root@DEV.ORACLE.COM server: krbtgt/DEV.ORACLE.COM@DEV .ORACLE.COM <- krb error e-text: CLIENT_NOT_FOUND
要通过 krb5kdc 守护进程使用该脚本,必须启用 svc:/network/security/krb5kdc:default 服务并使其联机。请注意,以下命令不使用 LD_NOLAZYLOAD=1,因为 mech_krb5.so 库将装入 krb5kdc 守护进程。
# dtrace -s ./krb\-dtrace.d -p $(pgrep -x krb5kdc)示例 8-2 使用 DTrace 查看 Kerberos 预验证类型
以下示例显示客户机选择的预验证类型。第一步是创建 DTrace 脚本,如下所示:
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"); }
接下来,以 Kerberos 系统上的某个特权用户的身份执行 krbtrace.d 脚本,方法为键入以下命令:
# 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)
在输出中显示了预验证类型。有关各种预验证类型的更多信息,请参见 RFC 4120。
示例 8-3 使用 DTrace 转储 Kerberos 错误消息# 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 = testuser@EXAMPLE.COM server = krbtgt/EXAMPLE.COM@EXAMPLE.COM e_text = CLIENT_NOT_FOUND e_data = }示例 8-4 使用 DTrace 查看 SSH 服务器的服务票证
# 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 local@four.example.com" -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/four.example.com@EXAMPLE.COM示例 8-5 使用 DTrace 查看请求初始 TGT 时不可用的 KDC 的地址和端口
# 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 credentials示例 8-6 使用 DTrace 查看来自 Kerberos 主体的请求
# 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/admin@TEST.NET server: kadmin/interop1.example.com@TEST.NET krb message sent: KRB_AS_REQ(10) krb message recved: KRB_ERROR(30) Err code: KDC_ERR_PREAUTH_REQUIRED(25) Err msg client: kdc/admin@TEST.NET server: kadmin/interop1.example.com@TEST.NET Err e-text: NEEDED_PREAUTH krb kdc_req msg type: KRB_AS_REQ(10) krb kdc_req make client: kdc/admin@TEST.NET server: kadmin/interop1.example.com@TEST.NET 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/admin@TEST.NET server: kadmin/interop2.example.com@TEST.NET 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/admin@TEST.NET server: kadmin/interop2.example.com@TEST.NET Err e-text: SERVER_NOT_FOUND krb kdc_req msg type: KRB_AS_REQ(10) krb kdc_req make client: kdc/admin@TEST.NET server: kadmin/interop2.example.com@TEST.NET
以下脚本用于生成上述输出。
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); }