【问题标题】:Write non-ASCII characters to stdin of a progam on a tty (over ssh)将非 ASCII 字符写入 tty 上程序的标准输入(通过 ssh)
【发布时间】:2018-03-01 22:49:48
【问题描述】:

我通过 SSH 连接到远程服务器,遇到了一些二进制挑战。

有一次它要求我输入文本。我知道它使用fgets() 读取stdin,并且我可以在它被复制到的位置溢出并覆盖附近的变量。

问题是我不知道如何输入我需要的地址值,\x84\x04 等。如果我能够使用 bash,我会 echo -ne "\x84" 或使用 C 十六进制数组,但我可以不要在这里做那种事。

我尝试使用十六进制到 ASCII 转换器并复制二进制字符,还使用期望脚本发送二进制值,但两者都有相同的问题。 x84 添加了一个额外的字符,而 x04 根本不会写入。

知道如何在 Unix tty 上通过 ssh 将无法用 ASCII 字符表示的值可靠地写入内存的最佳方法吗?

【问题讨论】:

  • 您的问题令人困惑。您是在问如何在终端上输入控制字符,还是 C 程序如何将读取的内容写入内存?
  • 如果你在操作二进制数据,你不应该使用fgets() 和朋友。那是为了读取文本数据。
  • 抱歉,我现在正在打电话。可能是前者。如果我写 AAAA,我会在内存中得到 x41x41x41x41 等。如果我写 \x84 它会写 x78x38x34 等。我无法写出我想要的十六进制值,因为 fgets 将所有内容解释为 ascii 并且似乎不允许转义序列。
  • 这不是真正的编程问题,而是更多关于如何使用Unix。
  • 您确定您正确使用了expect 吗?当然fgets 不会使用它处理程序内部的转义序列。 strcpyscanf("%s") 也没有。在进行编辑之前,我没有完全阅读您的最后一条评论,所以我想我实际上通过编辑回答了您的一半问题。

标签: c terminal binary reverse-engineering tty


【解决方案1】:

对于高字符,您可能可以复制/粘贴。

例如echo -ne "\x84" | xclip -i 然后在终端模拟器中单击鼠标中键,如果您的桌面也在运行 Linux。 (也可能没有,见下文)。或者echo ... | ssh user@host 可以工作。

ssh -T 或任何其他终端仿真器中的等效项也可能是“禁用伪终端分配”的选项,因此远程端的程序将其 stdin 是来自 sshd 的管道,而不是我认为是一个伪终端。我认为这将禁用像 ^s^v 这样的特殊内容。

相反,echo foo | ssh -tt 将强制它在远程端请求一个 tty,即使您将内容通过管道传输到 ssh。


确保通过 SSH 传输的二进制数据通过 TTY 层并到达接收程序的stdin 的一种侵入性较小的方法是在每个字节前加上一个 control-v(十六进制 0x16)。

正如 Barmar 所指出的,这是文字下一个字符(stty -a 输出中的lnext)。您可以在有效载荷的每个字节之前使用它;它甚至在普通字符之前就被接收器中的 TTY 层剥离了。

# LANG=C sed to replace every byte with ^V byte
# using bash $'' to put a literal control-V on sed's command line
echo "hello" | LANG=C sed $'s/./\x16&/g' | hd
        16 68 16 65 16 6c 16 6c  16 6f 0a                 |.h.e.l.l.o.|

您可以通过输入hexdump -C(又名hd)在本地测试所有这些。只需在终端中运行它,然后键入或粘贴一些内容,然后按 control-D 直到它退出。

$ echo -ne "\x01\xff\x99" | LANG=C sed $'s/./\x16&/g' | hd
00000000  16 01 16 ff 16 99                                 |......|
00000006
      # yup, correct bytes from sed
$ echo -ne "\x01\xff\x99" | LANG=C sed $'s/./\x16&/g' | xclip -i
$ LANG=C hd
^A��     (middle click, return, control-d)
00000000  01 ef bf bd ef bf bd 0a                           |........|
     # nope, that munged my data :/

$ xclip -o | hd
00000000  16 01 16 ff 16 99                                 |......|

所以 X 选择本身是正确的,但它在我粘贴时被 Konsole 或在从 Konsole 到 hexdump 的途中被 TTY 层修改了?后者似乎不太可能;可能是粘贴问题。 Konsole 的“编码”设置是 UTF-8。它似乎没有纯 ASCII 设置。

也许尝试使用LANG=C xterm 或其他东西,或者只是正确编写expect 以将实际二进制数据发送到ssh,而不是转义码。


fgets 当然不处理转义序列,就像strcpy 一样。通常 C 函数不会;但在 C 中,compiler 在编译时处理 string literals 中的转义序列。

【讨论】:

  • '在每个字节之前加上一个 control-v (hex 0x16)' 对我来说非常有效。我使用 pexpect 脚本发送十六进制。对 Barmar 的回答进行了很好的扩展。两者都赞成。 '它甚至在普通字符之前就被接收器中的 TTY 层剥离'非常有趣的一点信息,谢谢!
【解决方案2】:

您可以通过在键盘上键入控制字符来编写0x000x1f 范围内的字符。在此ASCII Chart 的第三列中键入字符的同时按住 Control 键,以在第一列中获取相应的代码。

某些控制字符对终端驱动程序有特殊意义(例如Ctl-c 来终止进程),您可以通过在Ctl-v 前面按字面意思键入它们。

您可以通过键入 Ctl-vDelete 得到0x7f(这是向后删除字符,可能标记为 Backspace ,而不是可能在单独的键盘中的前向删除)。

我不确定是否有任何简单的方法可以在上面输入字符。根据终端模拟器中的设置,您可以通过在键入相应的 ASCII 字符时按住 Alt 键来设置高位。例如。 Alt-A 将发送0xc1 (0x80 | 0x41)。

【讨论】:

  • 如果您可以克服终端中的任何 UTF-8 假设,您也可以复制/粘贴设置为高位的数据。
猜你喜欢
  • 2012-12-16
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 2014-04-04
  • 1970-01-01
相关资源
最近更新 更多