문자열 변수로 쉘 명령 보호


9

프로그래밍 언어 내에서 간단한 쉘 명령을 실행합니다.

cd var; echo > create_a_file_here

var에 내가 파일 "create_a_file_here"을 만들려는 장소 (희망) 디렉토리의 문자열을 포함하는 변수 인. 이제 누군가가이 코드 라인을 보게되면, 예를 들어 다음과 같이 할당하여 코드를 이용할 수 있습니다.

var = "; rm -rf /"

상황이 꽤 추악해질 수 있습니다. 위의 경우를 피하는 한 가지 방법은 var 에서 문자열을 검색하여 ';'와 같은 특수 문자 를 찾는 것입니다 . 셸 명령을 실행하기 전에 가능한 모든 악용 가능성이 의심 스럽습니다.

"cd var"가 디렉토리 만 변경하고 다른 것은 변경하지 않는 좋은 방법을 아는 사람이 있습니까?


4
쉘을 호출하는 방법에 따라 var인수로 전달할 수도 있습니다 . 예는 호출 sh인수 -c, 'cd "$1"; echo > create_a_file_here', 'sh', var작품에 대한 변경이 필요하지 않습니다 var. 'sh'인수로 전달됩니다 $0.
ipsec

1
어떤 프로그래밍 언어? POSIX를 사용 sh하거나 비슷한 구문으로 고유 한 프로그래밍 언어를 작성하고 있지만 작성하는 var대신 확장 cd "$var"하는가? 아니면 이것 bash과 함께 shopt -s cdable_vars입니까? 오, 다른 프로그램에서이 명령을 실행하기 위해 쉘을 포크한다는 것을 의미한다고 생각합니다. 따라서 인용 만하십시오 var. 그러나 인용 부호 자체를 포함하지 않아야합니다.
Peter Cordes

@PeterCordes Bash에 대해 이야기하고 있다면 큰 따옴표를 포함하는 큰 따옴표로 묶인 변수가 좋습니다. 예 s='"'; echo "$s"를 인쇄합니다 ".
wjandrea

@WJAndrea : 예, 그러나 신뢰할 수없는 입력에서 변수 할당을 구성 할 때 이길 수없는 "트럼프 카드"따옴표는 없습니다. 오, 해결책 : var=untrusted string부모 프로그램에서하십시오. 따라서 var호출 할 때 이미 설정된 환경 변수입니다 sh. 그런 다음 확장 할 때마다 인용하면됩니다. 확실히 할 수 있습니다. 아, 나는 그 아이디어가 이미 스테판의 답변의 일부인 것을 본다>. <
Peter Cordes

답변:


9

내가 올바르게 이해하면 var프로그래밍 언어의 변수입니다.

그리고 프로그래밍 언어에서,을 연결하는 문자열 "cd ", 변수의 내용 및 을 해석하도록 쉘에 요청합니다 "; echo > create_a_file_here".

그렇다면 내용이 var엄격하게 통제되지 않으면 명령 삽입 취약점입니다.

쉘 구문에서 변수 ¹의 내용을 올바르게 인용하면 cd내장에 단일 인수로 전달되도록 보장 할 수 있습니다 .

다른 방법은 해당 변수의 내용을 다른 방식으로 전달하는 것입니다. 확실한 방법은 환경 변수에서 전달하는 것입니다. 예를 들어, C에서 :

char *var =  "; rm -rf /";
setenv("DIR", var, 1);
system("CDPATH= cd -P -- \"$DIR\" && echo something > create_a_file_here");

이번에는 셸이 해석하도록 요청하는 코드가 수정되었으므로 여전히 셸의 구문으로 작성해야합니다 (여기서는 POSIX 호환 셸이라고 가정).

  • split + glob를 방지하기 위해 쉘 변수 확장을 인용해야합니다.
  • 당신은 필요 -P에 대한 cd간단한 작업을 수행하는chdir()
  • (또는 일부 쉘에서) 시작하는 데 --문제가 발생하지 않도록 옵션 끝을 표시 해야 합니다.var-+
  • CDPATH환경에있는 경우 빈 문자열로 설정 했습니다.
  • 성공한 echo경우 에만 명령을 실행합니다 cd.

이 하나 남아있는 문제 (적어도) 다음의 경우 var입니다 -, 그것은라는 디렉토리에 chdir와하지 않습니다 -만에 이전 (에 저장된 디렉토리 $OLDPWD)와 OLDPWD=- CDPATH= cd -P -- "$DIR"그것을 해결하려면 보장 할 수 없습니다. 따라서 다음과 같은 것이 필요합니다.

system(
  "case $DIR in\n"
  " (-) CDPATH= cd -P ./-;;\n"
  " (*) CDPATH= cd -P -- \"$DIR\";;\n"
  "esac && ....");

¹ 단지를 수행하는 것을 주 system(concat("cd \"", var, "\"; echo..."));입니다 하지 갈 수있는 방법은, 당신은 단지 문제를 이동하는 것.

예를 들어, var = "$(rm -rf /)"여전히 문제가 될 수 있습니다.

만을 위한 인용 텍스트 신뢰할 수있는 방법 본쉘 작은 따옴표를 사용하는 것입니다 문자열에 발생할 수있는 작은 따옴표를 돌봐도. 예를 들어, a char *var = "ab'cd"를로 설정하십시오 char *escaped_var = "'ab'\\''cd'". 즉, 모두 '를 바꾸고 '\''안에있는 모든 것을 감싸십시오 '...'.

즉, 여전히 인용 문자열이 역 따옴표 내에서 사용되지 않는 것으로 간주하고 여전히 필요한 것 --, -P, &&, CDPATH=...


12

간단한 해결책 : 프로그램에서 쉘을 호출하지 마십시오. 조금도.

이 예제는 사소한 것이며 디렉토리를 변경하고 파일을 작성하는 것은 프로그래밍 언어에 관계없이 쉽습니다. 그러나 외부 명령을 실행해야하더라도 일반적으로 셸을 통해 수행 할 필요는 없습니다.

예를 들어 Python에서는을 실행하는 대신을 os.system("somecmd " + somearg)사용하십시오 subprocess.run(["somecmd", somearg]). 에서 C 대신 system()사용 fork()exec()(또는 그것을 수행하는 라이브러리를 찾을 수).

쉘을 사용해야 할 경우, 스테판의 답변 에서처럼 명령 행 인수를 인용하거나 환경을 통해 전달하십시오 . 또한 특수 문자에 대해 걱정하는 경우 올바른 해결책은 잠재적으로 위험한 문자를 걸러 내지 않고 (블랙리스트) 안전한 것으로 알려진 문자 만 유지 하는 것입니다 (허용 목록).

기능을 알고있는 캐릭터 만 허용하면 무언가를 놓칠 위험이 줄어 듭니다. 최종 결과는 허용하기로 결정 [a-zA-Z0-9_]했지만 작업을 완료하기에 충분할 수 있습니다. 당신은 또한 당신의 로케일 확인하고 같은 악센트 문자를 포함하지 않는 도구 모음 할 수 있습니다 äö그의를. 그것들은 아마도 어떤 쉘에서도 특별한 것으로 간주되지는 않지만 다시 통과하는지 여부를 확인하는 것이 좋습니다.


1
그리고 일치하는 데 사용하는 [a-zA-Z0-9]것이 로케일의 à일부 쉘 (예 :)에 의해 인코딩이 잘못 해석 될 수있는 것을 포함하지 않아야 bash합니다.
Stéphane Chazelas

@ StéphaneChazelas (관심없는) : 그것들은 (그리고 그 영향을받는 지역들 아래에 있습니까?)
Wilf

10

프로그래밍 언어에는 쉘 명령을 실행하는 것보다 더 나은 방법이 있습니다. 예를 들어, 교체 cd var의 프로그래밍 언어의 해당과 chdir (var);의 값을 어떤 속임수 있는지 확인해야합니다 varA의 결과 만 오류가 아니라 의도하지 않은 악의적 인 행동을 "디렉토리가 없습니다 발견".

또한 디렉토리를 변경하지 않고 절대 경로를 사용할 수 있습니다. 사용하려는 디렉토리 이름, 슬래시 및 파일 이름을 연결하십시오.

C에서는 다음과 같이 할 수 있습니다.

char filepath[PATH_MAX];  /* alternative constant: MAXPATHLEN */

/* Join directory name in var and the filename, guarding against exceeding PATH_MAX */
snprintf (filepath, PATH_MAX, "%s/%s", var, "create_a_file_here");

/* create an empty file/truncate an existing one */
fclose (fopen (filepath, "w") );

분명히 프로그래밍 언어가 비슷한 것을 할 수 있습니까?


귀하의 답변에 감사드립니다, 그러나 불행히도 나는 bash 명령으로 해결 방법을 사용해야합니다. muru가 제안한대로 변수를 인용하여 테스트했으며 작동하는 것 같습니다!
ES___
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.