쓰기 금지된 스크립트의 $0(0번째 인수)를 쓰기 액세스 권한이 없는 경로로 위조하려면 어떻게 해야 합니까?

쓰기 금지된 스크립트의 $0(0번째 인수)를 쓰기 액세스 권한이 없는 경로로 위조하려면 어떻게 해야 합니까?

스크립트에서 $0에 의존하는 것은 위험하다고 합니다(종종 가짜로 인용되는 경우: exec -a ...). 예, 쓰기 권한이 있는 디렉토리에서 $0를 위조하기 위해 스크립트에 심볼릭 링크를 걸 수 있습니다. 하지만 쓰기 권한이 없는 경로(예: 아래 /bin/pwd)를 $0으로 지정하려면 어떻게 해야 합니까?

아래에서 내 스크립트가 shebang을 사용한다고 가정하면 구현할 수 없습니다. 대상 스크립트가 shebang을 사용할 때 수행될 수 있습니까?

$ (exec -a /bin/pwd /tmp/a0.sh)
no-shebang: argv0=/bin/pwd /proc/.../cmdline=/bin/bash^@--noediting^@-i^@

$ (exec -a /bin/pwd /tmp/a1.sh)
yes-shebang: argv0=/tmp/a1.sh /proc/.../cmdline=/bin/sh^@/tmp/a1.sh^@

$ head /tmp/a0.sh /tmp/a1.sh
==> /tmp/a0.sh <==
echo no-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)

==> /tmp/a1.sh <==
#!/bin/sh
echo yes-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)

즉, 스크립트(및 해당 상위 디렉터리)가 쓰기 금지되어 있고 shebang을 사용하는 경우 다른 쓰기 금지 경로를 위조하지 않고 $0를 사용하는 것이 안전한가요?

이것은 $0의 간단한 위조로 bash의 exec 문(centos 7에서)을 사용합니다. execve()를 사용하는 C 프로그램은 다르지 않을까요? bash의 exec가 너무 약한 것이 아니라 execve() (커널 또는 shebang-target에서)의 다운스트림을 가짜로 만드는 것이 실패입니까?

편집: C의 execve()도 shebang의 경우 $0를 위조하지 않으며 출력은 위와 동일합니다.

#include <stdio.h>
int main(void) {
  char* argv[] = { "/bin/pwd", NULL };
  execve("/tmp/a1.sh", argv, NULL);
  perror(NULL);
}

사용자에게 루트 액세스 권한이 있으면 가짜 $0이 문제가 되지 않는다는 것을 알고 있습니다. 그러나 내 쓰기 금지 스크립트(shebang 사용)는 루트가 아닌 사용자가 $0(다른 쓰기 금지 경로)를 위조하는 데 사용할 수 없습니다. $0의 위험("그냥 exec -a..."를 사용)은 잘못된 것 같습니다. .

답변1

훌륭한,매뉴얼 execve(2)페이지설명하다:

통역사 스크립트

인터프리터 스크립트는 실행 권한이 활성화된 텍스트 파일이며 첫 번째 줄의 형식은 다음과 같습니다.

#!interpreter [optional-arg]

인터프리터는 실행 파일에 대한 유효한 경로 이름이어야 합니다.

execve()에 대한 경로 이름 인수가 인터프리터
스크립트를 지정하는 경우
인터프리터는 다음 인수를 사용하여 호출됩니다.

interpreter [optional-arg] pathname arg...

그래서 를 실행하면 exec -a /bin/pwd /tmp/a1.sh시스템이 실행되고 /bin/sh /tmp/a1.sh, 이렇게 실행하면 $0스크립트 파일 이름을 기준으로 쉘이 설정됩니다.

셸에서 가져온 값은 argv[0]표시되지 않습니다. 예를 들어 에는 exec -a foobar /bin/sh /tmp/a1.sh여전히 표시되며 의 내용으로 판단하면 스크립트를 실행할 때 설정된 값은 어쨌든 손실됩니다 ./tmp/a1.sh$0/proc/.../cmdline

그러나 이것이 스크립트에 표시된 값이 $0위조될 수 없다는 의미는 아닙니다. 사용자는 스크립트에 대한 심볼릭 링크를 생성하고 링크를 통해 이를 호출하거나 다음을 수행할 수 있습니다.

/bin/sh -c ". /tmp/a1.sh" foobar

이는 단순히 소스를 $0로 설정됩니다 .foobar/tmp/a1.sh

관련 정보