将非ASCII字符写入tty上程序的stdin(通过ssh)

将非ASCII字符写入tty上程序的stdin(通过ssh),c,terminal,binary,reverse-engineering,tty,C,Terminal,Binary,Reverse Engineering,Tty,我将SSHd引入一个带有一些二进制挑战的远程服务器 有一次,它要求我输入文本。我知道它正在使用fgets()读取stdin,我可以在复制到的地方溢出并覆盖附近的变量 问题是我不知道如何键入我需要的地址值,\x84和\x04等等。如果我能够使用bash,我将echo-ne“\x84”或使用C十六进制数组,但我不能在这里做这种事情 我尝试过使用十六进制到ASCII转换器,复制二进制字符,还使用expect脚本发送二进制值,但两者都有相同的问题。x84添加了一个额外的字符,x04根本不会写入 您知道在

我将SSHd引入一个带有一些二进制挑战的远程服务器

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

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

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


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

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

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

您可以通过键入Ctl vDelete(这是向后删除字符,可能是labeld Backspace,而不是单独键盘中的向前删除)来获得
0x7f


我不确定是否有任何简单的方法可以在上面键入字符。根据终端仿真器中的设置,在键入相应的ASCII字符的同时按住Alt键,可能可以获得高位集。例如,Alt-A将发送
0xc1
0x80 | 0x41
)。

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

e、 g.
echo-ne“\x84”| xclip-i
然后在终端仿真器中单击鼠标中键(如果桌面也运行Linux)。(或者不,请参见下文)。或
echo…|sshuser@host
可以工作

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

相反,
echo-foo | ssh-tt
将强制它在远程端请求tty,即使您正在将内容传输到ssh中


确保SSH上的二进制数据通过TTY层到达接收程序的
stdin
的一种干扰性较小的方法是在每个字节前面加一个控件-
v
(十六进制0x16)

正如巴尔马指出的,这是下一个文字字符(
lnext
in
stty-a
output)。您可以在有效负载的每个字节之前使用它;它甚至在普通字符之前就被接收器中的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.|
您可以在本地通过键入
hextump-C
(也称为
hd
)来测试所有这些。只需在终端中运行它,键入或粘贴一些内容,然后控制-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到
hextdump
的过程中被TTY层屏蔽?后者似乎不太可能;可能是粘贴问题。Konsole的“编码”设置为UTF-8。它似乎没有简单的ASCII设置

可以尝试使用
LANG=C xterm
或其他方法,或者只编写脚本
expect
,将实际的二进制数据发送到
ssh
,而不是转义代码



fgets
当然不会处理转义序列,就像
strcpy
一样。一般来说,C函数不需要;但在C语言中,编译器在编译时处理字符串文本中的转义序列。

您的问题令人困惑。您是在询问如何在终端上键入控制字符,还是C程序如何将读取的内容写入内存?如果您是在二进制数据上操作,您不应该使用
fgets()
和friends。那是用来阅读文字资料的。对不起,我现在正在打电话。可能是前者。如果我写AAAA,我会在内存中得到x41x41x41x41等。如果我写\x84,它写X78X34等等。我在写我想要的十六进制值时遇到困难,因为fgets将所有内容解释为ascii,并且似乎不允许转义序列。这不是真正的编程问题,那么,更多的是关于如何使用Unix。你确定你正确使用了
expect
?当然,
fgets
不会在使用它的程序中处理转义序列。无论是
strcpy
,还是
scanf(“%s”)
。直到编辑之后我才完全阅读你的上一条评论,所以我想我实际上通过编辑它回答了你一半的问题。如果你能克服终端中的任何UTF-8假设,你也可以用高位集复制/粘贴数据。“在每个字节之前加上控件-v(十六进制0x16)”对我来说非常有效。我使用了一个pexpect脚本来发送十六进制。Barmar回答的扩展很好。两人都投了赞成票它甚至在普通角色非常有趣的信息之前就被接收器中的TTY层剥离了,谢谢!