INFORMATION SECURITY - PRACTICAL ASSESSMENT - BASICS IN BUFFER EXPLOITATION GRENOBLE INP ENSIMAG http://www.ensimag.fr COMPUTER SCIENCE 3RD YEAR IF-MMIS - 1ST SEMESTER, 2011 Lecturers: Fabien Duchene - Karim Hossen firstname.lastname [ at ] imag.fr NOTE: Practical assessment regarding the course we had on Thu. 22th, September 2011 and regarding the chapter 1.1. They are due for Tuesday 27th, September 2011 23pm59. This practical assessment will give you some methods used by security professionals to exploit vulnerabilities. This is an introduction to such exploitation techniques. The second part will then focus on x86 binary exploitation. functionalities, you will have to exploit two vulnerabilities. After a brief exploration of the debugger Goals: Inspect a program thanks to a debugger (in that case the Immunity Debugger) Obtain a basic knowledge in buffer exploitation 1 Requirements: hypervisor and virtual machine image Download the hypervisor for your platform from http://www.virtualbox.org/wiki/downloads Install it on your laptop Download the virtual machine image from http://car-online.fr/en/files// import it into VirtualBox (follow the instructions at https://ensiwiki.ensimag.fr/index.php/ VirtualBox-) save a snapshot of the virtual machine (in its turned off state) launch the virtual machine log-on using those credentials (username / password): user / user (for -2011-2012-TP1-application exploitation.7z) or user / empty password (for TP1 - Exploitation.ova) 2 Binary exploitation 2.1 Let us discover the Immunity Debugger Launch the debugger
2 Open ex0.exe and eventually make the CPU view visible. Check the window title to see if you are in the ex0.exe module. If not, open the view executable modules, and choose ex0.exe. 1. (a) Describe in few lines the content of each 5 part of the CPU view (b) One instruction is selected, what is it and how it is generally called? (c) Where does the debugger find his address? 2. (a) Lets run the program (F9 keyboard shortcut). What just happened? (Hint : status bar) (b) What is the purpose of the first instructions block at the beginning of the program? Is that block our main function? 3. (a) Now we want to set a breakpoint. Use Right click > Search for > All intermodular call > printf to find the printf. The main function, for little program without a lot of libraries is often located few instructions after the entry point. Alternatively you also can scroll down till you see the printf call. At which address is the printf located? (b) Set the breakpoint (F2), restart and run the program (Ctrl+F2). The program is now stopped at the printf. How many arguments a printf function is supposed to have? (c) Locate and describe them on the stack part of the CPU view. (d) A debugger has a control on the control flow of a program it has loaded. It also is able to manage the data flow. Now let us modify the text to be printed. Find two ways to modify the text which will be printed and briefly describe them. Use at least one of these methods to change the text. (e) It is also possible to run the program step-by-step using Step into (F7) and Step over (F8) function. What is the difference between these functions? 4. Step over until the instruction at the address 0x00401340. What is this instruction? What is its purpose? Resume the execution of the program by pressing F9 and let it terminated. You are now sufficiently familiar with that debugger to perform the very next sections. 2.2 Bin100 - It is sometimes too small In order to help you for your first exploitation, we did provide you some few hints regarding the vulnerability you will exploit for this exercise. It is a classic simple - and unfortunately still possible in several today softwares - stack overflow assuming that DEP and ASLR are not activated. This is the perfect example your always have been dreaming of to exploit! 2.2.1 Controlling the flow 5. (a) Briefly remember ( 4 lines) what is a stack-based overflow and how can we exploit it. (b) Run the program (standalone, without the debugger attached) and play with it. Explain what is the purpose of that executable. (c) Open (in text editor) the script sendstring.py. What is the use of it? With the script, trigger an overflow. What happened when the overflow occured?
3 6. Now, we need more detailed information/impact about the overflow on the program. Run Immunity Debugger, open ex1.exe and run it. Trigger the overflow. The program will throw an exception and the debugger will catch it. Now the execution is paused at the instruction that triggered that overflow. (a) What is that instruction? (b) Describe the purpose of that instruction and why an overflow could happen here. (c) Now, have a look the registers which partly describe the state of the program (because the memory state is also important). What do you notice? What is the purpose of that (these) register(s) on which you just noticed something? (d) What is the content of that register? Change the string you send to the program, and restart it and see if the content of the register have changed. We seem to control the register. What does it mean? (e) To have a stable control on that register, we should know how many bytes we must send to overwrite the register. Some people already thought about it and produced 2 small and useful ruby scripts : pattern create and pattern offset These scripts are available in Metasploit. Open the system console of Metasploit. 1 >ruby t o o l s \ p a t t e r n c r e a t e. rb Usage : p a t t e r n c r e a t e. rb length [ set a ] [ set b ] [ set c ] (f) By reading and testing these two scripts, describe in what extend they could be useful. (g) Using pattern offset, how many bytes are necessary before overwriting the register? Let s call this value OFFSET EIP. We will have to send something following this format [padding][value of register] with size([padding]) = OFFSET EIP Test with aaaaa...aaaaabcd and check with the debugger if there is an attempt to execute instruction at the address ABCD (h) Now we really control the control flow because we almost be able to put any value in this register. Explain why the word almost is used in the previous sentence? 2.2.2 Controlling the flow to our code To prove that we control the control flow, you should be able to execute arbitrary codes. This code will be in the string that you send to the program. Codes are in string?? Don t forget that there are no type notions here, your string will be in memory, and a string is set of bytes like instructions. This kind of code is called shellcode because, most of time we use it to have a shell (terminal) on the victim system. There are a lot of shellcodes, to do a lot of things, show a messagebox, run an executable, download and execute something... We will use the simple messagebox shellcode. Technics to write a shellcode are out of the scope of this practical assesment, we will use Metasploit to generate one for us. Thanks to it :) Open the Metasploit system console. We use the S option to display a summary (or help). > ruby msfpayload windows/ messagebox S 2 Name : Windows MessageBox Module : payload / windows/ messagebox 4 Version : 13403 l a t f o r m : Windows 6 Arch : x86 Needs Admin : No 8 Total size : 270 Rank : Normal 10...
4 7. (a) What are the options we have for the message box? Metasploit can output the shellcode with different format, R for raw, C, P for Perl... As we use Python, we can take the C format which is closed to Python. This is an example : >ruby msfpayload windows/ messagebox EXITFUNC=p r o c e s s ICON=INFORMATION TEXT= Blabla TITLE= H e l l o C 2... OK, we have our shellcode, in C format. Now we have to redirect the control flow to our shellcode. Our shellcode will be located in memory because it will be in the string you send to the program. Copy your shellcode at the beginning of the string. Now, we can consider the string as a payload, so call it payload. Your payload should follow this format above [shellcode][padding][value of register] with size([shellcode][padding]) = OFFSET EIP From now, we will use the script exploit.py to send the string. Set padding to : \x90 xoffset EIP Set jmp to : abcd Set shellcode to : your shellcode previously generated 8. (a) Send your payload to the program under the debugger, it will stop at the exception. Locate your shellcode. Where is it? (b) Jumping to a fix address in the stack could be problematic, because the two first bytes of stack address can change. Look the register. Do you find something interesting? Why? So we need to jump to the address in this register. Let find a jmp esp instruction. Open the view executable modules. What we can find in this view? (don t answer executable modules :)) Choose the module kernel32.dll, go to the CPU view. You should see the instruction of kernel32.dll. (c) Now, we will use the debugger to find a jmp esp. Right click in the instruction panel > Search for > Command : jmp esp What is the address of the jmp esp? Now, you should have a good payload following this format : [shellcode][padding][@jmp esp] 2.2.3 Encoding the shellcode 9. (a) Test your previously created payload. Does it works?... ok. Let us find the problem. Use the debugger to locate your shellcode in the stack. Compare it from the original shellcode. (b) The beginning of the shellcode is correctly copied but there is an error after few bytes. What bytes was not copied successfully? In fact, the program can modify some byte of the strings and most of time its special character like \r, \n and space. Of course, there is a technic to bypass these modifications. We just need to avoid this character in our shellcode :) For that, there are encoders which encode the shellcode in a format which doesn t have chosen characters. And again, its module is available in Metasploit. To use it, you will send the raw shellcode to the encoder and tell him to output C again and removing some characters. The command become : > 2 ruby msfpayload windows/ messagebox EXITFUNC=p r o c e s s ICON=INFORMATION TEXT= Blabla TITLE= H e l l o R ruby msfencode a x86 b \ x00 \ x0a \ x0d t c Now retry your payload. If it work : \o/
5 2.2.4 With DEP? 10. Active DEP and test your payload again. It should work. What?? Indeed, you just activated a thing called by Microsoft Software DEP. it is a good memory protection mechanism but not the real DEP. 2.2.5 With DEP 11. To active the real DEP, you have to modify the configuration of the virtual machine to enable the PAE mode (cf. course) Now test your payload again. It should lead to an application crash, with a message from windows. That s the real DEP. Well done for those who successfully finished this part. It is however is not yet the end :) 2.3 Bin200 - Where are my parameters?! For your second exploitation, you have to exploit a vulnerability in the format string. 2.3.1 Reminders 12. (a) Briefly describe what a format string vulnerability is and compare it to stack based buffer overflow. Which one is the most powerful? Why? (b) Locate the vulnerable function and start playing with its parameters Print the content of the first 40 bytes on the stack. Why the printed result doesn t have 80 bytes exactly? Use the debugger to check. 2.3.2 Control WHERE you want to write (ECX) Let s call the string the content of input.txt. In order to exploit, we first need to reach the end of our string. From now, we will use the script exploit.py to build the input.txt. Set address to : abcd => This is where we will write. We use abcd because we don t yet where to write. Set write to : %x => Use to print (%x) the address or write (%n) to the address Set moves to : %x *30 => Use to moves on the stack (30*4 bytes) We know that %x read 4 bytes, but if we want to control where we are on the stack accurately, we need something else to move at the byte scale. This is the goal of the padding value. 13. (a) Now play with the number of moves until you recognize the address. Remember you are printing bytes in hexadecimal and in Little-endian. Remember after hexadecimal stuff, you should see the abcd string of course. (We put it in the printf) (b) How abcd should be printed? Let s call it AABBCCDD You should see :...AABBCCDDabcd... AABBCCDD will be replaced later by the address to overwrite. Now replace the write by an %n and check in the debugger if there is an attempt to write at the address AABBCCDD. Now we control where we want to write. You can replace AABBCCDD by something else to check. Note the value of EAX register, we will need it in the next part.
6 2.3.3 Control WHAT you write (EAX register) 14. (a) Remember what the function of %n in printf is The register EAX is used to store this number. Let s call EAX the value of EAX register. We will need to write 1000 (3e8 in hexadecimal) at the address of target to pass the test. We just have to write 3e8-EAX bytes before the %n. (b) We can put a lot of padding in the string to do that. Why it is not a good way? (c) Use the printf reference to find how we can print a lot of bytes using a short string (Think simple) Set write to : %x, we are still testing, no need to write. Set value to : %#x replacing the # by the result of 3e8-EAX But the length of the string have changed again, we need to adjust the padding or moves. Set moves to : 32 Set padding to : m, m or another character except \x00 You should see :...64636261abcd... again. Now we are ready to exploit! 2.3.4 Exploitation 15. (a) What is the address of the target variable? (b) There is a null byte in it and we use fgets. Is it a problem? Why? Replace the address (abcd) by target address in little-endian with this syntax \ x6c \ x f f \ x22 Remember that since the new address contains 1 character less than abcd, we need to increment that value by 1. You should see Well done! :)