Tutorial – Buffer Overflows Part 2
ORIGINALLY POSTED BY NOKIA FOR THETAZZONE/TAZFORUM HERE
Do not use, republish, in whole or in part, without the consent of the Author. TheTAZZone policy is that Authors retain the rights to the work they submit and/or post…we do not sell, publish, transmit, or have the right to give permission for such…TheTAZZone merely retains the right to use, retain, and publish submitted work within it’s Network
Buffer Overflows Part 2!
This is a continuation from my first Buffer Overflow Tutorial; I would highly recommend that you read that tut, before you read this one! (Even if you’ve read it before re-read it to refresh your memory!)
Ok, so in part one we looked at
How a Buffer Overflow happens and the security implications of this.
Ways to find what programs have SUID privileges using the
find / -type f –perm -04000 –ls command .
We also looked at how to change a program to give it #root privileges.
I will start this tutorial off at the point where, you have compiled a piece of code that is vulnerable to an overflow (see part 1), you have changed the ownership of the program to root and you have made it a SUID root program. We will call this program “pool”
So, we know pool can be exploited with a buffer overflow (as we programmed it) and we know it has root privileges (as we gave them to it)
Now what we need to do is generate a program with a buffer (remember a buffer is a portion of memory assigned to a program) that contains the shellcode, which will spawn a shell that can be “fed” into the pool program. We will call this program “snooker”
Our aim is to make the program pool overflow in to the buffer that the program snooker has given it and make the EIP point to where our shellcode within this buffer and then to make snooker accidentally execute this shellcode.
Obviously for this to work we need to know where our shellcode is stored in the buffer!
There two main ways of doing this: Using a NOP sled or by flooding the end of a buffer with quite a few “return addresses”.
No Operation (NOP)
As the name suggests this is an instruction that does nothing, its sole purpose is to take up a byte of memory so nothing else can occupy it.
Why is this useful to us?
For a few reasons really.
1. If our NOP is occupying a byte of memory we know that our shell code couldn’t possibly be there!
2. The processor will skip over a NOP until it gets to something that tells it to do something, i.e. our shellcode (hopefully)
3. A program wont crash if it hits a NOP as the NOP isn’t telling it to do anything, it will just move down or up to the next memory “block”
Consider this (each number represents a bock of memory in our buffer)
Pool Snooker Snooker Shellcode Snooker Snooker Snooker Snooker
For us to execute our shellcode we would have to ensure the EIP was pointing at “4” and no where else, otherwise snooker would continue to run. There would be a lot of trial and error not to mention luck in executing the shell code!
But, what about if we done this:
Pool Snooker NOP NOP NOP NOP NOP Shellcode
As long as the EIP was pointing at either 3,4,5,6,7 or 8 our shellcode would be executed, because as I said earlier the processor would just skip along them NOP’s until it got to something it could execute!
Obviously this gives us a bigger area of error for the EIP to execute the shellcode
So along as we overwrite the EIP with any address in the NOP we can be assured our shellcode will be executed
*The NOP sled is not limited in size, it can be 200+ bytes if you want it to be.
Use common sense though as if you fill the memory up with NOP’s then nothing is going to work!
The other way of doing it is with return address; this method can be and is, used in conjunction with the NOP method!
This is a very simple method.
All it does is “floods” the last part of our buffer with lots and lots of return address to where our shellcode or NOP is located.
Snooker Snooker NOP NOP NOP NOP Shellcode R/A7 R/A5 R/A3
So the return address (R/A) is telling the EIP to go to “7 , 5 or 3”
Have a look at the room for error we now have!
As long as the EIP is NOT pointing at 1 or 2 our shellcode is going to be executed
So compared to the first diagram:
Pool Snooker Snooker Shellcode Snooker Snooker Snooker Snooker
Where we needed to hit “4” right on the head to execute our shellcode
Now all we need to do is make sure the EIP stays away from 1 + 2!
Of course both of these methods require us to know the approximate location of the buffer in the system memory!
How do we find this?
We find this by finding out where the current Stack Pointer is.
(Remember a stack pointer, amongst other things, is used to tell the EIP where to return to after a function has been completed), hence if we can control the stack pointer, we can control the EIP!!
In the snooker program them first place the stack will be telling the EIP to look at will be the start of the buffer, remember our shellcode is located in this buffer and we know how big the buffer is because we created it in our snooker program, so already we have a rough idea where our shellcode will be!
I feel it may be starting to get confusing, so I will break it all down:
1. Created a program that is susceptible to Buffer Overflows called Pool
2. Made Pool run with root privileges, so that, when we make it spawn a shell, the shell will have the same privileges (#root)
3. Created a program called Snooker, which gave pool a buffer, containing the shellcode to be executed.
4. Filled this buffer with NOP’s and Return Addresses, to maximise the chance of getting the shellcode to be run.
5. Found out where snookers buffer is by using the current stack pointer
6. We know how many bytes pool will take up, so when we coded (programmed) snooker we leave the first bytes free that pool will require to run, then we put some NOP’s to leave space between pool and our shellcode, this increases the %age of our shellcode executing
7. Filled the end of the buffer with return address that point to the NOP’s that are after pool.
So Pool overflows, the EIP will go where ever it likes in snookers buffer, if we are lucky it goes straight to the shellcode and spawns a root shell for us.
If we are unlucky it lands on a NOP, it then goes to the next NOP and the next and the next until it comes to our shell code and spawns a root shell!
Or, it land on a return address, which is telling it to go to either a NOP or if we are lucky again, the shellcode, if it goes to the shellcode, happy days we get a root shell, if it goes to a NOP, it slides down and down and down until low and behold….. yup, we get a root shell!
Did it make scene to anyone??
•This is a very very simplified version of it.
•There is a bit more to finding our buffer using stack pointer offsets, but I will cover this in a future tutorial!
•Again I have took liberties with memory addressing, just to keep it simple
•In Part 1 Snooker was called vuln but I felt like renaming it for this tut!
•I have has a few pm’s from people asking how to compile the code from my last tutorial, hence my next one will be about how to do that using Linux and a Windows based compiler.
Please bear in mind that this is a simplified version and liberties have been taken!
I hope you enjoyed reading it and maybe learnt something from it; I’m now off to buy me a big bottle of JD as I’ve drank a whole one whilst typing this! (Thank god for spell checkers!)