diff --git a/README.md b/README.md index 62fb1aa..54853ee 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,48 @@ # TryHackMe OpenVPN Troubleshooting Script -### Script to troubleshoot connectivity to the TryHackMe network using OpenVPN on Linux. +Script to troubleshoot connectivity to the TryHackMe network using OpenVPN on Linux. -Usage: +## Usage -- Download the `thm-troubleshoot` script. Saving it to the same place as your OpenVPN configuration pack (`~/Downloads` by default) is advisable, but not essential. -- In your Linux terminal, make the script executable with `chmod +x `. If you downloaded the script to your Downloads folder, this will be `chmod +x ~/Downloads/thm-troubleshoot`. -- Run the script by typing `sudo` followed by the path to the script into your terminal and pressing enter. If the script is in your downloads, it will be the following command: `sudo ~/Downloads/thm-troubleshoot`. -- The script will instruct you on how to proceed from there. +1. Download the `thm-troubleshoot` script +2. Save it in the same folder as your `.ovpn` config file (or provide the path when prompted) +3. Make it executable: `chmod +x thm-troubleshoot` +4. Run with sudo: `sudo ./thm-troubleshoot` +5. Follow the on-screen instructions -**Disclaimer -- this script was originally designed to work on Kali, Ubuntu, or other Debian based systems to solve basic OpenVPN errors. If you're using a non-recommended distribution then it is assumed that you can also troubleshoot these errors manually** +**Check version:** `./thm-troubleshoot --version` -**March 2023 update -- the script has been updated to support Arch linux users! With that said, Arch is still a non-recommended distribution. Using this flavor of linux is almost certainly guaranteed to lead to other more specific connection issues that this script won't be able to cover, ultimately taking away from the learning experience at TryHackMe. Use it at your own discretion.** +## Supported Distros -Any question or issues (or if connectivity problems persist), please ask in the [TryHackMe Discord server](https://discord.gg/F7ERYzz). -Happy Hacking! +- **Debian/Ubuntu** (apt) +- **Arch Linux** (pacman) +- **Fedora/RHEL** (dnf) + +Other distributions should work but may require manual OpenVPN installation. + +## What This Script Checks + +- Internet connectivity +- OpenVPN installation (offers to install if missing) +- VPN connection and tun0 interface +- Correct IP range (192.168.x.x for current infrastructure) +- Multiple VPN connection conflicts +- MTU issues +- Routes to target VMs (10.x.x.x) + +## Known Issues + +### OpenVPN 2.5 (Ubuntu 22.04 and older) +The new TryHackMe configs use inline `` which requires OpenVPN 2.6+. The script will detect this and provide solutions. + +### Network Rooms +This script does **not** support Network room VPNs (rooms with a network diagram at the top). Those use separate configs downloadable from the [Access page](https://tryhackme.com/manage-account/access). + +## Links + +- [TryHackMe Access Page](https://tryhackme.com/manage-account/access) - Download VPN configs +- [TryHackMe Discord](https://discord.gg/tryhackme) - Get help from the community + +--- + +**Note:** Make sure your VPN server region matches your target VM region in the Access page settings. diff --git a/README_RU.md b/README_RU.md index 3203deb..872c6ad 100644 --- a/README_RU.md +++ b/README_RU.md @@ -1,13 +1,48 @@ # TryHackMe Скрипт устранения неполадок OpenVPN -### Сценарий для устранения неполадок при подключении к сети TryHackMe с помощью OpenVPN на Linux. -Использование: -* Загрузите скрипт `thm-troubleshoot`. Желательно сохранить его в том же месте, где находится ваш пакет конфигурации OpenVPN (по умолчанию `~/Downloads`), но не обязательно. -* В терминале Linux сделайте скрипт исполняемым с помощью `chmod +x `. Если вы загрузили скрипт в папку Downloads, это будет chmod +x ~/Downloads/thm-troubleshoot. -* Запустите сценарий, набрав в терминале команду `sudo`, затем путь к сценарию и нажав клавишу Enter. Если скрипт находится в загружаемых файлах, это будет следующая команда: `sudo ~/Downloads/thm-troubleshoot`. -* Сценарий проинструктирует вас о том, как действовать дальше. +Скрипт для устранения неполадок при подключении к сети TryHackMe с помощью OpenVPN на Linux. -**Отказ от ответственности -- этот скрипт предназначен для работы на Kali, Ubuntu или других системах на базе Debian для решения основных ошибок OpenVPN. Если вы используете не рекомендованный дистрибутив, предполагается, что вы можете устранить эти ошибки вручную.** +## Использование -Любые вопросы или проблемы (или если проблемы с подключением сохраняются), пожалуйста, задавайте на сервере [TryHackMe Discord server](https://discord.gg/F7ERYzz). -Счастливого взлома! \ No newline at end of file +1. Загрузите скрипт `thm-troubleshoot` +2. Сохраните его в той же папке, что и ваш `.ovpn` конфиг (или укажите путь при запросе) +3. Сделайте его исполняемым: `chmod +x thm-troubleshoot` +4. Запустите с sudo: `sudo ./thm-troubleshoot` +5. Следуйте инструкциям на экране + +**Проверить версию:** `./thm-troubleshoot --version` + +## Поддерживаемые дистрибутивы + +- **Debian/Ubuntu** (apt) +- **Arch Linux** (pacman) +- **Fedora/RHEL** (dnf) + +Другие дистрибутивы должны работать, но могут потребовать ручной установки OpenVPN. + +## Что проверяет скрипт + +- Подключение к интернету +- Установку OpenVPN (предложит установить, если отсутствует) +- VPN-подключение и интерфейс tun0 +- Правильный диапазон IP (192.168.x.x для текущей инфраструктуры) +- Конфликты нескольких VPN-подключений +- Проблемы с MTU +- Маршруты к целевым ВМ (10.x.x.x) + +## Известные проблемы + +### OpenVPN 2.5 (Ubuntu 22.04 и старше) +Новые конфиги TryHackMe используют inline ``, что требует OpenVPN 2.6+. Скрипт обнаружит это и предложит решения. + +### Сетевые комнаты (Network Rooms) +Этот скрипт **не поддерживает** VPN сетевых комнат (комнаты с сетевой диаграммой вверху). Они используют отдельные конфиги, доступные на [странице доступа](https://tryhackme.com/manage-account/access). + +## Ссылки + +- [Страница доступа TryHackMe](https://tryhackme.com/manage-account/access) - Скачать VPN конфиги +- [TryHackMe Discord](https://discord.gg/tryhackme) - Получить помощь от сообщества + +--- + +**Примечание:** Убедитесь, что регион вашего VPN-сервера соответствует региону целевой ВМ в настройках страницы доступа. diff --git a/tests/test-thm-troubleshoot.sh b/tests/test-thm-troubleshoot.sh new file mode 100644 index 0000000..05527b7 --- /dev/null +++ b/tests/test-thm-troubleshoot.sh @@ -0,0 +1,250 @@ +#!/bin/bash +# Test script for thm-troubleshoot +# Run on a test VM (Ubuntu) with a valid TryHackMe .ovpn config +# +# Prerequisites: +# - Place your .ovpn config as: ./test.ovpn +# - Run from the repo root: sudo ./tests/test-thm-troubleshoot.sh + +set -e + +SCRIPT="./thm-troubleshoot" +OVPN_FILE="./test.ovpn" +OVPN_MODIFIED="./a-test-modified.ovpn" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +pass() { echo -e "${GREEN}✓ PASS${NC}: $1"; } +fail() { echo -e "${RED}✗ FAIL${NC}: $1"; exit 1; } +skip() { echo -e "${YELLOW}⊘ SKIP${NC}: $1"; } +info() { echo -e "${YELLOW}→${NC} $1"; } + +cleanup() { + info "Cleaning up..." + sudo killall openvpn 2>/dev/null || true + sudo iptables -D OUTPUT -p udp --dport 1194 -m length --length 1201: -j DROP 2>/dev/null || true + rm -f "$OVPN_MODIFIED" /tmp/auth.txt 2>/dev/null || true + # Restore original if it was backed up + [ -f "${OVPN_FILE}.bak" ] && mv "${OVPN_FILE}.bak" "$OVPN_FILE" 2>/dev/null || true +} + +trap cleanup EXIT + +echo "========================================" +echo " TryHackMe Troubleshoot Script Tests" +echo "========================================" +echo "" + +# Check prerequisites +if [ ! -f "$SCRIPT" ]; then + fail "Script not found: $SCRIPT (run from repo root)" +fi + +if [ ! -f "$OVPN_FILE" ]; then + fail "Test ovpn file not found. Please place your .ovpn config as: $OVPN_FILE" +fi + +if [ "$EUID" -ne 0 ]; then + fail "Please run as root: sudo $0" +fi + +# Detect distro +if command -v apt >/dev/null 2>&1; then + DISTRO="ubuntu" +elif command -v pacman >/dev/null 2>&1; then + DISTRO="arch" +elif command -v dnf >/dev/null 2>&1; then + DISTRO="fedora" +else + DISTRO="unknown" +fi +info "Detected distro: $DISTRO" +echo "" + +######################################## +# Test 1: Version flag +######################################## +echo "--- Test 1: Version flag ---" +VERSION_OUT=$($SCRIPT --version 2>&1) +if echo "$VERSION_OUT" | grep -q "TryHackMe VPN Troubleshoot"; then + pass "--version outputs version info" +else + fail "--version did not output expected text" +fi +echo "" + +######################################## +# Test 2: OpenVPN installation (Ubuntu only) +######################################## +echo "--- Test 2: OpenVPN installation ---" +if [[ "$DISTRO" == "ubuntu" ]]; then + # Remove OpenVPN if installed + if command -v openvpn >/dev/null 2>&1; then + info "Removing OpenVPN for install test..." + apt remove -y openvpn >/dev/null 2>&1 + fi + + if command -v openvpn >/dev/null 2>&1; then + skip "Could not remove OpenVPN for install test" + else + info "Running script to test OpenVPN installation..." + # Answer Y to install, then n to not connect (we just want to test install) + OUTPUT=$(echo -e "Y\nn" | timeout 60 $SCRIPT 2>&1 || true) + + if command -v openvpn >/dev/null 2>&1; then + pass "OpenVPN was installed successfully" + else + fail "OpenVPN was not installed" + echo "Output: $OUTPUT" + fi + fi +else + skip "OpenVPN install test only runs on Ubuntu (detected: $DISTRO)" +fi +echo "" + +######################################## +# Test 3: Inline auth-user-pass detection (OpenVPN 2.5) +######################################## +echo "--- Test 3: Inline auth-user-pass detection ---" +OVPN_VERSION=$(openvpn --version 2>&1 | head -1 | grep -oP 'OpenVPN \K[0-9]+\.[0-9]+' || echo "unknown") +if [[ "$OVPN_VERSION" == "2.5" ]]; then + info "OpenVPN $OVPN_VERSION detected - testing inline auth detection" + cleanup + + # Only test if the config has inline auth + if grep -q "" "$OVPN_FILE"; then + OUTPUT=$(yes 2>/dev/null | timeout 60 $SCRIPT 2>&1 || true) + if echo "$OUTPUT" | grep -q "does not support inline authentication"; then + pass "Detected inline auth-user-pass incompatibility" + else + fail "Did not detect inline auth-user-pass issue" + echo "Output was:" + echo "$OUTPUT" | head -30 + fi + else + skip "Config does not have inline block" + fi +else + skip "OpenVPN version is $OVPN_VERSION (need 2.5 to test inline auth detection)" +fi +echo "" + +######################################## +# Test 4: Successful connection +######################################## +echo "--- Test 4: Successful connection ---" +info "Stopping any running OpenVPN..." +killall openvpn 2>/dev/null || true +sleep 2 + +info "Creating compatible config..." +cp "$OVPN_FILE" "$OVPN_MODIFIED" + +# Extract credentials for OpenVPN 2.5 compatibility (if inline auth exists) +if grep -q "" "$OVPN_MODIFIED"; then + sed -n '//,/<\/auth-user-pass>/p' "$OVPN_MODIFIED" | grep -v "auth-user-pass" > /tmp/auth.txt + chmod 600 /tmp/auth.txt + sed -i '//,/<\/auth-user-pass>/d' "$OVPN_MODIFIED" + sed -i 's|^auth-user-pass$|auth-user-pass /tmp/auth.txt|' "$OVPN_MODIFIED" +fi + +# Remove any previous MTU settings +sed -i '/^# Added by the thm-troubleshoot/,/^tun-mtu/d' "$OVPN_MODIFIED" 2>/dev/null || true + +# Hide original so script finds our modified config +mv "$OVPN_FILE" "${OVPN_FILE}.bak" + +info "Running script (this takes ~60s)..." +OUTPUT=$(yes 2>/dev/null | timeout 120 $SCRIPT 2>&1 || true) + +# Restore original +mv "${OVPN_FILE}.bak" "$OVPN_FILE" + +if echo "$OUTPUT" | grep -q "You are connected to the TryHackMe VPN"; then + pass "Script completed successfully" + + if echo "$OUTPUT" | grep -q "192.168.x.x"; then + pass "Detected correct IP range" + else + fail "Did not report correct IP range" + fi + + if echo "$OUTPUT" | grep -q "MTU value OK\|MTU set at"; then + pass "MTU check completed" + else + fail "MTU check did not complete" + fi +else + fail "Script did not complete successfully" + echo "Output was:" + echo "$OUTPUT" +fi +echo "" + +######################################## +# Test 5: MTU detection (constrained network) +######################################## +echo "--- Test 5: MTU detection (constrained network) ---" +info "Stopping any running OpenVPN..." +killall openvpn 2>/dev/null || true +sleep 2 + +info "Adding iptables rule to simulate 1200 MTU..." +iptables -A OUTPUT -p udp --dport 1194 -m length --length 1201: -j DROP + +# Reset config +cp "$OVPN_FILE" "$OVPN_MODIFIED" +if grep -q "" "$OVPN_MODIFIED"; then + sed -n '//,/<\/auth-user-pass>/p' "$OVPN_MODIFIED" | grep -v "auth-user-pass" > /tmp/auth.txt + chmod 600 /tmp/auth.txt + sed -i '//,/<\/auth-user-pass>/d' "$OVPN_MODIFIED" + sed -i 's|^auth-user-pass$|auth-user-pass /tmp/auth.txt|' "$OVPN_MODIFIED" +fi + +# Hide original so script finds our modified config +mv "$OVPN_FILE" "${OVPN_FILE}.bak" 2>/dev/null || true + +info "Running script with constrained MTU (this takes ~90s)..." +OUTPUT=$(yes 2>/dev/null | timeout 180 $SCRIPT 2>&1 || true) + +# Restore original +mv "${OVPN_FILE}.bak" "$OVPN_FILE" 2>/dev/null || true + +if echo "$OUTPUT" | grep -q "MTU not working with the original value"; then + pass "Detected MTU issue" + + if echo "$OUTPUT" | grep -q "MTU set at"; then + pass "Applied MTU fix" + + # Verify the MTU lines are actually in the file + if grep -q "# Added by the thm-troubleshoot script" "$OVPN_MODIFIED" && \ + grep -q "tun-mtu" "$OVPN_MODIFIED"; then + pass "MTU settings correctly written to .ovpn file" + info "File header:" + head -5 "$OVPN_MODIFIED" + else + fail "MTU settings not found in .ovpn file" + info "File header:" + head -10 "$OVPN_MODIFIED" + fi + else + fail "Did not apply MTU fix" + fi +else + fail "Did not detect MTU issue" + echo "Output was:" + echo "$OUTPUT" | grep -i mtu +fi + +# Remove iptables rule +iptables -D OUTPUT -p udp --dport 1194 -m length --length 1201: -j DROP 2>/dev/null || true +echo "" + +echo "========================================" +echo " All tests completed!" +echo "========================================" + diff --git a/thm-troubleshoot b/thm-troubleshoot index 284c52e..8b2dc2c 100755 --- a/thm-troubleshoot +++ b/thm-troubleshoot @@ -1,373 +1,496 @@ -#!/bin/bash -#TryHackMe VPN Troubleshooting -#Jan, 2021 -#V1.5 -#MuirlandOracle - -#Define Colours -colour(){ - if [ $# -lt 2 ]; then - exit 1 - fi - case "$1" in - "green") - printf "\033[01;32m$2\033[0m\n" - ;; - "red") - printf "\033[01;31m$2\033[0m\n" - ;; - "yellow") - printf "\033[01;93m$2\033[0m\n" - ;; - "header") - printf "\033[0;1;4m$2\033[0m\n" - ;; - "code") - printf "\033[01;31;47m$2\033[0m\n" - ;; - "warning") - printf "\033[01;93m[Warning!]\033[0m $2\n" - ;; - "process") - printf "\033[01;94m$2\033[0m\n" - ;; - *) - return 1 - ;; - esac - if [ $# -eq 3 ]; then - sleep $3s - fi +#!/usr/bin/env bash +# TryHackMe VPN Troubleshooting +# Updated for new VPN infra (192.168.x.x addressing) +# Original: Jan 2021, V1.5, MuirlandOracle +# Updated: Dec 2025, V2.0 +# +# NOTE: This script does NOT support Network room VPNs (rooms with network diagrams). +# Those use separate configs downloadable from the Access page. + +VERSION="2.0 (Dec 2025)" + +if [[ "$1" == "--version" || "$1" == "-v" ]]; then + echo "TryHackMe VPN Troubleshoot v$VERSION" + exit 0 +fi + +######################################## +# Colour Helper +######################################## +colour() { + if [ $# -lt 2 ]; then + exit 1 + fi + + case "$1" in + "green") printf "\033[01;32m%s\033[0m\n" "$2" ;; + "red") printf "\033[01;31m%s\033[0m\n" "$2" ;; + "yellow") printf "\033[01;93m%s\033[0m\n" "$2" ;; + "header") printf "\033[0;1;4m%s\033[0m\n" "$2" ;; + "code") printf "\033[01;31;47m%s\033[0m\n" "$2" ;; + "warning") printf "\033[01;93m[Warning!]\033[0m %s\n" "$2" ;; + "process") printf "\033[01;94m%s\033[0m\n" "$2" ;; + *) return 1 ;; + esac + + if [ $# -eq 3 ]; then + sleep "$3"s + fi } -fin(){ - printf "\n\n" - exit 1 +fin() { + printf "\n\n" + exit 1 } -connect(){ - testSuccess() ( if grep -qio "Initialization Sequence Completed" $ovpnoutput;then return 0; else return 1;fi ) - testCert() ( if grep -qioE "Cannot load inline certificate file|certificate verify failed|cannot load CA" $ovpnoutput;then return 0; else return 1;fi ) - testCipher() ( if grep -qioE "cipher AES-256-CBC" $ovpn;then return 0; else return 1;fi ) - ovpnoutput=$(mktemp) - openvpn $ovpn $ovpnoutput & - colour process "[+] Connecting...." 10 - for i in {1..2};do - if testSuccess; then - colour green "[+] Connection Process completed successfully!" 1 - return 1 - elif testCert; then - killall -9 openvpn &>/dev/null 2>/dev/null - colour red "[-] Fatal Error: Inline Certificate is invalid" 1 - printf "Please regenerate your VPN config on the access page (https://tryhackme.com/access)\nIf errors persist, change server then regenerate the config.\nIf all else fails, ask for further assistance on the TryHackMe Discord server, subreddit or forums.\n" - colour red "[-] Exiting" 2 - return 0 - elif testCipher; then - colour red "[-] Using outdated switch for ciper negotiations. Attempting to update..." 1 - sed -i 's/cipher AES-256-CBC/data-ciphers AES-256-CBC/' $ovpn - colour green "[+] Successfully updated cipher switch! Please connect to the vpn using the following command: " - colour code "sudo openvpn $ovpn" 2 - - return 0 - fi - if [ $i -le 1 ]; then - colour warning "Connection process is taking longer than expected to complete" 30 - else - colour red "[-] Failed to connect" 1 - printf "Failure to connect to the VPN can usually be solved by one of the following options:\n" - printf " -Regenerating your OpenVPN config on the TryHackMe access page (https://tryhackme.com/access)\n" - printf " -Switching servers, then regenerating your OpenVPN config\n" - printf " -Checking your system time. If your system time is incorrect then this can cause issues with the authentication process\n" - printf "If none of these methods work, please ask for further assistance in the TryHackMe Discord server, subreddit or forums.\n" - colour red "[-] Exiting" 2 - return 0 - fi - done +######################################## +# Connection Helper +######################################## +connect() { + local ovpnoutput + ovpnoutput=$(mktemp) + trap "rm -f '$ovpnoutput'" RETURN + + testSuccess() ( + if grep -qio "Initialization Sequence Completed" "$ovpnoutput"; then + return 0 + else + return 1 + fi + ) + + testCert() ( + if grep -qioE "Cannot load inline certificate file|certificate verify failed|cannot load CA" "$ovpnoutput"; then + return 0 + else + return 1 + fi + ) + + testCipher() ( + if grep -qioE "cipher AES-256-CBC" "$ovpn"; then + return 0 + else + return 1 + fi + ) + + testInlineAuth() ( + if grep -qioE "option 'auth-user-pass' is not expected to be inline" "$ovpnoutput"; then + return 0 + else + return 1 + fi + ) + + # Capture OpenVPN output for analysis ( "$ovpnoutput" & + colour process "[+] Connecting...." 10 + + for i in 1 2; do + if testSuccess; then + colour green "[+] Connection process completed successfully!" 1 + return 0 + elif testCert; then + killall -9 openvpn &>/dev/null + colour red "[-] Fatal Error: Inline Certificate is invalid" 1 + printf "Please re-download your VPN config at https://tryhackme.com/manage-account/access\n" + printf "If all else fails, ask for further assistance on the TryHackMe Discord server.\n" + colour red "[-] Exiting" 2 + return 1 + elif testCipher; then + killall -9 openvpn &>/dev/null + colour red "[-] Using outdated switch for cipher negotiations. Attempting to update..." 1 + sed -i 's/cipher AES-256-CBC/data-ciphers AES-256-CBC/' "$ovpn" + colour green "[+] Successfully updated cipher switch!" 1 + colour green "[+] Please connect to the VPN using the following command: " + colour code "sudo openvpn \"$ovpn\"" 2 + return 1 + elif testInlineAuth; then + killall -9 openvpn &>/dev/null + colour red "[-] Your OpenVPN version does not support inline authentication" 1 + colour yellow "[!] The TryHackMe config uses inline which requires OpenVPN 2.6+" 1 + printf "\nYour options:\n" + printf " 1. Update OpenVPN to version 2.6 or later\n" + printf " - Ubuntu 24.04+ and other recent distros have OpenVPN 2.6 by default\n" + printf " - For older distros, search for 'install OpenVPN 2.6 '\n" + printf "\n" + printf " 2. Extract credentials to a separate file:\n" + printf " - Open your .ovpn file and find the section\n" + printf " - Copy the 2 lines between and to a new file (e.g. auth.txt)\n" + printf " - Remove the ... block from the .ovpn file\n" + printf " - Change 'auth-user-pass' to 'auth-user-pass /path/to/auth.txt'\n" + printf "\n" + colour red "[-] Exiting" 2 + return 1 + fi + + if [ "$i" -eq 1 ]; then + colour warning "Connection process is taking longer than expected to complete" 30 + else + killall -9 openvpn &>/dev/null + colour red "[-] Failed to connect" 1 + printf "Failure to connect to the VPN can usually be solved by one of the following options:\n" + printf " - Re-downloading your OpenVPN config at https://tryhackme.com/manage-account/access\n" + printf " - Checking your system time. If your system time is incorrect then this can cause issues with the authentication process\n" + printf "If none of these methods work, please ask for further assistance in the TryHackMe Discord server, subreddit or forums.\n" + colour red "[-] Exiting" 2 + return 1 + fi + done + + return 1 } -distro_call=$("lsb_release" "-is") +######################################## +# Distro + Title +######################################## +distro_call=$("lsb_release" "-is" 2>/dev/null) distro="${distro_call[*]}" -#Title -title(){ - printf "\n\n\033[0;1;32m" - cat << "EOF" - _____ _ _ _ __ __ - |_ _| __ _ _| | | | __ _ ___| | _| \/ | ___ - | || '__| | | | |_| |/ _` |/ __| |/ / |\/| |/ _ \ - | || | | |_| | _ | (_| | (__| <| | | | __/ - |_||_| \__, |_| |_|\__,_|\___|_|\_\_| |_|\___| - |___/ +title() { + printf "\n\n\033[0;1;32m" + cat << "EOF" + _____ _ _ _ __ __ + |_ _| __ _ _| | | | __ _ ___| | _| \/ | ___ + | || '__| | | | |_| |/ _` |/ __| |/ / |\/| |/ _ \ + | || | | |_| | _ | (_| | (__| <| | | | __/ + |_||_| \__, |_| |_|\__,_|\___|_|\_\_| |_|\___| + |___/ EOF -if [[ -n $distro ]]; then - printf "\033[38;2;216;1;81mLooks like you're running %s \033[0m" "$distro" -else - printf "\033[38;2;216;1;81mLinux distro not recognized \033[0m" -fi - - printf "\033[0;35m @MuirlandOracle\033[0m\n\n\n" + if [[ -n $distro ]]; then + printf "\033[38;2;216;1;81mLooks like you're running %s \033[0m" "$distro" + else + printf "\033[38;2;216;1;81mLinux distro not recognized \033[0m" + fi + printf "\033[0;35m @MuirlandOracle\033[0m\n\n\n" } - if [ ! -f /tmp/thm-title ]; then - title + title else - colour green "[+] Re-running with root permissions" 1 - rm /tmp/thm-title + colour green "[+] Re-running with root permissions" 1 + rm /tmp/thm-title fi - sleep 1s -#Check that the script is being run with sudo +######################################## +# Ensure root +######################################## if [[ $EUID -ne 0 ]]; then - colour red "[-] Script is being run as a low-privileged user" 1 - read -p "Would you like to run this script with higher privileges automatically (Y/n)? " choice - case "$choice" in - n|N) - printf "\n\nPlease run the script with the following command:\n" - colour code "sudo $0" 1 - colour red "[-] Exiting" 2 - fin - ;; - *) - touch /tmp/thm-title - sudo -E $0 - ;; - esac - fin + colour red "[-] Script is being run as a low-privileged user" 1 + read -p "Would you like to run this script with higher privileges automatically (Y/n)? " choice + case "$choice" in + n|N) + printf "\n\nPlease run the script with the following command:\n" + colour code "sudo $0" 1 + colour red "[-] Exiting" 2 + fin + ;; + *) + touch /tmp/thm-title + sudo -E "$0" + ;; + esac + fin fi -# TODO add a check for network vpn files and/or other vpn configs - how to differentiate main THM VPN config from others? -#Find the VPN Config +######################################## +# Find the VPN Config +######################################## ovpn=$(find . -maxdepth 1 -name "*.ovpn" -print -quit) -if [ ${#ovpn} -eq 0 ]; then - colour red "[-] Config not found in current directory" 1 - read -ep "Please enter the path to your config: " ovpn - ovpn=${ovpn/\~/$HOME} - if [ ${#ovpn} -lt 5 ]; then - colour red "[-] Invalid File -- Config should be .ovpn" 1 - colour red "[-] Exiting" 2 - fin - elif [ -f $ovpn ] && [ ${ovpn: -5} == ".ovpn" ]; then - colour green "[+] Config Located successfully" 1 - else - colour red "[-] Config not located" 1 - colour red "[-] Exiting" 2 - fin - fi -fi - - +if [ -z "$ovpn" ]; then + colour red "[-] Config not found in current directory" 1 + read -ep "Please enter the path to your config: " ovpn + ovpn=${ovpn/\~/$HOME} + + if [ ${#ovpn} -lt 5 ]; then + colour red "[-] Invalid file -- config should be .ovpn" 1 + colour red "[-] Exiting" 2 + fin + elif [ -f "$ovpn" ] && [ "${ovpn: -5}" == ".ovpn" ]; then + colour green "[+] Config located successfully" 1 + else + colour red "[-] Config not located" 1 + colour red "[-] Exiting" 2 + fin + fi +fi -#Check Internet connectivity -if [ $(ping -c 1 -q 1.1.1.1 >&/dev/null; echo $?) -gt 0 ]; then - colour red "[-] You are not connected to the internet" 1 - colour red "[-] Exiting" 2 - fin +######################################## +# Check Internet connectivity +######################################## +if ! ping -c 1 -q 1.1.1.1 >&/dev/null; then + colour red "[-] You are not connected to the internet" 1 + colour red "[-] Exiting" 2 + fin else - colour green "[+] Stable internet connection" 1 + colour green "[+] Stable internet connection" 1 fi +######################################## +# Ensure OpenVPN installed (modern detection) +######################################## +ensure_openvpn_installed() { + if command -v openvpn >/dev/null 2>&1; then + colour green "[+] OpenVPN is installed" 1 + return 0 + fi + + colour red "[-] OpenVPN is not installed" 1 + read -p "Would you like to install OpenVPN automatically (Y/n)? " choice + case "$choice" in + n|N) + printf "\n\nPlease install OpenVPN manually (e.g.:\n" + printf " sudo apt install openvpn\n" + printf "or appropriate command for your distro.)\n" + colour red "[-] Exiting" 2 + fin + ;; + *) + if command -v apt >/dev/null 2>&1; then + colour process "[+] Installing OpenVPN via apt..." + apt update -y &>/dev/null + apt install openvpn -y &>/dev/null + elif command -v pacman >/dev/null 2>&1; then + colour process "[+] Installing OpenVPN via pacman..." + pacman -Syy --noconfirm openvpn &>/dev/null + elif command -v dnf >/dev/null 2>&1; then + colour process "[+] Installing OpenVPN via dnf..." + dnf install -y openvpn &>/dev/null + else + colour red "[-] Could not detect a supported package manager (apt, pacman, dnf)" 1 + colour red "[-] Please install OpenVPN manually" 2 + fin + fi + + if command -v openvpn >/dev/null 2>&1; then + colour green "[+] OpenVPN installed successfully" 1 + else + colour red "[-] Installation failed. Please try installing OpenVPN manually or ask for help on the TryHackMe Discord/Reddit/forums." 1 + colour red "[-] Exiting" 2 + fin + fi + ;; + esac +} -# Determine package manager being used to create variables -if pacman -V &>/dev/null; then - pkg_manager_status=("pacman" "-V"); - is_openvpn_installed=("pacman" "-Qs" "openvpn"); - pkg_manager_update=("pacman" "-Syy"); - install_openvpn=("pacman" "-S" "openvpn" "--noconfirm"); +ensure_openvpn_installed + +######################################## +# Check tun0 exists +######################################## +if ! ip a | grep -q "tun0"; then + colour red "[-] tun0 interface does not exist" 1 + read -p "Would you like the script to attempt a connection automatically (Y/n)? " choice + case "$choice" in + n|N) + printf "\n\nPlease connect to the VPN using the following command:\n" + colour code "sudo openvpn \"$ovpn\"" + printf "\nOnce connected, re-run this script.\n" + colour red "[-] Exiting" 2 + fin + ;; + *) + if ! connect; then + fin + fi + ;; + esac +else + colour green "[+] tun0 exists" 1 fi -if dpkg-query -W -f='${Status}' apt &>/dev/null; then - pkg_manager_status=("dpkg-query" "-W" "-f='${Status}'" "apt") - is_openvpn_installed=("dpkg-query" "-W" "-f='${Status}'" "openvpn") - pkg_manager_update=("apt" "update") - install_openvpn=("apt" "install" "openvpn" "-y") +######################################## +# Check that tun0 IP is in the right range (NEW: 192.168.x.x) +######################################## +vpn_expected_regex="192\.168\.[0-9]{1,3}\.[0-9]{1,3}" + +if ! ip a show tun0 | grep -qoE "$vpn_expected_regex"; then + tun_ip=$(ip addr show tun0 | awk '/inet / {print $2}') + + colour red "[-] tun0 IP is not in the expected range: $tun_ip" 1 + colour yellow "[!] The TryHackMe VPN should assign you a 192.168.x.x address." 1 + + printf "\nThis could mean:\n" + printf " 1. You are using an OUTDATED TryHackMe VPN config\n" + printf " 2. You are connected to a NETWORK ROOM VPN (this script does not support those)\n" + printf " 3. You have a different VPN connected, or the wrong .ovpn file in this directory\n" + + printf "\nTo fix:\n" + printf " - Download a fresh config from https://tryhackme.com/manage-account/access\n" + printf " - Make sure the VPN server region matches your target VM region\n" + printf " - Disconnect any other VPNs that might be using tun0\n\n" + + read -p "Would you like the script to attempt to fix this by reconnecting (Y/n)? " choice + case "$choice" in + n|N) + colour red "[-] Exiting" 2 + fin + ;; + *) + colour green "[+] Resetting tun0 interface" 1 + ip link delete tun0 2>/dev/null + if ! connect; then + fin + fi + + if ! ip a show tun0 | grep -qoE "$vpn_expected_regex"; then + tun_ip=$(ip addr show tun0 | awk '/inet / {print $2}') + colour red "[-] tun0 IP still not in expected range: $tun_ip" 1 + printf "Please download a fresh config from https://tryhackme.com/manage-account/access\n" + colour red "[-] Exiting" 2 + fin + fi + ;; + esac +else + colour green "[+] tun0 IP is in the correct range (192.168.x.x)" 1 fi -#Ensure that Openvpn is installed -if ! "${is_openvpn_installed[@]}" &>/dev/null; then - colour red "[-] OpenVPN is not installed" 1 - read -p "Would you like to install OpenVPN automatically (Y/n)? " choice - case "$choice" in - n|N) - printf "\n\nPlease install OpenVPN manually\n" - colour red "[-] Exiting" 2 - fin - ;; - *) - if ! "${pkg_manager_status[@]}" &>/dev/null; then - colour red "[-] System doesn't use apt or pacman -- please install OpenVPN manually" 1 - colour red "[-] Exiting" 2 - fin - else - "${pkg_manager_update[@]}" &>/dev/null && "${install_openvpn[@]}" &>/dev/null & pid=$! - colour process "[+] Installing OpenVPN..." - while :; do - running=$(ps aux | grep $pid | wc -l) - if [ $running -eq 1 ]; then - break - fi - done - if "${is_openvpn_installed[@]}" &>/dev/null; then - colour green "[+] Installation Process Completed" 1 - else - colour red "[-] Installation failed. Please try installing OpenVPN manually -- otherwise ask for further assistance in the TryHackMe Discord server, subreddit or forum" 1 - colour red "[-] Exiting" 2 - fin - fi - fi - ;; - esac +######################################## +# Check for multiple OpenVPN connections +######################################## +connections=$(ps aux | grep -v "sudo\|grep" | grep -Eo "openvpn .*\.ovpn" | wc -l) +if [ "$connections" -gt 1 ]; then + colour red "[-] More than one OpenVPN connection is running" 1 + read -p "Would you like the script to attempt to fix this (Y/n)? " choice + case "$choice" in + n|N) + printf "\n\nPlease run the following command, then reconnect manually:\n" + colour code "sudo killall -9 openvpn" + fin + ;; + *) + killall -9 openvpn 2>/dev/null + colour green "[+] Killed duplicate processes" 1 + if ! connect; then + fin + fi + ;; + esac else - colour green "[+] OpenVPN is installed" 1 + colour green "[+] Only one instance of OpenVPN is running" 1 fi - -#Check that a tun0 exists -if ! ip a | grep -q tun0; then - colour red "[-] tun0 interface does not exist" 1 - printf "Would you like the script to attempt a connection automatically (Y/n)? " - read -p "" choice - case "$choice" in - n|N) - printf "\n\nPlease connect to the vpn using the following command:\n" - colour code "sudo openvpn $ovpn" - printf "\n" - colour red "[-] Exiting" 2 - fin - ;; - *) - if connect; then - exit 0 - fi - ;; - esac -else - colour green "[+] tun0 exists" 1 -fi - - -#Check that the tun0 IP is in the right range -if ! ip a show tun0 | grep -qoE "10\.(2|4|6|8|9|11|13|14|17|50)\.[0-9]{1,3}\.[0-9]{1,3}" | head -1; then - colour red "[-] tun0 ip is in the wrong range: $(ip addr show tun0 | grep "inet " | awk '{print $2}')" 1 - read -p "Would you like the script to attempt to fix this (Y/n)? " choice - case "$choice" in - n|N) - printf "\n\nIf you're using another VPN, please check that it isn't operating on tun0\nOtherwise please regenerate your TryHackMe VPN config pack, or try another server.\n" - colour red "[-] Exiting" 2 - fin - ;; - *) - colour green "[+] Resetting tun0 interface" 1 - ip link delete tun0 - if connect; then - exit 0 - elif ! ip a | grep -qoE "10\.(2|4|6|8|9|11|13|14|17|50)\.[0-9]{1,3}\.[0-9]{1,3}" | head -1; then - colour red "[-] Fatal Error: tun0 IP still in the wrong range: $(ip addr show tun0 | grep "inet " | awk '{print $2}')" 1 - printf "Please try switching servers and/or regenerating your VPN config\n" - colour red "[-] Exiting" 2 - fin - fi - ;; - esac +######################################## +# MTU / Connectivity Check (NEW target: 192.168.128.1) +######################################## +vpn_server_ip="192.168.128.1" + +origin_mtu=$(cat /sys/class/net/tun0/mtu 2>/dev/null) + +if [ -n "$origin_mtu" ]; then + mtu=$((origin_mtu - 30)) + + colour process "[+] Confirming connectivity to VPN server ($vpn_server_ip)..." 1 + + # Wait for basic connectivity before testing MTU (connection can take a moment to stabilise) + for attempt in {1..10}; do + if ping -c 1 -W 2 "$vpn_server_ip" >&/dev/null; then + break + fi + if [ "$attempt" -eq 10 ]; then + colour warning "Could not reach VPN server after 10 attempts – skipping MTU optimisation" 1 + origin_mtu="" # Skip MTU check + fi + sleep 1 + done + + if [ -n "$origin_mtu" ]; then + colour process "[+] Optimising MTU..." 1 + fi + + while [ -n "$origin_mtu" ]; do + # Ping the VPN server without fragmenting packets + # Retry once before assuming MTU is too large (handles transient packet loss) + mtu_ok=false + for _retry in 1 2; do + if ping -M do -s "$mtu" -W 2 -c 2 "$vpn_server_ip" >&/dev/null; then + mtu_ok=true + break + fi + sleep 1 + done + + if [ "$mtu_ok" = false ]; then + if [[ "$mtu" -lt 1000 ]]; then + colour warning "MTU value failed at 1000, aborting MTU optimisation" 1 + break + fi + mtu=$((mtu - 30)) + else + # Add 30 bytes back to get working MTU + mtu=$((mtu + 30)) + + if [[ "$mtu" -eq "$origin_mtu" ]]; then + colour green "[+] MTU value OK ($origin_mtu)" 1 + break + else + colour red "[-] MTU not working with the original value of $origin_mtu" 1 + ip link set dev tun0 mtu "$mtu" + colour green "[+] MTU set at $mtu on tun0" 1 + colour yellow "[!] Note that a working MTU value might change depending on your network condition" 1 + + read -p "Would you like the script to set the MTU value permanently in your .ovpn file (Y/n)? " choice + case "$choice" in + n|N) + colour green "[+] You can set the value manually in your .ovpn file with the following line:" + colour code "tun-mtu $mtu" + ;; + *) + if grep -q "thm-troubleshoot" "$ovpn" >&/dev/null; then + sed -i "s/tun-mtu.*/tun-mtu $mtu/g" "$ovpn" + colour green "[+] .ovpn file MTU value changed" 1 + else + # Prepend MTU setting with comment to ovpn file + { + echo "# Added by the thm-troubleshoot script" + echo "# The MTU value might need to be changed depending on your network." + echo "# Default is 1500" + echo "tun-mtu $mtu" + echo "" + cat "$ovpn" + } > "${ovpn}.tmp" && mv "${ovpn}.tmp" "$ovpn" + colour green "[+] .ovpn file MTU value and comment added" 1 + fi + ;; + esac + break + fi + fi + done else - colour green "[+] tun0 IP is in the correct range" 1 + colour warning "Could not read MTU from /sys/class/net/tun0/mtu – skipping MTU optimisation" 1 fi - - -#Check for multivpn -connections=$(ps aux | grep -v "sudo\|grep" | grep -Eo "openvpn .*\.ovpn" | wc -l) -if [ $connections -gt 1 ]; then - colour red "[-] More than one connection running" 1 - read -p "Would you like the script to attempt to fix this (Y/n)? " choice - case $choice in - n|N) - printf "\n\nPlease run the following command, then reconnect manually:\n" - colour code "sudo killall -9 openvpn" - fin - ;; - *) - killall -9 openvpn - colour green "[+] Killed duplicate processes" - if connect; then - exit 0 - fi - esac +######################################## +# Check that 10.X routes exist (NEW) +######################################## +if ip route | awk '{print $1}' | grep -qE '^10\.'; then + colour green "[+] 10.X.X.X routes detected – target VM routes are present" 1 + colour yellow "[!] Make sure your VPN server region matches your VM region in https://tryhackme.com/manage-account/access" 1 else - colour green "[+] Only one instance of OpenVPN is running" 1 + colour warning "No 10.X.X.X routes detected – you may not be able to reach TryHackMe target VMs" 1 + colour warning "Try re-downloading your config at https://tryhackme.com/manage-account/access" 1 fi -#Check MTU value -# default mtu is 1500, but get value from the actual tun interface -origin_mtu=$(cat /sys/class/net/tun0/mtu) -# Usually 30 bytes are needed for the vpn additions in the packet -mtu=$((origin_mtu-30)) - -colour process "[+] Confirming connectivity" 2 - -while true; do - # ping THM machine without breaking the packet into fragments. If fails, packet too big - # -M do disables packet fragmentation - # -s sets packet size - # -W sets timeout (1 second) (second fractions not working in Ubuntu ping, wtf?) - # -c only send 1 ping - if [ $(ping -M do -s $mtu -W 1 -c 1 10.10.10.10 >&/dev/null; echo $?) -gt 0 ]; then - # A very rare case would be an MTU value below 1000 not working. If that happens, something else is probably wrong - break the MTU check - if [[ $mtu -lt 1000 ]]; then - colour red "[-] MTU value failed at 1000, aborting MTU check" - break - fi - # decrease MTU until it goes through - mtu=$((mtu-30)) - # if ping goes through, that's a working MTU value - else - # Add the 30 bytes back - mtu=$((mtu+30)) - # if working with the original value, nothing needs to be done - if [[ $mtu -eq $origin_mtu ]]; then - colour green "[+] MTU value OK" 1 - break - else - colour red "[-] MTU not working with the value of $origin_mtu" - # Fix the MTU in the interface - sudo ip link set dev tun0 mtu $mtu - colour green "[+] MTU set at $mtu in tun0" - colour yellow "[!] Note that a working MTU value might change depending on your network condition" - # fix the ovpn file - read -p "Would you like the script to set the MTU value permanently in your .ovpn file (Y/n)? " choice - case $choice in - n|N) - colour green "[+] You can set the value manually in your .ovpn file with the following line:" - colour code "tun-mtu $mtu" - ;; - *) - if [ $(grep "thm-troubleshoot" $ovpn >&/dev/null; echo $?) -eq 0 ]; then - sed -i "s/tun-mtu.*/tun-mtu $mtu/g" $ovpn - colour green "[+] .ovpn file MTU value changed" - else - sed -i "1i# Added by the thm-troubleshoot script\n# The MTU value might need to be changed depending on your network. Default is 1500\ntun-mtu $mtu\n" $ovpn - colour green "[+] .ovpn file MTU value and comment added" - fi - ;; - esac - break - fi - fi -done - -#Final Check -if [ $(ping -c 1 -q 10\.10\.10\.10 >&/dev/null; echo $?) -eq 0 ];then - colour green "[+] Connectivity checks completed!" 2 - colour green "[+] You are connected to the TryHackMe Network" 2 - printf "Your TryHackMe IP address is: $(curl -s http://10.10.10.10/whoami)\n\n" - colour green "Happy Hacking!" 3 +######################################## +# Final Connectivity Check (NEW behaviour) +######################################## +if ping -c 1 -q "$vpn_server_ip" >&/dev/null; then + colour green "[+] Connectivity checks completed!" 2 + colour green "[+] You are connected to the TryHackMe VPN" 2 + client_ip=$(ip addr show tun0 | awk '/inet / {print $2}') + printf "Your VPN-assigned IP address (on tun0) is: %s\n\n" "$client_ip" + colour green "Happy Hacking!" 3 else - colour red "[-] Something went wrong -- please ask for further assistance in the TryHackMe Discord server, subreddit, or forum" 3 + colour red "[-] Unable to reach the VPN server at $vpn_server_ip" 1 + colour red "[-] Something went wrong -- please ask for further assistance in the TryHackMe Discord server." 3 fi -printf "\n" +printf "\n" \ No newline at end of file