Como jogar com um companheiro de quarto

Do tradutor


O estudante da Universidade Tufts conta como provocar o colega de quarto. Ele até me prendeu quando começou sua história com o fato de que eles tinham uma TV 4K no albergue.

1. Introdução


Antes de falar sobre como trouxe o infeliz Logan, devo explicar o sistema de mídia em nossa sala. Em breve você entenderá o porquê.

Logan, se você leu isso, espero que tenha se divertido mais do que não.

Disposição


Temos um computador com um Ubunt de mesa conectado a um aparelho de TV. Ele atua como um servidor de mídia. Como ele ainda precisa de uma conexão permanente com a Internet, um servidor da Web com algumas páginas, um servidor SSH e vários outros serviços ainda estão funcionando lá.

Devido ao fato de que a televisão é 4K e o computador é montado a partir do que estava à mão, sua placa de vídeo não é puxada. Logan decidiu comprar o velho NVIDIA vidyuha, lançado há algumas gerações (o que ainda é muito melhor do que era) para reproduzir vídeo 4K normalmente.

O nascimento de uma ideia


Logo após a instalação, descobrimos algumas falhas nos drivers. Naquele momento, pensei que seria divertido poder exibir manualmente mensagens de erro.

Após algumas pesquisas na Internet, ficou claro que chamar remotamente uma mensagem na televisão é tão simples quanto:

  1. Efetue login via SSH no computador como o usuário executando a transmissão
  2. DISPLAY=:0 zenity --info --text '!'

DISPLAY=:0 necessário, porque na minha sessão não há exibição, mas quero mostrar a mensagem na tela principal.

Como tivemos problemas com o NVIDIA vidyuha, decidi me concentrar em algo como:

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

Funcionou, mas cada vez que efetuar login no servidor usando o cliente SSH para baixar o Logan é um prazer. Então eu decidi trapacear. Pensei na tarefa da coroa de enfurecê-lo dentro do cronograma, mas havia alguns problemas:

  1. Na verdade, regularidade
  2. Tivemos outras tarefas na coroa, o que aumentou o risco de divulgar minha tarefa insidiosa

Outras opções como o script SysVInit foram descartadas pelos mesmos motivos. Por isso, decidi criar uma página pública com o botão "Have a Logan".

Preparação do sorteio


Imaginei que precisaria de algumas coisas para começar:

  1. Algo que manipula a entrada do usuário
  2. Algo executando comandos arbitrários como um usuário da web

Então eu vim para:

  1. Nginx
  2. Extensão FPM para NGINX
  3. Php
  4. Pacote FPM para PHP

Como resultado, criei um site com a página de logan.html logan.html e a "página de ação" 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> 

Há um pouco de absurdo nas meta para adaptar a página para celulares (lembre-se de que eu facilito o uso em qualquer lugar?) Para aqueles que não sabem como renderizar HTML na minha cabeça, mostro como fica:



Quando o botão é pressionado, a solicitação POST voa para outra página, que faz todo o trabalho sujo:

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' /> 

Esta página faz várias coisas:

  1. Seleciona uma mensagem de erro aleatória
  2. Seleciona o tipo de caixa de diálogo.
  3. Demonstra uma mensagem por um período especificado (10 segundos)
  4. Ele aperta um botão e explica o que está acontecendo - tudo acompanhado pessoalmente pela imagem engraçada de Logan

Para aqueles que ainda não conseguem renderizar HTML em suas cabeças (novamente, esperamos que a maioria das pessoas), a página fica assim:



Se você estiver surpreso por que uma página da Web pode executar código dessa maneira e por que o proprietário de uma sessão do servidor da Web ( www-data ) pode executar comandos como um usuário de exibição ( thedisplayuser ), você ficará feliz em saber que eu thedisplayuser severamente arquivo sudoers :

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

Essa parte específica da configuração permite que www-data execute apenas / usr / bin / zenity como o usuário da tela sem uma senha. Eu fiz isso depois de mexer com erros estúpidos nas configurações PHP e NGINX. Então enviei o URL para alguns amigos no campus que conhecem Logan.

Resultado do sorteio


Louvado seja o céu, Logan reagiu o mais violentamente possível. Se ele estivesse um pouco irritado, o pensamento de que meus esforços haviam sido desperdiçados teria me irritado. Mas não! Ele perdeu a paciência. Não consigo contar quantas reinicializações, reinstalações de drivers e modificações no kernel houve. Só lamento não ter gravado um vídeo sobre como ele ficou louco depois de iniciar o VLC, quando alguém abriu um monte de janelas com mensagens sobre erros na placa de vídeo.

Mas fiquei muito empolgado e Chris, nosso outro colega de quarto, decidiu intervir ...

Caça ao caçador


Primeira etapa


Um belo dia, quando Logan estava dormindo, notei uma mensagem de erro que dizia: "Max está por trás de tudo isso". Choooo? Eu tenho uma brincadeira! Então, comecei a entender e descobri que alguém (Chris) introduziu essa frase em um conjunto de mensagens aleatórias no zenity.php . Eu o apaguei rapidamente (até Logan saber que eles estavam tocando) e decidi que a diversão havia terminado. Lá estava.

Segunda etapa


Depois de uma semana ou mais, a mensagem apareceu novamente. Eu pensei que Chris me tivesse queimado e re-adicionado à lista. Nada. Ele não estava lá. Após um estudo cuidadoso do arquivo, notei que agora ele é chamado /usr/sbin/zenity vez de /usr/bin/zenity (o padrão do sistema), e os sudoers tinham uma entrada permissiva correspondente. Então, o que é /usr/sbin/zenity ? Script de shell:

 #!/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 

Bem, esse foi o próximo nível de merda, se eu já conheci algo assim. 99% das vezes tudo funcionava como deveria e, no restante, um por cento da mensagem "Max está por trás" apareceu. Excluí o arquivo (eu sei, não valia a pena) e escrever para sudoers trouxe o zenity.php à sua forma original. As mensagens pararam de aparecer. Mas então eles voltaram.

Terceira etapa


Eu verifiquei o zenity.php . Nada de novo. /usr/sbin/zenity ? Desapareceu. Estou desanimado. Então eu decidi olhar dentro de /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 

Bastardo astuto. Ele consertou o binário do zenity, tornando-o um script bash que funciona uma vez e 70. Que diabos? E que tipo de rpmdb-client ? Então, lutei de volta mudando:

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

Você percebeu a diferença? Caso contrário, /usr/sbin/rpmdb-client é chamado em vez de /usr/bin/rpmdb-client , que inicia um script bash que não faz nada. Com sorte suficiente, ele não notará um caractere extra e sua mensagem nunca aparecerá.

TODO: Entenda a diferença entre os executáveis ​​do ELF /usr/sbin/zenity e o /usr/bin/rpmdb-client que Chris criou. Há alguma diferença estranha nos binários que eu ainda não entendi.

Quarta etapa


Eu decidi fortalecer a defesa, até Chris perceber a diferença em uma letra descrita acima. Cancelei todas as minhas alterações e decidi corrigir o zenity . Profunda gratidão a Tom Hebb (como em todos os meus posts técnicos) por me ajudar com isso. Aqui está o que eu fiz:

  1. Configurado o apt para baixar os fontes (neste caso, adicionando deb-src ao /etc/apt/sources.list )
  2. apt-get source zenity
  3. Feito um patch com quilt :
    1. quilt new myPatch.diff
    2. Um patch para src/msg.c que determina a presença da palavra "Max" no corpo da mensagem:

      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. Percebi que criar e instalar um novo pacote é mais pálido do que substituir um binário
  7. Substituiu silenciosamente o rpmdb-client (sua zenity ) pela minha versão
  8. Deu um tapinha nas costas

Esse patch altera o comportamento do zenity forma que, assim que a palavra "Max" aparece no texto da mensagem, o aplicativo silenciosamente não faz nada.

Conclusão


Até o final de março, Chris nunca descobriu que eu corrigi o binário. Como resultado, Logan não viu uma única mensagem com meu nome. Então decidi continuar o rali até contar tudo a ele depois do final do curso. Mas quando as aulas terminaram, nos separamos. Embora Logan e eu moremos juntos novamente no próximo ano, provavelmente não passaremos tanto tempo na sala para que o rali faça sentido. Decidi publicar este post antes de iniciar novos truques.

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


All Articles