Backdoory w aplikacjach PHP

05 maja 2014, 16:22 | Teksty | komentarzy 15
Tagi: , ,
: zin o bezpieczeństwie - pobierz w pdf/epub/mobi.

Wstęp

Backdoor (ang. „tylne drzwi”) to fragment kodu źródłowego, który umożliwia dostęp do aplikacji internetowej (bądź do innego rodzaju oprogramowania) w sposób znany jedynie jego autorowi, i z reguły dający niczym nie ograniczone uprawnienia do korzystania z systemu.

Tego rodzaju „tylne wejścia” z reguły pozostawiają sobie autorzy oprogramowania (np. w celach diagnostycznych). Ale nie tylko.

Celowo dodany backdoor jest najczęściej stosowanym przez włamywaczy sposobem na pozostawienie sobie możliwości powrotu do skompromitowanej aplikacji sieciowej. Ponieważ podstawową cechą takiego nieautoryzowanego wejścia powinna być jego niewykrywalność (np. przez administratorów serwera, autorów aplikacji, oprogramowanie do analizy kodu źródłowego, czy też systemy IDS/IPS), kluczową rolę odgrywa tutaj pomysłowość w „zaciemnieniu” kodu w taki sposób, by na pierwszy rzut oka nie wzbudzał żadnych podejrzeń co do swojego przeznaczenia.

W artykule przyjrzymy się kilku metodom służącym do maskowania zamieszczonego w kodzie aplikacji złośliwego kodu. Mimo sporych możliwości obfuskacji (zaciemniania) prawdziwej intencji podejrzanego kodu kilka rzeczy pozostaje dość charakterystycznych, np. atakujący musi w jakiś sposób przekazać payload do swojego „tylnego wejścia”. Stąd naszą uwagę powinny wzbudzić wszelkie odwołania do tablic globalnych umożliwiających przekazanie danych do aplikacji z zewnątrz (np. $_REQUEST, $_SERVER, $_COOKIES itp.), co do których jesteśmy pewni, że nie powinny się znaleźć tam, gdzie się na nie natknęliśmy.

O metodach wykrywania złośliwego kodu powiemy sobie parę słów pod koniec artykułu, na początek przyjrzymy się kliku przykładom tego, jak, korzystając z natywnych możliwości języka PHP, można ukryć backdoora w kodzie aplikacji internetowej.

 

Od eval() do funkcji zwrotnych, czyli mały przegląd backdoorów w aplikacjach PHP

W większości przypadków pozostawiony w kodzie skompromitowanej aplikacji złośliwy kod służy do wykonywania dowolnych poleceń w systemie operacyjnym serwera. Istnieją nawet całe, gotowe skrypty (jak c99 czy r57), które umożliwiają operacje na plikach i katalogach serwera czy wykonywanie zapytań w bazie danych. Udostępniają one nawet proste interfejsy graficzne.

Skrypty te cechuje jedna zasadnicza wada: są duże (nawet kilkadziesiąt kB) i łatwo wykrywalne zarówno przez oprogramowanie IDS/IPS, jak i podczas manualnej inspekcji. Do tych samych zadań, choć może w nieco utrudniony od strony „user experience” sposób, zwykle wystarczy możliwość przekazania do aplikacji polecenia powłoki i wykonanie go na serwerze przez zainfekowany kod.

1. eval() backdoor

Najprostszym typem backdoora w PHP jest użycie funkcji eval(), która wykonuje kod przekazany jej jako argument typu string:

Znak ‚@’ użyty przed nazwą funkcji powoduje, że na standardowe wyjście nie są przekazywane przez interpreter PHP żadne komunikaty błędów. To zabezpiecza backdoora przed wykryciem w przypadku np. niezgodności typów argumentów bądź ich braku (co w przypadku właściwej konfiguracji interpretera PHP powinno skutkować ostrzeżeniem – tzw. „warning” bądź „notice” zapisanym w logach – pamiętajmy o wyłączaniu raportowania błędów bezpośrednio do aplikacji!).

Wracając do przykładu – w rezultacie uzyskujemy możliwość przekazania w parametrze GET prawidłowego kodu PHP i jego wykonanie na zdalnym serwerze:

1. Użycie funkcji eval() i przekazanie jej kodu PHP jako argumentu wywołania.

1. Użycie funkcji eval() i przekazanie jej kodu PHP jako argumentu wywołania.

Aby umożliwić wykonanie bardziej rozbudowanego kodu (np. wielolinijkowego), przekazywany payload może być zakodowany przy użyciu Base 64, a następnie wykonany przez lekko zmodyfikowaną wersję z poprzedniego przykładu:

Sposobów na zaciemnienie kodu PHP jest więcej – sporo ciekawych przykładów wraz z dekoderem online można znaleźć na stronie Simple online PHP obfuscator (mobilefish.com)

Aby nieco utrudnić wykrycie naszego złośliwego kodu, zamiast przetwarzania argumentu przesłanego w żądaniu HTTP, możemy posłużyć się zmienną globalną $_SERVER i umieścić złośliwy kod np. w nagłówku żądania User-Agent czy Referrer (ogólnie – w jednym z nagłówków, nad którego treścią mamy kontrolę w momencie wysyłania żądania do serwera). Możemy także skorzystać z mechanizmu ciasteczek (jako payload dla funkcji eval() podajemy wtedy odpowiednio spreparowane ciasteczko).

W przypadku użycia powyższych metod jedynym ograniczeniem jest dla nas maksymalny rozmiar złośliwego payloadu, który możemy wysłać. Parametry żądania HTTP mogą zawierać od 2kB do ok. 8kB w zależności od ustawień serwera WWW (w razie przekroczenia limitu otrzymamy błąd HTTP 414 Request-URI too long). Ciasteczko może mieć rozmiar maksymalnie 4096 bajtów, ale to ograniczenie można obejść, stosując kilka osobnych ciasteczek i łącząc je w jeden ciąg:

Możliwość modyfikacji nagłówków żądania może także okazać się pomocna, gdy chcemy zapisać wykonywalny kod PHP do logów serwera www, by wykorzystać go w dalszym etapie ataku wykorzystującym podatność Local File Include – ale to już temat na inne opracowanie.

2. @extract() backdoor

Bardzo ciekawym przykładem jest kod wykorzystujący funkcję extract() . Poniżej znajduje się krótki kod źródłowy, który z pozoru wygląda bardzo niegroźnie:

2. Przykładowy backdoor wykorzystujący funkcję extract() oraz funkcje anonimowe.

Aby przeanalizować powyższy kod, musimy omówić pewną cechę języka PHP, która została dodana w wersji 5.3 – funkcje anonimowe. Jedną z ich właściwości jest możliwość przypisania funkcji jako wartości zmiennej (podobnie, jak ma to miejsce np. w JavaScript), a następnie wywołanie jej, posługując się tylko zmienną jako jej identyfikatorem:

3. Funkcje anonimowe umożliwiają nam przypisanie funkcji jako wartości zmiennej.

Wróćmy teraz do backdoora z listingu (1) i zobaczmy, co stanie się, gdy wywołamy zainfekowaną stronę z następującymi parametrami żądania HTTP:

http://site.com?f=system&a=ls

4. Rezultat wywołania strony zainfekowanej kodem z listingu (2).

4. Rezultat wywołania strony zainfekowanej kodem z listingu (2).

Zauważmy, że w złośliwym kodzie nie została użyta żadna z funkcji języka PHP, która umożliwia wykonanie kodu w systemie operacyjnym (np. system()) lub pozwala na wykonanie kodu przekazanego jej jako argument (eval()). Dzięki wykorzystaniu mechanizmu funkcji anonimowych odpowiednią metodę przekazaliśmy dopiero w momencie wywołania backdoora.

3. Backdoor wykorzystujący preg_replace() z modyfikatorem /e

Wspomniane w poprzednim podrozdziale funkcje eval() oraz system() to tylko dwa przykłady, czego powinniśmy się wystrzegać i na co zwrócić uwagę (pozostałe niebezpieczne funkcje i konstrukcje językowe w postaci zestawienia znajdują się w dalszej części artykułu).

Kolejnym przykładem, któremu przyjrzymy się dokładniej, będzie funkcja preg_replace(). Rzut oka na dokumentację nie wskazuje, że może ona przyjmować jako jeden ze swoich argumentów funkcję zwrotną (callbacka) i umożliwić wykonanie dowolnego kodu. Przyjrzyjmy się zatem dokładnie argumentom, jakie przekazujemy do tej funkcji:

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

http://pl1.php.net/manual/en/function.preg-replace.php

Pierwszym ($pattern) jest ciąg w postaci wyrażenia regularnego, którego szukamy w argumencie trzecim ($subject). Gdy go znajdziemy, zastępujemy go ciągiem z argumentu drugiego ($replacement). Gdy do pierwszego argumentu dodamy modyfikator /e spowodujemy, że dopasowanie z drugiego argumentu zostanie wykonane – wystarczy zadbać, by był nim prawidłowy kod PHP:

5. Przykład na wykonanie dowolnego kodu przy użyciu funkcji preg_replace() i modyfikatora /e

4. Backdoor wykorzystujący funkcję zwrotną (callback) jako argument

Przyjrzymy się fragmentowi kodu, który do wykonania złośliwego payloadu używa funkcji zwrotnej jako jednego z argumentów funkcji, w której został ukryty. W przykładzie użyta została funkcja array_diff_ukey(), której wywołanie wygląda następująco:

array array_diff_ukey ( array $array1 , array $array2 [, array $... ], callable $key_compare_func )

http://www.php.net/manual/en/function.array-diff-ukey.php

Jej działanie jest dość proste: porównuje klucze dwóch (lub więcej) tablic asocjacyjnych przy użyciu funkcji zwrotnej przekazanej jej w postaci ostatniego argumentu.

Lecz co się stanie, gdy użyjemy array_diff_ukey() w następujący sposób:

a następnie wywołamy stronę zawierającą taki kod z następującymi argumentami:

http://site.com/page.php?password=ls&re_password=''&login=system

W kluczach porównywanych tablic znajdą się kolejno: ciąg ‚ls’ oraz ciąg pusty, a jako funkcję zwrotną podaliśmy system(), do której trafią oba klucze jako argumenty wykonania. W ostatecznym rachunku uzyskaliśmy efekt podobny, jak w poprzednich przykładach, czyli doprowadziliśmy do wykonania dowolnego polecenia w systemie operacyjnym, na co kod backdoora nie wskazuje nawet przy dość dogłębnym jego przeanalizowaniu.

6. Rezultat wywołania strony zainfekowanej kodem backdoora wykorzystującego array_diff_ukey() oraz funkcję system() przekazaną jako jeden z argumentów. z listingu (2).

6. Rezultat wywołania strony zainfekowanej kodem backdoora wykorzystującego array_diff_ukey() oraz funkcję system() przekazaną jako jeden z argumentów z listingu (2).

5. Kilka metod „zmylenia” przeciwnika

Aby ukryć złośliwy kod np. przed zautomatyzowanymi skryptami do wykrywania niebezpiecznych funkcji (które zostaną opisane w dalszej części), atakujący często próbują zamaskować fakt ich użycia.

Ciekawym przykładem może być użycie funkcji strrev() (odwracanie stringów) połączone z ich konkatenacją przy pomocy operatora kropki. Popatrzmy na przykłady:

Czy ktoś jest w stanie na pierwszy rzut oka wskazać, co stanie się po wykonaniu trzeciej linijki kodu w drugim przykładzie? A co się stanie, gdy te trzy linijki (odczytanie zmiennej $e z tablicy $_REQUEST, zainicjalizowanie zmiennej $p funkcją preg_replace() oraz jej wywołanie) będzie dzielić kilkadziesiąt czy nawet kilkaset linijek kodu? Co, jeśli w aplikacji dołączającej wiele zewnętrznych plików poprzez dyrektywy include() czy require() każda z tych linijek znajdzie się w innym pliku? Taki backdoor stanie się praktycznie niewykrywalny:

Sam payload także może zostać zakodowany (np. do ciągu nic nie znaczących liczb szesnastkowych), a następnie w rezultacie działania kilku rozsianych po całej aplikacji funkcji zamieniony w wykonywalny kod PHP albo polecenie powłoki wykonywane na serwerze.

 

Przykład z życia – Joomla Plugin Constructor Backdoor

Klika dni temu (23.04.14) na blogu firmy Sucuri pojawił się tekst opisujący pewien ciekawy rodzaj backdoora, który został znaleziony w jednym z pluginów do Joomli, a konkretnie w kodzie konstruktora tego pluginu.

Przykład jest połączeniem kliku opisanych wcześniej technik – wykorzystania właściwości funkcji preg_replace() z modyfikatorem ‚/e’, funkcji anonimowych oraz przekazywania argumentów przez mechanizm ciasteczek.

Spójrzmy zatem na kod źródłowy:

Na pierwszy rzut oka kod wydaje się niegroźny, jednak korzystając z wiedzy z poprzednich akapitów parę rzeczy powinno wydać się podejrzane. Przede wszystkim konstrukcja „/123/e”, która sugeruje użycie preg_replace() jako głównego „wykonawcy”. Sama nazwa funkcji nie pojawia się bezpośrednio w kodzie, ale fragment $option("/123/e",$auth,123); wskazuje na zmienną $option, której jako wartość może zostać podany rezultat wykonania kodu zawartego w linijce $option = $filter(JRequest::getString('p2', Null, 'cookie')); – mamy tu do czynienia z klasyczną sytuacją, kiedy zmienna otrzyma wartość będącą nazwą funkcji do wykonania (w tym wypadku będzie to właśnie preg_replace()).

Z kolei w zmiennej $auth powinien znaleźć się kod do wykonania. W rezultacie, w zależności od wartości zapisanej w ciasteczku p3 wykona się funkcja odczytana z ciasteczka p2 z argumentem zapisanym w ciasteczku p1.

 

Czego się wystrzegać

Jeśli jesteś programistą aplikacji internetowych, warto zastanowić się, jak uniknąć zaprezentowanych zagrożeń. Zacznijmy od zdefiniowania zestawu funkcji, których występowanie w kodzie źródłowym, jeśli nie jest przez nas zamierzone, powinno natychmiast wzbudzić nasze podejrzenia. Poniżej znajduje się ich zestawienie – każda z nich może posłużyć do budowy backdoora będącego w stanie wykonać dowolny kod przekazany przez atakującego np. w parametrach żądania HTTP.

Wśród funkcji języka PHP, które mogą posłużyć do stworzenia backdoora, możemy wyróżnić te, które umożliwiają zdalne wykonanie kodu w systemie operacyjnym, oraz te, które są w stanie wykonać kod PHP przekazany jako argument.

1. Funkcje umożliwiające zdalne wykonanie kodu na serwerze

Poza opisaną już wcześniej funkcją system(), są to:

2. Funkcje, które są w stanie wykonać kod PHP przekazany im jako argument

Do tej grupy zaliczamy najpopularniejszy sposób wykonania kodu, czyli zaprezentowaną w przykładach powyżej funkcję eval(). Poza nią są to:

3. Dobre praktyki

      • Jeśli używamy w naszej aplikacji konstrukcji wymienionych w tych dwóch podpunktach, zawsze miejmy na uwadze fakt, że brak kontroli nad tym, co przekazywane jest do tych funkcji jako argumenty (np. parametry żądań HTTP użyte bez żadnej walidacji) w prostej linii doprowadzi do sytuacji, gdy atakujący będzie w stanie zmusić aplikację do działania niezgodnego z przeznaczeniem.
      • Dlatego należy bezwzględnie przestrzegać zasady, że każde dane pochodzące z zewnątrz, a służące do sterowania logiką aplikacji (podobnie, jak ma to miejsce w przypadku zapobiegania atakom SQL Injection) powinny dotrzeć do docelowej funkcji w dokładnie takiej postaci, jakiej spodziewamy się, by kod wykonał się prawidłowo.
      • Dobrą metodą jest tu zastosowanie podejścia „whitelist” (białej listy), czyli dopuszczamy jedynie to, co jest dozwolone, odrzucając wszelkie nie pasujące do listy wartości.

Przykładem takiego podejścia może być sytuacja, gdy dołączamy do aplikacji (przy pomocy jednej z funkcji z rodziny include()/require()) kod z pliku, którego nazwa odczytywana jest z parametru GET żądania HTTP. Zdefiniowanie dopuszczalnych wartości, które mogą się tam pojawić, zapobiegnie atakowi Local File Include, gdyż nie pozwoli na dołączenie innego pliku niż pochodzący z listy dozwolonych wartości.

 

Jak znaleźć backdoora i jak się przed nim uchronić

Na zakończenie warto wspomnieć parę słów o metodach wykrywania złośliwego kodu w naszych aplikacjach. Ponieważ jest rzeczą praktycznie niemożliwą zidentyfikowanie wszystkich możliwych kombinacji przekazania payloadu do backdoora oraz jego wykonania, skupimy się na najpopularniejszych przypadkach.

Analizę aplikacji powinniśmy zacząć od przejrzenia drzewa katalogów i próby odnalezienia plików nie należących do niej. Jeśli jest to aplikacja dedykowana (np. naszego autorstwa bądź zlecona firmie zewnętrznej) będzie to zadanie w miarę proste. W przypadku aplikacji opensource (np. WordPress, Joomla czy inny popularny CMS) warto zajrzeć na forum poświęcone danemu systemowi i potwierdzić, czy znaleziony podejrzany plik należy do aplikacji, jakiegoś pluginu bądź szablonu czy znalazł się tam za sprawą udanego ataku.

Z kolei wizyta na stronie z repozytorium kodu źródłowego umożliwi nam porównanie oryginalnego kodu i szybką weryfikację dodanych bądź zmodyfikowanych linijek. Dobrym pomysłem będzie pobranie repozytorium na lokalny dysk i wykonanie kompleksowego porównania (np. poleceniem diff czy git diff) – wynik takiej operacji wskaże nam wszystkie miejsca, gdzie występują jakiekolwiek różnice.

Jeśli nie mamy dostępu do repozytorium z oryginalnym kodem źródłowym, a backdoor nie występuje jako samodzielny plik (został dopisany przez atakującego np. w wyniku udanej kompromitacji serwera FTP) – często jedyną metodą jest samodzielne przeanalizowanie zawartości plików z kodem źródłowym pod kątem występowania popularnych w backdoorach fraz i funkcji.

W tym celu można posłużyć się prostymi skryptami, które to zadanie realizują. Przykładowy skrypt powłoki, który przeszuka nam pliki, próbując odnaleźć wystąpienia niebezpiecznych funkcji, może wyglądać np. tak:

źródło: https://bechtsoudis.com/hacking/detect-protect-from-php-backdoor-shells/

Dużo wskazówek może nam dostarczyć analiza logów serwera www i żądań HTTP. W zależności od parametrów, jakie nasza aplikacja przyjmuje, w podobny sposób możemy przygotować prosty skrypt wykrywający w logach żądania zawierające dziwne wartości parametrów np. będące zakodowanymi w Base 64 ciągami sugerującymi użycie gdzieś w kodzie backdoora opartego na base64_decode().

Bardzo ważną kwestią jest niedopuszczenie do samego zarażenia aplikacji złośliwym kodem. Najczęstszą przyczyną są błędy umożliwiające bądź upload pliku zawierającego kod backdoora na serwer, bądź nieprawidłowe uprawnienia zapisu/odczytu plików i katalogów aplikacji, bądź też słabo zabezpieczony serwer FTP lub dane uwierzytelniające do niego.

Kod backdoora może też znaleźć się na serwerze w wyniku wysłania przez atakującego odpowiednio spreparowanego żądania HTTP PUT. Często do zarażenia dochodzi w wyniku błędu SQL Injection i wykorzystania funkcji serwera MySQL SELECT … INTO OUTFILE ….

 

Podsumowanie

Backdoor w aplikacji internetowej, niezależnie od tego, czy został w niej pozostawiony celowo przez programistów, czy też został dodany przez atakującego, to bardzo niebezpieczna sytuacja, do której nie powinniśmy w żaden sposób dopuścić. Możliwość wykonania dowolnego kodu czy to w kontekście naszej aplikacji, czy bezpośrednio na serwerze nie powinna być dostępna dla nikogo i w żaden sposób.

Ataki wykorzystujące pozostawione w kodzie źródłowym „furtki” mogą spowodować konsekwencje trudne do przewidzenia (od utraty danych po całkowite przejęcie serwera czy nawet całej infrastruktury sieciowej firmy. Sposoby zaciemniania kodu źródłowego oraz tworzenia backdoorów ewoluują wraz z językiem PHP i dodawanymi do niego funkcjonalnościami (dobrym przykładem są tu funkcje anonimowe, które pojawiły się wraz z wersją 5.3), dlatego warto śledzić to, co dzieje się w świecie PHP.

Jedną z ostatnich nowości jest zaprezentowany przez Facebooka język Hack, będący rozwinięciem języka PHP (hacklang.org). Pojawiło się w nim kilka nowości (jak choćby klasy generyczne), które mogą spowodować pojawienie się nowych technik umieszczania złośliwego kodu w aplikacjach budowanych z wykorzystaniem tej technologi.

 

Źródła

 

Rafał ‚bl4de’ Janicki– bloorq[at]gmail.com

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. e

    Jeśli chodzi o znajdowanie backdoorów w stronach na popularnych CMS, to nie ma potrzeby porównywać kodu z oryginałem ręcznie, są gotowe skanery.

    Do WP polecam Wordfence (darmowy plugin, w repozytorium). Miewa czasami false positivy (np. przy spolszczonej wersji WP), ale ładnie pokazuje diff plików i można mu kazać zignorować daną różnicę. Poza skanowaniem ma sporo innych przydatnych funkcji np blokowanie prób wejścia brute-forcem, czy skanowanie na podejrzany kod plików poza katalogiem WP.

    Do Joomli pewnie też są jakieś skanery.

    Odpowiedz
    • bl4de

      Oczywiście masz rację. Ale jest wiele systemów CMS, może nie tak popularnych, jak WP i Joomla, ale też dość często stosowanych – i do nich nie ma takich narzędzi. A także masa innych aplikacji (sklepy, CRM-y, platformy blogowe itp.)

      Odpowiedz
  2. Akurat wydaje mi się, że w PHP można było przypisywać funkcje przez nazwę do zmiennych od dawna (i wywoływać taką zmienną jako funkcję). Podobnie już od dłuższego czasu można zrobić:

    $className = get_class($this);
    $myCopy = new $className();

    Funkcje anonimowe (lambda) to chyba co innego – mianowicie, wtedy mamy faktycznie referencję do obiektu funkcji, a nie jej nazwę, w zmiennej…

    Odpowiedz
    • bl4de

      Tak, dokładnie o to mi chodziło – zmienna jest referencją do f-cji.

      Po prostu możesz zamiast np. takiego wywołania:

      doSomething($var, function() { // do something inside me });

      zrobić:
      $fn = function() {
      // do something inside me
      }

      doSomething($var, $fn);

      Różnica polega na tym, że $fn możesz zainicjalizować dowolną funkcją, natomiast pierwsze wywołanie przesyła samą definicję funkcji jako argument do doSomething() i nie masz jej jak „nadpisać”.

      Odpowiedz
  3. No nieźle, o wielu z tych technik nie miałem pojęcia…

    Odpowiedz
    • bl4de

      Tak naprawdę większość z nich to kombinacja kilku podstawowych technik oraz wykorzystanie małych trików (np. ten z f-cją strrev() albo „zaciemnienie” payloadu poprzez wykonanie na nim kilku następujących po sobie operacji) utrudniających zidentyfikowanie takiego szkodliwego kodu.

      Odpowiedz
  4. Damian Wąsik

    Super artykuł!

    Odpowiedz
    • bl4de

      Cieszę się, że się spodobał :)

      Odpowiedz
  5. m

    Warto wspomnieć że jeśli mamy możliwość skonfigurowania interpretera php (php.ini) wszystkie „niebezpieczne” funkcje (eval(), exec(), php_info() etc.) jeśli NIE są konieczne do prawidłowego działania aplikacji można wyłączyć korzystając z dyrektywy disable_functions

    (http://www.php.net/manual/en/ini.core.php#ini.disable-functions)

    Jeśli nawet mamy backdoor-a to i tak funkcja nie zadziała.

    Oczywiście NIE jest to lekarstwo na wszystko :)

    Odpowiedz
  6. józek

    Odczuwam pewien dyskomfort na myśl, że bl4de zna i wykorzystuje takie techniki w praktyce (If you know what I mean bl4de ;).

    Odpowiedz
  7. Bartek

    Super wpis. Już poszedł do znajomych PHP developerów :)

    Odpowiedz
  8. Czesław

    Świetny wpis. Niedługo moim zadaniem będzie przejrzenie kodu strony w php pod katem podatności, wezmę to pod uwagę. dzieki!

    Odpowiedz
  9. MateuszM

    Jako rozwinięcie tego artykułu chętnie przeczytałbym o „instalowaniu” takiego backdoora na serwerze „Powered by: PHP”.

    Odpowiedz

Odpowiedz