40

これは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)私を変えましょeuid0

4

4 に答える 4

36

2つのケースがあります、

  1. setuidプログラムの実行中にroot権限を一時的に削除したい
  2. setuidプログラムの実行中にroot権限を永久に削除したい...
  • euidを実際のユーザーIDに設定してから、uidを任意の値に変更することで、一時的にこれを行うことができます。後でroot権限が必要になったときに、rootにsetuidすると、有効なユーザーIDがrootに戻ります。これは、保存されているユーザーIDが変更されていないためです。
  • uidをすぐに特権の低いユーザーIDに変更することで、特権を完全に削除できます。この後、root権限を取り戻すことができなくても。

ケース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       |
               |    |      |            |
               +------------------------+

この場合、root権限を取り戻すことはできません。これは、次のコマンドで確認できます。

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が前述のように変更されていることを確認できます。

euidがrootであり、uidを変更すると、特権は完全に削除されます。有効なユーザーIDがrootでない場合、保存されたユーザーIDは変更されず、プログラムでいつでもroot特権を取り戻すことができます。

于 2011-12-14T05:04:24.453 に答える
11

説明 setuid()は、呼び出しプロセスの実効ユーザーIDを設定します。呼び出し元の有効なUIDがrootの場合、実際の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権限を取り戻すことはできません。

したがって、root権限を一時的に削除し、非特権ユーザーのIDを想定し、後でroot権限を取り戻すことを希望するset-user-ID-rootプログラムは、setuid()を使用できません。これは、seteuid(2)を使用して実行できます。

(Linuxプログラマーマニュアル、2014-09-21、ページからsetuid.2

于 2011-12-14T04:01:42.970 に答える
5

おお!これらの機能を正しく使用することは困難です。

マニュアルページには、setuidが実際の保存された有効なuidを変更すると記載されています。したがって、setuid(1000)を呼び出した後、3つすべてが1000に変更されます。

これは、あなたがeuid 0である場合にのみ当てはまりますsetuid(0)。ただし、呼び出した時点では、あなたはeuid 1000であり、uid 0を保存getresuid(2)しています(たとえば、チェックしてください)。そのため、特権を取り戻すことができます。

于 2011-12-14T05:19:06.323 に答える
3

コード:

#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のプロセスには、REAL uid、EFFECTIVE uid、SAVEDuidの3つのuidがあります。
条件1.euidがrootの場合、setuidまたはseteuidは任意のuidに設定できますが、副作用があります。setuid(seteuidではない)を使用すると、3つすべてをROOTではない同じuidに設定できます。その場合、プロセスは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):Cond 2、euidを0(suid)に設定
4. setuid(1000):Cond 1、3つのuidすべてを1000に設定
5. setuid(0):Cond 2、3つのuidすべてが0に等しくないため、' tを0に設定し、ret=-1で失敗しました

于 2019-04-10T17:00:31.527 に答える