Gentoo Archives: gentoo-commits

From: "Hanno Boeck (hanno)" <hanno@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in net-mail/mailman/files: mailman-2.1.9-fix-XSS.patch
Date: Tue, 05 Feb 2008 11:24:05
Message-Id: E1JMLuD-0004Me-TN@stork.gentoo.org
1 hanno 08/02/05 11:24:01
2
3 Added: mailman-2.1.9-fix-XSS.patch
4 Log:
5 mailman security bump
6 (Portage version: 2.1.4.1)
7
8 Revision Changes Path
9 1.1 net-mail/mailman/files/mailman-2.1.9-fix-XSS.patch
10
11 file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-mail/mailman/files/mailman-2.1.9-fix-XSS.patch?rev=1.1&view=markup
12 plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-mail/mailman/files/mailman-2.1.9-fix-XSS.patch?rev=1.1&content-type=text/plain
13
14 Index: mailman-2.1.9-fix-XSS.patch
15 ===================================================================
16 === modified file 'Mailman/Cgi/edithtml.py'
17 --- Mailman/Cgi/edithtml.py 2006-08-30 14:54:22 +0000
18 +++ Mailman/Cgi/edithtml.py 2007-12-04 19:52:18 +0000
19 @@ -1,4 +1,4 @@
20 -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
21 +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
22 #
23 # This program is free software; you can redistribute it and/or
24 # modify it under the terms of the GNU General Public License
25 @@ -159,7 +159,20 @@
26 doc.AddItem('<hr>')
27 return
28 code = cgi_info['html_code'].value
29 - code = re.sub(r'<([/]?script.*?)>', r'&lt;\1&gt;', code)
30 + if Utils.suspiciousHTML(code):
31 + doc.AddItem(Header(3,
32 + _("""The page you saved contains suspicious HTML that could
33 +potentially expose your users to cross-site scripting attacks. This change
34 +has therefore been rejected. If you still want to make these changes, you
35 +must have shell access to your Mailman server.
36 + """)))
37 + doc.AddItem(_('See '))
38 + doc.AddItem(Link(
39 +'http://www.python.org/cgi-bin/faqw-mm.py?req=show&file=faq04.048.htp',
40 + _('FAQ 4.48.')))
41 + doc.AddItem(Header(3,_("Page Unchanged.")))
42 + doc.AddItem('<hr>')
43 + return
44 langdir = os.path.join(mlist.fullpath(), mlist.preferred_language)
45 # Make sure the directory exists
46 omask = os.umask(0)
47
48 === modified file 'Mailman/Gui/General.py'
49 --- Mailman/Gui/General.py 2006-08-30 14:54:22 +0000
50 +++ Mailman/Gui/General.py 2007-12-04 19:52:18 +0000
51 @@ -1,4 +1,4 @@
52 -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
53 +# Copyright (C) 2001-2007 by the Free Software Foundation, Inc.
54 #
55 # This program is free software; you can redistribute it and/or
56 # modify it under the terms of the GNU General Public License
57 @@ -436,17 +442,21 @@
58 # Convert any html entities to Unicode
59 mlist.subject_prefix = Utils.canonstr(
60 val, mlist.preferred_language)
61 + elif property == 'info':
62 + if val <> mlist.info:
63 + if Utils.suspiciousHTML(val):
64 + doc.addError(_("""The <b>info</b> attribute you saved
65 +contains suspicious HTML that could potentially expose your users to cross-site
66 +scripting attacks. This change has therefore been rejected. If you still want
67 +to make these changes, you must have shell access to your Mailman server.
68 +This change can be made with bin/withlist or with bin/config_list by setting
69 +mlist.info.
70 + """))
71 + else:
72 + mlist.info = val
73 else:
74 GUIBase._setValue(self, mlist, property, val, doc)
75
76 - def _escape(self, property, value):
77 - # The 'info' property allows HTML, but let's sanitize it to avoid XSS
78 - # exploits. Everything else should be fully escaped.
79 - if property <> 'info':
80 - return GUIBase._escape(self, property, value)
81 - # Sanitize <script> and </script> tags but nothing else. Not the best
82 - # solution, but expedient.
83 - return re.sub(r'(?i)<([/]?script.*?)>', r'&lt;\1&gt;', value)
84
85 def _postValidate(self, mlist, doc):
86 if not mlist.reply_to_address.strip() and \
87
88 === modified file 'Mailman/Gui/GUIBase.py'
89 --- Mailman/Gui/GUIBase.py 2005-08-27 01:40:17 +0000
90 +++ Mailman/Gui/GUIBase.py 2007-11-18 20:01:26 +0000
91 @@ -1,4 +1,4 @@
92 -# Copyright (C) 2002-2004 by the Free Software Foundation, Inc.
93 +# Copyright (C) 2002-2007 by the Free Software Foundation, Inc.
94 #
95 # This program is free software; you can redistribute it and/or
96 # modify it under the terms of the GNU General Public License
97 @@ -12,7 +12,8 @@
98 #
99 # You should have received a copy of the GNU General Public License
100 # along with this program; if not, write to the Free Software
101 -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
102 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
103 +# USA.
104
105 """Base class for all web GUI components."""
106
107 @@ -122,10 +127,6 @@
108 # Validate all the attributes for this category
109 pass
110
111 - def _escape(self, property, value):
112 - value = value.replace('<', '&lt;')
113 - return value
114 -
115 def handleForm(self, mlist, category, subcat, cgidata, doc):
116 for item in self.GetConfigInfo(mlist, category, subcat):
117 # Skip descriptions and legacy non-attributes
118 @@ -144,10 +145,9 @@
119 elif not cgidata.has_key(property):
120 continue
121 elif isinstance(cgidata[property], ListType):
122 - val = [self._escape(property, x.value)
123 - for x in cgidata[property]]
124 + val = [x.value for x in cgidata[property]]
125 else:
126 - val = self._escape(property, cgidata[property].value)
127 + val = cgidata[property].value
128 # Coerce the value to the expected type, raising exceptions if the
129 # value is invalid.
130 try:
131
132 === modified file 'Mailman/Utils.py'
133 --- Mailman/Utils.py 2007-11-25 08:04:30 +0000
134 +++ Mailman/Utils.py 2007-12-04 19:52:18 +0000
135 @@ -876,3 +876,154 @@
136 except (LookupError, UnicodeError, ValueError, HeaderParseError):
137 # possibly charset problem. return with undecoded string in one line.
138 return EMPTYSTRING.join(s.splitlines())
139 +
140 +
141 +# Patterns and functions to flag possible XSS attacks in HTML.
142 +# This list is compiled from information at http://ha.ckers.org/xss.html,
143 +# http://www.quirksmode.org/js/events_compinfo.html,
144 +# http://www.htmlref.com/reference/appa/events1.htm,
145 +# http://lxr.mozilla.org/mozilla/source/content/events/src/nsDOMEvent.cpp#59,
146 +# http://www.w3.org/TR/DOM-Level-2-Events/events.html and
147 +# http://www.xulplanet.com/references/elemref/ref_EventHandlers.html
148 +# Many thanks are due to Moritz Naumann for his assistance with this.
149 +_badwords = [
150 + '<i?frame',
151 + '<link',
152 + '<meta',
153 + '<script',
154 + r'(?:^|\W)j(?:ava)?script(?:\W|$)',
155 + r'(?:^|\W)vbs(?:cript)?(?:\W|$)',
156 + r'(?:^|\W)domactivate(?:\W|$)',
157 + r'(?:^|\W)domattrmodified(?:\W|$)',
158 + r'(?:^|\W)domcharacterdatamodified(?:\W|$)',
159 + r'(?:^|\W)domfocus(?:in|out)(?:\W|$)',
160 + r'(?:^|\W)dommenuitem(?:in)?active(?:\W|$)',
161 + r'(?:^|\W)dommousescroll(?:\W|$)',
162 + r'(?:^|\W)domnodeinserted(?:intodocument)?(?:\W|$)',
163 + r'(?:^|\W)domnoderemoved(?:fromdocument)?(?:\W|$)',
164 + r'(?:^|\W)domsubtreemodified(?:\W|$)',
165 + r'(?:^|\W)fscommand(?:\W|$)',
166 + r'(?:^|\W)onabort(?:\W|$)',
167 + r'(?:^|\W)on(?:de)?activate(?:\W|$)',
168 + r'(?:^|\W)on(?:after|before)print(?:\W|$)',
169 + r'(?:^|\W)on(?:after|before)update(?:\W|$)',
170 + r'(?:^|\W)onbefore(?:(?:de)?activate|copy|cut|editfocus|paste)(?:\W|$)',
171 + r'(?:^|\W)onbeforeunload(?:\W|$)',
172 + r'(?:^|\W)onbegin(?:\W|$)',
173 + r'(?:^|\W)onblur(?:\W|$)',
174 + r'(?:^|\W)onbounce(?:\W|$)',
175 + r'(?:^|\W)onbroadcast(?:\W|$)',
176 + r'(?:^|\W)on(?:cell)?change(?:\W|$)',
177 + r'(?:^|\W)oncheckboxstatechange(?:\W|$)',
178 + r'(?:^|\W)on(?:dbl)?click(?:\W|$)',
179 + r'(?:^|\W)onclose(?:\W|$)',
180 + r'(?:^|\W)oncommand(?:update)?(?:\W|$)',
181 + r'(?:^|\W)oncomposition(?:end|start)(?:\W|$)',
182 + r'(?:^|\W)oncontextmenu(?:\W|$)',
183 + r'(?:^|\W)oncontrolselect(?:\W|$)',
184 + r'(?:^|\W)oncopy(?:\W|$)',
185 + r'(?:^|\W)oncut(?:\W|$)',
186 + r'(?:^|\W)ondataavailable(?:\W|$)',
187 + r'(?:^|\W)ondataset(?:changed|complete)(?:\W|$)',
188 + r'(?:^|\W)ondrag(?:drop|end|enter|exit|gesture|leave|over)?(?:\W|$)',
189 + r'(?:^|\W)ondragstart(?:\W|$)',
190 + r'(?:^|\W)ondrop(?:\W|$)',
191 + r'(?:^|\W)onend(?:\W|$)',
192 + r'(?:^|\W)onerror(?:update)?(?:\W|$)',
193 + r'(?:^|\W)onfilterchange(?:\W|$)',
194 + r'(?:^|\W)onfinish(?:\W|$)',
195 + r'(?:^|\W)onfocus(?:in|out)?(?:\W|$)',
196 + r'(?:^|\W)onhelp(?:\W|$)',
197 + r'(?:^|\W)oninput(?:\W|$)',
198 + r'(?:^|\W)onkey(?:up|down|press)(?:\W|$)',
199 + r'(?:^|\W)onlayoutcomplete(?:\W|$)',
200 + r'(?:^|\W)on(?:un)?load(?:\W|$)',
201 + r'(?:^|\W)onlosecapture(?:\W|$)',
202 + r'(?:^|\W)onmedia(?:complete|error)(?:\W|$)',
203 + r'(?:^|\W)onmouse(?:down|enter|leave|move|out|over|up|wheel)(?:\W|$)',
204 + r'(?:^|\W)onmove(?:end|start)?(?:\W|$)',
205 + r'(?:^|\W)on(?:off|on)line(?:\W|$)',
206 + r'(?:^|\W)onoutofsync(?:\W|$)',
207 + r'(?:^|\W)onoverflow(?:changed)?(?:\W|$)',
208 + r'(?:^|\W)onpage(?:hide|show)(?:\W|$)',
209 + r'(?:^|\W)onpaint(?:\W|$)',
210 + r'(?:^|\W)onpaste(?:\W|$)',
211 + r'(?:^|\W)onpause(?:\W|$)',
212 + r'(?:^|\W)onpopup(?:hidden|hiding|showing|shown)(?:\W|$)',
213 + r'(?:^|\W)onprogress(?:\W|$)',
214 + r'(?:^|\W)onpropertychange(?:\W|$)',
215 + r'(?:^|\W)onradiostatechange(?:\W|$)',
216 + r'(?:^|\W)onreadystatechange(?:\W|$)',
217 + r'(?:^|\W)onrepeat(?:\W|$)',
218 + r'(?:^|\W)onreset(?:\W|$)',
219 + r'(?:^|\W)onresize(?:end|start)?(?:\W|$)',
220 + r'(?:^|\W)onresume(?:\W|$)',
221 + r'(?:^|\W)onreverse(?:\W|$)',
222 + r'(?:^|\W)onrow(?:delete|enter|exit|inserted)(?:\W|$)',
223 + r'(?:^|\W)onrows(?:delete|enter|inserted)(?:\W|$)',
224 + r'(?:^|\W)onscroll(?:\W|$)',
225 + r'(?:^|\W)onseek(?:\W|$)',
226 + r'(?:^|\W)onselect(?:start)?(?:\W|$)',
227 + r'(?:^|\W)onselectionchange(?:\W|$)',
228 + r'(?:^|\W)onstart(?:\W|$)',
229 + r'(?:^|\W)onstop(?:\W|$)',
230 + r'(?:^|\W)onsubmit(?:\W|$)',
231 + r'(?:^|\W)onsync(?:from|to)preference(?:\W|$)',
232 + r'(?:^|\W)onsyncrestored(?:\W|$)',
233 + r'(?:^|\W)ontext(?:\W|$)',
234 + r'(?:^|\W)ontimeerror(?:\W|$)',
235 + r'(?:^|\W)ontrackchange(?:\W|$)',
236 + r'(?:^|\W)onunderflow(?:\W|$)',
237 + r'(?:^|\W)onurlflip(?:\W|$)',
238 + r'(?:^|\W)seeksegmenttime(?:\W|$)',
239 + r'(?:^|\W)svgabort(?:\W|$)',
240 + r'(?:^|\W)svgerror(?:\W|$)',
241 + r'(?:^|\W)svgload(?:\W|$)',
242 + r'(?:^|\W)svgresize(?:\W|$)',
243 + r'(?:^|\W)svgscroll(?:\W|$)',
244 + r'(?:^|\W)svgunload(?:\W|$)',
245 + r'(?:^|\W)svgzoom(?:\W|$)',
246 + ]
247 +
248 +
249 +# This is the actual re to look for the above patterns
250 +_badhtml = re.compile('|'.join(_badwords), re.IGNORECASE)
251 +# This is used to filter non-printable us-ascii characters, some of which
252 +# can be used to break words to avoid recognition.
253 +_filterchars = re.compile('[\000-\011\013\014\016-\037\177-\237]')
254 +# This is used to recognize '&#' and '%xx' strings for _translate which
255 +# translates them to characters
256 +_encodedchars = re.compile('(&#[0-9]+;?)|(&#x[0-9a-f]+;?)|(%[0-9a-f]{2})',
257 + re.IGNORECASE)
258 +
259 +
260 +def _translate(mo):
261 + """Translate &#... and %xx encodings into the encoded character."""
262 + match = mo.group().lower().strip('&#;')
263 + try:
264 + if match.startswith('x') or match.startswith('%'):
265 + val = int(match[1:], 16)
266 + else:
267 + val = int(match, 10)
268 + except ValueError:
269 + return ''
270 + if val < 256:
271 + return chr(val)
272 + else:
273 + return ''
274 +
275 +
276 +def suspiciousHTML(html):
277 + """Check HTML string for various tags, script language names and
278 + 'onxxx' actions that can be used in XSS attacks.
279 + Currently, this a very simple minded test. It just looks for
280 + patterns without analyzing context. Thus, it potentially flags lots
281 + of benign stuff.
282 + Returns True if anything suspicious found, False otherwise.
283 + """
284 +
285 + if _badhtml.search(_filterchars.sub(
286 + '', _encodedchars.sub(_translate, html))):
287 + return True
288 + else:
289 + return False
290
291
292
293
294 --
295 gentoo-commits@l.g.o mailing list