User Tools

Site Tools


session:07

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
session:07 [2018/07/02 09:06]
Dennis-Adrian PLOSCEANU (25612) [10. Tutorial: Use the stack buffer for storing the shellcode]
session:07 [2020/07/19 12:49] (current)
Line 1: Line 1:
-====== 0x07. Shellcodes ======+====== 0x06. Shellcodes ======
  
 ===== Resources ===== ===== Resources =====
  
-{{:public:sess-09_2015.pdf|Slides}}+To work this session, first clone/update [[https://github.com/hexcellents/sss-exploit|the repository]] and navigate to the ''07-shellcodes'' folder.
  
-[[http://security.cs.pub.ro/summer-school/res/arc/07-shellcodes-skel.zip|Tasks archive]] +Other resources
- +  [[http://shell-storm.org/shellcode/|Shellcode repository]]
-[[http://shell-storm.org/shellcode/|Shellcode repository]]+
  
 ===== Initial info ===== ===== Initial info =====
Line 15: Line 14:
 An attacker will typically employ information leak attacks to extract address and values, would use buffer overflow attacks to overwrite sensible data, inject shellcodes and execute them by modifying the program control flow and others. The way these steps are woven together depends on the vulnerability and the program specifics. The attacker is the one that needs to find the best way to tie these steps together to exploit the vulnerability. An attacker will typically employ information leak attacks to extract address and values, would use buffer overflow attacks to overwrite sensible data, inject shellcodes and execute them by modifying the program control flow and others. The way these steps are woven together depends on the vulnerability and the program specifics. The attacker is the one that needs to find the best way to tie these steps together to exploit the vulnerability.
  
-When doing a shellcode-based attack, the attacker needs to execute code from that shellcode into memory. For that to happen, the attacker needs to run three steps: 
-  - The attacker needs to create the shellcode. This is typically done by writing assembly code and then assembling that code into binary code. 
-  - The attacker places the shellcode inside the vulnerable process address space. This is done by feeding the binary shellcode as input: standard input, program arguments, reading from sockets, environment variables. 
-  - The attacker needs to trigger the execution of the shellcode. This means altering the program control flow by typically altering a function return address or a function pointer to point to the start of the shellcode. 
- 
-While the above three steps are not necessarily chronological, one can identify each of them as parts of a shellcode-based attack. 
 ===== Shellcode ===== ===== Shellcode =====
  
Line 328: Line 321:
 The ''hexdump'' command, with the given arguments prints each byte with a format such as ''\xAB'' where ''AB'' is the two nibbles hexadecimal representation of the number. The ''hexdump'' command, with the given arguments prints each byte with a format such as ''\xAB'' where ''AB'' is the two nibbles hexadecimal representation of the number.
  
-All of the above steps are incorporated in the ''Makefile'' file in the ''gen-hello-shellcode/'' subfolder. For getting the binary shellcode file, we would issue the command:<code>+All of the above steps are incorporated in the ''Makefile'' file in the ''04-tutorial-gen-hello-shellcode/src/'' subfolder. For getting the binary shellcode file, we would issue the command:<code>
 $ make $ make
 nasm -o shellcode.bin shellcode.S nasm -o shellcode.bin shellcode.S
Line 352: Line 345:
  
 Let's do the first one. A rather simple approach would be to add the ''ret'' instruction at the end of the shellcode. We do that  Let's do the first one. A rather simple approach would be to add the ''ret'' instruction at the end of the shellcode. We do that 
-by adding a ''ret'' instruction at the end of the ''shellcode.S'' file in the ''gen-hello-shellcode/'' subfolder in the tasks archive:<code>+by adding a ''ret'' instruction at the end of the ''shellcode.S'' file in the ''04-tutorial-gen-hello-shellcode/'' subfolder in the tasks archive:<code>
 $ cat shellcode.S  $ cat shellcode.S 
 BITS 32 BITS 32
Line 368: Line 361:
 In the above listing we can see the addition of the ''ret'' instruction to the shellcode. In the above listing we can see the addition of the ''ret'' instruction to the shellcode.
  
-We now need to extract the shellcode byte string and replace in the vulnerable program (''vuln.c''). We do that by using the ''Makefile'' file in the ''gen-hello-shellcode/'' subfolder:<code>+We now need to extract the shellcode byte string and replace in the vulnerable program (''vuln.c''). We do that by using the ''Makefile'' file in the ''04-tutorial-gen-hello-shellcode/'' subfolder:<code>
 $ make print $ make print
 nasm -o shellcode.bin shellcode.S nasm -o shellcode.bin shellcode.S
 \x68\x21\x0a\x00\x00\x68\x6f\x72\x6c\x64\x68\x6f\x2c\x20\x57\x68\x48\x65\x6c\x6c\xba\x0e\x00\x00\x00\x89\xe1\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xcd\x80\xc3 \x68\x21\x0a\x00\x00\x68\x6f\x72\x6c\x64\x68\x6f\x2c\x20\x57\x68\x48\x65\x6c\x6c\xba\x0e\x00\x00\x00\x89\xe1\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xcd\x80\xc3
 </code> </code>
-We now replace the above byte string shellcode in the ''vuln,c'' file in the ''hello-shellcode/'' subfolder:<code>+We now replace the above byte string shellcode in the ''vuln,c'' file in the ''03-tutorial-hello-shellcode/'' subfolder:<code>
 $ cat vuln.c  $ cat vuln.c 
 [...] [...]
Line 477: Line 470:
  
 Our goal is to properly set the stack pointer before executing ''ret'' to make a successful return to the ''main'' function. Our goal is to properly set the stack pointer before executing ''ret'' to make a successful return to the ''main'' function.
- 
 ==== 04.b. Challenge: Fix ret instruction in shellcode ==== ==== 04.b. Challenge: Fix ret instruction in shellcode ====
  
Line 565: Line 557:
 The shellcode was successful and we managed to obtain a new shell. The shellcode was successful and we managed to obtain a new shell.
  
-==== 07.a. Challenge: Update the execve shellcode to work properly ====+==== 05.a. Challenge: Update the execve shellcode to work properly ====
  
-In the ''bad-execve-shellcode/'' in the lab archive you can find of version of the ''vuln.c'' program that uses the execve-based shellcode from above. Except there are some random integer operations in there. If you compile and run the program you get a //Segmentation fault// error:<code>+In the ''05-tutorial-bad-execve-shellcode/'' in the lab archive you can find of version of the ''vuln.c'' program that uses the execve-based shellcode from above. Except there are some random integer operations in there. If you compile and run the program you get a //Segmentation fault// error:<code>
 $ make $ make
 cc -m32 -Wall -g   -c -o vuln.o vuln.c cc -m32 -Wall -g   -c -o vuln.o vuln.c
Line 588: Line 580:
 In the ''vuln.c'' program we used so far, we initialize the ''func_ptr'' function pointer with the "suitable" shellcode address. This is the triggering phase for the shellcode-based attack but that's far from common in programs. What is usually the case is that a buffer is overflowed to overwrite a suitable address. In the ''vuln.c'' program we used so far, we initialize the ''func_ptr'' function pointer with the "suitable" shellcode address. This is the triggering phase for the shellcode-based attack but that's far from common in programs. What is usually the case is that a buffer is overflowed to overwrite a suitable address.
  
-In the ''overflow-task-and-shellcode/'' there is a ''vuln.c'' source code file. In the file we use ''strcpy()'' to copy the first program argument (''argv[1]'') in a local buffer variable named ''buffer''. If we give a string longer than the buffer length (''32'') we would do a buffer overflow and be able to overwrite the ''func_ptr'' function pointer located just above the buffer. The ''vuln.c'' file is using a proper NUL-free, always-works shellcode that spawns a shell.+In the ''06-tutorial-overflow-and-shellcode/'' task there is a ''vuln.c'' source code file. In the file we use ''strcpy()'' to copy the first program argument (''argv[1]'') in a local buffer variable named ''buffer''. If we give a string longer than the buffer length (''32'') we would do a buffer overflow and be able to overwrite the ''func_ptr'' function pointer located just above the buffer. The ''vuln.c'' file is using a proper NUL-free, always-works shellcode that spawns a shell.
  
 Our goal is to provide the proper command line argument in order to overflow the ''buffer'' variable and overwrite the ''func_ptr'' function pointer with the address of the ''shellcode'' variable storing the byte string shellcode. Our goal is to provide the proper command line argument in order to overflow the ''buffer'' variable and overwrite the ''func_ptr'' function pointer with the address of the ''shellcode'' variable storing the byte string shellcode.
Line 836: Line 828:
 Let's now get to the next step towards making the attack more realistic. We would rarely have the benefit of a function pointer (such as ''func_ptr'') being conveniently placed after a buffer in memory. What we usually aim to do is overwrite the function return address, point that to the shellcode (in our case the ''shellcode'' variable) and profit! Let's now get to the next step towards making the attack more realistic. We would rarely have the benefit of a function pointer (such as ''func_ptr'') being conveniently placed after a buffer in memory. What we usually aim to do is overwrite the function return address, point that to the shellcode (in our case the ''shellcode'' variable) and profit!
  
-Inside the ''overwrite-return-address/'' subfolder in the tasks archive you will find a vulnerable source code file (''vuln.c''). This file has a buffer overflow vulnerability through the call of ''strcpy()'' inside the ''do_nothing_successfully()'' function.+Inside the ''06-challenge-overwrite-return-address/'' subfolder in the tasks archive you will find a vulnerable source code file (''vuln.c''). This file has a buffer overflow vulnerability through the call of ''strcpy()'' inside the ''do_nothing_successfully()'' function.
  
 Exploit this vulnerability by causing a buffer overflow of the ''buffer'' variable and overwriting the return address of the ''do_nothing_successfully()'' function to point to the shellcode (i.e. the address of the ''shellcode'' variable). Exploit this vulnerability by causing a buffer overflow of the ''buffer'' variable and overwriting the return address of the ''do_nothing_successfully()'' function to point to the shellcode (i.e. the address of the ''shellcode'' variable).
Line 851: Line 843:
 Passing information as a program argument is one of the way to provide input to the vulnerable program. Another way is through standard input. Let's use standard input to cause a buffer overflow and run the shellcode (again inside the ''shellcode'' variable). Passing information as a program argument is one of the way to provide input to the vulnerable program. Another way is through standard input. Let's use standard input to cause a buffer overflow and run the shellcode (again inside the ''shellcode'' variable).
  
-Inside the ''use-standard-input/'' subfolder in the tasks archive you will find a vulnerable source code file (''vuln.c'') with a similar vulnerability to the one above: the use of ''strcpy()'' to cause a buffer overflow inside the ''do_nothing_successfully()'' function. There are several differences: +Inside the ''07-challenge-use-standard-input/'' subfolder in the tasks archive you will find a vulnerable source code file (''vuln.c'') with a similar vulnerability to the one above: the use of ''strcpy()'' to cause a buffer overflow inside the ''do_nothing_successfully()'' function. There are several differences: 
-* the initial data is now read from standard input using ''fgets()'' +  * the initial data is now read from standard input using ''fgets()'' 
-* the buffer we are going to overwrite is now 70 characters long +  * the buffer we are going to overwrite is now 70 characters long 
-* we've added an extra local variable before the buffer to make it a bit more challenging to determine the return address+  * we've added an extra local variable before the buffer to make it a bit more challenging to determine the return address
  
 Similarly to the task above, exploit the vulnerability by causing a buffer overflow of the ''buffer'' variable and overwriting the return address of the ''do_nothing_successfully()'' function to point to the shellcode (i.e. the address of the ''shellcode'' variable). Similarly to the task above, exploit the vulnerability by causing a buffer overflow of the ''buffer'' variable and overwriting the return address of the ''do_nothing_successfully()'' function to point to the shellcode (i.e. the address of the ''shellcode'' variable).
Line 883: Line 875:
 Now that we know how to cause a buffer overflow and trigger the execution of the shellcode, let's make another step into making things more realistic by injecting the shellcode into the program. Up until now the shellcode was conveniently stored in the ''shellcode'' variable, which is fairly unrealistic. Now that we know how to cause a buffer overflow and trigger the execution of the shellcode, let's make another step into making things more realistic by injecting the shellcode into the program. Up until now the shellcode was conveniently stored in the ''shellcode'' variable, which is fairly unrealistic.
  
-Inside the ''fill-global-variable/'' subfolder in the tasks archive we have the ''vuln.c'' program that we want to exploit. Our aim is to inject and store the shellcode in the ''resident_data'' global variable. The shellcode will be stored in the ''resident_data'' global variable, while the attack payload (consisting of the ''A'' byte padding and the address of the ''resident_data'' variable) will be stored in the ''input_buffer'' variable and the in the ''buffer'' variable; both are provided through standard input.+Inside the ''07-challenge-fill-global-variable/'' subfolder in the tasks archive we have the ''vuln.c'' program that we want to exploit. Our aim is to inject and store the shellcode in the ''resident_data'' global variable. The shellcode will be stored in the ''resident_data'' global variable, while the attack payload (consisting of the ''A'' byte padding and the address of the ''resident_data'' variable) will be stored in the ''input_buffer'' variable and the in the ''buffer'' variable; both are provided through standard input.
  
 Similarly to the task above, exploit the vulnerability by injecting the ''shellcode'' through stadard input in the ''resident_data'' global variable, causing a buffer overflow of the ''buffer'' variable and overwriting the return address of the ''do_nothing_successfully()'' function to point to the shellcode (i.e. the address of the ''resident_data'' global variable). Similarly to the task above, exploit the vulnerability by injecting the ''shellcode'' through stadard input in the ''resident_data'' global variable, causing a buffer overflow of the ''buffer'' variable and overwriting the return address of the ''do_nothing_successfully()'' function to point to the shellcode (i.e. the address of the ''resident_data'' global variable).
Line 902: Line 894:
 In the above task we were in luck that we had two buffers and both were filled by feeding input to the vulnerable program (in our case, through standard input). But that's not usually the case. Let's consider the situation where the ''resident_data'' buffer is not part of our program. Could an attack be possible? Yes, of course: we can use the ''input_buffer'' variable both for storing the shellcode and the payload for causing the buffer overflow. This data will then be copied to the ''buffer'' variable and we'll profit! In the above task we were in luck that we had two buffers and both were filled by feeding input to the vulnerable program (in our case, through standard input). But that's not usually the case. Let's consider the situation where the ''resident_data'' buffer is not part of our program. Could an attack be possible? Yes, of course: we can use the ''input_buffer'' variable both for storing the shellcode and the payload for causing the buffer overflow. This data will then be copied to the ''buffer'' variable and we'll profit!
  
-In the ''shellcode-in-stack-buffer/'' subfolder in the tasks archive the ''vuln.c'' program has the ''strcpy()''-based vulnerability identical to the above tasks but no "helper" buffer. We'll have to use the ''buffer'' variable both for storing the shellcode and the payload for causing the buffer overflow.+In the ''08-tutorial-shellcode-in-stack-buffer/'' subfolder in the tasks archive the ''vuln.c'' program has the ''strcpy()''-based vulnerability identical to the above tasks but no "helper" buffer. We'll have to use the ''buffer'' variable both for storing the shellcode and the payload for causing the buffer overflow.
  
 In short, we'll have to get to a situation where we overwrite the return address of ''do_nothing_successfully()'' function with the start address of the ''buffer'' variable, such that we'll execute code from the ''buffer'' variable. The contents of the ''buffer'' variable will start with the shellcode we've used so far. We'll feed that as input to the buffer. In short, we'll have to get to a situation where we overwrite the return address of ''do_nothing_successfully()'' function with the start address of the ''buffer'' variable, such that we'll execute code from the ''buffer'' variable. The contents of the ''buffer'' variable will start with the shellcode we've used so far. We'll feed that as input to the buffer.
Line 1165: Line 1157:
 Run the attack on the **same** terminal you used to generate the segmentation fault and find out the ''esp'' address. It's generally a very good idea to run the vulnerable program under ''env -i''. Run the attack on the **same** terminal you used to generate the segmentation fault and find out the ''esp'' address. It's generally a very good idea to run the vulnerable program under ''env -i''.
 </note> </note>
-==== 10.a. Challenge: Use stack buffer for storing the shellcode on another program ====+==== 08.a. Challenge: Use stack buffer for storing the shellcode on a new program ====
  
-Let's to a similar task as the one above. In the ''shellcode-in-stack-buffer-2/'' subfolder from the tasks archive there is a slightly updated vulnerable file. Use the same vulnerability as in the task above to obtain a shell.+Let's to a similar task as the one above. In the ''08-challenge-shellcode-in-stack-buffer-2/'' subfolder from the tasks archive there is a slightly updated vulnerable file. Use the same vulnerability as in the task above to obtain a shell.
  
-===== Tasks ===== +===== Bonus =====
- +
-{{ :session:tasks_07.tar.gz |}}+
  
 <note warning> <note warning>
Line 1181: Line 1171:
  
  
-==== Call trampoline ====+==== 09. Challenge: Call trampoline ====
  
 Another way of working with strings is to declare them as data inside the shellcode. However, if you do this, you won't know their address at compile-time. You have to obtain the address at runtime by abusing the call instruction, like this: Another way of working with strings is to declare them as data inside the shellcode. However, if you do this, you won't know their address at compile-time. You have to obtain the address at runtime by abusing the call instruction, like this:
Line 1198: Line 1188:
 Write the shellcode that prints "Hello, world!" using this method. Write the shellcode that prints "Hello, world!" using this method.
  
-==== Exploit with known buffer address ====+==== 10. Challenge: Exploit with known buffer address ====
  
 <note important> <note important>
Line 1204: Line 1194:
 </note> </note>
  
-Switch to the //1-exact// directory.+Switch to the //10-challenge-known-buffer// directory.
 You'll have to exploit the vulnerable binary found there and get a shell. You'll have to exploit the vulnerable binary found there and get a shell.
  
Line 1219: Line 1209:
   * you run the program with an empty environment, using env -i (Example: $ env -i /path/to/vuln)   * you run the program with an empty environment, using env -i (Example: $ env -i /path/to/vuln)
   * when running under gdb you also run with an empty environment, by running "set exec-wrapper env -i" before executing the "run" command   * when running under gdb you also run with an empty environment, by running "set exec-wrapper env -i" before executing the "run" command
- 
  
session/07.1530511590.txt.gz · Last modified: 2018/07/02 09:06 by Dennis-Adrian PLOSCEANU (25612)