This presentation is on chapter ten in thebook, on software security and trusted systems.
The book begins by defining a buffer overflow.
A buffer overflow is a process that stores data in a buffer outside the memory the programmeraside for it.
If you guys have any experience with programming with C++, Java, or whatever,the case may be you guys are already familiar with the buffers, just this memory is beingallocated.
So a buffer overflow is where you are putting data in that buffer but it isactually outside of the memory that the programmers set aside for.
When this happens extra datawill then overwrite the adjacent memory which then can result in erratic program behavior.
A traditional way to understand this is computer security and programming, when a buffer overflowis overrun, it's an anomaly where it processes stored data and the buffer outside the storedmemory the programmer set aside for, the extra data, because it is being overwritten, theexcess data is now overwriting adjacent memory, which may contain other data including programvariables and program full control data.
Consequently as I have already explained this can resultin erratic program behavior including memory access errors, incorrect errors, or results,program termination, like a crash, or a breach of system security.
This is what we are goingto focus on, this is one way hackers get into a system, by using the buffer overflow.
Sothe very easy way to understand this is understanding that a buffer overflow is a condition in aprogram, written by a function that attempts to copy more data into the buffer then itcan hold.
So I think that is a pretty good, so hopefully I've explained what a bufferover flow is well, it is really difficult to get through this chapter without fullyunderstanding this first concept.
So I want to show you how this works in code.
So againif you guys already have a background in coding this will make a lot of sense to you guys.
So on the left hand side you see me code, this is just traditional C code, I have abuffer that is set to the size of 90 bytes, and I am going to print that buffer so theway this works if this is executed it is going to prompt the user to type something, andthen it is going to allocate a buffer to temporarily hold that user input, the user will then typein some data, the program copies user input to the buffer, and then the program will readand print the data in the buffer to the screen.
So this seems rather smooth, no issues here,if the user stays within that allocated space of 90 bytes, but what if the user enters datathat is more then 90 bytes? Well what is going to happen is the program can crash the erroror worse, and this is what buffer overflow is.
So this diagram shows you how this works,it is really important to understand where the input space is and what I am calling theoutput space is, this is where the program communicates to the user, and this is howa hacker can exploit your system.
So at the top is the input space, this is where youallocate the space for your buffer, then at the bottom in the red is your return address,this is when a function of procedures call, in the system it will say data, here.
So whena function ends, it is going to read the return address and let the program return to whereit left off, and depending upon how it operates, depending upon the program it can't show thedata results to the user.
Alright so lets say I have "hello," and I am the user andI put "hello" into the system as you guys can see, it is all good because of the factthat I have more allocated space then the space required for this string "hello.
" Nowin this particular case I put in the stream that exceeds my buffer, and as you can seeI have stuff being held red, and in this output space, the bottom, the local stack is beingoverwritten and the saved frame pointer, and most importantly the return address.
So nowwhat is going to happen when it returns, or when the return address is completed or itis off the stack, it jumps to that address and it starts executing instruction from thereturn address.
So what the attack, what he or she is doing is they have overwritten thereturn address with a pointer to the stack buffer which now contains attacker supplydata.
In an actual stack buffer overflow exploit the string is not having a's it would be shellcode, and we will talk about shell code shortly.
So the shell code that is suitable to theplatform and the desired function.
So if this program has special privileges like if theuser was a super user then the attacker can use this vulnerability to regain super userprivileges on the affected machine.
The attack can also modify internal variable values todisplace some bugs.
SO let me just walk you guys through this so this is clear.
If thea's just represent a's and it was nothing significant then it would still be a problembut your system hasn't been hacked.
Those a's are actually code and it exceeds the allocatedspace so the return address is pointing back to those instructions.
This is how this shellcode is executed by your program.
So shell code is malicious code, it spawns a shellor command prompt in a system, I'm pretty sure you guys all know what a shell code commandprompt is.
This is how hacker's interface into the system.
So it is really importantthat your security policies must prevent overflows to avoid execution of shell code for hackers.
This is the first part of software security, and in my opinion it probably should be it'sown separate course offering because this is very evolved and it is very important.
I want to just hit some of the high notes here, as we continue to get through this semester.
Though now it is important for us, now that we know what a buffer overflow is and howhackers use it to enter your system the question is, well how do we defend against those bufferoverflows? The first way is through compile-time defenses and the second was is run-time defenses.
There are several options with compile-time defense, again if you guys know what programmingis then you know what a compiler is and what compile time, and the difference between runtime or execution time.
So if you want to look at a compile-time to prevent buffer overflowsthe first thing you have to consider the programming languages.
You want to have your variabletype with strong notions.
You also want your compilers enforce range checks automaticallyon all of your variables.
Now of course with this cost there are draw backs to this method.
It results in longer compile times, requires more resources, it also results in longerrun times, your code is further abstracted while doing this.
So again it is an effectivetechnique.
To ward of from having you software exploited, but at the same time the exploitswould be longer compile times then the run times.
The other option is to practice safecoding techniques.
Now this is easier said then done of course but there are a lot of,today most organizations have software development and software engineering practices, and ina lot of cases, I know that when I was in the industry, not all the jobs I had, at leastsome of the programming jobs I had we would program in dyads, so there would be two people.
Usually one person is coding the specs, so this dyad team is given a project and theyare supposed to code up something, and the specks define how the code operates.
One personis going to handle that while the other person is writing air checks and air codes to makesure that the code operates as it should.
Then what we would do after that, once everythingit was good to go we had to submit it to our project manager, and he would run his ownset of tests, his own battery tests to make sure things look good.
He would actually reviewthe code as well, we had documentation procedures.
So it was a very involved process, much differentthen your old school programmer who just sits at a computer in his house and just codesaway.
Now a days most organizations rely on some type of team work when it comes to coding.
But then again still easier said then done because you sacrifice a lot of time in doingthis.
Another technique is using operating systems that are very safe, the one I mentionedhere is the UNIX-like OS, it is considered to be the safest operating system availableonly one remote hole discovered in eight years, 2006, that is pretty safe.
Another policyis, you don't want code for success, you want to always code for ways that things go wrong.
Again this isn't a class where to teach you how to code or how to code properly, hopefullyif you guys are programmers or have programming experience you guys already know some techniques,so I don't want to spend too much time on it now.
I do have some background in the software,one of my first jobs as a programmer and this is way back in the late 90's I was given anassignment to add some code to some of these projects, and this was C code, and every Cfile already had the error messages and the error handling already completed.
So theyalready took care of that first.
Now of course I don't know if that technique makes me practiceas much as it probably should, if you guys are leaders of your own organization I woulddefinitely try to encourage that, because that really helps steer the project in theright way and helps to avoid bugs.
Another technique is graceful failures you alwaysdo something sensible when the unexpected occurs, and never assume the user will dothe right or the expected thing.
I thin if you guys have any background in coding youguys definitely understand that last thing.
The user will always find a way to essentiallyscrew up your code.
So it is always best to make sure that you expect that and you developyou code.
Compile-Time Defenses use language extensions and use of safe libraries.
In doingthis you can actually have range checks to determine the size of the buffer, howeverthe drawback with this is it can not be done for dynamic buffers.
So you can also use librarieswith safer versions.
If you have legacy systems this is going to be a little more difficultand maybe in some cases impossible or at least feasible.
Because old libraries can be problematic,you don't really is depended upon in order for it to function properly so you have tobe very careful with that.
You can always make new libraries but then you are goingto have to rewrite your source code, or scan it, that's very time consuming and you don'treally need all the unintended consequences.
Another solution is to create patches usingdynamic libraries and this is what you see a lot nowadays it doesn't require recompile.
Now we go to run-time defenses.
Most of the compile-time defenses require, other thenthe last one we talked about you to recompile your code.
Now run-time defenses are deployableas an OS update, so any time you guys have to update Windows or Linux, and I am not thatfamiliar with MAC's but I am pretty sure they have the update for that.
Anytime you updatethe OS you are using run-time defenses.
There are several options with this.
So one wayis called executable address space protection, this is where you block the processing theexecutable code on the stack.
So you are going to block the j.
compilers, the C nestedfunctions, Linux signal handlers which would all require special provisions of that nature.
Another run-time defense is address space randomization this is where your address spaceis randomized, so your buffer, your return space is randomized, and because you are doingit, it forces the attacker to guess the location of the buffer in memory, which is really difficultto do.
The next this is guard pages, so this is putting in unwriteable memory between elementsof the stack frame.
So this completes the presentation for chapter ten, again thesetechniques are all available and again in a different course offering you we go intomore detail about what that looks like.
The purpose of this is to just understand whatoptions you guys have to defend against buffer overflows.