[ZCM] [ZC] 1315/ 5 Reject "Plone via sento_form can be used for sending SPAM"

Collector: Zope Bugs, Features, and Patches ... zope-coders-admin at zope.org
Wed May 5 10:01:37 EDT 2004


Issue #1315 Update (Reject) "Plone via sento_form can be used for sending SPAM"
 ** Security Related ** (Public)
 Status Rejected, Zope/bug+solution critical
To followup, visit:
  http://zope.org/Collectors/Zope/1315

==============================================================
= Reject - Entry #5 by Caseman on May 5, 2004 10:01 am

 Status: Pending => Rejected

This is not a Zope bug. Please file it in the Plone collector. Zope and Plone are developed independently.
________________________________________
= Comment - Entry #4 by johnf on May 5, 2004 8:42 am


Uploaded:  "template"
 - http://zope.org/Collectors/Zope/1315/template/view
filled in template
________________________________________
= Comment - Entry #3 by johnf on May 5, 2004 8:41 am


Uploaded:  "qfi457NUdL028368"
 - http://zope.org/Collectors/Zope/1315/qfi457NUdL028368/view
mqueue qf file
________________________________________
= Comment - Entry #2 by johnf on May 5, 2004 8:41 am


Uploaded:  "dfi457NUdL028368"
 - http://zope.org/Collectors/Zope/1315/dfi457NUdL028368/view
mqueue df file
________________________________________
= Request - Entry #1 by johnf on May 5, 2004 8:37 am


Uploaded:  "http_session"
 - http://zope.org/Collectors/Zope/1315/http_session/view
Hi,

  I think I've discovered a bug in Plone sento_form which allows spammers to send mail to arbitrary senders with arbitrary content. I noticed excessive load on my server this evening and after some investigation discovered my mail queue full of emails destined to AOL. These emails were coming from localhost sendmail logs are

May  5 17:00:58 odie sm-mta[25967]: i4570mdL025967: from=<jon462 at highstream.net>, size=7356, class=0, nrcpts=501, msgid=<200405050700.i4570mdL025967 at odie.inodes.org>, proto=ESMTP, daemon=MTA, relay=zope at localhost [127.0.0.1]
 May  5 17:01:11 odie sm-mta[25990]: i4570mdL025967: to=<josephine44 at eatmanifesto.com>, delay=00:00:22, xdelay=00:00:11, mailer =local, pri=15037593, dsn=2.0.0, stat=Sent

The two lines go on and on with about 500 recipients per message. With around 150 messages. Interestingly these requests are coming from many different IPs so it looks like a distributed attack.

In the from line you can see the messages are coming from zope at localhost. I checked the apache logs for the same time for all my zope sites and found entries like this.

213.52.201.254 - - [05/May/2004:18:30:13 +1000] "POST /eMBlog/organicboom/organicboom/sendto_form HTTP/1.0" 502 553 "http://www.eatmanifesto.com/" "-" 5 www.eatmanifesto.com

There are about 150 such entries around the time of the incident in my logs. It all seems to have started at around 4:47 am GMT. I picked it up about 2 hours after that. My IP is currently blocked by AOL not surprisingly.

There are about 150 such entries around the time of the incident in my logs. It all seems to have started at around 4:47 am GMT. I picked it up about 2 hours after that. My IP is currently blocked by AOL not surprisingly.

Next I did some tcpdumping to try and catch a request in action. I've attached a RAW dump but essentially a POST is being made with CGI parameters as follows

send_to_address="
To: louie590 at eatmanifesto.com
From: vernor357 at aol.com
Subject: autocorrelation                cz WI0Eea /a JXO QQZ Wo
bcc: <SNIP Hundereds of aol addresses>
Content-Type: multipart/mixed; boundary=JKycyn9eAgQSMkkdlCVthD5RW4ujH1

--JKycyn9eAgQSMkkdlCVthD5RW4u jH1
Content-Type: text/html
Content-Transfer-Encoding: quoted-printable

<SNIP SPAM BODY>

send_from_address=louie590 at www.eatmanifesto.com
form.button.Send=Send
form.submitted=1
lastfield=lastvalue


Notice that the send_to_address line is actually a whole email. The second and third attachments are sendmail mqueue files. You'll see that the result is an email addressed to 1000 recipients. The body of the email is the contents of the send_to_address field and the actual plone template is tacked onto the end.


After this I dove into the source code, whats happening is as follows.

The sendto_form basically executes
/usr/lib/zope/lib/python/Products/CMFPlone/skins/plone_form_scripts/sendto.cpy

in here the arguments are setup as
variables = { 'send_from_address' : REQUEST.send_from_address
            , 'send_to_address'   : REQUEST.send_to_address
            , 'url'               : context.absolute_url()
            , 'title'             : context.Title()
            , 'description'       : context.description
            , 'comment'           : REQUEST.get('comment',None)
            }

and a call is made to

plone_utils.sendto( variables )

>From the variables that are passed you would think it would be impossible to alter the content since no content is passed. 

Looking further at
/usr/lib/zope/lib/python/Products/CMFPlone/PloneTool.py
we find the sendto function.

First it takes all the variables and fills in the Template. This ends up giving you a large text string something like attachment 4.  With the first few lines looking like

To:
To: niki261 at eatmanifesto.com
From: webster482 at compkarori.com   
Subject: on the close order                                       fbfz KxeQr 76 AX 4/ E yGw
bcc: mpd2001 at aol.com,<SNIP>

<SNIP EMAIL CONTENT>
<SNIP Actual template>

sendto then takes all this text and calls

host = self.MailHost
host.send( mail_text )

so we proceed to
/usr/lib/zope/lib/python/Products/MailHost/MailHost.py

now in this case send has been called with only 1 argument no to fields etc have been set.

So the first thing send does is call _mungeHeaders(messageText, mto, mfrom, subject)
not that all of mto, mfrom, subject will be NULL since these args weren't passed to send.

in _mungeHeaders first the message gets converted to a string. Then rfc822.Message is called on this string to create a message object mo.


further on in munge headers we see the following bit of code.

if mto:
       <code snipped>
else:
        for header in ('To', 'Cc', 'Bcc'):
            v = mo.getheader(header)
            if v:
                mto += [rfc822.dump_address_pair(addr) for addr in rfc822.AddressList(v)]
        if not mto:
            raise MailHostError, "No message recipients designated"

this is where we come unstuck. mto isn't defined so getheader is called for To, Cc and Bcc in the message. Since we now have a deviously placed BCC field. 100 recipients are pulled out of the message and then the message is sent. MailHost is even kind enough to then delete the bcc line here

 if mo.getheader('Bcc'):
        mo.__delitem__('Bcc')

So as you can see there is a known exploit here to send spam. I wouldn't even have noticed except for high load on my box caused by spamassasin and clamav as it tried to process all these messages.


I would recommend to fixes to the problem

/usr/lib/zope/lib/python/Products/CMFPlone/skins/plone_form_scripts/validate_sendto.vpy
should validate that the send_to_address is sane and only contains one line maybe it should even check that there is only one recipient.


also in
/usr/lib/zope/lib/python/Products/CMFPlone/PloneTool.py
sendto should use a fuller version of send in MailHost ie
host.send(mail_text, send_to_address, send_from_address)

The template should also be fixed to not add To and From headers since it is utilising non sanitised data provided by the user. That way unallowed message content can never make its way into the message.

Anyway thats about as in depth an analysis as I can do. Also thanks to vinsci on IRC who pointed me in the right direction on how to report this the best.

Hopefully the above makes sense caveats are that even though I am a decent coder I don't actually know any Python and know next to nothing about zope. I just admin the server its installed on. So feel free to ignore my advice.

Also hope I'm not telling you something you already know.

Thanks

==============================================================




More information about the Zope-Collector-Monitor mailing list