
この C プログラムを見てください:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("UID: %d\n", getuid());
printf("EUID: %d\n", geteuid());
system("id");
printf("res=%d\n", setuid(1001));
printf("UID: %d\n", getuid());
printf("EUID: %d\n", geteuid());
system("id");
return 0;
}
私のユーザー アカウントは「test」(ID 1000) です。2 番目のユーザー アカウントは「test2」(ID 1001) です。
私がやったことは次のとおりです:
gcc test.c -o ./a.out
sudo chown test2 ./a.out
sudo chmod u+s ./a.out
ここで、./a.out を起動すると何が起こるかを示します。
UID: 1000
EUID: 1001
uid=1000(test) gid=1000(test) groups=1000(test),...
res=0
UID: 1000
EUID: 1001
uid=1000(test) gid=1000(test) groups=1000(test),...
2 番目の部分に uid=1001 が表示されない理由がわかりません...
私はこれを試しました:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("UID: %d\n", getuid());
printf("EUID: %d\n", geteuid());
system("id");
printf("res=%d\n", setuid(0)); // <- Here is the change
printf("UID: %d\n", getuid());
printf("EUID: %d\n", geteuid());
system("id");
return 0;
}
gcc test.c -o ./a.out
sudo chown root ./a.out
sudo chmod u+s ./a.out
./a.out を実行すると、次の結果が表示されます。
UID: 1000
EUID: 0
uid=1000(test) gid=1000(test) groups=1000(test),...
res=0
UID: 0
EUID: 0
uid=0(root) gid=1000(test) groups=1000(test),...
今は動作します。
では、setuid が test2 ユーザーでは機能せず、root ユーザーでは機能する理由がわかりません...
何か案が ?
ありがとう
答え1
ここで混乱を引き起こしているのは、いくつかのことです。Setuid はどちらの場合も機能しますが、思ったようには機能しません。まず、実際のユーザー ID と有効なユーザー ID の問題があります。setuid(2) マニュアルページ
呼び出しプロセスが特権を持っている場合 (より正確には、プロセスが
CAP_SETUID
ユーザー名前空間で機能を持っている場合)、実 UID と保存された set-user-ID も設定されます。
これはまた、呼び出しプロセスがない権限を持っている場合CAP_SETUID
(一般ユーザーの場合)、UIDはない変更されるのは EUID のみです。
では、呼び出しに移りますsystem()
。呼び出しはsystem("anything")
、次の呼び出しと同じです。
execl("/bin/sh", "sh", "-c", "anything", (char *) NULL);
そこで、/bin/sh
新しいシェルがコマンドを実行するための引数を提供する を生成します。シェルとしてbashを使用していると仮定します。bashは
シェルが実効ユーザー (グループ) ID と実際のユーザー (グループ) ID が等しくない状態で起動され、-p オプションが指定されていない場合、(...) 実効ユーザー ID は実際のユーザー ID に設定されます。
したがって、プロセスに権限がない場合CAP_SETUID
、実ユーザーIDは変更されず、実効UIDのみが変更されます。その後、bashが起動されると、UIDはEUIDと等しくないため、実効UIDが削除されます。これを確認するには、次を呼び出します。
system("touch /tmp/blah")
そして追加
FILE *file = fopen("/tmp/blah2", "w+");
fclose(file);
プログラムに追加します。 の所有者は/tmp/blah
「test」になりますが (EUID はシェル実行時に削除されるため)、/tmp/blah2
「test2」に属します。