perl -ne '…'실행의 보안 영향 *


27

분명히, 실행 중 :

perl -n -e 'some perl code' *

또는

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

( -p대신에 동일 -n)

또는

perl -e 'some code using <>' *

이 사이트에 게시 된 1 개의 라이너에서 종종 발견되며 보안에 영향을 미칩니다. 거래는 무엇입니까? 그것을 피하는 방법?

답변:


33

뭐가 문제 야

첫째, 많은 유틸리티와 마찬가지로 파일 이름으로 시작하는 문제가 있습니다 -. 있는 동안 :

sh -c 'inline sh script here' other args

다른 인수는 inline sh script; 와 perl동등한

perl -e 'inline perl script here' other args

다른 인수는 인라인 스크립트가 아닌 펄을 우선으로 하는 추가 옵션이 있는지 검사합니다 . 예를 들어 -eBEGIN{do something evil}현재 디렉토리에 파일이 있으면

perl -ne 'inline perl script here;' *

(의 유무에 관계없이 -n) 악한 일을합니다.

다른 유틸리티와 마찬가지로 해결 방법은 옵션 끝 마커 ( --)를 사용하는 것입니다.

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

그러나 그럼에도 불구하고 여전히 위험하며 /에 <>의해 사용되는 운영자 에게 달려 있습니다.-n-p

문제는 perldoc perlop설명서에 설명되어 있습니다.

이 특수 연산자는 입력의 한 줄 (하나의 레코드, 기본적으로 레코드 인 줄)을 읽는 데 사용됩니다. 여기서 해당 입력은에서 전달 된 각 인수에서옵니다 @ARGV.

에서:

perl -pe '' a b

-pwhile (<>)코드 주위 에 루프가 있음을 나타냅니다 (여기서는 비어 있음).

<>먼저 열리고 a파일이 소진 될 때까지 한 번에 한 줄씩 레코드를 읽은 다음 열 것입니다 b...

문제는 파일을 열 때 안전하지 않은 첫 번째 형식을 사용한다는 것입니다 open.

open ARGV, "the file as provided"

그 형식으로 논쟁이

  • "> afile"afile쓰기 모드에서 열립니다 .
  • "cmd|"을 실행 cmd하고 출력을 읽습니다.
  • "|cmd"의 입력에 쓸 수있는 스트림이 열려 cmd있습니다.

예를 들어 :

perl -pe '' 'uname|'

호출 된 파일의 내용 uname|(완전히 유효한 파일 이름 btw)은 출력하지 않지만 uname명령 의 출력은 출력하지 않습니다 .

당신이 실행중인 경우 :

perl -ne 'something' -- *

그리고 누군가가 rm -rf "$HOME"|현재 디렉토리에 (완전히 유효한 파일 이름) 이라는 파일을 만들었습니다 (예를 들어, 다른 사람이 해당 디렉토리를 한 번 쓸 수 있었거나, dodgy 아카이브를 추출했거나 dodgy 명령을 실행했거나, 다른 소프트웨어의 또 다른 취약점이 악용되었습니다)) 그러면 큰 어려움에 처하게됩니다. 이 문제를 인식하는 것이 중요한 영역 은 공용 영역 /tmp(또는 이러한 도구에서 호출 할 수있는 도구)과 같은 공용 영역 에서 자동으로 파일을 처리하는 도구입니다.

라는 파일은 > foo, foo|, |foo문제가 있습니다. 그러나 조금 적게 < foo하고 foo잘하는 수단으로 그 파일이 처리되지 않거나 잘못된 될 것으로 (공백, 탭, 줄 바꿈, 이러다 ... 포함) 선행 또는 후행 ASCII 간격 문자.

또한 멀티 바이트 문자 세트 ( ǖBIG5-HKSCS 와 같은)의 일부 문자는 0x7c의 바이트 인코딩으로 끝나는 점에 유의하십시오 |.

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

따라서 해당 문자셋을 사용하는 로케일에서

 perl -pe '' ./nǖ

실행하려고시겠습니까 ./n\x88로 명령을 perl수 없습니다 사용자의 로케일에서 해당 파일 이름을 해석하려고!

해결 / 해결 방법

AFAIK, perl시스템 전체에서 안전하지 않은 기본 동작을 한 번만 변경하려면 수행 할 수있는 작업이 없습니다 .

첫째, 파일 이름의 시작과 끝에있는 문자에서만 문제가 발생합니다. 따라서 문제가 perl -ne '' *있거나perl -ne '' *.txt

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

모든 인수는 이제 시작되지 않기 때문에 ./그리고 결국 .txt(그렇게하지 -, <, >, |..., 공간). 더 일반적으로, 그것은 좋은 아이디어에 접두사의 globs와 와 함께 ./. 또한 다른 많은 유틸리티로 -시작하거나 파일에서 시작하는 문제를 피할 수 -있습니다 (여기서 옵션 끝 ( --) 표시자가 더 이상 필요하지 않음 ).

사용 -Ttaint모드 것은 어느 정도 도움이됩니다. 이러한 악의적 인 파일이 발견되면 명령이 중단됩니다 ( >및 공백이 |아닌 및 경우 에만 해당 <).

이러한 명령을 대화식으로 사용할 때 유용한 정보가 있다는 것을 알려주므로 유용합니다. 자동 처리를 수행 할 때는 바람직하지 않을 수 있습니다. 즉, 누군가 파일을 작성하여 처리를 실패 하게 할 수 있기 때문 입니다.

이름에 관계없이 모든 파일을 처리 하려면 CPAN 에서 ARGV::readonly perl모듈을 사용할 수 있습니다 (불행하게도 기본적으로 설치되지 않음). 그것은 매우 짧은 모듈입니다.

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

기본적으로 " foo|"예를 들어로 전환 하여 @ARGV를 소독 "< ./ foo|\0"합니다.

명령 의 BEGIN명령문에서 동일한 작업을 수행 할 수 있습니다 perl -n/-p.

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

여기서는 ./사용중인 가정을 단순화합니다 .

ARGV::readonly그러나 (및 ) 의 부작용 은 그 뒤에 나오는 NUL 문자 $ARGVyour code here보여줍니다.

2015-06-03 업데이트

perlv5.21.5 이상에는 특수 처리를 수행하지 않는 것을 제외하고는 <<>>작동 하는 새 연산자가 있습니다. 인수는 파일 이름으로 만 간주됩니다. 따라서 해당 버전으로 다음과 같이 작성할 수 있습니다.<>

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

합니다 (잊지 마세요 --또는 사용 ./*이 파일을 덮어 쓰거나 예기치 않은 명령을 실행 두려움없이 생각을).

-n/ -p그래도 위험한 <>형태를 사용하십시오 . 그리고 심볼릭 링크를 계속 따르고 있으므로 반드시 신뢰할 수없는 디렉토리에서 사용하는 것이 안전하지는 않습니다.


2
당신은 하루 종일 노력하고 있습니다, 나는 내기. 잘 했어.
mikeserv

2
펄을 멋지게 업데이트했지만 펄 개발자가 -P 및 -N 옵션을 사용하지 않았기 때문에 (일부 스크립트는 안전하지 않은 동작에 의존하기 때문에 기존의 -p 및 -n을 변경할 수 없음)
cas

9

@ Stéphane Chazelas의 답변 외에도 -i명령 줄 옵션을 사용하면이 문제에 대해 걱정할 필요가 없습니다 .

$ perl -pe '' 'uname|'
Linux

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

-i옵션을 perl사용할 때 파일을 처리하기 전에 stat 를 사용 하여 파일 상태를 확인하십시오.

$ 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수표와 유효한 펄 처리 사이에 경쟁 조건이있을 수 있습니까?
Totor

@Totor : 아니요.
cuonglm

이 아닙니다 stat. 파일 을 제자리에서 -i편집 하는 것 뿐 이므로 실제 파일 경로 이외의 인수를 허용하는 것은 합리적이지 않으므로 특수 처리가 수행되지 않습니다. -i
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.