章节大纲

  • 本实验在 SEEDUbuntu20.04 VM 中测试可行。你可以在本页面右端选择虚拟机版本为 SEEDUbuntu20.04,点击“创建虚拟机”来获取虚拟机平台的临时用户名与密码,登录虚拟机平台即可获得一台预先构建好的 SEEDUbuntu20.04 VM,该虚拟机以及用户名密码将在开启 24 小时后自动销毁。
     
    你也可以在其他 VM、物理机器以及云端 VM 上自行配置环境进行实验,但我们不保证实验能在其他 VM 下成功。实验所需的文件可从下方下载,解压后会得到一个名为 Labsetup 的文件夹,该文件夹内包含了完成本实验所需的所有文件。
      • Ubuntu 操作系统里有内置的防止竞态条件攻击的安全措施,它限制谁可以跟随符号链接。根据文档说明,全局可写的粘性目录(例如 /tmp)中的符号链接只能在符号链接的所有者和跟随者和目录所有者的其中之一相匹配时才能被跟随。Ubuntu 20.04 还引入了一种新的安全机制,防止 root 用户向由他人拥有的 /tmp 文件中写入数据。为了关闭这些防护措施,请使用以下命令:
         
        // 在Ubuntu 20.04上,使用如下命令:
        $ sudo sysctl -w fs.protected_symlinks=0
        $ sudo sysctl fs.protected_regular=0
        
        // 在Ubuntu 16.04上,使用如下命令:
        $ sudo sysctl -w fs.protected_symlinks=0
      • 以下是一个看似无害的程序(vulp.c),它包含一个竞态条件漏洞。
         
        #include <stdio.h>
        #include<unistd.h>
        
        int main()
        {
           char * fn = "/tmp/XYZ";
           char buffer[60];
           FILE *fp;
        
           /* 获取用户输入 */
           scanf("%50s", buffer );
        
           if(!access(fn, W_OK)){                 🅰
              fp = fopen(fn, "a+");               🅱
              fwrite("\n", sizeof(char), 1, fp);
              fwrite(buffer, sizeof(char), strlen(buffer), fp);
              fclose(fp);
           }
           else printf("No permission \n");
        }

        该程序是一个拥有 root 权限的 setuid 程序,它会在临时文件 /tmp/XYZ 的末尾添加用户输入的内容。由于代码以 root 权限运行(有效用户 ID 为 0),因此可以覆盖任何文件。为了防止自己意外覆盖他人的文件,程序首先检查自己的真实用户 ID 是否具有对文件 /tmp/XYZ 的修改权限,这就是第 🅰 行 access()调用的目的。如果确实有权限,程序会在第 🅱 行打开该文件并往其中添加用户输入的内容。
         
        乍一看似乎这个程序没有问题。但是,在检查(access)和使用(fopen)之间存在一个时间窗口,在这段时间里,被 access() 检查的文件可能与被 fopen() 使用的文件不是同一个,尽管它们具有相同的文件名 /tmp/XYZ。如果攻击者能够在该时间窗口内使 /tmp/XYZ 成为指向 /etc/passwd 的符号链接,则可以导致用户输入被添加到 /etc/passwd中,由此获得 root 权限。由于该漏洞运行在 root 权限下,因此它有权限修改任何文件。
         
        我们首先编译上述代码,并将可执行程序转换为一个由 root 拥有的 setuid 程序:
         
        $ gcc vulp.c -o vulp
        $ sudo chown root vulp
        $ sudo chmod 4755 vulp