Perl -ne '…' * uygulamasının güvenlik etkileri


27

Görünüşe göre koşuyor:

perl -n -e 'some perl code' *

Veya

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

(aynı -pyerine -n)

Veya

perl -e 'some code using <>' *

sık sık bu sitede yayınlanan tek gömlek içinde bulunan, güvenlik çıkarımları vardır. Anlaşma ne? Nasıl engellenir?

Yanıtlar:


33

Sorun ne

İlk olarak, birçok yardımcı programda olduğu gibi, ile başlayan dosya adlarıyla ilgili bir sorun yaşarsınız -. İçinde iken:

sh -c 'inline sh script here' other args

Diğer argümanlar inline sh script; ile perleşdeğer

perl -e 'inline perl script here' other args

Diğer argümanlar , satır içi komut dosyasında değil, önce perl işleminde daha fazla seçenek için taranır . Örneğin, -eBEGIN{do something evil}geçerli dizinde adı verilen bir dosya varsa ,

perl -ne 'inline perl script here;' *

(olan veya olmayan -n) kötülük yapacak.

Diğer araçlarda olduğu gibi, bunun için çalışılması da seçenekler sonu işaretleyicisini ( --) kullanmaktır:

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

Fakat o zaman bile, hala tehlikelidir ve bu <>, -n/ tarafından kullanılan operatöre bağlıdır -p.

Sorun perldoc perlopbelgelerde açıklanmıştır .

Bu özel operatör girişin bir satırını (bir kayıt, varsayılan olarak satırları kaydeder) okumak için kullanılır, burada o giriş her bir argümandan sırayla gelir @ARGV.

İçinde:

perl -pe '' a b

-pwhile (<>)kodun etrafında bir döngü anlamına gelir (burada boş).

<>açılacak a, dosya tükenene kadar her seferinde bir satır kayıtları okuyacak ve sonra açacaktır b...

Sorun şu ki, dosyayı açmak için ilk, güvensiz şeklini kullanıyor open:

open ARGV, "the file as provided"

Argüman ise, bu formla

  • "> afile", afileyazma modunda açılır ,
  • "cmd|", çalışır cmdve çıktılarını okur.
  • "|cmd", girişine yazmak için açık bir akışınız var cmd.

Mesela:

perl -pe '' 'uname|'

uname|Adı verilen dosyanın içeriğini ( btw olarak tamamen geçerli bir dosya adı) çıkarmaz, ancak unamekomutun çıktısını alır .

Eğer koşuyorsanız:

perl -ne 'something' -- *

Ve birisi rm -rf "$HOME"|geçerli dizinde (yine de geçerli bir dosya adı) adlı bir dosya yarattı (örneğin, bu dizin bir zamanlar başkaları tarafından yazılabilirdi ya da çok tehlikeli bir arşiv çıkarttınız ya da çok tehlikeli bir komut çalıştırdınız ya da başka bir yazılımdaki başka bir güvenlik açığından yararlanıldı), o zaman başınız büyük belada. Bu sorunun farkında olmanın önemli olduğu alanlar , kamuya açık alanlarda /tmp(veya bu araçlar tarafından çağrılabilecek araçlar) dosyaları otomatik olarak işleyen araçlardır.

Denilen Dosyalar > foo, foo|, |foobir sorun vardır. Ancak, daha az ölçüde < foove fooönde gelen veya sondaki ASCII boşluk karakterleri (boşluk, sekme, yeni satır, cr ... dahil) ile birlikte, bu dosyaların işlenmeyeceği veya yanlış olanın olacağı anlamına gelir.

Ayrıca bazı çok baytlık karakter kümelerindeki bazı karakterlerin ( ǖBIG5-HKSCS'de olduğu gibi) kodlaması olan bayt 0x7c ile bittiğine dikkat edin |.

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

Yani bu karakter dizisini kullanan yerel ayarlarda,

 perl -pe '' ./nǖ

Çalıştırmayı denediğinizde misiniz ./n\x88olarak komutunu perlolur değil kullanıcının yerel ayar o dosya adını yorumlamaya çalışın!

Nasıl düzeltilir / çalışır

AFAIK, bir perlkez ve tüm sistem genelinde güvenli olmayan varsayılan davranışını değiştirmek için yapabileceğiniz hiçbir şey yoktur .

İlk olarak, sorun yalnızca dosya adının başındaki ve sonundaki karakterlerle oluşur. Yani, ne zaman perl -ne '' *ya perl -ne '' *.txtda bir sorun

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

Tüm bağımsız değişkenler şimdi ile başlamaz, çünkü ./ve bitiş içinde .txt(yani değil -, <, >, |..., uzay). Daha genel olarak, bu iyi bir fikir için önek var Neználkovo ile ./. Bu, çağrılan -veya -başka birçok yardımcı programla başlayan dosyalardaki sorunları da önler (ve burada, seçeneklerin sonunu ( --) artık işaretlemeye gerek duymazsınız).

Kullanımı -Taçmak için taintmod bir ölçüde yardımcı olur. Böyle kötü amaçlı bir dosyayla karşılaşılırsa komutu iptal eder (ancak >ve |durumlar için değil, <boşluklar için).

Bu tür komutları etkileşimli olarak kullanmanız yararlıdır, çünkü sizi tehlikeli bir şey olduğuna dair uyarır. Bazı otomatik işlemler yaparken bu arzu edilmeyebilir, çünkü bu işlem birisinin sadece bir dosya oluşturarak işlemi başarısız hale getirebileceği anlamına gelir .

Her dosyayı işlemek istiyorsanız, adından bağımsız olarak , ARGV::readonly perlmodülü CPAN'da kullanabilirsiniz (ne yazık ki genellikle varsayılan olarak kurulmaz). Bu çok kısa bir modül yapar:

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

Temel olarak, @ARGV'yi " foo|", örneğin içine çevirerek temizler "< ./ foo|\0".

Aynısını komutunuzdaki bir BEGINifadede yapabilirsiniz perl -n/-p:

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

Burada ./kullanılmakta olan varsayımı basitleştiriyoruz .

(Ve bir yan etkisi ARGV::readonly) rağmen olmasıdır $ARGVolarak your code heregösterir NULL karakteri arka olduğu.

Güncelleme 2015-06-03

perlv5.21.5 ve üzeri , özel işlem yapmaması haricinde <<>>davranan yeni bir operatöre sahiptir . Bağımsız değişkenler yalnızca dosya adları olarak kabul edilir. Yani bu sürümlerle, şimdi yazabilirsiniz:<>

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

(unutma --ya da kullanma ./*), dosyaların üzerine yazma veya beklenmeyen komutları çalıştırmadan korkmadan.

-n/ -pyine de tehlikeli <>formu kullanın . Ve dikkatin devam eden sembolik bağları takip etmeye devam edin, bu yüzden mutlaka güvenilmez dizinlerde kullanmanın güvenli olduğu anlamına gelmez.


2
Bütün gün bunun üzerinde çalıştın, ben bahse gireceğim aferin.
mikeserv

2
perl için güzel güncelleme, ancak perl devs'in onu kullanmak için -P ve -N seçenekleri eklememesi gariptir (varolan -p ve -n'yi değiştiremez çünkü bazı betikler güvensiz davranışlara güvenebilir)
cas

9

@ Stéphane Chazelas'ın cevabına ek olarak , -ikomut satırı seçeneğini kullanırsak bu konuda endişelenmemize gerek yok :

$ perl -pe '' 'uname|'
Linux

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

Çünkü, -iseçeneği kullanırken , işlemden önce dosya durumunu kontrol etmek için statperl kullanılır :

$ 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
statÇek ile etkin perl işleme arasında hemen sonra gerçekleşmesi muhtemel bir yarış koşulu yok mu?
Totor 19.05

@Totor: Hayır sanırım.
cuonglm

Mesele değil stat. Sadece dosyaları yerinde -idüzenlemek , gerçek dosya yollarından başka argümanları kabul etmek mantıklı değil, dolayısıyla özel işlem yapılmıyor. -i
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.