これはset-root-uidプログラムです
_$ls -l
-rwsr-sr-x 1 root root 7406 2011-12-13 22:37 ./x*
_
_int main(void) {
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
seteuid(600);
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
setuid(1000);
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
setuid(0); // HOW DOES THIS SUCCEED IN SETTING THE EUID BACK TO 0
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
return 0 ;
}
_
_ UID GID
Real 1000 Real 1000
Effective 0 Effective 0
UID GID
Real 1000 Real 1000
Effective 600 Effective 0
UID GID
Real 1000 Real 1000
Effective 1000 Effective 1000
UID GID
Real 1000 Real 1000
Effective 0 Effective 1000
_
マニュアルページには、setuidが実際の保存された有効なuidを変更することが記載されています。したがって、setuid(1000)
を呼び出した後、3つすべてが_1000
_に変更されます。 setuid(0)
どうすればeuid
を_0
_に変更できますか?
2つのケースがあります。
- Setuidプログラムの実行中に一時的にroot特権を削除したい
- Setuidプログラムの実行中にルート権限を永久に削除したい...
事例1:
Setuidプログラムの実行開始後
1.seteuid(600);
2.setuid(1000);
3.setuid(0);
この場合、ルート権限を再度取得できます。
+----+------+------------+
| uid|euid |saved-uid |
|----|------|------------|
1.|1000| 0 | 0 |
2.|1000| 600 | 0 |
3.|1000| 1000 | 0 |
4.|1000| 0 | 0 |
| | | |
+------------------------+
事例2:
Setuidプログラムの実行開始後、
1.setuid(1000);
2.setuid(0);
+----+------+------------+
| uid|euid |saved-uid |
|----|------|------------|
1.|1000|0 | 0 |
2.|1000|1000 | 1000 |
| | | |
+------------------------+
この場合、ルート権限を取り戻すことはできません。これは、次のコマンドで確認できます。
cat/proc/PROCID/task/PROCID/status |もっと少なく
Uid: 1000 0 0 0
Gid: 1000 0 0 0
このコマンドは、UidとGidを表示し、4つのフィールドがあります(最初の3つのフィールドは、対象のフィールドです)。上記のようなもの
3つのフィールドは、uid、euid、およびsaved-user-idを表します。 setuidプログラムに一時停止(ユーザーからの入力)を導入し、各ステップでcat /proc/PROCID/task/PROCID/status | less
コマンド。各ステップで、保存されたuidが前述のように変更されていることを確認できます。
Rootであるユーザーがuidを変更すると、特権は永久に削除されます。有効なユーザーIDがrootでない場合、保存されたユーザーIDは変更されず、プログラムでいつでもルート特権を取り戻すことができます。
[〜#〜] description [〜#〜] setuid()は、呼び出しプロセスの実効ユーザーIDを設定します。呼び出し元の実効UIDがルートの場合、実際のUIDと保存されたset-user-IDも設定されます。
Linuxでは、setuid()は_POSIX_SAVED_IDS機能を備えたPOSIXバージョンのように実装されます。これにより、set-user-ID(root以外)プログラムがすべてのユーザー特権をドロップし、特権のない作業を行ってから、元の有効なユーザーIDを安全な方法で再利用できます。
ユーザーがrootであるか、プログラムがset-user-ID-rootである場合、特別な注意が必要です。 setuid()関数は、呼び出し元の実効ユーザーIDをチェックし、それがスーパーユーザーである場合、すべてのプロセス関連ユーザーIDはuidに設定されます。これが発生した後、プログラムがルート特権を取り戻すことは不可能です。
したがって、root特権を一時的にドロップし、非特権ユーザーのIDを引き継ぎ、その後root特権を取り戻したいset-user-ID-rootプログラムは、setuid()を使用できません。 seteuid(2)でこれを達成できます。
(Linuxプログラマーズマニュアル、2014-09-21、ページsetuid.2
)
O!これらの機能を正しく使用することは困難です。
マニュアルページには、setuidが実際の保存された有効なuidを変更することが記載されています。したがって、setuid(1000)を呼び出した後、3つすべてが1000に変わります。
あなたがeuid 0である場合にのみ、そうなります。ただし、setuid(0)
を呼び出すときは、euid 1000であり、saved uid 0(check getresuid(2)
、 例えば)。そのため、特権を取り戻すことができます。
コード:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
void print_uid(char *str, int ret)
{
uid_t ruid;
uid_t euid;
uid_t suid;
getresuid(&ruid, &euid, &suid);
printf("%s ret:%d\n"
"Real:%4d Effective:%4d Saved:%4d\n",
str, ret, ruid, euid, suid);
}
int main(void)
{
int ret = 0;
print_uid("init", ret); /* Real:1000 Effective: 0 Saved: 0 */
ret = seteuid(600);
print_uid("seteuid(600)", ret); /* Real:1000 Effective: 600 Saved: 0 */
ret = setuid(1000);
print_uid("setuid(1000)", ret); /* Real:1000 Effective:1000 Saved: 0 */
ret = setuid(0);
print_uid("setuid(0)", ret); /* Real:1000 Effective: 0 Saved: 0 */
ret = setuid(1000);
print_uid("setuid(1000)", ret); /* Real:1000 Effective:1000 Saved:1000 */
ret = setuid(0);
print_uid("setuid(0)", ret); /* Real:1000 Effective:1000 Saved:1000 */
return 0 ;
}
Sudo chown root setuid_feature
sudo chmod + s setuid_feature
Linuxのプロセスには3つのuidがあります:REAL uid、Effective uid、SAVED uid。
条件1. euidがrootの場合、setuidまたはseteuidを任意のuidに設定できますが、副作用があります。setuid(not seteuid)を使用すると、3つすべてを同じuidに設定できます。 ROOTではないため、プロセスはROOT特権を取り戻すことができません。
条件2. euidがrootでない場合、setuidまたはseteuidをruidまたはsuidに設定でき、euidのみが変更されます。
| seteuid | setuid
Cond 1. (euid == root) | set euid to any uid | set all three uids to any uid
Cond 2. (euid != root) | set euid to ruid or suid | set euid to ruid or suid
そのため、コードには5つのsetuidまたはseteuidプロセスがあります。それらを分類してみましょう。
1。 seteuid(600):Cond 1、euidを600に設定
2。 setuid(1000):Cond 2、euidを1000に設定
3。 setuid(0):条件2、euidを0(suid)に設定
4。 setuid(1000):Cond 1、3つすべてのuidを1000に設定
5。 setuid(0):条件2、3つのすべてのuidが0に等しくないため、0に設定できません。ret= -1で失敗しました