Ekspozycja zrzutu bazy
ważność krytycznamierzonysposób exposure
Pliki backup.sql, dump.sql i database.sql. Hasła użytkowników, dane osobowe, klucze — najgorszy możliwy wyciek.
Rozstrzygają słowa kluczowe SQL przy braku HTML na początku pliku.
WIKI
artykuł z 16.09.2026 · źródeł 10Ekspozycja zrzutu bazy to parametr monitoringu stron internetowych, który sprawdza, czy pod przewidywalnymi adresami w katalogu głównym witryny, takimi jak /backup.sql, /dump.sql i /database.sql, serwer oddaje tekstowy zrzut bazy danych. Pomiar kończy się jednym z trzech wyników: zrzut dostępny publicznie, zrzut niedostępny albo nie udało się uzyskać odpowiedzi. Zrzut jest kopią zapasową, więc jego publiczne udostępnienie mieści się w słabości CWE-530: plik kopii przechowywany w miejscu dostępnym dla nieuprawnionych podmiotów [10].
Jak działa
Program mysqldump wykonuje kopie logiczne: tworzy zestaw instrukcji SQL, które po wykonaniu odtwarzają definicje obiektów bazy i dane tabel [1]. Służy do kopii zapasowych i do przenoszenia baz na inny serwer SQL [1]. Domyślny wynik zawiera instrukcje CREATE TABLE, które odtwarzają każdą tabelę, oraz instrukcje INSERT z danymi [1]. Opcja --add-drop-table, włączona domyślnie, dopisuje DROP TABLE przed każdym CREATE TABLE [1], a --add-locks otacza zrzut tabeli instrukcjami LOCK TABLES i UNLOCK TABLES [1]. Włączona domyślnie opcja --comments dopisuje na początku pliku komentarze z wersją programu, wersją serwera i nazwą hosta [1]. Opcja --compact wyłącza między innymi komentarze i instrukcje DROP TABLE [1].
Taki plik jest zwykłym tekstem. Gdy leży w katalogu, z którego serwer WWW podaje pliki, jest kopią zapasową dostępną dla każdego, kto zna jej adres [10].
Po kodzie 200 zrzutu nie da się rozpoznać, bo pod dowolnym adresem może stać strona błędu. Rozpoznanie opiera się na dwóch cechach treści. Strona błędu zaczyna się od znaczników HTML, np. <!doctype html>, a zrzut od komentarza albo instrukcji SQL. W dalszej części zrzutu występują słowa kluczowe instrukcji wymienionych w dokumentacji: CREATE TABLE, INSERT, DROP TABLE, LOCK TABLES [1]. Znaczniki HTML w środku pliku nie przesądzają, bo tabela wp_posts przechowuje wpisy i strony witryny [2], a ich treść zawiera kod HTML.
Pierwsza odpowiedź to strona HTML z kodem 200, więc nie jest zrzutem. Druga oznacza brak pliku. Trzecia zaczyna się komentarzem i zawiera instrukcję CREATE TABLE, czyli ma cechy zrzutu.
Standardy i specyfikacje
- Dokumentacja mysqldump (MySQL 8.4) opisuje format zrzutu: instrukcje SQL, domyślne komentarze nagłówkowe i opcje dopisujące
DROP TABLEorazLOCK TABLES[1]. - Baza WordPressa. Każda tabela ma ten sam prefiks zdefiniowany w
wp-config.php, domyślniewp_[2]. Tabelawp_usersprzechowuje informacje o użytkownikach witryny, po jednym wierszu na użytkownika [2], awp_optionsustawienia witryny [2]. Tabelawp_commentszawiera komentarze do wpisów i stron [2]. Wśród danych użytkownika są login, adres e-mail i nazwa wyświetlana [3]. - Hasła w wp_users. Funkcja
wp_set_passwordzapisuje do kolumnyuser_passtabeli użytkowników skrót hasła, nie samo hasło [4]. Od wersji 6.8 WordPress zamiast przenośnego skrótu phpass używa bcrypt, co znacznie zwiększa koszt łamania skrótów [5]. Nowe skróty mają prefiks$wp$2y$, a stare są przeliczane na bcrypt przy najbliższym logowaniu albo zmianie hasła [5]. - CWE-530 w opisie skutków stwierdza, że kto pobierze plik kopii, ma wszystkie zapisane w nim informacje [10].
- RODO. Według UODO zgłoszenie naruszenia do organu nadzorczego na podstawie art. 33 ust. 1 RODO powinno nastąpić nie później niż 72 godziny od jego stwierdzenia [8]. Rządowy serwis Biznes.gov.pl zalicza do naruszeń nieuprawnione ujawnienie danych osobowych i nieuprawniony dostęp do nich [9].
Zagrożenia i skutki
Łamanie skrótów offline. OWASP wymaga, żeby hasła były chronione także wtedy, gdy baza danych zostanie przejęta [6]. Atakujący, który ma skróty, sprawdza dla nich długą listę kandydatów na hasło [6]. Przy szybkim sprzęcie i chmurze koszt takiego łamania jest stosunkowo niski [6]. Silne hasła zapisane nowoczesnym algorytmem powinny być w praktyce niemożliwe do złamania [6], więc najbardziej narażone są hasła słabe i skróty w starym formacie, jeszcze nieprzeliczone na bcrypt [5].
Kradzież kont poza witryną. Pary login i hasło z wycieku jednej witryny służą do ataku credential stuffing, czyli sprawdzania ich w innych serwisach [7].
Obowiązek zgłoszenia. Publicznie dostępny zrzut z danymi użytkowników może oznaczać nieuprawnione ujawnienie danych osobowych albo nieuprawniony dostęp do nich [9]. Termin 72 godzin liczy się od stwierdzenia naruszenia [8]. Administrator nie musi zgłaszać naruszenia, jeśli po jego odkryciu oceni ryzyko dla praw i wolności osób jako małe [9]. Gdy ryzyko jest wysokie, trzeba też zawiadomić osoby, których dane dotyczą, zgodnie z art. 34 RODO [8].
Przykłady
| Sytuacja | Co zobaczy sonda | Znaczenie |
|---|---|---|
| Zrzut mysqldump z domyślnymi opcjami [1] | 200, komentarze z wersją serwera, potem DROP TABLE i CREATE TABLE | zrzut dostępny publicznie |
Zrzut z opcją --compact [1] | 200, bez komentarzy, od razu instrukcje SQL | zrzut dostępny publicznie |
| Strona błędu podawana z kodem 200 | 200, treść od <!doctype html> | brak zrzutu |
| Zrzut z treścią wpisów zawierającą HTML [2] | znaczniki HTML w środku pliku, początek od komentarza SQL | nadal zrzut |
| Baza sprzed WordPressa 6.8 bez ponownych logowań [5] | skróty phpass w user_pass | skróty łatwiejsze do złamania |
| Zrzut z danymi klientów sklepu lub autorów komentarzy [9] | adresy e-mail i dane osobowe w INSERT | ocena ryzyka i ewentualne zgłoszenie w 72 h [8] |
- [1] mysqldump — A Database Backup Program (MySQL 8.4 Reference Manual) · Oracle / MySQL
- [2] The WordPress Database · Learn WordPress
- [3] wp_insert_user() — Function Reference · WordPress.org
- [4] wp_set_password() — Function Reference · WordPress.org
- [5] WordPress 6.8 will use bcrypt for password hashing · Make WordPress Core
- [6] Password Storage Cheat Sheet · OWASP
- [7] Credential Stuffing Prevention Cheat Sheet · OWASP
- [8] Naruszenia ochrony danych osobowych należy zgłaszać Prezesowi UODO bez zbędnej zwłoki · Urząd Ochrony Danych Osobowych
- [9] Zgłoś naruszenie ochrony danych osobowych · Biznes.gov.pl
- [10] CWE-530: Exposure of Backup File to an Unauthorized Control Sphere · MITRE
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 (B28) |
|---|---|
| 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_sql_dump (trzy ścieżki sklejone w jedno) |
| Jednostka | brak — wynik jakościowy; w dowodzie ścieżka i długość ocenianej treści, bez samej treści pliku |
| Próg i reguła | Timeout odpowiedzi 15 s, połączenia 5 s. Reguła: kod 200 + początek nie jest HTML-em + marker SQL w pierwszych 5000 znakach. |
| Gdzie leżą pokrętła | CREATO_PING/helpers/exposure_check.py → PROBES (reguła sql_dump), _SQL_MARKERS, _HTML_MARKERS, _text_file_matches, _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_sql_dump |
| 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ć |
|---|---|---|---|---|---|
| Publiczny zrzut bazyexposure_sql_dump | Pilne | Ewidentne | PODATNA | tak / tak | Usuń zrzut, zmień hasło do bazy i wszystkie ujawnione sekrety; rozważ zgłoszenie naruszenia. |
LOOP
pętli: 3Trafnoś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 kopii zapasowych, 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 kopii zapasowych, 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 |
Sygnał: Przegląd kodu nowych sond przed wdrożeniem: reguła odrzucała plik, gdy HTML pojawił się gdziekolwiek w pierwszych 5000 znaków, a prawdziwy zrzut bazy WordPressa ma znaczniki HTML w treści wpisów — pilny wyciek zostałby przeoczony. · dotyczy też: Ekspozycja .htaccess.bak
- 1. Zbiórkabrakreguła poprawiona przed pierwszym przebiegiem
- 2. Werdyktręcznieprzegląd kodu: zrzut WordPressa zawiera HTML w treści wpisów
- 3. Miarabrakliczników trafności wtedy nie było
- 4. Kartabrakkarta parametru powstała 2026-09-16
- 5. Zmianazrobionerozstrzyga początek pliku
- 6. Replaybrakpo wdrożeniu suchy przebieg na żywo, bez zapisanych odczytów
| Data | Zmiana | Powód | Wpływ na system | Commit · replay |
|---|---|---|---|---|
| 2026-09-16 | Plik uznany za stronę HTML tylko wtedy, gdy zaczyna się od <html, <!doctype, <head albo <body; dotyczy zrzutów .sql i kopii .htaccess.bak.helpers/exposure_check.py | Strona błędu zaczyna się od HTML-a, a zrzut bazy od komentarza albo CREATE; szukanie HTML-a w całej treści dawało fałszywy negatyw na ustaleniu pilnym. | tylko ten parametr | 193591fbez replayubez zapisu zatwierdzenia |