Monday 22 October 2012

Fixing Postie the Wordpress Plugin for XSS Attacks that don't exist

Fixing the "Possible XSS attack - ignoring email" error message in Postie

As you may know if you read my earlier post on fixing the Wordpress plugin Postie when it wouldn't let me pass multiple categories in their various formats in the subject line a new version of Postie has come out since.

However I have been regularly noticing that emails that should be appearing on my Wordpress site when they are posted by email using Postie haven't been.

Today I looked into why and when I ran the manual process to load emails by pressing the "Run Postie" button I was met with an error message that said

possible XSS attack - ignoring email

I looked into the code and searched for the error message which is on line 38 of the file postie_getmail.php and it gets displayed when a Regular Expression runs that is supposed to detect XSS attacks.

The code is below

if (preg_match("/.*(script|onload|meta|base64).*/is", $email)) {
 echo "possible XSS attack - ignoring email\n";
 continue;
}

I tested this was the problem by running the script manually in the config area of Postie and outputting the full email before the regular expression test.

As the email is base64 encoded (well mine is anyway) the full headers are shown at the top of the encoded email e.g

Return-Path:
X-Original-To: xx12autopost230.sitename@domain-name.com
Delivered-To: xx12autopost230.sitename@domain-name.com
Received: from smtp-relay-2.myrelay (smtp-relay-2.myrelay [111.11.3.197])
by domain-name.com (Postfix) with ESMTP id 8497724009C
for ; Mon, 22 Oct 2012 05:49:32 +0000 (UTC)
Received: from xxxxxxx (unknown [11.1.1.1])
by smtp-relay-2.myrelay (Postfix) with ESMTP id 9E3B495733
for ; Mon, 22 Oct 2012 06:45:30 +0100 (BST)
MIME-Version: 1.0
From: admin@sitename.com
To: xx12autopost230.sitename@domain-name.com
Date: 22 Oct 2012 06:46:28 +0100
Subject: Subject: [My Subject Category1] [My Subject Category2] Title of Email
 October 2012
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
Message-Id: <20121022054530 .9e3b495733=".9e3b495733" smtp-relay-2.myrelay="smtp-relay-2.myrelay">

PHA+PHN0cm9uZz5ZZXN0ZXJkYXlzIG1lbWJlcnMgaGFkIGFjY2VzcyB0byA0NSB0aXBzIGFj
cm9zcyA4IGRpZmZlcmVudCBzeXN0ZW1zLjwvc3Ryb25nPjwvcD48cD5JZiB5b3UgaGFkIHBs
YWNlZCBhIEJldGZhaXIgbWluaW11bSBiZXQgb2YgJnBvdW5kOzIuMDAgb24gZWFjaCBiZXQg
PHN0cm9uZz5vbiBFVkVSWSBzeXN0ZW08L3N0cm9uZz4gKExheXMsIFBsYWNlIERvdWJsZXMs
IFdpbnMgZXRjKSB0aGF0IGhhZCBhbiBTUCBsZXNzIHRoYW4gMTkvMSBhdCB0aGUgdGltZSBJ

I've just shown a bit of the message which is base64 encoded.

As you can see if you do a search for one of the strings he is searching for as a word not in a scriptual context e.g base64 not base64("PHA+PHN0cm9"); 

The word base64 appears in the headers of the email e.g:

Content-Transfer-Encoding: base64

Therefore the regular expression test fails and Postie displays the "possible XSS attack - ignoring email" error message.

Therefore just doing a basic string search for these words:

script, onload, meta and base64

Will mean that you could find yourself having emails deleted and content not appearing on your Wordpress site when you expect it to. All due to this regular expression which will be popping up false positives for XSS attacks when none really exist.

Also these words could legitimately appear in your HTML content for any number of reasons and not just because they are used in the email headers so a better regular expression is required to check for XSS attacks.

How to fix this problem

You could either remove the word base64 from the regular expression or you could delete the whole test for the XSS attack.

However I went for keeping a test for XSS attacks but making sure they were checking more thoroughly for proper usage of the functions rather than simple tests for occurrences of the word.

The regular expression is more complicated but it covers more XSS attack vectors and I have tested it myself on my own site and it works fine.

You can replace the code that is causing the problem with the code below.


if(preg_match("@((%3C|<)/?script|<meta|document\.|\.cookie|\.createElement|onload\s*=|(eval|base64)\()@is",$email)){
      echo "possible XSS attack - ignoring email\n";
      continue;
}

Not only does this mean that it won't fall over when the words are mentioned in headers but it actually looks for the correct usage of the hack and not just the word appearing. E.G instead of looking for "script" it will look for

<script %3Cscript </script %3Cscript 

This includes not only the basic <script but also urlencoded brackets which are another common XSS attack vector. You could include other forms of encoding such as UTF-8 but it all depends on how complicated you want to make the test.

As you may know if you have read my blog for a long time hackers are always changing their methods and I have come across clever two stage SQL injection attacks which involve embedding an encoded hack string first and then a second attack that's role is to unencode the first injection and role out the hack.

The same can be done in XSS attacks, e.g encoding your hack so it's not visible and then decoding it before using an eval statement to execute it. However I am keeping things simple for now.

I have also added some more well known XSS attack vectors such as:

eval( , document. , .createElement and .cookie 

As you can see I have all prefixed or suffixed them with a bracket or dot which is how they would be used in JavaScript or PHP.

Notice however that I haven't prefixed createElement and cookie with the word document. This is because it is all too easy to do something like this:

var q=document,c=q.cookie;alert(c)

Which stores the document object in a variable called "q" and then uses that to access the cookie information. If you have a console just run that piece of JavaScript and you will see all your cookie information.

This regular expression still also tests for:

<script, base64(, <meta, onload= and onload =

but as you can see I have prefixed the words with angled brackets or suffixed them with rounded brackets, dots or equal signs (with or without a space).

This has solved the problem for me and kept in the XSS attack defence however if you are passing HTML emails containing JavaScript to your site just beware that if you use any of these functions they might be flagged up. 

I have tested each XSS attack vector but let me know of any problems with the regular expression.

Also I have removed the .* before and after the original test as it's not required. Also it just uses up memory as its looking for any character that may or may not be there and the longer the string it's searching the more memory it eats up.

I have updated my own version of this file and everything has gone onto the site fine since I have done so.

If anyone else is having problems with disappearing posts driven by Postie then this "might be the cause."

You can see my Wordpress response here: Wordpress - Postie Deletes Email but doesn't post

13 comments:

Mota e Nogueira Advogados said...

you are a genius! thanks so much.
one thing: please add a "{" at the end of the first line of your fix code... it is missing. I added and it worked.

Rob Reid said...

Hi Mota

Cheers for spotting that.

It's amazing what you lose on the way from a working file to writing a blog!

I have added the { at the end of the first line.

Thanks for commenting

Joe Skelton said...

You are (pardon my French) fuxxking ace!

Not only did you fix the Posite plugin for the categories now your fixing the XSS false positives.

Is the developer paying you or something as if he isn't he should be?

Rex said...

I am sorry, but this still does not fix it.

I can publish plain text email with attached images to the my blog. But either rich text or html emails still fail to get through the test.

<meta still gets matched, but curiously when I remove |<meta, the email gets only partially published.

I am still looking for a solution on this one ...

Rex.

Rex said...

I have tested this further. The problem of the post corrupting is not related to removing |<meta from the regular expression. The problem also occurs if I remove the XSS test lines altogether. If I send the email in rich text or plain text, it gets posted fine.

For the moment I am using the regular expression without the |<meta search parameter and emailing using rich text.

Thanks.

Rex.

Rob Reid said...

So you are saying that the old OR new XSS test is not the reason why your emails are not getting posted to your website?

It sounds as if you remove the full regular expression XSS test then your post is still not appearing and if you were not getting a "possible XSS attack - ignoring email" error message then it was nothing to do with the XSS code in the first place. Am I right?

Have you tried just putting simple echo statements all through the function outputting your email contents to see where it gets to before it dies?

Also what error message are you getting when you run Postie manually with an email in the queue waiting to be posted?

Post an example of the full HTML email containing all your HTML tags etc that way people can try to replicate your problem.

Thanks

Unknown said...

Thanks for the work you've done on this. I still have an XSS problem though.

For a while using 1.4.3 there were no issues as such. But now using 1.4.5 I still have XSS problems using Outlook from my computer - but it does send from Gmail.

I assume something to do with a code that Outlook is putting in the header?

Rob Reid said...

You need to put echo statements in that function outputting the full email Postie is trying to parse and post it so I can see otherwise I can't help you if I don't know what your email content is.

Rob Reid said...

Of course you could just do the easy thing and remove the XSS code or keep using the version that worked.

Unknown said...

Thanks Mr Reid,

Unfortunately I'm no programmer so don't really understand how to take the XSS stuff out although I think it's misinterpreting the Base 64 stuff.

Here is what you asked for:-


Return-path:
Envelope-to: email@mydomain.com
Delivery-date: Sat, 17 Nov 2012 23:15:25 -0600
Received: from [86.22.6.128] (port=2572 helo=owner9d7244b5f)
by gator271.hostgator.com with esmtpa (Exim 4.80)
(envelope-from )
id 1TZxE5-0007GL-6F
for email@mydomain.com; Sat, 17 Nov 2012 23:15:25 -0600
Reply-To:
From: "Jeremy"
To: ,
"'Anna'"
Subject: Tech: YOYYOYOYO This is a test
Date: Sun, 18 Nov 2012 05:15:23 -0000
Organization: Organisation
Message-ID: <003d01cdc54b$b78024a0$26806de0$@co.uk>
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_003E_01CDC54B.B78024A0"
X-Mailer: Microsoft Office Outlook 12.0
Thread-Index: Ac3FNZ3AzntnrYwqSm2JyYBrosJJ6gAAEOBgAAAXVbAAABJH0AAADlNwAAA+UNAAABs28AAEx9ygAAAYuqA=
Content-Language: en-gb
X-MS-TNEF-Correlator: 0000000041E8648103E69E408EB986CED8F5D955C43B8C00

This is a multi-part message in MIME format.

------=_NextPart_000_003E_01CDC54B.B78024A0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

:start

BODY TEXT

:end


------=_NextPart_000_003E_01CDC54B.B78024A0
Content-Type: application/ms-tnef;
name="winmail.dat"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="winmail.dat"

CODE

------=_NextPart_000_003E_01CDC54B.B78024A0--

Hope it makes sense to you.

Richard

Rob Reid said...

Well the old XSS test just checked for the word "base64" anywhere in the email and the headers the new one I did checks for the word with a bracket after it which is how it would be used in an XSS hack attack eg "base64(" I cannot see anything in there that would throw a false positive but I'm on my phone so can't do much. Just read the article, go to the file and lines mentioned and comment out or remove the whole 3 lines that carry out the XSS test. Then you can see if its a problem with that code. Also you might be passing other content in your email that would cause a false positive eg passing any Jacascript etc or meta tags or other script content as if your passing that in your email it would be flagged as dangerous anyway so if you want to pass content like that you need to remove the code. By the way I'm not the programmer of the plugin so if you want to pay someone to fix your code you should probably ask him first.

Unknown said...

Okay

Thanks for getting back to me.

Will try

iWebExpert said...

Wow. So this is how to fix it. Thanks so much for sharing.
Do keep it up.