
권한 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
수 있도록 허용하는 항목을 추가하는 것입니다. 그 주요 단점은 이 작업을 수행할 때마다 항목을 입력해야 한다는 것과 호출자가 단지 입력하는 대신에 항목을 입력해야 한다는 것입니다.ALL
NOPASSWD
sudoers
sudo some-script
some-script
답변1
Linux는 해석된 모든 실행 파일(즉, 한 줄로 시작하는 실행 파일)에서 setuid1 비트를 무시합니다 #!
. 그만큼comp.unix.questions FAQsetuid 쉘 스크립트의 보안 문제를 설명합니다. 이러한 문제는 Shebang 관련 문제와 Shell 관련 문제의 두 가지 종류가 있습니다. 아래에서 더 자세히 설명하겠습니다.
보안에 관심이 없고 setuid 스크립트를 허용하려면 Linux에서 커널을 패치해야 합니다. 3.x 커널부터는 다음에 대한 호출을 추가해야 한다고 생각합니다.install_exec_creds
에서load_script
함수를 호출하기 전에 테스트 open_exec
했지만 테스트하지 않았습니다.
Setuid shebang
shebang( )이 일반적으로 구현되는 방식에는 고유한 경쟁 조건이 있습니다 #!
.
- 커널은 실행 파일을 열고
#!
. - 커널은 실행 파일을 닫고 대신 인터프리터를 엽니다.
- 커널은 인수 목록에 스크립트 경로를 삽입하고( as
argv[1]
) 인터프리터를 실행합니다.
이 구현에서 setuid 스크립트가 허용되는 경우 공격자는 기존 setuid 스크립트에 대한 기호 링크를 생성하고 이를 실행한 다음 커널이 1단계를 수행한 후 인터프리터가 해당 스크립트를 실행하기 전에 링크를 변경하도록 조정하여 임의의 스크립트를 호출할 수 있습니다. 첫 번째 주장을 시작합니다. 이런 이유로,대부분의 유닉스는 setuid 비트를 무시합니다.그들이 shebang을 감지했을 때.
이 구현을 보호하는 한 가지 방법은 인터프리터가 스크립트 파일을 열 때까지 커널이 스크립트 파일을 잠그는 것입니다(이렇게 하면 파일 링크를 해제하거나 덮어쓰는 것뿐만 아니라 경로에 있는 디렉터리의 이름을 바꾸는 것도 방지해야 합니다). 그러나 유닉스 시스템은 필수 잠금을 기피하는 경향이 있으며 기호 링크는 올바른 잠금 기능을 특히 어렵고 침해적으로 만듭니다. 이렇게 하는 사람은 없을 것 같아요.
몇몇 유닉스 시스템(주로 OpenBSD, NetBSD 및 Mac OS X, 모두 활성화하려면 커널 설정이 필요함)이 구현됩니다.보안 setuid shebang추가 기능 사용: 경로는 파일 설명자에서 이미 열려 있는 파일을 참조합니다./dev/fd/N
N(따라서 열기는 대략 와 동일합니다 ). 많은 Unix 시스템(Linux 포함)에는 setuid 스크립트가 있지만 없습니다./dev/fd/N
dup(N)
/dev/fd
- 커널은 실행 파일을 열고
#!
. 실행 파일의 파일 설명자가 3이라고 가정해 보겠습니다. - 커널이 인터프리터를 엽니다.
- 커널은
/dev/fd/3
인수 목록( asargv[1]
)을 삽입하고 인터프리터를 실행합니다.
Sven Mascheck의 shebang 페이지다음을 포함하여 unices 전반에 걸쳐 shebang에 대한 많은 정보가 있습니다.setuid 지원.
Setuid 통역사
sudo
OS가 setuid shebang을 지원하거나 기본 바이너리 래퍼(예: ) 를 사용했기 때문에 프로그램을 루트로 실행했다고 가정해 보겠습니다 . 보안 허점을 열었나요?아마도. 여기서 문제는~ 아니다해석된 프로그램과 컴파일된 프로그램에 대해 문제는 귀하의 여부입니다.런타임 시스템권한을 가지고 실행하면 안전하게 동작합니다.
동적으로 링크된 기본 바이너리 실행 파일은 다음과 같은 방식으로 해석됩니다.동적 로더(예:
/lib/ld.so
)은 프로그램에 필요한 동적 라이브러리를 로드합니다. 많은 unices에서는 환경(LD_LIBRARY_PATH
은 환경 변수의 공통 이름)을 통해 동적 라이브러리에 대한 검색 경로를 구성할 수 있으며 실행된 모든 바이너리에 추가 라이브러리를 로드할 수도 있습니다(LD_PRELOAD
). 프로그램 호출자는 (다른 전술 중에서)libc.so
특별히 제작된 코드를 배치하여 해당 프로그램의 컨텍스트에서 임의의 코드를 실행할 수 있습니다.$LD_LIBRARY_PATH
모든 제정신 시스템은LD_*
setuid 실행 파일의 변수를 무시합니다.~ 안에껍질sh, csh 및 파생물과 같은 환경 변수는 자동으로 쉘 매개변수가 됩니다.
PATH
, 등 의 매개변수를 통해IFS
스크립트 호출자는 쉘 스크립트의 컨텍스트에서 임의의 코드를 실행할 수 있는 많은 기회를 갖습니다. 일부 쉘은 스크립트가 권한으로 호출되었음을 감지하면 이러한 변수를 정상적인 기본값으로 설정하지만 신뢰할 수 있는 특정 구현이 있는지는 알 수 없습니다.대부분의 런타임 환경(네이티브, 바이트코드 또는 해석 여부에 관계없이) 유사한 기능을 가지고 있습니다. setuid 실행 파일에서 특별한 예방 조치를 취하는 사람은 거의 없지만 네이티브 코드를 실행하는 실행 파일은 동적 링크(예방 조치를 취함)보다 더 멋진 작업을 수행하지 않는 경우가 많습니다.
펄주목할만한 예외입니다. 그것명시적으로 setuid 스크립트를 지원합니다.안전한 방법으로. 실제로 OS가 스크립트의 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,DR:
- Setuid shebang은 안전하지 않지만 일반적으로 무시됩니다.
- 권한(sudo 또는 setuid를 통해)으로 프로그램을 실행하는 경우 네이티브 코드 또는 Perl을 작성하거나 환경을 위생 처리하는 래퍼(예: 옵션이 있는 sudo
env_reset
)를 사용하여 프로그램을 시작하세요.
¹ 이 논의는 "setuid"를 "setgid"로 대체하는 경우에도 동일하게 적용됩니다.둘 다 스크립트의 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
이는 .dll을 사용하여 현재 파일을 사용하지 않고 단순히 실행한다는 점에 유의하세요 sudo
.
답변4
어떤 이유로든 sudo
사용할 수 없는 경우 C로 씬 래퍼 스크립트를 작성할 수 있습니다.
#include <unistd.h>
int main() {
setuid(0);
execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}
그리고 일단 컴파일하면 setuid
with 와 같이 설정됩니다 chmod 4511 wrapper_script
.
이것은 게시된 다른 답변과 유사하지만 깨끗한 환경에서 스크립트를 실행하고 /bin/bash
by 호출된 셸 대신 명시적으로 사용하므로 system()
일부 잠재적인 보안 허점이 닫힙니다.
이렇게 하면 환경이 완전히 삭제됩니다. 취약점을 공개하지 않고 일부 환경 변수를 사용하려면 실제로 sudo
.
분명히 스크립트 자체는 루트에서만 쓸 수 있는지 확인하고 싶을 것입니다.