Ekspozycja kopii zapasowych
ważność krytycznamierzonysposób exposure
Pliki backup.zip i backup.tar.gz w katalogu głównym. Cała strona i baza do pobrania jednym kliknięciem — typowa pamiątka po migracji w pośpiechu.
Rozstrzyga sygnatura pliku (ZIP, gzip, 7z, RAR, xz), nie sam kod 200 — strona błędu nie jest archiwum.
WIKI
artykuł z 16.09.2026 · źródeł 9Ekspozycja kopii zapasowych to parametr monitoringu stron internetowych, który sprawdza, czy pod przewidywalnymi adresami w katalogu głównym witryny, takimi jak /backup.zip i /backup.tar.gz, serwer oddaje archiwum kopii zapasowej. Pomiar kończy się jednym z trzech wyników: archiwum dostępne publicznie, archiwum niedostępne albo nie udało się uzyskać odpowiedzi. MITRE opisuje to zjawisko jako słabość CWE-530: plik kopii zapasowej przechowywany w katalogu lub archiwum, do którego mają dostęp nieuprawnione podmioty [1].
Jak działa
Kopia strony powstaje zwykle na tym samym serwerze, który stronę podaje. Wtyczka UpdraftPlus domyślnie zapisuje kopie na serwerze hostingu, w folderze wewnątrz katalogu wp-content, a jej dokumentacja zaleca przechowywanie ich poza serwerem [7]. Duplicator dzieli każdą kopię na dwa pliki: archiwum archive.zip albo archive.daf z bazą danych i plikami strony oraz skrypt installer.php [5]. Przy klasycznej instalacji oba pliki trafiają do katalogu głównego docelowej witryny, skąd instalator jest dostępny pod adresem w rodzaju https://domena/installer.php [5]. Po udanej migracji dokumentacja każe usunąć instalator i archiwum, bo ich pozostawienie jest ryzykiem [5]. Lista plików do usunięcia obejmuje archiwum z identyfikatorem w nazwie, leżące w katalogu z plikiem wp-config.php, a w starszych wersjach wtyczki także pliki .sql ze zrzutem bazy [6].
Skaner nie zna nazwy pliku, więc ją zgaduje. Przewodnik OWASP opisuje najprostszą postać tej metody jako przepuszczanie listy typowych nazw plików przez mechanizm wysyłający żądania, żeby odgadnąć istniejące pliki i katalogi [4]. Wśród plików pozostawionych na serwerze wymienia kopie tworzone ręcznie albo automatycznie w postaci skompresowanych archiwów [4]. Nazwa stała, taka jak backup.zip, jest łatwiejsza do odgadnięcia niż nazwa z losowym identyfikatorem.
Sam kod 200 nie dowodzi, że archiwum istnieje, bo serwer może pod dowolnym adresem podać stronę HTML. Rozstrzyga początek treści. Według specyfikacji ZIP firmy PKWARE nagłówek lokalny pliku zaczyna się od sygnatury 0x04034b50 [2], a pola są zapisywane w kolejności od najmłodszego bajtu [2], więc w pliku są to bajty 50 4B 03 04, czyli znaki PK i dwa bajty sterujące. Rekord końca katalogu centralnego ma sygnaturę 0x06054b50 [2]. Plik gzip według RFC 1952 składa się z serii członów, a każdy zaczyna się od stałych bajtów ID1 = 31 (0x1f) i ID2 = 139 (0x8b), które identyfikują format [3].
Pierwsza odpowiedź to strona błędu podana z kodem 200, druga zaczyna się sygnaturą ZIP, trzecia sygnaturą gzip. Odczyt sygnatury komplikuje kodowanie treści. Dyrektywa AddEncoding serwera Apache, np. AddEncoding x-gzip .gz, oznacza pliki o danym rozszerzeniu jako zakodowane i dopisuje kodowanie do nagłówka Content-Encoding [9]. Nagłówek ten mówi klientowi, że treść trzeba zdekodować, żeby dostać właściwy typ danych [9]. Klient, który rozpakowuje taką odpowiedź automatycznie, widzi już treść po dekompresji, bez bajtów 1F 8B na początku [9].
Standardy i specyfikacje
- PKWARE APPNOTE 6.3.10 opisuje strukturę ZIP: nagłówki lokalne z danymi plików, katalog centralny i rekord końca katalogu centralnego, każdy z własną sygnaturą [2].
- RFC 1952 definiuje format gzip: bajty identyfikujące ID1 i ID2, metodę kompresji CM = 8 (deflate) oraz pole FNAME z oryginalną nazwą pliku zakończoną bajtem zerowym [3].
- OWASP WSTG-CONF-04 zauważa, że kopie mogą ujawnić kod źródłowy stron wykonywanych na serwerze [4], a pliki bez odnośników mogą zawierać pliki dołączane z danymi dostępowymi do bazy [4]. Do zgadywania poleca własne listy z rozszerzeniami kopii, m.in.
bak,old,orig,copyitmp[4]. - CWE-530 w rozszerzonym opisie wskazuje stare kopie pozostawione w katalogu WWW pod zmienioną nazwą, z których da się pobrać kod źródłowy [1]. Jako zabezpieczenie podaje politykę organizacji zakazującą trzymania kopii kodu aplikacji w katalogu WWW [1]. Słabość jest potomkiem CWE-552, „Files or Directories Accessible to External Parties” [1].
Zagrożenia i skutki
Cała strona w jednym pliku. Archiwum Duplicatora zawiera bazę danych i pliki strony [5]. Wśród plików jest wp-config.php, który leży w katalogu głównym instalacji i przechowuje dane połączenia z bazą: nazwę bazy, użytkownika, hasło i host [8]. Zawiera też unikalne klucze i sole, którymi WordPress zabezpiecza sesje użytkowników [8]. Według CWE-530 kto pobierze kopię, ma wszystkie zapisane w niej informacje, od zapytań do bazy po strukturę serwisu [1].
Pozostawiony instalator. Dokumentacja Duplicatora ostrzega, że każdy, kto znajdzie adres instalatora, może go uruchomić ponownie [5]. Instalator i archiwum leżą obok siebie, więc znalezienie jednego ułatwia znalezienie drugiego.
Usunięcie pliku nie cofa pobrania. Skasowanie archiwum zamyka dostęp do niego, ale nie odbiera kopii temu, kto już ją ściągnął. Dane z wp-config.php [8] trzeba wtedy traktować jak ujawnione.
Fałszywe trafienia. Serwer, który pod każdym adresem podaje stronę HTML z kodem 200, wygląda w samym kodzie odpowiedzi jak serwer z archiwum. Sygnatura ZIP [2] albo gzip [3] odróżnia plik od takiej strony.
Przykłady
| Sytuacja | Co zobaczy sonda | Znaczenie |
|---|---|---|
| Archiwum ZIP po migracji w katalogu głównym [5] | 200, treść od bajtów 50 4B 03 04 [2] | kopia do pobrania |
Archiwum .tar.gz w katalogu głównym | 200, treść od bajtów 1F 8B [3] | kopia do pobrania |
| Strona błędu podawana z kodem 200 | 200, dokument HTML | brak archiwum, fałszywy kod |
| Archiwum z losowym identyfikatorem w nazwie [6] | 404 pod adresem /backup.zip | plik istnieje, ale nazwa jest nieprzewidywalna |
Kopie wtyczki w podkatalogu wp-content [7] | 404 pod adresem w katalogu głównym | lokalizacja poza zakresem sondy |
Plik .gz z nagłówkiem Content-Encoding [9] | treść po dekompresji, bez 1F 8B | klient dekodujący automatycznie nie widzi sygnatury gzip |
- [1] CWE-530: Exposure of Backup File to an Unauthorized Control Sphere · MITRE
- [2] APPNOTE.TXT — .ZIP File Format Specification, wersja 6.3.10 · PKWARE
- [3] RFC 1952 — GZIP file format specification version 4.3 · IETF
- [4] WSTG-CONF-04 — Review Old Backup and Unreferenced Files for Sensitive Information · OWASP Web Security Testing Guide
- [5] Classic Installation · Duplicator
- [6] Removing Duplicator Files After Installation · Duplicator
- [7] Where are my UpdraftPlus backups stored? · TeamUpdraft
- [8] wp-config.php — Advanced Administration Handbook · WordPress.org
- [9] Apache Module mod_mime — AddEncoding · Apache Software Foundation
STATS
wyniki z systemu · tylko liczby zbiorczeTen parametr nie zapisuje odczytu per strona — przebieg zostawia tylko ustalenia, więc liczby sprawdzonych stron i wyników „ok” system nie ma. Pojawią się po wdrożeniu zapisu przebiegów per strona per parametr.
Ten parametr nie otworzył jeszcze żadnego ustalenia w bazie LAB247. Pusto nie znaczy „czysto” — znaczy, że nic nie przekroczyło reguły.
- Przebiegów
- 33sposób exposure
- W 30 dni
- 33przebiegów
- Ostatni
- 19.09.2026start przebiegu
- Stron w przebiegach
- —33 przebiegów bez liczby stron
CARD
karta z kodu CREATO_PING, odczyt 16.09.2026| Obszar i ważność | Bezpieczeństwo · krytyczna (B27) |
|---|---|
| Workflow i częstotliwość | creato_ping_security_v2 · P3 działa na LAB247cron co 24 h, T1–T3; T4 raz po anomalii · Dokładny skan. dns_integrity porównuje NS, MX, SPF i DMARC z wzorcem z poprzedniego przebiegu. |
| Sonda i helper | sposób exposure · CREATO_PING/helpers/exposure_check.py |
| Testy |
|
| Typ wyniku | 0 albo 1 ustalenie exposure_backup_archive (dwie ścieżki sklejone w jedno) |
| Jednostka | brak — wynik jakościowy; w dowodzie ścieżka, długość treści i rozmiar z nagłówka, bez samej treści pliku |
| Próg i reguła | Timeout odpowiedzi 15 s, połączenia 5 s. Reguła: kod 200 + sygnatura archiwum na początku surowych bajtów. |
| Gdzie leżą pokrętła | CREATO_PING/helpers/exposure_check.py → PROBES (reguła archive_magic), _ARCHIVE_MAGIC, _soft_200CREATO_PING/helpers/config.py → TIMEOUTS["exposure"], TIMEOUTS["security_connect"]CREATO_PING/helpers/security_runner.py → _TASK_SEVERITIESCREATO_PING/config/incident_policy.toml → [finding] exposure_backup_archive |
| Retencja odczytów | Odczytu per strona nie zapisujemy — zostaje tylko ustalenie w tabeli findings (otwarcie, zamknięcie, dowód). Replay po surowych odczytach dziś niemożliwy. |
| Znane rozbieżności |
|
| Karta przepisana z | CREATO_PING/helpers/exposure_check.py · CREATO_PING/helpers/config.py · CREATO_PING/config/incident_policy.toml · CREATO_PING/helpers/security_runner.py · CREATO_PING/helpers/tests/test_exposure_check.py · odczyt 16.09.2026 |
Powaga pilna w helperze i w polityce, pewność ewidentna, skutek PODATNA — subtask z priorytetem pilnym, status strony przeliczony na PODATNA. Kolejne przebiegi odświeżają opis i datę; helper nie wysyła sygnału zamknięcia.
| Ustalenie | Powaga | Pewność | Skutek | Subtask / alarm | Co zrobić |
|---|---|---|---|---|---|
| Publiczna kopia zapasowaexposure_backup_archive | Pilne | Ewidentne | PODATNA | tak / tak | Usuń archiwum z serwera, zmień hasła do bazy i konta administratorów. |
LOOP
pętli: 2Trafności jeszcze nie liczymy: zamknięcie subtaska nie niesie dziś werdyktu (prawdziwy / fałszywy / nie dało się sprawdzić). Cztery liczby pojawią się, gdy każde zamknięcie dostanie werdykt — to warunek startu pętli 1.
Sygnał: Tarcze antybotowe hostingu, strony parkingowe i serwery catch-all odpowiadają 200 na każdą ścieżkę, więc sondy oparte na kodzie 200 dawały „wystawiony” wszędzie. Równocześnie sondy na wolnych hostingach odpowiadały po około 15 s, a limit 5 s ucinał je bez śladu. · dotyczy też: Ekspozycja .env, Ekspozycja plików wrażliwych, Ekspozycja .htaccess.bak, Dostępność xmlrpc.php, REST API: enumeracja użytkowników, Ekspozycja .git/HEAD, Dostępność readme.html, Dostępność wp-cron.php, Ekspozycja zrzutu bazy, Ekspozycja manifestów dev, Ekspozycja .DS_Store
- 1. Zbiórkaręcznieodczyt z nocnego skanu, bez zapisu per strona
- 2. Werdyktręcznieprzegląd skanera: 200 na wszystko i ciche timeouty to fałszywe wyniki
- 3. Miarabrakliczników trafności wtedy nie było
- 4. Kartabrakkarta parametru powstała 2026-09-16
- 5. Zmianazrobionestrażnik ścieżki, 15 s, logowanie błędów
- 6. Replaybrakbrak zapisanych odczytów do replayu
| Data | Zmiana | Powód | Wpływ na system | Commit · replay |
|---|---|---|---|---|
| 2026-09-05 | Przed sondami GET losowej, nieistniejącej ścieżki; odpowiedź 200 z treścią = zero sond i jedno ustalenie exposure_scan_unreliable (niska powaga, bez subtaska).helpers/exposure_check.py · config/incident_policy.toml | Odpowiedź 200 na losową ścieżkę dowodzi, że kod 200 na tym serwerze nic nie znaczy; dalsze sondowanie tarczy grozi banem IP monitoringu. | cały system Obejmuje wszystkie sondy ekspozycji naraz i wprowadza typ „nie dało się sprawdzić”; tę samą konwencję dostało wykrywanie wtyczek. Ustalenie ma niską powagę, więc filtr przebiegu je odrzuca i w produkcji nie zostawia śladu. | b0fc77cbez replayubez zapisu zatwierdzenia |
| 2026-09-05 | Limit odpowiedzi z 5 s na 15 s i połączenia z 2 s na 5 s, przeniesione do config.py; błąd sieci sondy logowany zamiast cichego pustego wyniku; do 4 sond naraz na stronę.helpers/config.py · helpers/exposure_check.py · helpers/html_fetch.py · helpers/wp_fingerprint.py | Wolne hostingi odpowiadały po około 15 s, a pusty wynik po timeoucie był nieodróżnialny od „sprawdzone, czysto”. | cały system Limit połączenia 5 s przejęło wspólne pobieranie HTML całego skanu bezpieczeństwa i wykrywanie wersji — strony z wolnym TLS przestały wypadać z całego skanu. | b0fc77cbez replayubez zapisu zatwierdzenia |
Sygnał: Brak pamięci podczas skanu: publiczny debug.log jednej ze stron był bardzo duży, a klient HTTP buforował całą odpowiedź. · dotyczy też: Sitemap.xml, Ekspozycja plików wrażliwych, Ekspozycja .env, Ekspozycja .htaccess.bak, Dostępność xmlrpc.php, REST API: enumeracja użytkowników, Ekspozycja .git/HEAD, Dostępność readme.html, Dostępność wp-cron.php, Ekspozycja zrzutu bazy, Ekspozycja manifestów dev, Ekspozycja .DS_Store
- 1. Zbiórkaręcznieodczyt z nocnego skanu, bez zapisu per strona
- 2. Werdyktręcznieawaria procesu przypisana ścieżce debug.log
- 3. Miarabrakliczników trafności wtedy nie było
- 4. Kartabrakkarta parametru powstała 2026-09-16
- 5. Zmianazrobionestrumień z limitem 64 KB
- 6. Replaybrakbrak zapisanych odczytów do replayu
| Data | Zmiana | Powód | Wpływ na system | Commit · replay |
|---|---|---|---|---|
| 2026-07-19 | Odpowiedź sondy czytana strumieniem do 64 KB; do oceny idzie pierwsze 5000 znaków.helpers/exposure_check.py · helpers/html_fetch.py · helpers/sitemap_check.py | Do rozpoznania ekspozycji wystarcza początek pliku; zmiana dotyczy sposobu czytania, nie werdyktu. | cały system Brak pamięci w helperze zatrzymywał cały proces skanu bezpieczeństwa partii stron; ten sam limit dostało sprawdzenie sitemap. | 343b699bez replayubez zapisu zatwierdzenia |