Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sskras/45f140128c2ae7b945a28e3fa54c7527 to your computer and use it in GitHub Desktop.
Save sskras/45f140128c2ae7b945a28e3fa54c7527 to your computer and use it in GitHub Desktop.
Linux Bash Script to Parse OpenVMS Operator Log forwarded to Unix-Style SYSLOG on Linux, Generating auth failure audit events for fail2ban reporting to Blocklist.de. See http://supratim-sanyal.blogspot.com/2016/12/mitigate-openvms-telnet-port-brute.html
#!/bin/bash
#
# --------------------------------
# openvms-telnet-spam-blocklist.sh
# --------------------------------
#
# READS LINUX (CENTOS) SYSTEM LOG FILE, LOOKING FOR REMOTELY LOGGED OPENVMS VAX INTRUSIONS.
# FOR EACH OPENVMS INTRUDER FOUND, LOGS AN EQUIVALENT PAM AUTHENTICATION FAILURE LOG LINE.
# FAIL2BAN PICKS UP THE PAM AUTHENTCATION FAILURES AS USUAL AND REPORTS TO BLOCKLIST.DE.
# ALSO WRITES AN INFORMATIONAL SUMMARY REPORT OF BRUTE-FORCE ATTACK SOURCES.
#
# SEE http://sanyal.blogspot.com/2016/12/mitigate-openvms-telnet-port-brute.html FOR
# MORE INFORMATION
#
#
# REVISION HISTORY
# REV 1.0 04-DEC-2016 INITIAL RELEASE
#
#
# (C) 2016 SUPRATIM SANYAL <SUPRATIM AT RISEUP DOT NET>
# FREELY USABLE AND REDISTRIBUTABLE UNDER GNU AGPLv3
# LICENSE: http://tuklusan.decsystem.org/agpl-3.0-standalone.html
# -----------------------
#
#
# -----------------------
# EXAMPLE OF OPENVMS INTRUSION LOGGED IN /var/log/messages BY REMOTE VAXserver RUNNING OpenVMS and VAX SYSLOGD.EXE tool
# -----------------------
# Nov 23 16:11:31 sanyalnet-vax [OPCOM] %%%%%%%%%%% OPCOM 23-NOV-2016 16:11:31.06 %%%%%%%%%%%
# Nov 23 16:11:31 sanyalnet-vax [OPCOM] Message from user INTERnet on QCOCAL
# Nov 23 16:11:31 sanyalnet-vax [OPCOM] TELNET Login from Host: 120.59.231.133 Port: 4783
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] %%%%%%%%%%% OPCOM 23-NOV-2016 16:11:32.34 %%%%%%%%%%%
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Message from user AUDIT$SERVER on QCOCAL
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Security alarm (SECURITY) and security audit (SECURITY) on QCOCAL, system id: 1574
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Auditable event: Remote interactive breakin detection
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Event time: 23-NOV-2016 16:11:32.33
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] PID: 0000023E
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Process name: _TNA29:
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Username: ROOT
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Terminal name: TNA29:, _TNA29:, Host: 120.59.231.133 Port: 4783
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Remote node id: 2246523768 (14.888)
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Remote node fullname: 120.59.231.133
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Remote username: TELNET_783BE785
# Nov 23 16:11:32 sanyalnet-vax [OPCOM] Status: %LOGIN-F-NOSUCHUSER, no such user
# -----------------------
#
# -----------------------
# EXAMPLE OF OPENVMS INTRUSION LOG CONVERTED TO LOOK LIKE PAM AUTHENTICATION FAILURE IN /var/log/secure
# -----------------------
# Dec 4 16:07:35 dormarth sshd[00002457]: pam_unix(sshd:auth): authentication failure; logname=SYS$MANAGER:OPERATOR.LOG uid=0 euid=0 tty=TELNET_BD1AB4A8:38942 ruser=ROOT rhost=189.26.180.168.dynamic.adsl.gvt.net.br user=TELNET_BD1AB4A8 rport=38942 time="4-DEC-2016 15:46:59.08 UTC" event="%LOGIN-F-NOSUCHUSER, no such user;[OPCOM] Auditable event: Remote interactive breakin detection" reporter="Digital-VAXserver-3900-OpenVMS-7.3;DECnet:QCOCAL(1.550);inet:http://sanyalnet-openvms-vax.freeddns.org:82/"
# -----------------------
# dec2ip() takes parameter integer IP like 3994475481 (in OpenVMS Byte Order) and
# returns dotted IP like 217.219.22.238
# Usage example: dottedip=$(dec2ip "3994475481")
dec2ip(){
local a=$((~(-1<<8))) b=$1;
set -- "$((b&a))" "$((b>>8&a))" "$((b>>16&a))" "$((b>>24&a))";
local IFS=.;
echo "$*";
}
# Duplicate execution check
# PIDFILE is deleted at script end
PIDFILE=/var/run/openvms-telnet-spam-blocklist.pid
if [ -f $PIDFILE ]
then
PID=$(cat $PIDFILE)
ps -p $PID > /dev/null 2>&1
if [ $? -eq 0 ]
then
echo "Process already running"
exit 1
else
## Process not found assume not running
echo $$ > $PIDFILE
if [ $? -ne 0 ]
then
echo "Could not create PID file"
exit 1
fi
fi
else
echo $$ > $PIDFILE
if [ $? -ne 0 ]
then
echo "Could not create PID file"
exit 1
fi
fi
# ---
DEBUG=0
if [ "$1" == "-v" ] ; then DEBUG=1; echo "$0: ******** VERBOSE MODE ACTIVE ********"; fi
TEMPFILE="/tmp/vmsbreakins.tmp"
TEMPFILE2="/tmp/vmsbreakins-singlelines.tmp"
TEMPFILE3="/tmp/vmsbreakins-sorted-uniqued.tmp"
nice -n 19 ionice -c3 egrep -B6 -A9 "\[OPCOM\] Auditable event: Remote interactive breakin detection" /var/log/messages* | nice -n 19 ionice -c3 egrep -v "^--" | cut -f 6- -d " " > $TEMPFILE
:>$TEMPFILE2
while IFS='' read -r l_evt || [[ -n "$l_evt" ]]; do # %%%%%%%%%%% OPCOM 23-NOV-2016 16:35:40.67 %%%%%%%%%%%
if [[ $l_evt != *" OPCOM "* ]]; then continue; fi
read -r l_msgfrominternet # Message from user INTERnet on QCOCAL
if [[ $l_msgfrominternet != *"Message from user INTERnet on "* ]]; then continue; fi
read -r l_login_info # TELNET Login from Host: 217.219.22.238 Port: 32817
if [[ $l_login_info != *"TELNET Login from Host: "* ]]; then continue; fi
# ++
# Ignore certain domains and IPs from being reported
# --
if [[ $l_login_info == *"uptimerobot.com"* ]]; then continue; fi
if [[ $l_login_info == *" localhost "* ]]; then continue; fi
if [[ $l_login_info == *" localhost.localdomain "* ]]; then continue; fi
if [[ $l_login_info == *" 127.0.0.1 "* ]]; then continue; fi
if [[ $l_login_info == *" 0.0.0.0 "* ]]; then continue; fi
if [[ $l_login_info == *" 10.42.2.2 "* ]]; then continue; fi
if [[ $l_login_info == *"sanyalnet-cloud-vps.freeddns.org"* ]]; then continue; fi
if [[ $l_login_info == *"sanyalnet-cloud-vps2.freeddns.org"* ]]; then continue; fi
if [[ $l_login_info == *"cloudatcost.com "* ]]; then continue; fi
if [[ $l_login_info == *" 103.25.58.8 "* ]]; then continue; fi # proxy-au.ftelnet.ca web telnet proxy
if [[ $l_login_info == *" proxy-au.ftelnet.ca "* ]]; then continue; fi # proxy-au.ftelnet.ca web telnet proxy
# --
read -r l_evt2 # %%%%%%%%%%% OPCOM 23-NOV-2016 16:35:41.35 %%%%%%%%%%%
if [[ $l_evt2 != *" OPCOM "* ]]; then continue; fi
read -r l_msgfromauditsvr # Message from user AUDIT$SERVER on QCOCAL
if [[ $l_msgfromauditsvr != *"Message from user AUDIT\$SERVER on "* ]]; then continue; fi
read -r l_secalarm # Security alarm (SECURITY) and security audit (SECURITY) on QCOCAL, system id: 1574
if [[ $l_secalarm != *"Security alarm (SECURITY) and security audit (SECURITY) on "* ]]; then continue; fi
read -r l_auditevt # Auditable event: Remote interactive breakin detection
if [[ $l_auditevt != *"Auditable event: Remote interactive breakin detection"* ]]; then continue; fi
read -r l_evttm # Event time: 23-NOV-2016 16:35:41.34
if [[ $l_evttm != *"Event time: "* ]]; then continue; fi
read -r l_pid # PID: 00000260
if [[ $l_pid != *"PID: "* ]]; then continue; fi
read -r l_pname # Process name: _TNA63:
if [[ $l_pname != *"Process name: "* ]]; then continue; fi
read -r l_user # Username: ROOT
if [[ $l_user != *"Username: "* ]]; then continue; fi
read -r l_termname # Terminal name: TNA29:, _TNA29:, Host: 120.59.231.133 Port: 4783
# This one sometimes contains only a "Port: xxxx" string
# Or even worse, just a single digit
# Read it but don't use it!
#if [[ $l_termname != *"Port: "* ]]; then continue; fi
read -r l_remnodeid # Remote node id: 3994475481 (54.985)
if [[ $l_remnodeid != *"Remote node id: "* ]]; then continue; fi
read -r l_remnode # Remote node fullname: 217.219.22.238
if [[ $l_remnode != *"Remote node fullname: "* ]]; then continue; fi
read -r l_remuser # Remote username: TELNET_D9DB16EE
if [[ $l_remuser != *"Remote username: "* ]]; then continue; fi
read -r l_remstatus # Status: %LOGIN-F-NOSUCHUSER, no such user
if [[ $l_remstatus != *"Status: "* ]]; then continue; fi
l_evt="$(echo -e "${l_evt##*:}" | sed -e 's/^[[:space:]]*//')"
l_evttm="$(echo -e "${l_evttm##*time:}" | sed -e 's/^[[:space:]]*//')"
l_user="$(echo -e "${l_user##*:}" | sed -e 's/^[[:space:]]*//')"
l_remoteip="$(echo -e "${l_remnodeid##*:}" | sed -e 's/^[[:space:]]*//')"
l_remoteip=${l_remoteip%% *}
l_remoteip=$(dec2ip "$l_remoteip")
l_remnode="$(echo -e "${l_remnode##*fullname:}" | sed -e 's/^[[:space:]]*//')"
l_remport="$(echo -e "${l_login_info##*Port: }" | sed -e 's/^[[:space:]]*//')"
l_remuser="$(echo -e "${l_remuser##*:}" | sed -e 's/^[[:space:]]*//')"
l_remstatus="$(echo -e "${l_remstatus##*:}" | sed -e 's/^[[:space:]]*//')"
l_pid="$(echo -e "${l_pid##*:}" | sed -e 's/^[[:space:]]*//')"
if [ "$DEBUG" -eq 1 ]; then
echo "Event: [$l_auditevt]"
echo "Time: [$l_evttm]"
echo "Username: [$l_user]"
echo "IP: [$l_remoteip]"
echo "Host: [$l_remnode]"
echo "Port: [$l_remport]"
echo "RemUsr: [$l_remuser]"
echo "PID: [$l_pid]"
echo "Status: [$l_remstatus]"
echo "-------------------"
fi
# --
# Add to line-summary report file
# 194.140.233.79|194-140-233-79.luksus.net.pl|44395|12-DEC-2016 05:37:51.16|SHSTEM|%LOGIN-F-NOSUCHUSER, no such user|Auditable event: Remote interactive breakin detection
# --
oneline="$l_remoteip|$l_remnode|$l_remport|$l_evttm|$l_user|$l_remstatus|$l_auditevt"
echo $oneline >> $TEMPFILE2
if [ "$DEBUG" -eq 1 ]; then
echo $oneline
echo "-------------------"
fi
# ---
# generate pam-lookalike message for fail2ban to pick up
# fail2ban filter template:
# ^%(__prefix_line)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=<HOST>\s.*$
#
# generated line looks like follows:
# pam_unix(sshd:auth): authentication failure; logname=SYS$MANAGER:OPERATOR.LOG uid=0 euid=0 tty=TELNET_58F97EB9:46428 ruser=ROOT rhost=88.249.126.185 user=TELNET_58F97EB9 rport=46428 time="12-DEC-2016 05:45:34.27 UTC" event="88.249.126.185.dynamic.ttnet.com.tr;%LOGIN-F-NOSUCHUSER, no such user;Auditable event: Remote interactive breakin detection" reporter="Digital-VAXserver-3900-OpenVMS-7.3;DECnet:QCOCAL(1.550);inet:http://sanyalnet-openvms-vax.freeddns.org:82/"
# ---
logline="pam_unix(sshd:auth): authentication failure; logname=SYS\$MANAGER:OPERATOR.LOG uid=0 euid=0 tty=$l_remuser:$l_remport ruser=$l_user rhost=$l_remoteip user=$l_remuser rport=$l_remport time=\"$l_evttm UTC\" event=\"$l_remnode;$l_remstatus;$l_auditevt\" reporter=\"Digital-VAXserver-3900-OpenVMS-7.3;DECnet:QCOCAL(1.550);inet:http://sanyalnet-openvms-vax.freeddns.org:82/\""
if [ "$DEBUG" -eq 1 ]; then
echo $logline
echo "-------------------"
fi
logger -p authpriv.info -t "sshd[$l_pid]" $logline
sleep 1
done < $TEMPFILE
if [ "$DEBUG" -eq 1 ]; then
cat $TEMPFILE2
echo "-------------------"
fi
# ++
# Generate a sorted file with unique IP per line (may be useful later), move it to /var/log/QCOCAL-openvms-vax-attacks.txt
# Each line looks like
# 114-32-206-181.HINET-IP.hinet.net|39097|24-NOV-2016 08:16:03.61|SHSTEM|%LOGIN-F-NOSUCHUSER, no such user|Auditable event: Remote interactive breakin detection
# ++
: > $TEMPFILE3
echo "# ++" >> $TEMPFILE3
echo "# QCOCAL-openvms-vax-attacks.txt" >> $TEMPFILE3
echo "#" >> $TEMPFILE3
echo "# ACTIVE BRUTEFORCE ATTACKS ON SANYALNET QCOCAL OPENVMS 7.3 VAX VAXserver-3900 SERVER (http://sanyalnet-openvms-vax.freeddns.org:82/)" >> $TEMPFILE3
echo "# Generated: `date`" >> $TEMPFILE3
echo "#" >> $TEMPFILE3
echo "# (C) SUPRATIM SANYAL - Contact me at QCOCAL::SANYAL OVER HECnet OR http://mcaf.ee/sdlg9f OVER INTERNET" >> $TEMPFILE3
echo "#" >> $TEMPFILE3
echo "# ++" >> $TEMPFILE3
sort $TEMPFILE2 | awk -F"[. ]" '!a[$1]++' >> $TEMPFILE3
mv $TEMPFILE3 /var/log/QCOCAL-openvms-vax-attacks.txt
if [ "$DEBUG" -eq 1 ]; then
cat /var/log/QCOCAL-openvms-vax-attacks.txt
echo "-------------------"
fi
rm -f $PIDFILE
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment