Insecure hardware (was Re: gets(3) nonsense)

Chris Torek chris at mimsy.UUCP
Mon Nov 28 13:53:46 AEST 1988


>In article <2330 at cbnews.ATT.COM> lvc at 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 at bsu-cs.UUCP> dhesi at 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 at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.unix.wizards mailing list