Wpływ na bezpieczeństwo uruchamiania perla -ne „…” *


27

Najwyraźniej działa:

perl -n -e 'some perl code' *

Lub

find . ... -exec perl -n -e '...' {} +

(to samo z -pzamiast -n)

Lub

perl -e 'some code using <>' *

często spotykane w linijkach opublikowanych na tej stronie, ma wpływ na bezpieczeństwo. O co chodzi? Jak tego uniknąć?

Odpowiedzi:


33

Jaki jest problem

Po pierwsze, podobnie jak w przypadku wielu narzędzi, będziesz mieć problem z nazwami plików zaczynającymi się od -. Podczas gdy w:

sh -c 'inline sh script here' other args

Pozostałe argumenty są przekazywane do inline sh script; z perlodpowiednikiem

perl -e 'inline perl script here' other args

Pozostałe argumenty są skanowane w poszukiwaniu najpierw większej liczby opcji perla , a nie wbudowanego skryptu. Na przykład jeśli -eBEGIN{do something evil}w bieżącym katalogu znajduje się plik o nazwie

perl -ne 'inline perl script here;' *

(z lub bez -n) zrobi coś złego.

Podobnie jak w przypadku innych narzędzi, obejście tego polega na użyciu znacznika końca opcji ( --):

perl -ne 'inline perl script here;' -- *

Ale nawet wtedy jest to nadal niebezpieczne i zależy to od <>operatora używanego przez -n/ -p.

Problem wyjaśniono w perldoc perlopdokumentacji.

Ten specjalny operator służy do odczytu jednego wiersza (jeden rekord, domyślnie zapisanych wierszy) danych wejściowych, gdzie dane wejściowe pochodzą z każdego przekazywanego argumentu @ARGV.

W:

perl -pe '' a b

-pzakłada while (<>)pętlę wokół kodu (tutaj pusta).

<>najpierw otworzy się a, odczyta rekordy pojedynczo, aż do wyczerpania pliku, a następnie otworzy b...

Problem polega na tym, że do otwarcia pliku używa pierwszej, niebezpiecznej formy open:

open ARGV, "the file as provided"

W tej formie, jeśli argument jest

  • "> afile", otwiera się afilew trybie pisania,
  • "cmd|", działa cmdi odczytuje dane wyjściowe.
  • "|cmd", masz strumień otwarty do zapisu na wejściu cmd.

Na przykład:

perl -pe '' 'uname|'

Nie wyświetla treści pliku o nazwie uname|(doskonale poprawna nazwa pliku btw), ale dane wyjściowe unamepolecenia.

Jeśli biegasz:

perl -ne 'something' -- *

I ktoś utworzył plik o nazwie rm -rf "$HOME"|(ponownie doskonale poprawna nazwa pliku) w bieżącym katalogu (na przykład dlatego, że ten katalog był kiedyś zapisywalny przez innych, lub wyodrębniłeś podejrzane archiwum, lub uruchomiłeś jakieś podejrzane polecenie lub została wykorzystana inna luka w zabezpieczeniach innego oprogramowania), wtedy masz duże problemy. Obszary, w których należy zdawać sobie sprawę z tego problemu, to narzędzia przetwarzające pliki automatycznie w miejscach publicznych , takie jak /tmp(lub narzędzia, które mogą być wywoływane przez takie narzędzia).

Pliki zwane > foo, foo|, |foosą problemem. Ale w mniejszym stopniu < fooi fooz czołowymi lub końcowe znaki odstępów ASCII (w tym miejsca, tabulacjami, Cr ...), a także, że środki te pliki nie będą przetwarzane lub niewłaściwy z nich będzie.

ǖPamiętaj też, że niektóre znaki w niektórych zestawach znaków wielobajtowych (jak w BIG5-HKSCS) kończą się bajtem 0x7c, kodowaniem |.

$ printf ǖ | iconv -t BIG5-HKSCS | od -tx1 -tc
0000000  88  7c
        210   |
0000002

Więc w lokalizacjach używających tego zestawu znaków,

 perl -pe '' ./nǖ

Spróbuje uruchomić ./n\x88komendę jak perlby nie spróbować zinterpretować tę nazwę pliku w lokalizacji użytkownika!

Jak to naprawić / obejść

AFAIK, nic nie możesz zrobić, aby zmienić to niebezpieczne zachowanie domyślne perlraz na zawsze w całym systemie.

Po pierwsze, problem występuje tylko w przypadku znaków na początku i na końcu nazwy pliku. Tak więc, podczas gdy perl -ne '' *lub perl -ne '' *.txtstanowią problem,

perl -ne 'some code' ./*.txt

nie dlatego, że wszystkie argumenty, teraz zaczynają się ./i kończą w .txt(więc nie -, <, >, |, przestrzeń ...). Mówiąc bardziej ogólnie, że to dobry pomysł, aby prefiks globs z ./. Pozwala to również uniknąć problemów z plikami wywoływanymi -lub rozpoczynającymi się -od wielu innych narzędzi (a tutaj oznacza to, że nie potrzebujesz już --znacznika końca opcji ( )).

Używanie trybu -Twłączania taintpomaga w pewnym stopniu. Przerywa polecenie, jeśli napotka taki złośliwy plik (tylko dla przypadków >i |, ale nie <lub białych znaków).

Jest to przydatne, gdy używasz takich poleceń interaktywnie, ponieważ ostrzega Cię, że dzieje się coś podejrzanego. Może to nie być pożądane podczas automatycznego przetwarzania, ponieważ oznacza to, że ktoś może spowodować, że przetwarzanie nie powiedzie się, po prostu przez utworzenie pliku.

Jeżeli chcesz, aby przetworzyć każdy plik, niezależnie od ich nazwy, można korzystać z ARGV::readonly perlmodułu na CPAN (niestety zwykle nie zainstalowanego domyślnie). To bardzo krótki moduł, który:

sub import{
   # Tom Christiansen in Message-ID: <24692.1217339882@chthon>
   # reccomends essentially the following:
   for (@ARGV){
       s/^(\s+)/.\/$1/;   # leading whitespace preserved
       s/^/< /;       # force open for input
       $_.=qq/\0/;    # trailing whitespace preserved & pipes forbidden
   };
};

Zasadniczo dezynfekuje @ARGV, zmieniając " foo|"na przykład w "< ./ foo|\0".

Możesz zrobić to samo w BEGINpoleceniu w swoim perl -n/-ppoleceniu:

perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*

Tutaj upraszczamy to przy założeniu, że ./jest używane.

Efektem ubocznym, że (i ARGV::readonly) jest jednak, że $ARGVw your code herepokazach że końcowe znak NUL.

Aktualizacja 2015-06-03

perlWer. 5.21.5 i nowsze mają nowego <<>>operatora, który zachowuje się tak, <>z tym wyjątkiem, że nie wykona tego specjalnego przetwarzania. Argumenty będą traktowane tylko jako nazwy plików. Dzięki tym wersjom możesz teraz pisać:

perl -e 'while(<<>>){ ...;}' -- *

(nie zapomnij --lub użyj ./*) bez obawy, że nadpisze pliki lub uruchomi nieoczekiwane polecenia.

-n/ -pnadal jednak używam niebezpiecznej <>formy. Uważaj też na dowiązania symboliczne, dlatego niekoniecznie oznacza to, że można bezpiecznie korzystać z niezaufanych katalogów.


2
pracujesz nad tym przez cały dzień, założę się. dobra robota.
mikeserv

2
niezła aktualizacja do Perla, ale dziwne, że deweloperzy Perla nie dodali opcji -P i -N, aby z niego skorzystać (nie mogą zmienić istniejących opcji -p i -n, ponieważ niektóre skrypty mogą polegać na niepewnym zachowaniu)
cas

9

Oprócz odpowiedzi @ Stéphane Chazelas nie musimy się martwić tym problemem, jeśli użyjemy -iopcji wiersza poleceń:

$ perl -pe '' 'uname|'
Linux

$ perl -i -pe '' 'uname|'
Can't open uname|: No such file or directory.

Ponieważ przy użyciu -iopcji perlstosowany stat , aby sprawdzić stan pliku przed procesem IT:

$ strace -fe trace=stat perl -pe '' 'uname|'
stat("/home/cuonglm/perl5/lib/perl5/5.20.1/x86_64-linux", 0x7fffd44dff90) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/5.20.1", 0x7fffd44dff90) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/x86_64-linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
Process 6106 attached
Linux
Process 6105 suspended
Process 6105 resumed
Process 6106 detached
--- SIGCHLD (Child exited) @ 0 (0) ---

$ strace -fe trace=stat perl -i -pe '' 'uname|'
stat("/home/cuonglm/perl5/lib/perl5/5.20.1/x86_64-linux", 0x7fffdbaf2e50) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/5.20.1", 0x7fffdbaf2e50) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/x86_64-linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("uname|", 0x785f40)                = -1 ENOENT (No such file or directory)
Can't open uname|: No such file or directory.

1
Czy nie jest możliwy warunek wyścigu między statczekiem a efektywnym przetwarzaniem perla, który ma miejsce zaraz po nim?
Totor

@Totor: Myślę, że nie.
cuonglm,

Nie chodzi o to stat. Chodzi tylko o -ito, aby edytować pliki w miejscu, więc nie ma sensu akceptować argumentów innych niż rzeczywiste ścieżki plików, więc dzięki -itemu specjalne przetwarzanie nie jest wykonywane.
Stéphane Chazelas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.