루트가 아닌 사용자에게 setuid()가 작동하지 않는 이유는 무엇입니까?

루트가 아닌 사용자에게 setuid()가 작동하지 않는 이유는 무엇입니까?

setuid()setuid 비트와 관련하여 이상한 동작이 발생했습니다.

suid 비트와 setuid()가 예상대로 작동하지 않는 것 같습니다. 나는 +s가 있고 uid 1001이 소유한 바이너리를 기대하고 있습니다. 이 바이너리는 setuid(1001)모든 uid에서 호출될 수 있으며 호출 후 uid 1001을 가정합니다. 그러나 이는 다음과 같은 경우에만 작동하는 것 같습니다.

  1. +s가 설정되지 않았고 호출 사용자는 루트입니다.
  2. +s가 설정되었고 바이너리는 루트에 속합니다.

세부 사항을 간과하고 있기를 바라지만 오류를 찾을 수 없습니다.

궁극적인 목표는 모든 사용자가 호출할 수 있고 고정된 UID를 가정하는 바이너리를 만드는 것입니다. 나는 그것을 루트가 소유하는 것이 아니라 신원을 가정해야 하는 사용자가 소유하기를 원합니다(주로 이것은 스택 스매싱 연습이고 priv esc가 허용되기 때문입니다).

내 문제를 식별하기 위해 다음과 같이 최소한의 예를 만들었습니다.

test.c를 고려해보세요:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
int main() {
        int t = setuid(1001);
        if (t < 0) {
                perror("Error with setuid() - errno " + errno);
        }
        else {
                printf("did work fine, look who I am:.\n");
                system("/bin/bash -c whoami");
        }
}

또한 passwd는 관련 부분에서 다음과 같습니다.

test1:x:1000:1000::/home/test1:/bin/sh
test2:x:1001:1001::/home/test2:/bin/sh

이제 다음 출력을 고려해보세요.

root@kali:/tmp/test# ls -la
total 12
drwxr-xr-x  2 root root 4096 Oct 24 09:53 .
drwxrwxrwt 18 root root 4096 Oct 24 09:52 ..
-rw-r--r--  1 root root  304 Oct 24 09:51 test.c
root@kali:/tmp/test# gcc test.c -o test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# chown test2:test2 test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# chmod +s test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
root
root@kali:/tmp/test# su test1
$ ./test
did work fine, look who I am:.
test1
$ 

보시다시피 오류는 표시되지 않지만 필수 uid가 올바르게 가정되지 않습니다. 부상에 모욕을 더하려면 다음을 고려하십시오.

root@kali:/tmp/test# chown root:root test
root@kali:/tmp/test# chmod +s test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# su test1
$ ./test
did work fine, look who I am:.
test2

그래서 내 질문은: 내가 뭘 잘못하고 있는 걸까요? 왜 setreuid()작동하고 setuid()무엇이 작동하지 않습니까?

내가 시도한 다른 것들: 사용 execve(), 우분투 18.04에서 복사, /bin/bash 대신 /bin/sh 사용.

답변1

setuid()응용 프로그램이 setuid 루트인지 여부에 따라 다른 작업을 수행한다는 점에서 의 정의는 약간 이상합니다. (타당한 이유가 있지만 언뜻 보면 반드시 명확하지 않을 수도 있습니다.)

기본적으로 필요한 것은 호출하기 전에 원래 사용자 ID를 포기하는 것입니다 system(). 일부 쉘은 setuid 존중을 거부하기 위해 최선을 다하기 때문입니다. 이는 코드의 수정된 버전입니다. 주석 처리된 줄을 사용하거나 사용하지 않고 실행하여 차이점을 확인하세요.

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

int main() {
    int t;

    printf("before, geteuid() returned %d\n", geteuid());
    printf("before, getuid() returned %d\n", getuid());

    t = setuid(geteuid());
    if (t < 0) {
        perror("Error with setuid() - errno " + errno);
        exit(1);
    }

    printf("after, geteuid() returned %d\n", geteuid());
    printf("after, getuid() returned %d\n", getuid());

    // setreuid(geteuid(), geteuid());

    printf("finally, geteuid() returned %d\n", geteuid());
    printf("finally, getuid() returned %d\n", getuid());

    printf("did work fine, look who I am:\n");
    system("/bin/bash -c whoami");
}

관련 정보