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中的文件指针漏洞分析相关推荐

  1. CVE-2020-1938 幽灵猫( GhostCat ) Tomcat-Ajp协议 任意文件读取/JSP文件包含漏洞分析

    title: CVE-2020-1938 幽灵猫( GhostCat ) Tomcat-Ajp协议 任意文件读取/JSP文件包含漏洞分析 date: 2021-05-19 01:07:08 categ ...

  2. 看个AV也中招之cve-2010-2553漏洞分析

    试想:某一天,你的基友给你了一个视频文件,号称是陈老师拍的苍老师的老师题材的最新电影.avi,你满心欢喜,在确定文件格式确实为avi格式后,愉快的脱下裤子准备欣赏,打开后却发现什么也没有,而随后你的基 ...

  3. 安全研究 | Jenkins 任意文件读取漏洞分析

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由云鼎实验室 发表于云+社区专栏 一.漏洞背景 漏洞编号:CVE-2018-1999002 漏洞等级:高危 Jenkins 7 月 18 ...

  4. Ruby on Rails路径穿越与任意文件读取漏洞分析(CVE-2019-5418)

    Ruby on Rails是一个 Web 应用程序框架,是一个相对较新的 Web 应用程序框架,构建在 Ruby 语言之上.它被宣传为现有企业框架的一个替代,而它的目标,就是让 Web 开发方面的生活 ...

  5. ThinkPHP文件包含漏洞分析

    出品|长白山攻防实验室(ID:A_Tree) 0x00 声明 以下内容,来自长白山攻防实验室的A_Tree作者原创,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责 ...

  6. FFmpeg任意文件读取漏洞分析

    6月24号的时候hackerone网站上公布了一个ffmpeg的本地文件泄露的漏洞,可以影响ffmpeg很多版本,包括3.2.2.3.2.5.3.1.2.2.6.8等等. hackerone网站上的漏 ...

  7. 文件包含漏洞分析和防御

    目录 简介 形成原因 文件包含函数 判断类型 文件包含 本地文件包含(LFI) 防御 本地包含技巧 php://协议的使用 data:协议 日志包含: session 远程文件包含(RFI) 文件读取 ...

  8. 【代码审计】CLTPHP_v5.5.3后台任意文件删除漏洞分析

      0x00 环境准备 CLTPHP官网:http://www.cltphp.com 网站源码版本:CLTPHP内容管理系统5.5.3版本 程序源码下载:https://gitee.com/chich ...

  9. 公开仓库中Docker镜像的漏洞分析结果发布

    Federacy的一名研究人员发布了一项报告,该报告分析了公开仓库中Docker镜像的漏洞.24%的镜像发现了明显的漏洞,其中基于Ubuntu的镜像漏洞最多,而基于Debian的镜像漏洞最少. \\ ...

最新文章

  1. linux文件编辑操作,Linux下文本编辑及其文件操作
  2. 《2019人工智能发展报告》!含计算机视觉、机器人等13个子领域(附链接)
  3. 【并发编程】对线程的初步认识
  4. (29)Verilog HDL系统函数:$finish
  5. domain or business logic
  6. 【图像隐写】基于matlab GUI DWT+DCT+PBFO改进图像水印隐藏提取【含Matlab源码 081期】
  7. C语言笔记 清屏(循环时不一闪一闪的) 光标移动到任意位置 带注释(详细)
  8. forum.php 下载,PHPWind Forums
  9. php mysql网页象棋源码_C# 中国象棋 游戏源码
  10. matlab 2017a界面,超详细干货:matlab2017a与 CCS 6.2联调设置
  11. mac如何配置环境变量
  12. 正规手游代理该怎么选?
  13. robots.txt存放的位置robots.txt文件的作用及写法 (搜索引擎)
  14. python写斗地主游戏_python斗地主
  15. WRF4.2安装过程全记录
  16. linux can远程帧,【值得收藏】详解Linux的CAN接口编程技巧
  17. 外网如何连接学校服务器
  18. 身份信息认证服务器,在线身份认证解决方案
  19. JS逆向之人口流动态势
  20. 使用 setoolkit 伪造站点窃取用户信息

热门文章

  1. git push 报错 error: src refspec master does not match any 解决
  2. 关于税务筹划的47个提醒!务必收藏!
  3. 2021中小企业税收筹划存在的问题,为什么要做税务筹划
  4. 化妆品致敏成分识别——python图像处理之文字识别+匹配
  5. Qt杂谈小技巧集锦()如何高效储存以及读取数据
  6. 初学构建小项目之仓库管理系统货物管理功能实现(四)
  7. python爬取百度图片之js逆向
  8. 美的c++研发岗面经---2020秋招
  9. 大数据将对广告业的未来产生什么影响?
  10. html form表单数据转为json传输