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