"인수를 명령으로 해석하는 명령에 신뢰할 수 없는 데이터를 전달하는 명령을 실행하십시오."

"인수를 명령으로 해석하는 명령에 신뢰할 수 없는 데이터를 전달하는 명령을 실행하십시오."

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

이 접근 방식은 모든 문제를 방지한다고 보장할 수는 없지만 공격자가 선택한 데이터를 셸 명령 텍스트로 바꾸는 것보다 훨씬 안전합니다.

  1. find -exec sh -c "something {}" \;대체 항목이 {}인용되지 않아 단일 문자열로 처리되지 않는 것이 문제의 원인입니까 ?
  2. 솔루션 find -exec sh -c 'something "$@"' sh {} \;에서는

    • 가 먼저 {}교체되었지만 {}인용되지 않았기 때문에 "$@"원래 명령과 동일한 문제가 있습니까? 예를 들어, 이는 , 및 ? "$@"로 확장됩니다 ."/tmp/foo;""rm""-rf""$HOME"

    • {}탈출하거나 인용하지 않습니까?

  3. 동일한 유형의 문제 및 솔루션( 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 $HOMEshsh-csomething foo; rm -rf $HOME

  • sh-c이제 결과가 구문 분석된 것을 볼 수 있습니다 something foo; rm -rf $HOME(옵션이 아닌 첫 번째 매개변수) 결과를 실행합니다.

이제 더 안전한 변형을 고려해보세요.

find -exec sh -c 'something "$@"' sh {} \;
  • 쉘은 , , , , , , find매개변수로 실행됩니다 .find-execsh-csomething "$@"sh{};

  • 이제 find발견 되면 foo; rm -rf $HOME다시 대체되고 {}매개변수 , , 로 실행됩니다.shsh-csomething "$@"shfoo; 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는 실행될 명령으로 간주되지 않을 수 있으므로 문제가 되지 않습니다.$HOMEsomethingsomething


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. 다른 예를 들어주실 수 있나요?

일종의 코드 (*) 로 처리되는 문자열에서 파일 이름을 있는 그대로(또는 제어되지 않은 다른 문자열) 확장 할 때마다 임의의 명령을 실행할 수 있습니다.

예를 들어, 이는 $fPerl 코드를 직접 확장하므로 파일 이름에 큰따옴표가 포함된 경우 문제가 발생할 수 있습니다. 파일 이름의 따옴표는 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

관련 정보