【问题标题】:How to intercept SSH stdin and stdout? (not the password)如何拦截 SSH 标准输入和标准输出? (不是密码)
【发布时间】:2011-08-03 02:36:55
【问题描述】:

我意识到这个问题经常被问到,主要是那些想要拦截 SSH 的密码询问阶段的人。这不是我想要的。我在关注登录后的文字。

我想为 ssh 编写一个包装器,它充当 SSH 和终端之间的中介。我想要这个配置:

(typing on keyboard / stdin) ----> (wrapper) ----> (ssh client)

对于来自 ssh 的输出也是如此:

(ssh client) -----> (wrapper) -----> stdout

通过我在网上找到的标准技巧(简化代码),我似乎能够达到我想要的 stdout 效果:

pipe(fd)
if (!fork()) {
  close(fd[READ_SIDE]);
  close(STDOUT_FILENO);  // close stdout ( fd #1 )
  dup(fd[WRITE_SIDE]);   // duplicate the writing side of my pipe ( to lowest # free pipe, 1 )
  close(STDERR_FILENO);
  dup(fd[WRITE_SIDE]);
  execv(argv[1], argv + 1); // run ssh
} else {
  close(fd[WRITE_SIDE]);
  output = fdopen(fd[READ_SIDE], "r");
  while ( (c = fgetc(output)) != EOF) {
    printf("%c", c);
    fflush(stdout);
  }
}

就像我说的,我认为这行得通。但是,我似乎不能做相反的事情。我无法关闭(STDIN_FILENO)并复制管道的读取端。 SSH 似乎检测到了这一点并阻止了它。我读过我可以使用“-t -t”选项来强制 SSH 忽略其输入的非标准输入;但是当我尝试这个时它仍然不起作用。

有什么提示吗?

非常感谢!

【问题讨论】:

  • 您真的应该使用dup2 而不是dup 来替换stdout/stdin 等。
  • ssh 不应该关心标准输入的文件类型,如果您使用私钥而不是密码。你可以试试吗?

标签: c linux ubuntu ssh pipe


【解决方案1】:

Python 的Paramiko 使用 SSH 完成所有这些工作,但它是在 Python 源代码中。但是,对于 C 程序员来说,阅读 Python 很像阅读伪代码,因此请前往源代码并准确了解其工作原理。

【讨论】:

    【解决方案2】:

    如果您想在拦截器到位的情况下允许任何交互使用 ssh,则管道将不起作用。在这种情况下,您需要创建一个伪 tty。查找 posix_openptptsnamegrantpt 函数。还有一个名为openpty 的非标准但更直观的函数,以及一个名为forkpty 的包装器,这使您尝试做的事情变得非常容易。

    【讨论】:

      【解决方案3】:

      这行可能是错的:

        execv(argv[1], argv + 1); // run ssh
      

      如果您使用 argv[] 来自main() 的参数,则数组必须由 NULL 指针终止,我认为不能保证是这种情况。 编辑:刚刚检查了 C99 标准,并且 argv 是 NULL 终止的。

      execv() 不会搜索要执行的文件的路径,因此如果您将ssh 作为参数传递,则它等效于./ssh,这可能不是您想要的。您可以使用execvp(),但如果名为ssh 的恶意程序出现在/bin/ssh 之前的$PATH 中,则存在安全风险。最好使用execv() 并强制使用正确的路径。

      【讨论】:

        【解决方案4】:

        这是一个写入 ssh 的工作示例:

        #include <unistd.h>
        
        int main(int argc, char **argv)
        {
            int pid;
            int fds[2];
        
            if (pipe(fds))
                return -1;
        
            pid = fork();
        
            if (!pid)
            {
                close(fds[1]);
                close(STDERR_FILENO);
                dup2(fds[0], STDIN_FILENO);
                execvp(argv[1], argv + 1);
            }
            else
            {
                char buf[256];
                int rc;
        
                close(fds[0]);
                while ((rc = read(STDIN_FILENO, buf, 256)) > 0)
                {
                    write(fds[1], buf, rc);
                }
            }
            wait(NULL);
            return 0;
        }
        

        【讨论】:

          【解决方案5】:

          使用popen(而不是execv)来执行ssh cmd并且能够读写会话。

          【讨论】:

          • popen 的实现是否与所示代码有任何显着差异(即除了dup2dup)?
          猜你喜欢
          • 2021-06-24
          • 2014-09-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-20
          • 2013-09-18
          • 1970-01-01
          • 2013-06-13
          • 2012-03-16
          相关资源
          最近更新 更多