Created attachment 238511 [details] tickle bugs in kadmind's RPC/GSS interface by sending RPCs in the clear The heimdal kadmind has code to receive requests via ONC RPC protected by GSS encryption and signatures; this is handle_mit() etc in kadmind/rpc.c. One problem is that kadmind reads RPC arguments in the clear direct from the TCP connection, with no encryption or signature (and not preceded by a length). This means that an eavesdropper could read or modify RPC arguments (including, I believe, the passwords in create requests). That is, when receiving an RPC on a connection that's already been set up and had initial authentication done, process_stream(...,sp) in kadmind/rpc.c does this: read an RPC length from sp (which is just the socket, no crypto yet); read_data(sp, msg, len); // copy bytes from sp socket to msg buffer parse the RPC header, including cred and verf, out of msg; case RPC_DATA: gss_unwrap(... &gout ...) which I believe decrypts, and checks the signature (*procs[chdr.proc].func)(server_handle, sp, dreply); Note that the 2nd argument to procs[].func is sp, not gout or sp1. That is, the RPC handler function is going to read its arguments in clear-text from the underlying socket, not from a data buffer that is the result of decryption and signature check. Separately, after the RPC handler has returned, process_stream() frees sp but then uses it to send the reply: krb5_storage_free(sp); ... much later; CHECK(krb5_store_uint32(sp, data.length | LAST_FRAGMENT)); sret = krb5_storage_write(sp, data.data, data.length); This potentially results in reading and writing and calling through garbage pointers. Separately, there are a couple of calls to ret_string_xdr() and ret_principal_xdr() that assume that if these fuctions return zero (success), then they allocated a string. That's not the case: if the client specified a zero-length string, these functions set the string pointer to NULL. I've attached a demo. Due to some error in my setup, the host name must be set to "admin" in order for this to work; otherwise the gss rpc library changes "kadmin/admin" to "kadmind\\/admin", which kdc doesn't recognize. valgrind or a debugging malloc is required to see the use-after-free. kinit is required. # cc kadmind27a.c -lrpcsec_gss # hostname admin # kinit # valgrind /usr/libexec/kadmind --debug & # ./a.out If the user has no kadmind permissions, I get the use-after-free bug: #0 0x00000f24b3546b31 in krb5_store_int (sp=0xf24bb6d6180, value=<optimized out>, len=4) at /usr/src/crypto/heimdal/lib/krb5/store.c:328 #1 krb5_store_int32 (sp=0xf24bb6d6180, value=<optimized out>) at /usr/src/crypto/heimdal/lib/krb5/store.c:356 #2 krb5_store_uint32 (sp=sp@entry=0xf24bb6d6180, value=<optimized out>) at /usr/src/crypto/heimdal/lib/krb5/store.c:375 #3 0x00000f1c8fc8d07d in process_stream (contextp=0xf24bb6d7000, buf=0xf24b0753974 "$\017", ilen=0, sp=0xf24bb6d6180) at /usr/src/crypto/heimdal/kadmin/rpc.c:1087 #4 handle_mit (contextp=contextp@entry=0xf24bb6d7000, buf=buf@entry=0xf24b0753970, len=len@entry=4, sock=<optimized out>) at /usr/src/crypto/heimdal/kadmin/rpc.c:1107 #5 0x00000f1c8fc8e46a in kadmind_loop (contextp=0xf24bb6d7000, keytab=0xf24bb6eb000, sock=-1) at /usr/src/crypto/heimdal/kadmin/server.c:591 #6 0x00000f1c8fc8fae9 in main (argc=<optimized out>, argv=<optimized out>) at /usr/src/crypto/heimdal/kadmin/kadmind.c:202 If the user has kadmind permissions, kadmind crashes when trying to use a NULL principal name: #0 _hdb_fetch_kvno (context=0x6972dc59000, db=0x6972dc74000, principal=0x0, flags=93, kvno=0, entry=0x6971fd5d880) at /usr/src/crypto/heimdal/lib/hdb/common.c:110 #1 0x0000069721cadb81 in kadm5_s_delete_principal ( server_handle=0x6972dc5a040, princ=0x0) at /usr/src/crypto/heimdal/lib/kadm5/delete_s.c:51 #2 0x0000068efeee0140 in proc_delete_principal (contextp=0x6972dc5a040, in=<optimized out>, out=0x6972dc58200) at /usr/src/crypto/heimdal/kadmin/rpc.c:597 #3 0x0000068efeee1d15 in process_stream (contextp=0x6972dc59000, buf=0x6971fd5dd14 "\227\006", ilen=0, sp=0x6972dc58180) at /usr/src/crypto/heimdal/kadmin/rpc.c:926 #4 handle_mit (contextp=contextp@entry=0x6972dc59000, buf=buf@entry=0x6971fd5dd10, len=len@entry=4, sock=<optimized out>) at /usr/src/crypto/heimdal/kadmin/rpc.c:1107 #5 0x0000068efeee346a in kadmind_loop (contextp=0x6972dc59000, keytab=0x6972dc6d000, sock=93) at /usr/src/crypto/heimdal/kadmin/server.c:591 #6 0x0000068efeee4ae9 in main (argc=<optimized out>, argv=<optimized out>) at /usr/src/crypto/heimdal/kadmin/kadmind.c:202
This must have been fixed by a prior commit. The output I get is: bob# valgrind /usr/libexec/kadmind --debug ==53991== Memcheck, a memory error detector ==53991== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al. ==53991== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info ==53991== Command: /usr/libexec/kadmind --debug ==53991== ==53991== ==53991== HEAP SUMMARY: ==53991== in use at exit: 9,395 bytes in 67 blocks ==53991== total heap usage: 870 allocs, 803 frees, 135,661 bytes allocated ==53991== ==53991== LEAK SUMMARY: ==53991== definitely lost: 0 bytes in 0 blocks ==53991== indirectly lost: 0 bytes in 0 blocks ==53991== possibly lost: 437 bytes in 6 blocks ==53991== still reachable: 8,958 bytes in 61 blocks ==53991== suppressed: 0 bytes in 0 blocks ==53991== Rerun with --leak-check=full to see details of leaked memory ==53991== ==53991== For lists of detected and suppressed errors, rerun with: -s ==53991== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 1) bob# echo $? 0 bob# On the client: bob# ./kadmind27a rpc_gss_seccreate() failed bob#