"find -exec sh -c"를 사용해도 안전합니까?

"find -exec sh -c"를 사용해도 안전합니까?

나는 일부 파일에서 findto를 사용하려고 시도했지만 echo 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안전하지 않은 것을 사용하고 있는 것이 있습니까?

답변1

{}쉘 코드를 삽입하지 마십시오 ! 이로 인해 명령 주입 취약점이 발생합니다. 의 경우 , 문자에 관한 것 뿐만 아니라 문제 도 cat "{}"있습니다 (예: 이라는 파일을 고려 )."\`$./$(reboot)/accept_ra

(덧붙여서,일부 find구현네가 이런 짓을 하도록 놔두지 않을 거야.POSIX 탈퇴 동작명시되지 않은의 인수에서 {}단독으로 존재하지 않는 경우 )find -exec

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 -l1 ./*.txt -- do-it

zsh에서 루프를 사용할 수도 있지만 for매우 짧을 수 있습니다.

for f (*.txt) cmd > $f

(단, 마지막 실패 이외의 실패는 cmd전체 종료 상태에 보고되지 않습니다.)

위의 모든 예에서 sh위의 두 번째 항목은 인라인 스크립트로 들어갑니다 . 와 같은 항목 이나 빈 문자열이 아닌 관련 항목(예: or ) $0을 사용해야 합니다 . 메시지:shfind-sh_---$0

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

GNU는 parallel다르게 작동합니다. 그것으로 당신은 할 수 있습니다아니요sh -c사용하고 싶다parallel{}이미 쉘을 실행 중이고 쉘의 올바른 구문에 인용된 매개변수를 바꾸려고 합니다..

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

구현에 따라 sh다른 문자의 인코딩에는 이러한 문자의 인코딩이 포함됩니다(실제 및 실제 문자 인코딩에서는 바이트 0x5c 및 0x60으로 제한됨)

관련 정보