Example of a buffer overflow leading to a security leak

百般思念 提交于 2021-02-04 09:39:44

问题


I read many articles about unsafe functions like strcpy, memcpy, etc. which may lead to security problems when processing external data, like the content of a file or data coming from sockets. This may sound stupid, but I wrote a vulnerable program but I did not manage to "hack" it.

I understand the problem of buffer overflow. Take this example code:

int main() {
   char buffer[1];
   int var = 0;

   scan("%s", &buffer);
   printf("var = 0x%x\n", var);
   return 0;
}

When I execute the program and type "abcde", the program outputs 0x65646362 which is "edcb" in hexadecimal + little-endian. However I read that you could modify the eip value that was pushed on the stack in order to make the program execute some unwanted code (eg. right before a call to the system() function).

However the function's assembly starts like this:

push %ebp
mov %ebp, %esp
and $0xfffffff0, %esp
sub $0x20, %esp

Since the value of %esp is random at the start of the function and because of this "and", there seems to be no reliable way to write a precise value into the pushed eip value.

Moreover, I read that it was possible to execute the code you wrote in the buffer (here the buffer is only 1 byte long, but in reality it would be large enough to store some code) but what value would you give to eip in order to do so (considering the location of the buffer is random)?

So why are developpers so worried about security problems (except that the program could crash) ? Do you have an example of a vulnerable program and how to "hack" it to execute unwanted code? I tried this on linux, is Windows less safe?


回答1:


Read the excellent article by Aleph One: Smashing the Stack for Fun and Profit.




回答2:


Well for one thing, don't under estimate the hazards associated with being able to unreliably place a value inside EIP. If an exploit works one in 16 times, and the service it is attacking automatically restarts, like many web applications, then an attacker that fails when trying to get access can always try, try again.

Also in a lot of cases the value of ESP is less random than you think. For starters on a 32-bit system it is nearly always a multiple of four. That means that the extra padding offered by the and $0xfffffff0, %esp instruction will be either 0, 4, 8 or 12 bytes. That means that it is possible to just repeat the value that is to be written into the return EIP four times to cover all possible offsets to the address of return EIP.

There are actually much more aggressive stack protection / buffer overflow detection mechanisms around. However, there are ways and means around even these.

Also, for an example of where this sort of thing can be dangerous, consider if the value of var was important to you logic as in the following toy example.

int main() {
  char buffer[1];
  int var = 0;

  var = SecurityCheck();

  scan("%s", &buffer);
  if (var != 0)
    GrantAccess();
  else
    DenyAccess()
}



回答3:


Further you don't have to overwrite EIP with a pointer to something in your string. For example you could overwrite it with a pointer to system() and overwrite the next word with a pointer to /bin/sh at a fixed location in the program image.

Edit: Note that system uses the PATH (actually it runs the command via a shell), so "sh" would be just as good; thus, any English word ending in "sh" at the end of a string provides the argument you need.




回答4:


A classic example of an actual exploit based on buffer overruns is the Morris Worm of 1988.




回答5:


As mentioned in other answers, absolute reliability is not always essential for the attack to succeed. Applications that restart automatically are an example. Locally exploitable buffer overflows on suid programs would be another. And there's the NOP sled technique to increase chances of successful exploitation, put a lot of NOPs before your shellcode so you have a much better chance to correctly guess the "start" of your shellcode.

There are many more techniques for increasing the reliability of attacks. On Windows, back in the day, many exploits overwrote the return address with the address of a "jmp %esp" located somewhere in the program (trampoline).

"Insecure programming by example" had a nice trick for Linux. Clean your environment and put your shellcode in an environment variable. Back in the day, this would lead to a predictable address near the top of the stack.

And there are also variants like return-into-libc and return-oriented programming.

There was even an article on Phrack on how to exploit 1-byte stack overflows (meaning the buffer was overrun by only one byte) (btw, 1-byte heap overflows are also exploitable in the vast majority of cases, barring protections).

To sum up, it's not that developers are paranoid, there are lots of ways to exploit even the strangest cases, and remember:

  • A program is of good quality when it does what it is supposed to do.
  • A program is secure when it does what it is supposed to do, and nothing more.



回答6:


Here's a windows version and tutorial:

http://www.codeproject.com/KB/winsdk/CodeInject.aspx

The general case I was always warned about was:

printf( string );

Because the user can provide a "%n" in there, which allows you to insert anything you want into memory. All you need to do is find the memory offset for a system call, pass a few "%n"'s and junk characters, and thus insert the memory address onto the stack where the return vector would normally be. Voila -- insert any code you like.



来源:https://stackoverflow.com/questions/3291936/example-of-a-buffer-overflow-leading-to-a-security-leak

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!