IP address blocking under LINUX.

I suggest you see here the most effective and efficient method to block an IP under LINUX, namely the use of IPSET.
The blocking is then done dynamically, namely that everything added to the IPSET list is immediately blocked.

The installation is done in single line:

aptitude install ipset

With the SHOREWALL firewall :

First step we create an empty IPSET list named « banthis » :

ipset create banthis hash:net maxelem 6000000

ipset add banthis x.x.x.x

ipset save > /etc/shorewall/ipsets

Now we can enable it into SHOREWALL rules, note that the prefix for IPSET list is the caracter « + » :

File : /etc/shorewall/shorewall.conf
We add : 

SAVE_IPSETS=/etc/shorewall/ipsets


After : 

shorewall check
shorewall reload

File : /etc/shorewall/rules
We add for exemple :

DROP:$LOG       znet:+banthis                   all

Then we reload/apply configuration  :

shorewall check
shorewall reload


With the UFW firewall :

ipset create banthis hash:net maxelem 5000000 

ipset -S > /etc/ufw/ipsets

File : /etc/ufw/after.init
We insert rules for persistence :

chmod 740 /etc/ufw/after.init 

#!/bin/sh
set -e

savefile="/etc/ufw/ipsets"
if [ ! -f "$savefile" ]; then
    echo "Could not find '$savefile'" >&2
    return
fi

IPSET_EXE="/sbin/ipset"



case "$1" in
start)
    # typically required

    # Loading ipsets
    $IPSET_EXE restore < "$savefile"

    # Setting firewall rules
    iptables -I INPUT -m set --match-set banthis src -j DROP
    iptables -I INPUT -m set --match-set banthis src -j LOG --log-prefix "[UFW BLOCK IN bl-ip] "
    iptables -I FORWARD -m set --match-set banthis src -j DROP
    iptables -I FORWARD -m set --match-set banthis src -j LOG --log-prefix "[UFW BLOCK FW bl-ip] "
    iptables -I OUTPUT -m set --match-set banthis src -j DROP
    iptables -I OUTPUT -m set --match-set banthis src -j LOG --log-prefix "[UFW BLOCK IN bl-ip] "
    ;;
stop)
    # typically required

    # Unset firewall rules
    iptables -D INPUT -m set --match-set banthis src -j DROP || true
    iptables -D INPUT -m set --match-set banthis src -j LOG --log-prefix "[UFW BLOCK IN bl-ip] " || true
    iptables -D FORWARD -m set --match-set banthis src -j DROP || true
    iptables -D FORWARD -m set --match-set banthis src -j LOG --log-prefix "[UFW BLOCK FW bl-ip] " || true
    iptables -D OUTPUT -m set --match-set banthis src -j DROP || true
    iptables -D OUTPUT -m set --match-set banthis src -j LOG --log-prefix "[UFW BLOCK IN bl-ip] " || true

    $IPSET_EXE destroy banthis || true
    ;;
status)
    # optional
    ;;
flush-all)
    # optional
    ;;
*)
    echo "'$1' not supported"
    echo "Usage: after.init {start|stop|flush-all|status}"
    ;;
esac
after.ini ufw

Test :

#Block IP : 
ipset add banthis x.x.x.x 

#Persistence test : 
/etc/init.d/ufw restart 

#List ipset rules :
ipset -S

If you want a « test server » you can use :
https://www.thc.org/segfault/

Threat Hunting with PHP and BASH (part 2).

Hello everyone,

After reflection I decided to improve my IPS so that the agents send their alert via an API and that they also update their rules regularly via this API.
I also added a database (mariadb) and a graphical interface, and implemented a whitelist/blacklist system directly from the GUI. Here is a first result.

I’ve add link to usefull tools like :   https://viz.greynoise.io/     https://www.abuseipdb.com/   https://threatbook.io/
I will publish soon source code of the part 2.




 

 

Threat Hunting with PHP and BASH.

After testing fail2ban, I decided to create my own tool (MyIPSPHP) because I needed a tool that did not directly use IP lists (sometimes paid) and above all I needed a tool specific to my WEB applications.

The functioning of the tool that I propose to you here is based on PHP and BASH as well as on the GEOIP library. It also allows alerts to be sent to my phone via « ntfy.sh ». I used CHATGPT to improve the filters (add new shells/exploits).

Finally I use this tool on a mail server, an apache service, an nginx service and an iptables/ulog firewall, the operation is sensitively the same, we parse the logs and we detect possible alerts (via counting of DROP ports for example for iptables over a day).

Here is the code for NGINX log (for reverse proxy setup here), the APACHE version is very similar, note that I mix PHP and BASH calls, this does not pose a particular problem even if a « full » php or « full » bash version would be even better :  (here the date filter scope is 60min)

If you want to test, don’t forget to set RUNMODE to 0 to enable the no-action mode (only output the ban action).

#!/usr/bin/php
<?php
#MyIPSPHP (c) f4eyq@crx.cloud - v1.0
#sec_check_nginxlogs.php
error_reporting(E_ALL);
#sec_check_nginxlogs.php
############################################################
define('DEVICE_FW_NAME','myrp01');
define('NTFY_URI','ntfy.sh/mycustomalert1245');
define('NGINX_LOG','/var/log/nginx/*.log');
define('WHITELIST_IPS',array('192.168','82.99.99.99'));
define('BLOCK_TIME_S',3888000); // 45 days(86400*45)
define('RUNMODE',1);#Running mode : 1 => Real (detect and bloc IP adresse), 0 => Dry run.
############################################################
require_once('/opt/security/libs/geo/geoip2.phar');
use GeoIp2\Database\Reader;
require_once('/opt/security/libs/libfw.php');
define('IP_LIST_BL','/opt/masscan_ip.txt');
define('DB_GEOLITE2_COUNTRY','/opt/security/libs/geo/GeoLite2-Country.mmdb');
#Prepare date filter :
#ex:  24/Mar/2023:18:16
$date_apache_d=date('j');
$date_apache_m=date('M');
$date_apache_Y=date('Y');
$date_apache_h=date('H');
$filder_current_h="$date_apache_d/$date_apache_m/$date_apache_Y:$date_apache_h";
echo "Run security Nginx log monitoring : ".$filder_current_h.".\n";
if(RUNMODE == 1){
 echo "Running real mode. \n";
}
$log_path       =       NGINX_LOG;
function detect_vuln($log_path, $filder_current_h, $scan_vuln, $message,$plugin='Default') {
    $dos=false;
    $cmd = "sudo cat $log_path | grep '$filder_current_h' | grep -E '$scan_vuln' | awk '{ print $1}' | sort | uniq -c | sort | ".genPaternGrepv()." | grep -v '/'";

    #Scan all archives :
    #$cmd = "sudo zcat $log_path*gz | grep -E '$scan_vuln' | awk '{ print $1}' | sort | uniq -c | sort | ".genPaternGrepv()." | grep -v '/'";

    if($plugin=='Dos'){
        $cmd="sudo cat $log_path | grep '$filder_current_h' | awk '{ print $1}' | sort | uniq -c | sort | ".genPaternGrepv()." | grep -v '/'";
        $dos=true;
    }

    if($plugin=='Googlebot'){
        $scan_vuln = 'Googlebot';
        $ggrange = '66.249';
        $cmd = "sudo cat $log_path | grep '$filder_current_h' | grep -E -v '".$ggrange."' | grep -E '$scan_vuln' | awk '{ print $1}' | sort | uniq -c | sort | ".genPaternGrepv()." | grep -v '/'";
        #Scan all archives :
        #$cmd = "sudo zcat $log_path*gz | grep -E -v '".$ggrange."' | grep -E '$scan_vuln' | awk '{ print $1}' | sort | uniq -c | sort | ".genPaternGrepv()." | grep -v '/'";
    }

    $now      = time();
    $ban_end  = $now + BLOCK_TIME_S;

    $check = `$cmd`;
    $statsbrut = explode(PHP_EOL, $check ?? '');
    foreach($statsbrut as $k=>$line){
        preg_match('!\d+\.*\d*!', $line, $matches);
        if(isset($matches[0])){
           $hits=(int)$matches[0];
           preg_match('!\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}!', $line, $matches);
           if(isset($matches[0]) && !checkIfIPIsLog2($matches[0])){

              $ip=$matches[0];

              $t=0;

              if($dos)
                $t=8000;

              if($hits>$t){
                $str=dspMessage($hits,$ip,$message);
                if(RUNMODE == 1){

                        echo "$str \n";

                        logm($str);

                        sendAlert($str);
                        blockIp($ip);

                        $log="$ip|$ban_end";
                        addIPinLog($log);

                }
                else{
                        echo "Dry mode : \n";
                        echo $str."\n";
                }
              }
           }
        }
    }
}

###########################################
##Exploit/Vuln
# w00tw00 / mstshash / nmaplowercheck ...
# Detect  rdp/nmap call.
###########################################
$scan_vuln = '/boaform/admin|mstshash|nmaplowercheck|w00tw00t|\.\.\/.\.\/|/bin/sh|Apache/2|apache/2|cgi-bin/|/HNAP1|/Tri%6Eity.txt%2ebak';
$message = 'Alert try2call exploit on '.DEVICE_FW_NAME;
detect_vuln($log_path, $filder_current_h, $scan_vuln, $message);

###########################################
#Detect Webshell / autodiscover
# like  vuln.php, shell.php, alfashell.php
###########################################
$scan_vuln = '/IOptimize.php|/vuln.php|/marijuana.php|/shell.php|/alfashell.php|/autodiscover|/eval-stdin.php|/alfacgiapi/perl.alfa|/ALFA_DATA|/alfashell.php|/alfa.php|/c99.php|/r57.php|/wso.php|/b374k.php|/phpshell.php|/tryag.php|/FilesMan.php|/zehir.php|/izocin.php|/milw0rm.php|/cgitelnet.php|/darkmail.php|/GFS-webshell.php|/ANTICHAT_SHELL.php|/AntichatShell.php|/antichat.php|/php-backdoor.php|/php-backdoor2.php|/php-backdoor3.php|/php-webshells.php|/php-remoteview.php|/FSOCK.php|/jackal.php|/wsoshell.php|/php-spy-shells.php|/c99ud.php|/c100.php|/c99shell.php|/r57shell.php|/kacak.php|/ToolsBrasil.php|/cyber_shell.php|/WebShell.php|/simple-backdoor.php|/php-backdoor4.php';
$message = 'Alert try2call webshell on '.DEVICE_FW_NAME;
detect_vuln($log_path, $filder_current_h, $scan_vuln, $message);

####################################
# Detect webadmin Call :
####################################
$scan_vuln='/sqlbuddy/login.php|/phpma/|/phpMyAdmin/|/pmamy2/|/PHPMYADMIN/|/mymanage/|/manage/|/manager/|/mysql/|/mysql-admin/|/mysqladmin/|/mysqlmanager/|/myadmin/|/mydb/|/phpmyadmin2/|/phpmyadmin3/|/phpmyadmin4/|/phpMyAdmin-3/|/phpMyAdmin-4/|/phpMyAdmin-5/|/phpMyAdmin-6/|/phpmyadmin-old/|/phpmyadmin2/|/phpmyadmin3/|/phpmyadmin4/|/phpmyadmin5/|/phpMyExplorer/|/pma/|/PMA2/|/PMA3/|/PMA4/|/PMA5/|/PMA6/|/PMA2005/|/PMA2006/|/PMA2007/|/PMA2008/|/PMA2009/|/PMA2010/|/PMA2011/|/PMA2012/|/PMA2013/|/PMA2014/|/PMA2015/|/PMA2016/|/PMA2017/|/PMA2018/|/PMA2019/|/PMA2020/|/PMA2021/|/PMA2022/|/pma-old/|/pma2005/|/pma2006/|/pma2007/|/pma2008/|/pma2009/|/pma2010/|/pma2011/|/pma2012/|/pma2013/|/pma2014/|/pma2015/|/pma2016/|/pma2017/|/pma2018/|/pma2019/|/pma2020/|/pma2021/|/pma2022/|/PMA-old/|/adminer/|/dbadmin/|/sqladmin/|/myadmin/|/sqlyog/|/emysql/|/websql/|/adminsql/|/sqlweb/|/mysqlgui/|/dbtool/|/dbweb/|/sqleditor/|/sqlmanager/|/sqlbuddy/|/datadmin/|/dbVisualizer/|/sqlworkbench/|/heidiSQL/|/navicat/|/toad/|/phpsqliteadmin/|/sqliteadmin/|/SQLiteManager/|/adminer.php';

$message = 'Alert try2call web-admin on '.DEVICE_FW_NAME;
detect_vuln($log_path, $filder_current_h, $scan_vuln, $message);

####################################
# Detect Configuration collector
####################################
$scan_vuln='/phpinfo.php|/.env|/.env.bak|config.php.bak|settings.php.bak|wp-config.php.bak|settings.py|.sqlite|database.php.bak|config.inc.php.bak|config.yml.bak';
$message = 'Alert try2collect conf on '.DEVICE_FW_NAME;
detect_vuln($log_path, $filder_current_h, $scan_vuln, $message);

###########################
#Detect SQL injection :
###########################
$scan_vuln='SELECT%20|INSERT%20|UPDATE%20|UNION%20|AND%20|DROP%20|DESCRIBE%20|DELETE%20|TRUNCATE%20|SELECT%20INTO%20|OR%20';
$message = 'Alert detect SQL injection on '.DEVICE_FW_NAME;
detect_vuln($log_path, $filder_current_h, $scan_vuln, $message);

###########################
#Detect DDOS :
###########################
$plugin = 'Dos';
$message = 'Alert DDOS on '.DEVICE_FW_NAME;
detect_vuln($log_path, $filder_current_h, $scan_vuln, $message,$plugin);

##########################
#Detect fake google bot
##########################
$plugin  = 'Googlebot';
$message = 'Alert fake GoogleBot on '.DEVICE_FW_NAME;
detect_vuln($log_path, $filder_current_h, $scan_vuln, $message,$plugin);

###########################
#Uban process :
###########################
uBanProcess();
sec_check_nginxlogs.php

Here is the Firewall version :  (here the date filter scope is 24 hours)

<?php
#MyIPSPHP (c) f4eyq@crx.cloud - v1.0
#sec_check_fw.php
define('BLOCK_TIME_S',5184000); // 60 days ( 86400 x 60 )
define('TRIGGER_threshold_portscan',20);

#Prepare date filter :
##ex: Mar 27 09:43:47
$date_apache_d=date('j');
$date_apache_d=str_pad($date_apache_d,3,' ',STR_PAD_LEFT);
$date_apache_m=date('M');
$date_apache_Y=date('Y');
$filder_current_h = $date_apache_m.$date_apache_d;

#replay / all archives logs :
#$cmd = "zcat /var/log/auth.log*gz | grep 'invalid' | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' |cut -d ':' -f 5 | cut -d ' ' -f 4 | sort | ".genPaternGrepv()." | uniq -c";

$cmd="cat $alog | grep '".$filder_current_h."' | grep 'DROP' | cut -d '=' -f 5 |cut -d ' ' -f 1 | ".genPaternGrepv()." | sort | uniq -c";

$check = `$cmd`;

$now      = time();
$ban_end  = $now + BLOCK_TIME_S;
$statsbrut = explode(PHP_EOL, $check ?? '');

#ex:Mar 28 05:53:51 server2343 znet-zfw DROP  IN=eno1 OUT= MAC=d0:30:99:d7:6b:fc:a0:b4:31:cf:1b:41:08:00 SRC=22.22.22.22 DST=23.23.23.23 LEN=28 TOS=00 PREC=0x00 TTL=34 ID=34354 PROTO=UDP SPT=21345 DPT=1194 LEN=8 MARK=0
foreach($statsbrut as $k=>$line){
        preg_match('!\d+\.*\d*!', $line, $matches);
        if(isset($matches[0])){
           $hits=(int)$matches[0];
           preg_match('!\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}!', $line, $matches);
           if(isset($matches[0]) && !checkIfIPIsLog2($matches[0])){
               if($hits>TRIGGER_threshold_portscan){
                 $ip=$matches[0];
                 #echo "$ip, $hits \n";
                 $log="$ip|$ban_end";
                 #echo "Ban end:".date('d/m/y H:i',$ban_end).' - '.$ip." - $hits \n";
                 if(RUNMODE == 1){
                        #now check if port is different / count uniq item ( DPT=(X) )
                        $cmd="cat /var/log/ulog/syslogemu.log | grep '".$filder_current_h."' | grep '$ip' | cut -d '=' -f 14 | cut -d ' ' -f 1 | sort | uniq | wc -l";
                        $check = `$cmd`;
                        $check = (int) $check;
                        if($check>=TRIGGER_threshold_portscan)  {
                                $message = 'Alert portscanning on '.DEVICE_FW_NAME;
                                $str=dspMessage($hits,$ip,$message);
                                echo "Ban end:".date('d/m/y H:i',$ban_end).' - '.$ip." - $hits => $check \n";
                                logm($str);
                                sendAlert($str);
                                blockIp($ip);
                                addIPinLog($log);
                        }
                 }
                 else{
                        echo "Dry mode : \n";
                        echo $str."\n";
                 }

               }
           }
        }
}

And the small php lib use for various task like ban/uban and new ip in blacklist db etc :

<?php
#MyIPSPHP (c) f4eyq@crx.cloud - v1.0
#libs/libfw.php
use GeoIp2\Database\Reader;
function logm($m){
   $m2=date('d/m/Y H:i:s') . ": \n" . $m;
   $e = `echo "$m2" >> /var/log/securitychecks.log`;
}
function genPaternGrepv(){
  $nb=count(WHITELIST_IPS);
  $str='';
  $i=1;
  foreach(WHITELIST_IPS as $k=>$ip){
     $str.="grep -v '$ip'";
     if($i<$nb){
       $str.=" | ";
     }
   $i++;
  }
  return $str;
}
function checkIfIPIsLog2($ip){
        $l=IP_LIST_BL;
        $test = trim(`cat $l |grep '$ip|';echo $1;`);
        if($test<>''){
          return true;
        }
        return false;
}
function addIPinLog($ip){
        $l=IP_LIST_BL;
        $test= `echo "$ip" >> $l`;
}
function remoteIPFromLog($ip,$ipl){
        $e=`grep -v '$ip' $ipl > temp && mv temp $ipl`;
}
function blockIp($ip){
        $a=`ip route add blackhole $ip`;
}
function uBanIp($ip){
        $a=`ip route del blackhole $ip`;
}
function sendAlert($str){
       $uri=NTFY_URI;
       $a=`curl -d "$str" $uri`;
}
function dspMessage($hits,$ip,$message){
        $str=$message."\nBlock Ip: $hits => $ip,";
        $str.="\nCountry : ".getIpInfo($ip,'cn').".\n";
        return $str;
}
function getIpInfo($ip,$t='cn'){
        $reader = new Reader(DB_GEOLITE2_COUNTRY);
        $record = $reader->country($ip);
        if($t=='cn')return $record->country->name;
        if($t=='iso')return $record->country->isoCode;
}
function uBanProcess(){
$now      = time();
#Uban process :
$ipl=IP_LIST_BL;
$cmd="cat $ipl";
$check=`$cmd`;
$statsbrut = explode(PHP_EOL, $check ?? '');
#Format :   141.98.10.172|1681208329
#              IP        |    UBAN time (end ban)
foreach($statsbrut as $k=>$line){
   $p=explode('|',$line);
   if(isset($p[0]))$p[0]=trim($p[0]);
   if(isset($p[0]) && $p[0]<>''){
        $ip=$p[0];
        $bt=(int)$p[1];
        if($bt<=$now){
          #delete ip route
          uBanIp($ip);
          #echo "Uban $ip\n";
          remoteIPFromLog($ip,$ipl);
        }
   }
}
}

?>
libs/libfw.php

Finaly i’m using a CRON to launch the script every 1min :

*/1 * * * * /opt/security/sec_check_nginxlogs.php >> /dev/null 2>&1

Setup your central rsyslog server

Rsyslog can be configured to receive logs from the network and can then store them in a structured way,
that’s what I suggest you see in this article. Here I am using LINUX DEBIAN machines.

Central server configuration

rsyslog.conf :

– Here we use the rsyslog modules imudp and imtcp which allow the server to listen for rsyslog client connections.
– We will use a template « remote-logs » to create a log file name and its path dynamically.
– We will use « remote-logs » template only if host IP is not the local server ( 127.0.0.1 ).

###################################
# RSYSLOG SERVER CONFIGURATION 
###################################
# /etc/rsyslog.conf configuration file for rsyslog
#
# For more information install rsyslog-doc and see
# /usr/share/doc/rsyslog-doc/html/configuration/index.html

#################
#### MODULES ####
#################

module(load="imuxsock") # provides support for local system logging
module(load="imklog")   # provides kernel logging support
#module(load="immark")  # provides --MARK-- message capability

# provides UDP syslog reception
module(load="imudp")
input(type="imudp" port="514")

# provides TCP syslog reception
module(load="imtcp")
input(type="imtcp" port="514")

# Remote logs directory : (/var/log/remoteservers/[CLIENT]/)
$template remote-logs,"/var/log/remoteservers/%HOSTNAME%/%PROGRAMNAME%.log"

if not($fromhost-ip == '127.0.0.1') then {
*.* ?remote-logs
& ~
}

###########################
#### GLOBAL DIRECTIVES ####
###########################

#
# Use traditional timestamp format.
# To enable high precision timestamps, comment out the following line.
#
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

#
# Set the default permissions for all log files.
#
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022

#
# Where to place spool and state files
#
$WorkDirectory /var/spool/rsyslog

#
# Include all config files in /etc/rsyslog.d/
#
$IncludeConfig /etc/rsyslog.d/*.conf


###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*			/var/log/auth.log
*.*;auth,authpriv.none		-/var/log/syslog
#cron.*				/var/log/cron.log
daemon.*			-/var/log/daemon.log
kern.*				-/var/log/kern.log
lpr.*				-/var/log/lpr.log
mail.*				-/var/log/mail.log
user.*				-/var/log/user.log

#
# Logging for the mail system.  Split it up so that
# it is easy to write scripts to parse these files.
#
mail.info			-/var/log/mail.info
mail.warn			-/var/log/mail.warn
mail.err			/var/log/mail.err

#
# Some "catch-all" log files.
#
*.=debug;\
	auth,authpriv.none;\
	mail.none		-/var/log/debug
*.=info;*.=notice;*.=warn;\
	auth,authpriv.none;\
	cron,daemon.none;\
	mail.none		-/var/log/messages

#
# Emergencies are sent to everybody logged in.
#
*.emerg				:omusrmsg:*

Client server configuration

rsyslog.conf :

###################################
# RSYSLOG CLIENT CONFIGURATION 
###################################
# /etc/rsyslog.conf configuration file for rsyslog
#
# For more information install rsyslog-doc and see
# /usr/share/doc/rsyslog-doc/html/configuration/index.html

#################
#### MODULES ####
#################

module(load="imuxsock") # provides support for local system logging
module(load="imklog")   # provides kernel logging support
#module(load="immark")  # provides --MARK-- message capability

###########################
#### GLOBAL DIRECTIVES ####
###########################

#
# Use traditional timestamp format.
# To enable high precision timestamps, comment out the following line.
#
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

#
# Set the default permissions for all log files.
#
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022

#
# Where to place spool and state files
#
#$WorkDirectory /var/spool/rsyslog

#
# Include all config files in /etc/rsyslog.d/
#
$IncludeConfig /etc/rsyslog.d/*.conf

###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*			/var/log/auth.log
*.*;auth,authpriv.none		-/var/log/syslog
#cron.*				/var/log/cron.log
daemon.*			-/var/log/daemon.log
kern.*				-/var/log/kern.log
lpr.*				-/var/log/lpr.log
mail.*				-/var/log/mail.log
user.*				-/var/log/user.log

#
# Logging for the mail system.  Split it up so that
# it is easy to write scripts to parse these files.
#
mail.info			-/var/log/mail.info
mail.warn			-/var/log/mail.warn
mail.err			/var/log/mail.err

#
# Some "catch-all" log files.
#
*.=debug;\
	auth,authpriv.none;\
	mail.none		-/var/log/debug
*.=info;*.=notice;*.=warn;\
	auth,authpriv.none;\
	cron,daemon.none;\
	mail.none		-/var/log/messages

#
# Emergencies are sent to everybody logged in.
#
*.emerg				:omusrmsg:*

#CLI configuration : 
#Enable sending system logs over UDP to rsyslog server
*.* @[rsyslog_server]:514
#Enable sending system logs over TCP to rsyslog server
*.* @@[rsyslog_server]:514

It is possible to create a dedicated configuration, for example to change the spool folder, which allows not to modify the main configuration file rsyslog.conf,
To do this we add this file:  /etc/rsyslog.d/01-client.conf

– The client sends its logs to the IP [rsyslog_server].
– The spool folder used (apache log for example) is: /var/log/rsyslogspools
– A quota of 1G is set on it.

#/etc/rsyslog.d/01-client.conf
$WorkDirectory /var/log/rsyslogspools
$ActionQueueFileName fwdRule1
$ActionQueueMaxDiskSpace 1g
$ActionQueueSaveOnShutdown on
$ActionQueueType LinkedList
$ActionResumeRetryCount -1

In the case of an APACHE service, you will have to tell rsyslog where to fetch the data and then send it to the remote rsyslog server : [rsyslog_server]

#/etc/rsyslog.d/02-apache-defaultlog.conf.j2

$ModLoad imfile

# Default Apache Error Log
$InputFileName /var/log/apache2/error.log
$InputFileTag apache-error-default:
$InputFileStateFile apache-error-default
$InputRunFileMonitor

# Default Apache Access Log
$InputFileName /var/log/apache2/access.log
$InputFileTag apache-access-default:
$InputFileStateFile apache-access-default
$InputRunFileMonitor
$InputFilePollInterval 30

if $programname == "apache-error-default" then @@[rsyslog_server]:514
if $programname == "apache-error-default" then ~

if $programname == "apache-access-default" then @@[rsyslog_server]:514
if $programname == "apache-access-default" then ~

And There you go !

 

Update Debian PHP distribution ( 8.2 ).

PHP8.2 is now available, i describe here how to update the debian server with this version.

First i need a list of php install package ( here 8.0 ) :

dpkg -l | grep php8.0 | cut -d ' ' -f 3 > list.txt

I create this script using to convert the list of packages to list of packages to install on the target server :

<?php
#create list of package to upgrade version
#ex:    php up.php --currentversion="php8.0" --newversion="php8.2"
$short_options = "cur:new:";
$long_options = ["currentversion:", "newversion:"];
$options = getopt($short_options, $long_options);

if(empty($options) || !isset($options['currentversion']) || !isset($options['newversion']) ){
        echo "Params:\n";
        print_r($long_options);
        echo "\n";
        return;
}

$fh = fopen('list.txt','r');
while ($line = fgets($fh)) {
  $line=str_replace("\n","",$line);
  $line=str_replace($options['currentversion'],$options['newversion'],$line);

  echo $line." ";


}
fclose($fh);


?>
up.php

Now i create a list of php packages for the target :

# php up.php --currentversion="php8.0" --newversion="php8.2"
libapache2-mod-php8.2 php8.2 php8.2-bcmath php8.2-bz2 php8.2-cli php8.2-common php8.2-curl php8.2-dev php8.2-fpm php8.2-gd php8.2-igbinary php8.2-imagick php8.2-imap php8.2-intl php8.2-ldap php8.2-mbstring php8.2-memcache php8.2-memcached php8.2-msgpack php8.2-mysql php8.2-opcache php8.2-readline php8.2-soap php8.2-sqlite3 php8.2-tidy php8.2-xml php8.2-xmlrpc php8.2-zip

I remove all of old php packages :

# apt-get purge `dpkg -l | grep php| awk '{print $2}' |tr "\n" " "`
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
  apache2 apache2-bin apache2-data apache2-utils debhelper dh-autoreconf dh-strip-nondeterminism dwz fonts-droid-fallback fonts-noto-mono ghostscript gsfonts imagemagick-6-common
  intltool-debian libaom0 libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap libarchive-cpio-perl libarchive-zip-perl libc-client2007e libdav1d4 libde265-0 libdebhelper-perl
  libfftw3-double3 libfile-stripnondeterminism-perl libgs9 libgs9-common libheif1 libijs-0.35 libjbig2dec0 liblqr-1-0 liblua5.3-0 libmagickcore-6.q16-6 libmagickwand-6.q16-6
  libmail-sendmail-perl libmemcached11 libmemcachedutil2 libnuma1 libonig5 libopenjp2-7 libpaper-utils libpaper1 libpcre2-16-0 libpcre2-32-0 libpcre2-dev libpcre2-posix2 libsodium23
  libssl-dev libsub-override-perl libsys-hostname-long-perl libtidy5deb1 libwebpdemux2 libwebpmux3 libx265-192 libxmlrpc-epi0 libxslt1.1 libzip4 mlock pkg-config po-debconf poppler-data
  shtool ttf-dejavu-core
Use 'sudo apt autoremove' to remove them.
The following packages will be REMOVED:
  libapache2-mod-php7.4* libapache2-mod-php8.0* libapache2-mod-php8.1* php-common* php-imagick* php-memcache* php-memcached* php-msgpack* php-pear* php5.6-memcache* php7.0-memcache*
  php7.1-memcache* php7.2-memcache* php7.3-memcache* php7.4* php7.4-bcmath* php7.4-bz2* php7.4-cli* php7.4-common* php7.4-curl* php7.4-dev* php7.4-fpm* php7.4-gd* php7.4-igbinary*
  php7.4-imap* php7.4-intl* php7.4-json* php7.4-mbstring* php7.4-memcache* php7.4-mysql* php7.4-opcache* php7.4-readline* php7.4-soap* php7.4-tidy* php7.4-xml* php7.4-xmlrpc* php7.4-zip*
  php8.0* php8.0-bcmath* php8.0-bz2* php8.0-cli* php8.0-common* php8.0-curl* php8.0-dev* php8.0-fpm* php8.0-gd* php8.0-igbinary* php8.0-imagick* php8.0-imap* php8.0-intl* php8.0-ldap*
  php8.0-mbstring* php8.0-memcache* php8.0-memcached* php8.0-msgpack* php8.0-mysql* php8.0-opcache* php8.0-readline* php8.0-soap* php8.0-tidy* php8.0-xml* php8.0-xmlrpc* php8.0-zip*
  php8.1-cli* php8.1-common* php8.1-memcache* php8.1-opcache* php8.1-phpdbg* php8.1-readline* php8.1-sqlite3* pkg-php-tools*
0 upgraded, 0 newly installed, 71 to remove and 21 not upgraded.
After this operation, 95.1 MB disk space will be freed.
Do you want to continue? [Y/n]

I can now install the new version, via the list of packages ( return by up.php ) :

# apt-get install libapache2-mod-php8.2 php8.2 php8.2-bcmath php8.2-bz2 php8.2-cli php8.2-common php8.2-curl php8.2-dev php8.2-fpm php8.2-gd php8.2-igbinary php8.2-imagick php8.2-imap php8.2-intl php8.2-ldap php8.2-mbstring php8.2-memcache php8.2-memcached php8.2-msgpack php8.2-mysql php8.2-opcache php8.2-readline php8.2-soap php8.2-sqlite3 php8.2-tidy php8.2-xml php8.2-xmlrpc php8.2-zip
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following package was automatically installed and is no longer required:
  ttf-dejavu-core
Use 'sudo apt autoremove' to remove it.
The following additional packages will be installed:
  php-common php-pear pkg-php-tools
Suggested packages:
  dh-php dh-make
The following NEW packages will be installed:
  libapache2-mod-php8.2 php-common php-pear php8.2 php8.2-bcmath php8.2-bz2 php8.2-cli php8.2-common php8.2-curl php8.2-dev php8.2-fpm php8.2-gd php8.2-igbinary php8.2-imagick php8.2-imap
  php8.2-intl php8.2-ldap php8.2-mbstring php8.2-memcache php8.2-memcached php8.2-msgpack php8.2-mysql php8.2-opcache php8.2-readline php8.2-soap php8.2-sqlite3 php8.2-tidy php8.2-xml
  php8.2-xmlrpc php8.2-zip pkg-php-tools
0 upgraded, 31 newly installed, 0 to remove and 21 not upgraded.
Need to get 8343 kB/8377 kB of archives.
After this operation, 39.9 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y

That all !

 

 

 

 

 

Recherche de vulnérabilités sous DEBIAN.

Si vous utilisez l’OS DEBIAN, il existe un outil très pratique pour cela, il s’agit de Debsecan.

Voyons voir comment l’utiliser, on commence par installer l’outil :

root@crx-sec01 / # apt-get install debsecan
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  debsecan
0 upgraded, 1 newly installed, 0 to remove and 25 not upgraded.
Need to get 33.2 kB of archives.
After this operation, 112 kB of additional disk space will be used.
Get:1 http://deb.debian.org/debian bullseye/main amd64 debsecan all 0.4.20.1 [33.2 kB]
Fetched 33.2 kB in 0s (688 kB/s)
Preconfiguring packages ...
Selecting previously unselected package debsecan.
(Reading database ... 63992 files and directories currently installed.)
Preparing to unpack .../debsecan_0.4.20.1_all.deb ...
Unpacking debsecan (0.4.20.1) ...
Setting up debsecan (0.4.20.1) ...
setup debsecan

Suivant la distribution on va adapter le nom de la suite :

Debian 11 (Bullseye)
Debian 10 (buster)
Debian 9 (stretch)
Debian 8 (jessie)
Debian 7 (wheezy)
Debian 6.0 (squeeze)

Ensuite on lance un scan :

root@crx-sec01 / # debsecan --suite bullseye
CVE-2021-3447 ansible
CVE-2022-2795 bind9
CVE-2022-2881 bind9
CVE-2022-3080 bind9
CVE-2022-38177 bind9
CVE-2022-38178 bind9
CVE-2022-2795 bind9-dnsutils
CVE-2022-2881 bind9-dnsutils
CVE-2022-3080 bind9-dnsutils
CVE-2022-38177 bind9-dnsutils
CVE-2022-38178 bind9-dnsutils
CVE-2022-2795 bind9-host
CVE-2022-2881 bind9-host
CVE-2022-3080 bind9-host
CVE-2022-38177 bind9-host
CVE-2022-38178 bind9-host
CVE-2022-2795 bind9-libs
CVE-2022-2881 bind9-libs
CVE-2022-3080 bind9-libs
CVE-2022-38177 bind9-libs
CVE-2022-38178 bind9-libs
CVE-2022-2795 bind9-utils
CVE-2022-2881 bind9-utils
CVE-2022-3080 bind9-utils
CVE-2022-38177 bind9-utils
CVE-2022-38178 bind9-utils
CVE-2016-2781 coreutils (low urgency)
CVE-2021-38185 cpio
CVE-2022-35252 curl (fixed)
CVE-2022-2795 dnsutils
CVE-2022-2881 dnsutils
CVE-2022-3080 dnsutils
CVE-2022-38177 dnsutils
CVE-2022-38178 dnsutils
CVE-2022-1664 dpkg (fixed)
CVE-2022-1304 e2fsprogs
CVE-2018-12886 gcc-8-base
CVE-2019-15847 gcc-8-base
CVE-2016-1585 libapparmor1 (low urgency)
..... 

Et voilà !   on obtient la liste des vulnérabilités du système, truc pratique on peut obtenir un affichage détaillé :

root@crx-sec01 / # debsecan --suite bullseye --format detail
...
CVE-2022-24919
  An authenticated user can create a link with reflected Javascript code ...
  installed: zabbix-agent 1:5.0.8+dfsg-1
             (built from zabbix 1:5.0.8+dfsg-1)
  fixed in unstable: zabbix 1:6.0.7+dfsg-2 (source package)
  fixed on branch:   zabbix 1:3.0.32+dfsg-0+deb9u3 (source package)
...

Ensuite on peut récupérer une liste des paquets disponibles pour corriger toutes ces failles :

root@crx-sec01 / # debsecan --suite buster --only-fixed --format packages
dpkg
libdns-export1104
libdpkg-perl
libisc-export1100
python3-paramiko
zlib1g

Enfin pour mettre à jour le tout avec cette liste :

root@crx-sec01 / # apt-get install $(debsecan --suite buster --only-fixed --format packages)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
python3-paramiko is already the newest version (2.7.2-1).
python3-paramiko set to manually installed.
libdns-export1104 is already the newest version (1:9.11.5.P4+dfsg-5.1+deb10u5).
libisc-export1100 is already the newest version (1:9.11.5.P4+dfsg-5.1+deb10u5).
Suggested packages:
  debsig-verify debian-keyring gcc | c-compiler binutils patch git bzr
The following packages will be upgraded:
  dpkg libdpkg-perl zlib1g
3 upgraded, 0 newly installed, 0 to remove and 22 not upgraded.
Need to get 0 B/4178 kB of archives.
After this operation, 11.3 kB of additional disk space will be used.
Do you want to continue? [Y/n]

 

Debscan marche aussi sur Ubuntu, pour cela suivez ce guide : https://korben.info/debsecan-cve.html

 

Configuration WSL/VISUALSTUDIO CODE.

Bonjour à tous,

Si votre éditeur vous renvoi un message indiquant que votre instance WSL n’est pas en V2, CTRL+MAJ+u  puis :
wsl_term

Lancez un powershell en tant qu’administrateur puis :

PS C:\Users\tux> wsl --list --verbose
NAME STATE VERSION
* Debian Stopped 1
PS C:\Users\bba>

Lancez ensuite cette commande pour convertir l’image WSL ici « Debian » :

PS C:\Users\tux> wsl --set-version Debian 2

Enfin vous pouvez décider que toutes vos images soient en V2 via cette commande :

PS C:\WINDOWS\system32> wsl --set-default-version 2
Pour plus d’informations sur les différences de clés avec WSL 2, visitez https://aka.ms/wsl2
L’opération a réussi.

Et voilà !

wsl --list --verbose
  NAME      STATE           VERSION
* Debian    Running         2

Sources :
https://docs.microsoft.com/fr-fr/windows/wsl/troubleshooting
https://aka.ms/wsl2

ANSIBET project is launch !

Hello everybody,

I developed a new concept to control the Ansible layer, my project is called « ANSIBET », phylosophy is make my ansible system experience better

The objective of this one is to bring a fast piloting of Ansible by freeing itself from the modification of files and by making more « user friendly » the interface of Ansible.

For the moment it is a « beta » version, the idea being progressively to build an advanced Ansible management system.

https://bastien.barbe.pw/ansibet/

 

Goodbye !

Configuration du NAT pour une machine hyper-v avec Windows 10/11.

Bonjour à tous,

Dans cet article je vais vous parler de configuration NAT pour une VM sous HYPERV avec Windows 10.
L’idée de cette configuration est de permettre le surf Internet d’une machine virtuelle ici DEBIAN LINUX.

hyper_vm_nat_net

1 Contrôle de la navigation Internet de la couche « virtualisation » :

Cette étape bien que facultative vous permet de vous s’assurez que votre machine WSL sort sur Internet,
Notez que ici ma machine WSL est de type « 1 ».

PS C:\Windows\System32\WindowsPowerShell\v1.0> wsl --list --running -v
NAME STATE VERSION
* Debian Running 1

N’utilisant que peu WSL, je commence par changer le mot de passe ROOT :

#Reset root pasword 
#run WINOWS cli 
wsl -u root 
passwd

Un simple ping en root fait l’affaire ensuite :

bba@CT-6SYSFC2:~$ su -
Password:
root@CT-6SYSFC2:~# ping www.google.fr
PING www.google.fr(par21s20-in-x03.1e100.net (2a00:1450:4007:818::2003)) 56 data bytes
64 bytes from par21s20-in-x03.1e100.net (2a00:1450:4007:818::2003): icmp_seq=1 ttl=114 time=16.2 ms
64 bytes from par21s20-in-x03.1e100.net (2a00:1450:4007:818::2003): icmp_seq=2 ttl=114 time=17.8 ms
..

2. Création d’un « v-switch » : 

Je créé ici un switch virtuel que j’appel « NATLINUX » :

New-VMSwitch –SwitchName "NATLINUX" –SwitchType Internal –Verbose

#pour enlever celui ci 
#Remove-VMSwitch -Name "NATLINUX"

Je récupère ensuite l’ID de l’interface de ce SW ici « 14 » :

PS C:\WINDOWS\system32> Get-NetAdapter

Name                      InterfaceDescription                    ifIndex Status       MacAddress             LinkSpeed
----                      --------------------                    ------- ------       ----------             ---------
vEthernet (NATLINUX)      Hyper-V Virtual Ethernet Adapter #3          14 Up           00-15-5D-B0-01-08        10 Gbps

PS C:\WINDOWS\system32>

3. Création de la passerelle NAT et rattachement à la machine virtuelle : 

Je peux ensuite créer la passerelle de NAT via cette commande POWERSHELL :

New-NetIPAddress -IPAddress 172.16.229.10 -PrefixLength 24 -InterfaceIndex 14 -Verbose

Maintenant je « map » ma machine virtuelle LINUX pour utiliser cette passerelle :

Get-VM | Get-VMNetworkAdapter | Connect-VMNetworkAdapter –SwitchName "NATLINUX"

Je précise alors que ma machine virtuelle va sortir par l’adresse IP de cette passerelle NAT pour ceci je créé une règle de NAT :

New-NetNat -Name NATOutsideDebian -InternalIPInterfaceAddressPrefix 172.16.229.0/24

#Pour effacer cette règle : Remove-NetNat

Ensuite je peux lister la règle via cette commande :

PS C:\WINDOWS\system32> Get-NetNat


Name                             : NATNetwork
ExternalIPInterfaceAddressPrefix :
InternalIPInterfaceAddressPrefix : 192.168.1.33/32
IcmpQueryTimeout                 : 30
TcpEstablishedConnectionTimeout  : 1800
TcpTransientConnectionTimeout    : 120
TcpFilteringBehavior             : AddressDependentFiltering
UdpFilteringBehavior             : AddressDependentFiltering
UdpIdleSessionTimeout            : 120
UdpInboundRefresh                : False
Store                            : Local
Active                           : True

Et voilà  :

bba@debian:~$ ping www.google.fr
PING www.google.fr (216.58.214.67) 56(84) bytes of data.
64 bytes from fra15s10-in-f3.1e100.net (216.58.214.67): icmp_seq=1 ttl=119 time=16.5 ms
64 bytes from fra15s10-in-f67.1e100.net (216.58.214.67): icmp_seq=2 ttl=119 time=17.0 ms
64 bytes from fra15s10-in-f67.1e100.net (216.58.214.67): icmp_seq=3 ttl=119 time=16.0 ms
^C
--- www.google.fr ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 16.034/16.493/16.964/0.379 ms
bba@debian:~$

Il est possible maintenant d’utiliser différents outils comme un serveur X windows pour pouvoir utiliser la GUI de ma machine virtuelle depuis WINDOWS,
Ou encore y accéder et disposer d’une multitude d’outils.

A très bientôt !

 

 

 

Gestion des mises à jour LINUX suite, cibler les mises à jour de sécurité

Bonjour à tous,

Suite à mon petit article d’introduction à ANSIBLE et les mises à jour LINUX ici : automatisation-de-la-gestion-des-utilisateurs-et-des-mises-a-jour
Je vous propose ici de gérer une ou plusieurs mises à jour de sécurité en mode « automatique » toujours avec ANSIBLE.

Dans mon exemple ici je pars du principe que j’ai un ensemble de serveurs à mettre à jour ( en cas de mise à jour urgente à faire ),
Que j’ai un accès SSH sur ceux-ci et que je dispose de la couche ANSIBLE opérationnelle :

Je commence par identifier la mise à jour à faire via cette commande :

# apt-cache policy php8.0-memcache
php8.0-memcache:
  Installed: 8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-1+0~20210302.23+debian10~1.gbpff8707
  Candidate: 8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4
  Version table:
     8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4 500
        500 https://packages.sury.org/php buster/main amd64 Packages
 *** 8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-1+0~20210302.23+debian10~1.gbpff8707 100
        100 /var/lib/dpkg/status

Je déduis donc que le paquet cible à déployer est :

php8.0-memcache:8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4

Dans cet exemple, il s’agit d’une simple mise à jour, bien sur cela peut être une mise à jour de sécurité ou encore un paquet à installer
comme nous l’avons vu précédemment.

Maintenant, je peux donc utiliser ce playbook, notez ici l’utilisation du signe  » =  » comme mentionné dans la documentation ANSIBLE,
Voici mon code YAML :    crx-awx/upgrade_package.yml

---

- hosts: all
  become: yes
  tasks:
    - name: Install the package
      apt:
        name: php8.0-memcache=8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4
        update_cache: yes

Je peux donc le lancer via cette commande :

bba@crx-ans01 ~ $ ansible-playbook crx-awx/upgrade_package.yml --limit crx-webng04.crxcluster.lan

PLAY [all] **********************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************************************************************
ok: [crx-webng04.crxcluster.lan]

TASK [Install the package] ******************************************************************************************************************************************************************************************************************
[WARNING]: Updating cache and auto-installing missing dependency: python3-apt
changed: [crx-webng04.crxcluster.lan]

PLAY RECAP **********************************************************************************************************************************************************************************************************************************
crx-webng04.crxcluster.lan : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

bba@crx-ans01 ~ $

Ensuite je contrôle que tout est bon :

# apt-cache policy php8.0-memcache
php8.0-memcache:
  Installed: 8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4
  Candidate: 8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4
  Version table:
 *** 8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4 500
        500 https://packages.sury.org/php buster/main amd64 Packages
        100 /var/lib/dpkg/status

Ou je peux aussi le contrôler via cette commande ANSIBLE :

$ ansible crx-webng04.crxcluster.lan -a "apt-cache policy php8.0-memcache" | grep -- 'Installed\|Candidate'
  Installed: 8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4
  Candidate: 8.0+4.0.5.2+3.0.9~20170802.e702b5f9+-7+0~20220117.28+debian10~1.gbp8ceec4
b

Et voilà j’ai pu mettre à jour simplement un paquet via un processus ANSIBLE.

 

A bientôt,