glibc中的文件指针漏洞分析
glib版本2.17
在上一篇文章(源码解析glibc中的pclose与fclose函数)中,初步了解到了glibc中的文件指针。
现在我们再来深入分析一下glibc文件指针,并解析一下其漏洞所在。
glibc中的文件结构
先了解一下普通文件的方式(注意3个标准文件描述符的链接顺序)
普通文件的操作
在文件libio/stdfile.c
中可以找到如下定义:
// DEF_STDFILE 这是个宏定义,里面包含了将标准输入、标准输出、标准出错用链表链接起来的操作
// 感兴趣的可以看看源码,其中用到的FILEBUF_LITERAL宏定义 libio/libioP.h 中
// FILEBUF_LITERAL 只是把文件结构体初始化
DEF_STDFILE(_IO_2_1_stdin_, 0, 0, _IO_NO_WRITES);
DEF_STDFILE(_IO_2_1_stdout_, 1, &_IO_2_1_stdin_, _IO_NO_READS);
DEF_STDFILE(_IO_2_1_stderr_, 2, &_IO_2_1_stdout_, _IO_NO_READS+_IO_UNBUFFERED);struct _IO_FILE_plus *_IO_list_all = &_IO_2_1_stderr_;
再来看看文件打开和关闭时的操作
//----------------------- 文件 打开 -----------------------
// 在调用fopen时,会调用这个函数
// 在文件libio/fileops.c中
void
_IO_new_file_init (fp)struct _IO_FILE_plus *fp;
{/* POSIX.1 allows another file handle to be used to change the positionof our file descriptor. Hence we actually don't know the actualposition before we do the first fseek (and until a following fflush). */fp->file._offset = _IO_pos_BAD;fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS;_IO_link_in (fp);fp->file._fileno = -1;
}/// 在文件libio/genops.c中
void
_IO_link_in (fp)struct _IO_FILE_plus *fp;
{if ((fp->file._flags & _IO_LINKED) == 0){fp->file._flags |= _IO_LINKED;
#ifdef _IO_MTSAFE_IO_IO_cleanup_region_start_noarg (flush_cleanup);// 对全局链表上锁,线程安全_IO_lock_lock (list_all_lock);run_fp = (_IO_FILE *) fp;_IO_flockfile ((_IO_FILE *) fp);
#endif// 在链表的表头插入,新打开的文件fp->file._chain = (_IO_FILE *) _IO_list_all;// 因此_IO_list_all 总是指向最新打开的文件_IO_list_all = fp;// 递增文件描述符的修改次数++_IO_list_all_stamp;
#ifdef _IO_MTSAFE_IO_IO_funlockfile ((_IO_FILE *) fp);run_fp = NULL;_IO_lock_unlock (list_all_lock);_IO_cleanup_region_end (0);
#endif}
}
//----------------------- 文件 打开 -----------------------//----------------------- 文件 关闭 -----------------------
// 在函数fclose中或者打开文件失败时会调用
// 在文件libio/genops.c中
void
_IO_un_link (fp)struct _IO_FILE_plus *fp;
{if (fp->file._flags & _IO_LINKED){struct _IO_FILE **f;
#ifdef _IO_MTSAFE_IO_IO_cleanup_region_start_noarg (flush_cleanup);// 上锁_IO_lock_lock (list_all_lock);run_fp = (_IO_FILE *) fp;_IO_flockfile ((_IO_FILE *) fp);
#endifif (_IO_list_all == NULL);else if (fp == _IO_list_all){_IO_list_all = (struct _IO_FILE_plus *) _IO_list_all->file._chain;// 递增文件描述符的修改次数++_IO_list_all_stamp;}else// 不知道为什么源码没有对齐,看起来挺蛋疼的// 在已打开的文件列表中找到要取消链接的文件指针,在链表中区中for (f = &_IO_list_all->file._chain; *f; f = &(*f)->_chain)if (*f == (_IO_FILE *) fp){// 指向下一个文件*f = fp->file._chain;// 递增文件描述符的修改次数++_IO_list_all_stamp;break;}fp->file._flags &= ~_IO_LINKED;
#ifdef _IO_MTSAFE_IO_IO_funlockfile ((_IO_FILE *) fp);run_fp = NULL;_IO_lock_unlock (list_all_lock);_IO_cleanup_region_end (0);
#endif}
}
//----------------------- 文件 关闭 -----------------------
管道文件的打开与关闭
在文件libio/iopopen.c
可以找到管理 管道文件 的链表结构
struct _IO_proc_file
{struct _IO_FILE_plus file;/* Following fields must match those in class procbuf (procbuf.h) */_IO_pid_t pid;struct _IO_proc_file *next;
};
static struct _IO_proc_file *proc_file_chain;
管道文件的打开与关闭跟普通文件都是一样会操作链表,这里就不在重复说明了。
文件指针中的漏洞
文件断链时的死循环漏洞
这种漏洞比较容易检测到,具体的表现为了在关闭文件句柄时,一直卡在fclose
函数中,无法跳出。
int main()
{FILE *fpReader_1 = fopen("1.txt","w");FILE *fpReader_2 = fopen("2.txt","w");if(NULL == fpReader_1 || NULL == fpReader_2){printf("open file error \n");}// 在执行下面的操作之前,_chain 指向的是fpReader_1 // 执行下面的操作之后,打开的文件链表中形成了一个环fpReader_2->_chain = fpReader_2;// fclose函数会调用unlink函数,以便将fpReader_1指向的文件从链表中剔除。// unlink函数会从表头(这里是fpReader_2)开始一个个往下找。// 由于next指针(即变量_chain)被替换,从而形成环,导致for循环无法终止。if (fclose(fpReader_1) != 0){printf("%s \n", strerror(errno));}else{printf("close success\n");}return 0;
}
虚表执行漏洞
在 2.24版本之后,添加了地址检查函数,如果覆盖了虚表,则会报如下错误:
Fatal error: glibc detected an invalid stdio handle
Aborted (core dumped)
上篇文章讲到,无论是虚表中的__close
函数在关闭文件指针时是一定会被执行的。而虚表又只是一个结构体指针,指向的内容可以是动态分配的内容(默认的虚表都被保护的内存地址中),因此我们可以通过覆盖虚表来实现一些操作。
// 这里为了增加可读性,我仿造了一个 IO_jump_t 出来,部分的函数指针类型会对不上,但这不影响测试。
// 当然也可以通过指针进行操作,但我认为可读性不高。
typedef int (*MY_IO_close_t)(_IO_FILE *);
struct MY_IO_jump_t {size_t __dummy;size_t __dummy2;MY_IO_close_t __finish;MY_IO_close_t __overflow;MY_IO_close_t __underflow;MY_IO_close_t __uflow;MY_IO_close_t __pbackfail;MY_IO_close_t __xsputn;MY_IO_close_t __xsgetn;MY_IO_close_t __seekoff;MY_IO_close_t __seekpos;MY_IO_close_t __setbuf;MY_IO_close_t __sync;MY_IO_close_t __doallocate;MY_IO_close_t __read;MY_IO_close_t __write;MY_IO_close_t __seek;MY_IO_close_t __close;MY_IO_close_t __stat;MY_IO_close_t __showmanyc;MY_IO_close_t __imbue;
};
// 仿造一个 IO_FILE_plus 结构体,提高可读性
struct MY_IO_FILE_plus {_IO_FILE file;const struct MY_IO_jump_t *vtable;
};// 用于测试的函数,会覆盖原有的close动作
int test_close(_IO_FILE *fp) {// 注意!!!!!!!!!!!// 这里是 rm 操作// 千万不要改成 rm -rf /// !!!!!!!!!!!!!!!!!!!!!FILE *p = popen("rm -rf test.txt", "re");!!! // 去掉这3个感叹号即可编译成功pclose(p);return 0;
}int main() {for (unsigned int i = 0; i < 10; ++i) {FILE *fpReader;fpReader = fopen("1.txt", "w");if (NULL == fpReader) {printf("open file error \n");break;}struct MY_IO_FILE_plus *p = (struct MY_IO_FILE_plus *)fpReader;struct MY_IO_jump_t *pNewJump =(struct MY_IO_jump_t *)malloc(sizeof(struct MY_IO_jump_t));// 复制原有的虚表,保留其他操作,只改变close动作memcpy(pNewJump, p->vtable, sizeof(MY_IO_jump_t));pNewJump->__close = test_close;p->vtable = pNewJump;printf("close\n");if (fclose(fpReader) == -1) {printf("%s \n", strerror(errno));} else {printf("close success\n");}sleep(1);}return 0;
}
通过上面代码,我们可以实现删库跑路的动作。
glibc中的文件指针漏洞分析相关推荐
- CVE-2020-1938 幽灵猫( GhostCat ) Tomcat-Ajp协议 任意文件读取/JSP文件包含漏洞分析
title: CVE-2020-1938 幽灵猫( GhostCat ) Tomcat-Ajp协议 任意文件读取/JSP文件包含漏洞分析 date: 2021-05-19 01:07:08 categ ...
- 看个AV也中招之cve-2010-2553漏洞分析
试想:某一天,你的基友给你了一个视频文件,号称是陈老师拍的苍老师的老师题材的最新电影.avi,你满心欢喜,在确定文件格式确实为avi格式后,愉快的脱下裤子准备欣赏,打开后却发现什么也没有,而随后你的基 ...
- 安全研究 | Jenkins 任意文件读取漏洞分析
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由云鼎实验室 发表于云+社区专栏 一.漏洞背景 漏洞编号:CVE-2018-1999002 漏洞等级:高危 Jenkins 7 月 18 ...
- Ruby on Rails路径穿越与任意文件读取漏洞分析(CVE-2019-5418)
Ruby on Rails是一个 Web 应用程序框架,是一个相对较新的 Web 应用程序框架,构建在 Ruby 语言之上.它被宣传为现有企业框架的一个替代,而它的目标,就是让 Web 开发方面的生活 ...
- ThinkPHP文件包含漏洞分析
出品|长白山攻防实验室(ID:A_Tree) 0x00 声明 以下内容,来自长白山攻防实验室的A_Tree作者原创,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责 ...
- FFmpeg任意文件读取漏洞分析
6月24号的时候hackerone网站上公布了一个ffmpeg的本地文件泄露的漏洞,可以影响ffmpeg很多版本,包括3.2.2.3.2.5.3.1.2.2.6.8等等. hackerone网站上的漏 ...
- 文件包含漏洞分析和防御
目录 简介 形成原因 文件包含函数 判断类型 文件包含 本地文件包含(LFI) 防御 本地包含技巧 php://协议的使用 data:协议 日志包含: session 远程文件包含(RFI) 文件读取 ...
- 【代码审计】CLTPHP_v5.5.3后台任意文件删除漏洞分析
0x00 环境准备 CLTPHP官网:http://www.cltphp.com 网站源码版本:CLTPHP内容管理系统5.5.3版本 程序源码下载:https://gitee.com/chich ...
- 公开仓库中Docker镜像的漏洞分析结果发布
Federacy的一名研究人员发布了一项报告,该报告分析了公开仓库中Docker镜像的漏洞.24%的镜像发现了明显的漏洞,其中基于Ubuntu的镜像漏洞最多,而基于Debian的镜像漏洞最少. \\ ...
最新文章
- linux文件编辑操作,Linux下文本编辑及其文件操作
- 《2019人工智能发展报告》!含计算机视觉、机器人等13个子领域(附链接)
- 【并发编程】对线程的初步认识
- (29)Verilog HDL系统函数:$finish
- domain or business logic
- 【图像隐写】基于matlab GUI DWT+DCT+PBFO改进图像水印隐藏提取【含Matlab源码 081期】
- C语言笔记 清屏(循环时不一闪一闪的) 光标移动到任意位置 带注释(详细)
- forum.php 下载,PHPWind Forums
- php mysql网页象棋源码_C# 中国象棋 游戏源码
- matlab 2017a界面,超详细干货:matlab2017a与 CCS 6.2联调设置
- mac如何配置环境变量
- 正规手游代理该怎么选?
- robots.txt存放的位置robots.txt文件的作用及写法 (搜索引擎)
- python写斗地主游戏_python斗地主
- WRF4.2安装过程全记录
- linux can远程帧,【值得收藏】详解Linux的CAN接口编程技巧
- 外网如何连接学校服务器
- 身份信息认证服务器,在线身份认证解决方案
- JS逆向之人口流动态势
- 使用 setoolkit 伪造站点窃取用户信息