2012-03-03 5 views
3

경쟁 조건의 셸 (또는 bash) 명령 목록은 얼마나 안전합니까? 셸 명령 목록의 경쟁 조건

if [ -h "$dir" ]; then 
    echo 'Directory exists and is a symlink' 
    exit 1 
fi 
cd "$dir" 

위의 코드

조건을 경주 분명히 경향이있다 : 공격자가 확인 후 심볼릭 링크를 생성하지만, 여전히 그것으로 디렉토리를 변경하기 전에 할 수 있습니다.

동일한 내용이 || 명령 목록에도 적용됩니까? 다른 말로하면 : 아래의 명령은 경쟁 조건에 영향을받지 않습니까? 아니면 위의 규칙과 동일한 규칙이 적용됩니까? 오류 메시지와 함께

[ -h "$dir" ] || cd "$dir" 

: 동일한 경쟁 조건에 취약되지 않을 것 ||를 사용하는 이유

[ -h "$dir" ] 
    && { echo 'Directory exists and is a symlink'; exit 1; } 
    || cd "$dir" 
+0

공격자가 심볼릭 링크로 기존 디렉토리를 바꾸거나 심볼릭 링크를 만들거나 두 가지 모두를 할 우려가 있습니까? –

+0

-h와 관련된 테스트 맨 페이지에서 :이 연산자는이 프로그램의 이전 버전과의 호환성을 위해 유지됩니다. 그 존재에 의지하지 마라. 대신 -L을 사용하십시오. –

+0

@WilliamPursell : 흥미 롭습니다 ... sh (1)의 맨 페이지가 정확히 반대라고 말합니다 :»-L file 파일이 존재하고 심볼릭 링크 인 경우 True입니다. 이 연산자는이 프로그램의 이전 버전과의 호환성을 위해 유지됩니다. 그 존재에 의지하지 마라. 대신에 -h를 사용하십시오.«man bash (1)는 둘 사이의 차이점을 언급하지 않습니다. – knittl

답변

0

나는 이유를 볼 수 없습니다. 이 취약하지에 대한 사실, 그것은 사용하여 구현 될 필요가 하나

  • 원자 합계 앤 CHDIR 파일 시스템 작업의 일종 (나는 확신 존재하지 않음), 또는

  • cd 뒤에 어떤 종류의 이중 검사를해도 디렉토리가 이전과 동일한 위치를 가리키는 지 확인해야합니다.

나는 bash 전문가가 아니지만 나는 이들 중 어느 것도 확실하지 않습니다.

+0

이중 검사는 좋은 생각처럼 들리며 아마도 유일한 안전한 방법 일 것입니다. – knittl

+2

나는 그것이 갈 길이라고 생각합니다. 그러나 원래 디렉토리 경로가 여전히 같은 위치로 확인되는지는 충분하지 않습니다. 누군가가 변경했을 수 있습니다. 대신 실제로 변경 한 디렉토리를'stat'해야하고 원래 디렉토리와 동일한 디렉토리인지 확인해야합니다. –

+1

내가 올바른 방법으로 할 수있게 해주셔서 감사합니다. 나는 이미 inode를 비교하고있다 :'stat -c % i dir && cd dir && stat -c % i '.' 둘 다 inode 비교. &. 다른 경합 조건을 도입하지 않고도 경로가 동일한 디렉토리로 확인되는지 어떻게 확인할 지 모르겠다;) – knittl

3

위의 내용은 훌륭한 교육적 질문이지만, 실제로는 잘못된 문제를 해결하고 있습니다. 리눅스 보안 모델은 동시성 문제를 스크립팅하는 것에 대한 걱정보다 파일 시스템 권한에 의존합니다.

공격자가 실행중인 프로그램 아래에서 작업 환경을 변경할 우려가있는 경우 환경을 보호해야합니다. 실행중인 스크립트와 바이너리에 대한 쓰기 권한 만 있고 파일 및 오직 당신이 쓸 수있는 위치에있는 디렉토리.

이진 실행 파일의 경우 일반 사용자가 상승 된 권한으로 실행할 수 있지만이 방식으로 실행되는 프로세스는 신중하게 디버깅하고 보안 문제를 검사해야한다는 경고가 표시됩니다 (setuid 비트 사용). 그러나 대부분의 리눅스 배포판에서는 이러한 방식으로 스크립트를 실행할 수 없습니다.

귀하의 (또는 루트) 암호를 얻은 공격자가이 보안 조치 및 다른 보안 조치를 쉽게 물리 칠 수는 있지만 그 경우에는 더 큰 문제가 있음을 언급 할 필요가 있습니다. :-)

행운을 빌어 요!

+0

답변 해 주셔서 감사합니다. 문제의 스크립트는 setuid로 실행되며 첫 번째 인수로 디렉토리가 전달되어'cd'로 들어가고'chmod' +'chown' 작업을 수행합니다. (그리고 나는 누군가에게 그가 허용되지 않는 파일에 대해 그 작업을 수행하기를 원하지 않는다.) – knittl

+1

아마 다른 프로그래밍 언어를 사용하는 것이 나을 것이다. –

+0

대신 chown 명령에 특별한 것이 있습니다. 모든 변경 사항이 제한된 수의 Unix 사용자 사이에 있고 제한된 (가능하지 않은) 사용자 세트에 의해 발행 된 경우 setuid 쉘 스크립트를 사용하는 것을 피할 수 있습니다. 대신 스크립트에서'chown'을'sudo chown'으로 변경하십시오. –

3

심볼 링크를 따르지 않고 디렉토리를 변경하는 데는 두 가지 보안 방법과 비교적 이식성이 있습니다. 쉘 스크립트에서도 쉽게 사용할 수 없습니다.

"foo"에 안전하게 chdir하려고 시도한다고 가정합니다. 첫 번째 방법은 현재 디렉토리를 open(".", O_RDONLY), lstat() "foo"디렉토리와 함께 열린 파일 설명자에 저장하고 그 결과로 st_devst_ino 값을 기록하고 chdir ("foo")를 호출 한 다음 stat() "."를 호출하는 것입니다. 결과 값인 st_devst_ino 값을 비교하십시오. 그들이 같으면 경주에서 승리했습니다.그렇지 않다면 저장된 fd를 사용하여 fchdir()이라는 오류 메시지를 내 보낸 다음 중단하거나 다시 시도하십시오.

덜 휴대용 방식으로 fd = open("foo", O_RDONLY|O_NOFOLLOW) 다음에 fchdir(fd)을 사용하는 것입니다. open 대신 여기 openat을 사용할 수도 있습니다. 이식성 문제는 모든 시스템에 O_NOFOLLOW이있는 것은 아니며 일부 구형 커널은 해당 플래그를 올바르게 해석하지 못하기 때문입니다 (보안 문제이므로이를 무시합니다).

자세한 내용은 GNU find의 소스 코드를 참조하십시오.이 소스 코드에서 위에 설명 된 것과 매우 유사한 방법을 사용하여 이런 종류의 문제를 피할 수 있습니다. 쉘 스크립트에서이 문제를 해결하기위한로

: 시스템이 펄과 같은 stat(1) 명령이나 무언가가

경우, 통계 작업을 수행하는 사람들을 사용할 수 있습니다; 결과를 쉘 변수에 기록 할 수 있습니다. 즉, 회복을 위해 fchdir을 사용해야하는 경우를 제외하고 쉘 스크립트에서 첫 번째 방법을 더 많거나 적게 구현할 수 있습니다. 쉘 스크립트가 레이스를 잃었을 때 즉시 중단하는 것이 좋으면, 쉘에서 사용할 첫 번째 방법을 확실히 채택 할 수 있습니다. 그러나 결국 셸에서 보안 코드를 작성하는 것은 매우 어렵습니다.

+0

이 답변을 주셔서 감사합니다. 나는 (이미'stat'을 사용하고있다.) (http://stackoverflow.com/a/9549413/112968#comment-12103060) 디렉토리로 변경 한 후에 inode를 비교한다. – knittl

0

일반적으로 쉘 스크립트에서 경쟁 조건을 피할 수는 없습니다. C를 사용해야하고 openat, fchdir 등과 같은 TOCTTOU 안전 인터페이스를 사용해야합니다. TOCTTOU (인종) 취약점을 피하는 것은 중요하지 않으므로주의 깊게 학습해야합니다.