Published January 6th, 2009 by kabir
Problem Statement
When using the find command, it has the ability to find whatever you are looking for in sub-directories. For example, find . -type f -name "*2008*.txt" -ls will find all files with 2008 and .txt in the name in the current directory or any of its sub-directories. This is good but if you are trying to move such files into a sub-directory that already has files with this pattern, you are going to find it difficult to use find. Here is a short tick that you can use to hack this.
Limiting nosy find’s interest to current directory only
To limit find to your current directory, just use the -maxdepth 1 in the command-line. For example:
$ find . -maxdepth 1 -name "*2008*.txt"
This command will tell find to look for files with 2008 and .txt in the name but limit the scope to only one level of depth, which is equal to the current directory.
In our real-world scenario, we wanted to move these files to a sub-folder which is also called 2008 so here is what we ran:
$ find . -maxdepth 1 -name "*2008*.txt" -exec mv {} 2008 \;
Worked like charm!
Category: Utility | Tags: | Be the First to Comment »
Published January 5th, 2009 by kabir
Problem Statement
The most commonly used shell in CentOS is /bin/bash and like other shells such as /bin/sh, /bin/tcsh, it has command line limitations. One such limitation is the wildcard expansion size. For example, say you have a directory with thousands of files or subdirectories and want to run the rm command to remove only files with .php extension using rm -f *.php, you will run into the wildcard limitation of the shell. Here we will show you a simple work around.
Trying to delete a lot of files in a directory with thousands of files using rm -f *
Say you are trying to delete all PHP files using rm -f *.php in a directory with thousands of PHP cache files generated by the Smarty template engine, in such a case you will see an error message from shell such as the following:
/bin/rm: Argument list too long
What happened is that shell tried to expand the wildcard *.php and placed the file list in rm’s command-line argument list. Since each command-line argument list is really an array and there is a limit to how many arguments can be stored in a process’s memory space, it fails.
Using a workaround for wildcard expansion problem for commands like rm
The easiest solution is to run the find command and execute rm one by one for each matching file. For example, to delete all PHP scripts in a directory, you can run:
$ find . -type f -name "*.php" -exec rm -f {} \;
This tells the find command to find all files matching the given wildcard (*.php) and execute the rm -f command on each of the matching file. Thus, this command can avoid the wildcard expansion issue as the rm -f command sees only one argument at a time.
Category: shell | Tags: | Be the First to Comment »
Published December 10th, 2008 by kabir
Problem Statement
We really dislike plain-old FTP service for its lack of security. Unfortunately, there are still brain-dead (windows) programs out there that will not work with Secure FTP (SFTP) via SSH. When your users just cannot live without such brain-dead programs and you are tired of chasing down the vendors for a reasonable explanation for not using SFTP, you are forced to enable FTP service. Here we will discuss how you can make this ungodly act of enabling FTP service a bit more secure.
| Time Estimate (10 ~ 15 min) |
| We estimate that the entire process to create a chrooted jail using vsftpd daemon might take anywhere from ten to fifteen minutes. |
Step 1: Discourage users from using FTP service all together
Yes, try to talk the users out of using the FTP service all together! Show them the following flash video that our User Interface team put together up in a zippy to let (thick) people see the difference between SFTP and plain-old FTP.
Step 2: (Reluctantly) Use vsFTPD FTP Server
If you fail in step 1, install VSFTPD using yum -y install vsftpd. Once installed you will need to add the following line in your /etc/modprove.conf file:
alias ip_conntrack ip_conntract_ftp ip_nat_ftp
Now load the ip_conntrack module by running the following command as root:
modprobe ip_conntrack
Next update your /etc/sysconfig/iptables-config and modify the IPTABLES_MODULES line to include
“ip_nat_ftp” as shown below:
IPTABLES_MODULES ="ip_nat_ftp"
Restart iptables using service iptables restart.
Consider one or more of the security options:
- Use chroot jail concept so that each user who uses FTP can only see her home directory. You can always point her home directory to the directory where she likes to work
- Use IP based access control using iptables so that FTP is not available from anywhere in the world.
We will discuss both techniques here.
Step 3: Lock’em Up in Chroot Jail
The chroot jail concept is simple — user connects to your FTP server and gets locked into the home directory and cannot go outside the home directory as the home directory becomes the root (/) for the session. This forbids nosy users from browsing files and directories that have nothing to do with their work.
To enable chroot jail for vsftp daemon, do the following:
- Edit the
/etc/vsftpd/vsftpd.conf file and add or uncomment the following line:
chroot_local_user=YES
- Now restart vsftpd daemon using
service vsftpd restart
Now test your setup by FTPing into the server using an user account and see if you can browse files and directories outside the home directory or not. If your setup is correctly configured, you won’t be able to get outside the home directory, which appears as / (root).
Step 4: Use FTP only accounts
When creating FTP service on a CentOS server, consider making FTP-only users by setting the user’s shell to /sbin/nologin.
Step 5: Restrict incoming FTP access only to known IP addresses
If you know that your users access the FTP service from a known IP address list, you should consider locking up the FTP service to only work for those IP addresses. You can restrict this by creating iptable rules.
For example, to restrict FTP access to an IP address — 1.2.3.4 — you can change your FTP rule in the /etc/sysconfig/iptables file as follows:
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp -s 1.2.3.4 --dport ftp -j ACCEPT
After restarting iptables using service iptables restart you should be able to test if FTP connection is restricted to the named IP address or not by making an FTP request from that IP and also from an IP that is not listed in the iptables rules file for FTP.
Category: Remove Access, Security | Tags: | 2 Comments »
Published December 10th, 2008 by kabir
Problem Statement
We recently enabled Ip_conntrack for supporting FTP service using vsftpd daemon on a CentOS server that also runs memcached. A bit later we noticed that /proc/net/ip_conntrack shows a lot of entries for memcached. Since kernel level tracking of connections require memory and CPU resources, we wanted to not track memcached connections on a busy server. Here you will find out what we had to do to overcome this problem.
First Choice: stop using ip_conntrack kernel module on memcached server
This is the best option as tracking connections in kernel is really a memory/CPU resource concern.
Because, conntrac mechanism of the Linux kernal eats up memory and cpu time and may be disabling it can improve overall performance of memcached.
Second Choice: increase the max connection tracking size for the kernel
If you must use ip_conntrack, consider setting the maximum entry size (CONNTRACK_MAX) of the connection tracking table in the kernel to a large number.
Take a look at /proc/sys/net/ipv4/netfilter/ip_conntrack_max
and if it set to a low number. For systems with more than 1GB of RAM, default value is limited to 65536. To calculate what size you can set this to, use the following information:
On i386 architecture:
CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 = RAMSIZE (in MegaBytes) * 64.
So for example, a 32 bits PC with 512MB of RAM can handle 512*1024^2/16384 = 512*64 = 32768 simultaneous connections by default.
But the real formula is:
CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (x / 32)
where x is the number of bits in a pointer (for example, 32 or 64 bits). To set a new value run:
echo "new value" > /proc/sys/net/ipv4/netfilter/ip_conntrack_max
For example:
echo 1234567 > /proc/sys/net/ipv4/netfilter/ip_conntrack_max
To make this setting permanent, add this line in your /etc/rc.local file so that when you reboot your CentOS server, it also sets the connection tracking size to the desired value.
Third Choice: use iptables to stop tracking memcached connections
To minimize the resource use (memory/CPU) for connection tracking, you can consider disabling connection tracking of your memcached daemon. For example, if you run memcached on the default 11211 port, you can run the following iptables rules on the memcached CentOS server:
iptables -t raw -I PREROUTING -p tcp --dport 11211 -j NOTRACK
iptables -t raw -I OUTPUT -p tcp --dport 11211 -j NOTRACK
The first iptables rule tells CentOS kernel to not to track incoming traffic from your memcached clients. The second one tells CentOS kernel to not to track outgoing traffic from your memcached daemon.
Category: Performance | Tags: | Be the First to Comment »
Published December 10th, 2008 by kabir
Problem Statement
Once you have memcached installed, you want to know how well it is working out for you. Here we will show you how you can get stats on memcached from the command-line in a hurry.
Getting memcached stats from the command-line
From your terminal app such as putty, do the following:
- Telnet to your memcached server using the memcached port. For example, if you are running memcached on your localhost on the default port 11211, you can run:
telnet localhost 11211
- Once connected, enter
stats and you will see the current memcached stats as shown in the sample below:
[root@cassini ~]# telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
stats
STAT pid 16781
STAT uptime 2891159
STAT time 1228931142
STAT version 1.2.6
STAT pointer_size 32
STAT rusage_user 0.071989
STAT rusage_system 0.380942
STAT curr_items 69
STAT total_items 249
STAT bytes 3871
STAT curr_connections 2
STAT total_connections 1965
STAT connection_structures 6
STAT cmd_get 3270
STAT cmd_set 249
STAT get_hits 403
STAT get_misses 2867
STAT evictions 0
STAT bytes_read 62361
STAT bytes_written 27026
STAT limit_maxbytes 268435456
STAT threads 1
END
Category: Performance | Tags: | Be the First to Comment »
Published December 4th, 2008 by kabir
Problem Statement
If you have PCI DSS compliance requirements for your Web server doing ecommerce, you probably have a third-party scanner that checks your security compliance, in such case you might already be aware of the fact that ICMP timestamp-request and timestamp-response is not good to have turned on. These type of ICMP packets allows a potential intruder to calculate your server’s local time and possibly also do a fingerprint of your operating system. It is a good idea to disable these packets. Here we will show you how.
Disabling ICMP timestamp-request and timestamp-response requests
To disable these ICMP packet types, you can add a iptables firewall rule in your /etc/sysconfig/iptables file as follows:
-A RH-Firewall-1-INPUT -p ICMP --icmp-type timestamp-request -j DROP
-A RH-Firewall-1-INPUT -p ICMP --icmp-type timestamp-reply -j DROP
Then restart the iptables service using service iptables restart and check the iptables using: iptables -L -n you should see two lines as shown below:
DROP icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 13
DROP icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 14
These rules tells centos to drop the ICMP timestamp packets.
Disabling ICMP echo requests
If you would much rather have your server not reply to typical ping (ICMP echo) requests, you can disable it by adding the following line in your /etc/rc.local script.
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
You should also run the above command immediately to disable ping right away.
Category: SSH, Security | Tags: | 2 Comments »
Published November 27th, 2008 by kabir
Problem Statement
It is always a good idea to routinely scan your server for open ports so that you know exactly what is open and available on the Internet. In this article, we will show you how to use too popular utility programs to do just that.
Using nc to scan for ports on your CentOS server
First make sure you have nc installed on your system. If you simply enter the nc at the root shell prompt and do not get the syntax information, you need to install it. Installing nc is very simple. Just run: yum -y install nc to have yum install it for you.
Once installed, you can use nc to scan for open ports on any server that you manage. Please note that it is not polite and possibly not legal in your country to scan someone else’s system without receiving appropriate permissions apriori.
To scan a host using nc for open ports between 1 to 9999, run:
$ nc -w 2 -z [hostname or IP address] [port range]
For example:
$ nc -w 2 -z www.example.com 1-9999
Here the host named www.example.com will be scanned for all ports in 1-9999 range.
A sample output of such a command is shown below:
Connection to www.example.com 80 port [tcp/http] succeeded!
Connection to www.example.com 110 port [tcp/pop3] succeeded!
Connection to www.example.com 143 port [tcp/imap] succeeded!
Here nc reports that the www.example.com server has port 80 (HTTP), 110 (POP3), and 143 (IMAP) open.
Using nmap to scan for ports on your CentOS server
Like nc, the nmap utility program is also a great tool for scanning your server ports. If you do not have it already installed just run: yum -y install nmap and let yum install it for you.
Once installed, you can run various types of scans that you can do with nmap, the one that we found most interesting is as follows:
$ nmap -A -T4 [hostname]
A sample output is shown below:
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2008-11-27 12:37 PST
Stats: 0:00:01 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 2.17% done; ETC: 12:38 (0:00:49 remaining)
Interesting ports on demo.evoknow.com (75.142.210.121):
Not shown: 1018 filtered ports, 658 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.0.5
80/tcp open http Apache httpd
443/tcp open http Apache httpd
3306/tcp open mysql MySQL (unauthorized)
MAC Address: 00:11:25:2A:11:00 (IBM)
Device type: general purpose
Running: Linux 2.6.X
OS details: Linux 2.6.5 - 2.6.11
Uptime 42.268 days (since Thu Oct 16 07:11:35 2008)
Service Info: OS: Unix
Nmap finished: 1 IP address (1 host up) scanned in 13.303 seconds
The -A option enables OS detection and Version detection, Script scanning and Traceroute and the -T4 tells nmap to be aggressive with timing.
Category: Security | Tags: | Be the First to Comment »
Published November 25th, 2008 by kabir
Problem Statement
The real problem in the world is that there are too many people with too much free time. These wanna-be hackers often download scripts and ready-made-software to scan servers all around the globe and see if there is one that is poorly maintained to get in and deface Web pages or steal information. SSH is a great improvement over telnet based remote access but it is also setup typically using username/password based authentication. So if your password is weak, SSH has no benefit. Having weak password in combination with a default SSH server is like inviting trouble by going out of your way. Here in this article we will show you how you can secure SSH and automatically ban access attempts from people who have either forgotten their password or those who should have never connected to your SSH server.
| Time Estimate (30 ~ 60 min) |
| We estimate that the entire process to get DenyHosts installed, and tested might take half an hour to an hour. |
Securing SSH by Running on a Non-Standard Port
We covered this topic in another article called <a href=”http://centoshacker.com/admin/ssh/running-ssh-on-a-non-standard-port.html”>Running SSH on a Non-standard Port</a>. Read and implement as recommended so that your SSH server is not on the default 22.
Deny the Idiot Users and/or Wanna-be Hackers and Script Kiddies
DenyHosts is a Python script that runs as a daemon and monitors SSH attempts (by watching /var/log/secure) on your server. After n number of invalid attempts using non-existent user accounts are made by a potential intruder, it locks up the IP address by placing it in /etc/hosts.deny which the SSH server checks every time a connection attempt is made. This means that after n number of invalid attempts to access non-existent user accounts, the intruder has to change the IP address to resume attack your server, this is a bit of annoyance at the least and most likely a good enough deterrent that the idiot moves on and looks for another potential victim server.
Download the source distribution from:
http://www.denyhosts.net/
Step 1: Installing DenyHosts
Once you have downloaded the source and extracted the source in /usr/local/src, do the following from the newly created DenyHosts-<version> directory:
- Run:
python setup.py install
to install the package
- Change directory to
/usr/share/denyhosts
- Run:
cp denyhosts.cfg-dist denyhosts.cfg to copy the sample configuration into a new configuration file that you can edit
The sample configuration has comments that you can follow to make any applicable changes if needed. Here is the list of options (shown without the comments) that you can configure:
SECURE_LOG = /var/log/secure
HOSTS_DENY = /etc/hosts.deny
PURGE_DENY =
BLOCK_SERVICE = sshd
DENY_THRESHOLD_INVALID = 5
DENY_THRESHOLD_VALID = 10
DENY_THRESHOLD_ROOT = 1
DENY_THRESHOLD_RESTRICTED = 1
WORK_DIR = /usr/share/denyhosts/data
SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES
HOSTNAME_LOOKUP=YES
LOCK_FILE = /var/lock/subsys/denyhosts
ADMIN_EMAIL =
SMTP_HOST = localhost
SMTP_PORT = 25
SMTP_FROM = DenyHosts
SMTP_SUBJECT = DenyHosts Report
AGE_RESET_VALID=5d
AGE_RESET_ROOT=25d
AGE_RESET_RESTRICTED=25d
AGE_RESET_INVALID=10d
DAEMON_LOG = /var/log/denyhosts
DAEMON_SLEEP = 30s
DAEMON_PURGE = 1h
By default, DenyHosts will block access to ssh service by placing an entry sshd: <bad ip address> in the /etc/hosts.deny file. However, if you like to block all the xinetd services that check /etc/hosts.deny than set BLOCK_SERVICE = ALL
By default, DENY_THRESHOLD_INVALID is set to 5, which means that after five invalid attempts using wrong password, the intruder will be locked by because DenyHosts will add the intruder’s IP address in the /etc/hosts.deny file
By default, DENY_THRESHOLD_ROOT is set to 1, which means, that after one invalid attempt to login as root user, DenyHosts will disable the IP address. However, we highly recommend that you completely disable root login via SSH. See Stop root Login via SSH Immediately!
To receive email from DenyHosts, set the ADMIN_EMAIL field to your email address. You will also have to set SMTP_HOST and SMTP_PORT to approrpiate values unless the defaults — assumes that you are running a SMTP mail server on local host — works for you. If your SMTP server requires username and password, you will also have to uncomment and set SMTP_USERNAME and SMTP_PASSWORD to appropriate values. You should also review SMTP_FROM to make sure that the email address used as the From header in the email sent by DenyHost is OK. You might have to white list this email address in your anti-spam program/appliance, etc. Similarly, review the SMTP_SUBJECT field’s default value to meet your needs
Now copy the sample daemon control file in /usr/share/denyhosts using cp daemon-control-dist daemon-control. You can review the daemon-control file but most likely it will work as-is
To start DenyHosts automatically at server startup/reboot, create a symbolic link as follows:
ln -s /usr/share/denyhosts/daemon-control /etc/init.d/denyhosts
Now add the denyhosts service to your current runlevel using chkconfig --add denyhosts
Step 2: Starting DenyHosts for the First Time
To start DenyHosts, run service denyhosts start and you should see something similar to the following:
starting DenyHosts:
/usr/bin/env python /usr/bin/denyhosts.py --daemon \
--config=/usr/share/denyhosts/denyhosts.cfg
To ensure that it is running, run ps x | grep denyhosts and you should see something similar to the following:
28788 ? S 0:00 python /usr/bin/denyhosts.py --daemon --config=/usr/share/denyhosts/denyhosts.cfg
If you see a running denyhosts script that has been started using python you are all set!
Step 3: Excluding Known IP Addresses from Getting Denied
If you have users who forget their SSH username a lot and they access your SSH server from known static IP addresses, you can exclude these IP addresses from DenyHost’s radar. Here is how:
Now if any of the users using the IP addresses listed in the allowed-hosts files ever misspell their username multiple times, they won’t call you. Because, denyhosts will forgive them for good. This might not be a good practice since you want your users to really know what they are doing and perhaps you DO want them to get locked out when they forget their username. How much can you take? Never mind.
Step 4: Testing Your DenyHosts Setup
To test your denyhosts setup, do the following:
To test if an allowed IP address can make username mistakes, just add the IP address in the /usr/share/denyhosts/data/allowed-hosts file and try to access the SSH server using invalid username and/or password. You will be allowed to try as much as you like.
Step 5: Using Centralized DenyHosts Knowledge base
The denyhosts.net provides a free global synchronization of attack data. The benefits are:
- You receive IP addresses that have been already considered bad by other hosts elsewhere in the world. This way, you get to ban the bad IP addresses before they attack your server
- Your bad IP addresses are contributed to the global pool of bad IP addresses so that someone else’s server can ban the IP before any attempt is made to access such a server
To enable this service, edit the /usr/share/denyhosts/denyhosts.cfg file as follows:
- Uncomment
SYNC_SERVER = http://xmlrpc.denyhosts.net:9911 to allow DenyHosts to send and receive synchronization data from the denyhosts.net service
- Uncomment
SYNC_INTERVAL = 1h so that your DenyHosts deamon can contact the denyhosts.net every hour
- If you wish to upload your bad IP list, uncomment and set
SYNC_UPLOAD = yes
- If you wish to download bad IP list from denyhosts.net, uncomment and set
SYNC_DOWNLOAD = yes
Category: Security | Tags: | 2 Comments »
Published November 25th, 2008 by kabir
Problem Statement
If you are still allowing root login via SSH, you love living on the edge, don’t ya? I didn’t think so. Here in this short article you will find out how to disable root login and still gain root access in a manner that is safer than direct root login via SSH.
Disabling root user login via SSH
Edit the /etc/ssh/sshd_config file and see if you have PermitRootLogin directive set to yes. Change this directive to be:
PermitRootLogin no
Save the changes and restart SSH daemon using service sshd restart. Now try to login to your SSH server from a remote system using the root account. For example:
$ ssh -l root your.server -p [ssh port]
If you are not able to login via root, great!. Use a standard user account to ssh to your server and then use su - to switch to root user. Using su is much better than direct login as root because:
- Bad guys cannot keep on trying to guess your root password
- Root user account should be only used occasionally and switching from a regular user to root makes more sense as your normal privilege is limited and thus less damage in case someone guesses your password.
Category: Security | Tags: | Be the First to Comment »
Published November 10th, 2008 by kabir
Problem Statement:
We recently uploaded a few sample PHP script on as available downloads for an article in this blog and one of our lead engineers realized that WordPress is allowing PHP execution on the upload directory by default! This is BAD! Here is how to fix this simple but potentially high risk problem with WordPress upload directory on a Apache Web server.
Step 1: Edit your Virtual Host Configuration for the Blog
In your virtual host configuration for the blog, add the following directives:
<DirectoryMatch "/uploads/">
AddType text/plain .php
</DirectoryMatch>
This will make sure that any request for a file ending with .php in /uploads/ results in displaying the contents of the file instead of executing it on your server.
Step 2: Restart Apache and test your new settings
Now restart Apache Web server and upload a file with .php extension in one of your blog posts using WordPress. Once file is uploaded and you have added the file link in your blog post, save the post.
You can post a simple script has follows:
Visit the post and click on the file link and see if it runs the script or shows the source code. If you see PHP source code, you are done!
Category: Security | Tags: | 1 Comment »