VYPR
High severityNVD Advisory· Published Jun 16, 2012· Updated Apr 29, 2026

CVE-2012-2395

CVE-2012-2395

Description

Incomplete blacklist vulnerability in action_power.py in Cobbler 2.2.0 allows remote attackers to execute arbitrary commands via shell metacharacters in the (1) username or (2) password fields to the power_system method in the xmlrpc API.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
cobblerPyPI
< 2.6.02.6.0

Affected products

1

Patches

1
6d9167e5da44

Merge pull request #164 from jimi1283/powerpipe

https://github.com/cobbler/cobblerjimi1283May 7, 2012via ghsa
3 files changed · +44 49
  • cobbler/action_power.py+9 33 modified
    @@ -69,8 +69,9 @@ def power(self, desired_state):
             interested in maximum security should take that route.
             """
     
    -        template = self.get_command_template()
    -        template_file = open(template, "r")
    +        power_command = utils.get_power(self.system.power_type)
    +        if not power_command:
    +            utils.die(self.logger,"no power type set for system")
     
             meta = utils.blender(self.api, False, self.system)
             meta["power_mode"] = desired_state
    @@ -81,43 +82,34 @@ def power(self, desired_state):
             if self.force_pass is not None:
                meta["power_pass"] = self.force_pass
     
    -        tmp = templar.Templar(self.api._config)
    -        cmd = tmp.render(template_file, meta, None, self.system)
    -        template_file.close()
    -
    -        cmd = cmd.strip()
    -
             self.logger.info("cobbler power configuration is:")
    -
             self.logger.info("      type   : %s" % self.system.power_type)
             self.logger.info("      address: %s" % self.system.power_address)
             self.logger.info("      user   : %s" % self.system.power_user)
             self.logger.info("      id     : %s" % self.system.power_id)
     
             # if no username/password data, check the environment
    -
             if meta.get("power_user","") == "":
                 meta["power_user"] = os.environ.get("COBBLER_POWER_USER","")
             if meta.get("power_pass","") == "":
                 meta["power_pass"] = os.environ.get("COBBLER_POWER_PASS","")
     
    -        self.logger.info("- %s" % cmd)
    -
    -        # use shell so we can have mutliple power commands chained together
    -        cmd = ['/bin/sh','-c', cmd]
    +        template = utils.get_power_template(self.system.power_type)
    +        tmp = templar.Templar(self.api._config)
    +        template_data = tmp.render(template, meta, None, self.system)
     
             # Try the power command 5 times before giving up.
             # Some power switches are flakey
             for x in range(0,5):
    -            output, rc = utils.subprocess_sp(self.logger, cmd, shell=False)
    +            output, rc = utils.subprocess_sp(self.logger, power_command, shell=False, input=template_data)
                 if rc == 0:
                     # If the desired state is actually a query for the status
                     # return different information than command return code
                     if desired_state == 'status':
    -                    match = re.match('(^Status:\s)(ON|OFF)', output)
    +                    match = re.match('(^Status:\s)(on|off)', output, re.IGNORECASE)
                         if match:
                             power_status = match.groups()[1]
    -                        if power_status == 'ON':
    +                        if power_status.lower() == 'on':
                                 return True
                             else:
                                 return False
    @@ -132,19 +124,3 @@ def power(self, desired_state):
     
             return rc
     
    -    def get_command_template(self):
    -
    -        """
    -        In case the user wants to customize the power management commands, 
    -        we source the code for each command from /etc/cobbler and run
    -        them through Cheetah.
    -        """
    -
    -        if self.system.power_type in [ "", "none" ]:
    -            utils.die(self.logger,"Power management is not enabled for this system")
    -
    -        result = utils.get_power(self.system.power_type)
    -        if not result:
    -            utils.die(self.logger, "Invalid power management type for this system (%s, %s)" % (self.system.power_type, self.system.name))
    -        return result
    -
    
  • cobbler/item_system.py+5 5 modified
    @@ -54,11 +54,11 @@
       ["virt_auto_boot","<<inherit>>",0,"Virt Auto Boot",True,"Auto boot this VM?",0,"bool"],
       ["ctime",0,0,"",False,"",0,"float"],
       ["mtime",0,0,"",False,"",0,"float"],
    -  ["power_type","SETTINGS:power_management_default_type",0,"Type",True,"Power management script to use",utils.get_power_types(),"str"],
    -  ["power_address","",0,"Address",True,"Ex: power-device.example.org",0,"str"],
    -  ["power_user","",0,"Username ",True,"",0,"str"],
    -  ["power_pass","",0,"Password",True,"",0,"str"],
    -  ["power_id","",0,"ID",True,"Usually a plug number or blade name, if power type requires it",0,"str"],
    +  ["power_type","SETTINGS:power_management_default_type",0,"Power Management Type",True,"Power management script to use",utils.get_power_types(),"str"],
    +  ["power_address","",0,"Power Management Address",True,"Ex: power-device.example.org",0,"str"],
    +  ["power_user","",0,"Power Management Username ",True,"",0,"str"],
    +  ["power_pass","",0,"Power Management Password",True,"",0,"str"],
    +  ["power_id","",0,"Power Management ID",True,"Usually a plug number or blade name, if power type requires it",0,"str"],
       ["hostname","",0,"Hostname",True,"",0,"str"],
       ["gateway","",0,"Gateway",True,"",0,"str"],
       ["name_servers",[],0,"Name Servers",True,"space delimited",0,"list"],
    
  • cobbler/utils.py+30 11 modified
    @@ -1680,29 +1680,34 @@ def is_remote_file(file):
         else:
            return False
     
    -def subprocess_sp(logger, cmd, shell=True):
    +def subprocess_sp(logger, cmd, shell=True, input=None):
         if logger is not None:
             logger.info("running: %s" % cmd)
    +
    +    stdin = None
    +    if input:
    +        stdin = sub_process.PIPE
    +
         try:
    -        sp = sub_process.Popen(cmd, shell=shell, stdout=sub_process.PIPE, stderr=sub_process.PIPE, close_fds=True)
    +        sp = sub_process.Popen(cmd, shell=shell, stdin=stdin, stdout=sub_process.PIPE, stderr=sub_process.PIPE, close_fds=True)
         except OSError:
             if logger is not None:
                 log_exc(logger)
             die(logger, "OS Error, command not found?  While running: %s" % cmd)
     
    -    (out,err) = sp.communicate()
    +    (out,err) = sp.communicate(input)
         rc = sp.returncode
         if logger is not None:
             logger.info("received on stdout: %s" % out)
             logger.debug("received on stderr: %s" % err)
         return out, rc
     
    -def subprocess_call(logger, cmd, shell=True):
    -    data, rc = subprocess_sp(logger, cmd, shell=shell)
    +def subprocess_call(logger, cmd, shell=True, input=None):
    +    data, rc = subprocess_sp(logger, cmd, shell=shell, input=input)
         return rc
     
    -def subprocess_get(logger, cmd, shell=True):
    -    data, rc = subprocess_sp(logger, cmd, shell=shell)
    +def subprocess_get(logger, cmd, shell=True, input=None):
    +    data, rc = subprocess_sp(logger, cmd, shell=shell, input=input)
         return data
     
     def popen2(args, **kwargs):
    @@ -1964,8 +1969,8 @@ def get_power_types():
         Return all possible power types
         """
         power_types = []
    -    power_template = re.compile(r'power_(.*).template')
    -    for x in glob.glob("/etc/cobbler/power/power_*.template"):
    +    power_template = re.compile(r'fence_(.*)')
    +    for x in glob.glob("/usr/sbin/fence_*"):
             power_types.append(power_template.search(x).group(1))
         power_types.sort()
         return power_types
    @@ -1975,11 +1980,25 @@ def get_power(powertype=None):
         Return power command for type
         """
         if powertype:
    -        powerpath = "/etc/cobbler/power/power_%s.template" % powertype
    -        if os.path.isfile(powerpath):
    +        powerpath = "/usr/sbin/fence_%s" % powertype
    +        if os.path.isfile(powerpath) and os.access(powerpath, os.X_OK):
                 return powerpath
         return None
     
    +def get_power_template(powertype=None):
    +    """
    +    Return power template for type
    +    """
    +    if powertype:
    +        powertemplate = "/etc/cobbler/power/fence_%s.template" % powertype
    +        if os.path.isfile(powertemplate):
    +            f = open(powertemplate)
    +            template = f.read()
    +            f.close()
    +            return template
    +    # return a generic template if a specific one wasn't found
    +    return "action=$power_mode\nlogin=$power_user\npasswd=$power_pass\nipaddr=$power_address\nport=$power_id"
    +
     def get_shared_secret():
         """
         The 'web.ss' file is regenerated each time cobblerd restarts and is
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

17

News mentions

0

No linked articles in our index yet.