👍
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 许可协议。转载请注明出处!