root以外のユーザーにsetuid()が機能しないのはなぜですか?

root以外のユーザーにsetuid()が機能しないのはなぜですか?

setuid()setuid ビットに関して異常な動作が発生しました。

suidビットとsetuid()が期待どおりに機能しないようです。私は+sを持ち、uid 1001が所有するバイナリを期待しています。このバイナリはsetuid(1001)すべてのuidで呼び出すことができ、呼び出し後にuid 1001を想定します。ただし、これは次の場合にのみ機能するようです。

  1. + sが設定されておらず、呼び出し側のユーザーはrootです。
  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()、Ubuntu 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");
}

関連情報