euid, ruid, suid
Reading time: 12 minutes
tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:
HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
ユーザー識別変数
ruid: 実ユーザーIDは、プロセスを開始したユーザーを示します。euid: 有効ユーザーIDとして知られ、システムがプロセスの特権を確認するために使用するユーザーの識別を表します。一般的に、euidはruidと一致しますが、SetUIDバイナリの実行のような場合には、euidがファイル所有者の識別を引き受け、特定の操作権限を付与します。suid: この保存されたユーザーIDは、高特権プロセス(通常はrootとして実行される)が特定のタスクを実行するために一時的に特権を放棄し、後に元の昇格した状態を取り戻す必要があるときに重要です。
重要な注意
rootでないプロセスは、euidを現在のruid、euid、またはsuidに一致させることしかできません。
set*uid関数の理解
setuid: 初期の仮定とは異なり、setuidは主にruidではなくeuidを変更します。具体的には、特権プロセスの場合、指定されたユーザー(通常はroot)にruid、euid、およびsuidを一致させ、これらのIDを強化します。詳細な情報はsetuid man pageで確認できます。setreuidおよびsetresuid: これらの関数は、ruid、euid、およびsuidの微妙な調整を可能にします。ただし、その機能はプロセスの特権レベルに依存します。非rootプロセスの場合、変更は現在のruid、euid、およびsuidの値に制限されます。対照的に、rootプロセスまたはCAP_SETUID権限を持つプロセスは、これらのIDに任意の値を割り当てることができます。詳細はsetresuid man pageおよびsetreuid man pageで確認できます。
これらの機能は、セキュリティメカニズムとしてではなく、プログラムが有効ユーザーIDを変更して他のユーザーの識別を採用するなど、意図された操作フローを促進するために設計されています。
特に、setuidはrootへの特権昇格の一般的な手段である一方で(すべてのIDをrootに一致させるため)、これらの関数の違いを理解し、さまざまなシナリオでユーザーIDの動作を操作することが重要です。
Linuxにおけるプログラム実行メカニズム
execveシステムコール
- 機能:
execveは、最初の引数によって決定されるプログラムを開始します。2つの配列引数、argv(引数用)とenvp(環境用)を取ります。 - 動作: 呼び出し元のメモリ空間を保持しますが、スタック、ヒープ、およびデータセグメントを更新します。プログラムのコードは新しいプログラムによって置き換えられます。
- ユーザーIDの保持:
ruid、euid、および追加のグループIDは変更されません。- 新しいプログラムにSetUIDビットが設定されている場合、
euidに微妙な変更があるかもしれません。 - 実行後に
suidはeuidから更新されます。 - 文書: 詳細な情報は
execveman pageで確認できます。
system関数
- 機能:
execveとは異なり、systemはforkを使用して子プロセスを作成し、その子プロセス内でコマンドを実行します。 - コマンド実行:
shを介してコマンドを実行します。execl("/bin/sh", "sh", "-c", command, (char *) NULL);を使用します。 - 動作:
execlはexecveの一形態であり、同様に動作しますが、新しい子プロセスの文脈で実行されます。 - 文書: さらなる洞察は
systemman pageで得られます。
SUIDを持つbashとshの動作
bash:euidとruidの扱いに影響を与える-pオプションがあります。-pなしでは、bashはeuidをruidに設定します(最初に異なる場合)。-pがある場合、最初のeuidが保持されます。- 詳細は
bashman pageで確認できます。 sh:bashの-pに類似したメカニズムはありません。- ユーザーIDに関する動作は明示的に記載されていませんが、
-iオプションの下でeuidとruidの等価性の保持が強調されています。 - 追加情報は
shman pageで入手できます。
これらのメカニズムは、異なる動作を持ち、プログラムの実行と遷移のための多様なオプションを提供し、ユーザーIDの管理と保持における特定のニュアンスを持っています。
実行におけるユーザーIDの動作のテスト
例はhttps://0xdf.gitlab.io/2022/05/31/setuid-rabbithole.html#testing-on-jailから取得しています。さらなる情報はそちらで確認してください。
ケース1: systemとのsetuidの使用
目的: systemとbashをshとして組み合わせたときの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
分析:
ruidとeuidはそれぞれ 99 (nobody) と 1000 (frank) から始まります。setuidは両方を 1000 に揃えます。systemは/bin/bash -c idを実行します。これは sh から bash へのシンボリックリンクによるものです。bashは-pなしで実行され、euidをruidに合わせるため、両方が 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
分析:
euidがsetuidによって1000に設定されているにもかかわらず、bashは-pがないためにeuidをruid(99)にリセットします。
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
参考文献
tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:
HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
HackTricks