Skip to content

Instantly share code, notes, and snippets.

@alryaz
Created February 7, 2025 08:02
Show Gist options
  • Save alryaz/819e1f9352a8b1c2ca0a1125ed850e34 to your computer and use it in GitHub Desktop.
Save alryaz/819e1f9352a8b1c2ca0a1125ed850e34 to your computer and use it in GitHub Desktop.
Supermicro IPMIView iKVM hook for Linux

Supermicro IPMIView iKVM hook for Linux

What it does?

It replaces the java in the build-in JRE so that it catches calls to iKVM.jar, and then opens a .jnlp file downloaded straight from the remote server.

What it doesn't?

Fix all issues with iKVM.

Installation

  • Install a javaws binary (for Ubuntu that would be: sudo apt install icedtea-netx)
  • Download the ipmiview-ikvm-hook.sh to your IPMIView directory (where IPMIView20 file resides)
  • Open the IPMIView directory in terminal (or cd to it from other place)
  • Run ./fix-ipmi.sh --install-to-ipmiview

Check if it works

  • Launch IPMIView normally
  • Connect to a server (save credentials; this is important)
  • Select the KVM Console tab
  • Press Launch KVM Console

@TODO@

  • Check SSL certificates when receiving the .jnlp
  • Normal exit codes
#!/bin/bash
if [[ $* == *--install-to-ipmiview* ]]; then
echo "Installing redirector into IPMIView..."
# Use current directory as default if it contains the IPMIView20.jar file
ipmiview_dir=$(find . -maxdepth 1 -name IPMIView20.jar -exec dirname {} \; | head -n1)
# Ask for the IPMIView directory in CLI
if [ -z "$ipmiview_dir" ]; then
read -p "Enter the IPMIView directory: " ipmiview_dir
fi
echo "Using the IPMIView directory: $ipmiview_dir"
# Check if IPMIView comes with JRE (jre/bin/java.real)
java_bin="$ipmiview_dir/jre/bin/java"
if [ ! -f "$java_bin" ]; then
echo "Error: IPMIView does not contain the JRE (./jre/bin/java)."
exit 1
fi
# Check if the script is already installed
if [ -f "$java_bin.real" ]; then
echo "Warning: possible existing script installation encountered!"
else
# Backup the original java binary
mv "$java_bin" "$java_bin.real"
fi
# Copy the script to the IPMIView directory
cp "$0" "$java_bin"
echo "Installation complete. You can now launch iKVM sessions IPMIView."
exit 0
fi
get_decrypted_password() {
local device_name="$1"
local ciphertext="$2"
# Ensure key is 16 bytes long (padded with null bytes if needed)
local key=$(printf "%s" "$device_name" | xxd -p | tr -d $'\n')
for (( length=${#key}; length<=32; length+=2 )); do
key="${key}00"
done
# Decrypt using AES-128-ECB with OpenSSL
local decrypted_password=$(echo -n "$ciphertext" | xxd -r -p | tr -d '\0' | openssl enc -d -nopad -aes-128-ecb -K "$key" -nosalt 2>/dev/null)
# Remove null byte padding
echo -n "$decrypted_password" | tr -d '\0'
}
# Check if it's the specific iKVM.jar call
if [[ "$*" == *"-jar iKVM.jar"* ]]; then
(
args=("$@")
for ((i = 0; i < ${#args[@]}; i++)); do
if [[ "${args[i]}" == "-jar" && "${args[i + 1]}" == "iKVM.jar" ]]; then
IP="${args[i + 2]}"
break
fi
done
echo "Intercepted iKVM.jar execution for IP $IP"
# Add your interception logic here
# Initialize username and password variables
USERNAME=""
PASSWORD_ENCRYPTED=""
PASSWORD=""
FILE_HOSTS="IPMIView.properties"
FILE_ACCOUNTS="account.properties"
# Check if the properties file exists and extract credentials
if [[ -f "$FILE_HOSTS" ]] && [[ -f "$FILE_ACCOUNTS" ]]; then
echo "Checking $FILE_HOSTS for entry..."
DEVICE_NAME=$(grep "=$IP:" "$FILE_HOSTS" | cut -d '=' -f1)
if [ ! -z "$DEVICE_NAME" ]; then
echo "Found device name: '$DEVICE_NAME'"
echo "Checking $FILE_ACCOUNTS for entry..."
# @TODO: fix regex escape
CREDENTIALS_LINE=$(egrep "^${DEVICE_NAME}=" "$FILE_ACCOUNTS")
if [ ! -z "$CREDENTIALS_LINE" ]; then
USERNAME=$(echo "$CREDENTIALS_LINE" | cut -d '=' -f2 | cut -d ',' -f1)
PASSWORD_ENCRYPTED=$(echo "$CREDENTIALS_LINE" | cut -d '=' -f2 | cut -d ',' -f2)
fi
fi
else
echo "Properties file not found. Skipping."
fi
if [ ! -z "$PASSWORD_ENCRYPTED" ]; then
echo "Decrypting password..."
PASSWORD=$(get_decrypted_password "$DEVICE_NAME" "$PASSWORD_ENCRYPTED")
echo "Decrypted password: $PASSWORD"
fi
# if [[ -z "$USERNAME" || -z "$PASSWORD" ]]; then
# # Ask for username and password
# if command -v zenity &>/dev/null; then
# USER_CREDENTIALS=$(zenity --forms --title="Supermicro KVM @ $IP" \
# --text="Enter your credentials for $IP_ADDRESS" \
# --add-entry="Username" \
# --add-password="Password")
# USERNAME=$(echo "$USER_CREDENTIALS" | head -n1)
# PASSWORD=$(echo "$USER_CREDENTIALS" | tail -n1)
# elif command -v kdialog &>/dev/null; then
# USERNAME=$(kdialog --inputbox "Enter your username for $IP:" "User")
# PASSWORD=$(kdialog --password "Enter your password:")
# else
# echo "No GUI prompt tool (zenity/kdialog) found. Exiting."
# exit 1
# fi
# fi
# Create a temporary file for cookies
COOKIE_FILE=$(mktemp)
OUTPUT_FILE=$(mktemp)
# # Ensure temporary files are deleted on exit
# trap "rm -f $COOKIE_FILE $OUTPUT_FILE" EXIT
if [ ! -z "$USERNAME" ] && [ ! -z "$PASSWORD" ]; then
# Perform login request
curl -k -c "$COOKIE_FILE" -X POST "https://$IP/cgi/login.cgi" -d "name=$USERNAME&pwd=$PASSWORD"
# Use stored cookies to access the redirect URL and save the output
curl -k -b "$COOKIE_FILE" "https://$IP/cgi/url_redirect.cgi?url_name=ikvm&url_type=jwsk" -o "$OUTPUT_FILE"
# Print the output file location (for debugging)
echo "Downloaded file saved at: $OUTPUT_FILE ($COOKIE_FILE)"
javaws "$OUTPUT_FILE"
else
echo "No credentials provided"
fi
exit 1
) >>/tmp/java_wrapper.log 2>&1 || exit 1
fi
# Forward all other calls to the original java binary
exec ./jre/bin/java.real "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment