Commit ee14bf1952e9221a0d0375bea74cef7354cf6012
1 parent
fa476b8f
oleid: added check for external relationships
Showing
1 changed file
with
39 additions
and
12 deletions
oletools/oleid.py
| @@ -98,7 +98,7 @@ if _parent_dir not in sys.path: | @@ -98,7 +98,7 @@ if _parent_dir not in sys.path: | ||
| 98 | sys.path.insert(0, _parent_dir) | 98 | sys.path.insert(0, _parent_dir) |
| 99 | 99 | ||
| 100 | from oletools.thirdparty.tablestream import tablestream | 100 | from oletools.thirdparty.tablestream import tablestream |
| 101 | -from oletools import crypto, ftguess, olevba, mraptor | 101 | +from oletools import crypto, ftguess, olevba, mraptor, oleobj, ooxml |
| 102 | from oletools.common.log_helper import log_helper | 102 | from oletools.common.log_helper import log_helper |
| 103 | from oletools.common.codepages import get_codepage_name | 103 | from oletools.common.codepages import get_codepage_name |
| 104 | 104 | ||
| @@ -243,6 +243,15 @@ class OleID(object): | @@ -243,6 +243,15 @@ class OleID(object): | ||
| 243 | self.indicators = [] | 243 | self.indicators = [] |
| 244 | self.suminfo_data = None | 244 | self.suminfo_data = None |
| 245 | 245 | ||
| 246 | + def get_indicator(self, indicator_id): | ||
| 247 | + """Helper function: returns an indicator if present (or None)""" | ||
| 248 | + result = [indicator for indicator in self.indicators | ||
| 249 | + if indicator.id == indicator_id] | ||
| 250 | + if result: | ||
| 251 | + return result[0] | ||
| 252 | + else: | ||
| 253 | + return None | ||
| 254 | + | ||
| 246 | def check(self): | 255 | def check(self): |
| 247 | """ | 256 | """ |
| 248 | Open file and run all checks on it. | 257 | Open file and run all checks on it. |
| @@ -288,6 +297,7 @@ class OleID(object): | @@ -288,6 +297,7 @@ class OleID(object): | ||
| 288 | # self.check_powerpoint() | 297 | # self.check_powerpoint() |
| 289 | # self.check_visio() | 298 | # self.check_visio() |
| 290 | self.check_macros() | 299 | self.check_macros() |
| 300 | + self.check_external_relationships() | ||
| 291 | self.check_object_pool() | 301 | self.check_object_pool() |
| 292 | self.check_flash() | 302 | self.check_flash() |
| 293 | if self.ole is not None: | 303 | if self.ole is not None: |
| @@ -321,21 +331,10 @@ class OleID(object): | @@ -321,21 +331,10 @@ class OleID(object): | ||
| 321 | self.indicators.append(author) | 331 | self.indicators.append(author) |
| 322 | return appname, codepage, author | 332 | return appname, codepage, author |
| 323 | 333 | ||
| 324 | - def get_indicator(self, indicator_id): | ||
| 325 | - """Helper function: returns an indicator if present (or None)""" | ||
| 326 | - result = [indicator for indicator in self.indicators | ||
| 327 | - if indicator.id == indicator_id] | ||
| 328 | - if result: | ||
| 329 | - return result[0] | ||
| 330 | - else: | ||
| 331 | - return None | ||
| 332 | - | ||
| 333 | def check_encrypted(self): | 334 | def check_encrypted(self): |
| 334 | """ | 335 | """ |
| 335 | Check whether this file is encrypted. | 336 | Check whether this file is encrypted. |
| 336 | 337 | ||
| 337 | - Might call check_properties. | ||
| 338 | - | ||
| 339 | :returns: :py:class:`Indicator` for encryption or None if file was not | 338 | :returns: :py:class:`Indicator` for encryption or None if file was not |
| 340 | opened | 339 | opened |
| 341 | """ | 340 | """ |
| @@ -353,6 +352,34 @@ class OleID(object): | @@ -353,6 +352,34 @@ class OleID(object): | ||
| 353 | encrypted.description = 'The file is encrypted. It may be decrypted with msoffcrypto-tool' | 352 | encrypted.description = 'The file is encrypted. It may be decrypted with msoffcrypto-tool' |
| 354 | return encrypted | 353 | return encrypted |
| 355 | 354 | ||
| 355 | + def check_external_relationships(self): | ||
| 356 | + """ | ||
| 357 | + Check whether this file has external relationships (remote template, OLE object, etc). | ||
| 358 | + | ||
| 359 | + :returns: :py:class:`Indicator` | ||
| 360 | + """ | ||
| 361 | + ext_rels = Indicator('ext_rels', 0, name='External Relationships', _type=int, | ||
| 362 | + risk=RISK.NONE, | ||
| 363 | + description='External relationships such as remote templates, remote OLE objects, etc', | ||
| 364 | + hide_if_false=False) | ||
| 365 | + self.indicators.append(ext_rels) | ||
| 366 | + # this check only works for OpenXML files | ||
| 367 | + if not self.ftg.is_openxml(): | ||
| 368 | + return ext_rels | ||
| 369 | + # to collect relationship types: | ||
| 370 | + rel_types = set() | ||
| 371 | + # open an XmlParser, using a BytesIO instead of filename (to work in memory) | ||
| 372 | + xmlparser = ooxml.XmlParser(self.data_bytesio) | ||
| 373 | + for rel_type, target in oleobj.find_external_relationships(xmlparser): | ||
| 374 | + log.debug('External relationship: type={} target={}'.format(rel_type, target)) | ||
| 375 | + rel_types.add(rel_type) | ||
| 376 | + ext_rels.value += 1 | ||
| 377 | + if ext_rels.value > 0: | ||
| 378 | + ext_rels.description = 'External relationships found: {} - use oleobj for details'.format( | ||
| 379 | + ', '.join(rel_types)) | ||
| 380 | + ext_rels.risk = RISK.HIGH | ||
| 381 | + return ext_rels | ||
| 382 | + | ||
| 356 | def check_word(self): | 383 | def check_word(self): |
| 357 | """ | 384 | """ |
| 358 | Check whether this file is a word document | 385 | Check whether this file is a word document |