`find -exec sh -c`를 안전하게 사용할 수 있습니까? 1 martin

내가 사용하려고 해요 findecho 0일부 파일에,하지만 분명히 이것은 단지와 함께 작동합니다 sh -c:

find /proc/sys/net/ipv6 -name accept_ra -exec sh -c 'echo 0 > {}' \;

그러나 sh -cwith find -exec을 사용 하면 인용 문제가 의심되므로 매우 불편합니다. 나는 그것으로 조금 바이올린을 썼고 분명히 내 의심은 정당화되었다.

  • 내 테스트 설정 :

    martin@dogmeat ~ % cd findtest
    martin@dogmeat ~/findtest % echo one > file\ with\ spaces
    martin@dogmeat ~/findtest % echo two > file\ with\ \'single\ quotes\'
    martin@dogmeat ~/findtest % echo three > file\ with\ \"double\ quotes\"
    martin@dogmeat ~/findtest % ll
    insgesamt 12K
    -rw-rw-r-- 1 martin martin 6 Sep 17 12:01 file with "double quotes"
    -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with 'single quotes'
    -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with spaces
  • find -exec없이 사용하면 sh -c문제없이 작동하는 것 같습니다.

    martin@dogmeat ~ % find findtest -type f -exec cat {} \;
    one
    two
    three
  • 그러나 내가 사용할 때 sh -c {}어떤 종류의 인용이 필요한 것 같습니다.

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c 'cat {}' \;
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: spaces: No such file or directory
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: single quotes: No such file or directory
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: double quotes: No such file or directory
  • 큰 따옴표는 파일 이름에 큰 따옴표가없는 한 작동합니다.

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c 'cat "{}"' \;
    one
    two
    cat: findtest/file with double: No such file or directory
    cat: quotes: No such file or directory
  • 작은 따옴표는 파일 이름에 작은 따옴표가 포함되지 않는 한 작동합니다.

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c "cat '{}'" \;
    one
    cat: findtest/file with single: No such file or directory
    cat: quotes: No such file or directory
    three

모든 경우에 작동하는 솔루션을 찾지 못했습니다. 내가 간과하거나 본질적으로 안전하지 않은 것을 사용 sh -c하고 find -exec있습니까?



답변

{}쉘 코드에 포함시키지 마십시오 ! 명령 주입 취약점이 발생합니다. 주를 위해 것을 cat "{}"그것의의에 대해서뿐만 아니라 "문자, \, `, $또한 문제가 있습니다 (예를 들어라는 파일을 고려 ./$(reboot)/accept_ra).

(그런데, 일부 find구현에서는 그렇게 할 수 없으며 POSIX{} 는에 대한 인수에서 자체가 아닌 경우 동작을 지정 하지 않은 채로 둡니다find )

여기에서 파일 이름을 별도의 인수로 sh( 코드 인수가 아닌 ) 및 sh인라인 스크립트 ( 코드 인수)로 전달하여 위치 매개 변수를 사용하여 파일 이름 을 참조하려고합니다.

find . -name accept_ra -exec sh -c 'echo 0 > "$1"' sh {} \;

또는 sh파일 당 하나를 실행하지 않으려면 다음을 수행 하십시오.

find . -name accept_ra -exec sh -c 'for file do
  echo 0 > "$file"; done' sh {} +

동일 적용 xargs -I{}또는 zshzargs -I{}. 쓰지 마십시오 :

<list.txt xargs -I {} sh -c 'cmd> {}'

find위와 같은 방법으로 명령 주입 취약점이 될 수 있지만,

<list.txt xargs sh -c 'for file do cmd > "$file"; done' sh

또한 sh파일 당 하나를 실행 list.txt하지 않고 파일이 포함되지 않은 경우 오류 를 피할 수 있다는 이점이 있습니다.

함께 zshS ‘ zargs, 당신은 아마 호출보다는 기능을 사용하고자하는 것입니다 sh -c:

do-it() cmd > $1
zargs ./*.txt -- do-it

위의 모든 예제에서 위의 두 번째 예제 sh는 인라인 스크립트로 이동합니다 $0. 당신이 관련 일을 (같이 사용해야 sh또는 find-sh)가 아닌 상황이 좋아 _, -, --, 또는 빈 문자열 값으로 $0쉘의 오류 메시지에 사용됩니다 :

$ find . -name accept_ra -exec sh -c 'echo 0 > "$1"' inline-sh {} \;
inline-sh: ./accept_ra: Permission denied

GNU parallel는 다르게 작동합니다. 그것으로, 당신은 이미 쉘을 실행하는 것처럼 사용하고 싶지 않으며 에 대한 올바른 구문에서 인용 된 인수 로 대체하려고합니다 .sh -cparallel{}

<list.txt PARALLEL_SHELL=sh parallel 'cmd > {}'


답변