2014-12-12 85 views
8

system()execve() 모두 프로그램 내에서 다른 명령을 실행할 수 있습니다. 왜 UID가 설정된 프로그램에서 system()은 위험하며 execve()은 안전합니까?system() vs execve()

답변

9

system()execve()은 다른 방식으로 작동합니다. system()은 항상 쉘을 호출하며이 쉘은 명령을 별도의 프로세스로 실행합니다 (이 때문에 system()을 사용할 때 명령 행에서 와일드 카드 및 기타 쉘 기능을 사용할 수 있습니다).

execve() (및 exec() 제품군의 다른 함수)은 현재 프로세스를 직접 생성 된 프로세스로 바꿉니다 (오류가 발생한 경우를 제외하고는 execve() 함수가 반환되지 않습니다). 실제로 system() 구현에서는 fork(), execve()wait() 시퀀스를 사용하여 해당 기능을 수행합니다.

물론 프로세스에 루트 권한이있을 때 실행중인 내용에 따라 둘 다 위험합니다. 그러나 system()은 질문의 경우처럼 루트 쉘을 호출 할 때 (즉, 프로세스에 suid 비트가 있음) 방 보안 위반을 야기하는 추가 "쉘"레이어로 인해 추가 위험을 초래합니다.

+0

execve()를 사용할 때 현재 프로세스를 대체한다고 언급합니다. 프로세스가 setuid로 남아 있습니까? – Jake

+0

예.execve에 의해 시작된 "새로운"프로세스는 filedescriptors, 소켓 등과 같이 대체 될 속성의 여러 속성을 상속받습니다. 유효 uid는 그 중 하나이지만 execve의 실행 중에 uid가 변경되는 상황이 있습니다 execve 매개 변수가 가리키는 실행 파일에 suid 비트가 설정된 경우. 이 경우 uid는 파일 시스템에 정의 된대로 파일 소유자로 변경됩니다. – Marcelo

12

system은 쉘 (sh)을 호출하여 인수로 보낸 명령을 실행합니다. 쉘 동작이 명령을 실행하는 사용자에 의존하기 때문에 system의 문제점. 작은 예 : 그럼

#include <stdio.h> 

int main(void) { 
    if (system ("ls") != 0) 
     printf("Error!"); 
    return 0; 
} 

: : 이제

$ cat > ls 
#!/bin/sh 

/bin/sh 

$ chmod +x ls 

:

$ gcc test.c -o test 

$ sudo chown root:root test 

$ sudo chmod +s test 

$ ls -l test 
-rwsr-sr-x 1 root root 6900 Dec 12 17:53 test 

현재 디렉토리에 ls라는 스크립트를 작성

는 파일 test.c 만들기

$ PATH=. ./test 
# /usr/bin/id 
uid=1000(cuonglm) gid=1000(cuonglm) euid=0(root) egid=0(root) groups=0(root), 
24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),105(scanner), 
110(bluetooth),111(netdev),999(docker),1000(cuonglm) 
# /usr/bin/whoami 
root 

죄송합니다. 루트 권한이있는 쉘이 있습니다.

execve은 쉘을 호출하지 않습니다. 첫 번째 인수로 전달 된 프로그램을 실행합니다. 프로그램은 이진 실행 파일이거나 스크립트가 shebang 줄로 시작해야합니다.

+0

'system()'은 아무런 문제가 없지만 바이너리 실행 파일의 절대 경로를 사용하면 위의 내용을 해결할 수 없습니까? – Bratchley

+1

@JoelDavis, 아니요, 적어도 환경 전체를 지우고 필요한 경우 몇 가지 envvars (PATH, HOME ...)에 기본 값을 부여해야합니다. 필요하면 소독 후 일부 환경을 보존하십시오 (TERM, DISPLAY, LANG. ..) fds 0, 1, 2가 열려 있는지 확인하십시오 ... 기본적으로 sudo가하는 일을하십시오. 그럼에도 불구하고 나는 거기에 가지 않을 것이다. 권한 상승 에스컬레이션 컨텍스트에서 셸을 호출하지 마십시오. 'ls'는 환경과 관련된 멋진 일을 할 수 있으므로'system()'이 없어도 환경을 위생해야 할 것입니다. setuids를 사용할 때 루트로 수행되는 작업을 최소화하려고합니다 (일반적으로 명령을 실행하지 않음). –

+3

@JoelDavis : 아니요, 전체 경로를 사용하더라도 문제가 있습니다. '/ bin/ls'을 사용하면'$ IFS'에'/'를 추가 할 수 있습니다. 그러면 쉘이'/ bin/ls '을'bin'과'ls'로 나눕니다. 이제, 현재 디렉토리에서'bin'이라는 실행 파일은 나의 대답에서'ls'와 같은 것을 할 수 있습니다. – cuonglm

0

system()의 보안 문제 외에도 생성 된 프로세스는 주 프로그램 환경을 상속합니다. 이것은 suid을 사용할 때 매우 문제가 될 수 있습니다. 예를 들어 호출 프로세스가 LD_LIBRARY_PATH - 환경 변수를 설정할 때입니다.

exec() 패밀리를 사용하면 호출 프로그램은 exec()을 호출하기 전에 호출 된 프로그램에 필요한 환경을 정확하게 설정할 수 있습니다.

그리고 물론 system()이 호출하는 셸 자체에 보안 문제가있을 수 있습니다.