Linux
Check Linux books from Amazon
index:
Linux boot sequence
This is what happens when you turn on a Linux-based PC:
- the BIOS performs a POST (Power On Self Test), then checks installed hw, and then
passes the control to the first level boot loader, which is a little
program written into the first sector of the boot device. The boot device usually is
the hard disk and the first sector is called MBR (Master Boot Record). MBR contains
both the first level boot loader (which is passed the control to by the BIOS) *and*
the partitioning information of the hard disk
- the MBR first level boot loader calls, in turn, a second level boot loader
which is another little program that is used to load into memory the true Operating
System. In case more than one OS is installed, the second level boot loader also lets
you choose the OS that you want to start. If you don't hit any key in the keyboard
the second level boot loader waits a few seconds and then boots the first OS in the
list. Usually the list contains only Linux
- Linux offers two second level boot loaders: lilo and grub. The latter
is much more easy to configure because you just need to configure its configuration
file (/boot/grub/grub.conf)
- The second level boot loader does the following:
- loads the kernel into memory (it stands at /boot/vmlinuz-2.4.x-xx)
- loads initrd into memory (it is a RAM disk used by the kernel to load any
non-compiled driver that is necessary to startup the system; at the end of the job
the memory is freed)
- the kernel is passed the control to by the second level boot loader. The kernel is
the core of the OS, and once it is loaded into the memory and has been given the control,
Linux is fully operative into the PC
- the kernel passes the control to /sbin/init, that is in charge for configuring the
user environment, and it does the following:
- calls /etc/rc.d/rc.sysinit, to initialize any dependance that needs to be
initialized at system startup
- calls /etc/inittab, which is a script that defines the runlevels, and
also indicates the initial runlevel to start with
- sets the source library into /etc/rc.d/init.d/functions
- calls /etc/rc.d/rc.local, which is a script that is executed on entering any
runlevel; use this script to add any eventual daemon you want to add at any runlevel
disable vi syntax highlight
- enabling/disabling syntax highlightning when the editor is opened: syntax on/off
- prevent coloured syntax highlightning in Perl scripts: find the file perl.vim and rename it (this works fine)
add a job to crontab
ipchains
common daemons
- httpd: /etc/rc.d/init.d/httpd start
- httpd: /usr/local/apache/bin/apachectl start (rel. 1.3.33)
- mysqld: /etc/rc.d/init.d/mysqld start
- ipchains: /etc/rc.d/init.d/ipchains start
- network configuration /etc/rc.d/init.d/network start
To have them automatically start at startup, if they don't, add the corresponding lines in
this file: /etc/rc.d/rc3.d/S99local.
host name resolution
Linux uses the /etc/hosts file to resolve the IPs that have been defined there. Add as many IPs as you want.
Each line starts with one IP, then the name follows, and finally one or more aliases. In the example below www
is an alias for www.mydomain.it.
#/etc/hosts
127.0.0.1 localhost.localdomain localhost
195.110.140.75 www.mydomain.it www
231.144.0.23 orion
192.168.0.1 spacecalf spacecalf.mydomain.it
192.168.0.233 neptune
192.168.0.234 jupiter
Linux also uses the /etc/resolv.conf file to resolve IPs. This file contains one or more DNS IPs, and the
name resolution is performed by the listed DNS. Be sure to supply at least one valid DNS IP, differently many
network services will fail (for example squid will refuse to start).
#/etc/resolv.conf
nameserver 195.110.128.1
nameserver 197.128.140.22
The file /etc/host.conf tells Linux to search /etc/hosts before using the DNS services listed into
/etc/resolv.conf:
#/etc/host.conf
order hosts,bind
multi on
(bind is the name server daemon). multi on means "return more than one result if there are aliases"
(a host can have several IP numbers, and an IP number can have several host names; this option should always be
turned on; most applications use only the first value returned).
network
#/etc/sysconfig/network
NETWORKING=yes
HOSTNAME="www.mydomain.it"
GATEWAY="195.110.140.65" // this is the default route
GATEWAYDEV="eth0"
FORWARD_IPV4="no"
NIC configuration file
/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=static
IPADDR=80.183.250.18
NETMASK=255.255.255.248
ONBOOT=yes
/etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
IPADDR=192.168.0.1
NETMASK=255.255.255.0
ONBOOT=yes
PPP
PPP configuration file:
#/etc/ppp/options
demand // will use DialOnDemand
idle 120 // drop connection after 120s idle
ipcp-accept-remote // the ISP gives a dynamic IP (overrides any dafault)
ipcp-accept-local
lock // prevents anything else accessing the modem or terminal adapter
noauth // no need for ISP to authenticate itself
defaultroute // sets this connection as the default route to the Internet
user
remotename ppp0
/dev/modem 115200 // max transfer rate through serial port
crtscts // hardware flow control
connect 'usr/sbin/chat -f /etc/sysconfig/network-scripts/chat-ppp0'
The last line points to a chat script that tells pppd howto to dial. The script might look
like this:
'ABORT' 'BUSY'
'ABORT' 'ERROR'
'ABORT' 'NO CARRIER'
'ABORT' 'NO DIALTONE'
'ABORT' 'Invalid Login'
'ABORT' 'Login Incorrect'
'' 'ATZ'
'OK' 'ATDI
'CONNECT' ''
'TIMEOUT' '5'
'~__' ''
Standard dynamic HTML page
Skeleton:
#!/usr/bin/perl -w
# INIZIALIZATION
use strict;
use diagnostics;
use DBI;
my $single_quote = "\'";
my $double_quote = "\"";
# RECEIVING VARIABLES (POST or GET)
my $buffer = '';
my %FORM;
if ( $ENV{ 'REQUEST_METHOD' } eq 'GET' )
{
$buffer = $ENV{ 'QUERY_STRING' };
}
if ( $ENV{ 'REQUEST_METHOD' } eq 'POST' )
{
read ( STDIN, $buffer, $ENV{ 'CONTENT_LENGTH' } );
}
my @pairs = split ( /&/, $buffer );
foreach my $pair ( @pairs )
{
my ( $name, $value ) = split ( /=/, $pair );
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{ $name } = $value;
}
# START HTML
print qq |Expires: 0\n|;
print qq |Content-type: text/html\n\n|;
print qq |<html>|;
print qq |< ---------- HEAD ---------- >|;
print qq |<head>|;
print qq |<title>PAGE TITLE<title>|;
print qq |<script launguage=JavaScript>|;
print qq |function my_js_function ( args ) {|;
print qq | ...|;
print qq |}|;
print qq |</script>|;
print qq |</head>|;
print qq |< -------- END HEAD -------- >|;
print qq |< ---------- BODY ---------- >|;
print qq |<body bgcolor=FFFFFF onload='my_js_function ( args );' |;
print qq |topmargin='0' leftmargin='0' marginheight='0' marginwidth='0' |;
print qq |link=0055bb alink=0066aa vlink=003355>|;
# PUT HERE BODY CONTENTS
# A TABLE
print qq |<table width=780 border=2 cellpadding=2 cellspacing=2 bordercolor=FFFFFF>|;
# first row
print qq | <tr colspan=2>|;
print qq | <td>|;
print qq | ...|;
print qq | </td>|;
print qq | </tr>|;
# second row
print qq | <tr>|;
print qq | <td>|;
print qq | ...|;
print qq | </td>|;
print qq | <td>|;
print qq | ...|;
print qq | </td>|;
print qq | </tr>|;
# third row
print qq | <tr>|;
print qq | <td>|;
print qq | ...|;
print qq | </td>|;
print qq | <td>|;
print qq | ...|;
print qq | </td>|;
print qq | </tr>|;
print qq |</table>|;
# END HTML
print qq |</body>|;
print qq |< -------- END BODY -------- >|;
print qq |</html> |;
exit;
Perl & MySQL
Connecting to the database:
my ( $dbh, $sth, $rv, %RECORD );
$dbh = DBI -> connect ( 'dbi:mysql:DATABASENAME', 'username', 'password' )
or die 'Could not open DATABASENAME';
Disonnecting from the database:
$dbh -> disconnect;
Query a table and fetch a couple of fields:
$query = "SELECT field_1, field_2 FROM table WHERE search_clause";
$sth = $dbh -> prepare ( $query ) or die "\r\n $dbh -> errstr";
$rv = $sth -> execute;
if ( $rv == 0 )
{
$alert = "Empty set.";
}
else
{
while ( ( $field_1, $_field_2 ) = $sth -> fetchrow_array )
{
# substitutions required only when fetching text fields
$field_1 =~ s/\\'/$single_quote/g;
$field_1 =~ s/\\"/$double_quote/g;
do something
}
}
Query a table and fetch all fields:
$query = "SELECT * FROM table WHERE search_clause";
$sth = $dbh -> prepare ( $query ) or die "\r\n $dbh -> errstr";
$rv = $sth -> execute;
if ( $rv == 0 )
{
$alert = "Empty set.";
}
else
{
while ( $rv > 0 )
{
%RECORD = %{ $sth -> fetchrow_hashref };
$rv--;
$field_1 = $RECORD{ "field_1" };
# substitutions required only when fetching text fields
$field_1 =~ s/\\'/$single_quote/g;
$field_1 =~ s/\\"/$double_quote/g;
$field_2 = $RECORD{ "field_2" };
$field_3 = $RECORD{ "field_3" };
...
$field_n = $RECORD{ "field_n" };
do something
}
}
Storing a record into a table:
# get fields in some way
$field_1 = $FORM{ 'field_1' };
...
# process text fields
$field_1 =~ s/$single_quote/\\'/g;
$field_1 =~ s/$double_quote/\\'/g;
...
# insert
$rv = $dbh -> do ( qq | INSERT INTO table SET
field_1 = '$field_1',
field_2 = '$field_2',
...
field_n = '$field_n' | );
if ( $rv == 1 )
{
print STDOUT qq |<b>OK</b><br>|;
}
else
{
print STDOUT qq |<font face=courier size=4>|;
my $error_msg = $dbh -> errstr;
print STDOUT qq |<br>ALERT !!! Something went wrong ($rv).|;
print STDOUT qq |<br>Error message from MySQL: $error_msg<br>|;
}
Altering records into a table:
# get fields in some way
$field_1 = $FORM{ 'field_1' };
...
# process text fields
$field_1 =~ s/$single_quote/\\'/g;
$field_1 =~ s/$double_quote/\\'/g;
...
# update
$rv = $dbh -> do ( qq | UPDATE table SET
field_1 = '$field_1',
field_2 = '$field_2',
...
field_n = '$field_n'
WHERE clause | );
if ( $rv == "0E0" )
{
print STDOUT qq |<b>No records affected.</b><br>|;
}
else
{
print STDOUT qq |<font face=courier size=4>|;
print STDOUT qq |<br>Number of affected records: $rv.|;
}
Armoring Linux
- install Linux with the box disconnected from the net to avoid intrusions at
installation time
- check last patches at www.redhat.com/support (and
use another box to download them; use "rpm -Uvh" to install patches)
- comment all unuseful services in /etc/inetd.conf to avoid /usr/sbin/inetd
running them; check the remaining active services with grep -v "^#" /etc/inetd.conf;
restart /usr/sbin/inetd with killall -HUP inetd
- prevent unuseful scripts from being started by the init process in /etc/rc.d/rc3.d
by replacing the capital S with a small s. Script you can start when needed:
S60lpd (printing services daemon), S85httpd (HTTP service daemon).
- use /etc/shadow password file by typing pwconv at the command prompt
- remove all unused accounts from /etc/passwd
Protect the Linux box from script kiddies
- periodically visit cert and
ciac to inform yourself about current and common exploits
- turn off any unused communication port; leave only httpd and ssh ports opened
- don't use bind, wu-ftp etc.
- periodically check logs to determine if your box is being probed
- protect your log files by firewalling port 514 UDP
wu-ftpd
xinetd is in charge to load wu-ftpd whenever a FTP client attempts to
connect to the server box. Although some tutorials exist, editing wu-ftpd configuration
files can be extremely difficult. To configure user access to wu-ftpd do the following:
- start KDE
- select control panel
- select wu-ftpd configurator
- set any element in each tab of the window
- in the last tab you can allow/deny access to normal users defined in passwd
(I discourage
you enabling FTP to users defined in passwd because their password will be
sent unencrypted over the connection, with all the possible consequences)
- select File, Save, and then exit (note: all the settings are saved into
the /etc/ftpaccess configuration file. Other configuration files ftp*
in the /etc/ directory appear not to be strictly required.)
- restart xinetd issuing the following command: service xinetd restart
Be sure that the wu-ftpd service is on at the runlevel that the server box
is usually run. Type chkconfig --list and see. Eventually type chkconfig wu-ftpd on:
this command will turn on the wu-ftpd service at the runlevel that you are currently
logged on.
Automated site backup
Suppose you have some sites under the directory /home/httpd in your web server, and
you want to save them once a week. A good solution is to tar the directory and to
transfer the tarball into another server. This solution can be run unattended using the
services provided by crond, tar and wget. The solution provided below
will also save all your MySQL data in your database.
In the /etc/cron.weekly directory of the web server create a script
sitesave.sh with the following lines:
cd /ftp_user_dir
tar -czf sitebackup.tar.gz /home/httpd/*
mysqldump databasename > /ftp_user_dir/databasename.sql
(and don't forget to chmode it in order to be executed). In the /etc/cron.weekly
directory of the backup server create a script
get_tarball.sh with the following two lines:
cd /backupdir
/usr/local/bin/wget -m ftp://ftp_username:ftp_password@xxx.xxx.xxx.xxx/
(remember to make it executable). A good refinement would be to program the backup
server weekly job to be executed one day after the web server weekly job.
Please note that wget operates in FTP mode, and you need an FTP-registered-user to
accomplish the task. Its username and password are respectively ftp_username and
ftp_password, and ftp_user_dir is the default directory where the
FTP-registered-user is switched into at logon. xxx.xxx.xxx.xxx, finally, is the IP
address of the web server. You can substitute it with its domain name
www.foobar.com.
The backup tarball (togheter with the database dump) remains into the /backupdir
of the backup server in the hope it will never be necessary to restore it.
.
sendmail
sendmail will not work if HOSTNAME in /etc/sysconfig/network is not a valid domain
name registered in a valid Internet DNS server.
You can query the HOSTNAME of your server by typing hostname at the command prompt.
You can also experiment by temporarily changing the hostame. To temporarily change it
type hostname www.foobar.org at the command prompt. It will override the
/etc/sysconfig/network HOSTNAME current setting. This latter will be restored at the next
boot.
Also /usr/sbin/sendmail wants no firewalling rules to stop
packets in transit to/from port number 25 (the smtp port).
Check rock solid firewalling rules using ipchains to see how to
let port 25 usable from a smpt client.
sendmail daemon is not required to stay up when calling /usr/sbin/sendmail
from within your Perl script.
Simple instructions to send a mail from a Perl script are the following:
open ( MAIL, "|/usr/sbin/sendmail -t" );
print MAIL <<EndMail;
To: somebody\@foobar.org
From: do-not-reply\@mydomain.org
Subject: odds & sodds
Hi. This is a mail message.
EndMail
close ( MAIL );
preventing Apache from directory listing
Edit /etc/httpd/conf/httpd.conf and search the following line:
Options Indexes FollowSymLinks
then delete the word Indexes, save the file, and restart httpd.
misc
Finding accounts with no password:
awk -F: '$2 == "" { print $1, "has no password" }' /etc/shadow
Finding Superuser Accounts:
awk -F: '$3 == 0 { print $1, "is a superuser!" }' /etc/passwd
Checking for Suspicious Account Use:
To print the entire login history:
last [username]
To print failed login attempts:
lastb [username]
Testing Your Search Path
perl -e 'print "PATH contains insecure relative directory \"$_\"\n" foreach grep ! m[^/], split /:/, $ENV{"PATH"}, -1;'
Finding setuid (or setgid) Programs
find / -xdev -type f -perm +ug=s -print
find / -xdev -type f -perm +ug=s -print0 | \
perl -0ne 'chomp;
open(FILE, $_);
read(FILE, $magic, 2);
print $_, "\n" if $magic eq "#!";
close(FILE)'
Securing Device Special Files
find / -xdev \( -type b -o -type c \) -ls
find /dev -type f ! -name MAKEDEV -print
Finding Writable Files
find / -xdev -perm +o=w ! \( -type d -perm +o=t \) ! -type l -print
logwatch --range All --detail High --output html-embed --save (nome del file di output)
Mount USB pendrive
mount -t vfat /dev/sdb1 /mnt/pendrive
umount /mnt/pendrive
(get off /mnt/pendrive before issuing umount)
SPAM blacklists
MAPS RBL
MX toolbox
...
|