Link to home
Start Free TrialLog in
Avatar of iaing1000
iaing1000

asked on

Implementing a whitelist of permitted services and hosts in a WordPress site

After a security review of our new WordPress site it was pointed out that we're vulnerable to "External Service Redirecton - DNS". Specifically, if a URL is entered into the "Your Name" field of our Contact 7 Form then the testers have found that: "It was possible to induce the application to perform server-side DNS lookups of arbitrary domain names"

The suggested remedial action is to implement a whitelist of permitted services and hosts and to block interaction not on this whitelist.

I'm something of a newbie when it comes to this, and it occured to me (perhaps wrongly!) that there may be different whitelists; one for those who cannot enter the site, and a separate for sites to which our server is allowed to speak. Or does a whitelist imply both ways?

Anyway, all help on this gratefully received and I'm imagining this is something that's been done a zillion times before!

I'm using IIS and would prefer that answer, although Apache related help just as good because I've realised I can kind of 'translate' how to do it once I've got the idea.

Incidentally, we definitely want to avoid editing the Contact 7 form's code too much becasue this may be lost when we upgrade, even though I dare say this would fix the issue. Unfortunately the latest version has the same problem, although will let the Contact 7 team know to look into this. Would ideally like to use another form for data collection of this sort although i'm a part of a team that prevents this!

And so, in the meantime it appears that a whitelist solution will likely do the trick, any ideas on how to do that anyway?


Thanks in advance
Iain
Avatar of Dan McFadden
Dan McFadden
Flag of United States of America image

- What version of the Contact 7 Form are you using?
- Have you enabled the "Spam Filtering with Akismet" functionality.  This checks if the content of the field is spam or not.  I imagine this functionality includes doing a lookup because it talks with an API.  A quote from Contact 7's docs about this functionality:

When at least one of those options are set (remember, it’s recommended to set all of the options for accurate judgment), Contact Form 7 will send Akismet all of the sender’s input and the information relating to the submitting activity. Akismet will then judge whether this submission is likely to be spam.

Link:  https://contactform7.com/spam-filtering-with-akismet/

Can you post the configuration of the "Your Name" field from the Admin section of the Contact 7 manager?

It sort of sounds like the text field is defined incorrectly in the Contact 7 plugin.

Dan
Avatar of iaing1000
iaing1000

ASKER

Hi Dan,

Brilliant, thanks for this, I'll have a look in the morning. Hopefully this will this clear things up.

Do you happebn to know how to configure a whitelist? Looks like this is going to be a requirement anyway,

Thanks
Iain
I'm not sure what exactly is meant by white-listing "services and hosts."  IIS does have a feature called IP Address and Domain Restrictions which you can configure to allow or deny rules based on specific IP Addresses (or ranges) and/or Domains.

As for white-listing applications, IIS does not have any features that implement such controls over access.

In IIS Manager, if there is a physical directory where the Contact7 form exists, you can place a default DENY rule on all access and then setup rule or rule that would allow access for specific IPs or IP Ranges.  I do not recommend enabling the Domain part of the feature since it will consume additional resources in order to resolve DNS domains prior to implementing the rules.

Here is the tech docs from Microsoft for the IIS Feature:  https://docs.microsoft.com/en-us/iis/configuration/system.webserver/security/ipsecurity/

If you can share more from the security review report, it may be possible that I can make some additional recommendations.

Dan
Thanks again Dan, wil lcome back to this later just got tied up with something. Much appreciated
Security Issue
External service interaction (DNS)

It was possible to induce the application to perform server-side DNS lookups of arbitrary domain names. The payload http://pzsf5lcz574jehijh6sav5698bvcdsd6o76ct0lnhb6.burpcollaborator.net?Fred_Bloggs was submitted in the your-name parameter.
The application performed a DNS lookup of the specified domain.
The lookup was received from IP address xx.xx.xx.xx at 2017-Nov-11 10:56:47 UTC.


Description
External service interaction arises when it is possible to induce an application to interact with an arbitrary external service, such as a web or mail server. The ability to trigger arbitrary external service interactions does not constitute a vulnerability in its own right, and in some cases might even be the intended behavior of the application. However, in many cases, it can indicate a vulnerability with serious consequences.

In cases where DNS-based interactions can be triggered, it is normally possible to trigger interactions using other service types, and these are reported as separate issues. If a payload that specifies a particular service type (e.g. a URL) triggers only a DNS-based interaction, then this strongly indicates that the application attempted to connect using that other service, but was prevented from doing so by egress filters in place at the network layer. The ability to send requests to other systems can allow the vulnerable server to be used as an attack proxy. By submitting suitable payloads, an attacker can cause the application server to attack other systems that it can interact with. This may include public third-party systems, internal systems within the same organization, or services available on the local loopback adapter of the application server itself. Depending on the network architecture, this may expose highly vulnerable internal services that are not otherwise accessible to external attackers.


Recommendation
You should review the purpose and intended use of the relevant application functionality, and determine whether the ability to trigger arbitrary external service interactions is intended behavior. If so, you should be aware of the types of attacks that can be performed via this behavior and take appropriate measures. These measures might include blocking network access from the application server to other internal systems, and hardening the application server itself to remove any services available on the local loopback adapter.

If the ability to trigger arbitrary external service interactions is not intended behavior, then you should implement a whitelist of permitted services and hosts, and block any interactions that do not appear on this whitelist.


Evidence
Whilst it is hard to demonstrate this particular finding as there is no visual response from the webserver, the request and response headers have been included which show the request that was made and also includes the time stamp. This could be correlated to the webservers DNS logs to further validate that a DNS request was made as a result of the request.
Hi,

I've posted the specifics of the finding. Specifically, the long URL was submitted in the your-name field of our Contact 7 form (I dare say the same issue exists in other fields too of course). The description and recommendation I've discovered are lifted directly from the Portswigger site where External Service Interaction (DNS) is listed as a potential security flaw.

I'm simply trying to follow the recommendations and set up such a Whitelist. Another tricky thing is that this isn't an obvious one to test internally once we have a supposed fix (at least it's not clear to me anyway!), as it also states in the evidence section.

Hope that makes sense,

Thanks
Iain
After reading thru the analysis posted, I would recommend investigating the configuration of the Contact7 form.  Where or who is the developer of the site?  I would present the above statement about the vulnerability to the person/team/company that developed the site for you and have them mitigate this issue.

Also, is this form available on the Internet or is this only an internal form?

Setting up rules in the "IP Address and Domain Restrictions" feature will be complicated (if not impossible) if this is an Internet facing site.  

Can you post the Evidence that they provided for this issue?  

Whilst it is hard to demonstrate this particular finding as there is no visual response from the webserver, the request and response headers have been included which show the request that was made and also includes the time stamp.

Dan
Hi Dan,

The site was developed by a separate company and we've been handed over the work although they will continue to edit parts of the WP site. Our experience (3 of us!) is really more databases and app development.

One of our jobs now is to get us through CHECK certification and an initial analysis of what we'd been left indicated 24 issues, of varying severity (critical, high, medium, low - although that's kind of a very subjective scale!) of which I've resolved 22. Mainly edits to wp_config, http headers, httpd.conf or IIS settings to do with SSL/TLS and similar, plus WP updates for the core and plugins and the addition of a 2FA plugin. All good so far but for two remaining, one of which is this (all of wihch were pretty much new to me).

The site is public facing on the internet. Will shortly post their transcription of the 'evidence'.

Thanks
Iain
Here's what they supplied as evidence:

HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Type: text/html: charset=UTF-8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Server: Microsoft-IIS/8.5
X-Powered-By: PHP/5.5.34
X-Pingback: https://oursite_xxxx.com/xyzxyz.php
Link: <https://oursite_xxxx.com/wp-json/>; rel="https://api.w.org"
Link: <https://oursite_xxxx.com/?p=34>; rel=shortlink
Date: Mon, 20 Nov 2017 10:56:53 GMT
Connection: close
Content-Length: 27929
So, first a few questions:

- What version of WP?
- What version of the Contact Form 7?
- How many sites are running on the server?
- How IPv4 addresses are set up on the server?
- What protocols are bound to the site's IP Address?
- How are those protocols bound to the site's IP Address?

Unfortunately this is not an easy one to resolve.  "External service interaction" is also known as "Server Side Request Forgery (SSRF)" and is usually resolved down at the coding level.  Here's a little info about it:

Links:
- https://www.owasp.org/index.php/Server_Side_Request_Forgery
- https://affinity-it-security.com/prevent-server-side-request-forgery/
- https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery (scroll down to the "JavaScript, AJAX, and SPAs" section)
- https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

If you read thru the links above, they all speak of using code to address this specific vulnerability. So mitigating this issue would, most likely, require some type of code fix or plug-in fix on the Contact Form 7.  Again, I recommend inspecting the configuration of the form fields that are affected.

Most fixes involve input validation, use of Antiforgery tokens and sometimes jsut designing around it.

Also interesting to note, the in Wordpress sites (according to the article Understanding WordPress Security Vulnerabilities), SSRF constitutes less than 1% of the known vulnerabilities.

There are also a few other configuration items that I see, from a security standpoint, that have not been implemented at either the IIS Server scope or the site scope.

For example:
1. The HTTP Response Header "Server" is returning the server info "Microsoft-IIS/8.5"
--- this tells me that you are running Windows Server 2012 R2.
--- This header should be disabled
2.  The HTTP Response Header "X-Powered-By" is returning PHP info "PHP/5.5.34"
--- this tells me that you are using an old version of PHP (5.5.34 was release 30-MAR-2016) & is 32bit since 5.5.x support for x64 is only experimental.
--- IMO, this is a significant attack vector.  This header should, at least, be disabled!
3.  There are no advanced security HTTP Response headers setup.
--- Test your site's HTTP Response Headers at:  https://securityheaders.io/
--- How to article:  https://scotthelme.co.uk/hardening-your-http-response-headers/

Without knowing more about the Contact Form 7, it will be hard for me to make any further recommendations.

Hopefully some of this info helps.

Dan
Hi, thanks for this, here's some more details:

WP — 4.9.2
Contact Form 7 — 4.9.1
Just the one site running on the server
Just running from one IPv4 address
http & https are both bound on ports 8080 & 43 respectively (is this what you're asking?)

Some of the http header information we've now changed anyway since these cropped up in the list of initial 24 security concerns, although this is very useful to me with the links as well.

My suspicion is now that we go the input validation route because a) the IP whitelisting may be a hassle and b) if it fixes the issue then I'm less worried anyway and it'll 'pass'.

Looking back at your previous post, and before I grab it, were you referring to seeing how the your-name field appears in the admin.php file for the Contact 7 form or was there somewhere else I needed to look?

Thanks again
Iain
The HTTP & HTTPS ports.... why the non-standard configuration?   Default is HTTP on 80/tcp and HTTPS on 443/tcp.  On the site bindings, are you using "All Unassigned" for the IP address binding or have you specified the server's IP address.

My recommendation is to specify an IP address on the bindings.  The only time I recommend using the "All unassigned" option, is when implementing a catch-all site.  For example, in a web hosting provider scenario where you want to catch all 404s and serve up a default content not found page, in the event the hosted website does not define one.

Looking back at your previous post, and before I grab it, were you referring to seeing how the your-name field appears in the admin.php file for the Contact 7 form or was there somewhere else I needed to look?

Yes it was.

Dan
There would have been some odd legacy reason why these were changed. In any case these are now 80 & 443 respectivley - standardising makes sense. The IP address binding is currently set for All Unassigned, will need to look at this.

In the meantime I've installed the Akismet spam filtering free version and got the WP key etc to have it all working with the Contact Form 7. The collection for the your-name field is now appended with the akismet:author tag and the your-email with akismet:author_email tag. The upshot is that this correctly fails for their test case where name is suplied as "viagra-test-123" however it doesn't filter if the your-name field has a URL supplied. Which is what we're trying to filter out...

Before I go futher, is there anything specific I should be looking for in the admin.php file, e.g which function in particular?

Thanks
Iain
SOLUTION
Avatar of Dan McFadden
Dan McFadden
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
That makes a lot of sense. Now that the Akismet looks as though it won't filter URLa, validating the form details in code must be the best step. Will have a look at that and see if that fixes it.

Thanks again
OK, now that I know where to aim I've made some great progress.

In the functions.php file for the Contact Form 7 I've put the following:

add_filter('wpcf7_validate_text', 'your_validation_filter_func', 999, 2);
add_filter('wpcf7_validate_text*', 'your_validation_filter_func', 999, 2);

function your_validation_filter_func($result, $tag) {
	
	$type = $tag['type'];
	$name = $tag['name'];

	if ('your-name' == $name) {
   	 	$the_value = $_POST[$name];
   	 	$myresult = substr($the_value, 0, 4);
   	 	if ($myresult == "Iain") {
     	   $result['valid'] = true;
   	 	} else {
    	    $result->invalidate($tag, "Test validation for text field");
    	}
	}

	return $result;
}

Open in new window


Obvs this isn't the final version but it works exactly as I'd like and doesn't post out, insteadgiving a validation error on the field.

Now just need to adapt it to use a RegEx that denies URLs that I'll look up shortly. Then may as well apply the same logic to the email field wihch it transpires also has no validation!

...and maybe have a word with whoever wrote this to start with :-)
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for this Dan, much appreciated.
Thanks for this, got it all sorted months back now!

Just came across this issue whilst looking for something else and thought I ought to give feedback - excellent stuff :-)
So what is the solution at last?