Talos Vulnerability Report


Atlantis Word Processor Windows Enhanced Metafile Code Execution Vulnerability

October 1, 2018
CVE Number



An exploitable heap-based buffer overflow vulnerability exists in the Windows enhanced metafile parser of Atlantis Word Processor, version A specially crafted image embedded within a document can cause an undersized allocation, resulting in an overflow when the application tries to copy data into it. An attacker must convince a victim to open a document in order to trigger this vulnerability.

Tested Versions

Atlantis Word Processor

start    end        module name
00400000 007f0000   awp      C (no symbols)           
    Loaded symbol image file: awp.exe
    Image path: C:\Program Files (x86)\Atlantis\awp.exe
    Image name: awp.exe
    File version:
    Product version:

Product URLs


CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H


CWE-122: Heap-based Buffer Overflow


Atlantis' Word Processor is a traditional word processor that is aimed to be both portable, flexible, and full of a number of features. This word processor is ideally suited for writers and students and provides a number of useful features that can help simplify and even improve one's writing. Atlantis Word Processor is fully compatible with other word processors, such as Microsoft Office Word 2007 and even has several similarities. Atlantis also has the capability to encrypt document files and fully customize the interface. This application is written in Delphi and contains the majority of its capabilities within a single relocatable binary.

When processing a Microsoft Word XML Document, the application has the ability to embed various images within the document. There are a number of image types, and these are handled by a class named TDocPicture. When constructing a TDocPicture class, the following function will be executed. This function will first check the header of the file to see if it matches a known signature for the PNG, GIF, or JFIF image formats. If the signature is not detected, then the application will determine the actual image type by checking the file extension embedded within the document against a global list. This enumeration is then passed to the function call at [1].

005e6820 55              push    ebp
005e6821 8bec            mov     ebp,esp
005e6823 83c4d0          add     esp,0FFFFFFD0h
005e6826 53              push    ebx
005e6827 56              push    esi
005e6828 57              push    edi
/* check the fingerprint of a few image file format types */
005e6941 55              push    ebp
005e6942 8bd3            mov     edx,ebx                    // Image type enumeration
005e6944 8bc6            mov     eax,esi
005e6946 e80dfeffff      call    awp+0x1e6758 (005e6758)    // [1]
005e694b 59              pop     ecx
005e694c 84c0            test    al,al
005e694e 7438            je      awp+0x1e6988 (005e6988)

Inside the function call at 0x5e6758, the application will assign the image type enumeration to a local variable at [2]. Later at [3], the application will pass the image type enumeration as an argument to a function call. This function is responsible for constructing an instance of the class specific to the detected image file format. At [4], the application will enter a case statement and will then branch to the case that instantiates the constructor for the image format type specified by the enumeration.

005e6758 55              push    ebp
005e6759 8bec            mov     ebp,esp
005e675b 51              push    ecx
005e675c 53              push    ebx
005e675d 56              push    esi
005e675e 8855ff          mov     byte ptr [ebp-1],dl        // [2] Image type enumeration
005e6761 8bf0            mov     esi,eax
005e67e2 55              push    ebp
005e67e3 8a55ff          mov     dl,byte ptr [ebp-1]        // Image type enumeration
005e67e6 8bc6            mov     eax,esi
005e67e8 e88bfaffff      call    awp+0x1e6278 (005e6278)    // [3] \
005e67ed 59              pop     ecx
005e67ee 8845fe          mov     byte ptr [ebp-2],al
005e67f1 807dfe00        cmp     byte ptr [ebp-2],0
005e67f5 7521            jne     awp+0x1e6818 (005e6818)
005e6278 55              push    ebp
005e6279 8bec            mov     ebp,esp
005e627b 83c4e4          add     esp,0FFFFFFE4h
005e627e 53              push    ebx
005e627f 56              push    esi
005e6280 57              push    edi
005e6281 33c9            xor     ecx,ecx
005e6283 894de8          mov     dword ptr [ebp-18h],ecx
005e62a4 33c0            xor     eax,eax
005e62a6 8ac2            mov     al,dl                      // [4]
005e62a8 83f809          cmp     eax,9
005e62ab 0f879c030000    ja      awp+0x1e664d (005e664d)
005e62b1 ff2485b8625e00  jmp     dword ptr awp+0x1e62b8 (005e62b8)[eax*4]
005e62b8 e062            loopne  awp+0x1e631c (005e631c)

When handling a Windows metafile, it will branch to the following case. This handler will first construct an instance of a TMetaFile object at [5] and then store it to a variable. A method will be called at [6] immediately afterward with the path to the actual image file. This method is a wrapper that will instantiate a TFileStream object and then proceed to use the object to load the image file for usage by the TDocPicture object.

005e63e1 b201            mov     dl,1
005e63e3 a160fb4000      mov     eax,dword ptr [awp+0xfb60 (0040fb60)]  // TMetaFile
005e63e8 e807bde2ff      call    awp+0x120f4 (004120f4)                 // [5]
005e63ed 8945f0          mov     dword ptr [ebp-10h],eax                // variable containing TMetaFile instance
005e63f0 33c0            xor     eax,eax
005e63f2 55              push    ebp
005e63f3 6896645e00      push    offset awp+0x1e6496 (005e6496)
005e63f8 64ff30          push    dword ptr fs:[eax]
005e63fb 648920          mov     dword ptr fs:[eax],esp
005e63fe 8b4508          mov     eax,dword ptr [ebp+8]                  // frame
005e6401 8b4008          mov     eax,dword ptr [eax+8]                  // caller frame
005e6404 8b50fc          mov     edx,dword ptr [eax-4]                  // path to image file
005e6407 8b45f0          mov     eax,dword ptr [ebp-10h]                // variable containing TMetaFile instance
005e640a 8b08            mov     ecx,dword ptr [eax]
005e640c ff5138          call    dword ptr [ecx+38h]                    // [6]

Inside this method, the following code will be executed to wrap the loading of the image. The method will first construct a TFileStream object at [7] and then pass it as an argument to a method specific to each file format parser. The object's method is called at [8] and is actually responsible for reading the image file contents.

0041187c 55              push    ebp
0041187d 8bec            mov     ebp,esp
0041187f 51              push    ecx
00411880 53              push    ebx
00411881 8bd8            mov     ebx,eax
00411883 6a20            push    20h
00411885 8bca            mov     ecx,edx
00411887 a1b86b4000      mov     eax,dword ptr [awp+0x6bb8 (00406bb8)]  // TFileStream
0041188c b201            mov     dl,1
0041188e e8b97dffff      call    awp+0x964c (0040964c)                  // [7]
00411893 8945fc          mov     dword ptr [ebp-4],eax                  // TFileStream variable
004118a4 8b55fc          mov     edx,dword ptr [ebp-4]  
004118a7 8bc3            mov     eax,ebx
004118a9 8b08            mov     ecx,dword ptr [eax]
004118ab ff5140          call    dword ptr [ecx+40h]                    // [8] TMetaFile::LoadFromStream

The method that gets called is named TImageType::LoadFromStream depending on the image type. This results in the following code being executed. This code is used to load data for parsing a Windows Enhanced Metafile image and starts out by calling the function at [9]. This call is responsible for verifying that the signature at the beginning of the file begins with "EMF" and aborting if not. Once the signature is verified, the application will finally make the call at [10] which will actually parse the image file header and contains the vulnerability within.

00412404 53              push    ebx
00412405 56              push    esi
00412406 8bf2            mov     esi,edx
00412408 8bd8            mov     ebx,eax
0041240a 8bd6            mov     edx,esi
0041240c 8bc3            mov     eax,ebx
0041240e e8e1040000      call    awp+0x128f4 (004128f4) // [9] TMetaFile::TestEMF
00412413 84c0            test    al,al
00412415 740b            je      awp+0x12422 (00412422)
00412417 8bd6            mov     edx,esi
00412419 8bc3            mov     eax,ebx
0041241b e8cc000000      call    awp+0x124ec (004124ec) // [10] Parse EMF file
00412420 eb1b            jmp     awp+0x1243d (0041243d)

The following function actually contains our vulnerability and starts by allocating 0x64 bytes on the stack. This space is used by the function to read the beginning of the EMF header. At [11], the application will call a function that wraps TFileStream::ReadFile to accomplish this and load data from the file onto the stack. The header for an EMF file includes a field representing the size of the entire file. This field is used by the application at [12] to perform an allocation. Due to the size from the file's header being provided by a user. This allows one to control the size of the allocation. Immediately following this allocation, the application will make a call to bcopy at [13] using a hard-coded length of 0x64. Due to the file data being explicitly trusted to control the size used for the allocation of the destination pointer. An aggressor can specify a size less than 0x64, which will result in the call at [13] overflowing the destination buffer, which can allow for heap corruption. If the call to bcopy for the 0x64 byte header does not corrupt memory, the following call at [14] that reads the rest of the file may corrupt memory. These types of heap corruptions can allow for code execution under the context of the application.

004124ec 53              push    ebx
004124ed 56              push    esi
004124ee 57              push    edi
004124ef 55              push    ebp
004124f0 83c49c          add     esp,0FFFFFF9Ch                 // allocate 0x64 bytes
004124fe 8bd4            mov     edx,esp                        // destination
00412500 b964000000      mov     ecx,64h                        // size
00412505 8bc5            mov     eax,ebp
00412507 e8f86fffff      call    awp+0x9504 (00409504)          // [11] calls TFileStream::ReadFile
0041250c 817c242820454d46 cmp     dword ptr [esp+28h],464D4520h // verify signature once again
00412514 7405            je      awp+0x1251b (0041251b)
0041251b 8b442430        mov     eax,dword ptr [esp+30h]        // size of metafile in header
0041251f e81cfefeff      call    awp+0x2340 (00402340)          // [12] allocate space based on header
00412524 8bf0            mov     esi,eax
00412526 8b5f10          mov     ebx,dword ptr [edi+10h]
00412529 8bd6            mov     edx,esi                        // pointer from previous allocation
0041252b 8bc4            mov     eax,esp                        // header on stack
0041252d b964000000      mov     ecx,64h                        // hardcoded size
00412532 e8a5fefeff      call    awp+0x23dc (004023dc)          // [13] calls bcopy
00412537 8b4c2430        mov     ecx,dword ptr [esp+30h]        // Take the total file size
0041253b 83e964          sub     ecx,64h                        // Subtract 0x64 for the header that was previously read
0041253e 8d5664          lea     edx,[esi+64h]                  // Seek after the file header
00412541 8bc5            mov     eax,ebp
00412543 e8bc6fffff      call    awp+0x9504 (00409504)          // [14] Read the rest of the file into the heap buffer

Crash Information

(430.720): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000064 ebx=0b1f1490 ecx=00000014 edx=00000000 esi=0018ea14 edi=0b37ffec
eip=004023ed esp=0018ea08 ebp=0963ac2c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
004023ed f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

0:000> kv L4
 # ChildEBP RetAddr  Args to Child              
00 0018ea0c 00412537 00000001 0000006c 00000000 awp+0x23ed
01 00000000 00000000 00000000 00000000 00000000 awp+0x12537


2018-09-10 - Vendor Disclosure
2018-09-11 - Vendor patched via beta version
2018-09-26 - Vendor released
2018-10-01 - Public Disclosure


Discovered by a member of Cisco Talos.