Richard Rasker
08/01/03, 22:20
Dag beste allemaal,
Ik heb een bash-scriptje gemaakt met de naam blockcheck, dat op basis va=
n=20
het error-log van mijn Apache-webserver een blocklist aanmaakt met daari=
n=20
hosts die op hinderlijke wijze mijn serverlogs vervuilen met Code Red- e=
n=20
Nimda-scans. Dit blokkeerscript start vervolgens het=20
iptables-firewall-script (init_firewall), dat naast de normale=20
firewall-configuratie opdrachten bevat om alle hosts in de blocklist=20
geheel te blokkeren, zodat ze niet meer honderden of soms duizenden kere=
n=20
achtereen in mijn logs opduiken.
Nu heb ik het volgende probleem: als ik blockcheck handmatig start (als =
root), werkt alles perfect. Als ik blockcheck echter via cron laat=20
starten, gebeurt er iets vreemds: het firewall-script wordt wel compleet=
=20
uitgevoerd, maar de firewall-configuratie bestaat na afloop *niet* uit d=
e=20
opgegeven policy, maar uit de default-policy - wat natuurlijk erg=20
ongewenst is.
Dit is in het kort wat er gebeurt:
- cron roept blockcheck aan via de root-crontab
- blockcheck roept init_firewall aan
- init_firewall wordt keurig gestart, maar installeert *niet* de gewenst=
e=20
chains
Er treden geen foutmeldingen op, en toen ik in init_firewall wat=20
opdrachten
echo [voorgangsbericht] >> controlebestand
had rondgestrooid, bleek dat init_firewall van begin tot einde was=20
uitgevoerd.
Als ik blockcheck zoals gezegd handmatig uitvoer, doet init_firewall het=
=20
wel zoals ik verwacht. Het enige verschil is dus opstarten vanaf de=20
opdrachtregel versus opstarten via cron.
Weet iemand wat ik fout doe? Vermoedelijk zie ik iets fundamenteels over=
=20
het hoofd, maar ondanks dat ik van alles over cron en crontab heb=20
nageplozen, zie ik niet waar het verkeerd gaat.
Alvast bedankt,
Richard Rasker
Voor wie de details wil zien, volgen hier de betreffende scripts en=20
andere informatie.
>>>>>>>>>>>>>>> De crontab-instelling: <<<<<<<<<<<<<<<
# crontab -l
10 0,6,12,18 * * * /usr/local/bin/blockcheck
>>>>>>>>>>>>>>> Het script blockcheck: <<<<<<<<<<<<<<<
# cat blockcheck
#!/bin/bash
#
# blockcheck v. 1.0
# 29-12-2002
# Auteur: R.E.Rasker - rasker@linetec.nl
# http://www.linetec.nl/
#
# Dit script kan automatisch grote vervuilers van bijvoorbeeld
# webserver-logbestanden identificeren, in een blocklist opslaan
# en via een iptables-firewall blokkeren. In de blocklist wordt
# tevens de datum opgeslagen waarop een host is toegevoegd, zodat
# deze na een bepaalde expire-tijd ook weer automatisch uit de
# blocklist verwijderd kan worden.
#
# Het firewall-script zelf moet de volgende code bevatten om de
# blocklist automatisch te verwerken; deze code moet natuurlijk
# voorafgaan aan regels die toegang verlenen:
#
# for i in `grep -v "^#" /usr/local/etc/blocklist.db | cut -d : -f 1`; d=
o
# iptables -A INPUT -i eth0 -s $i -j block
# done
#
#
# Variabelen en vaste waarden:
# ERRMIN geeft aan hoe vaak een bepaald verdacht IP-adres minimaal
# in het error-log moet voorkomen om automatisch geblokkeerd te worden.
# EXPIRE geeft aan na hoeveel tijd een IP-adres weer toegang krijgt
# (de honderdtallen geven de maanden aan - al werkt dit niet bijzonder
# nauwkeurig).
# ERRLOG geeft de locatie aan van het Apache error-log.
# BLOCKLIST geeft de locatie aan van de blocklist; let op dat deze
# locatie ook in het firewall-script wordt gebruikt (zie boven).
# FIREWALL geeft de locatie aan van het firewall-script.
# De variabele FIRESTART geeft aan of de firewall uiteindelijk
# opnieuw gestart moet worden.
ERRMIN=3D10
EXPIRE=3D100
ERRLOG=3D/var/log/httpd/error_log
BLOCKLIST=3D/usr/local/etc/blocklist.db
FIREWALL=3D/usr/local/bin/init_firewall
FIRESTART=3Dfalse
# Allereerst wordt de huidige datum bepaald.
DATENOW=3D`date +%y%m%d`
# Met de volgende opdracht wordt gezocht naar hosts die pogen requests
# uit te voeren voor Windows-systeembestanden (zoals bij Nimda) of
# buffer-overflows (zoals bij CodeRed).
# De genoemde worms zijn de grootste logvervuilers:
for i in `grep "winnt.*exe\|NNNNNNNNNNN" $ERRLOG | sed -e 's/^.*\[client=
=20
//g' -e 's/\].*$//g' | sort -u`; do
# Als een host al in de blocklist voorkomt, moet dit gesignaleerd worden=
:
=20
MATCH=3Dfalse
for j in `grep -v "^#" $BLOCKLIST | cut -d : -f 1`; do
if [ $i =3D $j ]; then
MATCH=3Dtrue
fi
done
=20
# Als een host niet in de blocklist voorkomt, kijk dan of deze minstens =
het
# opgegeven aantal keren in ERRLOG voorkomt; zo ja, voeg de host dan toe=
# aan de blocklist, samen met de datum, en signaleer dat de firewall=20
opnieuw
# gestart moet worden:
=20
if [ $MATCH =3D false ]; then
if [ `grep -c $i $ERRLOG` -gt $ERRMIN ]; then
echo $i":"$DATENOW >> $BLOCKLIST
FIRESTART=3Dtrue
fi
fi
done
=20
# Voor de automatische expire van hosts in de blocklist wordt alleen=20
gekeken
# naar de datum. Zodra een expired host wordt gevonden, wordt dit=20
gesignaleerd
# om de firewall te kunnen aanpassen. Hosts die niet expired zijn, komen=
=20
in een
# tijdelijk bestand terecht, dat na de for-lus BLOCKLIST vervangt.
# Met de eerste grep-opdracht worden eventuele commentaarregels behouden=
..
=20
grep "#" $BLOCKLIST > $BLOCKLIST.tmp
for HOST in `grep -v "^#" $BLOCKLIST`; do
BLOCKDATE=3D`echo $HOST | cut -d : -f 2`
if [ `expr $DATENOW - $BLOCKDATE` -gt $EXPIRE ]; then
FIRESTART=3Dtrue
else
echo $HOST >> $BLOCKLIST.tmp
fi
done
mv $BLOCKLIST.tmp $BLOCKLIST
=20
# Als hosts aan BLOCKLIST zijn toegevoegd dan wel uit BLOCKLIST zijn=20
verwijderd,
# wordt de firewall opnieuw gestart:
=20
if $FIRESTART =3D true; then
$FIREWALL
fi
>>>>>>>>>>>>>>> Het script init_firewall: <<<<<<<<<<<<<<<<
#!/bin/sh
# Breng firewall down
/etc/rc.d/init.d/iptables stop
# NAT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# Maak de blocking-chain
iptables -N block
iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A block -j DROP
# Zet forward vanaf buiten dicht
iptables -A FORWARD -i eth0 -j block
# Blokkeer hosts die door blockcheck zijn herkend:
for i in `grep -v "^#" /usr/local/etc/blocklist.db | cut -d : -f 1`; do
iptables -A INPUT -i eth0 -s $i -j block
done
# Accepteer ICMP/Echo
iptables -A INPUT -i eth0 -p icmp -j ACCEPT
# Accepteer WWW/HTTP
iptables -A INPUT -i eth0 -p tcp --dport www -j ACCEPT
iptables -A INPUT -i eth0 -p udp --dport www -j ACCEPT
# Zet rest van de input vanaf buiten dicht
iptables -A INPUT -i eth0 -j block
# Firewall-configuratie opslaan
/sbin/service iptables save
>>>>>>>>>>>>>>> De foutieve iptables-policy na uitvoering vanuit cron:=20
<<<<<<<<<<<<<<<
# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
>>>>>>>>>>>>>>> De correcte iptables-policy: <<<<<<<<<<<<<<<
(de drie IP-adressen xxx.xxx.xxx.xxx staan voor geblokkeerde hosts)
# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
block all -- xxx.xxx.xxx.xxx anywhere
block all -- xxx.xxx.xxx.xxx anywhere
block all -- xxx.xxx.xxx.xxx anywhere
ACCEPT icmp -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere tcp dpt:http=
ACCEPT udp -- anywhere anywhere udp dpt:http=
block all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
block all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain block (5 references)
target prot opt source destination
ACCEPT all -- anywhere anywhere state=20
RELATED,ESTABLISHED
DROP all -- anywhere anywhere
Ik heb een bash-scriptje gemaakt met de naam blockcheck, dat op basis va=
n=20
het error-log van mijn Apache-webserver een blocklist aanmaakt met daari=
n=20
hosts die op hinderlijke wijze mijn serverlogs vervuilen met Code Red- e=
n=20
Nimda-scans. Dit blokkeerscript start vervolgens het=20
iptables-firewall-script (init_firewall), dat naast de normale=20
firewall-configuratie opdrachten bevat om alle hosts in de blocklist=20
geheel te blokkeren, zodat ze niet meer honderden of soms duizenden kere=
n=20
achtereen in mijn logs opduiken.
Nu heb ik het volgende probleem: als ik blockcheck handmatig start (als =
root), werkt alles perfect. Als ik blockcheck echter via cron laat=20
starten, gebeurt er iets vreemds: het firewall-script wordt wel compleet=
=20
uitgevoerd, maar de firewall-configuratie bestaat na afloop *niet* uit d=
e=20
opgegeven policy, maar uit de default-policy - wat natuurlijk erg=20
ongewenst is.
Dit is in het kort wat er gebeurt:
- cron roept blockcheck aan via de root-crontab
- blockcheck roept init_firewall aan
- init_firewall wordt keurig gestart, maar installeert *niet* de gewenst=
e=20
chains
Er treden geen foutmeldingen op, en toen ik in init_firewall wat=20
opdrachten
echo [voorgangsbericht] >> controlebestand
had rondgestrooid, bleek dat init_firewall van begin tot einde was=20
uitgevoerd.
Als ik blockcheck zoals gezegd handmatig uitvoer, doet init_firewall het=
=20
wel zoals ik verwacht. Het enige verschil is dus opstarten vanaf de=20
opdrachtregel versus opstarten via cron.
Weet iemand wat ik fout doe? Vermoedelijk zie ik iets fundamenteels over=
=20
het hoofd, maar ondanks dat ik van alles over cron en crontab heb=20
nageplozen, zie ik niet waar het verkeerd gaat.
Alvast bedankt,
Richard Rasker
Voor wie de details wil zien, volgen hier de betreffende scripts en=20
andere informatie.
>>>>>>>>>>>>>>> De crontab-instelling: <<<<<<<<<<<<<<<
# crontab -l
10 0,6,12,18 * * * /usr/local/bin/blockcheck
>>>>>>>>>>>>>>> Het script blockcheck: <<<<<<<<<<<<<<<
# cat blockcheck
#!/bin/bash
#
# blockcheck v. 1.0
# 29-12-2002
# Auteur: R.E.Rasker - rasker@linetec.nl
# http://www.linetec.nl/
#
# Dit script kan automatisch grote vervuilers van bijvoorbeeld
# webserver-logbestanden identificeren, in een blocklist opslaan
# en via een iptables-firewall blokkeren. In de blocklist wordt
# tevens de datum opgeslagen waarop een host is toegevoegd, zodat
# deze na een bepaalde expire-tijd ook weer automatisch uit de
# blocklist verwijderd kan worden.
#
# Het firewall-script zelf moet de volgende code bevatten om de
# blocklist automatisch te verwerken; deze code moet natuurlijk
# voorafgaan aan regels die toegang verlenen:
#
# for i in `grep -v "^#" /usr/local/etc/blocklist.db | cut -d : -f 1`; d=
o
# iptables -A INPUT -i eth0 -s $i -j block
# done
#
#
# Variabelen en vaste waarden:
# ERRMIN geeft aan hoe vaak een bepaald verdacht IP-adres minimaal
# in het error-log moet voorkomen om automatisch geblokkeerd te worden.
# EXPIRE geeft aan na hoeveel tijd een IP-adres weer toegang krijgt
# (de honderdtallen geven de maanden aan - al werkt dit niet bijzonder
# nauwkeurig).
# ERRLOG geeft de locatie aan van het Apache error-log.
# BLOCKLIST geeft de locatie aan van de blocklist; let op dat deze
# locatie ook in het firewall-script wordt gebruikt (zie boven).
# FIREWALL geeft de locatie aan van het firewall-script.
# De variabele FIRESTART geeft aan of de firewall uiteindelijk
# opnieuw gestart moet worden.
ERRMIN=3D10
EXPIRE=3D100
ERRLOG=3D/var/log/httpd/error_log
BLOCKLIST=3D/usr/local/etc/blocklist.db
FIREWALL=3D/usr/local/bin/init_firewall
FIRESTART=3Dfalse
# Allereerst wordt de huidige datum bepaald.
DATENOW=3D`date +%y%m%d`
# Met de volgende opdracht wordt gezocht naar hosts die pogen requests
# uit te voeren voor Windows-systeembestanden (zoals bij Nimda) of
# buffer-overflows (zoals bij CodeRed).
# De genoemde worms zijn de grootste logvervuilers:
for i in `grep "winnt.*exe\|NNNNNNNNNNN" $ERRLOG | sed -e 's/^.*\[client=
=20
//g' -e 's/\].*$//g' | sort -u`; do
# Als een host al in de blocklist voorkomt, moet dit gesignaleerd worden=
:
=20
MATCH=3Dfalse
for j in `grep -v "^#" $BLOCKLIST | cut -d : -f 1`; do
if [ $i =3D $j ]; then
MATCH=3Dtrue
fi
done
=20
# Als een host niet in de blocklist voorkomt, kijk dan of deze minstens =
het
# opgegeven aantal keren in ERRLOG voorkomt; zo ja, voeg de host dan toe=
# aan de blocklist, samen met de datum, en signaleer dat de firewall=20
opnieuw
# gestart moet worden:
=20
if [ $MATCH =3D false ]; then
if [ `grep -c $i $ERRLOG` -gt $ERRMIN ]; then
echo $i":"$DATENOW >> $BLOCKLIST
FIRESTART=3Dtrue
fi
fi
done
=20
# Voor de automatische expire van hosts in de blocklist wordt alleen=20
gekeken
# naar de datum. Zodra een expired host wordt gevonden, wordt dit=20
gesignaleerd
# om de firewall te kunnen aanpassen. Hosts die niet expired zijn, komen=
=20
in een
# tijdelijk bestand terecht, dat na de for-lus BLOCKLIST vervangt.
# Met de eerste grep-opdracht worden eventuele commentaarregels behouden=
..
=20
grep "#" $BLOCKLIST > $BLOCKLIST.tmp
for HOST in `grep -v "^#" $BLOCKLIST`; do
BLOCKDATE=3D`echo $HOST | cut -d : -f 2`
if [ `expr $DATENOW - $BLOCKDATE` -gt $EXPIRE ]; then
FIRESTART=3Dtrue
else
echo $HOST >> $BLOCKLIST.tmp
fi
done
mv $BLOCKLIST.tmp $BLOCKLIST
=20
# Als hosts aan BLOCKLIST zijn toegevoegd dan wel uit BLOCKLIST zijn=20
verwijderd,
# wordt de firewall opnieuw gestart:
=20
if $FIRESTART =3D true; then
$FIREWALL
fi
>>>>>>>>>>>>>>> Het script init_firewall: <<<<<<<<<<<<<<<<
#!/bin/sh
# Breng firewall down
/etc/rc.d/init.d/iptables stop
# NAT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# Maak de blocking-chain
iptables -N block
iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A block -j DROP
# Zet forward vanaf buiten dicht
iptables -A FORWARD -i eth0 -j block
# Blokkeer hosts die door blockcheck zijn herkend:
for i in `grep -v "^#" /usr/local/etc/blocklist.db | cut -d : -f 1`; do
iptables -A INPUT -i eth0 -s $i -j block
done
# Accepteer ICMP/Echo
iptables -A INPUT -i eth0 -p icmp -j ACCEPT
# Accepteer WWW/HTTP
iptables -A INPUT -i eth0 -p tcp --dport www -j ACCEPT
iptables -A INPUT -i eth0 -p udp --dport www -j ACCEPT
# Zet rest van de input vanaf buiten dicht
iptables -A INPUT -i eth0 -j block
# Firewall-configuratie opslaan
/sbin/service iptables save
>>>>>>>>>>>>>>> De foutieve iptables-policy na uitvoering vanuit cron:=20
<<<<<<<<<<<<<<<
# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
>>>>>>>>>>>>>>> De correcte iptables-policy: <<<<<<<<<<<<<<<
(de drie IP-adressen xxx.xxx.xxx.xxx staan voor geblokkeerde hosts)
# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
block all -- xxx.xxx.xxx.xxx anywhere
block all -- xxx.xxx.xxx.xxx anywhere
block all -- xxx.xxx.xxx.xxx anywhere
ACCEPT icmp -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere tcp dpt:http=
ACCEPT udp -- anywhere anywhere udp dpt:http=
block all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
block all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain block (5 references)
target prot opt source destination
ACCEPT all -- anywhere anywhere state=20
RELATED,ESTABLISHED
DROP all -- anywhere anywhere