Commit bd2c3566 by devttys0

Added option to turn off privilege dropping

parent 0d6bf607
...@@ -11,6 +11,7 @@ import tempfile ...@@ -11,6 +11,7 @@ import tempfile
import subprocess import subprocess
import binwalk.core.common import binwalk.core.common
from binwalk.core.compat import * from binwalk.core.compat import *
from binwalk.core.exceptions import ModuleException
from binwalk.core.module import Module, Option, Kwarg from binwalk.core.module import Module, Option, Kwarg
from binwalk.core.common import file_size, file_md5, unique_file_name, BlockFile from binwalk.core.common import file_size, file_md5, unique_file_name, BlockFile
...@@ -49,7 +50,7 @@ class Extractor(Module): ...@@ -49,7 +50,7 @@ class Extractor(Module):
UNIQUE_PATH_DELIMITER = '%%' UNIQUE_PATH_DELIMITER = '%%'
# Unprivileged user account to execute external extraction utilities # Unprivileged user account to execute external extraction utilities
UNPRIVILEGED_USER_NAME = 'binwalksafe' UNPRIVILEGED_USER_NAME = 'binwalk_safe_user_69'
TITLE = 'Extraction' TITLE = 'Extraction'
ORDER = 9 ORDER = 9
...@@ -108,6 +109,10 @@ class Extractor(Module): ...@@ -108,6 +109,10 @@ class Extractor(Module):
long='subdirs', long='subdirs',
kwargs={'extract_into_subdirs': True}, kwargs={'extract_into_subdirs': True},
description="Extract into sub-directories named by the offset"), description="Extract into sub-directories named by the offset"),
Option(short='0',
long='unsafe',
kwargs={'unsafe_extraction': True},
description="Execute external extractions without dropping privileges"),
] ]
KWARGS = [ KWARGS = [
...@@ -122,12 +127,25 @@ class Extractor(Module): ...@@ -122,12 +127,25 @@ class Extractor(Module):
Kwarg(name='manual_rules', default=[]), Kwarg(name='manual_rules', default=[]),
Kwarg(name='matryoshka', default=0), Kwarg(name='matryoshka', default=0),
Kwarg(name='enabled', default=False), Kwarg(name='enabled', default=False),
Kwarg(name='unsafe_extraction', default=False),
] ]
def load(self): def load(self):
self.unpriv_uid = None
self.unpriv_gid = None
if self.enabled is True and self.unsafe_extraction is False:
if os.getuid() != 0:
raise ModuleException("Binwalk requires root privileges to safely execute external extraction utilities as an unprivileged user.")
self.shell_call('useradd %s' % self.UNPRIVILEGED_USER_NAME)
user_info = pwd.getpwnam(self.UNPRIVILEGED_USER_NAME) user_info = pwd.getpwnam(self.UNPRIVILEGED_USER_NAME)
self.unpriv_uid = user_info.pw_uid self.unpriv_uid = user_info.pw_uid
self.unpriv_gid = user_info.pw_gid self.unpriv_gid = user_info.pw_gid
else:
self.unpriv_uid = os.getuid()
self.unpriv_gid = os.getgid()
# Holds a list of extraction rules loaded either from a file or when # Holds a list of extraction rules loaded either from a file or when
# manually specified. # manually specified.
...@@ -860,7 +878,6 @@ class Extractor(Module): ...@@ -860,7 +878,6 @@ class Extractor(Module):
Returns True on success, False on failure, or None if the external extraction utility could not be found. Returns True on success, False on failure, or None if the external extraction utility could not be found.
''' '''
tmp = None
rval = 0 rval = 0
retval = True retval = True
command_list = [] command_list = []
...@@ -879,11 +896,6 @@ class Extractor(Module): ...@@ -879,11 +896,6 @@ class Extractor(Module):
retval = False retval = False
binwalk.core.common.warning("Internal extractor '%s' failed with exception: '%s'" % (str(cmd), str(e))) binwalk.core.common.warning("Internal extractor '%s' failed with exception: '%s'" % (str(cmd), str(e)))
elif cmd: elif cmd:
# If not in debug mode, create a temporary file to redirect
# stdout and stderr to
if not binwalk.core.common.DEBUG:
tmp = tempfile.TemporaryFile()
# Generate unique file paths for all paths in the current # Generate unique file paths for all paths in the current
# command that are surrounded by UNIQUE_PATH_DELIMITER # command that are surrounded by UNIQUE_PATH_DELIMITER
while self.UNIQUE_PATH_DELIMITER in cmd: while self.UNIQUE_PATH_DELIMITER in cmd:
...@@ -898,20 +910,8 @@ class Extractor(Module): ...@@ -898,20 +910,8 @@ class Extractor(Module):
# command with fname # command with fname
command = command.strip().replace(self.FILE_NAME_PLACEHOLDER, fname) command = command.strip().replace(self.FILE_NAME_PLACEHOLDER, fname)
# Fork a child to drop privs
child_pid = os.fork()
if child_pid is 0:
# Switch to unprivileged user
binwalk.core.common.debug("Dropping privileges to user '%s'" % self.UNPRIVILEGED_USER_NAME)
os.setgid(self.unpriv_uid)
os.setuid(self.unpriv_gid)
# Execute external extractor # Execute external extractor
binwalk.core.common.debug("subprocess.call(%s, stdout=%s, stderr=%s)" % (command, str(tmp), str(tmp))) rval = self.shell_call(command)
rval = subprocess.call(shlex.split(command), stdout=tmp, stderr=tmp)
sys.exit(rval)
else:
rval = os.wait()
# Check the return value to see if extraction was successful or not # Check the return value to see if extraction was successful or not
if rval in codes: if rval in codes:
...@@ -935,7 +935,33 @@ class Extractor(Module): ...@@ -935,7 +935,33 @@ class Extractor(Module):
binwalk.core.common.warning("Extractor.execute failed to run external extractor '%s': %s, '%s' might not be installed correctly" % (str(cmd), str(e), str(cmd))) binwalk.core.common.warning("Extractor.execute failed to run external extractor '%s': %s, '%s' might not be installed correctly" % (str(cmd), str(e), str(cmd)))
retval = None retval = None
return (retval, '&&'.join(command_list))
def shell_call(self, command):
# Fork a child to drop privs
child_pid = os.fork()
if child_pid is 0:
# Switch to unprivileged user, if one has been set
if self.unpriv_uid is not None and self.unpriv_gid is not None:
binwalk.core.common.debug("Dropping privileges to %d:%d" % (self.unpriv_uid, self.unpriv_gid))
os.setgid(self.unpriv_uid)
os.setuid(self.unpriv_gid)
# If not in debug mode, create a temporary file to redirect
# stdout and stderr to
if not binwalk.core.common.DEBUG:
tmp = tempfile.TemporaryFile()
else:
tmp = None
# Execute command
binwalk.core.common.debug("subprocess.call(%s, stdout=%s, stderr=%s)" % (command, str(tmp), str(tmp)))
rval = subprocess.call(shlex.split(command), stdout=tmp, stderr=tmp)
# Clean up temp file
if tmp is not None: if tmp is not None:
tmp.close() tmp.close()
return (retval, '&&'.join(command_list)) sys.exit(rval)
else:
return os.wait()[1]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment