Xref: utzoo comp.lang.c:14323 comp.unix.wizards:12917 Path: utzoo!utgpu!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!cwjcc!hal!nic.MR.NET!tank!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.c,comp.unix.wizards Subject: Re: Insecure hardware (was Re: gets(3) nonsense) Message-ID: <14733@mimsy.UUCP> Date: 28 Nov 88 03:53:46 GMT References: <867@cernvax.UUCP> <645@quintus.UUCP> <339@igor.Rational.COM> <4869@bsu-cs.UUCP> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 65 >In article <2330@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) >asks: >>Was the one of the reasons the two processor types were attacked >>because they would allow code to be executed in data space? (It is worth noting that the fingerd attack was applied only to VAXen.) In article <4869@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: >The fingerd bug was that sending a long line to it via gets() allowed >you to push anything you wanted on the stack. Since the stack contains >both data and return addresses, keeping code space and data space >separate would probably not have helped. (I don't know if hardware >separation of code and data inhibited the worm but it would still leave >the same loophole there for exploitation in some other way.) It would indeed have helped, although it might not have made a similar attack impossible. The attack consisted of sending a 536-byte `line' (with embedded NULs, so it was not a C string) which contained 400 control-As, some VAX machine code, numerous NULs, and finally a hand-crafted stack frame that caused fingerd's return from main()---fingerd did not use exit()---to return somewhere into the 512-byte buffer (to 0x7fffe9fc, actually). I have not gone so far as to analyse the stack of a normal (inetd-spawned) 4.3BSD or 4.3BSD-tahoe fingerd, but the obvious probability is that the ^As were used to allow for some slop in addressing: ^A, or ASCII 01, is a VAX NOP instruction. The stack of a 4BSD VAX Unix process looks like this: 8000 0000 System space 7fff ec00 u. area + red zone + kernel stack (UPAGES=0t10) 7fff xxxx environment variables 7fff yyyy argv strings 7fff zzzz stack frame for return from main() 7fff wwww local variables for main() xxxx depends on the number and length of environment variables, and would typically be ebxx (<256 bytes of environment, e.g., just HOME and PATH). yyyy depends on xxxx and on the number and length of the argv strings; zzzz depends on yyyy and on the number of registers used in main(). Apparently, for fingerd, wwww is around (7fff)cabc. The 400 ^As would allow for up to 400 bytes of error in the worm's assumption for the value of wwww above. If you had made changes to /etc/rc.local and/or inetd and/or fingerd, but had not pushed the address far enough away from the `usual' location, the worm could write a frame that would still look reasonable and would skip over its NOPs and execute the code it sent after the NOPs. That code essentially did an execve("/bin/sh"), but cleverly avoided anything but stack-relative addressing. Now, if the VAX hardware had refused to execute data pages---perhaps by refusing to execute any pages with user-write permission enabled--- the worm could not have run code off the stack. It could still replace the old stack frame, and change the argv and environment strings. I will not speculate on possible ways to break in using this ability. I will, however, note that any number of local changes might have moved the address `wwww' far enough to foil the attack. One could argue that, perhaps, each process should have a different view of its own address space. It would certainly be easy enough to have the c startup code move the stack down by a pseudo-random amount.... -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris