Talos Vulnerability Report


Atlantis Word Processor uninitialized TDocOleObject code execution vulnerability

October 1, 2018
CVE Number



An exploitable uninitialized variable vulnerability exists in the RTF-parsing functionality of Atlantis Word Processor. A specially crafted RTF file can leverage an uninitialized stack address, resulting in an out-of-bounds write, which in turn could lead to code execution.

Tested Versions

Atlantis Word Processor 3.2.6

Product URLs


CVSSv3 Score

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


CWE-457: Use of Uninitialized Variable


Atlantis is a traditional word processor containing quite a few features. Atlantis supports a large variety of document formats, as well as quite a few different graphics formats to complement the text in a document. Many of the capabilities of Atlantis are designed to be more efficient for the user.

One file format that is parsed by Atlantis is rich text format (RTF). RTF has a series of tokens that are parsed via a large switch statement as the parser comes across them. For example, the beginning of this parsing function looks like:

    token_index = (unsigned __int16)token_index;
    switch ( (unsigned __int16)token_index )
        case 0u:
            *(_DWORD *)(*(_DWORD *)(document_obj - 264) + 1464) = 3;
            goto continue_parsing;
        case 1u:
            *(_DWORD *)(*(_DWORD *)(document_obj - 264) + 1464) = 0;
            goto continue_parsing;
        case 3u:
            *(_DWORD *)(*(_DWORD *)(document_obj - 264) + 1468) = 4;
            goto continue_parsing

Some switch cases are simply setting flags in the overarching document object, while others took parameters and call further functions for parsing. Each index in this switch statement is referenced to a global list of tokens available in Atlantis.

CODE:00430918     aCell           db 'cell',0             
CODE:00430920     aCellx          db 'cellx',0            
CODE:00430928     aCf             db 'cf',0               
CODE:0043092C     aCharscalex     db 'charscalex',0       
CODE:00430938     aChcbpat        db 'chcbpat',0          
CODE:00430940     aChcfpat        db 'chcfpat',0          
CODE:00430948     aChftn          db 'chftn',0            
CODE:00430950     aChftnsep       db 'chftnsep',0         
CODE:0043095C     aChftnsepc      db 'chftnsepc',0        
CODE:00430968     aChshdng        db 'chshdng',0          
CODE:00430970     aClbrdrb        db 'clbrdrb',0          
CODE:00430978     aClbrdrl        db 'clbrdrl',0          
CODE:00430980     aClbrdrr        db 'clbrdrr',0          
CODE:00430988     aClbrdrt        db 'clbrdrt',0          

RTF format allows for embedded OLE objects. These objects rely on a few tokens specific for OLE and are used to set a variety of options in the OLE.

CODE:00431014     aObjautlink     db 'objautlink',0       ; DATA XREF: DATA:00664F9C↓o
CODE:0043103C     aObjemb         db 'objemb',0           ; DATA XREF: DATA:00664FAC↓o
CODE:00431044     aObjh           db 'objh',0             ; DATA XREF: DATA:00664FB0↓o
CODE:0043104C     aObjhtml        db 'objhtml',0          ; DATA XREF: DATA:00664FB4↓o
CODE:00431054     aObjlink        db 'objlink',0          ; DATA XREF: DATA:00664FB8↓o
CODE:00431064     aObjocx         db 'objocx',0           ; DATA XREF: DATA:00664FC0↓o
CODE:0043107C     aObjw           db 'objw',0             ; DATA XREF: DATA:00664FCC↓o

In particular, these tokens have the following switch cases:

    case 0x0ffu:
        *(_BYTE *)(*(_DWORD *)(document_obj - 0x8E0) + 44) = 3;
        goto continue_parsing;
    case 0x104u:
        *(_BYTE *)(*(_DWORD *)(document_obj - 0x8E0) + 44) = 1;
        goto continue_parsing;
    case 0x105u:
        *(_DWORD *)(*(_DWORD *)(document_obj - 0x8E0) + 12) = sub_43192C();
        goto continue_parsing;
    case 0x106u:
        *(_BYTE *)(*(_DWORD *)(document_obj - 0x8E0) + 44) = 4;
        goto continue_parsing;
    case 0x107u:
        *(_BYTE *)(*(_DWORD *)(document_obj - 0x8E0) + 44) = 2;
        goto continue_parsing;
    case 0x109u:
        *(_BYTE *)(*(_DWORD *)(document_obj - 0x8E0) + 44) = 5;
        goto continue_parsing;
    case 0x10Cu:
        *(_DWORD *)(*(_DWORD *)(document_obj - 0x8E0) + 8) = sub_43192C();
        goto continue_parsing;

These cases rely on the document_obj having a valid OLE pointer at offset - 0x8e0 in order to set the correct value. This document_obj passed to the RTF-parsing function comes from a stack variable:

CODE:0058EA29                  push    ebp
CODE:0058EA2A                  push    offset loc_58EA59
CODE:0058EA2F                  push    dword ptr fs:[eax]
CODE:0058EA32                  mov     fs:[eax], esp
CODE:0058EA35                  push    ebp
CODE:0058EA36                  xor     eax, eax
CODE:0058EA38                  call    sub_588f94 ; stack variable passed to the 

This stack variable is directly passed forward to the RTF-parsing function:

CODE:005894BE                  mov     edx, eax        
CODE:005894C0                  mov     eax, [ebp+document_obj]
CODE:005894C3                  lea     ecx, [eax-5Ch]  
CODE:005894C6                  mov     eax, [ebp+document_obj]
CODE:005894C9                  add     eax, 0FFFFF708h
CODE:005894CE                  call    rtf_parser_54B4E0

The assumption at this point is, if any of the Ole token are parsed, a valid OLE document object pointer exists at offset -0x8e0. The initialization function for the OLE document object is not necessarily called before parsing the OLE tokens. Because of this, the OLE document object pointer (offset -0x8e0) can be uninitialized. If this stack offset can be controlled by an attacker, then an attacker can write to an arbitrary address, causing an out-of-bounds write condition.

Crash Information

eax=01000000 ebx=00000104 ecx=0019f5fc edx=00000104 esi=0019ed60 edi=0019fdcc
eip=00587151 esp=0019ead8 ebp=0019eb10 iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210293
00587151 c6402c01        mov     byte ptr [eax+2Ch],1       ds:002b:0100002c=??


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 Cory Duplantis and another member of Cisco Talos.