👍
bashcommit 231df822d2ec2096d4ccf8d0b9e6a9c6bbfd3b69 (HEAD -> master, origin/master, origin/HEAD) Author: Thomas Bernard <miniupnp@free.fr> Date: Sat Mar 4 11:48:58 2023 +0100
在输入特定构造的gif文件之后可以导致目标segment fault
bash$ CC="${CarpetFuzz}/fuzzer/afl-clang-fast -fsanitize=address -g" CFLAGS+=-DNGIFLIB_NO_FILE make
$ ./gif2tga -i ./poc



漏洞存在于158行中 要求条件使用NGIFLIB_MODE_INDEXED其实就是加上-i参数 可以看到本身只是一个写入操作 将当前GIF图像的palette写入到目标的tga文件中

其中img来自113行的gif->cur_img 而gif来自107行的err = LoadGif(gif) 之前的gif变量只是一个初始化 对其进行分配内存空间 追入LoadGif

其中的cur_img相关的操作在ngiflib.c::864附近 没有看到palette相关操作 追入DecodeGifImg

追入DecodeGifImg后 关于palette相关操作在494行附近 其分支是由flags&128决定的 经过动态调试发现flags == 0 直接进入下面的分支 也就是i->palette = i->parent->palette 而这个i->parent就是上级函数中的g

经过查询资料 每个GIF图片中都可能包含多个图片信息(废话 不然为啥有GIF动图) 所以为了区分每一帧的图片信息 采用标志位
0x2C标志着每个图像的开始 然后前4个WORD分别为x偏移量 y偏移量 图像宽 图像高 经过审阅DecodeGIFImg内容发现在483行之前已经读取过相应数据 而GetByte和GetWord内部有个计数器 类似fseek的作用 指定当前读到哪里防止越界读 本来是好心 但是内部审查不严 当可能越界读时不抛出异常而是直接返回0 造成了flags == 0
返回上级查看g->palette 相关操作在714行附近 分支决定了相关值直接是NULL还是从文件中取

tmp相关操作在694行 在此之前对于文件流的操作有校验文件头和版本 取宽 取高

那么就是文件中的此位置 经过动态调试确认正确 程序会流向g->palette = NULL


那么至此 因为特定的flag导致GIF的palette属性为NULL 进而搭配GetByte的审查不严格 导致了GIF下每帧的palette属性都为NULL 最终在生成tga文件时造成了无效访问 且由此发现该程序对GIF文件结尾特定标志位0x3B校验不严格
cstatic u8 GetByte(struct ngiflib_gif * g) {
#ifndef NGIFLIB_NO_FILE
if(g->mode & NGIFLIB_MODE_FROM_MEM) {
#endif /* NGIFLIB_NO_FILE */
if (g->input.buffer.count > 0) {
g->input.buffer.count--;
return *(g->input.buffer.bytes++);
} else {
return 0;
}
#ifndef NGIFLIB_NO_FILE
} else {
#ifdef DEBUG
int c = getc(g->input.file);
if (c != EOF)
return (u8)c;
else {
if(g->log) fprintf(g->log, "getc() returned EOF !\n");
return 0;
}
#else
return (u8)(getc(g->input.file));
#endif
}
#endif /* NGIFLIB_NO_FILE */
}
本文作者:Du4t
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!