euid, ruid, suid

Support HackTricks

ユーザー識別変数

  • ruid: 実ユーザーIDは、プロセスを開始したユーザーを示します。

  • euid: 効果的ユーザーIDとして知られ、システムがプロセスの特権を確認するために使用するユーザーの識別を表します。一般的に、euidruidと同じですが、SetUIDバイナリの実行のような場合には、euidがファイル所有者の識別を引き受け、特定の操作権限を付与します。

  • suid: この保存されたユーザーIDは、高特権プロセス(通常はrootとして実行される)が特定のタスクを実行するために一時的に特権を放棄し、後で元の昇格した状態を取り戻す必要があるときに重要です。

重要な注意

rootでないプロセスは、euidを現在のruideuid、またはsuidに一致させることしかできません。

set*uid関数の理解

  • setuid: 初期の仮定とは異なり、setuidは主にeuidを変更します。具体的には、特権プロセスの場合、指定されたユーザー(通常はroot)にruideuid、およびsuidを合わせ、これらのIDを強化します。詳細な情報はsetuidマニュアルページで確認できます。

  • setreuidおよびsetresuid: これらの関数は、ruideuid、およびsuidの微妙な調整を可能にします。ただし、その機能はプロセスの特権レベルに依存します。非rootプロセスの場合、変更は現在のruideuid、およびsuidの値に制限されます。一方、rootプロセスまたはCAP_SETUID権限を持つプロセスは、これらのIDに任意の値を割り当てることができます。詳細はsetresuidマニュアルページおよびsetreuidマニュアルページで確認できます。

これらの機能は、セキュリティメカニズムとしてではなく、プログラムが他のユーザーの識別を採用するために効果的ユーザーIDを変更する際の意図された操作フローを促進するために設計されています。

特に、setuidはrootへの特権昇格の一般的な手段である一方で(すべてのIDをrootに合わせるため)、これらの関数の違いを理解し、さまざまなシナリオでユーザーIDの動作を操作することが重要です。

Linuxにおけるプログラム実行メカニズム

execveシステムコール

  • 機能: execveは、最初の引数によって決定されるプログラムを開始します。引数用の2つの配列引数argvと環境用のenvpを取ります。

  • 動作: 呼び出し元のメモリ空間を保持しますが、スタック、ヒープ、およびデータセグメントをリフレッシュします。プログラムのコードは新しいプログラムによって置き換えられます。

  • ユーザーIDの保持:

  • ruideuid、および追加のグループIDは変更されません。

  • 新しいプログラムにSetUIDビットが設定されている場合、euidに微妙な変更があるかもしれません。

  • 実行後にsuideuidから更新されます。

  • 文書: 詳細な情報はexecveマニュアルページで確認できます。

system関数

  • 機能: execveとは異なり、systemforkを使用して子プロセスを作成し、その子プロセス内でコマンドを実行します。

  • コマンド実行: shを介してコマンドを実行します。execl("/bin/sh", "sh", "-c", command, (char *) NULL);を使用します。

  • 動作: execlexecveの一形態であり、同様に動作しますが、新しい子プロセスの文脈で実行されます。

  • 文書: さらなる洞察はsystemマニュアルページから得られます。

SUIDを持つbashshの動作

  • bash:

  • euidruidの扱いに影響を与える-pオプションがあります。

  • -pなしでは、basheuidruidと異なる場合、euidruidに設定します。

  • -pがある場合、初期のeuidが保持されます。

  • 詳細はbashマニュアルページで確認できます。

  • sh:

  • bash-pに類似したメカニズムはありません。

  • ユーザーIDに関する動作は明示的に記載されておらず、-iオプションの下でeuidruidの等価性の保持が強調されています。

  • 追加情報はshマニュアルページで確認できます。

これらのメカニズムは、異なる動作を持ち、プログラムの実行と遷移のための多様なオプションを提供し、ユーザーIDの管理と保持における特定のニュアンスを持っています。

実行におけるユーザーIDの動作のテスト

例はhttps://0xdf.gitlab.io/2022/05/31/setuid-rabbithole.html#testing-on-jailから取得したもので、さらなる情報はそちらで確認してください。

ケース1: systemとのsetuidの使用

目的: systembashshとして組み合わせたときのsetuidの効果を理解すること。

Cコード:

#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>

int main(void) {
setuid(1000);
system("id");
return 0;
}

コンパイルと権限:

oxdf@hacky$ gcc a.c -o /mnt/nfsshare/a;
oxdf@hacky$ chmod 4755 /mnt/nfsshare/a
bash-4.2$ $ ./a
uid=99(nobody) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0

分析:

  • ruideuid はそれぞれ 99 (nobody) と 1000 (frank) から始まります。

  • setuid は両方を 1000 に揃えます。

  • system は sh から bash へのシンボリックリンクのために /bin/bash -c id を実行します。

  • bash-p なしで euidruid に合わせるため、両方が 99 (nobody) になります。

ケース 2: system で setreuid を使用する

C コード:

#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>

int main(void) {
setreuid(1000, 1000);
system("id");
return 0;
}

コンパイルと権限:

oxdf@hacky$ gcc b.c -o /mnt/nfsshare/b; chmod 4755 /mnt/nfsshare/b

実行と結果:

bash-4.2$ $ ./b
uid=1000(frank) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0

分析:

  • setreuid は ruid と euid の両方を 1000 に設定します。

  • system は bash を呼び出し、ユーザー ID の等価性によりそれらを維持し、実質的に frank として動作します。

ケース 3: execve と setuid の相互作用の使用

目的: setuid と execve の相互作用を探る。

#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>

int main(void) {
setuid(1000);
execve("/usr/bin/id", NULL, NULL);
return 0;
}

実行と結果:

bash-4.2$ $ ./c
uid=99(nobody) gid=99(nobody) euid=1000(frank) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0

分析:

  • ruidは99のままですが、euidはsetuidの効果に従って1000に設定されています。

Cコード例 2 (Bashを呼び出す):

#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>

int main(void) {
setuid(1000);
execve("/bin/bash", NULL, NULL);
return 0;
}

実行と結果:

bash-4.2$ $ ./d
bash-4.2$ $ id
uid=99(nobody) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0

分析:

  • euidsetuidによって1000に設定されていますが、bash-pがないためruid(99)にeuidをリセットします。

C コード例 3 (bash -pを使用):

#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>

int main(void) {
char *const paramList[10] = {"/bin/bash", "-p", NULL};
setuid(1000);
execve(paramList[0], paramList, NULL);
return 0;
}

実行と結果:

bash-4.2$ $ ./e
bash-4.2$ $ id
uid=99(nobody) gid=99(nobody) euid=100

参考文献

HackTricksをサポートする

Last updated