--- Mailman/Utils.py.orig 2011-12-11 07:56:23 UTC +++ Mailman/Utils.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2011 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2018 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -93,6 +93,12 @@ def list_exists(listname): # # The former two are for 2.1alpha3 and beyond, while the latter two are # for all earlier versions. + # + # But first ensure the list name doesn't contain a path traversal + # attack. + if len(re.sub(mm_cfg.ACCEPTABLE_LISTNAME_CHARACTERS, '', listname)) > 0: + syslog('mischief', 'Hostile listname: %s', listname) + return False basepath = Site.get_listpath(listname) for ext in ('.pck', '.pck.last', '.db', '.db.last'): dbfile = os.path.join(basepath, 'config' + ext) @@ -246,10 +252,28 @@ CRNLpat = re.compile(r'[^\x21-\x7e]') def GetPathPieces(envar='PATH_INFO'): path = os.environ.get(envar) if path: + remote = os.environ.get('HTTP_FORWARDED_FOR', + os.environ.get('HTTP_X_FORWARDED_FOR', + os.environ.get('REMOTE_ADDR', + 'unidentified origin'))) if CRNLpat.search(path): path = CRNLpat.split(path)[0] - syslog('error', 'Warning: Possible malformed path attack.') - return [p for p in path.split('/') if p] + syslog('error', + 'Warning: Possible malformed path attack domain=%s remote=%s', + get_domain(), + remote) + # Check for listname injections that won't be websafed. + pieces = [p for p in path.split('/') if p] + # Get the longest listname or 20 if none. + if list_names(): + longest = max([len(x) for x in list_names()]) + else: + longest = 20 + if pieces and len(pieces[0]) > longest: + syslog('mischief', + 'Hostile listname: listname=%s: remote=%s', pieces[0], remote) + pieces[0] = pieces[0][:longest] + '...' + return pieces return None @@ -952,6 +976,7 @@ _badwords = [ '