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/sfac
functions) 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
ArrayBuffer
andArray
objects on the heap. - Load the malicious font triggering the vulnerability by corrupting one byte
of the
length
field of theArrayBuffer
. - Find corrupted
ArrayBuffer
, allowing limited R/W. - Override
length
of the adjacentArray
using the corruptedArrayBuffer
to have complete arbitrary R/W and setup theaddrof
primitive. - Use the arbitrary R/W and
addrof
primitive to compute the ROP chain and write the shellcode in memory. - Without CFG, the exploit simply overrides the
TextSize
VTable of aTextBox
object and trigger its call to hijack the execution flow. - With CFG on, the exploit calls
RtlCaptureContext
to 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