GOFLEX HOME REGISTRATION RECOVERY ================================= # GoFlex Home Registration Recovery Recover a factory-reset Seagate FreeAgent GoFlex Home after the original Seagate/Axentra registration service became unavailable. This project temporarily emulates only the portion of the retired registration backend required by the stock GoFlex Home setup wizard. It does not: - flash the NAS; - replace its firmware; - modify its bootloader; - require a serial cable; - weaken the recovery computer's normal SSH server. ## The problem A factory-reset GoFlex Home can still boot and display its original setup wizard, but registration fails because the historical SeagateShare registration service is no longer available. Without successful registration, the stock wizard cannot normally proceed to creation of the first local administrator account. This emulator supplies the responses expected by the original firmware long enough to finish setup and create a working local administrator. ## Tested result The recovered stock GoFlex Home successfully: - completed product-key registration; - created a new local administrator; - completed the setup wizard; - accepted the new administrator login locally; - continued accepting that login after all temporary recovery changes were removed. ## Requirements You need: - a GoFlex Home you own or are authorized to recover; - its product key; - its current LAN IP address; - another Linux machine on the same LAN; - root or sudo access on that Linux machine; - OpenSSH server tools and iptables; - a router or DNS resolver capable of temporary local DNS overrides. ## Security design The GoFlex Home firmware uses SSH algorithms that modern OpenSSH disables by default. Do not weaken your normal SSH server to support it. The recovery script instead: 1. creates a separate temporary sshd; 2. enables the required legacy algorithms only in that instance; 3. redirects TCP port 22 only for traffic from the specified GoFlex IP; 4. accepts only the identities required by the recovery protocol; 5. removes temporary users, firewall rules and runtime data when stopped. Do not expose the emulator to the public Internet. ## Step 1 — Record your network settings Before changing DNS or DHCP settings, record their current values. Restore them exactly after recovery. ## Step 2 — Find the required values Determine: - GoFlex Home IP - Linux recovery-machine IP - GoFlex product key Example only: GoFlex Home: 192.168.1.50 Recovery Linux: 192.168.1.20 Product key: XXXX-XXXX-XXXX-XXXX Never publish your real product key. ## Step 3 — Add temporary DNS overrides Temporarily make these names resolve to the Linux recovery machine: - reg.seagateshare.com - seagateshare.com - s1.seagateshare.com The GoFlex must actually use the DNS resolver containing those records. ## Step 4 — Start the emulator Make the script executable: chmod +x goflex-registration-emulator.sh Run: sudo ./goflex-registration-emulator.sh \ --device-ip YOUR_GOFLEX_IP \ --server-ip YOUR_LINUX_IP \ --product-key YOUR-PRODUCT-KEY Wait until it reports that the recovery emulator is READY. Leave that terminal running. ## Step 5 — Run the stock setup wizard Open: http://YOUR_GOFLEX_IP/admin/wizards/setup/wrapper Complete the Registration page normally. Choose the GoFlex Home name you want. Do not stop the emulator after Registration succeeds. The GoFlex still contacts the historical central-server interface while the first administrator account is created. ## Step 6 — Create the administrator Continue to Administrator Account Creation. Choose the username and password you want. The stock firmware requires the password to contain: - at least six characters; - at least one number. Keep the emulator running until the wizard reaches Finish. ## Step 7 — Verify local login The old Finish-page Log In button may try to open the retired public SeagateShare website. Instead open: http://YOUR_GOFLEX_IP/admin Sign in with the administrator account you just created. Verify local login before stopping the emulator. An Adobe Flash warning may appear after login. That is separate from registration recovery. ## Step 8 — Stop the emulator Return to the Linux terminal and press Ctrl+C. The script automatically removes: - the temporary sshd; - the temporary Linux users; - the source-specific iptables rules; - the temporary runtime directory. ## Step 9 — Restore DNS and DHCP Remove the temporary SeagateShare DNS overrides. Restore your original DNS and DHCP settings exactly. Then verify again: http://YOUR_GOFLEX_IP/admin ## Troubleshooting ### GoFlex cannot reach seagateshare.com Check that: - the temporary DNS records are active; - the GoFlex is using that DNS resolver; - the emulator is running; - TCP port 22 from the GoFlex can reach the recovery machine. ### Administrator creation still fails Do not stop the emulator after Registration succeeds. The GoFlex performs additional central-server calls while creating the first administrator and setting its password. ## Privacy Before posting logs or requesting help, redact: - your product key; - administrator passwords; - password hashes; - generated device SSH keys; - public IP addresses; - personal usernames if desired. ## Scope This project is intended for recovery of GoFlex Home hardware you own or are authorized to administer. No firmware images or proprietary Seagate/Axentra source files are included. ## Validation status The recovery protocol documented here was proven on a real factory-reset GoFlex Home and successfully produced a persistent local administrator account. The generalized public script was then reconstructed from that proven recovery flow and passed syntax, privacy, cleanup, isolation and protocol-specific static audits. It has not been rerun against a second freshly factory-reset unit solely for publication testing. ============================================================ TECHNICAL NOTES ============================================================ # Technical Notes These notes document the registration behavior observed while recovering a factory-reset Seagate FreeAgent GoFlex Home running stock HipServ firmware. The recovery emulator was written from observed protocol behavior and does not contain copied Seagate/Axentra firmware or source files. ## Overview The stock setup process depends on the retired SeagateShare registration backend. The important discovery is that the registration flow is not a conventional HTTP API. The GoFlex performs SSH transactions with the historical registration server. There are two major phases: 1. initial product registration; 2. device-specific account operations. ## Stage 1 — Initial registration The GoFlex connects to the registration service over TCP port 22. The SSH login identity is: apache The requested remote command has this form: /usr/sbin/cpe-register.pl PRODUCT-KEY GOFLEX-NAME The GoFlex then sends a newly generated DSA public key through the SSH session's standard input. That key is later used to authenticate the device-specific SSH account. ## Stage 1 response A successful registration response contains two whitespace-separated fields: domain=GOFLEX-NAME ddpass=VALUE The stock firmware parses those values and stores them for later use. The requested GoFlex name is normalized to lowercase. The recovery emulator generates a temporary ddpass value rather than using any historical Seagate credential. ## Stage 2 — Device-specific SSH After Stage 1 succeeds, the GoFlex reconnects over SSH. The login identity is derived from the product key: cpe-PRODUCT-KEY Authentication uses the DSA public key that the GoFlex supplied during Stage 1. One of the first observed remote commands is: /usr/share/homebase-accounts/cpe-account.pl --action=enable-auth ## XML success response The device-specific account operations expect XML. A successful response has this form: The stock firmware parses the error number and treats zero as success. ## Administrator account creation Creating the first administrator is not purely local. The GoFlex performs additional device-specific central-server operations while creating the account and setting its password. Observed behavior shows separate SSH sessions during this stage. That is why the recovery emulator must remain running after the Registration page succeeds. Stopping it too early causes Administrator Account Creation to report that seagateshare.com could not be reached. ## Local system proxy path The stock administrative web code does not perform every privileged account operation directly. It calls: /usr/bin/sp-agent That client communicates with the local OEone System Proxy daemon: oe-spd The system proxy dispatches privileged operations through modules under: /usr/lib/spd/ The relevant account and password operations ultimately trigger the device-specific cpe-account.pl SSH calls described above. ## Recovery isolation The emulator does not modify the recovery host's normal sshd configuration. Instead it starts a separate temporary sshd on a high local port. A source-specific iptables rule redirects only: GoFlex-IP -> recovery-server:22 to that temporary SSH service. Other machines continue using the recovery host's normal SSH service. ============================================================ RECOVERY SCRIPT: goflex-registration-emulator.sh ============================================================ #!/usr/bin/env bash # # GoFlex Home registration recovery emulator # # Temporarily emulates the retired Seagate/Axentra registration backend # required by the stock GoFlex Home setup wizard. # # It does NOT modify the host's normal sshd configuration. # set -Eeuo pipefail set -o pipefail umask 077 DEVICE_IP='' SERVER_IP='' PRODUCT_KEY='' PORT='22022' usage() { cat <<'EOF' Usage: sudo ./goflex-registration-emulator.sh \ --device-ip 192.168.1.50 \ --server-ip 192.168.1.20 \ --product-key XXXX-XXXX-XXXX-XXXX Required: --device-ip GoFlex Home LAN IP --server-ip Linux recovery machine LAN IP --product-key Product key shown by the GoFlex setup wizard Optional: --port Temporary internal sshd port (default: 22022) Before running, temporarily resolve these names to --server-ip: reg.seagateshare.com seagateshare.com s1.seagateshare.com Keep the emulator running through: 1. Registration 2. Administrator Account Creation 3. Wizard Finish 4. Verification of local login at http://GOFLEX-IP/admin Press Ctrl+C only after local login works. Cleanup is automatic. EOF } while [ "$#" -gt 0 ]; do case "$1" in --device-ip) DEVICE_IP="${2-}" shift 2 ;; --server-ip) SERVER_IP="${2-}" shift 2 ;; --product-key) PRODUCT_KEY="${2-}" shift 2 ;; --port) PORT="${2-}" shift 2 ;; -h|--help) usage exit 0 ;; *) echo "Unknown argument: $1" >&2 usage >&2 exit 2 ;; esac done if [ "$(id -u)" -ne 0 ]; then echo 'ERROR: run this script with sudo/root.' >&2 exit 1 fi if [ -z "$DEVICE_IP" ] || [ -z "$SERVER_IP" ] || [ -z "$PRODUCT_KEY" ] then usage >&2 exit 2 fi PRODUCT_KEY="$( printf '%s' "$PRODUCT_KEY" | tr '[:lower:]' '[:upper:]' )" if ! printf '%s\n' "$PRODUCT_KEY" | grep -Eq '^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$' then echo 'ERROR: product key must look like XXXX-XXXX-XXXX-XXXX.' >&2 exit 2 fi python3 - "$DEVICE_IP" "$SERVER_IP" <<'PY' import ipaddress import sys for value in sys.argv[1:]: try: ipaddress.IPv4Address(value) except Exception: raise SystemExit(f"Invalid IPv4 address: {value}") PY if ! printf '%s\n' "$PORT" | grep -Eq '^[0-9]+$' || [ "$PORT" -lt 1024 ] || [ "$PORT" -gt 65535 ] then echo 'ERROR: --port must be between 1024 and 65535.' >&2 exit 2 fi for BIN in \ /usr/sbin/sshd \ iptables \ ss \ ssh-keygen \ openssl \ useradd \ userdel \ groupadd \ groupdel \ timeout \ python3 do if [[ "$BIN" = /* ]]; then [ -x "$BIN" ] || { echo "ERROR: missing $BIN" >&2 exit 1 } else command -v "$BIN" >/dev/null 2>&1 || { echo "ERROR: missing command: $BIN" >&2 exit 1 } fi done CPE_USER="cpe-$PRODUCT_KEY" WORK="/run/goflex-home-registration-recovery.$$" KEY="$WORK/hostkey" CFG="$WORK/sshd_config" HANDLER="$WORK/handler.sh" LOG="$WORK/sshd.log" CAP="$WORK/capture" AUTHDIR="$WORK/auth" SSHD_PID='' CREATED_GROUP=0 CREATED_APACHE=0 CREATED_CPE=0 RECOVERY_GROUP="goflexrec$$" cleanup() { set +e echo echo 'Cleaning up temporary recovery environment...' if [ -n "$SSHD_PID" ]; then kill "$SSHD_PID" 2>/dev/null || true wait "$SSHD_PID" 2>/dev/null || true fi while iptables -t nat -C PREROUTING \ -s "$DEVICE_IP" \ -d "$SERVER_IP" \ -p tcp \ --dport 22 \ -j REDIRECT \ --to-ports "$PORT" \ 2>/dev/null do iptables -t nat -D PREROUTING \ -s "$DEVICE_IP" \ -d "$SERVER_IP" \ -p tcp \ --dport 22 \ -j REDIRECT \ --to-ports "$PORT" done while iptables -C INPUT \ -s "$DEVICE_IP" \ -p tcp \ --dport "$PORT" \ -j ACCEPT \ 2>/dev/null do iptables -D INPUT \ -s "$DEVICE_IP" \ -p tcp \ --dport "$PORT" \ -j ACCEPT done if [ "$CREATED_CPE" = 1 ]; then userdel "$CPE_USER" 2>/dev/null || true fi if [ "$CREATED_APACHE" = 1 ]; then userdel apache 2>/dev/null || true fi if [ "$CREATED_GROUP" = 1 ]; then groupdel "$RECOVERY_GROUP" 2>/dev/null || true fi rm -rf "$WORK" echo 'Cleanup complete.' } trap cleanup EXIT trap 'exit 130' INT trap 'exit 143' TERM trap 'exit 129' HUP if getent group "$RECOVERY_GROUP" >/dev/null; then echo 'ERROR: temporary recovery group already exists.' >&2 exit 1 fi if getent passwd apache >/dev/null; then echo 'ERROR: this machine already has an account named apache.' >&2 exit 1 fi if getent passwd "$CPE_USER" >/dev/null; then echo 'ERROR: temporary CPE username already exists.' >&2 exit 1 fi if ss -H -ltn | grep -Eq ":${PORT}[[:space:]]"; then echo "ERROR: TCP port $PORT is already in use." >&2 exit 1 fi groupadd --system "$RECOVERY_GROUP" CREATED_GROUP=1 mkdir -p \ "$WORK" \ "$CAP" \ "$AUTHDIR" \ "$WORK/apache-home" \ "$WORK/cpe-home" chown root:"$RECOVERY_GROUP" "$WORK" "$CAP" "$AUTHDIR" chmod 0750 "$WORK" chmod 2770 "$CAP" "$AUTHDIR" chmod 0700 "$WORK/apache-home" "$WORK/cpe-home" printf '%s\n' "$PRODUCT_KEY" > "$WORK/product-key" printf '%s\n' "$CPE_USER" > "$WORK/cpe-user" printf 'd%s\n' "$(openssl rand -hex 6)" > "$WORK/ddpass" chown root:"$RECOVERY_GROUP" \ "$WORK/product-key" \ "$WORK/cpe-user" \ "$WORK/ddpass" chmod 0640 \ "$WORK/product-key" \ "$WORK/cpe-user" \ "$WORK/ddpass" RANDOM_PASSWORD_HASH="$( openssl passwd -6 "$(openssl rand -hex 24)" )" useradd \ --system \ --gid "$RECOVERY_GROUP" \ --no-create-home \ --home-dir "$WORK/apache-home" \ --shell /bin/sh \ --password "$RANDOM_PASSWORD_HASH" \ apache CREATED_APACHE=1 useradd \ --badname \ --system \ --gid "$RECOVERY_GROUP" \ --no-create-home \ --home-dir "$WORK/cpe-home" \ --shell /bin/sh \ --password "$RANDOM_PASSWORD_HASH" \ "$CPE_USER" CREATED_CPE=1 unset RANDOM_PASSWORD_HASH chown apache:"$RECOVERY_GROUP" "$WORK/apache-home" chown "$CPE_USER":"$RECOVERY_GROUP" "$WORK/cpe-home" # # Public half of the registrar key used by stock GoFlex Home firmware. # This is a public key only. No registrar private key is included. # cat > "$AUTHDIR/apache" <<'EOF' ssh-dss AAAAB3NzaC1kc3MAAACBAIB5v6ZE55AHojhfUBMK8BolnTwQCjICo6FqmQwalg3Izb3y6PkbFZHMYM6HI18b1m7wWD8xT2fcGUC9L+SnvLvKw4DC9NOub7HYlu/dLn7xgbGGNRNx4STztfF9qxHhv4b5SgYycnbdrDPwomdzi4buZGexeIrWt0nJBnGwfkYXAAAAFQD1rIVSJbh3AmoHYn6qUqSByJE3tQAAAIBQ26TC9stOtyjAwBEm5gDGFqrrjURkxgdMHf8es2kbw7WG3BBf0uOyRMOBtMehIIiJqdyBNdTdfiXIL/7kWmnKx9troGIM6wpEXmrgD9UrC5ghWbVQ3D2vb04FHIif/QndF25ShlKhoVIq4Q5q/Hmqst94lik3aNyiRGyVs09hSwAAAIAIAjh95VjWISG5qGf25E5Sw33/xAO+QfPYBqc4tZU+fputaLrqCB3oJyJdQ8uK0bY5C6bjw5S7NHYr5QHAlXg6VXprmwj2BPUnUXW1Cl7iHJfU3AACfV24yymbCa4Xq4lAPr0jQIQTr3xtlF+0LmYOJsoHCkRDLdbjNQXDxpYkbA== EOF chown root:"$RECOVERY_GROUP" "$AUTHDIR/apache" chmod 0640 "$AUTHDIR/apache" ssh-keygen \ -q \ -t rsa \ -b 2048 \ -N '' \ -f "$KEY" cat > "$HANDLER" <<'HANDLER' #!/bin/sh set -eu set -f umask 007 WORK="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)" AUTHDIR="$WORK/auth" CAP="$WORK/capture" PRODUCT_KEY="$(cat "$WORK/product-key")" CPE_USER="$(cat "$WORK/cpe-user")" LOGIN="$(id -un)" CMD="${SSH_ORIGINAL_COMMAND-}" success_xml() { cat <<'XML' XML } if [ "$LOGIN" = 'apache' ]; then set -- $CMD if [ "$#" -ne 3 ] || [ "$1" != '/usr/sbin/cpe-register.pl' ] || [ "$2" != "$PRODUCT_KEY" ] then printf '%s\n' \ 'stage1: unexpected registration command' \ >> "$CAP/events.log" exit 64 fi SUBDOMAIN="$3" if ! printf '%s\n' "$SUBDOMAIN" | grep -Eq '^[A-Za-z][A-Za-z0-9-]{1,15}$' then printf '%s\n' \ 'stage1: invalid requested GoFlex name' \ >> "$CAP/events.log" exit 65 fi SUBDOMAIN="$( printf '%s' "$SUBDOMAIN" | tr '[:upper:]' '[:lower:]' )" TMPKEY="$AUTHDIR/.cpe-key.$$" timeout 8 /bin/cat > "$TMPKEY" || true if ! grep -Eq \ '^ssh-dss[[:space:]]+[A-Za-z0-9+/=]+' \ "$TMPKEY" then rm -f "$TMPKEY" printf '%s\n' \ 'stage1: GoFlex device public key not received' \ >> "$CAP/events.log" exit 66 fi mv "$TMPKEY" "$AUTHDIR/$CPE_USER" chmod 0640 "$AUTHDIR/$CPE_USER" DDPASS="$(cat "$WORK/ddpass")" printf 'domain=%s ddpass=%s\n' \ "$SUBDOMAIN" \ "$DDPASS" printf 'stage1: registration accepted; name=%s\n' \ "$SUBDOMAIN" \ >> "$CAP/events.log" exit 0 fi if [ "$LOGIN" = "$CPE_USER" ]; then case "$CMD" in /usr/share/homebase-accounts/cpe-account.pl*) ACTION="$( printf '%s\n' "$CMD" | sed -n \ 's/.*--action=\([^[:space:]]*\).*/\1/p' )" [ -n "$ACTION" ] || ACTION='unspecified' printf 'cpe-account: action=%s\n' \ "$ACTION" \ >> "$CAP/events.log" success_xml exit 0 ;; *) printf '%s\n' \ 'stage2: unexpected remote command' \ >> "$CAP/events.log" cat <<'XML' XML exit 67 ;; esac fi printf '%s\n' \ 'unexpected SSH login identity' \ >> "$CAP/events.log" exit 68 HANDLER chmod 0755 "$HANDLER" cat > "$CFG" < "$LOG" 2>&1 & SSHD_PID=$! READY=0 for _ in $(seq 1 50); do if ss -H -ltn | grep -Eq ":${PORT}[[:space:]]" then READY=1 break fi if ! kill -0 "$SSHD_PID" 2>/dev/null; then echo 'ERROR: temporary sshd exited unexpectedly.' >&2 cat "$LOG" >&2 || true exit 1 fi sleep 0.1 done if [ "$READY" != 1 ]; then echo 'ERROR: temporary sshd did not become ready.' >&2 exit 1 fi cat </dev/null; do if [ -f "$CAP/events.log" ]; then CURRENT="$(cat "$CAP/events.log")" if [ "$CURRENT" != "$LAST" ]; then echo echo '--- recovery activity ---' printf '%s\n' "$CURRENT" echo '-------------------------' LAST="$CURRENT" fi fi sleep 1 done echo 'ERROR: temporary sshd stopped unexpectedly.' >&2 exit 1