$ myvar="/path to/my directory"
$ sudo bash -c "cd $myvar"
이 경우 $myvar
값의 공백으로 인해 단어 분할을 피하기 위해 어떻게 인용 할 수 myvar
있습니까?
sudo bash -c
의 변수 확장은 공백을 포함 할 수있는 경로명
$ myvar="/path to/my directory"
$ sudo bash -c "cd $myvar"
이 경우 $myvar
값의 공백으로 인해 단어 분할을 피하기 위해 어떻게 인용 할 수 myvar
있습니까?
sudo bash -c
의 변수 확장은 공백을 포함 할 수있는 경로명
답변:
더 없습니다 단어 분할 이 코드에서와 같이 (인용 부호로 둘러싸이지 않은 확장에 따라 분할 변수가있는 기능에서와 같이) $myvar
인용 부호로 둘러싸이지 않은되지는.
그러나 $myvar
에 전달되기 전에 확장 된 명령 삽입 취약점 이 bash
있습니다. 내용은 bash 코드로 해석됩니다!
공백이 있으면 단어 분리cd
때문이 아니라 셸 구문에서 여러 토큰으로 구문 분석되기 때문에 여러 인수가로 전달됩니다 . 값이 이면 재부팅됩니다! ¹bye;reboot
여기, 당신은 원할 것입니다 :
sudo bash -c 'cd -P -- "$1"' bash "$myvar"
(당신의 내용을 전달할 곳 $myvar
이 인라인 스크립트의 첫 번째 인수로를, 메모를하는 방법 모두 $myvar
와 $1
방지 IFS-워드 분할 (과) 글 로빙에 대한 각각의 쉘 인용했다).
또는:
sudo MYVAR="$myvar" bash -c 'cd -P -- "$MYVAR"'
( $myvar
환경 변수 의 내용을 전달하는 곳 ).
물론 당신은 실행하여 유용 아무것도 달성하지 않습니다 만 cd
(여부를 확인 이외의 그 인라인 스크립트에서 root
캔 cd
거기에를). 아마도, 당신은 그 스크립트를 cd
거기에두고 싶어 하고 다음과 같은 다른 것을 할 것입니다 :
sudo bash -c 'cd -P -- "$1" && do-something' bash "$myvar"
의도는 사용 인 경우 sudo
에 할 수 있도록 cd
당신이 그렇지 않으면 다음, 그 수없는 정말 작업에 대한 액세스 권한이없는 디렉토리에.
sudo sh -c 'cd -P -- "$1" && exec bash' sh "$myvar"
bash
의 현재 디렉토리와 대화식 으로 시작 됩니다 $myvar
. 그러나 해당 쉘은로 실행됩니다 root
.
당신은 할 수 있습니다 :
sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash
현재 디렉토리와의 특권이없는 대화식을 얻으려면 , 처음에 해당 디렉토리에 대한 $myvar
권한 cd
이없는 경우, 현재 작업 디렉토리 인 경우에도 해당 디렉토리에서 아무 것도 수행 할 수 없습니다.
$ myvar=/var/spool/cron/crontabs
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ ls
ls: cannot open directory '.': Permission denied
디렉토리 자체에 대한 검색 권한이 있지만 경로의 디렉토리 구성 요소 중 하나에 대한 검색 권한 이없는 경우는 예외입니다 .
$ myvar=1/2
$ mkdir -p "$myvar"
$ chmod 0 1
$ cd 1/2
cd: permission denied: 1/2
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ pwd
/home/stephane/1/2
bash-4.4$ mkdir 3
bash-4.4$ ls
3
bash-4.4$ cd "$PWD"
bash: cd: /home/stephane/1/2: Permission denied
¹ 엄밀히 말하면, (문자 그대로) $myvar
와 같은 값의 $(seq 10)
경우, bash
쉘로 시작된 명령 대체의 확장에 따라 단어 분리가 시작됩니다.root
의 내용을 신뢰할 수없는 경우 $myvar
GNU printf
를 사용하여 이스케이프 된 버전을 만드는 것이 합리적 입니다.
#!/bin/bash
myvar=$(printf '%q' "$myvar")
bash -c "echo $myvar"
현상태대로 printf
man 페이지는 말한다 :
%q
ARGUMENT는 제안 된 POSIX
$''
구문 으로 인쇄 할 수없는 문자를 이스케이프하여 쉘 입력으로 재사용 할 수있는 형식으로 인쇄됩니다 .
printf
는 GNU 시스템에서만 호출되며 내장 시스템 이 아닌 $(printf '%q' "$myvar")
쉘에서 실행될 경우에만 호출됩니다 printf
. printf
오늘날 대부분의 껍질은 내장되어 있습니다. 모든 것을 지원하는 %q
것은 아니며, 지원할 때 해당 쉘에서 지원하는 형식으로 항목을 인용 할 수 있습니다 bash
. 사실 bash
'들 printf
도 자체의 일부 값에 대한 제대로 일을 인용하지 못한 $myvar
일부 로케일한다.
bash-4.3
적어도, 그 명령 주입 취약점에 여전히 myvar=$'\xa3``reboot`\xa3`'
zh_HK.big5hkscs가 예를 들어 로케일에.
우선, 다른 사람들이 지적했듯이 cd
명령은 즉시 종료되는 쉘의 컨텍스트에서 발생하기 때문에 쓸모가 없습니다. 그러나 일반적으로 문제는 의미가 있습니다. 필요한 것은 임의의 문자열 을 쉘 인용하여 쉘 인용 문자열 로 해석되는 컨텍스트에서 사용할 수있는 방법입니다. 내 속임수 페이지 에 이에 대한 예가 있습니다 .
quote () { printf %s\\n "$1" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/" ; }
이 기능으로 다음을 수행 할 수 있습니다.
myvar="/path to/my directory"
sudo bash -c "cd $(quote "$myvar")"
Stéphane Chazelas가 제안하는 것은 확실히 이것을하는 가장 좋은 방법입니다. sed
R ..의 답변과 같이 하위 프로세스 를 사용하는 대신 매개 변수 확장 구문으로 안전하게 인용하는 방법에 대한 답변을 제공합니다 .
myvar='foo \'\''"bar'
quote() {
printf "'%s'" "${1//\'/\'\\\'\'}"
}
printf "value: %s\n" "$myvar"
printf "quoted: %s\n" "$(quote "$myvar")"
bash -c "printf 'interpolated in subshell script: %s\n' $(quote "$myvar")"
해당 스크립트의 출력은 다음과 같습니다.
value: foo \'"bar
quoted: 'foo \'\''"bar'
interpolated in subshell script: foo \'"bar
예, 단어 분리가 있습니다.
글쎄, 기술적으로, 명령 줄은 bash를 파싱 할 때 분할됩니다.
먼저 올바른 인용문을 보자.
내가 원하는대로 명령이 작동하도록하는 가장 단순하고 안전하지 않은 솔루션은 다음과 같습니다.
bash -c "cd \"$myvar\""
무슨 일이 일어 났는지 확인합시다 (가정 myvar="/path to/my directory"
) :
$ bash -c "printf '<%s>\n' $myvar"
<./path>
<to/my>
<directory>
보시다시피, 경로 문자열은 공백으로 분할되었습니다. 과:
$ bash -c "printf '<%s>\n' \"$myvar\""
<./path to/my directory>
분할되지 않습니다.
그러나 작성된 명령은 안전하지 않습니다. 더 나은 사용 :
$ bash -c "cd -P -- \"$myvar\"; pwd"
/home/user/temp/path to/my directory
이렇게하면 대시 (-)로 시작하거나 문제를 일으킬 수있는 링크로 시작하는 파일로부터 CD를 보호합니다.
문자열 $myvar
이 경로 라는 것을 신뢰할 수 있으면 작동합니다 .
그러나 "문자열 실행"으로 "코드 삽입"은 여전히 가능합니다.
$ myvar='./path to/my directory";date;"true'
$ bash -c "printf '<%s> ' \"$myvar\"; echo"
<./path to/my directory> Tue May 8 12:25:51 UTC 2018
다음과 같이 더 강력한 문자열 인용이 필요합니다.
$ bash -c 'printf "<%s> " "$1"; echo' _ "$myvar"
<./path to/my directory";date -u;"true>
위에서 볼 수 있듯이 값은 해석되지 않고로 사용되었습니다 "$1'
.
이제 sudo를 (안전하게) 사용할 수 있습니다 :
$ sudo bash -c 'cd -P -- "$1"; pwd' _ "$myvar"
_: line 0: cd: ./path to/my directory";date -u;"true: No such file or directory
인수가 여러 개인 경우 다음을 사용할 수 있습니다.
$ sudo bash -c 'printf "<%s>" "$@"' _ "$val1" "$val2" "$val3"
작은 따옴표는 여기에서 작동하지 않으므로 변수가 확장되지 않습니다. 경로 변수가 삭제되었다고 확신하는 경우 가장 간단한 해결책은 새 bash 쉘에 있으면 결과 확장 주위에 따옴표를 추가하는 것입니다.
sudo bash -c "cd \"$myvar\""
$myvar
같은 $(reboot)
또는"; reboot; #
sudo bash -c "cd -P -- '$myvar'"
하면 문제를 해결하기 $myvar
쉬운 작은 따옴표 문자가 포함 된 값으로 만 문제가 제한됩니다 .
cd
단지 내부에 효과가bash -c
쉘을.