Commit 4901744def7ebd487e4938c0fc32bdcaffebf964

Authored by decalage2
1 parent 13945508

rtofbj: extract and display the CLSID of OLE objects

Showing 2 changed files with 33 additions and 17 deletions
oletools/rtfobj.py
@@ -81,8 +81,9 @@ http://www.decalage.info/python/oletools @@ -81,8 +81,9 @@ http://www.decalage.info/python/oletools
81 # 2018-02-01 JRM: - fixed issue #251: \bin without argument 81 # 2018-02-01 JRM: - fixed issue #251: \bin without argument
82 # 2018-04-09 PL: - fixed issue #280: OLE Package were not detected on Python 3 82 # 2018-04-09 PL: - fixed issue #280: OLE Package were not detected on Python 3
83 # 2018-03-24 v0.53 PL: - fixed issue #292: \margSz is a destination 83 # 2018-03-24 v0.53 PL: - fixed issue #292: \margSz is a destination
  84 +# 2018-04-27 PL: - extract and display the CLSID of OLE objects
84 85
85 -__version__ = '0.53dev5' 86 +__version__ = '0.53dev7'
86 87
87 # ------------------------------------------------------------------------------ 88 # ------------------------------------------------------------------------------
88 # TODO: 89 # TODO:
@@ -115,6 +116,8 @@ if not _parent_dir in sys.path: @@ -115,6 +116,8 @@ if not _parent_dir in sys.path:
115 from oletools.thirdparty.xglob import xglob 116 from oletools.thirdparty.xglob import xglob
116 from oletools.thirdparty.tablestream import tablestream 117 from oletools.thirdparty.tablestream import tablestream
117 from oletools import oleobj 118 from oletools import oleobj
  119 +from oletools.thirdparty.olefile import olefile
  120 +from oletools.common import clsid
118 121
119 # === LOGGING ================================================================= 122 # === LOGGING =================================================================
120 123
@@ -618,6 +621,10 @@ class RtfObject(object): @@ -618,6 +621,10 @@ class RtfObject(object):
618 self.filename = None 621 self.filename = None
619 self.src_path = None 622 self.src_path = None
620 self.temp_path = None 623 self.temp_path = None
  624 + # Additional OLE object data
  625 + self.clsid = None
  626 + self.clsid_desc = None
  627 +
621 628
622 629
623 630
@@ -676,6 +683,12 @@ class RtfObjParser(RtfParser): @@ -676,6 +683,12 @@ class RtfObjParser(RtfParser):
676 rtfobj.temp_path = opkg.temp_path 683 rtfobj.temp_path = opkg.temp_path
677 rtfobj.olepkgdata = opkg.data 684 rtfobj.olepkgdata = opkg.data
678 rtfobj.is_package = True 685 rtfobj.is_package = True
  686 + else:
  687 + if olefile.isOleFile(obj.data):
  688 + ole = olefile.OleFileIO(obj.data)
  689 + rtfobj.clsid = ole.root.clsid
  690 + rtfobj.clsid_desc = clsid.KNOWN_CLSIDS.get(rtfobj.clsid,
  691 + 'unknown CLSID (please report at https://github.com/decalage2/oletools/issues)')
679 except: 692 except:
680 pass 693 pass
681 log.debug('*** Not an OLE 1.0 Object') 694 log.debug('*** Not an OLE 1.0 Object')
@@ -803,15 +816,14 @@ def process_file(container, filename, data, output_dir=None, save_object=False): @@ -803,15 +816,14 @@ def process_file(container, filename, data, output_dir=None, save_object=False):
803 print('='*79) 816 print('='*79)
804 print('File: %r - size: %d bytes' % (filename, len(data))) 817 print('File: %r - size: %d bytes' % (filename, len(data)))
805 tstream = tablestream.TableStream( 818 tstream = tablestream.TableStream(
806 - column_width=(3, 10, 31, 31),  
807 - header_row=('id', 'index', 'OLE Object', 'OLE Package'), 819 + column_width=(3, 10, 63),
  820 + header_row=('id', 'index', 'OLE Object'),
808 style=tablestream.TableStyleSlim 821 style=tablestream.TableStyleSlim
809 ) 822 )
810 rtfp = RtfObjParser(data) 823 rtfp = RtfObjParser(data)
811 rtfp.parse() 824 rtfp.parse()
812 for rtfobj in rtfp.objects: 825 for rtfobj in rtfp.objects:
813 ole_color = None 826 ole_color = None
814 - pkg_color = None  
815 if rtfobj.is_ole: 827 if rtfobj.is_ole:
816 ole_column = 'format_id: %d ' % rtfobj.format_id 828 ole_column = 'format_id: %d ' % rtfobj.format_id
817 if rtfobj.format_id == oleobj.OleObject.TYPE_EMBEDDED: 829 if rtfobj.format_id == oleobj.OleObject.TYPE_EMBEDDED:
@@ -827,33 +839,37 @@ def process_file(container, filename, data, output_dir=None, save_object=False): @@ -827,33 +839,37 @@ def process_file(container, filename, data, output_dir=None, save_object=False):
827 else: 839 else:
828 ole_column += 'data size: %d' % rtfobj.oledata_size 840 ole_column += 'data size: %d' % rtfobj.oledata_size
829 if rtfobj.is_package: 841 if rtfobj.is_package:
830 - pkg_column = 'Filename: %r\n' % rtfobj.filename  
831 - pkg_column += 'Source path: %r\n' % rtfobj.src_path  
832 - pkg_column += 'Temp path = %r' % rtfobj.temp_path  
833 - pkg_color = 'yellow' 842 + ole_column += '\nOLE Package object:'
  843 + ole_column += '\nFilename: %r' % rtfobj.filename
  844 + ole_column += '\nSource path: %r' % rtfobj.src_path
  845 + ole_column += '\nTemp path = %r' % rtfobj.temp_path
  846 + ole_color = 'yellow'
834 # check if the file extension is executable: 847 # check if the file extension is executable:
835 _, ext = os.path.splitext(rtfobj.filename) 848 _, ext = os.path.splitext(rtfobj.filename)
836 log.debug('File extension: %r' % ext) 849 log.debug('File extension: %r' % ext)
837 if re_executable_extensions.match(ext): 850 if re_executable_extensions.match(ext):
838 - pkg_color = 'red'  
839 - pkg_column += '\nEXECUTABLE FILE'  
840 - else:  
841 - pkg_column = 'Not an OLE Package' 851 + ole_color = 'red'
  852 + ole_column += '\nEXECUTABLE FILE'
  853 + # else:
  854 + # pkg_column = 'Not an OLE Package'
  855 + if rtfobj.clsid is not None:
  856 + ole_column += '\nCLSID: %s' % rtfobj.clsid
  857 + ole_column += '\n%s' % rtfobj.clsid_desc
  858 + if 'CVE' in rtfobj.clsid_desc:
  859 + ole_color = 'red'
842 # Detect OLE2Link exploit 860 # Detect OLE2Link exploit
843 # http://www.kb.cert.org/vuls/id/921560 861 # http://www.kb.cert.org/vuls/id/921560
844 if rtfobj.class_name == 'OLE2Link': 862 if rtfobj.class_name == 'OLE2Link':
845 ole_color = 'red' 863 ole_color = 'red'
846 ole_column += '\nPossibly an exploit for the OLE2Link vulnerability (VU#921560, CVE-2017-0199)' 864 ole_column += '\nPossibly an exploit for the OLE2Link vulnerability (VU#921560, CVE-2017-0199)'
847 else: 865 else:
848 - pkg_column = ''  
849 ole_column = 'Not a well-formed OLE object' 866 ole_column = 'Not a well-formed OLE object'
850 tstream.write_row(( 867 tstream.write_row((
851 rtfp.objects.index(rtfobj), 868 rtfp.objects.index(rtfobj),
852 # filename, 869 # filename,
853 '%08Xh' % rtfobj.start, 870 '%08Xh' % rtfobj.start,
854 - ole_column,  
855 - pkg_column  
856 - ), colors=(None, None, ole_color, pkg_color) 871 + ole_column
  872 + ), colors=(None, None, ole_color)
857 ) 873 )
858 tstream.write_sep() 874 tstream.write_sep()
859 if save_object: 875 if save_object:
setup.py
@@ -43,7 +43,7 @@ import os, fnmatch @@ -43,7 +43,7 @@ import os, fnmatch
43 #--- METADATA ----------------------------------------------------------------- 43 #--- METADATA -----------------------------------------------------------------
44 44
45 name = "oletools" 45 name = "oletools"
46 -version = '0.53dev6' 46 +version = '0.53dev7'
47 desc = "Python tools to analyze security characteristics of MS Office and OLE files (also called Structured Storage, Compound File Binary Format or Compound Document File Format), for Malware Analysis and Incident Response #DFIR" 47 desc = "Python tools to analyze security characteristics of MS Office and OLE files (also called Structured Storage, Compound File Binary Format or Compound Document File Format), for Malware Analysis and Incident Response #DFIR"
48 long_desc = open('oletools/README.rst').read() 48 long_desc = open('oletools/README.rst').read()
49 author = "Philippe Lagadec" 49 author = "Philippe Lagadec"