onsdag 6. juni 2012

Check for correct password in PostgreSQL

Check if a ROLE has the correct password, and change if it isn't:
1:  #!/bin/bash                                                                                                                    
2:  DB_USER='icinga'  
3:  DB_PASSWORD='Jaht5aChkib2The5iA'  
5:  MD5_PASSWORD=$(echo -n ${DB_PASSWORD}${SALT} | md5sum | cut -d" " -f1)  
7:  CURRENT_PASS=$(psql -tA -c "SELECT passwd FROM pg_shadow WHERE usename = '${DB_USER}';")  
9:  if ! [ $CURRENT_PASS == $PASSWORD_HASH ]; then  
10:    psql -tA -c "ALTER ROLE ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';"  
11:  fi  
Note: to be run locally as postgres user.

mandag 3. januar 2011

Restrict ssh access to one command, but allow parameters

Sometimes one needs to allow a script to login to a server using a SSH key to do a job. That can be achieved by adding the scripts SSH public key to the remote user's authorized_keys file. The private keys are often stored without password to allow the script to use the key and not stopping execution by an interactive prompt for the private key password.

This puts the remote server at risk because if the originating server is compromised an attacker would easily gain access to the remote server as well. To reduce the damage of a compromised private key, one often restricts the access of the key to the minimum required to get the script's job done. This can be accomplished by using SSH-key options in the authorized_keys file.

from="fromserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="/home/user/bin/script.sh" ssh-rsa  AAAAB3NzA..Dxq= user@fromserver.example.com

This is quite effective, and restricts the attacker to executing the specified forced command, and only from a specified host, with no terminal or X11 access.

Other times one needs to do a sync job using rsync. Let's see how that works out with the above scheme.

Example command:
/usr/bin/rsync /some/dir/ user@remote.example.com:/some/other/dir/

Example entry in authorized_keys:
from="fromserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="/usr/bin/rsync" ssh-rsa  AAAAB3NzA..Dxq= user@fromserver.example.com

Trying that, you'll soon noticed that all your command line arguments are ignored, and you'll get the help text from rsync as output. The forced command option does not allow arbitrary command line arguments to the command.

There is a workaround by using the $SSH_ORIGINAL_COMMAND environment variable that the ssh program creates. The problem with that is that you'll need a wrapper script to deal with the arguments because it will have the executable twice in the argument list:
from="fromserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="/usr/bin/rsync $SSH_ORIGINAL_COMMAND" ssh-rsa  AAAAB3NzA..Dxq= user@fromserver.example.com

This will produce this command:
/usr/bin/rsync /usr/bin/rsync /some/dir/ user@remote.example.com:/some/other/dir/

A solution to this is the wrapper script that interprets the environment variable and executes the correct command:
    "/usr/bin/rsync "*)
        echo "Permission denied."
        exit 1

This adds complexity and requires a script to be installed on the remote server. It is also possible to achieve a similar solution without the wrapper script:

from="fromserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="/usr/bin/rsync ${SSH_ORIGINAL_COMMAND#* }"

Notice the '#* ' right after SSH_ORIGINAL_COMMAND. The # modifier in bash is used to remove the smallest prefix pattern, and so '#* ' will remove everything up until and including the first space.

There are some security concerns however. For instance this would be possible from the machine "fromserver.example.com":

rsync authorized_keys user@server:/home/user/.ssh/authorized_keys

That would allow an attacker to swap the file with anything, and thus the security is easily breached. To prevent that,  make the file owned by root and remove write permissions on the file, or make it immutable with chattr.

chown root:root /home/user/.ssh/authorized_keys
chmod a-w       /home/user/.ssh/authorized_keys
chattr +i       /home/user/.ssh/authorized_keys

Allowing the unrestricted use of the rsync program will allow an attacker to replace any files the user has write access to. Beware that there probably are other holes in this that I didn't find.

mandag 13. september 2010

Managing GlassFish domains with Puppet

Following James Turnbull's plugin HOWTO, I've created a new Puppet resource type for managing GlassFish domains. You can get it via the Puppet Forge.

This plugin is meant to replace the previously used (with success) exec type for managing GlassFish domains:
$passfile = "/home/gfish/.aspass"
$portbase = "4900"
$asadmin = "/opt/NSBglassfish/bin/asadmin"
$domaindir = "/opt/NSBglassfish/glassfish/domains"

exec {
command => "$asadmin --user admin --passwordfile $passfile create-domain --profile cluster --portbase $portbase --savelogin $name",
user => "admin",
creates => "$domaindir/$name";

his new resource type allows for more functionality and expressive clarity than the exec type. For example, it allows you to easily delete the domain by using the ensure => absent property. This is how one specifies a new GlassFish domain with this:
glassfish {
portbase => "4800",
adminuser => "admin",
passwordfile => "/home/gfish/.aspass",
profile => "cluster",
ensure => present;

ensure => absent;

I plan to add more features to it, such as adding system-properties and jvm-options.

mandag 24. mai 2010

Parsing the /etc/passwd file with Ruby

I decided to write a program to parse the /etc/passwd file in my favourite scripting language. The file has seven fields: user, password, UID, GID, GECOS, home and shell.

Writing this snippet of code, I used some metaprogramming features in Ruby that I learned from Metaprogramming Ruby by Paolo Perrotta, like "OpenStruct", Dynamic Methods and method_missing(). I created a structure to hold the field information for each line in the file like this:

class PasswdFile
class PasswdEntry
def initialize
@attributes = {}

def method_missing(name, *args)
attribute = name.to_s
if attribute =~ /=$/
@attributes[attribute.chop] = args[0]

def import(line)
field_names = [:user, :password, :uid, :gid, :gecos, :home, :shell]
fields = line.split(":")
puts "Error: Not a passwd line, not 7 fields" unless fields.length == 7
field_names.each do |field_name|
self.send("#{field_name}=", fields[field_names.index(field_name)])

attr_reader :filename
def initialize(filename="/etc/passwd")
@entries = []

def import(filename)
File.open(filename, "r").each do |line|
entry = PasswdEntry.new
entry.import line
@entries << entry

def each
@entries.each do |entry|
yield entry

def print
field_names = [:user, :password, :uid, :gid, :gecos, :home, :shell]

@entries.each do |entry|
puts "ENTRY:"
field_names.each do |field_name|
puts " #{field_name}: " + entry.send("#{field_name}")

To show an example of useage, we can print each field, like this:

entries = PasswdFile.new

tirsdag 18. august 2009

Rooting the HTC Hero

On friday I got my new HTC Hero in the mail. Yesterday, I rooted it following instructions on phandroid.com. Instead of from Windows, like in the article on phandroid.com, I did it from Linux, and here is how.

1. Download android-sdk-linux_x86-1.5_r3.zip

2. Download orange-htc-hero-uk-boot.img-28-july-2009.zip

3. Download fastboot for Linux.

4. Run these commands:
# unzip android-sdk-linux_x86-1.5_r3.zip
# unzip orange-htc-hero-uk-boot.img-28-july-2009.zip
# mv orange-htc-hero-uk-boot.img-28-july-2009/boot.img.insecure android-sdk-linux_x86-1.5_r3/tools
# unzip fastboot.zip
# mv fastboot android-sdk-linux_x86-1.5_r3/tools
# cd android-sdk-linux_x86-1.5_r3/tools
5. Shutdown the phone and plug in the USB cable.

6. Press and hold the back key and power on the phone.
This will get you into the fastboot USB screen (the white screen with three androids at the bottom).

7. Run this command:
# sudo ./fastboot boot boot.img.insecure
downloading 'boot.img'... OKAY
booting... OKAY
Now your device will start from the given image with root access.

8. In the phone's alerts menu, click HTC Sync.

9. Run this command:
sudo ./adb shell
This will give you a root shell on the device.

10. From this shell, run these commands:
# mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system
# cp -a /system/bin/su /system/bin/su.backup
# cat /system/bin/sh > /system/bin/su
# chmod 4755 /system/bin/su
# reboot
Now your device is rooted!

tirsdag 11. august 2009

ZFS root disk mirror

So, I just installed OpenSolaris on a Sun Blade X6240 Server Module. I have two disks on this machine, and wanted to use disk mirroring. I didn't want to use the integrated LSI 1068E hardware RAID controller, I wanted to use the much cooler ZFS mirror feature.

During installation, it was not possible to set up mirroring, it had to wait until after the first boot. The installation wizard created the necessary partitions, ZFS filesystem and installed GRUB on the system, and I don't know what commands it has run to set up the disk the way it is now. So, to attach the mirror disk to the ZFS pool, I copied the partition table to the mirror:

# prtvtoc /dev/rdsk/c8t0d0s2 | fmthard -s - /dev/rdsk/c8t1d0s2

Now that's done, and I proceeded to attach the mirror disk into the ZFS pool:
# zpool status rpool
pool: rpool
state: ONLINE
scrub: none requested

rpool ONLINE 0 0 0
c8t0d0s0 ONLINE 0 0 0

errors: No known data errors
# zpool attach -f rpool c8t0d0s0 c8t1d0s0
Please be sure to invoke installgrub(1M) to make 'c8t1d0s0' bootable.
# zpool status rpool
pool: rpool
state: ONLINE
status: One or more devices is currently being resilvered. The pool will
continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
scrub: resilver in progress for 0h0m, 15.41% done, 0h1m to go

rpool ONLINE 0 0 0
mirror ONLINE 0 0 0
c8t0d0s0 ONLINE 0 0 0
c8t1d0s0 ONLINE 0 0 0 1.07G resilvered

errors: No known data errors

Installing GRUB and updating the master boot sector was also necessary to be able to boot off the mirror:
# installgrub -m /boot/grub/stage1 /boot/grub/stage2 /dev/rdsk/c8t1d0s0
Updating master boot sector destroys existing boot managers (if any).
continue (y/n)?y
stage1 written to partition 0 sector 0 (abs 16065)
stage2 written to partition 0, 271 sectors starting at 50 (abs 16115)
stage1 written to master boot sector

And that's that!

tirsdag 21. juli 2009

BADSIG 40976EAF437D05B5

When running apt-get update today, I got this error message:

The following signatures were invalid: BADSIG 40976EAF437D05B5 Ubuntu Archive Automatic Signing Key

Strange. And it was no good retrying, the same error occurred over and over again. apt-get stopped complaining after running update with this option:

apt-get update -o Acquire::http::No-Cache=True

and this:

apt-get update -o Acquire::BrokenProxy=true

I suspect my company's Barracuda Spam & Virus Firewall is to blame, as it has been blamed for arbitrarily corrupting downloads before by my co-workers. How can I know for certain?