Catégorie : HACK

USB Control and triggerhappy on LINUX for HAMRADIO

In the past, i was using a « multimedia controller knob USB »  (on Windows OS with AUTOHOTKEY script to map SYSCALL of sound to special key),
This system can control my RADIO TRANSCEIVER (FT897).

For exemple i can use one RASPBERRYPI for TRX/TCP-IP control with CRX-COM and another RASPBERRYPI from my remote for USB BUTTON control,
here i’m using the same RASPBERRY device for TRX CAT, CRX-COM and USB Control.

I’ve found a new system based on LINUX now to do that, AHK equivalent system is call « TRIGGERHAPPY » on LINUX.
I’m using a RASPBERRY PI4 + an USB « Cooidea USB Multimedia Control« .

In my case on RPI4, TRIGGERHAPPY is already install / natif.

The advantage of this solution is :
– i did’t have to use my PC/tablet here, only  RASPBERRYPI4 + USB CAT SYSTEM + USB MEDIA CONTROLLER.
– Can work via INTERNET/NETWORK.

For HAM radio, use « TRIGGERHAPPY » is very usefull, you can map key/button to call a specific command,
exemples : control relay by press a key/device button, change frequency, turn antenna (key press/relay map).

Here is a photo of the test system RASPBERRYPI4+USB MULTIMEDIA Button, on the bottom right :

1. First step identify KEY mapping with USB device : 

Simply connect a device (keyboard/media controller) to your raspberry.
For exemple here i connect the USB device, i launch a « dmesg » command to have information :

[ 6143.609009] usb 1-1.4: new full-speed USB device number 6 using xhci_hcd
[ 6146.029045] usb 1-1.4: new full-speed USB device number 7 using xhci_hcd
[ 6146.166273] usb 1-1.4: New USB device found, idVendor=0483, idProduct=5756, bcdDevice= 2.00
[ 6146.166290] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 6146.166303] usb 1-1.4: Product: USB Multimedia Control
[ 6146.166314] usb 1-1.4: Manufacturer: Cooidea
[ 6146.166326] usb 1-1.4: SerialNumber: 205435345950
[ 6146.175278] input: Cooidea USB Multimedia Control Keyboard as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:0483:5756.0003/input/input3
[ 6146.240139] input: Cooidea USB Multimedia Control Consumer Control as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:0483:5756.0003/input/input4
[ 6146.240454] hid-generic 0003:0483:5756.0003: input,hidraw1: USB HID v1.11 Keyboard [Cooidea USB Multimedia Control] on usb-0000:01:00.0-1.4/input0

Now let make a small test, we have a command to debug the « TRIGGERHAPPY » process it’s the THD command,
So after plug the USB device, i simply turn up/down the volume button and press on it to call « mute » option :

root@rmtrpi-56-f4eyq bastien # thd --dump /dev/input/event*
EV_KEY  KEY_VOLUMEUP    1       /dev/input/event2
# KEY_VOLUMEUP  1       command
EV_KEY  KEY_VOLUMEUP    0       /dev/input/event2
# KEY_VOLUMEUP  0       command
EV_KEY  KEY_VOLUMEDOWN  1       /dev/input/event2
# KEY_VOLUMEDOWN        1       command
EV_KEY  KEY_VOLUMEDOWN  0       /dev/input/event2
# KEY_VOLUMEDOWN        0       command

root@rmtrpi-56-f4eyq bastien # thd --dump /dev/input/event*
EV_KEY  KEY_MUTE        1       /dev/input/event2
# KEY_MUTE      1       command
EV_KEY  KEY_MUTE        0       /dev/input/event2
# KEY_MUTE      0       command

2. Create the TRIGGERHAPPY configuration : 

I can create the button configuration for EVENTS mapping :

root@rmtrpi-56-f4eyq crx-com # cat /etc/triggerhappy/triggers.d/volumectrl.conf
#change band:
KEY_MUTE            1       /opt/crx/crx-com/qrg_whell.php mute
#frequency up:
KEY_VOLUMEUP        1       /opt/crx/crx-com/qrg_whell.php up

#frequency down:
KEY_VOLUMEDOWN      1       /opt/crx/crx-com/qrg_whell.php down

I’ve create a PHP script to map KEYPAM to WEBSOCKET command here is the script :

I can call it with 3 commands for the moment, UP/DOWN and BAND UP (in future i will probably move to an USB system with more buttons, like STEP/MODE changing).

root@rmtrpi-56-f4eyq crx-com # /opt/crx/crx-com/qrg_whell.php mute
@DEBUG:n: 15m , 21000
@DEBUG, SET payload:0210000001
root@rmtrpi-56-f4eyq crx-com # /opt/crx/crx-com/qrg_whell.php up
@DEBUG, SET payload:0210010001
root@rmtrpi-56-f4eyq crx-com # /opt/crx/crx-com/qrg_whell.php down
C:21001
N:21000
@DEBUG, SET payload:0210000001
root@rmtrpi-56-f4eyq crx-com # /opt/crx/crx-com/qrg_whell.php up
@DEBUG, SET payload:0210010001
root@rmtrpi-56-f4eyq crx-com #

To create the script, i’ve first made this test (send a WEBSOCKET cmd via CLI with WEBSOCAT),
here CRX-COM program talk with JSON :

<?php

$cmd='echo \'{"protocol":"yaesu1","setQrg":"0071200001","readbuff":0}\' | /usr/local/bin/websocat -t --ws-c-uri=wss://192.168.1.167:5209/ - ws-c:cmd:\'socat - ssl:192.168.1.167:5209,verify=0\'';
$e=shell_exec($cmd);

?>

After succefully send QRG / change BAND,
i’ve create this script :  /opt/crx/crx-com/qrg_whell.php

#!/usr/bin/php
<?php
/*
 *	crx-com/qrg_whell.php	
 *	A CLI client for crx-com WEBSOCKET (remote station/crx-radio-cloud).
 *	(c) f4eyq@crx.cloud - 2024
 *	date: 27/02/2024
 *	up:   27/02/2024
 *	version: 0.1b
 * 
 *	Events mapping call this TRIGGERHAPPY script with args{mute,up,down} : 
 *	KEY_MUTE	1	/opt/crx/crx-com/qrg_whell.php mute	
 *	KEY_VOLUMEUP	1	/opt/crx/crx-com/qrg_whell.php up	
 *	KEY_VOLUMEDOWN	1	/opt/crx/crx-com/qrg_whell.php down
 *	See /etc/triggerhappy/triggers.d/volumectrl.conf	
 * */
require_once('/opt/crx/crx-com/qrg_whell.qrg.php');
$GTRX_conf			=	array(
	'crx-com-hostname'	=>	'192.168.1.167',
	'crx-com-port'		=>	'5209',
	'crx-com-protocol'	=>	'yaesu1'	
);
$GREG_file_crxcomqrgwhell	=	'/tmp/REG_file_crxcomqrgwhell';
$GDEF_QRG			=	'7000';
$GDEF_BAND			=	'40m';
$inputAction			=	'init';
if(isset($argv[1])){
	if($argv[1]=='up'){$inputAction='qrgup';}
	if($argv[1]=='down'){$inputAction='qrgdown';}
	if($argv[1]=='mute'){$inputAction='bandup';}
}
#echo "@DEBUG:".$inputAction."\n";
initRegistry();
$reg=getRegistry();
if($inputAction=='qrgup' && isset($reg['current_qrg'])){
	#echo "C:".$reg['current_qrg']."\n";
	$reg['current_qrg'] = $reg['current_qrg'] + 1;
	#echo "N:".$reg['current_qrg']."\n";
	saveRegistry($reg);
	setQrgTrx($reg);
	exit(0);
}
if($inputAction=='qrgdown' && isset($reg['current_qrg'])){
	#echo "C:".$reg['current_qrg']."\n";
	$reg['current_qrg'] = $reg['current_qrg'] - 1;
	#echo "N:".$reg['current_qrg']."\n";
	saveRegistry($reg);
	setQrgTrx($reg);
	exit(0);
}
if($inputAction=='bandup' && isset($reg['current_band'])){
	$current_band	=	$reg['current_band'];
	$fd=0;
	$next=$nextb=$nextq='';
	foreach($frequency_default as $vbd=>$vqrg){
                if($fd){//put the next band:
			$nextb=$vbd;
			$nextq=$vqrg;
                 break;
                }
		if($vbd==$current_band && $fd==0){
			$fd++;		
		}			
	}
	if($nextb=='' && $nextq==''){
		foreach($frequency_default as $vbd=>$vqrg){//put the first.
                        $nextb=$vbd;
			$nextq=$vqrg;
			break;
		}
	}
	#echo "@DEBUG:n: $nextb , $nextq  \n";
	$reg['current_band'] = $nextb;
        $reg['current_qrg']  = $nextq;
	saveRegistry($reg);
	setQrgTrx($reg);
}
function getQrgPayload($qrg,$protocol){
	//@TODO: implement all CRX-COM protocol
	//At this time only yaesu1 is supported (FT817,818,857,897)
	// input QRG exemple :  7006Khz
	$inm=$qrg/1000; //Convert KHZ to MHZ : 
	$qrgmhz=explode('.',$inm);//create array 0=> 7,  1=> 006 (floating part is part [1] of this array.
	// FA    P1  P1  P1  P1  P1  P1  P1  P1  => yaesu1 (ft817,897 etc... into crx-com).
	$part1=$qrgmhz[0];// 7
	$part1=str_pad($part1,3, "0", STR_PAD_LEFT);// 007
	if(!isset($qrgmhz[1]))$qrgmhz[1]='00';
	$part2=$qrgmhz[1];// 006
	$part2=str_pad($part2,5, "0", STR_PAD_RIGHT);// 006 0000 , => len 7
	$pl = ''.$part1.''.$part2.'01';
	return $pl;
}
function setQrgTrx($reg){
	global $GTRX_conf;
	if(!isset($reg['current_qrg']))return false;
	$qrg=$reg['current_qrg'];//QRG in KHZ
	$pl	=	getQrgPayload($qrg,$GTRX_conf['crx-com-protocol']);
	#echo "@DEBUG, SET payload:".$pl."\n";

    $cmd='echo \'{"protocol":"'.$GTRX_conf['crx-com-protocol'].'","setQrg":"'.$pl.'",';
	$cmd.='"readbuff":0}\' | /usr/local/bin/websocat -t --ws-c-uri=wss://'.$GTRX_conf['crx-com-hostname'].':'.$GTRX_conf['crx-com-port'];
	$cmd.='/ - ws-c:cmd:\'socat - ssl:'.$GTRX_conf['crx-com-hostname'].':'.$GTRX_conf['crx-com-port'].',verify=0\'';

	$e=shell_exec($cmd);
	return true;
}
function saveRegistry($ireg){
       global  $GREG_file_crxcomqrgwhell;
       $reg=serialize($ireg);
       file_put_contents($GREG_file_crxcomqrgwhell,$reg);
}
function initRegistry(){
	global	$GREG_file_crxcomqrgwhell;
	global	$GDEF_QRG;
	global	$GDEF_BAND;
	if(!file_exists($GREG_file_crxcomqrgwhell)){
		$r=touch($GREG_file_crxcomqrgwhell);
		if(!$r){
			die('cannot create :'.$GREG_file_crxcomqrgwhell.' ,please check right on file');			
		}
		else{
			echo "init reg file for TRX control : ".$GREG_file_crxcomqrgwhell." \n\n";
			$arr=array(
				'current_band'	=>	$GDEF_BAND,
				'current_qrg'	=>	$GDEF_QRG
			);
			$reg=serialize($arr);			
			file_put_contents($GREG_file_crxcomqrgwhell,$reg);
		}
	}
}
function getRegistry(){
	global  $GREG_file_crxcomqrgwhell;
	$rs=file_get_contents($GREG_file_crxcomqrgwhell);
	if($rs && $rs<>''){
		$reg=unserialize($rs);
		if(!$reg)return array();
		return $reg;
	}
	return array();
}
?>

Frequency configuration is a simple script :     /opt/crx/crx-com/qrg_whell.qrg.php

<?php
$frequency_default = array();
$frequency_default["136khz"]="135";
$frequency_default["500khz"]="493";
$frequency_default["160m"]="1855";
$frequency_default["80m"]="3672";
$frequency_default["60m"]="5353";
$frequency_default["40m"]="7090";
$frequency_default["30m"]="10120";
$frequency_default["20m"]="14057";
$frequency_default["17m"]="18068";
$frequency_default["15m"]="21250";
$frequency_default["12m"]="24890";
$frequency_default["10m"]="28090";
$frequency_default["6m"]="50315";
$frequency_default["4m"]="70000";
$frequency_default["2m"]="144300";
$frequency_default["70cm"]="430000";
?>

The setup of WEBSOCAT here is very simple here :

#wget : https://github.com/vi/websocat/releases/download/v1.2.0/websocat_nossl_arm-linux-static

root@rmtrpi-56-f4eyq websocat-master # whereis websocat
websocat: /usr/local/bin/websocat
root@rmtrpi-56-f4eyq websocat-master # ll /usr/local/bin/websocat
lrwxrwxrwx 1 root root 50 Feb 27 10:16 /usr/local/bin/websocat -> /opt/websocat-master/websocat_1.2.0_nossl_arm_mini

73 to all,

See :
CRX-COM/QRG-WHELL : https://git.crx.cloud/f4eyq/crx-com/-/tree/master/QRG-WHELL
TRIGGERHAPPY : https://github.com/wertarbyte/triggerhappy/
WEBSOCAT : https://github.com/vi/websocat
CRX-COM :
https://project.crx.cloud/Remote_ham_radio_station_setup_guide
https://project.crx.cloud/crx-com

VFO-USB :
https://bastien.barbe.pw/ham-un-bouton-vfo-usb-pour-son-catsystem/

USB DEVICE can be use, type « multimedia controller knob USB »
on ALIEXPRESS  /   AMAZON :

See also :

=> Test Windows10 +MCHF WINDOWS10PC +TRX-MCHF (FT817 protocol) : https://bastien.barbe.pw/webcontrol-radio-transceiver/
=> Test Mobile Phone / Mumble / m.crx.cloud / CRX-COM (01/10/2021) : https://bastien.barbe.pw/ham-remote-station-on-mobile-phone/
=> Test WIFI/RASPBERRY/FT817 (04/04/2020) : https://bastien.barbe.pw/cat-system-en-wifi/
=> Test FT817+CRX-COM (15/06/2019) :  https://project.crx.cloud/crx-com-rasb-ft817

Webcontrol radio transceiver !

Hello to all,

CRX-COM is now in version 1.0.4 release 5. I’ve migrate the server.js to node v16, serialport v10. Docker file is also update.

For info, the program can be run :
– with manual nodejs setup (v16) with the bin.js file.
– with LINUX/WINDOWS/MAC via the binary files (via pkg).
– with Docker.
I’ve test it here with Windows 10, MCHF/RS-918 and related transceiver (ft817 protocol)
and Google Chrome.     73 to all,

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

HAM – SETUP RASPBERRY PI for remote station via installer script.

Hello to all,

Configure your RASPBERRY PI 4 with CRX-COM + VOIP and FLRIG,
via these « installer » scripts : https://git.crx.cloud/f4eyq/crx-com/tree/master/scripts

See SETUP here :  https://git.crx.cloud/f4eyq/crx-com/blob/master/scripts/README.md
Setup is done via the single line :  ( it download and launch the DEBIAN installer ) :

wget --output-document /tmp/setupcrx.bash https://git.crx.cloud/f4eyq/crx-com/raw/master/scripts/setup_server.bash;chmod +x /tmp/setupcrx.bash;/tmp/setupcrx.bash;

The configuration work via a single file : « station.conf » :

pi@rmtrpi4f4eyq remote $ ll
total 16
-rw-r--r-- 1 root root 47 sept. 30 11:43 station.conf
lrwxrwxrwx 1 root root 36 sept. 30 11:49 voip.conf -> /opt/crx/conf/remote/voip_hight.conf
-rw-r--r-- 1 root root 33 sept. 30 11:49 voip_hight.conf
-rw-r--r-- 1 root root 31 sept. 30 11:49 voip_low.conf
-rw-r--r-- 1 root root 29 sept. 30 11:49 voip_mid.conf
pi@rmtrpi4f4eyq remote $ pwd
/opt/crx/conf/remote
pi@rmtrpi4f4eyq remote $ cat station.conf
SOUND_CARD="plughw:0,0"
STATION_NAME="f4eyq-1"
pi@rmtrpi4f4eyq remote $

You can edit your VOIP profile ( low / mid / hight ) via the command :

The VOIP is start via the rc.local file on the PI with this single line :

sudo su - pi -c "screen -dm -S pistartup /opt/crx/seren/voip.bash --start";

The SYSTEMD part for command used two scripts :

=> tcp_serial_catsystem.service
=> crx_com_tcp.service

sudo systemctl start crx_com_tcp.service
sudo systemctl stop crx_com_tcp.service

sudo systemctl start tcp_serial_catsystem.service
sudo systemctl stop tcp_serial_catsystem.service

=> with the first script you can use FLRIG, with second CRX-COM.

Tnx to @f4goh for his help,
Good weekend to all 73 s

PS: it work on all Raspberry PI version, Debian , Ubuntu, also into VMWARE Workstation/VIRTUALBOX.

HAM – Programmation d’un bouton VFO USB.

Update 22/09/2020 : mise à jour du script pour le support de CRX-COM ( alt+t, alt+o, alt + l ).

Je vous propose la programmation d’un bouton USB « Cooidea USB Volume Control » en bouton VFO. L’idée est d’utiliser un bouton USB de contrôle de volume pour piloter un VFO radio. Cette idée m’est venue il y a quelques mois et voyant une console remote sur un transceiver SDR « haut de gamme ». J’ai décidé d’investir dans un périphérique identique mais pour l’audio (qui coute 30 euros environ) et ensuite de créer une macro pour le contrôler.

Pré requis : disposer d’un bouton USB de contrôle du volume, ici je suis parti sur un « Cooidea USB Volume Control », n’importe quel bouton USB de contrôle de volume fera l’affaire. On le tourne pour le volume et on appuie dessus pour couper ou pas le son.

Comment ça marche ? Ici mon logiciel « CAT SYSTEM » FLRIG ne dispose pas du support de ce bouton nativement, j’ai donc créé un script « MACRO » qui permet de le faire. Ce script fonctionne avec AUTOHOTKEY qui est un petit langage de macro super pratique.

Afin d’optimiser les choses, je mémorise la position du curseur de souris et la fenêtre active quand le bouton est utilisé afin de ne pas modifier votre fenêtre active et votre souris (je remets tout en place une fois le scroll/commande PTT faite).

1. Installer AUTOHOTKEY :  ( pour nos amis pingouins, utiliser AutoHotkeyX )

Rendez vous ici : https://www.autohotkey.com/

2. Mon script AUTOHOTKEY  « cooidea4Ham.ahk » :

La première étape va être de lancer le logiciel de contrôle CAT SYSTEM ( ici FLRIG ).

Une fois lancé on va repérer 2 choses :
– la position X,Y du digit KHZ ( là où l’on peut avec la souris faire un scroll up/down ).
– la position X,Y du bouton PTT ( là où l’on va cliquer pour passer en émission ).

Pour ce faire, j’ai inclus un mode « configuration » dans le script, vous permettant de récupérer les coordonnées X et Y.
Ensuite on va simplement éditer le script avec ces coordonnées.

C’est ce que je vous propose à l’étape 3.

3. Configurer le script : 

Commencez par installer mon script là ou vous voulez ( il est disponible tout en bas de l’article ).
Ensuite on peut passer à sa configuration :

Editez le script avec votre bloc note favoris :
– passez la variable ci-dessous à 1
– on la passera à 0 une fois la configuration terminée :

;Enable only for coordination conf :
global CfgMode := 1

Ensuite lancez le script (double-clic dessus ou clic-droit : Run script).

Ensuite disposez votre logiciel là ou vous le souhaitez, notez que FLRIG mémorise sa position,
donc il sera de nouveau là lorsque vous le relancerez.

Ici je vous ai indiqué les 2 points que nous allons contrôler avec le bouton,
le digit « Khz » et le bouton « PTT » :

On va cliquer sur la fenêtre de notre logiciel « CAT SYSTEM » ici FLRIG.
– On se place avec la souris sur le digit des Khz dans le logiciel ( voir schéma C1 )
– Puis l’on va avec notre bouton VFO USB, le tourner vers le haut et regarder la popup qui s’affiche ici (juste en dessous du curseur de la souris) :

Current cursor position: 885, 75

– Même chose on va aller avec la souris sur la bouton « PTT » et récupérer les coordonnées X et Y (voir schéma C2 ) :

Current cursor position: 1640, 123

Il ne nous reste plus qu’à configurer le script avec ces valeurs,
Pour ce faire éditez celles-ci :

;Mouse position for Khz control :
; screen1 : 885,75 (flrig in full size top of screen here).
; screen2 : 728,88
global TwcX := 885
global TwcY := 75
;Mouse position for button PTT control :
; screen1 : 1633,123 (flrig in full size top of screen here).
; screen2 : 1317,123
global TwxX := 1633
global TwxY := 123

Enfin on va repasser la variable « CfgMode » à 0, on sauvegarder le script.

Ensuite on ferme et on exécute de nouveau notre script « cooidea4Ham.ahk »,
Et voilà vous pilotez maintenant le VFO via un bouton USB !

Bien sûr si vous utilisez un autre logiciel pour le pilotage (HRD par exemple ou n’importe quel logiciel SDR),
Il vous suffira d’adapter les variables du script :

;Window SDR/CAT class name :
global Twc := "Flrig"

Qui correspond à la valeur « ahk_class » d’AUTOHOTKEY.

4 Autre exemple, pilotez le WEB SDR

Voici un autre exemple pour piloter le SDR WEB avec le bouton USB :  http://websdr.ewi.utwente.nl:8901/
Faite une copie mon script, nommez là par exemple : « WEBSDR.ahk »

Ensuite, lancez le SDR, puis repérez le X, Y ( en activant : global CfgMode := 1  comme je l’ai indiqué avant ),
Pour ce faire lancez alors le script « WEBSDR.ahk », le debug va nous donner la valeur C1 ici :

Fermez le programme (clic droit sur l’icône H en vert dans la barre de tâche),
Editez la variable : CfgMode  et passez là à 0.

Renseignez alors les 2 variables X, Y avec par exemple :
global TwcX := 650
global TwcY := 760

Relancez le script, et voilà vous pouvez piloter le WEB SDR avec votre VFO USB !

73 à tous,
Bastien

PS: Voici mon script (à copier/coller quelque part sur votre PC, par exemple votre bureau)

;-----------------------------------------------------------------
; Control CRX/SDR/FLRIG by F4EYQ
; File			 : cooidea4Ham.ahk
;
; Description 	 : AutoHotkey script to map Volume UP/DOWN to Mousse Whell
; 				   and Mute/Unmute action (press on sound button) to PTT control.
;
; Hardware 		 : Cooidea USB Volume Control
;
; Date 			 : 08/2020
; Update		 : 22/09/2020 add CRX Control short key.
;
;-----------------------------------------------------------------
;Configuration : 
;-----------------------------------------------------------------
;Window SDR/CAT class name  :
global Twc := "Flrig"

;Enable only for coordination conf :
global CfgMode := 0

;Mouse position for Khz control :
; screen1 : 885,75 (flrig in full size top of screen here).
; screen2 : 728,88
global TwcX := 885
global TwcY := 75

;Mouse position for button PTT control : 
; screen1 : 1633,123 (flrig in full size top of screen here).
; screen2 : 1317,123
global TwxX := 1633
global TwxY := 123

;-----------------------------------------------------------------
;Global VARS: 
;-----------------------------------------------------------------
;Transceiver PTT status : 
global TwcTX := 0

;---------------------------
;Configure device mapping : 
;---------------------------
Volume_Up::MousseWheelUpDown("UP")
Volume_Down::MousseWheelUpDown("DOWN")
Volume_Mute::ControlTX()
;---------------------------
ControlTX()
{
	if TwcTX=0
	{
	 Send !t
	 TwcTX=1
	 WinActivate, ahk_class %Twc%
	 ;click on "PTT button"
	 MouseClick, left,%TwxX%,%TwxY%
	 MouseMove, %TwcX%, %TwcY%, 0
	}
	else 
	{
	  Send !t
	  TwcTX=0
	  WinActivate, ahk_class %Twc%
	  ;click on "PTT button"
	  MouseClick, left,%TwxX%,%TwxY%
	  MouseMove, %TwcX%, %TwcY%, 0
	}
}

MousseWheelUpDown(direction)
{
	;get current active window ID and class :
	Awc := WinExist("A")
	WinGetClass, class, A
	
	;need to retreive initial frequency cursor position :
	MouseGetPos,xpos,ypos,id,control
	
	;debug/conf if needed : 
	if(CfgMode=1){
		ToolTip, Current window Class:`n%class%`nCurrent cursor position:`n%xpos%`n%ypos%
	}
	;get current mouse pos:
	;MouseGetPos,xpos,ypos,id,control
	
	;set scroll on the flrig window:
	;WinActivate, ahk_class %Twc%
	;MouseMove, %TwcX%, %TwcY%, 0
	
	if(direction="UP"){
		Send !o
		;Send, {WheelUp}
	}
	
	if(direction="DOWN"){
		Send !l
		;Send, {WheelDown}
	}
	
	;set old position:
	;WinActivate, ahk_id %Awc%
	;MouseMove, %xpos%, %ypos%, 0
}
Control CRX/SDR/FLRIG by F4EYQ