Hackernoon logoReal-time Scanning of Other Terminals with Strace by@tutuz

Real-time Scanning of Other Terminals with Strace

Author profile picture

@tutuzTsuji Daishiro

Software Engineer

Introduction
Do you ever want to see other people's terminals on a Linux server? I have.Of course, having the terminal physically shown is one way, but it's a bit of a hassle. You can also use the 
script
 command, but it is a little more laborious because you have to ask the shower to execute the 
script
 command.
So I've created a tool that makes it easy to see the terminals of other users logged in on the server! This tool wraps 
strace
. It is called 
ttycopy
. It's incredible simple and very useful.
strace
It is well known that 
strace
 command can be used to trace a system call. Before introducing the workings of 
ttycopy
, let's review how to check a system call with 
strace
. For example, if the current directory is 
/tmp
 and there is an empty file named 
sample.txt
 under 
/tmp
, the result of stracing is shown below. In other words, the situation is as follows.
[root@localhost tmp]# pwd
/tmp
[root@localhost tmp]# ls
sample.txt
We can check with 
strace
 what kind of system call is being called when you call 
ls
.
[root@localhost tmp]# strace ls
execve("/usr/bin/ls", ["ls"], [/* 27 vars */]) = 0
brk(NULL)                               = 0xaf7000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2afb9f4000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=84100, ...}) = 0
mmap(NULL, 84100, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2afb9df000
close(3)                                = 0
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320i\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=155784, ...}) = 0
mmap(NULL, 2255184, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2afb5ad000
mprotect(0x7f2afb5d1000, 2093056, PROT_NONE) = 0
mmap(0x7f2afb7d0000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x23000) = 0x7f2afb7d0000
mmap(0x7f2afb7d2000, 6480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2afb7d2000

...

mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f288e995000
write(1, "sample.txt\n", 11sample.txt
)            = 11
close(1)                                = 0
munmap(0x7f288e995000, 4096)            = 0
close(2)                                = 0
exit_group(0)                           = ?
Even if we take one operation to get the result of the 
ls
 command as described above, we can see that many system calls are made behind the scenes.
ttycopy

I would like to tell you how this is being processing. The basic flow of the process is as follows.
  1. Check the PID of the tty's login process
  2. Retrieving read system calls to PID using the strace command
  3. Print a formatted string of the read system call output by strace
1.Check the PID of the tty's login process
The shell implementation is as follows.
pid=`ps fauwwx | grep sshd.*${tty} | grep -v grep | sed -e 's/^[a-zA-Z0-9]\+[ \n\r\f\t]\+\([0-9]\+\).*/\1/'`
This captures the PID using a regular expression with a string of the following process tree that can be retrieved when grep is done. You can use regular expressions to make it look neat.
[tsuji@localhost ~]$ ps fauwwx | grep sshd.
root      1531  0.0  0.1  82568  6236 ?        Ss   15:29   0:00 /usr/sbin/sshd -D
root      2830  0.0  0.2 149824  8916 ?        Ss   15:29   0:01  \_ sshd: root@pts/0
root     13315  0.0  0.2 158980 10280 ?        Ss   18:58   0:00  \_ sshd: root@notty
root     14956  0.0  0.2 154512  9352 ?        Ss   20:10   0:00  \_ sshd: tsuji [priv]
tsuji    14959  0.0  0.1 154512  4092 ?        S    20:10   0:00      \_ sshd: tsuji@pts/1
tsuji    15012  0.0  0.0 112672  2268 pts/1    S+   20:11   0:00              \_ grep --color=auto sshd.
2.Retrieving read system calls to PID using the strace command
The shell implementation is as follows.
strace -e read -s16384 -q -xx -p ${pid} 2>&1
What we're doing is using trace to retrieve the read system call issued by the PID associated with the tty we just retrieved. Because various other system calls are called besides the read system call, only the read system call is extracted with the option 
-e read
 of trace.
The read system call was the system call defined below, and the results that can be obtained with starce are also as follows.
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
For a user who is logged in at another terminal, execute the 
ls
 command in the 
/tmp
 directory.
straing terminal
# strace -p 14959 -e read
read(0, "l", 1)                         = 1
read(0, "s", 1)                         = 1
read(0, "\r", 1)                        = 1
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2985, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
We can only get results for read system calls that are being read from the standard input as shown above. The standard input is the file descriptor number 0.
3.Print a formatted string of the read system call output by strace

The goal is to display the contents of the second argument of the read system call obtained in step 2. The shell implementation is as follows.
sed -une "s/^read([0-9]\+, \"\(.*\)\".*/echo -n \$'\1'/p" | bash
First, the first part 
sed -une "s/^read([0-9]\+, \"\(.*\)\".*/echo -n \$'\1'/p"
. It captures the second argument of the read system call in a regular expression and gives it the strings 
echo -n` and `$''
.

Therefore, it is possible to restore the commands executed in the scanning terminal in real time.
The string output to the source terminal
[tsuji@localhost tmp]$ ls
sample.txt
[tsuji@localhost tmp]$
Strace the terminal string to be output after processing.
echo -n $'\x00\x00\x00\x10\x97\xcb\x9f\x29\xb7\x68\xee\xb5\x30\x84\xee\xad\x9d\x73\x52\x01\x17\x63\x30\x62\xe3\xe2\x7e\x61\x26\x64\x5b\x73\x93\x64\x96\xfd'
echo -n $'l'
echo -n $'\x00\x00\x00\x10\x70\x94\x30\xff\x6a\xfa\xbf\xfb\x1a\x1c\x23\x95\x85\x7d\x8f\xa4\xb7\x55\x42\xa4\x8e\x6e\x3e\x3e\xcd\xe4\xd1\xf7\xfb\x05\x5c\xb8'
echo -n $'s'
echo -n $'\x00\x00\x00\x10\x2d\xda\xa7\x40\xa5\xbc\x6a\xf4\x3f\x42\xce\x89\x6d\x3b\x6a\xe1\x16\xe6\x2e\x14\x55\x0d\xdd\x2b\xd8\x9c\xe0\x81\x84\x7d\x8d\x9d'
echo -n $'\r\n'
echo -n $'sample.txt\r\n'
echo -n $'\x1b\x5d\x30\x3b\x74\x73\x75\x6a\x69\x40\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74\x3a\x2f\x74\x6d\x70\x07\x5b\x74\x73\x75\x6a\x69\x40\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74\x20\x74\x6d\x70\x5d\x24\x20'
The 
-n
 option of 
echo -n
 is to avoid line breaks when interpreting. the 
$''
 form of Bash has the following effect. excerpt from the Man page
Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. Backslash escape sequences, if present, are decoded as follows:
ref: https://linux.die.net/man/1/bash

This can be used to expand to the meaning that the string holds.
All that's left to do is to let the shell interpret the 
echo
 string with the 
| bash
 to display the string.
Summary
I was able to casually share the terminal by retrieving a string of arguments for the read system call with 
strace
 and restoring them in real time. I think 
ttycopy
 is very useful and an educational tool because you can see other people's work in real time. If you want to scan the terminal, you should try it.
Thank you!

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!