web-dev-qa-db-ja.com

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

setuid()とsetuidビットに関して奇妙な動作が発生しています。

Suidビットとsetuid()が期待どおりに機能しないようです。 + sを含み、setuid(1001)を呼び出すuid 1001が所有するバイナリが任意のuidから呼び出され、呼び出しの後にuid 1001であると想定しています。それでも、それは次のいずれかの場合にのみ機能するようです。

  1. + sが設定されておらず、呼び出し元のユーザーがroot
  2. + sが設定され、バイナリがルートに属している

詳細を見落としていると思いますが、間違いが見つかりません。

最終目標は、任意のユーザーから呼び出すことができ、固定uidを想定できるバイナリを用意することです。 rootが所有するのではなく、IDを想定する必要があるユーザーが所有するようにします(主に、これはスタックスマッシングの演習であり、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を使用します。

2
Tobi Nary

setuid()の定義は、アプリケーションがsetuid rootであるかどうかによって異なることを行うため、少し奇妙です。 (正当な理由がありますが、一見しただけでは必ずしも明白な理由ではありません。)

基本的に、必要なのはsystem()を呼び出す前に、元のユーザーIDを放棄することです。これは、一部のシェルが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");
}
1
roaima