{"id":134,"date":"2016-02-10T09:51:02","date_gmt":"2016-02-10T08:51:02","guid":{"rendered":"http:\/\/blog.le-vert.net\/?p=134"},"modified":"2016-02-10T10:02:05","modified_gmt":"2016-02-10T09:02:05","slug":"a-short-story-about-php-cms-spam-rbl-and-postfix-rate-limiting","status":"publish","type":"post","link":"https:\/\/blog.le-vert.net\/?p=134","title":{"rendered":"A short story about PHP CMS, Spam, RBL and Postfix rate-limiting"},"content":{"rendered":"<div class=\"twttr_buttons\"><div class=\"twttr_twitter\">\n\t\t\t\t\t<a href=\"http:\/\/twitter.com\/share?text=A+short+story+about+PHP+CMS%2C+Spam%2C+RBL+and+Postfix+rate-limiting\" class=\"twitter-share-button\" data-via=\"\" data-hashtags=\"\"  data-size=\"default\" data-url=\"https:\/\/blog.le-vert.net\/?p=134\"  data-related=\"\" target=\"_blank\">Tweet<\/a>\n\t\t\t\t<\/div><\/div><p>We had some issues today, at work, with a PHP-based CMS (hello |*@#-?! joomla) being used as a spam gateway.<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>The root cause (Joomla)<\/li>\n<\/ul>\n<p>I fixed the issue by figuring out what was the broken PHP file using <a href=\"http:\/\/www.abuseat.org\/findbot.pl\">findbot.pl<\/a> tool from\u00a0<a href=\"http:\/\/www.abuseat.org\/cmsvuln.html\">abuseat.org<\/a>. But my main concerns is that there&#8217;s no way to prevent this to happen again. PHP is broken by design, especially while being used for a <strong>CMS<\/strong>.<\/p>\n<p>Abuseat&#8217;s script helped me to find suspicious code, then confirmed by the apache logs:<\/p>\n<pre>62.84.241.155 - - [10\/Feb\/2016:07:08:03 +0000] \"POST \/templates\/_old2\/session.php HTTP\/1.1\" 200 316 \"-\" \"Mozilla\/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko\/20100101 Firefox\/43.0\"\r\n62.84.241.155 - - [10\/Feb\/2016:07:08:51 +0000] \"POST \/templates\/_old2\/session.php HTTP\/1.1\" 200 316 \"-\" \"Mozilla\/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko\/20100101 Firefox\/43.0\"\r\n62.84.241.155 - - [10\/Feb\/2016:07:09:38 +0000] \"POST \/templates\/_old2\/session.php HTTP\/1.1\" 200 341 \"-\" \"Mozilla\/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko\/20100101 Firefox\/43.0\"<\/pre>\n<p>In the meanwhile, Joomla has been updated an hopefully the security issue has been fixed.<br \/>\nAfter removing the bad file, the owner of my <em>turned-into-a-spambox-cms<\/em> looks being annoyed and seemed to try break-in again:<\/p>\n<pre>195.206.253.146 - - [10\/Feb\/2016:08:18:21 +0000] \"GET \/administrator\/index.php HTTP\/1.0\" 200 7778 \"-\" \"Mozilla\/4.0 (compatible; MSIE 7.0; Windows NT 6.0)\"\r\n195.206.253.146 - - [10\/Feb\/2016:08:18:21 +0000] \"POST \/administrator\/index.php HTTP\/1.0\" 303 228 \"-\" \"Mozilla\/4.0 (compatible; MSIE 7.0; Windows NT 6.0)\"\r\n195.206.253.146 - - [10\/Feb\/2016:08:18:21 +0000] \"GET \/administrator\/index.php HTTP\/1.0\" 200 7778 \"-\" \"Mozilla\/4.0 (compatible; MSIE 7.0; Windows NT 6.0)\"\r\n195.206.253.146 - - [10\/Feb\/2016:08:18:21 +0000] \"POST \/administrator\/index.php HTTP\/1.0\" 303 228 \"-\" \"Mozilla\/4.0 (compatible; MSIE 7.0; Windows NT 6.0)\"<\/pre>\n<p>No thanks, really. It&#8217;s been a pleasure but it&#8217;s time for me to move on:<\/p>\n<pre>root@some.server.com:~# shorewall drop 195.206.253.146\r\n195.206.253.146 Dropped<\/pre>\n<p>&nbsp;<\/p>\n<ul>\n<li>Preventing this from happening again ?<\/li>\n<\/ul>\n<p>So how could you care about this ? First thing, be sure to not mess your main SMTP IP address with it. Be sure to relay the CMS emails throught a specific\u00a0<strong>dedicated\u00a0SMTP server<\/strong> that&#8217;s not hidden being the same NAT as your main SMTP server. Otherwise, you will get blacklisted as soon as any flows open in Joomla.<\/p>\n<p>To ensure you&#8217;re fine, you can use one the <strong>multi-rbl checks online<\/strong> like\u00a0<a href=\"http:\/\/www.anti-abuse.org\/multi-rbl-check-results\">anti-abuse.org<\/a>\u00a0or\u00a0<a href=\"http:\/\/www.senderbase.org\/\">senderbase.org by Cisco<\/a>. If you&#8217;re not listed here, you&#8217;re probably fine. Otherwise it&#8217;s time to ask for removal on any blacklist and be patient. Your SMTP server won&#8217;t be trusted again until at least a couple of hours, probably couple of days to be un-blacklisted on the whole Internet.<\/p>\n<p>Of course, you may consider <strong>upgrading Joomla<\/strong>, <strong>changing password<\/strong> and <strong>avoid<\/strong> having thousands of <strong>useless plugins<\/strong>, but I guess you&#8217;re not in charge of this Joomla website, right ?<\/p>\n<p>Another thing that may help is to enable some PHP hardening tool called &#8220;<strong>suhosin<\/strong>&#8220;. It wasn&#8217;t ready while Debian Jessie has been released, so we&#8217;ll use the official upstream repository to get it.<\/p>\n<p>Here&#8217;s an extract of my <strong>docker<\/strong> file to enable this extension:<\/p>\n<pre>RUN echo 'deb http:\/\/repo.suhosin.org\/ debian-jessie main' &gt;&gt; \/etc\/apt\/sources.list\r\nRUN curl https:\/\/sektioneins.de\/files\/repository.asc | apt-key add -\r\nRUN apt-get update\r\nRUN DEBIAN_FRONTEND=noninteractive apt-get -y -o 'Dpkg::Options::=--force-confdef' -o 'Dpkg::Options::=--force-confold' --no-install-recommends --no-install-suggests install \\\r\n  php5-suhosin-extension\r\nRUN php5enmod suhosin<\/pre>\n<p>&nbsp;<\/p>\n<ul>\n<li>Treat the symptoms, as well as the cause<\/li>\n<\/ul>\n<p>So now, you&#8217;re using a different SMTP to relay emails coming from the insecure website&#8230; To avoid spaming the world and\/or overloading the internet connection, we&#8217;ll setup <strong>rate-limiting<\/strong> on the postfix server.<\/p>\n<p>We&#8217;ll use <strong>postfwd<\/strong> for this.<\/p>\n<pre>apt-get install postfwd<\/pre>\n<p><em>If using Debian Wheezy, make sure to get the one from backports, the default one is completly broken.<\/em><\/p>\n<p>Then, we set-up a rule limiting enforcing each <em>client_address<\/em> (IP connecting this SMTP server) to not send more than 5 emails every 5 minutes.<\/p>\n<p>Create new\u00a0<strong>\/etc\/postfix\/postfwd.cf\u00a0<\/strong>configuration file containing the following:<\/p>\n<pre>id=RULE001\r\n\taction=rate(client_address\/5\/300\/450 4.7.1: $$client_address: only 5 messages per 5 minutes allowed)<\/pre>\n<p>Then set <strong>STARTUP=1<\/strong> in\u00a0<strong>\/etc\/default\/postfwd<\/strong>.<\/p>\n<p>Then, edit your postfix configuration in <strong>\/etc\/postfix\/main.cf<\/strong> to add a new <strong>smtpd_recipient_restrictions<\/strong> setting like this:<\/p>\n<pre>smtpd_recipient_restrictions = \r\n  check_policy_service inet:127.0.0.1:10040,\r\n  permit_mynetworks,\r\n  reject_unauth_destination,\r\n  permit<\/pre>\n<p>The <strong>check_policy_service<\/strong> will check postfwd running on port 10040 which will return either <em>permit<\/em> or <em>deny<\/em>. Postfwd will reply with a <strong>450 temporary error<\/strong> if the rate has been exceeded.<\/p>\n<p>Beware of the order, in this example, even hosts being allowed to relay emails with this SMTP server, listed in <strong>$mynetworks<\/strong>, have been rate-limited.<br \/>\nThe reason is that this SMTP server is outside main corporate network and I <strong>don&#8217;t trust any<\/strong> of the hosts using it.<\/p>\n<p>Here&#8217;s another snippet from a production server:<\/p>\n<pre>smtpd_recipient_restrictions =\r\n    permit_mynetworks,\r\n    permit_sasl_authenticated,\r\n    reject_non_fqdn_recipient,\r\n    reject_unknown_recipient_domain,\r\n    reject_unauth_destination,\r\n    check_policy_service inet:127.0.0.1:10040,\r\n    permit<\/pre>\n<p>If you don&#8217;t have this setting yet, you can get the <strong>default value<\/strong> on your system by running<\/p>\n<pre>postconf smtpd_recipient_restrictions<\/pre>\n<p>I suggest to always add &#8220;permit&#8221; as the last action, even if it&#8217;s implicit it&#8217;s way more easy to understand the workflow by adding it.<\/p>\n<p>You can now restart both service and check the log files:<\/p>\n<pre>service postfwd restart\r\nservice postfix restart<\/pre>\n<pre>Feb 10 08:27:10 server postfwd2\/policy[14962]: [RULES] rule=0, id=RULE001, client=server.some.domain[123.123.123.123], sender=<edith_alford@some.domain>, recipient=<bukuballs@gmail.com>, helo=<server.some.domain>, proto=SMTP, state=RCPT, rate=rate\/6\/0.00s, delay=0.00s, hits=RULE001, action=450 4.7.1: 123.123.123.123: only 5 messages per 5 minutes allowed\r\nFeb 10 08:27:10 server postfix\/smtpd[15881]: NOQUEUE: reject: RCPT from server.some.domain[123.123.123.123]: 450 4.7.1 <bukuballs@gmail.com>: Recipient address rejected: 4.7.1: 123.123.123.123: only 5 messages per 5 minutes allowed; from=<edith_alford@some.domain> to=<bukuballs@gmail.com> proto=SMTP helo=<server.some.domain>\r\nFeb 10 08:27:10 server postfix\/smtpd[15881]: disconnect from server.some.domain[123.123.123.123]\r\nFeb 10 08:27:10 server postfix\/smtpd[15881]: connect from server.some.domain[123.123.123.123]\r\nFeb 10 08:27:10 server postfwd2\/policy[14962]: [RULES] rule=0, id=RULE001, client=server.some.domain[123.123.123.123], sender=<edith_alford@some.domain>, recipient=<bukucat311@charter.net>, helo=<server.some.domain>, proto=SMTP, state=RCPT, rate=rate\/6\/0.00s, delay=0.00s, hits=RULE001, action=450 4.7.1: 1123.123.123.123: only 5 messages per 5 minutes allowed\r\n<\/pre>\n<p>Of course, postfwd has many more feature, check its <a href=\"http:\/\/www.postfwd.org\/doc.html\">online documentation<\/a> !<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We had some issues today, at work, with a PHP-based CMS (hello |*@#-?! joomla) being used as a spam gateway. &nbsp; The root cause (Joomla) I fixed the issue by figuring out what was the broken PHP file using findbot.pl &hellip; <a href=\"https:\/\/blog.le-vert.net\/?p=134\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/posts\/134"}],"collection":[{"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=134"}],"version-history":[{"count":12,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/posts\/134\/revisions"}],"predecessor-version":[{"id":146,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/posts\/134\/revisions\/146"}],"wp:attachment":[{"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}