findutils 매뉴얼에서:
예를 들어, 이 두 명령의 구조는 다음과 같습니다.
# risky find -exec sh -c "something {}" \; find -execdir sh -c "something {}" \;
매우 위험한. 그 이유는 "{}"가 세미콜론이나 기타 셸 관련 문자를 포함할 수 있는 파일 이름으로 확장되기 때문입니다. 예를 들어,
/tmp/foo; rm -rf $HOME
위의 두 명령은 누군가가 파일을 생성한 경우 누군가의 홈 디렉토리를 삭제할 수 있습니다.따라서 이러한 이유로 신뢰할 수 없는 데이터(예: 파일 이름)를 추가로 해석되도록 인수를 해석하는 명령에 전달하는 명령(예: "sh")을 실행하지 마십시오.
쉘의 경우 이 문제에 대한 깔끔한 해결 방법이 있습니다.
# safer find -exec sh -c 'something "$@"' sh {} \; find -execdir sh -c 'something "$@"' sh {} \;
이 접근 방식은 모든 문제를 방지한다고 보장할 수는 없지만 공격자가 선택한 데이터를 셸 명령 텍스트로 바꾸는 것보다 훨씬 안전합니다.
find -exec sh -c "something {}" \;
대체 항목이{}
인용되지 않아 단일 문자열로 처리되지 않는 것이 문제의 원인입니까 ?솔루션
find -exec sh -c 'something "$@"' sh {} \;
에서는가 먼저
{}
교체되었지만{}
인용되지 않았기 때문에"$@"
원래 명령과 동일한 문제가 있습니까? 예를 들어, 이는 , 및 ?"$@"
로 확장됩니다 ."/tmp/foo;"
"rm"
"-rf"
"$HOME"
왜
{}
탈출하거나 인용하지 않습니까?
- 동일한 유형의 문제 및 솔루션(
sh -c
해당되는 경우 포함 여부,find
필요하지 않을 수 있음)에 적용되고 최소한의 예인 다른 예를 제공할 수 있습니까? 주의를 산만하게 하는 것이 가능한 한 적은가? 바라보다"bash -c"로 실행되는 명령에 인수를 제공하는 방법
감사해요.
답변1
이는 실제로 참조와 관련이 없으며 매개변수 처리와 관련이 있습니다.
위험한 예를 생각해보십시오.
find -exec sh -c "something {}" \;
이것은 쉘에 의해 구문 분석되고 6개의 단어로 나뉩니다:
find
,-exec
,sh
,-c
,something {}
(더 이상 따옴표 없음),;
. 확장할 내용이 없습니다. 쉘은find
이 6개 단어를 인수로 사용하여 실행됩니다.find
예를 들어 처리할 항목을 찾으면 , 및 인수 로foo; rm -rf $HOME
대체되고 실행 됩니다 .{}
foo; rm -rf $HOME
sh
sh
-c
something foo; rm -rf $HOME
sh
-c
이제 결과가 구문 분석된 것을 볼 수 있습니다something foo; rm -rf $HOME
(옵션이 아닌 첫 번째 매개변수) 결과를 실행합니다.
이제 더 안전한 변형을 고려해보세요.
find -exec sh -c 'something "$@"' sh {} \;
쉘은 , , , , , ,
find
매개변수로 실행됩니다 .find
-exec
sh
-c
something "$@"
sh
{}
;
이제
find
발견 되면foo; rm -rf $HOME
다시 대체되고{}
매개변수 , , 로 실행됩니다.sh
sh
-c
something "$@"
sh
foo; rm -rf $HOME
sh
-c
, 및 를something "$@"
실행할 명령으로 처리 하고sh
및 를foo; rm -rf $HOME
위치 인수로 처리합니다(에서 시작하다$0
),"$@"
다음으로 확장됨foo; rm -rf $HOME
단일 값으로,something
단일 인수로 실행합니다foo; rm -rf $HOME
.
를 사용하여 이를 볼 수 있습니다 printf
. 새 디렉터리를 만들고 입력하고 실행하세요.
touch "hello; echo pwned"
다음과 같이 첫 번째 변형을 실행합니다.
find -exec sh -c "printf \"Argument: %s\n\" {}" \;
생산하다
Argument: .
Argument: ./hello
pwned
두 번째 변형은 다음과 같이 실행됩니다.
find -exec sh -c 'printf "Argument: %s\n" "$@"' sh {} \;
생산하다
Argument: .
Argument: ./hello; echo pwned
답변2
1 부:
find
텍스트 대체를 사용하십시오.
예, 다음과 같이 따옴표를 추가하지 않으면 다음과 같습니다.
find . -type f -exec sh -c "echo {}" \;
; echo owned
공격자 는 다음과 같은 파일을 생성할 수 있습니다.
sh -c "echo ; echo owned"
echo
그러면 쉘이 실행됩니다 echo owned
.
그러나 따옴표를 추가하면 공격자는 따옴표를 끝내고 다음과 같은 파일을 생성하여 그 뒤에 악의적인 명령을 입력할 수 있습니다 '; echo owned
.
find . -type f -exec sh -c "echo '{}'" \;
이로 인해 쉘 이 실행됩니다 echo ''
.echo owned
(큰따옴표를 작은따옴표로 바꾸면 공격자가 다른 유형의 따옴표를 사용할 수도 있습니다.)
2 부:
에서는 find -exec sh -c 'something "$@"' sh {} \;
처음 {}
에 셸에서 해석되지 않고 직접 실행되므로 execve
셸 따옴표를 추가해도 도움이 되지 않습니다.
find -exec sh -c 'something "$@"' sh "{}" \;
쉘이 실행하기 전에 큰따옴표를 제거하기 때문에 아무런 효과가 없습니다 find
.
find -exec sh -c 'something "$@"' sh "'{}'" \;
따옴표 추가는 셸에서 특별히 처리되지 않으므로 대부분의 경우 이는 명령이 원하는 대로 수행되지 않는다는 의미일 뿐입니다.
/tmp/foo;
, rm
, 로 확장하는 것은 의 매개변수이고 해당 인수 -rf
는 실행될 명령으로 간주되지 않을 수 있으므로 문제가 되지 않습니다.$HOME
something
something
3부:
신뢰할 수 없는 입력을 받아들이고 이를 명령(예: 및 의 일부)으로 실행하는 모든 항목에 유사한 고려 사항이 적용된다고 가정 xargs
합니다 parallel
.
답변3
find -exec sh -c "something {}" \;
1. 대체 항목이{}
인용되지 않아 단일 문자열로 처리되지 않는 것이 문제의 원인일 수 있습니까 ?
어떤 의미에서는 그렇지만여기서는 인용문이 도움이 되지 않습니다.. 교체할 파일 이름에는 {}
다음이 포함될 수 있습니다.어느수치,따옴표 포함. 어떤 형식의 인용이 사용되는지에 관계없이 파일 이름에는 동일한 참조가 포함될 수 있으며 참조가 "중단"될 수 있습니다.
2. ...하지만
{}
인용되지 않았기 때문에"$@"
원래 명령과 동일한 문제가 있습니까 ? 예를 들어,"$@"
로 확장될 예정입니까"/tmp/foo;", "rm", "-rf", and "$HOME"
?
아니요. "$@"
별도의 단어로 위치 인수로 확장됩니다.아니요그들은 더 나뉘어져 있습니다. 여기서는 {}
자체에 대한 인수 find
이며 find
현재 파일 이름도 다른 인수로 전달됩니다 sh
. 이는 쉘 명령 자체로 처리되지 않고 쉘 스크립트에서 변수로 직접 사용될 수 있습니다.
...
{}
이스케이프하거나 인용하면 어떨까요?
대부분의 쉘에서는 이것이 필요하지 않습니다. 을 실행하면 빈 줄이 인쇄될 것으로 fish
예상됩니다 . fish -c 'echo {}'
하지만 인용해도 상관없습니다. 쉘은 인용문만 제거합니다.
3. 다른 예를 들어주실 수 있나요?
일종의 코드 (*) 로 처리되는 문자열에서 파일 이름을 있는 그대로(또는 제어되지 않은 다른 문자열) 확장 할 때마다 임의의 명령을 실행할 수 있습니다.
예를 들어, 이는 $f
Perl 코드를 직접 확장하므로 파일 이름에 큰따옴표가 포함된 경우 문제가 발생할 수 있습니다. 파일 이름의 따옴표는 Perl 코드의 따옴표로 끝나고 파일 이름의 나머지 부분에는 Perl 코드가 포함될 수 있습니다.
touch '"; print "HELLO";"'
for f in ./*; do
perl -le "print \"size: \" . -s \"$f\""
done
(Perl은 전체 코드를 실행하기 전에 미리 구문 분석하기 때문에 파일 이름이 약간 이상할 수 있습니다. 따라서 구문 분석 오류를 피해야 합니다.)
매개변수를 통해 안전하게 전달할 수 있지만:
for f in ./*; do
perl -le 'print "size: " . -s $ARGV[0]' "$f"
done
(하나의 쉘을 다른 쉘에서 직접 실행하는 것은 의미가 없지만 그렇게 하면 비슷한 상황이 될 것입니다 find -exec sh ...
)
(* 일부 코드에는 SQL이 포함되어 있으므로 XKCD여야 합니다.https://xkcd.com/327/설명 추가: https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables)
답변4
귀하의 우려는 GNU Parallel이 입력을 인용하는 이유입니다.
touch "hello; echo pwned"
find . -print0 | parallel -0 printf \"Argument: %s\\n\" {}
이 실행되지 않습니다 echo pwned
.
쉘을 실행하므로 명령을 확장해도 갑자기 놀라지 않을 것입니다.
# This _could_ be run without spawining a shell
parallel "grep -E 'a|bc' {}" ::: foo
# This cannot
parallel "grep -E 'a|bc' {} | wc" ::: foo
셸 문제 빌드에 대한 자세한 내용은 다음을 참조하세요.https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell