| Chess | Tools | Data | Blog | Poetry | Why? | Wiki | Admin | Logout |

Download


#!/usr/bin/perl -w
# $Revision: 1.11 $
# Luis Mondesi < lemsx1@gmail.com >
#
# DESCRIPTION: set up a chroot environment for a binary
#
# USAGE: cd /chroot/path && chroot_this.pl /path/to/program
#
# LICENSE: GPL
#
# NOTES: 
# This script just does the right thing for the given program passed to it
# to setup a full chroot environment you will need all the common UNIX utils 
# used by the program you passed as an argument.
# Here is an example of what you would need if you want to setup ssh/sftp 
# chrooted on Fedora (with privilege separation):
#
# * /bin/{cp, ls, mkdir, mv, rm, rmdir, sh}: for i in cp ls mkdir mv rm rmdir sh; do chroot_this.pl /bin/$i; done
# * /usr/libexec/sftp-server: chroot_this.pl /usr/libexec/openssh/sftp-server
# * pam: mkdir -p etc/pam.d; cp -r /etc/pam.d/* etc/pam.d/
# * libpam: cp -r /lib/libpam* lib
# - cp /lib/libnss_files* lib
# - mkdir -p lib/security; chroot_this.pl `find /lib/security/ -depth`
# - mkdir -p etc/security; cp -r /etc/security/*.conf etc/security
# * ssh: mkdir -p etc/ssh; cp -a /etc/ssh/* etc/ssh/
# * /etc/nsswitch.conf: mkdir etc; cat > etc/nsswitch.conf <<-FIN
#     passwd:         files
#     group:          files
#     shadow:         files
#   FIN
# * /etc/{passwd,shadow,group}:
#   mkdir etc; cat > $CHROOTDIR/etc/passwd <<-FIN
#        root:x:0:0:Root:/root:/bin/bash
#        nobody:x:65534:65534:nobody:/:/bin/false
#        sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
#    FIN
#    cat > etc/shadow <<-FIN
#        root:*:11142:0:99999:7:::
#        nobody:*:11142:0:99999:7:::
#        sshd:!!:12871:0:99999:7:::
#    FIN
#    cat > etc/group <<-FIN
#        root:x:0
#        nogroup:x:65534:
#    FIN
# * /var:
#   - mkdir -p var/empty/sshd; chown root var/empty/sshd; chmod 0755 var/empty/sshd
#   - mkdir -p var/log
#   - mkdir -p var/run
#   - mkdir -p var/tmp; chmod 1777 var/tmp
# * /tmp: mkdir tmp; chmod 1777 tmp
# * /etc/init.d/ssh: mkdir -p etc/init.d; cp /etc/init.d/ssh* etc/init.d/
#   - cp /etc/init.d/functions etc/init.d/
# * Assorted kernel devices:
#   - mknod dev/null c 1 3
#   - mknod dev/zero c 1 5
#   - mknod dev/urandom c 1 9
#   - mknod dev/console c 5 1
#   
# * Assorted directories:
#   - mkdir -p etc/rc.d; cd etc/rc.d; ln -s ../init.d init.d
#
# * Assorted utilities:
#   - /sbin/initlog: chroot_this.pl /sbin/initlog; cp /etc/initlog.conf etc/
#   - /usr/bin/reset: chroot_this.pl /usr/bin/reset
#   - /sbin/nologin: chroot_this.pl /sbin/nologin
# * Assorted libraries:
#   - cp -a /lib/libssl* lib/
#   - cp -a /usr/lib/libssl* usr/lib/
#   - cp -a /usr/lib/libcrypt* usr/lib/
# * Assorted logging:
#   - syslog-ng: add unix-stream(/path/to/chroot/dev/log) to your s_all source
#   - syslog: edit /etc/sysconfig/syslog and add: -p /dev/log -a /path/to/chroot/dev/log
# * Assorted mounts:
#   ssh doesn't like to work without this:
#   - /dev/pts: mkdir dev/pts; mount -t devpts none dev/pts
#
# And finally, run: chroot /path/to/chrootdir
# And execute '/usr/sbin/sshd -dD' to test sshd in non-daemon debugging mode
# From a different shell/system, use "ssh -v -v user@server_or_ip" to test the client
# REFERENCES:
# * http://chrootssh.sourceforge.net/docs/chrootedsftp.html
# * http://www.bpfh.net/simes/computing/chroot-break.html

use strict;
$|++;

my $revision='1.11'; # version

# standard Perl modules
use Getopt::Long;
Getopt::Long::Configure('bundling');
#use POSIX;                  # cwd() ... man POSIX
use File::Spec::Functions qw/splitdir catdir/;  # abs2rel() and other dir/filename specific
use File::Copy;     # copy() and move()
#use File::Find;     # find();
use File::Basename; # basename() && dirname()
#use FileHandle;     # for progressbar

# Args:
my $PVERSION=0;
my $HELP=0;
my $DEBUG=0;
# get options
GetOptions(
    # flags
    'v|version'         =>  \$PVERSION,
    'h|help'            =>  \$HELP,
    'D|debug'           =>  \$DEBUG,
    # strings
    #'o|option=s'       =>  \$NEW_OPTION,
    # numbers
    #'a|another-option=i'      =>  \$NEW_ANOTHER_OPTION,
);

if ( $HELP ) { 
    use Pod::Text;
    my $parser = Pod::Text->new (sentence => 0, width => 78);
    $parser->parse_from_file(File::Spec->catfile("$0"),
			   \*STDOUT);
    exit 0;
}

if ( $PVERSION ) { print STDOUT ($revision,"
"); exit 0; }

my $usage = "usage: cd /path/to/chroot && chroot_this.pl /path/to/binary";

foreach my $bin ( @ARGV )
{
    print STDERR "DEBUG: now doing: $bin 
 " if ( $DEBUG );
    if ( ! -d $bin and -x $bin )
    {
        umask(0222);                            # make binaries executable and not writable
        my $binchrootedpath = dirname($bin);
        $binchrootedpath =~ s,^/,,;             # removes first /
        _mkdir($binchrootedpath);               # recursively makes needed dirs
        my $binchrootedpathnamed = "$binchrootedpath/".basename($bin);
        if ( copy($bin,$binchrootedpathnamed) )
        {
            chmod (0555,$binchrootedpathnamed);
            _success($binchrootedpathnamed);
        } else {
            warn ("*** Could not copy $bin to $binchrootedpathnamed ***");
        }

        # get dependencies
        my $linked_deps = qx/ldd $bin/;
        #print STDERR "DEBUG: dependancies for: $bin 
 $linked_deps
" if ( $DEBUG );
        foreach my $lib ( split(/
/,$linked_deps) )
        {
            my $libchrootedpath = "";
            $lib =~ s/\s*\(0x[0-9a-fA-F]+\)\s*$//;              # cleaned: (0x00000da)
            my ($libname,$libpath) = split(/\s*=>\s*/,$lib);    # splitted by =>
            next if ( ! defined($libpath) or $libpath =~ /^\s*$/ );
            if ( -r $libpath ) # can we read this library name?
            {
                ($libchrootedpath = $libpath) =~ s,^/,,;            # cleaned first /

                $libname =~ s/\s+//g;                               # cleaned spaces
                _mkdir(dirname($libchrootedpath));                  # recursively makes needed dirs
                if ( ! -f "$libchrootedpath/$libname" )
                {
                    if ( copy($libpath,$libchrootedpath) )
                    {
                        # surprisingly, in linux libraries must be exec also
                        chmod (0555,"$libchrootedpath/$libname");
                        _success($libchrootedpath);
                    } else {
                        print STDERR "*** Copying $libpath to $libchrootedpath failed! ***
";
                        print STDERR "$libpath: $!
";
                    }
                } else {
                    print STDERR "$libchrootedpath already exists
";
                }
            } else {
                no warnings;
                print STDERR "library '$libpath' is not valid from 'ldd $bin'
";
                print STDERR "try copying this file by hand.
";
            }
        }
    } else {
        print STDERR $usage,"
","'$bin' Non-executable
";
    }
}
# @desc implements `mkdir -p`
sub _mkdir
{
    my $old_umask = umask(0022);            # make dirs executable, readable and writable
    my $path = shift;
    my $root = ( $path =~ m,^([/|\\|:]), ) ? $1 : ""; # relative or full path?
    my @dirs = splitdir($path);
    my $last = "";
    my $flag=1;
    foreach (@dirs)
    {
        next if ( $_ =~ m/^\s*$/ );
        $last = ( $flag > 1 ) ? catdir($last,$_) : "$root"."$_" ;
        mkdir ($last) if ( ! -d $last);
        $flag++;
    }

    umask($old_umask);                      # reset umask
    return $flag;                           # number of directories created
}

sub _success
{
    my $str = shift;
    print STDOUT "$str copied successfully
" if ($DEBUG);
}

__END__

=head1 NAME

chroot_this - chroot_this script by Luis Mondesi <lemsx1@gmail.com>

=head1 SYNOPSIS

B<chroot_this>  [-v,--version]
                [-D,--debug] 
                [-h,--help]
                /path/to/program1 [/path/to/program2 | ... ]

=head1 DESCRIPTION 

    This script allows you to setup a chroot environment for a list of binaries

=head1 OPTIONS

=over 8

=item -v,--version

prints version and exits

=item -D,--debug

enables debug mode

=item -h,--help

prints this help and exits

=cut


Advertisement