내 문제를 설명하기 위해 다음과 같은 간단한 예를 고려하십시오.
서버의 운영 체제는 Debian 11 armhf입니다.
우리는 디렉토리에 있습니다 /botm/test/
:
drwx------ 2 b b 4096 Sep 27 19:27 hide
-rwsr-xr-x 1 b b 8260 Sep 27 19:54 test1
-rwsr-xr-x 1 b b 8264 Sep 27 19:58 test2
-rw-r--r-- 1 b b 56 Sep 27 19:52 test1.awk
-rw-r--r-- 1 b b 172 Sep 27 19:54 test1.c
-rw-r--r-- 1 b b 186 Sep 27 19:58 test2.c
보시다시피, 소유자만이 b
디렉토리에 접근할 수 있습니다 /botm/test/hide
.
이제 우리는 사용자이므로 test
파일에 액세스할 수 없습니다 /botm/test/hide/test.txt
.
$ cat hide/test.txt
cat: hide/test.txt: Permission denied
좋아요 프로그램이 SETUID 비트를 설정 test1
했습니다 . 따라서 우리는 사용자임에도 불구하고 이러한 프로그램을 사용자처럼 실행할 수 있습니다 .test2
test
b
첫 번째, test2.c
:
/* test2.c */
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int r;
r = execl("/usr/bin/cat","/usr/bin/cat","/botm/test/hide/test.txt", (char *)0);
printf("%d\n",r);
return r;
}
$ ./test2
hidden content
$
예상대로 작동합니다.
지금, test1.c
, test1.awk
:
/* test1.c */
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int r;
r = execl("/usr/bin/mawk","/usr/bin/mawk","-f","/botm/test/test1.awk", (char *)0);
printf("%d\n",r);
return r;
}
# test1.awk
BEGIN {
system("cat /botm/test/hide/test.txt");
};
$ ./test1
cat: /botm/test/hide/test.txt: Permission denied
$
놀랍게도 이것은 작동하지 않습니다.
내 기대:
SETUID 를 사용하여 프로그램을 실행하면 test1
user 로 실행되어야 합니다 b
.
따라서 프로그램이 호출되면 /usr/bin/mawk
user 로도 실행되어야 합니다 b
.
따라서 이후에 awk 스크립트가 호출되는 경우에도 user 로 실행되어야 cat
합니다 . 따라서 사용자만 사용할 수 있는 콘텐츠 에 액세스할 수 있어야 합니다 . 하지만 그런 일은 일어나지 않았습니다.cat
b
cat
/botm/test/hide/test.txt
b
이제 실제 상황을 살펴보겠습니다.
위의 내용은 단순화된 예일 뿐입니다. 여러 C 및 AWK 프로그램이 포함된 프로젝트가 있습니다. C 프로그램에서 AWK 프로그램을 호출하여 일부 텍스트를 처리하고 일부 출력을 생성합니다. 여기에는 전화 cat
나 기타 시스템 도구가 포함되는 경우도 있습니다. 이러한 프로그램 중 일부 www-data
는 해당 프로그램에서 생성된 특정 임시 파일에 액세스할 수 있는 권한이 없는(권한이 없어야 하는) 사용자로 Apache 서버에서 실행됩니다 . 이것이 SETUID가 사용되는 이유입니다. 그리고 이 워크플로는 이 프로젝트(2014년 시작)에서 많이 사용됩니다.
지금은 이전 서버(작동)에서 새 서버(작동하지 않음)로 이동하는 중입니다. 이 메커니즘에 의존하지 않도록 프로젝트를 변경하는 것은 매우 큰 재설계가 될 것이므로 지금은 그렇게 하고 싶지 않습니다.
C 프로그램(SETUID 포함)이 시스템 도구( , ... )를 호출하는 AWK 스크립트를 호출할 때 cat
SETUID가 유지되지 않는 이유는
무엇입니까?
이전 버전의 시스템에서는 작동했습니다.
다음을 추가하도록 편집되었습니다.
AWK 프로그램이 여전히 숨겨진 파일에 액세스할 수 있다는 것을 확인했습니다. don이 호출한 파일만 액세스 system()
할 수 없습니다.
따라서 이 동작을 발견한 이유는 파이프를 사용하고 system()
실행 명령을 호출할 때였습니다. AWK나 그와 유사한 것은 없습니다 .getline
mawk
sh
exec
sh
로 호출하지 않으면 SETUID가 제거됩니다 -p
.
이것은 새로운 행동입니다. 이 부분은 man sh
이전 서버에 존재하지 않습니다.
-p priviliged Do not attempt to reset effective uid if it does not match uid. This is not set by default to help avoid incorrect usage by
setuid root programs via system(3) or popen(3).
따라서 프로그램을 다시 실행하려면 다음 중 적어도 하나를 달성해야 합니다.
- make는
/usr/bin/sh
기본적으로 SETUID를 제거하지 않습니다. - make
mawk
또는 기타 호환 가능한 AWK 인터프리터를-p
사용할 때 사용됩니다/usr/bin/sh
.system()
- AWK 프로그램을 실행하는 다른 방법 찾기
- 이에 의존하지 않도록 모든 프로그램을 다시 설계하십시오. 예를 들어 C, Perl 또는 Python에서 실행하면
sh
.
전체 프로젝트(및 이 워크플로를 사용하는 다른 몇 가지 프로젝트)를 재설계하려면 현재 가지고 있지 않은 노력과 시간이 필요하므로 어떻게든 전체 SETUID 기능을 복원해야 합니다.
실제로 해당 기능은 AWK 프로그램에서 쉽게 재현될 수 있으며 cat
내 프로젝트의 다른 도구 system()
( [ -f
, , , , , , , )도 호출할 수 있습니다. 대부분의 경우 SETUID 없이 호출하는 것은 허용되지 않습니다.cat
cp
mkdir
mv
sleep
wget
답변1
이 비슷한 질문에 대한 대답은 다음과 같습니다.
https://unix.stackexchange.com/a/565254/543092
제안 사항이 있습니다 setresuid()
.
내 프로젝트에서 AWK 스크립트는 항상 C 프로그램에서 호출되므로 이것이 내가 사용할 수 있는 솔루션입니다.
나는 다음과 같은 일을 했습니다:
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char **argv)
{
uid_t euid;
int r;
euid = geteuid();
r = setreuid(euid, euid);
if (r != 0)
return (r = errno);
r = execl("/usr/bin/mawk","/usr/bin/mawk","-f","/botm/test/test1.awk", (char *)0);
printf("%d\n",r);
}
이런 식으로 "변장"이 완료되고 sh
SETUID는 이전에 알 수 없게 됩니다. 모든 것이 정상입니다.
이는 항상 존재하는 것처럼 동작하도록 만드는 것보다 sh
더 나은 솔루션 입니다 -p
. 내가 무엇을 하고 있는지 알고 있으면 SETUID가 유지됩니다.
나는 다음과 같은 이유로 제안된 것 setreuid()
대신에 사용합니다.setresuid()
setreuid()
충분한setresuid()
GNU 확장입니다.