Implicazioni sulla sicurezza dell'esecuzione di perl -ne '...' *


27

Apparentemente, in esecuzione:

perl -n -e 'some perl code' *

O

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

(lo stesso con -pinvece di -n)

O

perl -e 'some code using <>' *

spesso si trova in una riga inserita in questo sito, ha implicazioni per la sicurezza. Qual è l'accordo? Come evitarlo?

Risposte:


33

Qual è il problema

Innanzitutto, come per molte utility, avrai un problema con i nomi dei file che iniziano con -. Nel frattempo:

sh -c 'inline sh script here' other args

Gli altri argomenti vengono passati a inline sh script; con l' perlequivalente,

perl -e 'inline perl script here' other args

Gli altri argomenti vengono analizzati per più opzioni per perl prima, non lo script inline. Ad esempio, se esiste un file chiamato -eBEGIN{do something evil}nella directory corrente,

perl -ne 'inline perl script here;' *

(con o senza -n) farà qualcosa di malvagio.

Come per altre utility, la soluzione è quella di utilizzare il marker di fine opzioni ( --):

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

Ma anche in questo caso, è ancora pericoloso e dipende <>dall'operatore utilizzato da -n/ -p.

Il problema è spiegato nella perldoc perlopdocumentazione.

Tale operatore speciale viene utilizzato per leggere una riga (un record, i record sono righe per impostazione predefinita) dell'input, in cui l'input proviene da ciascuno degli argomenti a sua volta passati @ARGV.

Nel:

perl -pe '' a b

-pimplica un while (<>)ciclo attorno al codice (qui vuoto).

<>si aprirà prima a, leggerà i record una riga alla volta fino a quando il file non sarà esaurito e quindi si aprirà b...

Il problema è che, per aprire il file, utilizza la prima forma non sicura di open:

open ARGV, "the file as provided"

Con quel modulo, se l'argomento è

  • "> afile", si apre afilein modalità di scrittura,
  • "cmd|", viene eseguito cmde legge l'output.
  • "|cmd", hai uno stream aperto per la scrittura nell'input di cmd.

Quindi per esempio:

perl -pe '' 'uname|'

Non genera il contenuto del file chiamato uname|(un nome file perfettamente valido tra l'altro), ma l'output del unamecomando.

Se stai correndo:

perl -ne 'something' -- *

E qualcuno ha creato un file chiamato rm -rf "$HOME"|(di nuovo un nome file perfettamente valido) nella directory corrente (ad esempio perché quella directory una volta era scrivibile da altri, o hai estratto un archivio dannoso, o hai eseguito un comando dodgy, o un'altra vulnerabilità in alcuni altri software è stata sfruttata), quindi sei in grossi guai. Aree in cui è importante essere consapevoli di questo problema sono gli strumenti che elaborano automaticamente i file in aree pubbliche come /tmp(o strumenti che possono essere chiamati da tali strumenti).

File chiamati > foo, foo|, |foosono un problema. Ma in misura minore < fooe foocon caratteri di spaziatura ASCII iniziali o finali (inclusi spazio, tabulazione, nuova riga, cr ...), ciò significa che i file non verranno elaborati o che quello sbagliato sarà.

Attenzione anche che alcuni caratteri in alcuni set di caratteri multi-byte (come ǖin BIG5-HKSCS) finiscono nel byte 0x7c, la codifica di |.

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

Quindi nei locali che usano quel set di caratteri,

 perl -pe '' ./nǖ

Avrebbe cercato di eseguire il ./n\x88comando come perlsarebbe non cercare di interpretare che il nome del file in locale dell'utente!

Come risolvere / aggirare

AFAIK, non c'è nulla che tu possa fare per modificare quel comportamento predefinito non sicuro di perluna volta per tutte a livello di sistema.

Innanzitutto, il problema si verifica solo con i caratteri all'inizio e alla fine del nome del file. Quindi, mentre perl -ne '' *o perl -ne '' *.txtsono un problema,

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

non è perché tutti gli argomenti ora iniziano con ./e fine a se .txt(quindi non -, <, >, |, spazio ...). Più in generale, è una buona idea per il prefisso gocce con ./. Ciò evita anche problemi con i file chiamati -o che iniziano con -molte altre utilità (e qui, ciò significa che non è più necessario l'indicatore end-of-options ( --)).

L'uso -Tper attivare la taintmodalità aiuta in una certa misura. Annullerà il comando se viene rilevato tale file dannoso (solo per i casi >e |, non comunque <o gli spazi bianchi).

È utile quando si utilizzano tali comandi in modo interattivo in quanto ti avverte che sta succedendo qualcosa di complicato. Tuttavia, ciò potrebbe non essere desiderabile quando si esegue l'elaborazione automatica, poiché ciò significa che qualcuno può far fallire l' elaborazione semplicemente creando un file.

Se vuoi elaborare tutti i file, indipendentemente dal loro nome, puoi usare il ARGV::readonly perlmodulo su CPAN (sfortunatamente di solito non installato di default). Questo è un modulo molto breve che fa:

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
   };
};

Fondamentalmente, sanifica @ARGV trasformandolo " foo|"ad esempio in "< ./ foo|\0".

Puoi fare lo stesso in BEGINun'istruzione nel tuo perl -n/-pcomando:

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

Qui lo semplificiamo partendo dal presupposto che ./viene utilizzato.

Un effetto collaterale di che (e ARGV::readonly) è però che $ARGVin your code heremostra che trascinamento carattere NUL.

Aggiornamento 03/06/2015

perlv5.21.5 e soprattutto avere un nuovo <<>>operatore che si comporta come <>se non che essa non farlo lavorazioni speciali. Gli argomenti verranno considerati solo come nomi di file. Quindi con quelle versioni, ora puoi scrivere:

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

(non dimenticare --o utilizzare ./*però) senza timore di sovrascrivere i file o eseguire comandi imprevisti.

-n/ -puso comunque la <>forma pericolosa . E attenzione, i collegamenti simbolici sono ancora seguiti, quindi ciò non significa necessariamente che sia sicuro da usare in directory non attendibili.


2
ci hai lavorato tutto il giorno, scommetto. molto bene.
Mikeserv,

2
bel aggiornamento a perl, ma è strano che gli sviluppatori di perl non abbiano aggiunto le opzioni -P e -N per usarlo (non è possibile modificare gli esistenti -p e -n perché alcuni script possono fare affidamento sul comportamento insicuro)
Cas

9

Oltre alla risposta di @ Stéphane Chazelas , non dobbiamo preoccuparci di questo problema se utilizziamo l' -iopzione della riga di comando:

$ perl -pe '' 'uname|'
Linux

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

Perché quando si utilizza l' -iopzione, si perlutilizza stat per verificare lo stato del file prima di elaborarlo:

$ 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
Non esiste una possibile condizione di competizione tra il statcontrollo e l'effettiva elaborazione del perl in corso subito dopo?
Totor

@Totor: penso di no.
cuonglm

Non si tratta stat. È solo -iper modificare i file sul posto, quindi non ha senso accettare argomenti diversi dai percorsi dei file effettivi, quindi con -iquell'elaborazione speciale non viene eseguita.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.