it-swarm-ko.tech

쉘 스크립트에서 setuid 허용

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

> 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

Wikipedia 말) :

보안 결함 가능성이 높아짐에 따라 많은 운영 체제는 실행 가능한 쉘 스크립트에 적용될 때 setuid 속성을 무시합니다.

내가 이러한 위험을 감수 할 것이라고 가정하면 리눅스가 setuid 비트를 쉘 스크립트에서 실행 파일과 동일하게 취급하도록 지시 할 수 있습니까?

그렇지 않은 경우이 문제에 대한 일반적인 해결 방법이 있습니까? 현재 해결 방법은 sudoers 항목을 추가하여 ALL이 (가) 원하는 스크립트를 NOPASSWD와 함께 실행하여 원하는 스크립트를 실행할 수 있도록 허용하는 것입니다. 이것의 주요 단점은이 작업을 수행 할 때마다 sudoers 항목이 필요하고 발신자가 Sudo some-script 대신 some-script

195
Michael Mrozek

Linux는 해석 된 모든 실행 파일 (예 : #! 행으로 시작하는 실행 파일)에서 setuid¹ 비트를 무시합니다. comp.unix.questions FAQ 는 setuid Shell 스크립트의 보안 문제를 설명합니다. 이러한 문제는 Shebang 관련 및 Shell 관련 두 가지입니다. 자세한 내용은 아래를 참조하십시오.

보안에 신경 쓰지 않고 setuid 스크립트를 허용하려면 Linux에서 커널을 패치해야합니다. 3.x 커널부터는 install_exec_creds 함수에서 load_script 에 대한 호출을 추가해야한다고 생각합니다. open_exec, 테스트하지 않았습니다.


세이트 세방

Shebang (#!)이 일반적으로 구현되는 방식에 고유 한 경쟁 조건이 있습니다.

  1. 커널은 실행 파일을 열고 #!로 시작하는 것을 찾습니다.
  2. 커널은 실행 파일을 닫고 인터프리터를 대신 엽니 다.
  3. 커널은 스크립트에 대한 경로를 인수 목록에 argv[1]로 삽입하고 인터프리터를 실행합니다.

이 구현에서 setuid 스크립트가 허용되는 경우 공격자는 기존 setuid 스크립트에 대한 심볼릭 링크를 생성하고 실행하여 커널이 1 단계를 수행 한 후 및 인터프리터가 도착하기 전에 링크를 변경하여 임의의 스크립트를 호출 할 수 있습니다. 첫 번째 논쟁을여십시오. 이러한 이유로 대부분의 유니 세스는 setbang 비트를 무시합니다는 Shebang을 감지했을 때.

이 구현을 보호하는 한 가지 방법은 커널이 인터프리터가 파일을 열 때까지 스크립트 파일을 잠그는 것입니다 (이것은 파일을 링크 해제하거나 덮어 쓰는 것뿐만 아니라 경로의 디렉토리 이름을 바꾸는 것을 방지해야 함). 그러나 유닉스 시스템은 필수 잠금 장치에서 벗어나는 경향이 있으며 기호 링크는 올바른 잠금 기능을 특히 어렵고 침입 적으로 만듭니다. 나는 아무도 이런 식으로하지 않는다고 생각합니다.

몇 가지 유닉스 시스템 (주로 OpenBSD, NetBSD 및 Mac OS X, 모두 커널 설정을 활성화해야 함)은 추가 기능을 사용하여 secure setuid Shebang을 구현합니다. 경로 /dev/fd/N는 파일 설명자에서 이미 열린 파일 N (따라서 /dev/fd/N를 여는 것은 dup(N)와 거의 같습니다. Linux를 포함한 많은 유닉스 시스템에는 /dev/fd가 있지만 setuid 스크립트는 없습니다.

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

Sven Mascheck의 Shebang 페이지setuid support 를 포함하여 unices에 걸쳐 Shebang에 대한 많은 정보가 있습니다.


Setuid 통역사

OS가 setuid Shebang을 지원하거나 기본 바이너리 래퍼 (예 : Sudo)를 사용했기 때문에 프로그램을 루트로 실행했다고 가정 해 봅시다. 보안 구멍을 열었습니까? 아마도. 여기서 문제는 해석 된 vs 컴파일 된 프로그램에 대한 not입니다. 문제는 권한으로 실행 된 경우 runtime system이 안전하게 동작하는지 여부입니다.

  • 동적으로 연결된 네이티브 이진 실행 파일은 프로그램에 필요한 동적 라이브러리를로드하는 dynamic loader (예 : /lib/ld.so)로 해석됩니다. 많은 유니 세에서 환경을 통해 동적 라이브러리의 검색 경로를 구성하고 (LD_LIBRARY_PATH는 환경 변수의 일반 이름 임) 실행 된 모든 바이너리에 추가 라이브러리를로드 할 수도 있습니다 (LD_PRELOAD). . 프로그램의 호출자는 특수하게 조작 된 libc.so$LD_LIBRARY_PATH (다른 전술 중에서도)에 배치하여 해당 프로그램의 컨텍스트에서 임의의 코드를 실행할 수 있습니다. 모든 제정신 시스템은 setuid 실행 파일의 LD_* 변수를 무시합니다.

  • Sh, csh 및 파생 상품과 같은 shells에서 환경 변수는 자동으로 쉘 매개 변수가됩니다. PATH, IFS 등과 같은 매개 변수를 통해 스크립트 호출자는 쉘 스크립트 컨텍스트에서 임의의 코드를 실행할 수있는 기회가 많습니다. 일부 셸은 스크립트가 권한으로 호출 된 것을 감지하면 이러한 변수를 적절한 기본값으로 설정하지만, 신뢰할만한 특정 구현이 있는지는 알 수 없습니다.

  • 대부분의 런타임 환경 (기본, 바이트 코드 또는 해석 여부)의 기능은 비슷합니다. setuid 실행 파일에서 특별한 예방 조치를 취하는 사람은 거의 없지만 기본 코드를 실행하는 작업은 동적 연결 (예방 조치가 필요함)보다 더 멋진 일을하지 않는 경우가 많습니다.

  • Perl은 예외입니다. 안전한 방법으로 명시 적으로 setuid 스크립트 지원입니다. 실제로, OS에서 스크립트의 setuid 비트를 무시하더라도 스크립트는 setuid를 실행할 수 있습니다. 이는 Perl에 필요한 검사를 수행하고 원하는 권한으로 원하는 스크립트에서 인터프리터를 다시 호출하는 setuid 루트 도우미와 함께 제공되기 때문입니다. 이것은 perlsec 매뉴얼에 설명되어 있습니다. 이전에는 setuid Perl 스크립트가 #!/usr/bin/suidperl -wT 대신 #!/usr/bin/Perl -wT가 필요했지만 대부분의 최신 시스템에서는 #!/usr/bin/Perl -wT로 충분합니다.

기본 이진 래퍼는 이러한 문제를 방지하기 위해 아무 것도 수행하지 않습니다. 실제로 런타임 환경이 특권으로 호출되었음을 감지하고 런타임 구성 기능을 무시하지 못하도록 상황을 worse로 만들 수 있습니다.

래퍼 환경을 삭제합니다 인 경우 기본 바이너리 래퍼를 사용하여 셸 스크립트를 안전하게 만들 수 있습니다. 스크립트는 너무 많은 가정 (예 : 현재 디렉토리에 대한)을하지 않도록주의해야하지만 계속됩니다. 환경을 위생 처리하도록 설정된 경우 Sudo를 사용할 수 있습니다. 블랙리스트 변수는 오류가 발생하기 쉬우므로 항상 화이트리스트에 올리십시오. Sudo를 사용하면 env_reset 옵션이 켜져 있고 setenv이 꺼져 있고 env_fileenv_keep에 무해한 변수 만 포함되어 있는지 확인하십시오.


TL, DR :

  • Setuid Shebang은 안전하지 않지만 일반적으로 무시됩니다.
  • 권한이있는 프로그램 (Sudo 또는 setuid를 통해)을 실행하는 경우 기본 코드 또는 Perl을 작성하거나 환경을 삭제하는 래퍼 (예 : env_reset 옵션을 사용하는 Sudo)로 프로그램을 시작하십시오.

¹ 이 설명은 "setgid"를 "setuid"로 대체하는 경우에도 동일하게 적용됩니다. 스크립트에서 리눅스 커널에 의해 무시됩니다

이 문제를 해결하는 한 가지 방법은 setuid 비트를 사용할 수있는 프로그램에서 Shell 스크립트를 호출하는 것입니다.
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에 명령 줄 arg로 전달해야합니다.

57
Hemant

이 보트에있는 몇 가지 스크립트를 접두어로 사용합니다.

#!/bin/sh
[ "root" != "$USER" ] && exec Sudo $0 "[email protected]"

이것은 setuid를 사용하지 않고 단순히 Sudo로 현재 파일을 실행합니다.

24
rcrowley

Sudo some_script 전화를 피하려면 다음을 수행하십시오.

  #!/ust/bin/env sh

  Sudo /usr/local/scripts/your_script

SETUID 프로그램은 루트 권한으로 실행되며 사용자가 제어 할 수 있으므로 매우주의해서 설계해야합니다. 그들은 모든 것을 온전히 점검해야합니다. 다음과 같은 이유로 스크립트를 사용하여 수행 할 수 없습니다.

  • 쉘은 사용자와 크게 상호 작용하는 큰 소프트웨어입니다. 모든 코드를 검사하는 것은 거의 불가능합니다. 특히 대부분의 코드가 그러한 모드에서 실행되도록 설계되지 않았기 때문입니다.
  • 스크립트는 대부분 빠른 해결책이며 대개 setuid를 허용하도록주의를 기울이지 않습니다. 잠재적으로 위험한 기능이 많이 있습니다.
  • 그들은 다른 프로그램에 크게 의존합니다. 쉘을 점검하는 것만으로는 충분하지 않습니다. sed, awk 등도 확인해야합니다.

Sudo는 건전성 검사를 제공하지만 충분하지는 않습니다. 사용자 코드의 모든 줄을 확인하십시오.

마지막으로, 기능 사용을 고려하십시오. 일반적으로 루트 권한이 필요한 특수 권한을 사용자로 실행하는 프로세스를 제공 할 수 있습니다. 그러나 예를 들어, ping는 네트워크를 조작해야하지만 파일에 액세스 할 필요는 없습니다. 그러나 그들이 상속되는지 확실하지 않습니다.

12
Maciej Piechotka

super [-r reqpath] 명령 [args]

Super는 지정된 사용자가 마치 루트 인 것처럼 스크립트 (또는 다른 명령)를 실행할 수 있도록합니다. 또는 명령을 실행하기 전에 명령별로 uid, gid 및/또는 보충 그룹을 설정할 수 있습니다. 스크립트를 setuid 루트로 만드는 대신 안전한 대안이 될 것입니다. Super는 또한 일반 사용자가 다른 사용자가 실행할 명령을 제공 할 수 있도록합니다. 이들은 명령을 제공하는 사용자의 uid, gid 및 그룹으로 실행됩니다.

Super는``super.tab ''파일을 참조하여 사용자가 요청 된 명령을 실행할 수 있는지 확인합니다. 권한이 부여되면 super는 pgm [args]를 실행합니다. 여기서 pgm은이 명령과 관련된 프로그램입니다. (루트는 기본적으로 실행이 허용되지만 규칙에서 루트를 제외하면 여전히 거부 될 수 있습니다. 일반 사용자는 기본적으로 실행이 허용되지 않습니다.)

Command가 수퍼 프로그램에 대한 심볼릭 링크 (또는 하드 링크) 인 경우 % command args를 입력하는 것은 % super command args를 입력하는 것과 같습니다 (명령은 super가 아니어야합니다. 링크.)

http://www.ucolick.org/~will/RUE/super/README

http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html

5
Nizam Mohamed

Sudo + 스크립트 이름에 대한 별명을 작성할 수 있습니다. 물론 별명도 설정해야하므로 Sudo를 입력하지 않아도되므로 설정 작업이 훨씬 더 수월합니다.

그러나 끔찍한 보안 위험을 염두에 두지 않으면 setuid 셸을 셸 스크립트의 해석기로 사용하십시오. 그것이 당신에게 효과가 있는지는 모르겠지만, 아마도 그럴 것 같습니다.

실제로이 작업을 수행하지 말라고 조언하겠습니다. 교육 목적으로 만 언급하고 있습니다. ;-)

4
wzzrd

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

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

그리고 일단 컴파일하면 chmod 4511 wrapper_script와 함께 setuid로 설정됩니다.

이것은 다른 게시 된 답변과 비슷하지만 깨끗한 환경에서 스크립트를 실행하고 system()에 의해 호출 된 셸 대신 /bin/bash를 명시 적으로 사용하므로 잠재적 인 보안 허점을 닫습니다.

이것은 환경을 완전히 버립니다. 취약점을 열지 않고 일부 환경 변수를 사용하려면 실제로 Sudo를 사용해야합니다.

분명히 스크립트 자체는 루트 만 쓸 수 있어야합니다.

2
Chris