In article <DF8qC9.4Cw@sgi.sgi.com>, "Vladimir Z. Nuri" <vznuri@netcom.com> writes:
P.M. notes that anywhere there is a data-driven buffer overflow (which he suspects are all over netscape) he can get code to execute anything he wants. this reminds me of the Morris internet worm that ran exactly the same way. it used a bug in the finger demon that caused a string buffer overwrite (via strcpy, instead of strncpy) to execute customized code.
my question: I have not seen the specifics of how this works. does this require specialized knowledge of the native machine language on the host machine? or is it just used to cause something like a core dump to get a command line or something like that?
I question the accuracy of this. The fingerd bug was that a string in the static data area was read in with gets which could be overflowed. At some point in memory after this input buffer was the string constant that stored the name of the finger command. What the Morris work did was to overflow the input buffer and replace the string constant "finger" with "csh". When fingerd then exec'ed the command, that gave you a shell running on the machine. While it is certainly true that you can stomp on memory in static buffers, it's not clear that you can execute whatever code you insert there. If the buffer happens to be allocated off the stack (and the stack grows down) then you can modify the return address. Of course, you have to know the address of whatever code you want to execute. And that code has to do something useful. Presumably, if there are two bugs, one which lets you write over a static buffer and one for a buffer allocated from the stack, then you could execute code of your choosing. Of course, that also assumes that you can execute from the data area which is not always true. -- Sure we spend a lot of money, but that doesn't mean | Tom Weinstein we *do* anything. -- Washington DC motto | tomw@engr.sgi.com
I question the accuracy of this. The fingerd bug was that a string in the static data area was read in with gets which could be overflowed. At some point in memory after this input buffer was the string constant that stored the name of the finger command. What the Morris work did was to overflow the input buffer and replace the string constant "finger" with "csh". When fingerd then exec'ed the command, that gave you a shell running on the machine.
Nope, that wasn't it, either. See the Eichin/Rochlis "tour of the worm" paper. I was visiting friends at MIT the night the worm hit. After receiving some confused and unspecific reports that the worm was getting in through fingerd, I had a flash of insight as to how that might happen; as it turned out, this insight was correct, and shortly thereafter, I had reproduced a benign form of the fingerd attack. As implemented by the worm, it only worked on vaxes, but it could have worked on other systems. The buffer in question was on the stack, not in static storage. The attacker wrote a long sequence of NOP's, followed by machine instructions which implemented the equivalent of exec("/bin/sh"), followed by the approximate stack address of the stack buffer; the last address was at the right place to overwrite the saved PC field in the stack frame. When the routine "returned", it actually branched into the runway of NOP's, and then exec'ed "/bin/sh". Note that the actual stack address varied, as environment variables (which tend to vary from installation to installation) are located at the top of the stack. As it turned out, the attack did not work on most Athena systems, because the athena /etc/rc complex wound up using a large number of environment variables which pushed the location of the stack frame in question out of the range where the attack would have worked. - Bill
Tom Weinstein writes:
While it is certainly true that you can stomp on memory in static buffers, it's not clear that you can execute whatever code you insert there. If the buffer happens to be allocated off the stack (and the stack grows down) then you can modify the return address. Of course, you have to know the address of whatever code you want to execute.
Lets say, Mr. Weinstein, that you shove some code onto the stack along with the return address, and the address happens to be the code. If you don't believe it can be done, its easy enough to demonstrate it on your machines, which I believe suffer from the syslog(3) bug, which your company hasn't patched so far as I know, and which afflicts the Sendmail daemons you ship with your machines. See the recent 8lgm bug report if you want details.
Of course, that also assumes that you can execute from the data area which is not always true.
Its usually true on modern machines -- its very difficult to rig things otherwise given the way that lots of the dynamic loading works these days. Perry
Maybe I'm missing something here, but I don't see it. While it is easy to use the "overwrite buffer and stomp on stack" method to execute code for programs written as so void foo(char* inputdata) { char blah[X]; write_to_buffer_without_knowing_length(inputdata, blah); } How would you do it for a program rewritten as void foo(char* intputdata) { char* blah; blah=PMalloc(X); write_to_buffer_without_knowing_length(inputdata, blah); } Where PMalloc acts like malloc, but from a separate heap. Two other conditions further hold. All variables in this separate heap are viewed as "tainted" since they came from user input, and can not be used as arguments to system(), popen(), fopen(), etc. Given this, I don't see how it is possible to cause code to be executed. For one thing, you can't modify the stack. Secondly, since buffers can't be used as arguments for i/o calls, overwriting nearby buffers like char *program_path = "auxillary_program" to "/bin/csh" won't do you any good. (note: a pointer variable should never point to data on the stack anyway. I'm glad Java eliminated stack data. Pointers to stack data are the source of numerous bugs in C. There is a minor performance gain to having the compiler generate the stack allocation rather than call malloc(), but it's not worth it. Stack data has the benefit that it is automatically deallocated upon function return. My answer is to simply use C++ to achieve this with dynamically allocated resources) I for one, never use scanf(), gets(), or anything that doesn't know the size of the destination storage. It's plain stupid. I was tutoring a student today who had allocated a 20-byte buffer on the stack and used scanf to ask for a filename. Sheesh. One thing that should set off alarm bells immediately whenever your coding is a fixed size buffer justified with the idea "no one could ever use more than Y resources." Yeah, no one could ever use more than 11 character file names. 640K ram. 32-bit IP address space. etc, etc. If not for security, then for simple future flexability. -Ray
In article <199509220443.AAA02254@frankenstein.piermont.com>, "Perry E. Metzger" <perry@piermont.com> writes:
Tom Weinstein writes:
While it is certainly true that you can stomp on memory in static buffers, it's not clear that you can execute whatever code you insert there. If the buffer happens to be allocated off the stack (and the stack grows down) then you can modify the return address. Of course, you have to know the address of whatever code you want to execute.
Lets say, Mr. Weinstein, that you shove some code onto the stack along with the return address, and the address happens to be the code.
I never disputed that it could be done, I was just uncertain as to how easy it would be. As has been pointed out, it's not nearly as hard as I thought, assuming you can execute in the stack.
If you don't believe it can be done, its easy enough to demonstrate it on your machines, which I believe suffer from the syslog(3) bug, which your company hasn't patched so far as I know, and which afflicts the Sendmail daemons you ship with your machines. See the recent 8lgm bug report if you want details.
Hmm, could you explain how to exercise this bug? Perhaps a sample program?
Of course, that also assumes that you can execute from the data area which is not always true.
Its usually true on modern machines -- its very difficult to rig things otherwise given the way that lots of the dynamic loading works these days.
True. -- Sure we spend a lot of money, but that doesn't mean | Tom Weinstein we *do* anything. -- Washington DC motto | tomw@engr.sgi.com
Tom Weinstein writes:
Lets say, Mr. Weinstein, that you shove some code onto the stack along with the return address, and the address happens to be the code.
I never disputed that it could be done, I was just uncertain as to how easy it would be.
Its pretty obvious.
If you don't believe it can be done, its easy enough to demonstrate it on your machines, which I believe suffer from the syslog(3) bug, which your company hasn't patched so far as I know, and which afflicts the Sendmail daemons you ship with your machines. See the recent 8lgm bug report if you want details.
Hmm, could you explain how to exercise this bug? Perhaps a sample program?
I can tell you in general terms -- I don't write MIPS assembler myself. However, I will point out to you that you use an ancient Sendmail, and that it uses syslog(3) on user produced data, and that syslog uses a static buffer. Trick sendmail into logging something very big, and you can do what you like. The 8lgm people wrote a demo for Sparc as a proof of concept. Perry
participants (4)
-
Bill Sommerfeld -
Perry E. Metzger -
Ray Cromwell -
tomw@orac.engr.sgi.com