Skip to content

About

Site to practice vulnerabilities like XSS, SQL Injection, Command Injection for Cybersecurity course at Gdańsk University of Technology

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

Vulnerability Vault

Laboratorium SQL Injection, Command Injection, File Upload, XSS Reflected oraz XSS Stored. Dostępne są dwa tryby: publiczny web (domyślny) i pełny local (jawnie ustawiony w Docker Compose). Parametry URL, formularze i cookies nie zmieniają trybu. Nieprawidłowy APP_MODE zatrzymuje aplikację.

Publikacja i pakiety

Nie publikuj repozytorium ani pełnej wersji lokalnej na hostingu współdzielonym. Pełna wersja zawiera celowe wykonanie poleceń, SQL Injection i dowolny upload. Publiczna wersja nadal zawiera rzeczywisty, nieizolowany XSS — przeznacz ją na osobną domenę bez innych aplikacji, kont produkcyjnych i danych poufnych.

Ćwiczenie web local
SQL Injection Symulacja w przeglądarce Rzeczywiste SQL
Command Injection Symulacja w przeglądarce Rzeczywiste polecenia
Upload Metadane lokalnego pliku, bez wysyłania Rzeczywisty upload
XSS Reflected / Stored Rzeczywisty XSS po ostrzeżeniu Rzeczywisty XSS

Symulacje obsługują ograniczone przykłady z lekcji i nie wykonują danych wejściowych. SQL używa fikcyjnych kont admin/admin, test/test, user/user w pamięci strony; rejestracja dodaje fikcyjne konto do czasu odświeżenia. Komendy obsługują 127.0.0.1, 127.0.0.1; whoami i 127.0.0.1; ls. Upload analizuje wyłącznie nazwę, rozmiar i deklarowany typ — nie potwierdza bezpiecznej zawartości. Bez JavaScript dostępne są materiały, ale nie symulacje.

Budowanie pakietów po kompilacji frontendu (Python 3):

npm run build
python3 bin/package-release.py
  • dist/vulnerability-vault-web.zip: pakiet PHP pozbawiony lokalnych backendów, modeli kont i narzędzi administracji lokalnej; zawiera katalog dokumentów public. Na osobnej domenie działa bezpośrednio pod / (PL) i /en/ (EN).
  • dist/vulnerability-vault-local.zip: pełne źródła i stack Docker, bez sekretów, danych użytkownika, .git, vendor i node_modules.
  • manifest.json w każdym pakiecie zawiera sumy SHA-256 plików.

Instalacja publiczna, baza z ograniczonym kontem i cron: deployment/README.md. Publiczny pakiet nie pozwala włączyć local, nawet zmienną środowiskową. Należy wgrać pakiet do nowego katalogu wydania, nie nakładać go na pełną instalację. Web wymaga jawnych danych połączenia; root ani puste dane nie są akceptowane. Konfiguracja z config.php jest poza WWW; środowisko ma pierwszeństwo. Wymagane są również APP_ORIGIN (kanoniczny adres HTTPS bez ścieżki) oraz SESSION_SAVE_PATH (prywatny, zapisywalny katalog poza wszystkimi katalogami WWW, z prawami 0700). Obce hosty otrzymują 421. Cookie sesji zawsze ma Secure, HttpOnly i SameSite=Lax; strony informacyjne i symulacje nie tworzą sesji. Wdrożenie wymaga limitów żądań/równoległości przed PHP, rotacji logów oraz sprzątania sesji zgodnie z instrukcją instalacji. Sam ZIP nie włącza tych ustawień u operatora. Wspólny XSS nadal jest niebezpieczny dla odwiedzających.

Stored XSS przyjmuje do 200 wspólnych komentarzy, nazwę do 128 znaków i treść do 4 KiB, z globalnym limitem jednego zapisu na 5 sekund. Komentarze są czyszczone codziennie o 23:00 UTC przez cron, z nadrabianiem resetu przed odczytem i zapisem. Blokada transakcyjna InnoDB zapewnia spójność przy równoległych żądaniach. Reset nie chroni odwiedzających przed kodem wykonanym wcześniej. Komunikaty sesji są scalane i ograniczone do 10 najnowszych. Oczekiwanie na blokadę InnoDB trwa maksymalnie 2 s; przejściowe przeciążenie zwraca 503 z Retry-After: 5. Awaryjne usunięcie wszystkich komentarzy, wyłącznie przez CLI: php bin/purge-comments.php --confirm (szczegóły w instrukcji instalacji).

Uruchomienie

Wymagany Docker Engine z Docker Compose v2 lub Docker Desktop. Na Windows włącz integrację Docker Desktop z używaną dystrybucją WSL. W katalogu projektu uruchom:

docker compose up --build -d

Pierwsze uruchomienie pobiera obrazy i zależności, buduje PHP oraz tworzy bazę. PHP, Composer i Node.js nie muszą być zainstalowane na komputerze.

Compose ogranicza aplikację do 1 CPU / 256 MiB / 128 procesów, bazę do 1 CPU / 512 MiB / 128 procesów, a phpMyAdmin do 0,5 CPU / 256 MiB / 128 procesów. Port bazy nie jest publikowany; kontenery nie montują katalogów hosta ani gniazda Dockera. Wolumeny zachowują dane, ale nie mają limitu rozmiaru — monitoruj miejsce na dysku i resetuj laboratorium. Uruchamiaj je tylko lokalnie. Do eksperymentów z nieznanym kodem użyj osobnej maszyny wirtualnej; Docker współdzieli jądro hosta.

Stack: Apache z PHP 8.2, MariaDB 10.11 oraz phpMyAdmin 5.2. Kod i Composer dependencies znajdują się w obrazie. Istniejące zasoby frontendowe nie wymagają kompilacji. Część bibliotek i fontów jest pobierana przez przeglądarkę z CDN, więc pełny wygląd strony wymaga dostępu do Internetu. Highlight.js 11.12.0 i jego CSS są dołączone lokalnie; metadane, licencja i sumy znajdują się w deployment/highlight.json i deployment/highlight-LICENSE. npm run check:vendor i pakowanie sprawdzają wersje i SHA-256; npm audit sprawdza przypięte zależności. Publiczne strony poza XSS mają CSP ograniczającą skrypty do własnej domeny i nonce bootstrapu; XSS zachowuje celowy wyjątek.

Konfiguracja

Opcjonalnie skopiuj .env.example do .env i ustaw DB_USERNAME, DB_PASSWORD oraz DB_ROOT_PASSWORD przed pierwszym uruchomieniem. Compose przekazuje aplikacji DB_HOST=db, DB_PORT=3306, DB_DATABASE=vulnerability-vault. Użytkownik aplikacji ma uprawnienia wyłącznie do tej bazy; port bazy nie jest publikowany na hoście.

Zmiana haseł w .env nie zmienia kont w już istniejącym wolumenie MariaDB. Dla istniejących danych zmień hasła także w bazie, a następnie odtwórz kontenery.

Obsługa i dane

# Stan i logi
docker compose ps
docker compose logs -f app db

# Przebudowanie po zmianach kodu
docker compose up --build -d

# Zatrzymanie i ponowne uruchomienie
docker compose down
docker compose up -d

# Ponowna, idempotentna inicjalizacja tabel i kont testowych
docker compose exec app php bin/init-db.php

Baza jest zapisywana w wolumenie db_data, a pliki ćwiczenia File Upload w uploads, zamontowanym jako web/uploads. Restart i odtworzenie kontenerów zachowują te dane. Inicjalizacja dodaje konta testowe tylko wtedy, gdy brakuje użytkownika o danej nazwie; nie nadpisuje haseł istniejących użytkowników.

Pełny reset laboratorium usuwa bazę i przesłane pliki:

docker compose down -v
docker compose up --build -d

Galeria, MongoDB oraz niedokończone ćwiczenie CSRF nie są odtwarzane w tym stacku. Na Linuksie przykłady Command Injection używają ping -c 4 -W 2 i poleceń powłoki linuksowej; na Windows kod zachowuje ping -n 4.

WAMP/XAMPP i import danych

Bez Dockera ustaw APP_MODE=local w środowisku PHP/CLI lub config.php. Następnie umieść projekt w htdocs/vulnerability-vault, zainstaluj zależności przez composer install, uruchom Apache z mod_rewrite i bazę SQL. Wymagane rozszerzenia PHP to PDO MySQL i GD z JPEG/FreeType. Przed pierwszym wejściem uruchom w katalogu projektu:

php bin/init-db.php

Połączenie domyślnie używa localhost:3306, bazy vulnerability-vault, konta root i pustego hasła. Inne dane można przekazać zmiennymi środowiskowymi DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD; skrypt PHP nie odczytuje samodzielnie pliku .env. Użytkownik wykonujący inicjalizację musi mieć uprawnienia do tworzenia tej bazy i tabel. Na Windows utwórz web/uploads z prawem zapisu dla Apache. Aplikacja jest pod /vulnerability-vault/.

Dane z WAMP/XAMPP nie są importowane automatycznie. W dotychczasowym phpMyAdmin wyeksportuj bazę vulnerability-vault jako SQL z tabelami i danymi. W dockerowym phpMyAdmin wybierz tę bazę i zaimportuj eksport. Jeśli eksport zawiera CREATE TABLE, użyj opcji eksportu dodającej DROP TABLE, aby zastąpić tabele utworzone przy starcie. Import zastępujący tabele usuwa ich dotychczasowe dane — wcześniej wykonaj eksport, jeśli chcesz je zachować. Po imporcie uruchom ponownie php bin/init-db.php w kontenerze, aby uzupełnić brakujące konta testowe.

Weryfikacja

docker compose config --quiet
docker compose exec app sh -c 'find app views routes web bin -name "*.php" -exec php -l {} \;'
docker compose exec app composer check-platform-reqs --no-dev
python3 tests/docker_smoke.py

Test integracyjny wymaga Pythona 3 i działającego Dockera. Buduje osobny projekt Compose na wolnych lokalnych portach, sprawdza ćwiczenia, sesje, zasoby, inicjalizację, trwałość danych i błąd startu przy złym haśle, po czym usuwa wyłącznie własne kontenery, zachowując wolumeny testowe. Sprawdza HTML wariantów XSS; wykonanie JavaScript i wygląd strony należy dodatkowo sprawdzić w przeglądarce.

Warstwa wizualna / BREACH//LAB

Interfejs korzysta z istniejących widoków PHP, SCSS i TypeScript. Style systemu BREACH//LAB znajdują się w web/resources/scss/components/_breach.scss, a katalog pięciu laboratoriów w views/layouts/components/lab-catalog.php. Backend i pola formularzy ćwiczeń pozostają zachowane.

Po zmianach źródeł frontendowych (Node.js 20.11+):

npm ci
npm run check
npm run build

Wygenerowane CSS, mapy i JS są wersjonowane, więc uruchomienie przez Docker nie wymaga Node.js. Po zmianach przebuduj aplikację: docker compose up --build -d. Animacje respektują prefers-reduced-motion; treść i formularze są dostępne również bez animacji. Interfejs dodaje obsługiwane klawiaturą zakładki porównania kodu, kopiowanie, numery linii, mobilne menu i nawigację po etapach.

Stopka zawiera indeks laboratoriów, FAQ i odnośniki do projektu oraz autora. FAQ dotyczy uruchomienia i korzystania z laboratorium. Usunięto dawną stronę inwestycyjną, nieużywany slider, popupy oraz licznik czasu. Frontend korzysta z natywnego JavaScript; nie ładuje jQuery, jQuery UI, Poppera ani Bootstrap JS.

Wersje językowe PL / EN

Publiczna wersja na osobnej domenie używa /sql-injection (PL) i /en/sql-injection (EN). Instalacja lokalna zachowuje /vulnerability-vault/sql-injection oraz /vulnerability-vault/en/sql-injection. Aliasy strony głównej (/index, /home, /home/index) działają w obu językach. Język wynika wyłącznie z adresu — bez automatycznego wykrywania, cookies preferencji ani localStorage.

Przełącznik PL / EN w nawigacji działa również bez JavaScript i na telefonach. Otwiera odpowiednik bieżącej strony z nowym formularzem, bez parametrów testu i bez ponawiania POST. Adresy akcji, np. /file-uploader/upload, prowadzą po przełączeniu do właściwego ćwiczenia. JavaScript zachowuje kotwicę bieżącej sekcji. CSS, JS, obrazy i uploady zachowują wspólne adresy.

Dodawanie i zmiana tłumaczeń

  • Słowniki to resources/lang/pl.json i resources/lang/en.json. Mają identyczne klucze i parametry {name}.
  • TranslationService odczytuje język, kontekst trasy i słownik; t('key', ['name' => $value]) zwraca tekst, a te(...) escapuje go do HTML. Brak klucza lub parametru powoduje błąd, również w EN — nie ma polskiego fallbacku.
  • Klucze są pogrupowane w nav.*, form.*, ui.*, page.*, component.*, lesson.* itd. Istniejące identyfikatory text_XX są stałe; dodanie akapitu nie powinno powodować ich renumeracji. Nowe klucze powinny opisywać przeznaczenie tekstu.
  • Linki, akcje formularzy i przekierowania buduj przez PathService::url('/path'). Do zasobów używaj istniejących helperów zasobów, które nie dodają prefiksu języka.
  • Szablony korzystają z tych samych plików PHP w obu językach. Fragmenty treści są wykonywane przez include z buforowaniem wyjścia.
  • Do JavaScript trafia wyłącznie sekcja ui.*, w bezpiecznie zakodowanym JSON. Teksty w TypeScript pobieraj przez translate(...); nie umieszczaj komunikatów interfejsu w CSS.
  • Komunikaty walidacji zapisuj przez FlashMessageService::translatedError/translatedInfo, aby język był ustalany przy wyświetlaniu.
  • Każda strona ma właściwe lang, Content-Language, tytuł i opis. Strony GET mają alternatywne adresy hreflang PL/EN; błędy 404 mają lokalizowaną treść.

Marki Vulnerability Vault, BREACH//LAB, PromptLab, nazwy technologii i podatności SQL Injection, Command Injection, XSS Reflected, XSS Stored pozostają bez tłumaczenia. Stosujemy terminy laboratorium, podatny wariant, zabezpieczony wariant, dane wejściowe, wynik testu. „Payload” wyjaśniamy przy pierwszym użyciu w lekcji. Nazwa ćwiczenia to Przesyłanie plików / File Upload, ale adres pozostaje file-uploader. Polecenia, kod, payloady, nazwy pól backendowych, komentarze użytkowników oraz surowe wyniki narzędzi pozostają niezmienione. Celowo podatne miejsca demonstracyjne nadal wyświetlają dane tak jak wcześniej; escapowanie tłumaczeń nie jest zabezpieczeniem tych ćwiczeń.

Testy publikacji

python3 tests/public_package.py
php tests/public_comments.php
php tests/web_paths.php
php tests/security_hardening.php
unzip dist/vulnerability-vault-web.zip -d /tmp/vault-public-check
php tests/public_security.php /tmp/vault-public-check

public_package.py sprawdza allowlisty obu paczek i brak prywatnych plików w WWW. public_security.php analizuje wykonywalne tokeny PHP paczki publicznej (pomijając inertny kod edukacyjny) i sprawdza konfigurację trybów. public_comments.php sprawdza granicę resetu UTC; z jawną konfiguracją dedykowanej bazy testowej oraz VAULT_TEST_DB=1 sprawdza także limity, uprawnienia i równoległe operacje. Nie uruchamiaj testu bazy na danych rzeczywistych — wymaga bazy zakończonej _test. Przykład dla osobnej przygotowanej bazy testowej (konfiguracja przez środowisko lub prywatny config.php):

VAULT_TEST_DB=1 php tests/public_comments.php
# Dla już przygotowanej testowej instalacji HTTPS; web_http zapisuje komentarz:
VAULT_TEST_DB=1 VAULT_BASE_URL=https://lab-test.example.com python3 tests/web_http.py
PLAYWRIGHT_MODULE=/path/to/node_modules/playwright VAULT_BASE_URL=https://lab-test.example.com \
  node tests/web_demo.cjs

Cały zestaw integracyjny może sam utworzyć i usunąć osobną instancję MariaDB, bazy, paczki, katalog sesji i proxy HTTPS, korzystając wyłącznie z localhost:

PLAYWRIGHT_MODULE=/path/to/node_modules/playwright python3 tests/public_integration.py

Wymaga PHP z PDO MySQL, MariaDB (mariadb-install-db, mariadbd), OpenSSL i Node.js. Opcjonalne VAULT_PHP_BINARY, VAULT_MARIADB_BASEDIR, VAULT_NODE_BINARY oraz PHPRC pozwalają wskazać runtime. Playwright jest opcjonalny; bez niego test raportuje pominięcie przeglądarki. Test publiczny sprawdza również cookie Secure za proxy bez nagłówka HTTPS oraz 503 przy rzeczywistej blokadzie InnoDB. Lokalne ćwiczenia są sprawdzane na osobnej bazie i rozpakowanym pakiecie lokalnym. Skrypt nie łączy się z istniejącą bazą. Certyfikat testowy istnieje tylko w katalogu tymczasowym; samodzielny web_http.py może ufać mu przez VAULT_TEST_CA. To nie zastępuje odbioru konfiguracji Apache i limitów operatora hostingu.

Test przeglądarki uruchamiaj po web_http.py, który zapisuje jego marker XSS. Blokuje zewnętrzne żądania i sprawdza PL/EN, formularze bez wysyłania danych, bezpieczne wyświetlanie nazw plików, wykonanie XSS po ostrzeżeniu i brak JavaScript. Dodatkowy tests/local_http.py sprawdza pięć lokalnych ćwiczeń na dedykowanej bazie przez serwer testowy; uruchom go z VAULT_TEST_DB=1 i VAULT_BASE_URL tej instalacji. Pełny test stacku Apache/Docker pozostaje w tests/docker_smoke.py.

Sprawdzanie obu wersji

npm run check:i18n
npm run check
npm run build
python3 tests/docker_smoke.py

Kontrola tłumaczeń sprawdza zestawy kluczy, niepuste wartości, zgodność parametrów i odwołania w PHP/TypeScript. Test integracyjny sprawdza oba języki, aliasy, metadane, 404, przekierowania, SQL Injection, XSS Reflected/Stored, Command Injection oraz uploady. Wykonuje też test serwisu tłumaczeń i zachowanego szablonu galerii z tests/i18n.php. Używa osobnego projektu Compose vault-test-<identyfikator>; po teście usuwa jego kontenery, zachowując wolumeny.

Znana wcześniejsza rozbieżność: błędne logowanie w zabezpieczonym wariancie zwraca 302 zamiast zamierzonego 404, ponieważ RedirectView ustawia nagłówek Location. Test raportuje ją osobno jako KNOWN ISSUE; lokalizacja nie zmienia tego mechanizmu. Stare kontrolery galerii nie mają kompletnego zaplecza (User::getCurrentUser, dawny model obrazów). Ich szablony i komunikaty są przetłumaczone, ale ta zmiana nie odbudowuje funkcjonalności galerii.

Przy zmianach treści sprawdź obie wersje z JavaScript i bez niego przy szerokościach 320, 390, 768 i 1440 px. Zwróć uwagę na hero, widoczność przełącznika bez otwierania menu, długie etykiety, stopkę i aktywne laboratorium na wyniku uploadu.

Automatyczny przegląd widoków w przeglądarce: tests/browser_i18n.cjs (wymaga Playwright z Chromium). Jeśli Playwright jest zainstalowany poza projektem, podaj ścieżkę pakietu:

PLAYWRIGHT_MODULE=/path/to/node_modules/playwright node tests/browser_i18n.cjs

Domyślnie test otwiera http://localhost:8080; inny adres można ustawić przez VAULT_BASE_URL. Raport i zrzuty ekranu zapisuje w nowym katalogu tymczasowym, którego adres wypisuje na końcu.

Czytelność i typografia

Baza dokumentu to font-size: 100%, więc strona respektuje domyślny rozmiar tekstu ustawiony w przeglądarce. Przy domyślnej bazie 16px treść ma 18px, opisy, formularze i stopka 16px, a drugorzędne etykiety oraz kod minimum 14px. To przyjęta skala projektu, a nie uniwersalne minimum liczby pikseli określone przez WCAG. Wielkości nagłówków są względne; tekst można powiększyć do 200%. Kolumny i etykiety zawijają się, a przykłady kodu mają własne przewijanie poziome. Reguły skali i elastyczności układu są w web/resources/scss/components/_typography.scss.

Test tests/typography.cjs sprawdza rzeczywiste wielkości widocznego tekstu i przepełnienie strony dla PL/EN, 320/390/768/1440px i rozmiaru tekstu 100%/200%. Kontroluje też spójność nagłówków sekcji, ich przewagę nad tekstem opisów oraz brak nachodzenia terminala na podpis. Wymaga tej samej instalacji Playwright co test języków:

PLAYWRIGHT_MODULE=/path/to/node_modules/playwright node tests/typography.cjs

About

Site to practice vulnerabilities like XSS, SQL Injection, Command Injection for Cybersecurity course at Gdańsk University of Technology

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages