使用 scp 复制文件失败(debug1:退出状态 -1)

使用 scp 复制文件失败(debug1:退出状态 -1)

我想将单个文件从远程服务器复制到本地机器。

我没有远程机器的 root 权限,但我可以成功地通过 SSH 连接到给定密码的用户。

然而,在实际复制任何内容之前,连接就被关闭了。

这是我尝试过的:

scp -P PORT user@SRC_HOST:/tmp/file /home/k4mp3t/

使用详细模式我得到以下输出:

debug1: Next authentication method: password
Authenticated to HOST.IP ([IP]:PORT) using "password".
debug1: channel 0: new [client-session]
debug1: Requesting [email protected]
debug1: Entering interactive session.
debug1: pledge: filesystem
debug1: Sending subsystem: sftp
scp: Connection closed
debug1: client_input_channel_req: channel 0 rtype exit-signal reply 0
debug1: client_input_channel_req: channel 0 rtype [email protected] reply 0
debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 2896, received 3328 bytes, in 0.1 seconds
Bytes per second: sent 36199.5, received 41599.5
debug1: Exit status -1

scp连接为什么关闭了?

有关远程机器的信息:

ssh -V
OpenSSH_5.5p1 Debian-6+squeeze2, OpenSSL 0.9.8o 01 Jun 2010

有关我的机器的信息:

ssh -V
OpenSSH_9.0p1, OpenSSL 1.1.1q  5 Jul 2022

OS: EndeavourOS Linux x86_64
Host: VirtualBox 1.2
Kernel: 5.18.14-arch1-1
Shell: bash 5.1.16

我将非常感谢任何可以帮助我解决此问题的帮助或资源。

答案1

总结

尝试scp -O,例如:

scp -O -P 1234 user@server:/tmp/file /home/k4mp3t/

分析

输出的这个片段:

debug1: Sending subsystem: sftp
scp: Connection closed

告诉我您的本地scp尝试使用 SFTP 协议。传统scp使用不同的 SCP 协议。scp在这种情况下,您的不是传统的。


历史、SCP 和 SFTP

多年来scp(可执行文件)一直默认使用 SCP(协议),而不了解任何其他协议。我喜欢称 SCP 为“一种坚持不懈的黑客行为”。要通过 SCP 与远程系统通信,本地系统scp会调用ssh并传递命令。命令(就像任何通过的命令一样ssh) 由远程用户的 shell 解释。该命令尝试scp在远程端运行,使用未记录的选项将man 1 scp其转变scp为服务器。远程文件的名称嵌入在 shell 代码中。如果一切正常,本地scp和远程scp最终将相互通信并传输数据。

不幸的是,这是脆弱的;有些事情很容易破坏或滥用该协议:

  1. 如果你需要引用或转义将在远程端使用的路径名,则需要引用或转义本地 shell 和分别地对于远程 shell;即您需要两级引用/转义。一方面,这允许您在远程端使用通配符,例如,本地引用的*可能在远程端被取消引用并被扩展那里另一方面,如果你真的需要引用,并且你不知道这些东西是如何工作的,你很容易就会犯一个错误的命令(例子)。

  2. 如果您知道如何操作,或者不幸误操作(可能是因为引用错误,见上文),您实际上可以在远程端运行任意代码。换句话说,您可以传递一个“远程路径名”,远程 shell 会将其解释为 shell 代码(例子)。这实际上不是一个安全漏洞,因为ssh无论如何你都可以通过它运行相同的代码(毕竟这是你的本地scp为你做的)。问题在于潜在的将某些东西作为代码运行的能力无意中

  3. 服务器可能会给你提供你没有请求的文件,而你的本地文件scp可能会接受它们(取决于你使用的实现和版本,请参阅这个答案)。

  4. 如果远程“shell”实际上不是 shell(或者它是与 POSIX shell 不兼容的 shell sh),那么即使是简单、安全的命令也可能会失败。这可能包括您本地scp创建的任何命令。

  5. 远程 shell 可能会在执行命令之前运行某些操作(例子)。如果这涉及到打印到 stdout(即最终到本地scp)或从 stdin 读取(即最终从本地scp),则本地scp将失败(例子)。

  6. 如果远程端没有将 识别为命令,则不支持 SCP。如果远程端scp没有可执行文件,或者远程用户的 shell 中不包含远程 的目录,则会发生这种情况。scp$PATHscp

SFTP 是一种设计更好的协议。它肯定解决了 (1) 和 (2),我相信它解决了 (3)。在服务器端,它可以使用通过远程用户的 shell 调用的单独可执行文件,因此 (4) 和 (5) 仍然是问题;适当的配置可以使其独立于用户的 shell $PATH,因此 (6) 得到解决。或者它可以使用Subsystem sftp internal-sftp(in sshd_config),然后 (4) 和 (5) 得到解决(甚至可以修复远程用户损坏的启动脚本)。

SFTP 比 SCP 更好,但sftp(可执行文件)并不总是比 更好scpsftp在交互上工作得很好,而的语法scp类似于的语法cp(你甚至可以scp a b喜欢cp a bscp只需回到cp本地复制,对于某些人来说功能错误)。如果您想使用其中一个来以非交互方式(例如在脚本中)简单地传输几个文件,那么您可能会使用scp看起来更直接的那个。

现在你可以使用scpSFTP 代替 SCP。OpenSSHscp的 Modern 默认使用 SFTP。从变更日志

OpenSSH 9.0 于 2022-04-08 发布。 […]

[…]

此版本scp(1)默认从使用旧的 scp/rcp 协议切换到使用 SFTP 协议。


回到你的案子

您的scp服务器显然是现代的,并且默认使用 SFTP。但是,相关服务器不支持相关子系统。通常禁用它很简单,只需注释掉以下Subsystem sftp …。但是我期望subsystem request failed;你得到的是connection closed,所以可能不完全是这样。但出于某种原因,SFTP 仍然无法与此服务器配合使用。


解决方案

强制你scp使用 SCP。来自man 1 scp

-O
使用旧版 SCP 协议而不是 SFTP 协议进行文件传输。对于未实现 SFTP 的服务器、为了向后兼容特定的文件名通配符模式以及为了使用~旧版 SFTP 服务器的前缀扩展路径,可能需要强制使用 SCP 协议。

该命令如下:

scp -O …

请记住,这将使用 SCP 及其所有特性。


兼容性注意事项

即使您知道自己想要 SCP,一般来说也不能scp -O …盲目使用。对 SFTP 一无所知的实现或版本scp将无法识别-O,因此它们会失败。我知道您scp可以使用-O;它尝试使用 SFTP,因此它必须支持-O。但如果您尝试从旧系统使用一些旧版本进行相同的传输,scp则必须省略-O

您的原始问题表明您需要知道服务器支持哪些协议。我的观点是需要了解您所在地区scp支持哪些协议和选项。

要将文件传输到相关服务器或从相关服务器传输文件:

  • scp没有的现代版本-O无法工作(因为服务器不支持 SFTP),但应该可以工作-O
  • 但是旧的scp不能工作-O(因为它不识别该选项),它应该可以在没有的情况下工作-O
  • 并且我遇到过默认scp使用(并提供强制 SFTP)的情况;这个应该可以与没有显式的一样工作。-O-s-O-O

scp结论是:如今如果您想使用 SCP,那么没有通用的语法。

相关内容