
Cel - znalezienie panelu administratora
Ten lab ma niechroniony panel administratora - taki, który w żaden sposób nie sprawdza, czy odwiedzająca go osoba ma uprawnienia administratora. Panel znajduje się pod "nieprzewidywalnym" adresem, jednak adres ten jest jednak ujawniony w pewnym miejscu w aplikacji. Aby uznać lab za zaliczony, musimy znaleźć ten adres, a następnie skorzystać z panelu, by usunąć użytkownika o imieniu Carlos.
Krok 1: analiza kodu źródłowego strony
W poprzednim labie z tej serii adres panelu administratora znaleźliśmy w pliku robots.txt. Tym razem twórcy postanowili ukryć go nieco lepiej - adres jest generowany losowo przy każdym uruchomieniu laba, więc nie zgadniemy go ze słownika typowych ścieżek (/admin, /panel, /administrator-panel itd.). Gobuster tu nic nie zdziała. Adres jest jednak "nieprzewidywalny" tylko z pozoru.
Zajrzyjmy do kodu źródłowego strony głównej. Znajdziemy w nim taki fragment:
<script>
var isAdmin = false;
if (isAdmin) {
var topLinksTag = document.getElementsByClassName("top-links")[0];
var adminPanelTag = document.createElement('a');
adminPanelTag.setAttribute('href', '/admin-vtdbfx');
adminPanelTag.innerText = 'Admin panel';
topLinksTag.append(adminPanelTag);
var pTag = document.createElement('p');
pTag.innerText = '|';
topLinksTag.appendChild(pTag);
}
</script>
To bardzo ciekawy kawałek kodu - i całkiem zabawny adres! Zwróćmy jednak uwagę na to, co się poza tym dzieje w kodzie.
Skrypt sprawdza zmienną isAdmin. Gdyby ta zmienna miała wartość true, do menu na górze strony dodałby się link do panelu administratora prowadzący pod adres /admin-vtdbfx. U nas isAdmin jest ustawione na false, więc link nigdy się nie wyświetli.
Ale to, czy link się wyświetla w widocznym dla użytkownika miejscu na stronie, nie ma żadnego znaczenia. Logika sprawdzająca, czy strona powinna się wyświetlać, podaje jak na tacy znaleziony w źródle strony JavaScript. Gdyby isAdmin = true to ten kod dodałby odpowiednie elementy do drzewa DOM, wraz z linkiem do podstrony dla administratora. Wszystko, czego potrzebujemy do rozwiązania labu, jest po stronie klienta (client-side).
I tu pojawia się sedno tego labu: jeśli coś jest zahardcodowane w kodzie źródłowym albo generowane przy wejściu na stronę (i możliwe do odczytania w ramach aktywnej sesji), to nie jest to adres nieprzewidywalny. Nieprzewidywalność adresu miałaby może jakikolwiek sens dopiero wtedy, gdyby adres nie był nigdzie ujawniany osobie bez uprawnień, choć i wtedy dałoby się go znaleźć. A tutaj jest podany jak na tacy.
Krok 2: zaglądamy pod adres /admin-vtdbfx
Sprawdźmy więc ten adres - w moim przypadku było to https://0af200c00430be4c8030a82d00da00d4.web-security-academy.net/admin-vtdbfx (u Ciebie losowa część adresu będzie inna). Naszym oczom ukazuje się panel administratora z listą użytkowników:

No to pozamiatane. Klikamy Delete przy użytkowniku o imieniu Carlos - i tym samym rozwiązujemy lab.
Co jeszcze można znaleźć w kodzie źródłowym?
Dzisiejszy lab dotyczył znaleziska w kodzie źródłowym strony - teoretycznie nieprzewidywalnego adresu do panelu administratora. Ale kod źródłowy webaplikacji potrafi zdradzić znacznie więcej. Można w nim znaleźć między innymi:
- tag Google Tag Managera - taką informację można wykorzystać np. w phishingu, wysyłając maila powiązanego z jedną z usług faktycznie wykorzystywanych na stronie, co uwiarygadnia atak;
- informacje o wykorzystywanych wtyczkach - np. poprzez adres katalogu, z którego zaciągane są pliki, a który chociażby przypadku WordPressa można przypisać do konkretnej wtyczki;
- informacje o wersjach oprogramowania i wtyczek - np. wordpressowa wtyczka Yoast SEO automatycznie dodaje komentarz z wykorzystywaną wersją, podobnie zachowuje się m.in. wtyczka LiteSpeed Cache:
<!-- This site is optimized with the Yoast SEO plugin v26.6 - https://yoast.com/wordpress/plugins/seo/ -->
<!-- Page cached by LiteSpeed Cache 7.7 on 2025-12-31 05:23:16 -->
WordPress często też dodaje informację o wersji na końcu adresów plików CSS:
<link rel='stylesheet' href='https://adres-strony.pl/wp-includes/css/dist/block-library/style.min.css?ver=6.9' type='text/css' media='all' />
W tym przypadku jest to adres styli do elementów blokowych - to część możliwości low-code/no-code WordPressa, czyli edytora Gutenberg. Parametr ?ver=6.9 zdradza natomiast wersję silnika.
Każda taka informacja z osobna wygląda niegroźnie, ale razem budują obraz strony, który atakujący może wykorzystać w kolejnej fazie ataku - choćby dobierając exploity pod konkretne, znane z podatności wersje oprogramowania.
Jak się chronić?
Czasem nie da się wiele zrobić. Można próbować ukrywać wszystko, jednak ukrywanie bywa czasochłonne. niekiedy wręcz niemożliwe - szczególnie, gdy kolejne aktualizacje oprogramowania nadpisują wprowadzone zmiany. Do oceny, czy gra jest warta świeczki, służy analiza ryzyka.
Niezależnie od niej zawsze warto:
- dbać o aktualizacje oprogramowania - nawet jeśli ktoś pozna wersję wtyczki, to znacznie trudniej mu ją wykorzystać, gdy jest ona aktualna i pozbawiona znanych podatności;
- nie instalować od razu nowego oprogramowania - często warto poczekać 24-48h, aż zostaną znalezione i poprawione ewentualne błędy. Choć warto też pamiętać, że w przypadku krytycznych luk czy systemów czas ma znaczenie i lepiej dodać łatkę z potencjalną inną, jeszcze nieznaną luką, niż być wystawionym na cel cyberprzestępców;
- wiedzieć, jak chronić się przed phishingiem - sprawdzać adres URL i korzystać z managera haseł, który podpowie hasło tylko na właściwej domenie (jeśli nie podpowiada - to sygnał ostrzegawczy);
- nie kodować "na sztywno" w kodzie źródłowym danych, których nie chcielibyśmy pokazać osobom z zewnątrz - nawet jeśli nie wyświetlają się one na stronie. Jak pokazał ten lab, "niewidoczne" dla przeciętnego użytkownika nie znaczy "niedostępne".
