[LINUX] How to hack a terminal

Future Advent Calendar 2019 This is the article on the 17th day.

I'm addicted to Go these days, but this time I'll change my mind. I would like to introduce a tool called ttycopy that shares a terminal, which I used occasionally in the previous project.

There is a scene like ~~ I want to hack the screen ~~ I want to see ...! When the super engineer is sshing on the server and doing something. After that, check the screen by double-checking whether the command is entered correctly on the server. If there is a physical distance, it is difficult to display the screen on the monitor. [^ 1]

[^ 1]: Of course, when using it, decline it before using it.

One way is to show the screen, but it would be smart if you could refer to it with a little tool. In Perl, there is a tool called ttylog. Inspired by ttylog, I created a shell-powered ttycopy. It works in the shell, so you can copy and paste the ttycopy implementation and run it casually.

Sample operation

It works as follows. It's a bit confusing, but I'm logged in to a server as the root and tsuji users and running ttycopy as the root user. You can see that the terminal logged in as the tsuji user is displayed from the middle of the terminal.

ttycopy

How ttylog works is also introduced in Share the terminal screen without permission and take a peek at the work of others. , The basic processing flow is as follows.

  1. Find out the PID of the tty login process
  2. Peep into system calls using the strace command for PID
  3. Format and display the read system call string output by strace

In ttycopy, I implemented it in the shell according to the above procedure.

Implementation in shell (Bash)

1. Find out the PID of the tty login process

The implementation in the shell 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/'`

It captures the PID of the process tree, which can be obtained by grep, using a regular expression. It's refreshing with regular expressions.

[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. Use the strace command for PID to peek at system calls

The implementation in the shell is the following part.

strace -e read -s16384 -q -xx -p ${pid} 2>&1

What we are doing is using strace to make a read system call issued by the PID associated with the tty we got earlier. Get it. Since various system calls are called in addition to the read system call, only the read system call is extracted with the strace option -e read.

The read system call was the system call defined below. The results that can be obtained with strace are also as follows.

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

For example, suppose you issue the following command in the referenced terminal.

--Obtaining terminal

[tsuji@localhost gomi]$ hoge
bash: hoge:The command was not found...
[tsuji@localhost gomi]$

At this time, if you refer to the read system call with strace -p $ {PID} -e read, the following output will be output.

--Strace terminal

[root@localhost ttycopy]# strace -p 14959 -e read
strace: Process 14959 attached
read(3, "\0\0\0\20\356\202\375C&&\357q\276\210pZ)\300\26M\357T\313\303k\6p\232\351\263\32\224"..., 16384) = 36
read(11, "h", 16384)                    = 1
read(3, "\0\0\0\20\235\230\204Ud\36)\370\266\233\362\305\2219\253g\335M\23\212\374h\250i@\235/\216"..., 16384) = 36
read(11, "o", 16384)                    = 1
read(3, "\0\0\0\20\324\357\304\vn\357BbW\241m\220yS\236\362\301\337\337\237c\203\245\223\221\253;,"..., 16384) = 36
read(11, "g", 16384)                    = 1
read(3, "\0\0\0\20\344\215\235\300\226\236\0\323\376\r\217,\257\322\326w\323R\264\3}\266\7q\315\215\344\346"..., 16384) = 36
read(11, "e", 16384)                    = 1
read(3, "\0\0\0\20^``\333\263h\372Z\336\335Y2\250\203\335\221\372faj\177\260f\302Sb\35\354"..., 16384) = 36
read(11, "\r\n", 16384)                 = 2
read(11, "bash: hoge: \343\202\263\343\203\236\343\203\263\343\203\211\343\201\214\350\246\213\343\201"..., 16384) = 62
read(11, "\33]0;tsuji@localhost:~/gomi\7[tsuj"..., 16384) = 51
^Cstrace: Process 14959 detached

In the above example, the strings strace: Process 14959 attached and strace: Process 14959 detached are displayed, but the strace option -q is used to suppress this output. Also, the -x option converts the string to hexadecimal for ease of display.

3. Format and display the read system call string output by strace

The goal is to display the contents of the second argument of the read system call obtained in step 2. The implementation in the shell is as follows.

sed -une "s/^read([0-9]\+, \"\(.*\)\".*/echo -n \$'\1'/p" | bash

The first half is sed -une" s / ^ read ([0-9] \ +, \ "\ (. * \) \". * / Echo -n \ $'\ 1'/ p ". The expression captures the second argument of the read system call and gives it the strings ʻecho -nand$''`, so you can get a string like this:

--Character string output to the acquisition source terminal

[tsuji@localhost gomi]$ cat hoge
hoge
[tsuji@localhost gomi]$

--Terminal character string output after processing by strace

echo -n $'\x00\x00\x00\x10\xc6\x1e\x56\xc6\x1f\x11\x7e\x57\x11\xaf\xdb\x2a\x91\x32\x84\x8e\x6e\x5b\x12\xc1\x72\x94\x36\x17\x12\xbb\x7c\xab\x4b\xdd\x19\x33'
echo -n $'c'
echo -n $'\x00\x00\x00\x10\x5d\x68\x72\x7c\x74\xca\x3c\xd1\x57\xfc\x14\x7d\x55\x34\x66\x15\x03\xcb\x26\x7c\x17\xbc\x7f\x7a\xf5\x25\x40\xed\xa8\x21\x39\xb3'
echo -n $'a'
echo -n $'\x00\x00\x00\x10\x05\x3d\x4a\xc2\x76\x1c\xd4\x23\x2a\x17\xc6\xa1\x1c\xf2\xdb\x14\x75\x1c\x7d\xb7\x21\xfb\xfc\xcd\x2d\x5c\xef\x06\x6c\x97\x01\x28'
echo -n $'t'
echo -n $'\x00\x00\x00\x10\x66\xb0\x8c\x40\x10\xa6\xf3\x9b\x36\x75\xd5\xc1\x65\x63\x94\x4f\x77\xd9\x10\x6d\xcf\xbb\x48\xed\x8b\x43\x58\x20\x54\x08\xde\x9b'
echo -n $' '
echo -n $'\x00\x00\x00\x10\x60\x6e\xb6\x06\x43\x16\xf5\x75\x89\x90\xb6\x42\x2c\xfe\x8b\x97\xae\xad\x47\x26\xf9\x39\xfc\xd2\x84\x37\xde\x0d\xe5\x32\xbc\x80'
echo -n $'h'
echo -n $'\x00\x00\x00\x10\x00\xe4\x3d\xb7\xd9\x79\x2e\x46\x80\xd5\xa5\xc2\xa7\x9a\xc7\x0c\xe1\x58\x7b\xd5\x97\xff\x00\xab\x72\x51\xa4\xbb\xab\x7d\xd1\xaf'
echo -n $'o'
echo -n $'\x00\x00\x00\x10\xf8\x1d\xce\xe6\x7f\x1a\x43\x94\xa2\xde\x3d\x3c\xb5\xe9\xb9\x94\x39\x43\x63\xfd\xa9\x1f\x45\x83\x64\x5c\x3a\xdf\xa8\x1a\xa4\x86'
echo -n $'g'
echo -n $'\x00\x00\x00\x10\x90\x69\x42\xa9\x48\x99\x0c\x52\xe9\x49\xbd\x4e\xa5\x17\x01\xff\xac\xec\x29\x75\x2c\xc0\x2b\x7c\x07\x85\xf2\x2f\xce\x71\x8f\x46'
echo -n $'e'
echo -n $'\x00\x00\x00\x10\xd9\x91\x38\x08\x0b\x95\x78\xd4\x80\x51\xa2\xe8\xef\x20\x06\x45\xa9\x3c\xf0\xa3\x10\x7d\x06\x32\x2d\x31\x53\x57\x40\x77\x1b\x29'
echo -n $'\r\n'
echo -n $'\x68\x6f\x67\x65\x0d\x0a\x1b\x5d\x30\x3b\x74\x73\x75\x6a\x69\x40\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74\x3a\x7e\x2f\x67\x6f\x6d\x69\x07'
echo -n $'[tsuji@localhost gomi]$ '

The -n option of ʻecho -nis to prevent line breaks when interpreting. The Bash$''` format has the following effects: Excerpt from the Man page. [^ 2]

Words of the form $'string' are treated specially. This word expands to a string and is then replaced with a backslash-escaped character as specified by the ANSI C standard. The backslash escape sequence is decoded (if any) as follows:

By using this, it is possible to expand to the meaning that the character string holds.

After that, you can display the string by letting the shell interpret the string ʻecho with | bash`.

Summary

I was able to casually share the terminal by getting the string of the read system call argument with strace and restoring it in real time. I think it's an educational tool because you can see the work of other people in real time. If you want to hack the terminal, please use it.

If you like, you can get motivated by adding a star to ttycopy: v:

Recommended Posts

How to hack a terminal
How to call a function
How to write a Python class
How to make a slack bot
How to create a Conda package
How to make a crawler --Advanced
How to make a recursive function
How to create a virtual bridge
How to make a deadman's switch
How to create a Dockerfile (basic)
[Blender] How to make a Blender plugin
How to delete a Docker container
How to make a crawler --Basic
How to create a config file
How to create a clone from Github
How to split and save a DataFrame
How to build a sphinx translation environment
How to create a git clone folder
Qiita (1) How to write a code name
How to add a package with PyCharm
[Python] How to make a class iterable
How to draw a graph using Matplotlib
[Python] How to convert a 2D list to a 1D list
[Colab] How to copy a huge dataset
[Python] How to invert a character string
How to install a package using a repository
How to get a stacktrace in python
How to create a repository from media
How to make a Backtrader custom indicator
How to choose a Seaborn color palette
How to test on a Django-authenticated page
How to make a Pelican site map
How to run a Maya Python script
How to make a dialogue system dedicated to beginners
How to calculate the volatility of a brand
How to read a CSV file with Python 2/3
A simple example of how to use ArgumentParser
How to share a virtual environment [About requirements.txt]
How to send a message to LINE with curl
How to create a Python virtual environment (venv)
How to code a drone using image recognition
How to open a web browser from python
How to clear tuples in a list (Python)
How to hold a competition at Coda Lab
How to draw a 2-axis graph with pyplot
How to embed a variable in a python string
How to create a function object from a string
How to draw a 3D graph before optimization
How to create a JSON file in Python
How to make a dictionary with a hierarchical structure.
How to generate a Python object from JSON
How to deploy a Streamlit application to GCP (GAE)
How to implement a gradient picker in Houdini
How to add a Python module search path
How to make a QGIS plugin (package generation)
How to extract coefficients from a fractional formula
How to write a ShellScript Bash for statement
How to remember when you forget a word
How to measure line speed from the terminal
How to notify a Discord channel in Python
How to create a shortcut command for LINUX