NFsec Logo

Podstawy skryptów shell #3

29/07/2017 w Bezpieczeństwo Brak komentarzy.  (artykuł nr 628, ilość słów: 685)

T

rzecia część [ 1 ] [ 2 ] będzie poruszać ataki wstrzykiwania do skryptów powłoki. Te typy ataków występują, gdy użytkownik dostarcza jako argumenty przechowywane w zmiennych skryptu spreparowane polecenia lub wartości zamiast oczekiwanych danych wejściowych. W dodatku użyte zmienne są pozbawione znaków cytowania, które służą do usuwania interpretacji znaków specjalnych przez powłokę. Na przykład:

#!/bin/bash

read LOGIN
read COMMAND
if [ x$LOGIN = xroot ]; then
    echo $LOGIN
    eval $COMMAND
fi


Skrypt ten posiada dwie luki w kodzie. Wykonajmy skrypt na początku w “normalnym” przebiegu tak, aby wykonała się część zawarta w warunku if:

root@darkstar:~# bash -x ./example.sh
+ read LOGIN
root
+ read COMMAND
uptime
+ '[' xroot = xroot ']'
+ echo root
root
+ eval uptime
++ uptime
 21:47:19 up 104 days, 20:19,  1 user,  load average: 0.10, 0.13, 0.10

Teraz zamiast wyrażenia “root” wprowadźmy niespodziewaną wartość do skryptu:

root@darkstar:~# bash -x ./example.sh
+ read LOGIN
root = xroot -o x
+ read COMMAND
uptime
+ '[' xroot = xroot -o x = xroot ']'
+ echo root = xroot -o x
root = xroot -o x
+ eval uptime
++ uptime
 22:26:27 up 104 days, 20:58,  1 user,  load average: 0.10, 0.11, 0.09

Pomimo, że wartość LOGIN nie jest równa wyrażeniu xroot – jak zakładaliśmy – to instrukcje wewnątrz warunku if zostały wykonane mimo to, co jest nieoczekiwanym dla nas zachowaniem. W celu naprawy tego błędu warunek if powinien mieć postać:

if [ "x$LOGIN" = "xroot" ] ; then

Drugim błędem jest oczywiście pozwolenie na uruchomienie funkcji eval na danych przekazanych przez użytkownika. Do tego nigdy nie powinniśmy dopuścić chyba, że bardzo starannie przeprowadzamy sanityzację danych wejściowych i używamy białej listy, aby ograniczyć dozwolone wartości. Gdyby powyższy skrypt był uruchamiany z prawami administratora, atakujący bez problemu byłby w stanie przeprowadzić eskalację swoich uprawnień. Spójrzmy na drugi przykład, który nie używa funkcji eval, ale zapisuje dane do pliku bez ochrony ich wartości:

#!/bin/bash

read DATA
echo ls $DATA >> showdata.sh
chmod a+x showdata.sh
./showdata.sh

Jeśli użytkownik zdecyduje się na przekazanie do zmiennej DATA polecenia: ; rm /etc/shadow, spowoduje to usunięcie tego pliku:

root@darkstar:~# bash -x test.sh
+ read DATA
; rm /etc/shadow
+ echo ls ';' rm /etc/shadow
+ chmod a+x showdata.sh
+ ./showdata.sh
root@darkstar:~# cat showdata.sh
ls ; rm /etc/shadow

Spróbujmy to naprawić poprzez podmianę linii, która opakuje nam dane wejściowe w cudzysłów:

echo ls "\"$DATA\"" >> showdata.sh
export DATA

Rzeczywiście uruchamiając ponownie skrypt z tym samym poleceniem jesteśmy chronieni:

root@darkstar:~# bash -x test.sh
+ read DATA
; rm /etc/shadow
+ echo ls '"; rm dane"'
+ export DATA
+ chmod a+x showdata.sh
+ ./showdata.sh
ls: cannot access ; rm /etc/shadow: No such file or directory
root@darkstar:~# cat showdata.sh
ls "; rm /etc/shadow"

Ale w ten sposób nieświadomie otworzyliśmy sobie drugą lukę bezpieczeństwa. Wystarczy teraz wprowadzić wartość, która będzie już opakowana w cudzysłów:

root@darkstar:~# bash -x test.sh
+ read DATA
"; rm /etc/shadow; echo "
+ echo ls '""; rm /etc/shadow; echo ""'
+ export DATA
+ chmod a+x showdata.sh
+ ./showdata.sh
ls: cannot access : No such file or directory

root@darkstar:~# cat showdata.sh
ls ""; rm /etc/shadow; echo ""

Możemy naprawić ten błąd na dwa sposoby. Pierwszy z nich wymaga obecności funkcji export, która podniesie nam zmienną DATA do rangi globalnej, aby była widoczna dla skryptu showdata.sh – w przeciwnym wypadku będzie to dla niego tylko niezdefiniowana zmienna. Podmieniamy linię zaczynającą się od echo na:

echo ls "\"\$DATA\"" >> showdata.sh

i możemy przetestować skrypt dla dwóch poprzednich, wrogich wartości. Drugi sposób angażuje, jako filtr dla cudzysłowów narzędzie sed, ale nie wymaga zmiennych globalnych:

FILTER="$(echo "$DATA" | sed "s/'/'\"'\"'/g")"
echo ls "'$FILTER'" >> showdata.sh

Testy tego rozwiązania dają następujące wyniki:

root@darkstar:~# bash -x test.sh
+ read DATA
; rm /etc/shadow
++ echo '; rm /etc/shadow'
++ sed 's/'\''/'\''"'\''"'\''/g'
+ FILTER='; rm /etc/shadow'
+ echo ls ''\''; rm /etc/shadow'\'''
+ chmod a+x showdata.sh
+ ./showdata.sh
ls: cannot access ; rm /etc/shadow: No such file or directory
root@darkstar:~# cat showdata.sh
ls '; rm /etc/shadow'
-----
root@darkstar:~# bash -x test.sh
+ read DATA
"; rm /etc/shadow; echo "
++ echo '"; rm /etc/shadow; echo "'
++ sed 's/'\''/'\''"'\''"'\''/g'
+ FILTER='"; rm /etc/shadow; echo "'
+ echo ls ''\''"; rm /etc/shadow; echo "'\'''
+ chmod a+x showdata.sh
+ ./showdata.sh
ls: cannot access "; rm /etc/shadow; echo ": No such file or directory
root@darkstar:~# cat showdata.sh
ls '"; rm /etc/shadow; echo "'

Polecam również testy tego filtra z bardziej rozbudowanymi ciągami.

Więcej informacji: Quotes and escaping, How to escape single quotes within single quoted strings?

Kategorie K a t e g o r i e : Bezpieczeństwo

Tagi T a g i : , , , , , ,

Komentowanie tego wpisu jest zablokowane.