![系统管理员是否可以窃听他/她的用户终端?](https://linux22.com/image/49218/%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86%E5%91%98%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E7%AA%83%E5%90%AC%E4%BB%96%2F%E5%A5%B9%E7%9A%84%E7%94%A8%E6%88%B7%E7%BB%88%E7%AB%AF%EF%BC%9F.png)
当登录到计算机时,我可以从 的输出中找到每个用户的伪终端设备w
。作为系统管理员,我是否可以在用户不知情的情况下窃听该终端?换句话说,我希望看到该终端上所做的一切都作为我自己终端上的输出。
请注意以下事项:
- 这不适用于监视用户活动的实际用例:我知道有用于此目的的系统审核工具。我只是好奇是否可以做到。
- 我知道这个问题它似乎没有涵盖我要问的内容,因为所有解决方案都表明要么具有侵入性(用户会意识到我在做什么),要么产生太多噪音(解决方案
strace
)。一种接近的解决方案是建议使用gdb
.但这只能让我看到另一个终端的标准输出。
我尝试过的
我从我的终端尝试了这个:
tee /dev/pts/user_pts </dev/pts/user_pts
这使我可以看到用户在另一个伪终端中键入的每个字符。问题是,每隔几个字符,它就会“跳过”:它会在一台终端设备上显示一个流氓字符,但在另一台终端设备上则不会。它还可以防止从用户的伪终端设备执行任何命令。我不太确定为什么会发生这种情况以及是否有办法改进它。
我想看到什么
USER TERMINAL | MY TERMINAL
$ echo "Test" | # slick_command_here
Test | echo "Test"
$ | Test
答案1
如果您想查看终端仿真器上显示的内容,则需要监视该终端仿真器中伪终端的主端的 fd。那掌握fd 模拟连接到真实终端的线路。上面写的xterm
是您按下的按键生成的字符。它从中读取的内容就是它显示的内容。
例如,在 Linux 上:
$ lsof -ac xterm /dev/ptmx
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
xterm 15173 chazelas 4u CHR 5,2 0t0 2131 /dev/ptmx
然后运行例如:
stty -echo -opost
strace -e read -e read=4 -p15173 2>&1 | stdbuf -o0 sh -c '
grep "^ |" | cut -b11-60 | tr -d " " | xxd -r -p'
当然,如果您在与您要监视的终端类型和大小相同的终端中运行它,效果会更好。您可以通过以下方式获取尺寸:
stty size < /dev/pts/that-terminal
这会转储什么读从xterm
终端的主端,所以那里显示的内容,包括echo
正在键入的本地内容。
上面的命令-e read=4
用于输出在其 fd 4 上读取的strace
内容的十六进制转储xterm
。该命令的其余部分是将其转换为实际字符。我尝试过peekfd -n -8 15173 4
,但由于某种原因,只给出了所写的内容。
我们用来-opost
禁用监控终端中的任何后处理,以便xxd
写入从属端的所有内容使其在我们的主端保持不变,以便我们的监控xterm
获得与受监控的相同的东西。-echo
是这样的,如果受监控终端中的应用程序发送一个转义序列来请求终端的答复(例如那些请求光标位置或终端类型或窗口标题的转义序列),它将进入我们的监控xterm
和我们的xterm
意愿也回复一下。我们不希望在当地出现这样的情况。
您还可以通过跟踪write
对同一 fd 的系统调用来监视正在键入的内容(替换read
为write
上面的内容)。请注意,按 后Enter,终端仿真器会发送 CR 字符,而不是 LF。另外,由于我们在主端进行跟踪,因此如果用户键入a<Backspace>b
,即使终端设备处于规范模式,我们也会看到所有 3 个击键。
至于为什么你的不起作用:
tee /dev/pts/user_pts </dev/pts/user_pts
从终端设备读取就是读取用户输入,写入就是将其显示给用户。
您告诉我们tee
从终端设备读取。因此,它读取的内容(用户输入)不会read
由终端中运行的应用程序读取(反之亦然,tee
这application
将争夺终端输入)。写入终端设备,是为了在那里显示,而不是为了把它放回那里作为输入。当你这样做时
echo test
(echo
的 stdout 是终端),它与您输入的不同test
。
有一个ioctl
( TIOCSTI
) 可以将字符放回输入,但即使这样也不起作用,因为您可以将其放回后应用程序已经读取了更多内容,因此它会更改应用程序读取输入的顺序,无论如何,这意味着您将一遍又一遍地读取它。
答案2
答案3
这种方法涉及一些 gdb 和 tee。啊,它还使用 socat 来模拟伪终端。它可以在没有它的情况下工作,但用户会注意到他/她的输出不再是终端(像 vi 这样的程序会抱怨)。
它执行以下操作:
- 使用 socat 创建一个拦截器,它将自身公开为 pty。
- 拦截器连接到 tee,它在 $sys 终端和 $usr 终端中复制流。
- Gdb 用于替换 stdout/stderr 文件描述符以指向拦截器而不是 $usr 终端。
我注意到 bash 似乎将您输入的内容写入 stderr,我不确定其他程序是否也这样做。如果是这种情况,则不必拦截 stdin。
像这样称呼它:chmod +x /path/to/script; sudo /path/to/script <usr> <sys-adm>
。usr
和sys-adm
是终端的名称,例如/dev/pts/1
。因此,示例调用如下所示sudo /path/to/script /dev/pts/1 /dev/pts/2
:您可以使用命令找到您的终端tty
。用户终端用w
或ps
。
#!/bin/sh
[ "$1" ] || exit 1
[ "$2" ] || exit 1
usr=$1
sys=$2
utty=${1#/dev/}
ps -e -o tty= -o pid= -o user= | {
found_it=
while read -r tty pid_sh owner; do
if [ "$utty" = "$tty" ]; then
found_it=y
break;
fi
done
[ "$found_it" ] || exit 1
tmp=$(mktemp)
tmp_gdb=$(mktemp)
trap 'rm "$tmp" "$tmp_gdb"' EXIT
socat PTY,link="$tmp",echo=0,raw,openpty,user="$owner",mode=0600 SYSTEM:"tee $sys > $usr" &
printf 'call dup2(open("%s", 1), 1)\ncall dup2(open("%s", 1), 2)
detach\nquit\n' "$tmp" "$tmp" > "$tmp_gdb"
gdb -p "$pid_sh" -x "$tmp_gdb" >/dev/null 2>&1 &
wait
}
答案4
有一个名为 xkey.c 的简单 C 程序来展示 X11 的漏洞。我会让你谷歌一下。您可以使用它捕获 xterm 上的击键,而用户不会意识到。