CVE-2023-26369: Adobe Acrobat PDF Reader RCE when processing TTF fonts
Clement Lecigne, Google Threat Analysis Group
The Basics
Disclosure or Patch Date: September, 12, 2023
Product: Adobe Acrobat Reader on Windows and MacOS
Advisory: https://helpx.adobe.com/security/products/acrobat/apsb23-34.html
Affected Versions: 23.003.20284 and earlier versions
First Patched Version: 23.006.20320
Issue/Bug Report: N/A
Patch CL: N/A (closed source)
Bug-Introducing CL: N/A
Reporter(s): Anonymous
The Code
Proof-of-concept:
TTF font with the following bitmap tables.
EBLC :
     version : 0x20000
     numSizes : 0x1
     [-] 0th bitmapSizeTable
         indexSubTableArrayOffset : 0x38
         indexTablesSize : 0x100
         numberOfIndexSubTables : 0x2
         colorRef : 0x0
         hori : 0b fe 08 01 00 00 00 00 0b fe 00 00
         vert : 00 00 00 00 00 00 00 00 00 00 00 00
         startGlyphIndex : 0x4d
         endGlyphIndex : 0x4e
         ppemX : 0xfa
         ppemY : 0xfa
         bitDepth : 0x1
         flags : 0x1
         [-] 0th subArray
             firstGlyphIndex : 0x4d
             lastGlyphIndex : 0x4d
             additionalOffsetToIndexSubtable : 0x10
             indexFormat : 0x1
             imageFormat : 0x8
             imageDataOffset : 0x4
             offsetArray0 : 0x0
             offsetArray1 : 0x0
         [-] 1th subArray
             firstGlyphIndex : 0x4e
             lastGlyphIndex : 0x4e
             additionalOffsetToIndexSubtable : 0x20
             indexFormat : 0x1
             imageFormat : 0x1
             imageDataOffset : 0x4
             offsetArray0 : 0x0
             offsetArray1 : 0xc
EBDT :
     version : 0x20000
     [-] 0th metrics
         height : 0xa2
         width : 0x61
         BearingX : 0x4
         BearingY : 0x9
         Advance : 0x8
         pad : 0x0
         numComponents : 0x1
         [-] 0th ComponentArray
             glyphCode : 0x4e
             xOffset : 0x20
             yOffset : 0xa3
     [-] 1th metrics
         height : 0xa2
         width : 0x61
         BearingX : 0x4
         BearingY : 0x9
         Advance : 0x8
         pad : 0x0
         numComponents : 0x1
         [-] 0th ComponentArray
             glyphCode : 0x4e
             xOffset : 0x20
             yOffset : 0xa3
Note that the font has the following EBSC table which prevents the font from
being loaded in many font parsing libraries except libCoolType from Adobe.
2. 'EBSC' - checksum = 0x00000000, offset = 0xffffffff, len = 4294967295
Exploit sample: Not public.
Did you have access to the exploit sample when doing the analysis? Yes
The Vulnerability
Bug class: Heap buffer out-of-bounds write
Vulnerability details:
An out of bound (OOB) write vulnerability exists in sfac_GetSbitBitmap when
parsing a malformed TrueType font in Adobe libCoolType.
By enabling PageHeap for Adobe Reader, we get the following crash in
CoolType!CTCleanup+0x3ed54:
rax=00000000000000ff rbx=0000000000000001 rcx=fffffffff8a29014
rdx=0000000000000004 rsi=000000000000ffff rdi=0000000000000004
rip=00007ffc84736144 rsp=000000ab75f56fa0 rbp=0000000000000000
 r8=0000000000000010  r9=0000027bc9557000 r10=0000027bc1f80010
r11=0000000000000004 r12=000000000000fff3 r13=0000000000000001
r14=0000027b76539ba0 r15=0000000000000001
iopl=0         nv up ei ng nz na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010286
CoolType!CTCleanup+0x3ed54:
00007ffc`84736144 42080409        or      byte ptr [rcx+r9],al ds:0000027b`c1f80014=??
The code is attempting to bitwise OR the byte located at r9[rcx] with 0xFF
(al) and r9[rcx] is out of bound.
By tracing the code, we noticed that r9 is a bitmap buffer which was
previously allocated in sbit_GetMetrics using the following formula and data
from the font file.
bitmap_size
 = (((EBDT[0].width + 0x1F) >> 3) & 0xFFFC) * EBDT[0].height
 = (((0x61+0x1f)>>3)&0xfffc)*0xa2 = 0xA20
The OOB write happens in sfac_GetSbitBitmap when glyphs are merged together in
the bitmap buffer. To properly position the glyphs, each glyph has layout
information located in the EBDT table, including height, width, advance, X and
Y offsets. GetSbitComponent makes recursive calls to sfac_GetSbitBitmap to
handle the glyphs one by one. The problem with sfac_GetSbitBitmap is that it
merges glyphs without first checking if the X and Y offsets are within the
bounds of the bitmap buffer. For example with the font above, the OOB happens
when positioning the second glyph on the vertical axis (Y offset).
index = glyph[curr].yOffset * (glyph[curr].Advance+glyph[curr-1].Advance)
  = 0xa3 * (0x8 + 0x8)
  = 0xa30
0xa30 is outside of the allocated bitmap buffer.
Patch analysis:
The vulnerability was patched by adding multiple bound-checks [0] [1] before
entering the loop transforming the bitmaps in sfac_GetSbitBitmap. The size
allocated for the bitmap buffer by sbit_GetMetrics is also now passed as a new
parameter (max_sz) to sfac_GetSbitBitmap.
Pseudo-code:
int sfac_GetSbitBitmap(..., uint16 a12_yOffset, uint16 curr_advance, ..., uint32 max_sz)
...
    v25 = a12_yOffset * curr_advance;           // size
    if ( v25 >= max_sz )                        // [0] bound check
    {
        // err
        return 5120;
    }
...
    if (height) n_iter = a12_yOffset + height;
    max_idx = a13_somesize * n_iter;
    if ( max_idx >= lower_bound && max_idx < max_sz )   // [1] bound check
    {
...
        do
        {
...
            do
            {
                *((_BYTE *)data + idx++) |= *(_BYTE *)data;     // OOB before
                data = (unsigned __int16 *)((char *)data + 1);
                n_iter--;
            } while (n_iter)
...
            idx += curr_advance;
            --height;
        }
        while (height);
    }
Thoughts on how this vuln might have been found (fuzzing, code auditing, variant analysis, etc.):
3 possible options:
- Found via smart TTF fuzzing against the libCoolType shipped with Adobe Reader.
 - Binary diffing various library forks (e.g. both TrueType from MSFT and
CoolType from Adobe share the 
sbit/sfacfunctions) to spot discrepancies. The vulnerability is very similar to CVE-2011-3402 affecting the TrueType font parsing engine in win32k and exploited in the wild by Duqu. - Code auditing around bitmap size calculation and usage.
 
Out of these options, I consider 1) or 2) to be the most likely ones.
(Historical/present/future) context of bug: N/A
The Exploit
Exploit strategy (or strategies):
Through the vulnerability to achieve out-of-bounds write, and corrupting adjacent EScript objects previously allocated from the PDF.
Exploit flow:
- Activate LFH allocator on various bucket sizes by allocating multiple objects of specific size from Javascript.
 - Spray a pair of 
ArrayBufferandArrayobjects on the heap. - Load the malicious font triggering the vulnerability by corrupting one byte
of the 
lengthfield of theArrayBuffer. - Find corrupted 
ArrayBuffer, allowing limited R/W. - Override 
lengthof the adjacentArrayusing the corruptedArrayBufferto have complete arbitrary R/W and setup theaddrofprimitive. - Use the arbitrary R/W and 
addrofprimitive to compute the ROP chain and write the shellcode in memory. - Without CFG, the exploit simply overrides the 
TextSizeVTable of aTextBoxobject and trigger its call to hijack the execution flow. - With CFG on, the exploit calls 
RtlCaptureContextto leak the stack address and then overrides return pointers on the stack to redirect the execution flow to their ROP chain. 
Known cases of the same exploit flow:
Most exploits abusing memory corruption vulnerability in Adobe Reader such as CVE-2020-9715 have a similar exploit flow.
Part of an exploit chain?
Yes, this bug was used by government backed actors in North Korea as a way to get RCE within Adobe Reader, we didn't manage to retrieve or get access to the other stages of the chain like the sandbox escape.
The Next Steps
Variant analysis
Areas/approach for variant analysis (and why):
- Run extensive fuzzing of the libCoolType TTF parsers.
 - Code auditing around bitmap usage and size computation in TTF parsers.
 - Analyze differences between Microsoft and Adobe libCoolType to spot any discrepancies (e.g. missing bound checks).
 
Found variants:
N/A
Structural improvements
Ideas to kill the bug class:
Rewrite font parsing code in a memory safe language.
Ideas to mitigate the exploit flow:
- Isolate all or some specific ESOBjects into their own dedicated heap/partition.
 - Sandbox/isolate font parsing code.
 - Disable javascript processing in Adobe Reader.
 
0-day detection methods
What are potential detection methods for similar 0-days? Meaning are there any ideas of how this exploit or similar exploits could be detected as a 0-day?
N/A
Other References
- https://blog.google/threat-analysis-group/active-north-korean-campaign-targeting-security-researchers/
 - https://www.zerodayinitiative.com/blog/2020/9/2/cve-2020-9715-exploiting-a-use-after-free-in-adobe-reader
 - https://exploitshop.wordpress.com/2012/01/18/ms11-087-aka-duqu-vulnerability-in-windows-kernel-mode-drivers-could-allow-remote-code-execution/
 - https://improsec.com/tech-blog/bypassing-control-flow-guard-in-windows-10