Last active
August 29, 2015 14:15
-
-
Save SteelPangolin/b4dd43f42255a5d579d4 to your computer and use it in GitHub Desktop.
Look for wordexp() imports on your $PATH
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
""" | |
Look for binaries on $PATH that use the wordexp() POSIX libc function. | |
Only looks at dynamically linked binaries. | |
Works on Mac OS X and Linux systems, Python versions 2.4 to 3.4. | |
""" | |
import subprocess | |
import os | |
import sys | |
import logging | |
logging.basicConfig() | |
logger = logging.getLogger() | |
class CalledProcessErrorPy24(Exception): | |
def __init__(self, returncode, cmd): | |
self.returncode = returncode | |
self.cmd = cmd | |
def __str__(self): | |
return 'Command %r returned non-zero exit status %d' % (self.cmd, self.returncode) | |
def check_output_py24(args): | |
proc = subprocess.Popen(args, stdout=subprocess.PIPE) | |
output, _ = proc.communicate() | |
if proc.returncode != 0: | |
raise CalledProcessErrorPy24(proc.returncode, args) | |
return output | |
def any_py24(seq): | |
for s in seq: | |
if s: | |
return True | |
return False | |
check_output = getattr(subprocess, 'check_output', check_output_py24) | |
CalledProcessError = getattr(subprocess, 'CalledProcessError', CalledProcessErrorPy24) | |
try: | |
any([]) | |
except NameError: | |
any = any_py24 | |
def is_binary_executable_with_symbols(path): | |
output = check_output(['file', '-b', path]).decode('utf-8') | |
return 'executable' in output\ | |
and any(binword in output for binword in ['binary', 'ELF'])\ | |
and not 'static' in output | |
def has_wordexp(path): | |
# want to get all unresolved dynamic symbols | |
if 'darwin' in sys.platform: | |
nm_args = ['-u'] | |
else: | |
nm_args = ['-D', '-u'] | |
output = check_output(['nm'] + nm_args + [path]).decode('utf-8') | |
return 'wordexp' in output | |
def main(): | |
roots = os.getenv('PATH').split(os.pathsep) | |
for root in roots: | |
if not os.path.isdir(root): | |
continue | |
for child in os.listdir(root): | |
try: | |
path = os.path.join(root, child) | |
if not os.path.isfile(path): | |
continue | |
if not is_binary_executable_with_symbols(path): | |
continue | |
if has_wordexp(path): | |
print(path) | |
except CalledProcessError: | |
logger.error("Error scanning file: %s", path, exc_info=True) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment