Baby Wang ran recently wants to get married to someone!
A user wangran is created on a Linux host. There are two people, Wang ran and Wang Qi, who know the user's wangran password PW. In this case, Wang ran knows the root password while Wang ran does not. For the sake of security, remote users are not allowed to log on to the host directly using root, that is, Wang ran and Wang ran can only log on using the wangran user. Wang ran thinks that he is a Linux master, of course, she knows that their remote login terminal is/dev/pts/N, and N increases progressively from 0, she also knows that the/dev/pts/n permission is the permission of the user logging on through the terminal, that is, the permission of wangran. No su user will change the permission of the terminal file, because she does not know the root password, but she wants to do some XX, she came up with a way to marry people, and Wang ran started to work, her ultimate goal is to execute the root command on Wang Qi's login terminal. Imagine that Wang Qi's login terminal is/dev/pts/y, wang Ran's logon terminal is/dev/pts/X, and Wang ran was sure to execute the command on/dev/pts/Y because she had the right to operate/dev/pts/y, after all, they both use Usernames.
At first, Wang ran thought things simple. She first came up with a way for anyone who has used Linux:
Wangran @ drop :~ $ Echo ls>/dev/pts/y # certainly cannot be tested using the halt command, so LS is used.
In order to learn the results, Wang ran asked Wang to see how the screen changed. He was very depressed and wondered why a ls was written on the screen suddenly, while Wang ran only said that this was just a prank, in order to show her level of proficiency, she will definitely not tell her the ultimate goal, so the next job is done by Wang Qi in favor of Wang ran. I only wrote one ls, but it was useless. Didn't I write the carriage return symbol? So Wang ran, proficient in the VT100 terminal, came up with another one:
Wangran @ drop :~ $ Echo-e 'pwd ^ M'>/dev/pts/y # The line is changed, but LS is still not executed.
So Wang ran took out strace and asked Wang to execute strace bash on the screen. He got a lot of unreadable information and gave it to the hacker, so he left his seat, the two terminals are all given to Wang ran. At this time, Wang ran can certainly enter the passwd command to change the root password, but as a hacker, This is not elegant.
On Wang Qi's terminal: strace Bash is running:
...
Rt_sigprocmask (sig_block, null, [], 8) = 0
Read (0, "L", 1) = 1
Write (2, "L", 1l) = 1
Rt_sigprocmask (sig_block, null, [], 8) = 0
Read (0, "S", 1) = 1
Write (2, "S", 1 S) = 1
Rt_sigprocmask (sig_block, null, [], 8) = 0
Read (0, "/R", 1) = 1
Write (2, "/N", 1
) = 1
Rt_sigprocmask (sig_block, [int], [], 8) = 0
...
Stat64 (".", {st_mode = s_ifdir | 0755, st_size = 4096,...}) = 0
...
Clone (child_stack = 0, flags = clone_child_cleartid | clone_child_settid | sigchld, child_tidptr = 0x4005e968) = 8396
...
Waitpid (-1,... (LS command result )...
...
As long as you type a character, strace will read it from the standard input and write it back from the standard output. If something is written to another terminal through ECHO, in any case, it cannot be interpreted as a keyboard input by the target terminal. Because echo only writes characters to the output buffer and eventually sends them to the screen, you can only see the information you have written, however, you cannot send characters from another terminal to the input buffer of the terminal. In tty terminals and real terminals, only keyboard percussion can send messages to the input buffer, for terminals such as/dev/pts/N or serial ports, you must follow the "line rules", such as telnet terminal. You have typed the letter L remotely, the letter l will be encoded according to the transmission line and application protocol rules. After receiving the encoding, the host will also decode the data according to the line rules and application protocols, finally, the letter L is sent to the input buffer of the terminal. This process is complicated. The lovely Wang Ran decided to carry forward the hacker spirit, so she presented the process.
Take an SSH Linux host on a Windows machine as an example. Execute strace-p pid (an sshd process number at will), and The scaled result is as follows (marked ):
...
Read (4, "/3166/213/310/16384/..."...,) = 5 # read data from File ID 4 (encrypted data)
Select (11, [4 6 9 10], [8], null, null) = 1 (out [8]) # file 8 writable
...
Write (8, "L", 1) = 1 # Write 8 characters to the file "L"
...
Select (11, [4 6 9 10], [], null, null) = 1 (in [9]) # file 9 readable
...
Read (9, "L", 16384) = 1 # Read the character l in file 9
Select (11, [4 6 9 10], [4], null, null) = 1 (out [4])
...
Write (4, "A/313/3732/..."..., 36) = 36
Select (11, [4 6 9 10], [], null, null) = 1 (in [4])
...
Read (4, "/3./364/352/2..."..., 16384) = 52
Select (11, [4 6 9 10], [8], null, null) = 1 (out [8])
...
Write (8, "S", 1) = 1
...
Select (11, [4 6 9 10], [], null, null) = 1 (in [9])
...
Read (9, "S", 16384) = 1
Select (11, [4 6 9 10], [4], null, null) = 1 (out [4])
...
Write (4, "/20 zsms/215..."..., 36) = 36
Select (11, [4 6 9 10], [], null, null
...
The above is the output of strace, but what is the file descriptor 4, 8, 9? This requires the help of the lsof command. The following is the scaling result of lsof-p pid (sshd PID ).
----------------------------- Lsof sshd
...:/Usr/src/Linux # lsof-P 8793
Command PID user FD type device size node name
...
Sshd 8793 zyw 3u UNIX 0xc33c7ac0 12870 socket
Sshd 8793 zyw 4u IPv6 12857 TCP host1: SSH-> host2 #4 is a socket
Sshd 8793 zyw 5u UNIX 0xf413be40 12872 socket
Sshd 8793 zyw 6R FIFO 12873 Pipe
Sshd 8793 zyw 7 w fifo 12873 Pipe
Sshd 8793 zyw 8u CHR 5, 2 23921462/dev/ptmx #8 and 9 are terminals
Sshd 8793 zyw 9u CHR 23921462/dev/ptmx
...
After learning about the file descriptor, the next step is to analyze the execution process of sshd. You can see from the strace output that a piece of encrypted data is first read from the network, then it is written to/dev/ptmx, and then the same characters that have just been written are read from the same file, just like Echo. Where did sshd write the data? If you press enter after entering L and S, the file in the current directory will be displayed. Why?
To put it simply, a terminal is an old thing and generally divided into two categories. The first category is a real terminal, such as a terminal connected to a host through a serial port or a Slip Line terminal, this type of terminal is actually very simple. In essence, it is a network cable. You can understand the line procedure as a physical layer protocol and read the TTY line procedure code of slip, each line procedure has a receive_buf method that receives data from the driver and submits it to the line procedure for processing: slip_receive_buf is the receive_buf method of its slip, call netif_rx to decode the data according to the line rules and hand it over to the network protocol stack .; The second type of terminals is pseudo terminals, which are divided into two small categories: Console terminals, that is,/dev/ttyn (N is a number) and so on. They are simpler, the read buffer of this type of terminal is associated with input devices such as the keyboard, and the write buffer is associated with the output devices such as the screen or printer, as long as you hit the keyboard, data will enter the read buffer of the TTY series, and write data to the TTY series will be displayed on the output device. For another type of Network pseudo terminals, they are all paired, that is,/dev/ptmx and/dev/pts/n (n is a number). Therefore, if you write a character to the terminal file, the character will be read from the other end, vice versa. Therefore, Wang ran told everyone that sshd writes data to ptmx and then the data enters the read buffer of PTS/n. Who will read the data? The answer is shell. Execute lsof-p pid (Bash PID of an SSH terminal) and you will find that the standard input and output are all/dev/pts/n, then strace-p pid (Bash PID of an SSH terminal) will find that Bash first reads data from pts/N and then writes the same data to it, apparently, the data read is written by sshd to ptmx, and the same data is written to PTS/n. sshd can be read from ptmx, and then displayed back to a remote Windows terminal through socket, the entire process is sshd-ptmx and bash-pts/N in combination, Windows is only a display function.
Wang Ran's explanation is over. It should be still detailed. In other words, Wang ran still cannot forget her final task, so he made the last move, that is, writing a c file, the main function is as follows:
Int FD = open ("/dev/pts/0", o_rdwr );
IOCTL (FD, tiocsti, "L ");
IOCTL (FD, tiocsti, "S ");
IOCTL (FD, tiocsti, "/N ");
Return 0;
Run the command as a wangran user and get a disappointing permission error. After reading the kernel code, tiocsti's IOCTL will call tiocsti. In the tiocsti function, there are:
Static int tiocsti (struct tty_struct * tty, char _ User * P)
{
Char CH, mbz = 0;
Struct tty_ldisc * LD;
If (current-> signal-> tty! = TTY )&&! Capable (cap_sys_admin ))
Return-eperm; // permission Error
...
LD-> receive_buf (TTY, & Ch, & mbz, 1); // if you are a root user or use the current terminal, you can put the data in the read buffer.
...
}
But Wang ran is not Wang ran. What should I do? There is no way to place a trojan. In the end, the Linux vulnerability is still not found! However, it's slow! Can I put the permission check in the kernel like this? Wang ran felt very bad. Why didn't the user modify the permission of the corresponding terminal to the permission of the other when executing su other? Where is the answer? The answer is that the kernel writer does not trust the shell writer? Wang ran thinks this is the case, but the price of distrust is too high, and the mechanism and policy are no longer separated... obviously, why does it have to be done by the kernel? So Wang ran modified the kernel source code, removed the judgment in tiocsti, and modified the bash source code. Once the user su becomes another user, the terminal becomes another user permission, if Su becomes root, the wangran user has no permission to manipulate pts/N, and the kernel no longer needs to participate in authorization transactions in the user space, just as the kernel keeps the User Password safe, if a shell does not change the terminal permission during Su, you need to use the shell to execute functions similar to QQ or MSN Remote Assistance on other terminals.
Finally, Wang ran wants to summarize why ls cannot be executed on pts/N in/dev/pts/m through ECHO ls>/dev/pts/n, when she runs echo ls>/dev/pts/n on an SSH terminal on Windows, the entire command line is transmitted to the sshd process on the Linux host through the SSH protocol, then the sshd process writes it to/dev/ptmx, and finally the bash process read on/dev/pts/M returns the data that sshd writes to ptmx, that is, the entire command line, then execute bash, and finally redirect the output to/dev/pts/n. Writing pts/N means that the data can be read from ptmx. Indeed, the data is read by the sshd process related to PTS/n from ptmx, then, the characters LS +/n are displayed on the SSH terminal related to/dev/pts/n on Windows, bash on/dev/pts/n does not read any data. To execute the LS command, Bash must read When ls/N is output, data written to/dev/pts/N is only displayed on the SSH terminal of the Windows machine. We know that terminal input is generally related to the input device. Although the SSH terminal is far away from the Linux host and terminal, it is undeniable that if you want to execute ls on/dev/pts/n, this ls must be input on the keyboard of the Windows machine and in the SSH terminal window related to/dev/pts/n, data can be processed step by step through Windows machine-> Linux sshd-> Linux/dev/ptmx->/dev/pts/n-> bash and then run through bash->/dev/ PTS/n-> Linux/dev/ptmx-> Linux sshd-> Windows Server echo.