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'<\1>', 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'<\1>', 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('<', '<') |
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 |