summaryrefslogtreecommitdiff
path: root/plugins/python/checksec
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-12-27 22:35:39 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-12-27 22:35:39 (GMT)
commit865f6d87f3bce7f569343382c3dfd1bc68dcacee (patch)
tree64869be2c5e7ad9285829b48ba7f7b446d73e3ec /plugins/python/checksec
parentd33e8935c5186ab2459dfa6c9340396377524fb1 (diff)
Displayed mitigations for Elf files using a new Python plugin.
Diffstat (limited to 'plugins/python/checksec')
-rw-r--r--plugins/python/checksec/Makefile.am9
-rw-r--r--plugins/python/checksec/__init__.py4
-rw-r--r--plugins/python/checksec/mitigations.py135
-rw-r--r--plugins/python/checksec/plugin.py39
4 files changed, 187 insertions, 0 deletions
diff --git a/plugins/python/checksec/Makefile.am b/plugins/python/checksec/Makefile.am
new file mode 100644
index 0000000..eecee28
--- /dev/null
+++ b/plugins/python/checksec/Makefile.am
@@ -0,0 +1,9 @@
+
+checksecdir = $(pluginsdatadir)/python/checksec
+
+checksec_DATA = \
+ __init__.py \
+ mitigations.py \
+ plugin.py
+
+EXTRA_DIST = $(checksec_DATA)
diff --git a/plugins/python/checksec/__init__.py b/plugins/python/checksec/__init__.py
new file mode 100644
index 0000000..691b58d
--- /dev/null
+++ b/plugins/python/checksec/__init__.py
@@ -0,0 +1,4 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from checksec.plugin import CheckSec as AutoLoad
diff --git a/plugins/python/checksec/mitigations.py b/plugins/python/checksec/mitigations.py
new file mode 100644
index 0000000..1539fa7
--- /dev/null
+++ b/plugins/python/checksec/mitigations.py
@@ -0,0 +1,135 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from pychrysalide.format.elf import ElfFormat
+
+
+class ElfMitigations():
+
+ def __init__(self, fmt):
+ """Look for mitigations in a loaded Elf format."""
+
+ self._fmt = fmt
+
+ self._nx = self._get_nx_status()
+
+ self._pie = self._get_pie_status()
+
+ self._relro = self._get_reloc_status()
+
+ self._canary = self._get_canary_status()
+
+
+ def _get_nx_status(self):
+ """Find information about the stack status."""
+
+ # Cf. https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart
+ # ...#Causes_of_executable_stack_markings
+
+ # -Wl,-z,execstack / -Wl,-z,noexecstack
+
+ stack = self._fmt.find_program_by_type(ElfFormat.PT_GNU_STACK)
+
+ status = stack is None or stack.p_flags & ElfFormat.PF_X
+
+ return 'No' if status else 'Yes'
+
+
+ def _get_pie_status(self):
+ """Check for taking advantage of ASLR."""
+
+ # Cf. https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/5030518#5030518
+
+ # -pie -fPIE
+
+ hdr = self._fmt.get_header()
+
+ status = hdr.e_type == ElfFormat.ET_DYN
+
+ return 'Yes' if status else 'No'
+
+
+ def _get_reloc_status(self):
+ """Track protections for the GOT."""
+
+ # Cf. https://wiki.debian.org/Hardening
+ # ...#DEB_BUILD_HARDENING_RELRO_.28ld_-z_relro.29
+
+ # -Wl,-z,relro / -Wl,-z,now
+
+ prgm = self._fmt.find_program_by_type(ElfFormat.PT_GNU_RELRO)
+
+ entry = self._fmt.find_dynamic_item_by_type(ElfFormat.DT_BIND_NOW)
+
+ if prgm is None and entry is None:
+ status = 'No'
+
+ elif not(prgm is None) and entry is None:
+ status = 'Partial'
+
+ elif prgm is None and not(entry is None):
+ status = 'Full'
+
+ else:
+ status = 'Unknown'
+
+ return status
+
+
+ def _get_canary_status(self):
+ """Look for a canary as stack protection."""
+
+ # Cf. https://outflux.net/blog/archives/2014*01/24/fstack-protector-strong/
+
+ # -fno-stack-protector / -fstack-protector / -fstack-protector-all / -fstack-protector-strong
+
+ sym = self._fmt.find_symbol_by_label('__stack_chk_fail@plt')
+
+ status = sym is None
+
+ return 'No' if status else 'Yes'
+
+
+ def __str__(self):
+ """Output a mitigation summary."""
+
+ desc = fmt.content.describe(True) + ':'
+
+ desc += '\n'
+
+ desc += '-' * (len(desc) - 1)
+
+ desc += '\n'
+
+ desc += 'NX: %s' % self._nx
+
+ desc += '\n'
+
+ desc += 'PIE: %s' % self._pie
+
+ desc += '\n'
+
+ desc += 'RelRO: %s' % self._relro
+
+ desc += '\n'
+
+ desc += 'Canary: %s' % self._canary
+
+ return desc
+
+
+if __name__ == '__main__':
+
+ from pychrysalide.features import *
+ import sys
+
+ cnt = FileContent(sys.argv[1])
+ fmt = ElfFormat(cnt)
+
+ binary = LoadedBinary(fmt)
+
+ status = binary.analyze_and_wait()
+
+ if status :
+ m = ElfMitigations(binary.format)
+ print(m)
diff --git a/plugins/python/checksec/plugin.py b/plugins/python/checksec/plugin.py
new file mode 100644
index 0000000..6efb9b5
--- /dev/null
+++ b/plugins/python/checksec/plugin.py
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from .mitigations import ElfMitigations
+from pychrysalide import PluginModule
+from pychrysalide.core import log_message, LMT_INFO
+from pychrysalide.format.elf import ElfFormat
+
+
+class CheckSec(PluginModule):
+ """Check for Elf mititgations."""
+
+ def get_interface(self):
+ """Provide the full plugin description."""
+
+ desc = {
+
+ 'name' : 'CheckSec',
+ 'desc' : 'Output the exploit mitigations compiled with a loaded binary',
+ 'version' : '0.1',
+
+ 'actions' : [ PluginModule.PGA_FORMAT_POST_ANALYSIS_ENDED ]
+
+ }
+
+ return desc
+
+
+ def handle_format_analysis(self, action, format, gid, status):
+ """Get notified at the end of format analysis."""
+
+ if type(format) == ElfFormat:
+
+ m = ElfMitigations(format)
+
+ msg = 'Elf mitigations: NX: <b>%s</b> PIE: <b>%s</b> RelRO: <b>%s</b> Canary: <b>%s</b>' \
+ % (m._nx, m._pie, m._relro, m._canary)
+
+ self.log_message(LMT_INFO, msg)