setuid()
setuid 비트와 관련하여 이상한 동작이 발생했습니다.
suid 비트와 setuid()가 예상대로 작동하지 않는 것 같습니다. 나는 +s가 있고 uid 1001이 소유한 바이너리를 기대하고 있습니다. 이 바이너리는 setuid(1001)
모든 uid에서 호출될 수 있으며 호출 후 uid 1001을 가정합니다. 그러나 이는 다음과 같은 경우에만 작동하는 것 같습니다.
- +s가 설정되지 않았고 호출 사용자는 루트입니다.
- +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");
}