쉘 스크립트에 setuid 설정 허용

쉘 스크립트에 setuid 설정 허용

권한 setuid비트는 프로그램을 실행하기 위해 (실행자 대신) 소유자의 유효 사용자 ID를 사용하도록 Linux에 지시합니다.

> cat setuid-test.c

#include <stdio.h>
#include <unistd.h>

int main(int argc, char** argv) {
    printf("%d", geteuid());
    return 0;
}

> gcc -o setuid-test setuid-test.c
> ./setuid-test

1000

> sudo chown nobody ./setuid-test; sudo chmod +s ./setuid-test
> ./setuid-test

65534

그러나 이는 실행 파일에만 작동합니다. 쉘 스크립트는 setuid 비트를 무시합니다.

> cat setuid-test2

#!/bin/bash
id -u

> ./setuid-test2

1000

> sudo chown nobody ./setuid-test2; sudo chmod +s ./setuid-test2
> ./setuid-test2

1000

위키피디아설명하다:

보안 취약성이 증가할 가능성이 높기 때문에 많은 운영 체제에서는 실행 가능한 셸 스크립트에 적용될 때 setuid 속성을 무시합니다.

이러한 위험을 감수할 의향이 있다고 가정할 때, 실행 파일에서와 마찬가지로 쉘 스크립트에서도 setuid 비트를 동일하게 처리하도록 Linux에 지시할 수 있는 방법이 있습니까?

그렇지 않은 경우 이 문제에 대한 일반적인 해결 방법이 있습니까? 현재 해결 방법은 암호 프롬프트를 피하기 위해 특정 스크립트를 실행하려는 사용자로 실행할 sudoers수 있도록 항목을 추가하는 것입니다. 이 방법의 가장 큰 단점은 이 작업을 수행할 때마다 항목을 입력 해야 하며 호출자는 단순히 항목을 입력하는 대신에 항목 을 입력해야 한다는 것입니다.ALLNOPASSWDsudoerssudo some-scriptsome-script

답변1

Linux는 해석된 모든 실행 파일(즉, line으로 시작하는 실행 파일)에서 setuid1 비트를 무시합니다 #!. 이것comp.unix.questions 자주 묻는 질문setuid 쉘 스크립트의 보안 문제가 설명되었습니다. 이러한 문제는 Shebang 관련 문제와 Shell 관련 문제의 두 가지 종류로 나뉩니다. 아래에서 자세히 설명하겠습니다.

보안에 관심이 없고 Linux에서 setuid 스크립트를 허용하려면 커널을 패치해야 합니다. 3.x 커널부터 시작하면 다음을 추가해야 할 것 같습니다.install_exec_creds내부에load_script함수를 호출하기 전에 테스트 open_exec했지만 아직 테스트하지 않았습니다.


세트이드 셰이본

#!shebang( )의 일반적인 구현에는 고유한 경쟁 조건이 있습니다.

  1. 커널은 실행 파일을 열고 파일이 #!.
  2. 커널은 실행 파일을 닫고 인터프리터를 엽니다.
  3. 커널은 스크립트 경로를 인수 목록(예: argv[1])에 삽입하고 인터프리터를 실행합니다.

이 구현이 setuid 스크립트를 허용하는 경우 공격자는 기존 setuid 스크립트에 대한 기호 링크를 생성하고, 스크립트를 실행하고, 커널이 1단계를 실행한 후 인터프리터가 실행을 시작하기 전에 링크를 변경하도록 조정하여 임의의 스크립트를 호출할 수 있습니다. 첫 번째 인수를 시작합니다. 이런 이유로,대부분의 유닉스는 setuid 비트를 무시합니다.그들이 shebang을 감지했을 때.

이 구현을 안전하게 만드는 한 가지 방법은 인터프리터가 스크립트 파일을 열 때까지 커널이 스크립트 파일을 잠그는 것입니다(이렇게 하면 파일 링크를 해제하거나 덮어쓰는 것뿐만 아니라 경로에 있는 디렉터리의 이름을 바꾸는 것도 방지해야 합니다). 그러나 Unix 시스템은 강제 잠금을 기피하는 경향이 있으며 기호 링크로 인해 적절한 잠금 기능이 특히 어렵고 방해가 될 수 있습니다. 나는 누구도 그렇게 생각하지 않습니다.

일부 Unix 시스템(주로 OpenBSD, NetBSD 및 Mac OS X, 모두 활성화하려면 커널 설정이 필요함)이 구현됩니다.보안 setuid shebang추가 기능 사용: 경로는 파일 설명자에서 이미 열려 있는 파일을 참조합니다./dev/fd/N질소(따라서 오프닝은 거의 동일합니다). 많은 UNIX 시스템(Linux 포함)에는 setuid 스크립트가 있지만 없습니다./dev/fd/Ndup(N)/dev/fd

  1. 커널은 실행 파일을 열고 .로 시작하는 것을 찾습니다 #!. 실행 파일의 파일 설명자가 3이라고 가정합니다.
  2. 커널이 인터프리터를 엽니다.
  3. 커널은 /dev/fd/3인수 목록(예: argv[1])을 삽입하고 인터프리터를 실행합니다.

Sven Mascheck의 shebang 페이지다음을 포함하여 unices의 shebang에 대한 많은 정보가 있습니다.setuid 지원.


Setuid 통역사

sudo운영 체제가 setuid shebang을 지원하거나 기본 바이너리 래퍼(예 : ) 를 사용했기 때문에 프로그램이 루트로 실행되도록 관리했다고 가정합니다 . 보안 허점을 열었나요?아마도. 여기서 문제는아니요통역사와 컴파일러에 대하여. 문제는 당신이런타임 시스템권한을 사용하여 실행하면 동작이 안전합니다.

  • 동적으로 링크된 기본 바이너리 실행 파일은 어떤 방식으로든 생성됩니다.동적 로더(예: /lib/ld.so), 프로그램에 필요한 동적 라이브러리를 로드합니다. 많은 unices에서는 LD_LIBRARY_PATH환경(환경 변수의 일반적인 이름)을 통해 동적 라이브러리에 대한 검색 경로를 구성할 수 있으며 실행된 모든 바이너리( LD_PRELOAD)에 추가 라이브러리를 로드할 수도 있습니다. 프로그램 호출자는 libc.so특별히 제작된 코드(다른 전략 중에서)를 배치하여 해당 프로그램의 컨텍스트 내에서 임의의 코드를 실행할 수 있습니다. $LD_LIBRARY_PATH모든 제정신 시스템은 LD_*실행 파일의 setuid 변수를 무시합니다.

  • 존재하다껍데기예를 들어, sh, csh 및 그 파생물에서 환경 변수는 자동으로 쉘 매개변수가 됩니다. PATH등 의 매개변수를 통해 IFS스크립트 호출자는 쉘 스크립트의 컨텍스트에서 임의의 코드를 실행할 수 있는 많은 기회를 갖습니다. 일부 쉘은 스크립트가 권한으로 호출되었음을 감지하면 이러한 변수를 합리적인 기본값으로 설정하지만, 내가 신뢰하는 특정 구현이 있는지는 모르겠습니다.

  • 대부분의 런타임 환경(네이티브, 바이트코드 또는 해석 여부에 관계없이) 유사한 기능을 갖습니다. 기본 코드를 실행하는 실행 파일은 일반적으로 동적 연결(예방 조치를 취함)보다 더 특이한 작업을 수행하지 않지만 setuid 실행 파일에서 특별한 예방 조치를 취하는 사람은 거의 없습니다.

  • 진주주목할만한 예외입니다. 그것setuid 스크립트에 대한 명시적 지원안전한 방법으로. 실제로 운영 체제가 스크립트의 setuid 비트를 무시하더라도 스크립트는 setuid를 실행할 수 있습니다. 이는 Perl이 필요한 검사를 수행하고 필요한 권한이 있는 필수 스크립트에 대한 인터프리터를 다시 호출하는 setuid 루트 도우미 프로그램과 함께 제공되기 때문입니다. 이것은페르세크수동. 과거에는 #!/usr/bin/suidperl -wT대신 setuid perl 스크립트가 필요했지만 #!/usr/bin/perl -wT대부분의 최신 시스템에서는 #!/usr/bin/perl -wT이것으로 충분합니다.

네이티브 바이너리 사용에 유의하세요.래퍼 자체는 이러한 문제를 방지하기 위해 아무 것도 하지 않습니다.. 실제로 상황을 만들 수도 있다더 나쁜, 이는 런타임 환경이 권한을 가지고 호출되었음을 감지하지 못하게 하고 런타임 구성 기능을 우회할 수 있기 때문입니다.

네이티브 바이너리 래퍼는 래퍼가 다음과 같은 경우 쉘 스크립트를 안전하게 만들 수 있습니다.환경을 정화하세요. 스크립트는 너무 많은 가정(예: 현재 디렉터리에 대한 가정)을 하지 않도록 주의해야 하지만 그게 전부입니다. 환경을 정리하도록 설정된 경우 sudo를 사용하여 이 작업을 수행할 수 있습니다. 변수를 블랙리스트에 추가하면 오류가 발생하기 쉬우므로 항상 화이트리스트에 추가하세요. sudo를 사용하여 env_reset옵션이 켜져 있는지, setenv꺼져 있는지, 무해한 변수 env_file만 포함되어 있는지 확인하세요 .env_keep


TL, 박사:

  • Setuid shebang은 안전하지 않지만 종종 간과됩니다.
  • sudo 또는 setuid를 통해 권한을 사용하여 프로그램을 실행하는 경우 네이티브 코드 또는 Perl을 작성하거나 환경을 정리하는 래퍼(예: 옵션이 포함된 sudo env_reset)를 사용하여 프로그램을 시작하세요.

이 논의는 "setgid"를 "setuid"로 바꾸는 경우에도 적용됩니다.Linux 커널은 스크립트에서 이를 무시합니다.

답변2

이 문제를 해결하는 한 가지 방법은 setuid 비트를 사용할 수 있는 프로그램에서 쉘 스크립트를 호출하는 것입니다.
sudo와 비슷합니다. 예를 들어, C 프로그램에서 이를 수행하는 방법은 다음과 같습니다.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    setuid( 0 );   // you can set it at run time also
    system( "/home/pubuntu/setuid-test2.sh" );
    return 0;
 }

setuid-test2.c로 저장합니다.
이제
프로그램 바이너리에서 setuid를 실행합니다.

su - nobody   
[enter password]  
chown nobody:nobody a.out  
chmod 4755 a.out  

이제 이를 실행할 수 있으며 다른 사람의 허가 없이 스크립트가 실행되는 것을 볼 수 있습니다.
하지만 여기서도 스크립트 경로를 하드코딩하거나 이를 위의 exe에 명령줄 인수로 전달해야 합니다.

답변3

이 선박에 몇 가지 스크립트 접두어를 추가했습니다.

#!/bin/sh
[ "root" != "$USER" ] && exec sudo $0 "$@"

setuid이는 현재 파일을 사용하지 않고 단지 실행한다는 점에 유의하십시오 sudo.

답변4

어떤 이유로든 사용할 수 없는 경우 sudoC로 씬 래퍼 스크립트를 작성할 수 있습니다.

#include <unistd.h>
int main() {
    setuid(0);
    execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}

컴파일 후에 setuidchmod 4511 wrapper_script.

이는 게시된 다른 답변과 유사하지만 깨끗한 환경에서 스크립트를 실행하고 /bin/bash호출되는 대신 명시적으로 셸을 사용하여 system()일부 잠재적인 보안 허점을 제거합니다.

이렇게 하면 환경이 완전히 삭제됩니다. 취약점을 열지 않고 일부 환경 변수를 사용하려면 실제로 sudo.

분명히 스크립트 자체는 루트에서만 쓸 수 있는지 확인하고 싶을 것입니다.

관련 정보