📜 ⬆️ ⬇️

How to play a roommate

From translator


A Tufts University student tells how he teased his roommate. He even joked me when he began his story with the fact that they have a 4K TV in their hostel.

Introduction


Before I talk about how to bring unfortunate Logan, I have to explain the structure of the media system in our room. Soon you will understand why.

Logan, if you read this, I hope you have more fun than not.

Disposition


We have a computer with a desktop Ubuntu, connected to a TV set. It acts as a media server. Since he still needs a permanent Internet connection, a web server with a couple of pages, an SSH server and a number of other services are still running there.
')
Due to the fact that the 4K TV set, and the computer is assembled from what was at hand, its video card does not pull. Logan decided to buy the old NVIDIA, released a couple of generations ago (which is still much better than what it was) in order to play 4K video normally.

The birth of an idea


Soon after installation, we got a couple of glitches with drivers. At that point, I thought it would be fun to be able to manually display error messages.

After some searches in the internet, it became clear that remotely calling a message on the TV is as easy as:

  1. Log in via SSH on the computer under the user under which the translation is running
  2. DISPLAY=:0 zenity --info --text '!'

DISPLAY=:0 necessary, since there is no display in my session, and I want to show a message on the main screen.

Since we had problems with NVIDIA, I decided to stop at something like:

 DISPLAY=:0 zenity --warning --text '     .' 

It worked, but to log in to the server each time using an SSH client to pry Logan is such a pleasure. So I decided to cheat. I thought about the task in the crown to enrage him on schedule, but there were a couple of problems:

  1. Actually, the regularity
  2. We had other tasks in the crown, which increased the risk of disclosing my insidious task

Other variants of the SysVInit script type were dropped for the same reasons. Therefore, I decided to make a public web page with the “Fuck Logan” button.

Preparation of the draw


I figured that I would need a couple of things to get started:

  1. Something processing user input
  2. Something that executes arbitrary commands on behalf of a web user

So I came to:

  1. Nginx
  2. FPM extension for NGINX
  3. Php
  4. FPM package for PHP

As a result, I made a site with a landing logan.html and an “action page” zenity.php :

logan.html
 <!-- logan.html --> <html> <head> <style type="text/css"> form button { font-size: 20px; } div.explanation { width: 400px; } </style> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="HandheldFriendly" content="true"> </head> <body> <form method="POST" action="/zenity.php"> <button> </button> </form> </body> </html> 

There's a bit of nonsense in meta tags to adapt the page for mobiles (remember that I make it easy to use on the go?) For those who can't render HTML in their head, I’ll see what it looks like:



When the button is pressed, the POST request flies to another page that does all the dirty work:

zenity.php
 <?php /* zenity.php */ $messages = Array( " .", " .", " .", " .", " .", " .", "       .", "   .", "   .", "   .", "    and has recovered.", "     .", "     .", "     .", "     .", "     .", "     .", " NVIDIA  .", "NVIDIA    - . ( 43)", "    wlx10bef54d395c." ); $statuses = Array("error", "warning"); $msg = $messages[array_rand($messages)]; $status = $statuses[array_rand($statuses)]; $timeout = "--timeout 10"; exec("sudo -u thedisplayuser /usr/sbin/zenity --$status --display=:0 --text ': $msg' $timeout > /dev/null &"); include 'logan.html'; ?> <div class="explanation">                ,       .   ,        // .. </div> <br /> <img src='/logan.jpg' /> 

This page does a number of things:

  1. Selects a random error message.
  2. Selects the type of dialog box.
  3. Shows a message for a specified period of time (10 seconds)
  4. Draws a button and explains what is happening - all accompanied by a funny photo of Logan himself

For those who still can't render HTML in their heads (again, I hope most people), the page looks like this:



If you are wondering why a webpage is allowed to execute code in this way, and why the web server session owner ( www-data ) can execute commands as a display user ( thedisplayuser ), you might be happy to know that I strictly limited it to sudoers file:

 # /etc/sudoers www-data ALL=(thedisplayuser) NOPASSWD: /usr/bin/zenity 

This particular part of the configuration allows www-data to run only / usr / bin / zenity as thedisplayuser without a password. I did it after namayal with silly errors in the PHP and NGINX settings. Then I sent the URL to a couple of campus friends who know Logan.

Draw result


Praise heaven, Logan responded as violently as he can. If he were a little annoyed, the thought that my efforts were wasted would have annoyed me. But no! He lost his composure. I can not count how many reboots, reinstallations of the driver and kernel modifications. I only regret that I didn’t take a video of how he got mad after launching VLC, when someone threw out a bunch of windows with error messages on the video card.

But I got too carried away, and Chris, another of our roommates, decided to intervene ...

Hunter hunting


First stage


One fine day, when Logan was asleep, I noticed an error message that read: "Max is behind all this." Choooo? I got a pranchobrother! So, I began to understand and found out that someone (Chris) entered this phrase into a set of random messages in zenity.php . I quickly removed it (until Logan didn’t hear that he was being played) and decided that the fun was over. It was not there.

Second phase


After a week or so, the message came out again. I thought Chris burned me and re-added it to the list. Nothing. He was not there. After careful examination of the file, I noticed that it is now called /usr/sbin/zenity instead of /usr/bin/zenity (the system default), and sudoers had the corresponding permission record. So what is this /usr/sbin/zenity ? Shell script:

 #!/bin/bash echo '.' >> /tmp/log.txt if [ 0 -eq $((RANDOM % 100)) ]; then /usr/bin/zenity --error --display=:0 --text "   ." --timeout 10 > /dev/null & else /usr/bin/zenity "$@" fi 

Well, it was the next level shit, if I ever met like that. 99% of the time everything worked as it should, and in the remaining one percent, the message “Max is Behind” popped up. I deleted the file (I know, it was not worth it) and writing to sudoers , brought the zenity.php into its original form. Messages stopped appearing. But then they came back.

Third stage


I checked zenity.php . Nothing new. /usr/sbin/zenity ? Disappeared I am discouraged. Then I decided to look inside /usr/bin/zenity :

 #!/bin/bash # ---    --- # ---    --- # ---    --- # ---    --- # ---    --- if [ 0 -eq $((RANDOM % 70)) ]; then /usr/bin/rpmdb-client --error --display=:0 --text """"" """""" """""""""""" """"""""." --timeout 10 > /dev/null & else /usr/bin/rpmdb-client "$@" fi 

Little cunning little bastard. He fixed the zenity binary, making it a bash script that works 1 time and 70. What the hell? And what rpmdb-client is it all about? So, I fought back by changing it:

 # <> if [ 0 -eq $((RANDOM % 70)) ]; then /usr/sbin/rpmdb-client --error --display=:0 --text """"" """""" """""""""""" """"""""." --timeout 10 > /dev/null & else /usr/bin/rpmdb-client "$@" fi 

Got a difference? In the first case, it calls /usr/sbin/rpmdb-client instead of /usr/bin/rpmdb-client , which runs a non-doing bash script. With enough luck, he will not notice the extra character and his message will never appear.

TODO: Deal with the difference between the executable ELF files /usr/sbin/zenity and /usr/bin/rpmdb-client , which Chris created. There are some strange differences in binaries, which I have not yet understood.

Fourth stage


I decided to strengthen the defense, until Chris noticed the one letter difference described above. I canceled all my changes and decided to patch zenity instead. A deep thanks to Tom Hebba (as in every technical post I have) for helping me with this. Here is what I did:

  1. Configured apt to download sources (in this case, add deb-src to /etc/apt/sources.list )
  2. apt-get source zenity
  3. Made a patch with quilt :
    1. quilt new myPatch.diff
    2. Patch for src/msg.c , which determines the presence of the word "Max" in the message text:

      msg.c
       Index: zenity-3.18.1.1/src/msg.c =================================================================== --- zenity-3.18.1.1.orig/src/msg.c +++ zenity-3.18.1.1/src/msg.c @@ -21,6 +21,8 @@ * Authors: Glynn Foster <glynn.foster@sun.com> */ +#include <string.h> + #include "config.h" #include "zenity.h" @@ -85,6 +87,11 @@ zenity_msg (ZenityData *data, ZenityMsgD GObject *text; GObject *image; + if (strstr(msg_data->dialog_text, "Max") + || strstr(msg_data->dialog_text, "max")) { + return; + } + switch (msg_data->mode) { case ZENITY_MSG_WARNING: builder = zenity_util_load_ui_file ("zenity_warning_dialog", NULL); 
    3. quilt add src/msg.c
    4. quilt pop
  4. dpkg-source --commit
  5. dpkg-buildpackage -us -uc
  6. I realized that creating and installing a new package is more pale-yellow than replacing a binary
  7. Quietly replaced the rpmdb-client binary (its zenity ) with my version
  8. Patted his back

This patch changes the behavior of zenity in such a way that, as soon as the word “Max” appears in the message text, the application silently does nothing.

Conclusion


Until the end of March, Chris never found out that I had corrected the binary. As a result, Logan did not see a single message with my name. So I decided to continue the rally until I tell him everything after the end of the course. But when the classes were numb, we parted. Although Logan and I will live together again next year, most likely we will not spend so much time in the room so that the rally makes sense. Therefore, I decided to publish this post before making new tricks.

Source: https://habr.com/ru/post/417915/


All Articles