Drukarki, ASCII-Art i JavaScript

O mało znanej funkcji drukarek piszą Krzysztof Zając, CTO Laboratorium EE i Mateusz Sieniawski, Security Engineer.

Opisywana w tekście sytuacja mogłaby się wydarzyć jedynie w potencjalnej próżni prawnej, w której nie obowiązują przepisy k.k.

Wszelkie działania związane z badaniem bezpieczeństwa sieci wykonujemy jedynie w przypadkach testów na życzenie klienta i wyłącznie za jego zgodą. Twój kolega Igrekowski bardzo często robi Ci dowcipy, więc chcesz się na nim odegrać. Wiesz, że ma on drukarkę sieciową, zatem postanawiasz mu się zrewanżować i wydrukować na niej coś śmiesznego bez jego zgody. Czy jest to trudne? Okazuje się, że można to zrobić bez problemu. Niektóre drukarki sieciowe posiadają usługę port 9100 printing. Pliki w formacie PostScript, które zostały wysłane na jej port 9100, zostaną wydrukowane. Co ciekawe, nie musi to być dokładnie plik PostScript. Niektóre (np. testowana przeze mnie Brother HL-5470DW) przyjmą też dowolny tekst wysłany na port 9100 i wydrukują go ładnym fontem o stałej szerokości.

Pozostaje problem, jak coś wysłać do jego drukarki? Nie można połączyć się z drukarką, bo znajduje się ona w sieci wewnętrznej Igrekowskiego, do której nie masz dostępu. Okazuje się, że zamiast wysyłać żądanie do jego drukarki, można go nakłonić, aby odwiedził spreparowaną wcześniej przez nas stronę. Może się tam znajdować skrypt JavaScriptowy, który z poziomu jego komputera będzie wysyłał już faktyczne żądania druku. Pozostaje jeszcze pytanie, jaki jest adres IP drukarki? Można po prostu go zgadnąć; Igrekowski znajduje się w sieci wewnętrznej, gdzie adresacja jest zapewne postaci 192.168.0.xxx, 192.168.1.xxx, itd. Jeśli wyślemy żądania ze wszystkimi możliwymi kombinacjami, to w końcu trafimy na poszukiwaną drukarkę.

Działalibyśmy więc w następujący sposób:

  1. Igrekowskiemu zostałby wysłany link do spreparowanej strony.
  2. Ta strona tworzyłaby niewidoczny formularz przy użyciu Javascriptu, wypełniała go danymi i wysyłała go na adres IP_DRUKARKI:9100
  3. Drukarka przy odrobinie szczęścia traktowałaby żądanie jako plik do wydrukowania i drukowała go.

Możemy więc wysłać (i co za tym idzie wydrukować) żądanie HTTP. Nie jest to jeszcze najlepszy dowcip, gdyż tego typu żądania wyglądają tak:

POST /form HTTP/1.1

Host: evil.com

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-US,en;q=0.5

Connection: close

Content-Type: application/x-www-form-urlencoded

Content-Length: 10

key1=value1&key2=value2

Pierwsza część żądania to nagłówki, po których następują dane (w tym

przypadku danymi są key1=value1&key2=value2).

Najlepsze teraz byłoby wydrukowanie zdjęcia, niestety jakkolwiek bym nie

próbował, drukarka traktowała żądania HTTP przychodzące na port 9100 jako tekst.

Może więc ASCII-art? Niestety, domyślnie w zmiennych przesyłanych w formularzu spacje, tabulatory, znaki nowej linii, i inne narzędzia których potrzebujemy. żeby ten ASCII-art wyglądał sensownie, są zastępowane przez ich kody (np. %09, %0A...). Aby rozwiązać ten problem, możemy wykorzystać enctype formularza. Enctype opisuje, w jaki sposób dane wysyłane przez użytkownika są zapisywane w żądaniu HTTP. Jedna z możliwych opcji to ”text/plain”, która wyłącza zamianę np. tabulatorów i znaków nowych linie na krzaczki. Zazwyczaj, z różnych powodów, z tej opcji się nie korzysta, ale przeglądarki nadal ją obsługują, więc możemy jej użyć.

Podsumowując, cała procedura przebiega następująco: wysyłamy znajomemu link, znajomy klika, jego drukarka drukuje przygotowane przez nas dane, dzięki czemu możemy wydrukować np. taką wiadomość:

printing.jpg