メインコンテンツ

権限を削除する順序が正しくありません

昇格された権限のうち低い権限より前に高い権限を削除

説明

この欠陥は、setuidsetgid などの関数が誤った順序 (昇格された権限のうち下位の権限より先に、上位の権限が削除される) で使用された場合に発生します。たとえば、昇格された補助グループ権限を削除する前に、昇格されたプライマリ グループ権限を削除した場合です。

リスク

誤った順序で権限を削除すると、低い権限を削除するために必要な高い権限が先に削除されてしまう可能性があります。順序が正しくないと権限が削除されず、プログラムのセキュリティが侵害される可能性があります。

修正方法

昇格された権限を削除する場合は以下の順序に従います。

  • (昇格された) 補助グループ権限を削除し、次に (昇格された) プライマリ グループ権限を削除します。

  • (昇格された) プライマリ グループ権限を削除し、次に (昇格された) ユーザー権限を削除します。

すべて展開する

#define _BSD_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <stdlib.h>
#define fatal_error() abort()

static void sanitize_privilege_drop_check(uid_t olduid, gid_t oldgid)
{
    if (seteuid(olduid) != -1)
    {
        /* Privileges can be restored, handle error */
        fatal_error();
    }
    if (setegid(oldgid) != -1)
    {
        /* Privileges can be restored, handle error */
        fatal_error();
    }
}
void badprivilegedroporder(void) {
    uid_t
        newuid = getuid(),
        olduid = geteuid();
    gid_t
        newgid = getgid(),
        oldgid = getegid();

    if (setuid(newuid) == -1) {
        /* handle error condition */
        fatal_error();
    }
    if (setgid(newgid) == -1)  { 
        /* handle error condition */
        fatal_error();
    }
    if (olduid == 0) {
        /* drop ancillary groups IDs only possible for root */
        if (setgroups(1, &newgid) == -1) {
            /* handle error condition */
            fatal_error();
        }
    }

    sanitize_privilege_drop_check(olduid, oldgid);
}

この例では、2 つの権限を不適切な順序で削除しています。setgid はグループ権限の削除を試みます。ただし、setgid がこの関数を実行するにはユーザー権限が必要です。しかし、ユーザー権限はこれよりも前に setuid を使用して削除されています。グループ権限を削除後、この関数は setgroups を使用して補助グループ権限の削除を試みます。このタスクには setgid で削除された高い権限のプライマリ グループが必要です。権限を削除する順序が不適切なため、この関数の最後で、おそらくグループ権限を再取得することになります。

修正 - 権限を削除する順序の反転

考えられる 1 つの修正方法として、最下位レベルの権限を最初に削除します。この修正では、補助グループ権限を削除し、次にプライマリ グループ権限、最後にユーザー権限を削除します。

#define _BSD_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <stdlib.h>
#define fatal_error() abort()

static void sanitize_privilege_drop_check(uid_t olduid, gid_t oldgid)
{
    if (seteuid(olduid) != -1)
    {
        /* Privileges can be restored, handle error */
        fatal_error();
    }
    if (setegid(oldgid) != -1)
    {
        /* Privileges can be restored, handle error */
        fatal_error();
    }
}
void badprivilegedroporder(void) {
    uid_t
        newuid = getuid(),
        olduid = geteuid();
    gid_t
        newgid = getgid(),
        oldgid = getegid();

    if (olduid == 0) {
        /* drop ancillary groups IDs only possible for root */
        if (setgroups(1, &newgid) == -1) {
            /* handle error condition */
            fatal_error();
        }
    }
    if (setgid(getgid()) == -1)  {
        /* handle error condition */
        fatal_error();
    }
    if (setuid(getuid()) == -1) {
        /* handle error condition */
        fatal_error();
    }

    sanitize_privilege_drop_check(olduid, oldgid);
}

結果情報

グループ: セキュリティ
言語: C | C++
既定値: オフ
コマンド ライン構文: BAD_PRIVILEGE_DROP_ORDER
影響度: High

バージョン履歴

R2016b で導入