catch those malwares – outbound firewalling with openwrt / iptables

Hi,

ever wanted to do strict outbound firewalling on your openwrt router? For example only allow http and https outbound by default and get logging for everything that tries to connect to any different port on the internet?

You can to this quite easily by adding a couple of custom iptables lines to your openwrt firewall config file (/etc/firewall.user):

############ OUTBOUND Configuration ###################

#REJECT EVERYTHING
iptables -I zone_lan_forward -j zone_lan_dest_REJECT

#Enable Logging
iptables -I zone_lan_dest_REJECT -j REJECT
iptables -I zone_lan_dest_REJECT -p tcp -j REJECT --reject-with tcp-reset
iptables -I zone_lan_dest_REJECT -j LOG --log-prefix "REJECTED ON LAN: "
############ ALLOW SPECIFIC OUTBOUND TRAFFIC ##############
iptables -I zone_lan_forward -i br-lan -p tcp -m tcp --dport 80 -j zone_wan_dest_ACCEPT -m comment --comment "ALLOW HTTP"
iptables -I zone_lan_forward -i br-lan -p tcp -m tcp --dport 443 -j zone_wan_dest_ACCEPT -m comment --comment "ALLOW HTTPS"

Let me explain these lines one by one:

iptables -I zone_lan_forward -j zone_lan_dest_REJECT

This command will insert a rule at the top of your “zone_lan_forward” chain (which gets all traffic that is to be forwarded to the internet/wan interface) and will “jump” (-j) the packets over to the “zone_lan_dest_REJECT” chain.
All rules for traffic that we want to allow will be inserted later on and thus be above this rule. So this reject-rule only gets hit by traffic that we do not explicitly allow!

iptables -I zone_lan_dest_REJECT -j REJECT

This command will create a rule inside the “zone_lan_dest_REJECT” chain that will reject all traffic with an icmp uncreachable.

iptables -I zone_lan_dest_REJECT -p tcp -j REJECT –reject-with tcp-reset

This command will do the same as the one before, only that it will specifically reset tcp connections so they do not have to timeout slowly but get a tcp rst instantaneously. This saves you a lot of waiting for tcp timeouts.

iptables -I zone_lan_dest_REJECT -j LOG –log-prefix “REJECTED ON LAN: “

This command will log every packet hitting the “zone_lan_dest_REJECT” chain with a prefix of your liking (i chose “REJECTED ON LAN: “). You can grep on this prefix lateron.
Again notice the order of the commands. This command needs to be issued last so it will be sitting in front of the REJECT rules (see iptables -L output below for visualization).

iptables -I zone_lan_forward -i br-lan -p tcp -m tcp –dport 80 -j zone_wan_dest_ACCEPT -m comment –comment “ALLOW HTTP”

Now the traffic rules: This command inserts a rule at the top of the chain “zone_lan_forward”. Notice that this will insert this rule above the rule created from the first command I explained. Thus the traffic hitting this rule will be allowed instead of beeing “jumped” to the “zone_lan_dest_RECET” chain!

-i br-lan = incoming interface (check your routers config, e.g. ifconfig and see which interface holds your default gw ip)

-p tcp -m tcp = specifies the tcp protocoll and makes the connections state trackable (i dont use the state information in this example, you could leave the -m tcp option out)

–dport 80 = allow http / destination port 80

– j zone_wan_dest_ACCEPT = jump the packets to the accept-chain where they will be sucessfully routed

– m comment –comment “ALLOW HTTP” = comment the rule for human readability of the ruleset!

(I am only going to explain one rule as an example as these rules are quite self-explanatory and documentation of default iptables syntax is quite good on the internet and in the manpages)

You can also add this via the LuCI webfrontend:

iptables-LuCI

After you safed the /etc/firewall.user file (or the Custom Rules form in LuCI) make sure to restart the firewall:

/etc/init.d/firewall restart

The resulting iptables ruleset should look something like this:

root@router:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
delegate_input  all  --  anywhere             anywhere            

Chain FORWARD (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
delegate_forward  all  --  anywhere             anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
delegate_output  all  --  anywhere             anywhere            

Chain delegate_forward (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
zone_lan_forward  all  --  anywhere             anywhere            
zone_wan_forward  all  --  anywhere             anywhere            
reject     all  --  anywhere             anywhere            

Chain delegate_input (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
syn_flood  tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN
zone_lan_input  all  --  anywhere             anywhere            
zone_wan_input  all  --  anywhere             anywhere            

Chain delegate_output (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
zone_lan_output  all  --  anywhere             anywhere            
zone_wan_output  all  --  anywhere             anywhere            

Chain reject (4 references)
target     prot opt source               destination         
REJECT     tcp  --  anywhere             anywhere             reject-with tcp-reset
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable

Chain syn_flood (1 references)
target     prot opt source               destination         
RETURN     tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN limit: avg 25/sec burst 50
DROP       all  --  anywhere             anywhere            

Chain zone_lan_dest_ACCEPT (3 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            

Chain zone_lan_dest_REJECT (2 references)
target     prot opt source               destination         
LOG        all  --  anywhere             anywhere             LOG level warning prefix "REJECTED ON LAN: "
REJECT     tcp  --  anywhere             anywhere             reject-with tcp-reset
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable
reject     all  --  anywhere             anywhere            

Chain zone_lan_forward (1 references)
target     prot opt source               destination     
zone_wan_dest_ACCEPT  tcp  --  anywhere             anywhere             tcp dpt:https /* ALLOW HTTPS */    
zone_wan_dest_ACCEPT  tcp  --  anywhere             anywhere             tcp dpt:www /* ALLOW HTTP */
zone_lan_dest_REJECT  all  --  anywhere             anywhere            
zone_wan_dest_ACCEPT  all  --  anywhere             anywhere             /* forwarding lan->wan */
zone_lan_dest_REJECT  all  --  anywhere             anywhere            

Chain zone_lan_input (1 references)
target     prot opt source               destination         
zone_lan_src_ACCEPT  all  --  anywhere             anywhere            

Chain zone_lan_output (1 references)
target     prot opt source               destination         
zone_lan_dest_ACCEPT  all  --  anywhere             anywhere            

Chain zone_lan_src_ACCEPT (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            

Chain zone_wan_dest_ACCEPT (9 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            

Chain zone_wan_dest_REJECT (1 references)
target     prot opt source               destination         
reject     all  --  anywhere             anywhere            

Chain zone_wan_forward (1 references)
target     prot opt source               destination         
zone_wan_dest_REJECT  all  --  anywhere             anywhere            

Chain zone_wan_input (1 references)
target     prot opt source               destination         
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootpc /* Allow-DHCP-Renew */
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request /* Allow-Ping */
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https /* Allow-OpenVPN */
zone_wan_src_REJECT  all  --  anywhere             anywhere            

Chain zone_wan_output (1 references)
target     prot opt source               destination         
zone_wan_dest_ACCEPT  all  --  anywhere             anywhere            

Chain zone_wan_src_REJECT (1 references)
target     prot opt source               destination         
reject     all  --  anywhere             anywhere

Inspecting the logs

To see dropped connections you can use the “logread -f” command.

You should then manually allow all the connections you really want (add more lines after “allow http” and see all the junk that wants to phone home being dropped :)

I am currently thinking about redirecting the reject-logs to a central syslog server and build a small php/mysql frontend for log analysis.

You could also just forward all these logs to a splunk server…

Plese Note that this will not automatically show you all malware that could reside in your network. A lot of malware is likely to “phone home”/contact its c&c server via http/https. If you want to catch those you have to create a logging chain and rule for your accepted http/https traffic as well and create some kind of IP/URL tracking, blacklisting/whitelisting and possibly alerting!

Maybe I will create another blogpost regarding this.

Feel free to asks questions or post comments below!

Regards
Sebastian

Update 2014-09-14:

As requested in the comments here a screenshot of my “Netzwork -> Firewall -> General Settings”

general settings

Advertisements

About SebastianB

read it in my blog
This entry was posted in OpenWRT and tagged , , , , . Bookmark the permalink.

8 Responses to catch those malwares – outbound firewalling with openwrt / iptables

  1. Joe says:

    Hi SEbastian,

    Unfortunatelly I got the follwoing error message:

    root@OpenWrt:~# iptables -I zone_lan_forward -j zone_lan_dest_REJECT
    iptables v1.4.10: Couldn’t load target `zone_lan_dest_REJECT’:File not found

    Try `iptables -h’ or ‘iptables –help’ for more information.

    Would you be so kind that help me what’s the wrong?

    Thank you in advance.

    • SebastianB says:

      Hey,

      could you please post the exact console output in its entirety? Im not quite sure if this is because the Queue is missing or because your iptables is broken…

      Regards
      Sebastian

      • Joe says:

        Hi,

        I reseted my router(12.09) after then a tried your command in the firewall.user. After restart I got the follwoing:

        root@OpenWrt:~# /etc/init.d/firewall restart
        Loading defaults
        Loading synflood protection
        Adding custom chains
        Loading zones
        Loading forwardings
        Loading rules
        Loading redirects
        Loading includes
        iptables v1.4.10: Couldn’t load target `zone_lan_dest_REJECT’:File not found

        Try `iptables -h’ or ‘iptables –help’ for more information.
        iptables: No chain/target/match by that name.
        iptables: No chain/target/match by that name.
        iptables: No chain/target/match by that name.
        iptables v1.4.10: Couldn’t load target `zone_wan_dest_ACCEPT’:File not found

        Try `iptables -h’ or ‘iptables –help’ for more information.
        iptables v1.4.10: Couldn’t load target `zone_wan_dest_ACCEPT’:File not found

        Try `iptables -h’ or ‘iptables –help’ for more information.
        Optimizing conntrack
        Loading interfaces
        root@OpenWrt:~#

  2. JD says:

    Joe: I believe you need to set the default policy to “Reject” first, otherwise the “zone_lan_dest_REJECT” won’t be created.
    Using the GUI: Network -> Firewall – > Under ‘Zones’, select ‘Reject’ for WAN-LAN output.

  3. J says:

    SebastianB
    I was able to load all the firewall rules with no issues and did the restart command, but I noticed that my iptables details look very different than ours, all off my rules are missing the ACCEPT all- anywhere for all the policies, see below
    Chain INPUT (policy ACCEPT)
    target prot opt source destination
    delegate_input all — anywhere anywhere

    Chain FORWARD (policy DROP)
    target prot opt source destination
    delegate_forward all — anywhere anywhere

    Chain OUTPUT (policy ACCEPT)
    target prot opt source destination
    delegate_output all — anywhere anywhere

    It this normal? I made sure my general settings match your

    Thanks

  4. Dave B. says:

    Note the above will block DNS requests as well. if you want to allow those, add this to your /etc/firewall.user

    iptables -I zone_lan_forward -i br-lan -p udp -m udp –dport 53 -j zone_wan_dest_ACCEPT -m comment –comment “ALLOW DNS”

    With the addition of the above, this is a suitable configuration for the interior router mentioned in security now episode 549. Search https://www.grc.com/sn/sn-549.txt for “Matt from london”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s