Co możesz zrobić z eval
poleceniem? Dlaczego to jest przydatne? Czy to jakaś wbudowana funkcja w bash? Nie ma man
na to strony.
help eval
pobrać ze swojej powłoki stronę „man”
Co możesz zrobić z eval
poleceniem? Dlaczego to jest przydatne? Czy to jakaś wbudowana funkcja w bash? Nie ma man
na to strony.
help eval
pobrać ze swojej powłoki stronę „man”
Odpowiedzi:
eval
jest częścią POSIX. Jest to interfejs, który może być wbudowany w powłokę.
Jest to opisane w „Podręczniku programisty POSIX”: http://www.unix.com/man-page/posix/1posix/eval/
eval - construct command by concatenating arguments
Weźmie argument i zbuduje jego polecenie, które zostanie wykonane przez powłokę. Oto przykład strony man:
1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
$foo
za pomocą wartości '10'
i $x
wartości 'foo'
.$y
, który składa się z ciągu '$foo'
. Znak dolara musi być poprzedzony znakiem ucieczki '$'
.echo $y
.'$foo'
eval
. Najpierw oceni $x
do łańcucha 'foo'
. Teraz mamy oświadczenie, y=$foo
które zostanie ocenione y=10
.echo $y
jest teraz wartość '10'
.Jest to powszechna funkcja w wielu językach, np. Perl i JavaScript. Więcej przykładów na perldoc eval: http://perldoc.perl.org/functions/eval.html
eval
jest wbudowana, a nie funkcja. W praktyce wbudowane zachowują się bardzo podobnie do funkcji, które nie mają definicji w języku, ale nie do końca (co staje się oczywiste, jeśli jesteś wystarczająco pokręcony, aby zdefiniować funkcję o nazwie eval
).
Tak, eval
jest wewnętrznym poleceniem bash, więc jest opisane na bash
stronie man.
eval [arg ...]
The args are read and concatenated together into a single com-
mand. This command is then read and executed by the shell, and
its exit status is returned as the value of eval. If there are
no args, or only null arguments, eval returns 0.
Zwykle stosuje się go w połączeniu z zastępowaniem poleceń . Bez wyraźnej eval
powłoki powłoka próbuje wykonać wynik podstawienia polecenia, a nie go ocenić .
Powiedz, że chcesz zakodować odpowiednik VAR=value; echo $VAR
. Zwróć uwagę na różnicę w sposobie, w jaki powłoka obsługuje pisma echo VAR=value
:
andcoz@...:~> $( echo VAR=value )
bash: VAR=value: command not found
andcoz@...:~> echo $VAR
<empty line>
Powłoka próbuje wykonać echo
i VAR=value
jako dwóch oddzielnych komend. Zgłasza błąd dotyczący drugiego ciągu. Zadanie pozostaje nieskuteczne.
andcoz@...:~> eval $( echo VAR=value )
andcoz@...:~> echo $VAR
value
Powłoka scala (łączy) dwa ciągi echo
i VAR=value
analizuje tę pojedynczą jednostkę zgodnie z odpowiednimi regułami i wykonuje ją.Last but not least, eval
może być bardzo niebezpiecznym poleceniem. Wszelkie dane wejściowe do eval
polecenia muszą być dokładnie sprawdzane, aby uniknąć problemów z bezpieczeństwem.
eval
nie ma strony podręcznika, ponieważ nie jest to osobne polecenie zewnętrzne, ale wbudowana powłoka, co oznacza polecenie wewnętrzne i znane tylko powłoce ( bash
). Odpowiednia część strony podręcznika bash
mówi:
eval [arg ...]
The args are read and concatenated together into a single command.
This command is then read and executed by the shell, and its exit
status is returned as the value of eval. If there are no args, or only
null arguments, eval returns 0
Ponadto dane wyjściowe, jeśli help eval
jest:
eval: eval [arg ...]
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
Exit Status:
Returns exit status of command or success if command is null.
eval
jest potężnym poleceniem i jeśli zamierzasz go używać, powinieneś bardzo ostrożnie unikać potencjalnych zagrożeń bezpieczeństwa, które się z tym wiążą.
Instrukcja eval mówi powłoce, aby przyjęła argumenty eval jako polecenie i uruchomiła je z wiersza poleceń. Przydaje się w sytuacji takiej jak poniżej:
W swoim skrypcie, jeśli definiujesz polecenie w zmiennej, a później chcesz użyć tego polecenia, powinieneś użyć eval:
/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
ls | more
. Innymi słowy: Nazwa pojedynczego polecenia składała się z dziewięciu znaków, w tym spacji i symbolu potoku .
eval to polecenie powłoki, które zwykle jest implementowane jako wbudowane.
W POSIX jest wymieniony jako część „2.14. Specjalne narzędzia wbudowane” w pozycji „eval” .
Wbudowane oznacza:
Termin „wbudowany” oznacza, że powłoka może bezpośrednio uruchomić narzędzie i nie musi go szukać.
Mówiąc najprościej: sprawia, że wiersz wejściowy jest analizowany dwukrotnie .
Powłoka ma sekwencję kroków, które wykonuje, aby „przetworzyć” linię. Możesz spojrzeć na ten obraz i zdać sobie sprawę, że eval jest jedyną linią, która idzie w górę, z powrotem do kroku 1 po lewej stronie. Z opisu POSIX :
2.1 Wprowadzenie do powłoki
- Powłoka odczytuje dane wejściowe ....
- Powłoka dzieli dane wejściowe na tokeny: słowa i operatory
- Powłoka analizuje dane wejściowe na polecenia proste i złożone.
- Powłoka wykonuje różne rozszerzenia (osobno) ...
- Powłoka dokonuje przekierowania i usuwa operatory przekierowania oraz ich operandy z listy parametrów.
- Powłoka wykonuje funkcję, wbudowany plik wykonywalny lub skrypt ...
- Opcjonalnie powłoka czeka na zakończenie komendy i pobiera status wyjścia.
W kroku 6 zostanie wykonane wbudowane.
W kroku 6 eval powoduje, że przetworzona linia jest odsyłana z powrotem do kroku 1.
Jest to jedyny warunek, w którym sekwencja wykonania wraca.
Dlatego mówię: w eval linia wejściowa jest analizowana dwukrotnie .
I najważniejszy efekt do zrozumienia. Jest to, że jedną z konsekwencji po raz pierwszy linia podlega siedmiu powłoki kroków przedstawionych powyżej, jest cytowanie . W kroku 4 (rozwinięcia) znajduje się również sekwencja kroków umożliwiająca wykonanie wszystkich rozszerzeń , z których ostatnim jest usunięcie oferty :
Usunięcie wyceny należy zawsze wykonać na końcu.
Tak więc zawsze usuwany jest jeden poziom cytowania.
W wyniku tego pierwszego efektu dodatkowe / różne części linii są narażone na parsowanie powłoki i wszystkie pozostałe kroki.
Pozwala to na wykonywanie rozszerzeń pośrednich:
a=b b=c ; eval echo \$$a ### shall produce "c"
Dlaczego? Ponieważ w pierwszej pętli $
cytowany jest pierwszy .
Jako taki jest ignorowany dla rozszerzeń przez powłokę.
Następny $
z nazwą a jest rozwinięty, aby uzyskać „b”.
Następnie jeden poziom cytowania jest usuwany, co powoduje, że pierwszy $
nie jest cytowany .
Koniec pierwszej pętli.
To w drugiej pętli łańcuch $b
jest odczytywany przez powłokę.
Następnie rozwinięty do „c”
I podany jako argument do echo
.
Aby „zobaczyć”, co eval wytworzy w pierwszej pętli (do ponownej oceny), użyj echa. Lub dowolne polecenie / skrypt / program, który wyraźnie pokazuje argumenty:
$ a=b b=c
$ eval echo \$$a;
c
Zastąp eval przez echo, aby „zobaczyć”, co się dzieje:
$ echo echo \$$a
echo $b
Możliwe jest również pokazanie wszystkich „części” linii za pomocą:
$ printf '<%s> ' echo \$$a
<echo> <$b>
Który w tym przykładzie jest tylko jednym echem i jedną zmienną, ale pamiętaj o tym, aby pomóc w ocenie bardziej złożonych przypadków.
Trzeba powiedzieć, że: w powyższym kodzie jest błąd, widzisz go ?.
Łatwo: brakuje niektórych cytatów.
W jaki sposób? możesz zapytać. Proste, zmieńmy zmienne (nie kod):
$ a=b b="hi jk"
$ eval echo \$$a
hi jk
Widzisz brakujące miejsca?
Jest tak, ponieważ wartość wewnątrz $b
została podzielona przez powłokę.
Jeśli to Cię nie przekonuje, spróbuj tego:
$ a=b b="hi * jk"
$ eval echo \$$a ### warning this will expand to the list
### of all files in the present directory.
Brakujące cytaty. Aby działał poprawnie (dodaj cytaty wewnętrzne "$a"
i zewnętrzne \"
).
Spróbuj tego (jest całkowicie bezpieczny):
$ a=b b="hi * jk"
$ eval echo \" \$"$a" \"
hi * jk
Nie ma strony man dla tego ..
Nie, nie ma na to niezależnej strony podręcznika. Wyszukiwanie instrukcji z man -f eval
lub nawet apropos eval
nie pokazuje żadnego wpisu.
Jest zawarty w środku man bash
. Jak każde wbudowane.
Wyszukaj „SHELL BUILTIN COMMANDS”, a następnie „eval”.
Łatwiejszym sposobem na uzyskanie pomocy jest: w bash, możesz zrobić, help eval
aby zobaczyć pomoc dla wbudowanego.
Ponieważ dynamicznie wiąże tekst z kodem.
Innymi słowy: konwertuje listę swoich argumentów (i / lub rozwinięcie takich argumentów) na wykonywaną linię. Jeśli z jakiegokolwiek powodu osoba atakująca ustali argument, wykonasz kod osoby atakującej.
Lub nawet prościej, z eval mówisz każdemu, kto zdefiniował wartość jednego lub kilku argumentów:
No dalej, usiądź tutaj i wpisz dowolną linię poleceń, wykonam to z moimi mocami.
Czy to niebezpieczne? Powinno być jasne dla wszystkich, że tak jest.
Zasada bezpieczeństwa dla eval powinny być:
Wykonuje tylko eval na zmiennych, do których ty dały jego wartość.
Przeczytaj więcej szczegółów tutaj .
eval
jest cechą najbardziej interpretowanych językach ( TCL
, python
, ruby
...), nie tylko muszli. Służy do dynamicznej oceny kodu.
W powłokach jest zaimplementowany jako wbudowane polecenie powłoki.
Zasadniczo eval
bierze ciąg znaków jako argument i ocenia / interpretuje w nim kod. W powłokach eval
może przyjąć więcej niż jeden argument, ale eval
po prostu łączy je w celu utworzenia ciągu do oceny.
Jest bardzo wydajny, ponieważ można dynamicznie konstruować kod i uruchamiać go, czego nie można zrobić w skompilowanych językach, takich jak C.
Lubić:
varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
# which in Bourne-like shell language
# is a variable assignment.
Jest to również niebezpieczne, ponieważ ważne jest odkażanie dynamicznych (dostarczonych zewnętrznie) części tego, co jest przekazywane, z eval
tego samego powodu, że jest interpretowane jako kod powłoki.
Na przykład, powyżej, jeśli $1
jest evil-command; var
, eval
kończy ocenę evil-command; var=$varvalue
kodu powłoki, a następnie uruchamia ją evil-command
.
Zło eval
często jest przesadzone.
OK, to niebezpieczne, ale przynajmniej wiemy, że jest niebezpieczne.
Wiele innych poleceń oceni Shellcode w swoich argumentów, jeśli nie oczyszczone, jak (w zależności od powłoki), [
aka test
, export
, printf
, GNU sed
, awk
i oczywiście sh
/ bash
/ perl
i wszyscy tłumacze ...
Przykłady (tutaj przy użyciu uname
jako evil-command
i $a
jako dane zewnętrzne niezarządzane):
$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux
$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"
Linux
$ a=';uname'; sh -c "echo $a"
Linux
Ci sed
, export
... Polecenia mogą być uważane za bardziej niebezpieczne, ponieważ podczas, gdy jest oczywiste, eval "$var"
spowoduje, że zawartość $var
być oceniane jako Shellcode, to nie jest tak oczywiste, ze sed "s/foo/$var/"
albo export "$var=value"
albo [ "$var" -gt 0 ]
. Niebezpieczeństwo jest takie samo, ale ukryte jest w innych poleceniach.
sed
podobnie jak eval
przekazywanie łańcucha zawartego w zmiennej, i dla obu, treść tego łańcucha jest ostatecznie oceniana jako kod powłoki, więc sed
jest tak niebezpieczne, jak eval
to mówię. sed
jest przekazywany ciąg zawierający uname
(uname nie został jeszcze wykonany) i przez wywołanie sed
polecenia uname kończy się wykonywanie. Jak na eval. W sed 's/foo/$a/g'
nie przekazujesz niezaszyfrowanych danych sed
, nie o tym tutaj mówimy.
Ten przykład może rzucić nieco światła:
#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"
Wyjście powyższego skryptu:
$VAR2
$VAR1
25
eval
. Czy uważasz, że istnieje jakiś fundamentalny, krytyczny aspekt jego funkcjonalności, eval
który nie został uwzględniony w istniejących odpowiedziach? Jeśli tak, wyjaśnij to i użyj przykładu, aby zilustrować swoje wyjaśnienie. Proszę nie odpowiadać w komentarzach; edytuj swoją odpowiedź, aby była jaśniejsza i bardziej kompletna.
type command
aby dowiedzieć się, jakiego typu jest polecenie . (type eval
w tym przypadku)