Commit 4901744def7ebd487e4938c0fc32bdcaffebf964
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" |